mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2026-01-13 06:57:10 +03:00
Create a 2.5 branch.
This commit is contained in:
1192
.cdtproject
Normal file
1192
.cdtproject
Normal file
File diff suppressed because it is too large
Load Diff
200
.jupiter
Normal file
200
.jupiter
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Property>
|
||||||
|
<Review id="DEFAULT">
|
||||||
|
<Description>property.default.description</Description>
|
||||||
|
<Author />
|
||||||
|
<CreationDate format="yyyy-MM-dd :: HH:mm:ss:SSS z">1970-01-01 :: 00:00:00:000 GMT-10:00</CreationDate>
|
||||||
|
<Directory>review</Directory>
|
||||||
|
<Reviewers />
|
||||||
|
<Files />
|
||||||
|
<FieldItems>
|
||||||
|
<FieldItem id="Type" default="item.label.unset">
|
||||||
|
<Entry name="item.label.unset" />
|
||||||
|
<Entry name="item.type.label.codingStandards" />
|
||||||
|
<Entry name="item.type.label.programLogic" />
|
||||||
|
<Entry name="item.type.label.optimization" />
|
||||||
|
<Entry name="item.type.label.usability" />
|
||||||
|
<Entry name="item.type.label.clarity" />
|
||||||
|
<Entry name="item.type.label.missing" />
|
||||||
|
<Entry name="item.type.label.irrelevant" />
|
||||||
|
<Entry name="item.type.label.suggestion" />
|
||||||
|
<Entry name="item.type.label.other" />
|
||||||
|
</FieldItem>
|
||||||
|
<FieldItem id="Severity" default="item.label.unset">
|
||||||
|
<Entry name="item.label.unset" />
|
||||||
|
<Entry name="item.severity.label.critical" />
|
||||||
|
<Entry name="item.severity.label.major" />
|
||||||
|
<Entry name="item.severity.label.normal" />
|
||||||
|
<Entry name="item.severity.label.minor" />
|
||||||
|
<Entry name="item.severity.label.trivial" />
|
||||||
|
</FieldItem>
|
||||||
|
<FieldItem id="Resolution" default="item.label.unset">
|
||||||
|
<Entry name="item.label.unset" />
|
||||||
|
<Entry name="item.resolution.label.validNeedsfixing" />
|
||||||
|
<Entry name="item.resolution.label.validFixlater" />
|
||||||
|
<Entry name="item.resolution.label.validDuplicate" />
|
||||||
|
<Entry name="item.resolution.label.validWontfix" />
|
||||||
|
<Entry name="item.resolution.label.invalidWontfix" />
|
||||||
|
<Entry name="item.resolution.label.unsureValidity" />
|
||||||
|
</FieldItem>
|
||||||
|
<FieldItem id="Status" default="item.status.label.open">
|
||||||
|
<Entry name="item.status.label.open" />
|
||||||
|
<Entry name="item.status.label.resolved" />
|
||||||
|
<Entry name="item.status.label.closed" />
|
||||||
|
<Entry name="item.status.label.reopened" />
|
||||||
|
</FieldItem>
|
||||||
|
</FieldItems>
|
||||||
|
<Filters>
|
||||||
|
<Phase name="phase.individual" enabled="true">
|
||||||
|
<Filter name="Interval" value="7" enabled="false" />
|
||||||
|
<Filter name="Reviewer" value="item.reviewer.label.automatic" enabled="true" />
|
||||||
|
<Filter name="Type" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="Severity" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="AssignedTo" value="" enabled="false" />
|
||||||
|
<Filter name="Resolution" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="Status" value="item.status.label.open" enabled="false" />
|
||||||
|
<Filter name="File" value="" enabled="false" />
|
||||||
|
</Phase>
|
||||||
|
<Phase name="phase.team" enabled="true">
|
||||||
|
<Filter name="Interval" value="7" enabled="false" />
|
||||||
|
<Filter name="Reviewer" value="" enabled="false" />
|
||||||
|
<Filter name="Type" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="Severity" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="AssignedTo" value="" enabled="false" />
|
||||||
|
<Filter name="Resolution" value="item.label.unset" enabled="true" />
|
||||||
|
<Filter name="Status" value="item.status.label.open" enabled="false" />
|
||||||
|
<Filter name="File" value="" enabled="false" />
|
||||||
|
</Phase>
|
||||||
|
<Phase name="phase.rework" enabled="true">
|
||||||
|
<Filter name="Interval" value="7" enabled="false" />
|
||||||
|
<Filter name="Reviewer" value="" enabled="false" />
|
||||||
|
<Filter name="Type" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="Severity" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="AssignedTo" value="item.reviewer.label.automatic" enabled="true" />
|
||||||
|
<Filter name="Resolution" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="Status" value="item.status.label.open" enabled="true" />
|
||||||
|
<Filter name="File" value="" enabled="false" />
|
||||||
|
</Phase>
|
||||||
|
</Filters>
|
||||||
|
</Review>
|
||||||
|
<Review id="pre-2.5">
|
||||||
|
<Description>Pre 2.5 Review</Description>
|
||||||
|
<Author>brian</Author>
|
||||||
|
<CreationDate format="yyyy-MM-dd :: HH:mm:ss:SSS z">2008-01-04 :: 10:09:23:000 GMT-08:00</CreationDate>
|
||||||
|
<Directory>review</Directory>
|
||||||
|
<Reviewers>
|
||||||
|
<Entry id="brian" name="brian" />
|
||||||
|
<Entry id="ivan" name="ivan" />
|
||||||
|
</Reviewers>
|
||||||
|
<Files>
|
||||||
|
<Entry name="apache2/acmp.c" />
|
||||||
|
<Entry name="apache2/acmp.h" />
|
||||||
|
<Entry name="apache2/apache2.h" />
|
||||||
|
<Entry name="apache2/apache2_config.c" />
|
||||||
|
<Entry name="apache2/apache2_io.c" />
|
||||||
|
<Entry name="apache2/apache2_util.c" />
|
||||||
|
<Entry name="apache2/modsecurity.c" />
|
||||||
|
<Entry name="apache2/modsecurity.h" />
|
||||||
|
<Entry name="apache2/mod_security2.c" />
|
||||||
|
<Entry name="apache2/msc_geo.c" />
|
||||||
|
<Entry name="apache2/msc_geo.h" />
|
||||||
|
<Entry name="apache2/msc_logging.c" />
|
||||||
|
<Entry name="apache2/msc_logging.h" />
|
||||||
|
<Entry name="apache2/msc_lua.c" />
|
||||||
|
<Entry name="apache2/msc_lua.h" />
|
||||||
|
<Entry name="apache2/msc_multipart.c" />
|
||||||
|
<Entry name="apache2/msc_multipart.h" />
|
||||||
|
<Entry name="apache2/msc_parsers.c" />
|
||||||
|
<Entry name="apache2/msc_parsers.h" />
|
||||||
|
<Entry name="apache2/msc_pcre.c" />
|
||||||
|
<Entry name="apache2/msc_pcre.h" />
|
||||||
|
<Entry name="apache2/msc_reqbody.c" />
|
||||||
|
<Entry name="apache2/msc_test.c" />
|
||||||
|
<Entry name="apache2/msc_util.c" />
|
||||||
|
<Entry name="apache2/msc_util.h" />
|
||||||
|
<Entry name="apache2/msc_xml.c" />
|
||||||
|
<Entry name="apache2/msc_xml.h" />
|
||||||
|
<Entry name="apache2/pdf_protect.c" />
|
||||||
|
<Entry name="apache2/pdf_protect.h" />
|
||||||
|
<Entry name="apache2/persist_dbm.c" />
|
||||||
|
<Entry name="apache2/persist_dbm.h" />
|
||||||
|
<Entry name="apache2/re.c" />
|
||||||
|
<Entry name="apache2/re.h" />
|
||||||
|
<Entry name="apache2/re_actions.c" />
|
||||||
|
<Entry name="apache2/re_operators.c" />
|
||||||
|
<Entry name="apache2/re_tfns.c" />
|
||||||
|
<Entry name="apache2/re_variables.c" />
|
||||||
|
<Entry name="apache2/utf8tables.h" />
|
||||||
|
</Files>
|
||||||
|
<FieldItems>
|
||||||
|
<FieldItem id="Type" default="item.type.label.suggestion">
|
||||||
|
<Entry name="item.label.unset" />
|
||||||
|
<Entry name="item.type.label.codingStandards" />
|
||||||
|
<Entry name="item.type.label.programLogic" />
|
||||||
|
<Entry name="item.type.label.optimization" />
|
||||||
|
<Entry name="item.type.label.usability" />
|
||||||
|
<Entry name="item.type.label.clarity" />
|
||||||
|
<Entry name="item.type.label.missing" />
|
||||||
|
<Entry name="item.type.label.irrelevant" />
|
||||||
|
<Entry name="item.type.label.suggestion" />
|
||||||
|
<Entry name="item.type.label.other" />
|
||||||
|
</FieldItem>
|
||||||
|
<FieldItem id="Severity" default="item.severity.label.trivial">
|
||||||
|
<Entry name="item.label.unset" />
|
||||||
|
<Entry name="item.severity.label.critical" />
|
||||||
|
<Entry name="item.severity.label.major" />
|
||||||
|
<Entry name="item.severity.label.normal" />
|
||||||
|
<Entry name="item.severity.label.minor" />
|
||||||
|
<Entry name="item.severity.label.trivial" />
|
||||||
|
</FieldItem>
|
||||||
|
<FieldItem id="Resolution" default="item.resolution.label.validNeedsfixing">
|
||||||
|
<Entry name="item.label.unset" />
|
||||||
|
<Entry name="item.resolution.label.validNeedsfixing" />
|
||||||
|
<Entry name="item.resolution.label.validFixlater" />
|
||||||
|
<Entry name="item.resolution.label.validDuplicate" />
|
||||||
|
<Entry name="item.resolution.label.validWontfix" />
|
||||||
|
<Entry name="item.resolution.label.invalidWontfix" />
|
||||||
|
<Entry name="item.resolution.label.unsureValidity" />
|
||||||
|
</FieldItem>
|
||||||
|
<FieldItem id="Status" default="item.status.label.open">
|
||||||
|
<Entry name="item.status.label.open" />
|
||||||
|
<Entry name="item.status.label.resolved" />
|
||||||
|
<Entry name="item.status.label.closed" />
|
||||||
|
<Entry name="item.status.label.reopened" />
|
||||||
|
</FieldItem>
|
||||||
|
</FieldItems>
|
||||||
|
<Filters>
|
||||||
|
<Phase name="phase.individual" enabled="true">
|
||||||
|
<Filter name="Interval" value="7" enabled="false" />
|
||||||
|
<Filter name="Reviewer" value="item.reviewer.label.automatic" enabled="true" />
|
||||||
|
<Filter name="Type" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="Severity" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="AssignedTo" value="" enabled="false" />
|
||||||
|
<Filter name="Resolution" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="Status" value="item.status.label.open" enabled="false" />
|
||||||
|
<Filter name="File" value="" enabled="false" />
|
||||||
|
</Phase>
|
||||||
|
<Phase name="phase.team" enabled="true">
|
||||||
|
<Filter name="Interval" value="7" enabled="false" />
|
||||||
|
<Filter name="Reviewer" value="" enabled="false" />
|
||||||
|
<Filter name="Type" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="Severity" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="AssignedTo" value="" enabled="false" />
|
||||||
|
<Filter name="Resolution" value="item.label.unset" enabled="true" />
|
||||||
|
<Filter name="Status" value="item.status.label.open" enabled="false" />
|
||||||
|
<Filter name="File" value="" enabled="false" />
|
||||||
|
</Phase>
|
||||||
|
<Phase name="phase.rework" enabled="true">
|
||||||
|
<Filter name="Interval" value="7" enabled="false" />
|
||||||
|
<Filter name="Reviewer" value="" enabled="false" />
|
||||||
|
<Filter name="Type" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="Severity" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="AssignedTo" value="item.reviewer.label.automatic" enabled="true" />
|
||||||
|
<Filter name="Resolution" value="item.label.unset" enabled="false" />
|
||||||
|
<Filter name="Status" value="item.status.label.open" enabled="true" />
|
||||||
|
<Filter name="File" value="" enabled="false" />
|
||||||
|
</Phase>
|
||||||
|
</Filters>
|
||||||
|
</Review>
|
||||||
|
</Property>
|
||||||
|
|
||||||
85
.project
Normal file
85
.project
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>ModSecurity</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.cdt.make.core.makeBuilder</name>
|
||||||
|
<triggers>clean,full,incremental,</triggers>
|
||||||
|
<arguments>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.append_environment</key>
|
||||||
|
<value>true</value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
|
||||||
|
<value>true</value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.build.command</key>
|
||||||
|
<value>make</value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
|
||||||
|
<value>true</value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.build.target.auto</key>
|
||||||
|
<value>all</value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.stopOnError</key>
|
||||||
|
<value>false</value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.build.location</key>
|
||||||
|
<value></value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.build.target.inc</key>
|
||||||
|
<value>all</value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.build.arguments</key>
|
||||||
|
<value></value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.core.errorOutputParser</key>
|
||||||
|
<value>org.eclipse.cdt.core.MakeErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser;org.eclipse.cdt.core.VCErrorParser;</value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
|
||||||
|
<value>false</value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.environment</key>
|
||||||
|
<value></value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.enabledIncrementalBuild</key>
|
||||||
|
<value>true</value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.build.target.clean</key>
|
||||||
|
<value>clean</value>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary>
|
||||||
|
<key>org.eclipse.cdt.make.core.enableFullBuild</key>
|
||||||
|
<value>true</value>
|
||||||
|
</dictionary>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.cdt.make.core.ScannerConfigBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.make.core.makeNature</nature>
|
||||||
|
<nature>org.eclipse.cdt.make.core.ScannerConfigNature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
3
.settings/org.eclipse.cdt.core.prefs
Normal file
3
.settings/org.eclipse.cdt.core.prefs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#Fri Jan 04 09:57:26 GMT-08:00 2008
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
indexerId=org.eclipse.cdt.core.fastIndexer
|
||||||
290
CHANGES
290
CHANGES
@@ -1,21 +1,140 @@
|
|||||||
?? ???? 2007 - 2.5.0-dev3
|
19 Feb 2008 - 2.5.0
|
||||||
-------------------------
|
-------------------
|
||||||
|
|
||||||
* Added Cygwin to the list of platforms not supporting the hidden
|
* Updated included Core Ruleset to version 1.6.0 which uses 2.5 features.
|
||||||
visibility attribute.
|
|
||||||
|
|
||||||
21 June 2007 - 2.5.0-dev2
|
* Cleaned up and clarified some documentation.
|
||||||
-------------------------
|
|
||||||
|
|
||||||
* Reversioned from 2.2.0 base version to 2.5.0 because of the large changeset.
|
* Updated code to be more portable so it builds with MS VC++.
|
||||||
|
|
||||||
|
* Added unit tests for most operators and transformations.
|
||||||
|
|
||||||
|
* Fixed crash on startup when ENV is improperly used without a parameter.
|
||||||
|
|
||||||
|
* Allow macro resolution in setenv action.
|
||||||
|
|
||||||
|
* The default action is now a minimal "phase:2,log,pass" with no default
|
||||||
|
transformations performed.
|
||||||
|
|
||||||
|
* Implemented SecUploadFileMode to allow setting the mode for uploaded files.
|
||||||
|
|
||||||
|
* Implemented "block" action.
|
||||||
|
|
||||||
|
* Implemented SecRuleUpdateActionById.
|
||||||
|
|
||||||
|
* Fixed removal of phase 5 rules via SecRuleRemoveBy* directives.
|
||||||
|
|
||||||
|
* No longer log the query portion of the URI in the error log as
|
||||||
|
it may contain sensitive data.
|
||||||
|
|
||||||
|
* Build is now 'configure' based: ./configure && make && make install
|
||||||
|
|
||||||
|
* Added support for Lua scripting in the following ways: SecRuleScript
|
||||||
|
can be used to specify a script to execute as a rule, the exec
|
||||||
|
action processes Lua scripts internally, as does the @inspectFile
|
||||||
|
operator. Refer to the documentation for more details.
|
||||||
|
|
||||||
|
* Changed how allow works. Used on its own it now allows phases 1-4. Used
|
||||||
|
with parameter "phase" (e.g. SecAction allow:phase) it only affects
|
||||||
|
the current phase. Used with parameter "request" it allows phases
|
||||||
|
1-2.
|
||||||
|
|
||||||
|
* Fixed issue where only the first phase 5 rule would run when the
|
||||||
|
request was intercepted in an earlier phase.
|
||||||
|
|
||||||
|
* Stricter configuration parsing. Disruptive actions, meta actions and
|
||||||
|
phases are no longer allowed in a chained rule. Disruptive actions,
|
||||||
|
are no longer allowed in a logging phase (phase 5) rule, including
|
||||||
|
inheriting from SecDefaultAction.
|
||||||
|
|
||||||
|
* More efficient collection persistance.
|
||||||
|
|
||||||
|
* Fixed t:escapeSeqDecode to better follow ANSI C escapes.
|
||||||
|
|
||||||
|
* Added t:jsDecode to decode JavScript escape sequences.
|
||||||
|
|
||||||
|
* Added IS_NEW built-in collection variables.
|
||||||
|
|
||||||
|
* New audit log part 'K' logs all matching rules.
|
||||||
|
|
||||||
|
* Implemented SecRequestBodyNoFilesLimit.
|
||||||
|
|
||||||
|
* Enhance handling of the case where we run out of disk space while
|
||||||
|
writing to audit log entry.
|
||||||
|
|
||||||
|
* Added SecComponentSignature to allow other components the ability
|
||||||
|
to append to the logged signature.
|
||||||
|
|
||||||
|
* Added skipAfter:<id> action to allow skipping all rules until a rule
|
||||||
|
with a specified ID is reached. Rule execution then continues after
|
||||||
|
the specified rule.
|
||||||
|
|
||||||
|
* Added SecMarker <id> directive to allow a fixed target for skipAfter.
|
||||||
|
|
||||||
|
* Added ctl:ruleRemoveById action to allow rule removal on a match.
|
||||||
|
|
||||||
|
* Added a @containsWord operator that will match a given string anywhere in
|
||||||
|
the target value, but only on word boundaries.
|
||||||
|
|
||||||
|
* Added a MATCHED_VAR_NAME variable to store the last matched variable name
|
||||||
|
so that it can be more easily used by rules.
|
||||||
|
|
||||||
|
* Added a MATCHED_VAR variable to store the last matched variable value
|
||||||
|
so that it can be more easily used by rules.
|
||||||
|
|
||||||
|
* Fixed expansion of macros when using relative changes with setvar. In
|
||||||
|
addition, added support for expanding macros in the variable name.
|
||||||
|
|
||||||
|
* Situations where ModSecurity will intercept, generate an error or log
|
||||||
|
a level 1-3 message to the debug log are now marked as 'relevant' and may
|
||||||
|
generate an audit log entry.
|
||||||
|
|
||||||
|
* Fixed deprecatevar:var=N/S action so that it decrements N every S seconds
|
||||||
|
as documented instead of decrementing by a rate.
|
||||||
|
|
||||||
|
* Enable ModSecurity to look at partial response bodies. In previous
|
||||||
|
versions, ModSecurity would respond with status code 500 when the
|
||||||
|
response body was too long. Now, if SecResponseBodyLimitAction is
|
||||||
|
set to "ProcessPartial", it will process the part of the response
|
||||||
|
body received up until that point but send the rest without buffering.
|
||||||
|
|
||||||
|
* ModSecurity will now process phases 3 and 4 even when request processing
|
||||||
|
is interrupted (either by Apache - e.g. by responding with 400, 401
|
||||||
|
or 403, or by ModSecurity itself).
|
||||||
|
|
||||||
|
* Fixed the base64decode transformation function to not return extra
|
||||||
|
characters at the end.
|
||||||
|
|
||||||
|
* Return from the output filter with an error in addition to setting
|
||||||
|
up the HTTP error status in the output data.
|
||||||
|
|
||||||
|
* Used new Apache API calls to get the server version/banner when available.
|
||||||
|
|
||||||
|
* Added "logdata" meta action to allow logging of raw transaction data.
|
||||||
|
|
||||||
|
* Added TX_SEVERITY that keeps track of the highest severity
|
||||||
|
for any matched rules so far.
|
||||||
|
|
||||||
|
* Added ARGS_GET, ARGS_POST, ARGS_GET_NAMES, ARGS_POST_NAMES variables to
|
||||||
|
allow seperation of GET and POST arguments.
|
||||||
|
|
||||||
|
* Added an Apache define (MODSEC_2.5) so that you can conditionally include
|
||||||
|
directives based on the ModSecurity major/minor versions with IfDefine.
|
||||||
|
|
||||||
|
* Added MODSEC_BUILD variable that contains the numeric build value based
|
||||||
|
on the ModSecurity version.
|
||||||
|
|
||||||
|
* Enhanced debug logging by displaying more data on rule execution. All
|
||||||
|
invoked rules are now logged in the debug log at level 5.
|
||||||
|
|
||||||
|
* Stricter validation for @validateUtf8Encoding.
|
||||||
|
|
||||||
|
* No longer process Apache internal subrequests.
|
||||||
|
|
||||||
|
* Fixed warnings on Solaris and/or 64bit builds.
|
||||||
|
|
||||||
* Added @within string comparison operator with support for macro expansion.
|
* Added @within string comparison operator with support for macro expansion.
|
||||||
|
|
||||||
* Removed experimental variable RESPONSE_CONTENT_ENCODING which was not
|
|
||||||
working as intended.
|
|
||||||
|
|
||||||
* Update included core rules to latest version.
|
|
||||||
|
|
||||||
* Do not trigger "pause" action for internal requests.
|
* Do not trigger "pause" action for internal requests.
|
||||||
|
|
||||||
* Added matching rule filename and line number to audit log.
|
* Added matching rule filename and line number to audit log.
|
||||||
@@ -24,56 +143,14 @@
|
|||||||
an alternate set based matching engine (Aho-Corasick) to perform faster
|
an alternate set based matching engine (Aho-Corasick) to perform faster
|
||||||
phrase type matches such as black/white lists, spam keywords, etc.
|
phrase type matches such as black/white lists, spam keywords, etc.
|
||||||
|
|
||||||
* Cache transformations per-request/phase so they are not repeated.
|
* Allow caching transformations per-request/phase so they are not repeated.
|
||||||
|
|
||||||
* Fixed issue with requests that use internal requests. These had the
|
* Added Solaris and Cygwin to the list of platforms not supporting the hidden
|
||||||
potential to be intercepted incorrectly when other Apache httpd modules
|
|
||||||
that used internal requests were used with mod_security.
|
|
||||||
|
|
||||||
* Added Solaris to the list of platforms not supporting the hidden
|
|
||||||
visibility attribute.
|
|
||||||
|
|
||||||
* Removed excessive debug log entries about "capture" action.
|
|
||||||
|
|
||||||
* Fixed decoding full-width unicode in t:urlDecodeUni.
|
|
||||||
|
|
||||||
* Lessen some overhead of debugging messages and calculations
|
|
||||||
|
|
||||||
* Removed strnlen() calls for non-GNU platforms.
|
|
||||||
|
|
||||||
|
|
||||||
14 June 2007 - 2.1.2-rc1
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
* Update included core rules to latest version.
|
|
||||||
|
|
||||||
* Do not trigger "pause" action for internal requests.
|
|
||||||
|
|
||||||
* Fixed issue with requests that use internal requests. These had the
|
|
||||||
potential to be intercepted incorrectly when other Apache httpd modules
|
|
||||||
that used internal requests were used with mod_security.
|
|
||||||
|
|
||||||
* Added Solaris to the list of platforms not supporting the hidden
|
|
||||||
visibility attribute.
|
visibility attribute.
|
||||||
|
|
||||||
* Fixed decoding full-width unicode in t:urlDecodeUni.
|
* Fixed decoding full-width unicode in t:urlDecodeUni.
|
||||||
|
|
||||||
* Lessen some overhead of debugging messages and calculations.
|
* Add SecGeoLookupDB, @geoLookups and GEO collection to support
|
||||||
|
|
||||||
* Do not try to intercept a request after a failed rule. This fixes the
|
|
||||||
issue associated with an "Internal Error: Asked to intercept request
|
|
||||||
but was_intercepted is zero" error message.
|
|
||||||
|
|
||||||
* Added SecAuditLog2 directive to allow redundent concurrent audit log
|
|
||||||
index files. This will allow sending audit data to two consoles, etc.
|
|
||||||
|
|
||||||
* Small performance improvement in memory management for rule execution.
|
|
||||||
|
|
||||||
|
|
||||||
11 May 2007 - 2.2.0-dev1
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
* Add SecGeoLookupsDb, @geoLookups and GEO collection to support
|
|
||||||
geographical lookups by IP/host.
|
geographical lookups by IP/host.
|
||||||
|
|
||||||
* Do not try to intercept a request after a failed rule. This fixes the
|
* Do not try to intercept a request after a failed rule. This fixes the
|
||||||
@@ -86,9 +163,6 @@
|
|||||||
|
|
||||||
* Exported API for registering custom variables. Example in api directory.
|
* Exported API for registering custom variables. Example in api directory.
|
||||||
|
|
||||||
* Added experimental variables RESPONSE_CONTENT_LENGTH, RESPONSE_CONTENT_TYPE,
|
|
||||||
and RESPONSE_CONTENT_ENCODING.
|
|
||||||
|
|
||||||
* Added experimental support for content injection. Directive
|
* Added experimental support for content injection. Directive
|
||||||
SecContentInjection (On|Off) controls whether injection is taking place.
|
SecContentInjection (On|Off) controls whether injection is taking place.
|
||||||
Actions "prepend" and "append" inject content when executed. Do note that
|
Actions "prepend" and "append" inject content when executed. Do note that
|
||||||
@@ -120,15 +194,101 @@
|
|||||||
|
|
||||||
* Do not log 'allow' action as intercepted in the debug log.
|
* Do not log 'allow' action as intercepted in the debug log.
|
||||||
|
|
||||||
* Write debug log messages when "capture" is set, but the regex does not
|
|
||||||
capture and vice-versa.
|
|
||||||
|
|
||||||
* Small performance improvement in memory management for rule execution.
|
|
||||||
|
|
||||||
* Fixed some collection variable names not printing with the parameter
|
* Fixed some collection variable names not printing with the parameter
|
||||||
and/or counting operator in the debug log.
|
and/or counting operator in the debug log.
|
||||||
|
|
||||||
|
|
||||||
|
19 Feb 2008 - 2.1.6
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* Fixed crash on startup when ENV is improperly used without a parameter.
|
||||||
|
|
||||||
|
* Allow macro resolution in setenv action.
|
||||||
|
|
||||||
|
* Implemented SecUploadFileMode to allow setting the mode for uploaded files.
|
||||||
|
|
||||||
|
* No longer log the query portion of the URI in the error log as
|
||||||
|
it may contain sensitive data.
|
||||||
|
|
||||||
|
|
||||||
|
10 Jan 2008 - 2.1.5
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* Updated included Core Ruleset to version 1.5.1.
|
||||||
|
|
||||||
|
* Phase 5 rules can now be removed via SecRuleRemoveBy* directives.
|
||||||
|
|
||||||
|
* Fixed issue where only the first phase 5 rule would run when the
|
||||||
|
request was intercepted in an earlier phase.
|
||||||
|
|
||||||
|
* Fixed configuration parsing so that disruptive actions, meta actions
|
||||||
|
and phases are not allowed in a chained rule (as originally intended).
|
||||||
|
|
||||||
|
* Fixed t:escapeSeqDecode to better follow ANSI C escapes.
|
||||||
|
|
||||||
|
|
||||||
|
27 Nov 2007 - 2.1.4
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* Updated included Core Ruleset to version 1.5 and noted in the docs that
|
||||||
|
XML support is required to use the rules without modification.
|
||||||
|
|
||||||
|
* Fixed an evasion FP, mistaking a multipart non-boundary for a boundary.
|
||||||
|
|
||||||
|
* Fixed multiple warnings on Solaris and/or 64bit builds.
|
||||||
|
|
||||||
|
* Do not process subrequests in phase 2-4, but do hand off the request data.
|
||||||
|
|
||||||
|
* Fixed a blocking FP in the multipart parser, which affected Safari.
|
||||||
|
|
||||||
|
|
||||||
|
11 Sep 2007 - 2.1.3
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* Updated multipart parsing code adding variables to allow checking
|
||||||
|
for various parsing issues (request body abnormalities).
|
||||||
|
|
||||||
|
* Allow mod_rpaf and mod_extract_forwarded2 to work before ModSecurity.
|
||||||
|
|
||||||
|
* Quiet some compiler warnings.
|
||||||
|
|
||||||
|
* Do not block internal ErrorDocument requests after blocking request.
|
||||||
|
|
||||||
|
* Added ability to compile without an external API (use -DNO_MODSEC_API).
|
||||||
|
|
||||||
|
|
||||||
|
27 Jul 2007 - 2.1.2
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* Cleaned up and clarified some documentation.
|
||||||
|
|
||||||
|
* Update included core rules to latest version (1.4.3).
|
||||||
|
|
||||||
|
* Enhanced ability to alert/audit failed requests.
|
||||||
|
|
||||||
|
* Do not trigger "pause" action for internal requests.
|
||||||
|
|
||||||
|
* Fixed issue with requests that use internal requests. These had the
|
||||||
|
potential to be intercepted incorrectly when other Apache httpd modules
|
||||||
|
that used internal requests were used with mod_security.
|
||||||
|
|
||||||
|
* Added Solaris and Cygwin to the list of platforms not supporting the hidden
|
||||||
|
visibility attribute.
|
||||||
|
|
||||||
|
* Fixed decoding full-width unicode in t:urlDecodeUni.
|
||||||
|
|
||||||
|
* Lessen some overhead of debugging messages and calculations.
|
||||||
|
|
||||||
|
* Do not try to intercept a request after a failed rule. This fixes the
|
||||||
|
issue associated with an "Internal Error: Asked to intercept request
|
||||||
|
but was_intercepted is zero" error message.
|
||||||
|
|
||||||
|
* Added SecAuditLog2 directive to allow redundent concurrent audit log
|
||||||
|
index files. This will allow sending audit data to two consoles, etc.
|
||||||
|
|
||||||
|
* Small performance improvement in memory management for rule execution.
|
||||||
|
|
||||||
|
|
||||||
11 Apr 2007 - 2.1.1
|
11 Apr 2007 - 2.1.1
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
|
|
||||||
ModSecurity for Apache is an open source product, released under terms of
|
ModSecurity for Apache is an open source product, released under terms of
|
||||||
the General Public Licence, Version 2 (GPLv2). Please refer to the
|
the General Public Licence, Version 2 (GPLv2). Please refer to the
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
builddir = .
|
|
||||||
|
|
||||||
# To successfully build ModSecurity for Apache you will
|
|
||||||
# need to configure the "top_dir" variable properly. The
|
|
||||||
# correct value will differ from system to system.
|
|
||||||
#
|
|
||||||
# If you've installed Apache manually simply point to the
|
|
||||||
# installation directory. Most pre-packaged installations
|
|
||||||
# consist of two parts. One contains the binaries, and the
|
|
||||||
# other contains the "development" files. You will typically
|
|
||||||
# need both.
|
|
||||||
#
|
|
||||||
# The list below may help:
|
|
||||||
#
|
|
||||||
# Fedora Core - /usr/lib/httpd (the httpd-devel package must be installed)
|
|
||||||
#
|
|
||||||
# Debian - /usr/share/apache2 (apache2-prefork-dev or apache2-threaded-dev
|
|
||||||
# needed, depending on your installation type)
|
|
||||||
#
|
|
||||||
top_dir = /apps/apache22
|
|
||||||
|
|
||||||
top_srcdir = ${top_dir}
|
|
||||||
top_builddir = ${top_dir}
|
|
||||||
|
|
||||||
include ${top_builddir}/build/special.mk
|
|
||||||
|
|
||||||
APXS = apxs
|
|
||||||
APACHECTL = apachectl
|
|
||||||
|
|
||||||
INCLUDES = -I /usr/include/libxml2
|
|
||||||
DEFS = -DWITH_LIBXML2
|
|
||||||
#DEFS = -DWITH_LIBXML2 -DDEBUG_CONF
|
|
||||||
#DEFS = -DWITH_LIBXML2 -DCACHE_DEBUG
|
|
||||||
#LIBS = -Lmy/lib/dir -lmylib
|
|
||||||
|
|
||||||
CFLAGS = -O2 -g -Wuninitialized -Wall -Wmissing-prototypes -Wshadow -Wunused-variable -Wunused-value -Wchar-subscripts -Wsign-compare
|
|
||||||
|
|
||||||
all: local-shared-build
|
|
||||||
|
|
||||||
clean:
|
|
||||||
-rm -f *.o *.lo *.slo *.la *~ .libs
|
|
||||||
|
|
||||||
127
apache2/Makefile.in
Normal file
127
apache2/Makefile.in
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# Makefile for ModSecurity
|
||||||
|
|
||||||
|
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
|
||||||
|
re re_operators re_actions re_tfns re_variables \
|
||||||
|
msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \
|
||||||
|
persist_dbm msc_reqbody pdf_protect msc_geo acmp msc_lua
|
||||||
|
|
||||||
|
MSC_TEST = re re_operators re_actions re_tfns re_variables \
|
||||||
|
msc_logging msc_xml msc_multipart modsecurity \
|
||||||
|
msc_parsers msc_util msc_pcre persist_dbm \
|
||||||
|
msc_reqbody msc_geo acmp msc_lua
|
||||||
|
|
||||||
|
MOD_SECURITY2_H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h \
|
||||||
|
msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \
|
||||||
|
msc_geo.h acmp.h utf8tables.h msc_lua.h
|
||||||
|
|
||||||
|
CC = @APXS_CC@
|
||||||
|
LIBTOOL = @APXS_LIBTOOL@
|
||||||
|
PERL = @PERL@
|
||||||
|
EXTRA_CFLAGS = @EXTRA_CFLAGS@
|
||||||
|
MODSEC_EXTRA_CFLAGS = @MODSEC_EXTRA_CFLAGS@
|
||||||
|
|
||||||
|
### Note: must be in APXS format: -Wc,-flag
|
||||||
|
APXS_EXTRA_CFLAGS = @APXS_EXTRA_CFLAGS@
|
||||||
|
MODSEC_APXS_EXTRA_CFLAGS = @MODSEC_APXS_EXTRA_CFLAGS@
|
||||||
|
|
||||||
|
APXS = @APXS@
|
||||||
|
APXS_WRAPPER = @APXS_WRAPPER@
|
||||||
|
APXS_INCLUDES = @APXS_INCLUDES@
|
||||||
|
APXS_CFLAGS = @APXS_CFLAGS@
|
||||||
|
APXS_LDFLAGS = @APXS_LDFLAGS@
|
||||||
|
APXS_LIBS = @APXS_LIBS@
|
||||||
|
|
||||||
|
PCRE_CFLAGS = @PCRE_CFLAGS@
|
||||||
|
PCRE_LIBS = @PCRE_LIBS@
|
||||||
|
|
||||||
|
LUA_CFLAGS = @LUA_CFLAGS@
|
||||||
|
LUA_LIBS = @LUA_LIBS@
|
||||||
|
|
||||||
|
LIBXML_CFLAGS = @LIBXML_CFLAGS@
|
||||||
|
LIBXML_LIBS = @LIBXML_LIBS@
|
||||||
|
|
||||||
|
APR_CFLAGS = @APR_CFLAGS@
|
||||||
|
APR_LDFLAGS = @APR_LDFLAGS@
|
||||||
|
APR_LIBS = @APR_LIBS@
|
||||||
|
APR_LINK_LD = @APR_LINK_LD@
|
||||||
|
|
||||||
|
APU_CFLAGS = @APU_CFLAGS@
|
||||||
|
APU_LDFLAGS = @APU_LDFLAGS@
|
||||||
|
APU_LIBS = @APU_LIBS@
|
||||||
|
APU_LINK_LD = @APU_LINK_LD@
|
||||||
|
|
||||||
|
CPPFLAGS = @CPPFLAGS@ $(PCRE_CFLAGS) $(LIBXML_CFLAGS) $(LUA_CFLAGS)
|
||||||
|
LIBS = @LIBS@ $(PCRE_LIBS) $(LIBXML_LIBS) $(LUA_LIBS)
|
||||||
|
LDFLAGS = @LDFLAGS@
|
||||||
|
CFLAGS = @CFLAGS@
|
||||||
|
|
||||||
|
COMPILE_APACHE_MOD = $(APXS_WRAPPER) -c $(CPPFLAGS) $(LDFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
INSTALL_MOD_SHARED = $(APXS_WRAPPER) -i
|
||||||
|
|
||||||
|
all: mod_security2.la
|
||||||
|
|
||||||
|
install: install-mods
|
||||||
|
|
||||||
|
clean-extras:
|
||||||
|
@for dir in mlogc-src; do \
|
||||||
|
if test -d $$dir; then \
|
||||||
|
$(MAKE) -C $$dir clean; \
|
||||||
|
fi; \
|
||||||
|
done
|
||||||
|
@rm -rf ../tools/mlogc ../tools/mlogc-static
|
||||||
|
|
||||||
|
clean: clean-extras
|
||||||
|
@rm -rf *.la *.lo *.o *.slo .libs msc_test msc-test-debug.log
|
||||||
|
|
||||||
|
maintainer-clean: clean
|
||||||
|
@rm -rf Makefile mlogc-src/Makefile t/run-tests.pl config config.log config.status configure mod_security2_config.h ../tools/*.pl autoscan.log configure.scan build/libtool.m4 build/config.guess build/config.sub build/ltmain.sh build/apxs-wrapper
|
||||||
|
|
||||||
|
distclean: maintainer-clean
|
||||||
|
|
||||||
|
install-mods: mod_security2.la
|
||||||
|
$(INSTALL_MOD_SHARED) mod_security2.la
|
||||||
|
|
||||||
|
${MOD_SECURITY2:=.slo}: $(MOD_SECURITY2_H)
|
||||||
|
${MOD_SECURITY2:=.lo}: $(MOD_SECURITY2_H)
|
||||||
|
${MOD_SECURITY2:=.o}: $(MOD_SECURITY2_H})
|
||||||
|
|
||||||
|
mod_security2.la: $(MOD_SECURITY2_H) *.c
|
||||||
|
@src=""; \
|
||||||
|
for f in $(MOD_SECURITY2); do \
|
||||||
|
src="$$src $$f.c"; \
|
||||||
|
done; \
|
||||||
|
$(COMPILE_APACHE_MOD) $(APXS_EXTRA_CFLAGS) $(MODSEC_APXS_EXTRA_CFLAGS) $$src
|
||||||
|
|
||||||
|
### MLogC
|
||||||
|
mlogc:
|
||||||
|
@$(MAKE) -C mlogc-src mlogc \
|
||||||
|
&& cp -p mlogc-src/mlogc ../tools \
|
||||||
|
&& echo \
|
||||||
|
&& echo "Successfully built \"mlogc\" in ../tools." \
|
||||||
|
&& echo "See: mlogc-src/INSTALL" \
|
||||||
|
&& echo
|
||||||
|
|
||||||
|
mlogc-static:
|
||||||
|
@$(MAKE) -C mlogc-src static \
|
||||||
|
&& cp -p mlogc-src/mlogc ../tools/mlogc-static \
|
||||||
|
&& echo \
|
||||||
|
&& echo "Successfully built \"mlogc-static\" in ../tools." \
|
||||||
|
&& echo "See: mlogc-src/INSTALL" \
|
||||||
|
&& echo
|
||||||
|
|
||||||
|
### Experimental Test Framework (*NIX only right now)
|
||||||
|
msc_test.lo: msc_test.c
|
||||||
|
$(LIBTOOL) --mode=compile $(CC) $(APXS_CFLAGS) $(EXTRA_CFLAGS) $(MODSEC_EXTRA_CFLAGS) $(CPPFLAGS) $(APR_CFLAGS) $(APU_CFLAGS) -o msc_test.lo -c msc_test.c
|
||||||
|
|
||||||
|
msc_test: $(TESTOBJS) msc_test.lo
|
||||||
|
@objs=""; \
|
||||||
|
for f in $(MSC_TEST); do \
|
||||||
|
objs="$$objs $$f.lo"; \
|
||||||
|
done; \
|
||||||
|
$(LIBTOOL) --mode=link $(CC) $$objs -o msc_test msc_test.lo $(LDFLAGS) $(LIBS) $(APR_LINK_LD) $(APU_LINK_LD)
|
||||||
|
|
||||||
|
test: t/run-tests.pl msc_test
|
||||||
|
@rm -f msc-test-debug.log; \
|
||||||
|
$(PERL) t/run-tests.pl
|
||||||
|
|
||||||
@@ -1,43 +1,72 @@
|
|||||||
|
###########################################################################
|
||||||
|
### You Will need to modify the following variables for your system
|
||||||
|
###########################################################################
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
# Path to Apache installation
|
# Path to Apache httpd installation
|
||||||
BASE = "C:/Program Files/Apache Group/Apache2/"
|
BASE = C:\Apache2
|
||||||
|
|
||||||
CC = cl
|
# Paths to required libraries
|
||||||
|
LIBXML2 = C:\work\libxml2-2.6.31
|
||||||
|
LUA = C:\work\lua-5.1.3
|
||||||
|
PCRE = C:\work\httpd-2.2.8\srclib\pcre
|
||||||
|
|
||||||
# Add -DWITH_LIBXML2 below if you want to link against libxml2
|
# Linking libraries
|
||||||
DEFS = /nologo /Od /LD /W3 -DWIN32 -DWINNT
|
LIBS = $(BASE)\lib\libhttpd.lib \
|
||||||
DLL = mod_security2.dll
|
$(BASE)\lib\libapr-1.lib \
|
||||||
|
$(BASE)\lib\libaprutil-1.lib \
|
||||||
|
$(PCRE)\LibR\pcre.lib \
|
||||||
|
$(LIBXML2)\win32\bin.msvc\libxml2.lib \
|
||||||
|
$(LUA)\lua5.1.lib \
|
||||||
|
wsock32.lib
|
||||||
|
|
||||||
# Path to the headers - configure the libxml2 include path
|
###########################################################################
|
||||||
INCLUDES = -I. -I$(BASE)\include -IC:\libxml2\include
|
###########################################################################
|
||||||
|
|
||||||
CFLAGS= -O $(INCLUDES) $(DEFS)
|
CC = cL
|
||||||
|
|
||||||
# Paths to the required libraries
|
MT = mt
|
||||||
# Use the line below if you want to link against libxml2
|
|
||||||
# LIBS = $(BASE)\lib\libhttpd.lib $(BASE)\lib\libapr.lib $(BASE)\lib\libaprutil.lib $(BASE)\lib\pcre.lib C:\libxml2\lib\libxml2.lib
|
|
||||||
|
|
||||||
# Use the line belof if you don't want to link against libxml2
|
DEFS = /nologo /O2 /LD /W3 /wd4244 -DWIN32 -DWINNT -Dinline=APR_INLINE
|
||||||
LIBS = $(BASE)\lib\libhttpd.lib $(BASE)\lib\libapr.lib $(BASE)\lib\libaprutil.lib $(BASE)\lib\pcre.lib
|
|
||||||
|
|
||||||
OBJS = mod_security2.obj apache2_config.obj apache2_io.obj apache2_util.obj \
|
DLL = mod_security2.so
|
||||||
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 \
|
INCLUDES = -I. \
|
||||||
msc_util.obj msc_pcre.obj persist_dbm.obj msc_reqbody.obj pdf_protect.obj \
|
-I$(PCRE)\include -I$(PCRE) \
|
||||||
msc_geo.obj acmp.obj
|
-I$(LIBXML2)\include \
|
||||||
|
-I$(LUA)\include -I$(LUA) \
|
||||||
|
-I$(BASE)\include
|
||||||
|
|
||||||
|
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 pdf_protect.obj msc_geo.obj acmp.obj msc_lua.obj
|
||||||
|
|
||||||
all: $(DLL)
|
all: $(DLL)
|
||||||
|
|
||||||
dll: $(DLL)
|
dll: $(DLL)
|
||||||
|
|
||||||
|
mod_security2_config.h: mod_security2_config.hw
|
||||||
|
@echo off
|
||||||
|
type mod_security2_config.hw > mod_security2_config.h
|
||||||
|
|
||||||
.c.obj:
|
.c.obj:
|
||||||
$(CC) $(CFLAGS) -c $< -Fo$@
|
$(CC) $(CFLAGS) -c $< -Fo$@
|
||||||
|
|
||||||
.cpp.obj:
|
.cpp.obj:
|
||||||
$(CC) $(CFLAGS) -c $< -Fo$@
|
$(CC) $(CFLAGS) -c $< -Fo$@
|
||||||
|
|
||||||
$(DLL): $(OBJS)
|
$(DLL): mod_security2_config.h $(OBJS)
|
||||||
$(CC) $(CFLAGS) -LD $(OBJS) -Fe$(DLL) $(LIBS) /link /NODEFAULTLIB:MSVCRT
|
$(CC) $(CFLAGS) $(LDFLAGS) -LD $(OBJS) -Fe$(DLL) $(LIBS) /link
|
||||||
|
IF EXIST $(DLL).manifest $(MT) -manifest $(DLL).manifest -outputresource:$(DLL);2
|
||||||
|
|
||||||
|
install: $(DLL)
|
||||||
|
copy $(DLL) $(BASE)\modules
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
del $(OBJS) *.dll *.lib *.pdb *.idb *.ilk *.exp *.res *.rc *.bin
|
del $(OBJS) $(DLL) *.dll *.lib *.pdb *.idb *.ilk *.exp *.res *.rc *.bin mod_security2_config.h *.manifest
|
||||||
|
|||||||
153
apache2/acmp.c
153
apache2/acmp.c
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -9,7 +9,17 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "acmp.h"
|
#include "acmp.h"
|
||||||
|
|
||||||
|
#ifdef ACMP_USE_UTF8
|
||||||
|
/* UTF support */
|
||||||
#include "utf8tables.h"
|
#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 <apr_tables.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -58,7 +68,9 @@ struct acmp_btree_node_t {
|
|||||||
* Data related to parser, not to individual nodes
|
* Data related to parser, not to individual nodes
|
||||||
*/
|
*/
|
||||||
struct ACMP {
|
struct ACMP {
|
||||||
|
#ifdef ACMP_USE_UTF8
|
||||||
int is_utf8;
|
int is_utf8;
|
||||||
|
#endif
|
||||||
int is_case_sensitive;
|
int is_case_sensitive;
|
||||||
apr_pool_t *parent_pool;
|
apr_pool_t *parent_pool;
|
||||||
apr_pool_t *pool;
|
apr_pool_t *pool;
|
||||||
@@ -92,6 +104,7 @@ struct ACMP {
|
|||||||
* Functions for UTF-8 support
|
* Functions for UTF-8 support
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef ACMP_USE_UTF8
|
||||||
/**
|
/**
|
||||||
* Returns length of utf-8 sequence based on its first byte
|
* Returns length of utf-8 sequence based on its first byte
|
||||||
*/
|
*/
|
||||||
@@ -152,6 +165,7 @@ static long utf8_lcase(acmp_utf8_char_t ucs_code) {
|
|||||||
}
|
}
|
||||||
return ucs_code;
|
return ucs_code;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
@@ -163,7 +177,11 @@ static long utf8_lcase(acmp_utf8_char_t ucs_code) {
|
|||||||
* Returns length of given string for parser's encoding
|
* Returns length of given string for parser's encoding
|
||||||
*/
|
*/
|
||||||
static size_t acmp_strlen(ACMP *parser, const char *str) {
|
static size_t acmp_strlen(ACMP *parser, const char *str) {
|
||||||
|
#ifdef ACMP_USE_UTF8
|
||||||
return (parser->is_utf8 == 0) ? strlen(str) : utf8_strlen(str);
|
return (parser->is_utf8 == 0) ? strlen(str) : utf8_strlen(str);
|
||||||
|
#else
|
||||||
|
return strlen(str);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -176,15 +194,18 @@ static void acmp_strtoucs(ACMP *parser, const char *str, acmp_utf8_char_t *ucs_c
|
|||||||
int i;
|
int i;
|
||||||
const char *c = str;
|
const char *c = str;
|
||||||
|
|
||||||
if (parser->is_utf8 == 0) {
|
#ifdef ACMP_USE_UTF8
|
||||||
|
if (parser->is_utf8) {
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
*ucs_chars++ = *c++;
|
*(ucs_chars++) = utf8_decodechar(c);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
*ucs_chars++ = utf8_decodechar(c);
|
|
||||||
c += utf8_seq_len(c);
|
c += utf8_seq_len(c);
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
*(ucs_chars++) = *(c++);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,12 +226,15 @@ static acmp_node_t *acmp_child_for_code(acmp_node_t *parent_node, acmp_utf8_char
|
|||||||
* Adds node to parent node, if it is not already there
|
* 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) {
|
static void acmp_add_node_to_parent(acmp_node_t *parent, acmp_node_t *child) {
|
||||||
|
acmp_node_t *node = NULL;
|
||||||
|
|
||||||
child->parent = parent;
|
child->parent = parent;
|
||||||
if (parent->child == NULL) {
|
if (parent->child == NULL) {
|
||||||
parent->child = child;
|
parent->child = child;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
acmp_node_t *node = parent->child;
|
|
||||||
|
node = parent->child;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (node == child) return;
|
if (node == child) return;
|
||||||
if (node->sibling == NULL) {
|
if (node->sibling == NULL) {
|
||||||
@@ -241,6 +265,7 @@ static void acmp_copy_nodes_recursive(acmp_node_t *from, acmp_node_t *to, apr_po
|
|||||||
acmp_node_t *old_node = from->child, *new_node, *nn2;
|
acmp_node_t *old_node = from->child, *new_node, *nn2;
|
||||||
if (old_node == NULL) return;
|
if (old_node == NULL) return;
|
||||||
nn2 = apr_pcalloc(pool, sizeof(acmp_node_t));
|
nn2 = apr_pcalloc(pool, sizeof(acmp_node_t));
|
||||||
|
/* ENH: Check alloc succeded */
|
||||||
acmp_clone_node_no_state(old_node, nn2);
|
acmp_clone_node_no_state(old_node, nn2);
|
||||||
nn2->parent = to;
|
nn2->parent = to;
|
||||||
to->child = nn2;
|
to->child = nn2;
|
||||||
@@ -250,6 +275,7 @@ static void acmp_copy_nodes_recursive(acmp_node_t *from, acmp_node_t *to, apr_po
|
|||||||
old_node = old_node->sibling;
|
old_node = old_node->sibling;
|
||||||
if (old_node == NULL) break;
|
if (old_node == NULL) break;
|
||||||
new_node = apr_pcalloc(pool, sizeof(acmp_node_t));
|
new_node = apr_pcalloc(pool, sizeof(acmp_node_t));
|
||||||
|
/* ENH: Check alloc succeded */
|
||||||
acmp_clone_node_no_state(old_node, new_node);
|
acmp_clone_node_no_state(old_node, new_node);
|
||||||
new_node->parent = to;
|
new_node->parent = to;
|
||||||
nn2->sibling = new_node;
|
nn2->sibling = new_node;
|
||||||
@@ -275,7 +301,6 @@ static inline acmp_node_t *acmp_btree_find(acmp_node_t *node, acmp_utf8_char_t l
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static inline acmp_node_t *acmp_goto(acmp_node_t *node, acmp_utf8_char_t letter) {
|
static inline acmp_node_t *acmp_goto(acmp_node_t *node, acmp_utf8_char_t letter) {
|
||||||
//return acmp_child_for_code(node, letter);
|
|
||||||
return acmp_btree_find(node, letter);
|
return acmp_btree_find(node, letter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,16 +336,22 @@ static void acmp_add_btree_leaves(acmp_btree_node_t *node, acmp_node_t *nodes[],
|
|||||||
if ((pos - lb) > 1) {
|
if ((pos - lb) > 1) {
|
||||||
left = lb + (pos - lb) / 2;
|
left = lb + (pos - lb) / 2;
|
||||||
node->left = apr_pcalloc(pool, sizeof(acmp_btree_node_t));
|
node->left = apr_pcalloc(pool, sizeof(acmp_btree_node_t));
|
||||||
|
/* ENH: Check alloc succeded */
|
||||||
node->left->node = nodes[left];
|
node->left->node = nodes[left];
|
||||||
node->left->letter = nodes[left]->letter;
|
node->left->letter = nodes[left]->letter;
|
||||||
/* printf("%c ->left %c \n", node->node->letter, node->left->node->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) {
|
if ((rb - pos) > 1) {
|
||||||
right = pos + (rb - pos) / 2;
|
right = pos + (rb - pos) / 2;
|
||||||
node->right = apr_pcalloc(pool, sizeof(acmp_btree_node_t));
|
node->right = apr_pcalloc(pool, sizeof(acmp_btree_node_t));
|
||||||
|
/* ENH: Check alloc succeded */
|
||||||
node->right->node = nodes[right];
|
node->right->node = nodes[right];
|
||||||
node->right->letter = nodes[right]->letter;
|
node->right->letter = nodes[right]->letter;
|
||||||
/* printf("%c ->right %c \n", node->node->letter, node->right->node->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) {
|
if (node->right != NULL) {
|
||||||
acmp_add_btree_leaves(node->right, nodes, right, pos, rb, pool);
|
acmp_add_btree_leaves(node->right, nodes, right, pos, rb, pool);
|
||||||
@@ -336,25 +367,36 @@ static void acmp_add_btree_leaves(acmp_btree_node_t *node, acmp_node_t *nodes[],
|
|||||||
static void acmp_build_binary_tree(ACMP *parser, acmp_node_t *node) {
|
static void acmp_build_binary_tree(ACMP *parser, acmp_node_t *node) {
|
||||||
apr_size_t count, i, j;
|
apr_size_t count, i, j;
|
||||||
acmp_node_t *child = node->child;
|
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++;
|
for (count = 0; child != NULL; child = child->sibling) count++;
|
||||||
acmp_node_t *nodes[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;
|
child = node->child;
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
nodes[i] = child;
|
nodes[i] = child;
|
||||||
child = child->sibling;
|
child = child->sibling;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* We have array with all children of the node and number of those children
|
/* We have array with all children of the node and number of those children
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < count - 1; i++)
|
for (i = 0; i < count - 1; i++)
|
||||||
for (j = i + 1; j < count; j++) {
|
for (j = i + 1; j < count; j++) {
|
||||||
|
acmp_node_t *tmp;
|
||||||
|
|
||||||
if (nodes[i]->letter < nodes[j]->letter) continue;
|
if (nodes[i]->letter < nodes[j]->letter) continue;
|
||||||
acmp_node_t *tmp = nodes[i];
|
|
||||||
|
tmp = nodes[i];
|
||||||
nodes[i] = nodes[j];
|
nodes[i] = nodes[j];
|
||||||
nodes[j] = tmp;
|
nodes[j] = tmp;
|
||||||
}
|
}
|
||||||
node->btree = apr_pcalloc(parser->pool, sizeof(acmp_btree_node_t));
|
node->btree = apr_pcalloc(parser->pool, sizeof(acmp_btree_node_t));
|
||||||
apr_size_t pos = count / 2;
|
/* ENH: Check alloc succeded */
|
||||||
|
pos = count / 2;
|
||||||
node->btree->node = nodes[pos];
|
node->btree->node = nodes[pos];
|
||||||
node->btree->letter = nodes[pos]->letter;
|
node->btree->letter = nodes[pos]->letter;
|
||||||
acmp_add_btree_leaves(node->btree, nodes, pos, -1, count, parser->pool);
|
acmp_add_btree_leaves(node->btree, nodes, pos, -1, count, parser->pool);
|
||||||
@@ -368,10 +410,11 @@ static void acmp_build_binary_tree(ACMP *parser, acmp_node_t *node) {
|
|||||||
*/
|
*/
|
||||||
static apr_status_t acmp_connect_fail_branches(ACMP *parser) {
|
static apr_status_t acmp_connect_fail_branches(ACMP *parser) {
|
||||||
/* Already connected ? */
|
/* Already connected ? */
|
||||||
if (parser->is_failtree_done != 0) return APR_SUCCESS;
|
|
||||||
acmp_node_t *child, *node, *goto_node;
|
acmp_node_t *child, *node, *goto_node;
|
||||||
apr_array_header_t *arr, *arr2, *tmp;
|
apr_array_header_t *arr, *arr2, *tmp;
|
||||||
|
|
||||||
|
if (parser->is_failtree_done != 0) return APR_SUCCESS;
|
||||||
|
|
||||||
parser->root_node->text = "";
|
parser->root_node->text = "";
|
||||||
arr = apr_array_make(parser->pool, 32, sizeof(acmp_node_t *));
|
arr = apr_array_make(parser->pool, 32, sizeof(acmp_node_t *));
|
||||||
arr2 = apr_array_make(parser->pool, 32, sizeof(acmp_node_t *));
|
arr2 = apr_array_make(parser->pool, 32, sizeof(acmp_node_t *));
|
||||||
@@ -382,7 +425,9 @@ static apr_status_t acmp_connect_fail_branches(ACMP *parser) {
|
|||||||
for (child = parser->root_node->child; child != NULL; child = child->sibling) {
|
for (child = parser->root_node->child; child != NULL; child = child->sibling) {
|
||||||
child->fail = parser->root_node;
|
child->fail = parser->root_node;
|
||||||
*(acmp_node_t **)apr_array_push(arr) = child;
|
*(acmp_node_t **)apr_array_push(arr) = child;
|
||||||
/* printf("fail direction: *%s* => *%s*\n", child->text, child->fail->text); */
|
#ifdef DEBUG_ACMP
|
||||||
|
fprintf(stderr, "fail direction: *%s* => *%s*\n", child->text, child->fail->text);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -393,7 +438,9 @@ static apr_status_t acmp_connect_fail_branches(ACMP *parser) {
|
|||||||
goto_node = acmp_child_for_code(node->parent->fail, node->letter);
|
goto_node = acmp_child_for_code(node->parent->fail, node->letter);
|
||||||
node->fail = (goto_node != NULL) ? goto_node : parser->root_node;
|
node->fail = (goto_node != NULL) ? goto_node : parser->root_node;
|
||||||
}
|
}
|
||||||
/* printf("fail direction: *%s* => *%s*\n", node->text, node->fail->text); */
|
#ifdef DEBUG_ACMP
|
||||||
|
fprintf(stderr, "fail direction: *%s* => *%s*\n", node->text, node->fail->text);
|
||||||
|
#endif
|
||||||
child = node->child;
|
child = node->child;
|
||||||
while (child != NULL) {
|
while (child != NULL) {
|
||||||
*(acmp_node_t **)apr_array_push(arr2) = child;
|
*(acmp_node_t **)apr_array_push(arr2) = child;
|
||||||
@@ -431,7 +478,6 @@ static void acmp_found(ACMP *parser, acmp_node_t *node) {
|
|||||||
parser->bp_buffer[(parser->char_pos - node->depth - 1) % parser->bp_buff_len],
|
parser->bp_buffer[(parser->char_pos - node->depth - 1) % parser->bp_buff_len],
|
||||||
parser->char_pos - node->depth - 1);
|
parser->char_pos - node->depth - 1);
|
||||||
}
|
}
|
||||||
/* printf("found: %s at position %d\n", node->pattern, parser->char_pos - node->depth - 1); */
|
|
||||||
node->hit_count++;
|
node->hit_count++;
|
||||||
parser->hit_count++;
|
parser->hit_count++;
|
||||||
}
|
}
|
||||||
@@ -450,15 +496,21 @@ static void acmp_found(ACMP *parser, acmp_node_t *node) {
|
|||||||
ACMP *acmp_create(int flags, apr_pool_t *pool) {
|
ACMP *acmp_create(int flags, apr_pool_t *pool) {
|
||||||
apr_status_t rc;
|
apr_status_t rc;
|
||||||
apr_pool_t *p;
|
apr_pool_t *p;
|
||||||
|
ACMP *parser;
|
||||||
|
|
||||||
rc = apr_pool_create(&p, pool);
|
rc = apr_pool_create(&p, pool);
|
||||||
if (rc != APR_SUCCESS) return NULL;
|
if (rc != APR_SUCCESS) return NULL;
|
||||||
|
|
||||||
ACMP *parser = apr_pcalloc(p, sizeof(ACMP));
|
parser = apr_pcalloc(p, sizeof(ACMP));
|
||||||
|
/* ENH: Check alloc succeded */
|
||||||
parser->pool = p;
|
parser->pool = p;
|
||||||
parser->parent_pool = pool;
|
parser->parent_pool = pool;
|
||||||
|
#ifdef ACMP_USE_UTF8
|
||||||
parser->is_utf8 = (flags & ACMP_FLAG_UTF8) == 0 ? 0 : 1;
|
parser->is_utf8 = (flags & ACMP_FLAG_UTF8) == 0 ? 0 : 1;
|
||||||
|
#endif
|
||||||
parser->is_case_sensitive = (flags & ACMP_FLAG_CASE_SENSITIVE) == 0 ? 0 : 1;
|
parser->is_case_sensitive = (flags & ACMP_FLAG_CASE_SENSITIVE) == 0 ? 0 : 1;
|
||||||
parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t));
|
parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t));
|
||||||
|
/* ENH: Check alloc succeded */
|
||||||
return parser;
|
return parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,17 +533,22 @@ void acmp_destroy(ACMP *parser) {
|
|||||||
ACMP *acmp_duplicate(ACMP *parser, apr_pool_t *pool) {
|
ACMP *acmp_duplicate(ACMP *parser, apr_pool_t *pool) {
|
||||||
apr_status_t rc;
|
apr_status_t rc;
|
||||||
apr_pool_t *p;
|
apr_pool_t *p;
|
||||||
|
ACMP *new_parser;
|
||||||
|
|
||||||
if (pool == NULL) pool = parser->parent_pool;
|
if (pool == NULL) pool = parser->parent_pool;
|
||||||
rc = apr_pool_create(&p, pool);
|
rc = apr_pool_create(&p, pool);
|
||||||
if (rc != APR_SUCCESS) return NULL;
|
if (rc != APR_SUCCESS) return NULL;
|
||||||
|
|
||||||
ACMP *new_parser = apr_pcalloc(p, sizeof(ACMP));
|
new_parser = apr_pcalloc(p, sizeof(ACMP));
|
||||||
|
/* ENH: Check alloc succeded */
|
||||||
new_parser->pool = p;
|
new_parser->pool = p;
|
||||||
new_parser->parent_pool = pool;
|
new_parser->parent_pool = pool;
|
||||||
|
#ifdef ACMP_USE_UTF8
|
||||||
new_parser->is_utf8 = parser->is_utf8;
|
new_parser->is_utf8 = parser->is_utf8;
|
||||||
|
#endif
|
||||||
new_parser->is_case_sensitive = parser->is_case_sensitive;
|
new_parser->is_case_sensitive = parser->is_case_sensitive;
|
||||||
new_parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t));
|
new_parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t));
|
||||||
|
/* ENH: Check alloc succeded */
|
||||||
new_parser->dict_count = parser->dict_count;
|
new_parser->dict_count = parser->dict_count;
|
||||||
new_parser->longest_entry = parser->longest_entry;
|
new_parser->longest_entry = parser->longest_entry;
|
||||||
acmp_copy_nodes_recursive(parser->root_node, new_parser->root_node, new_parser->pool);
|
acmp_copy_nodes_recursive(parser->root_node, new_parser->root_node, new_parser->pool);
|
||||||
@@ -503,11 +560,15 @@ ACMP *acmp_duplicate(ACMP *parser, apr_pool_t *pool) {
|
|||||||
* Creates fail tree and initializes buffer
|
* Creates fail tree and initializes buffer
|
||||||
*/
|
*/
|
||||||
apr_status_t acmp_prepare(ACMP *parser) {
|
apr_status_t acmp_prepare(ACMP *parser) {
|
||||||
|
apr_status_t st;
|
||||||
|
|
||||||
if (parser->bp_buff_len < parser->longest_entry) {
|
if (parser->bp_buff_len < parser->longest_entry) {
|
||||||
parser->bp_buff_len = parser->longest_entry * 2;
|
parser->bp_buff_len = parser->longest_entry * 2;
|
||||||
parser->bp_buffer = apr_pcalloc(parser->pool, sizeof(apr_size_t) * parser->bp_buff_len);
|
parser->bp_buffer = apr_pcalloc(parser->pool, sizeof(apr_size_t) * parser->bp_buff_len);
|
||||||
|
/* ENH: Check alloc succeded */
|
||||||
}
|
}
|
||||||
apr_status_t st = acmp_connect_fail_branches(parser);
|
|
||||||
|
st = acmp_connect_fail_branches(parser);
|
||||||
parser->active_node = parser->root_node;
|
parser->active_node = parser->root_node;
|
||||||
if (st != APR_SUCCESS) return st;
|
if (st != APR_SUCCESS) return st;
|
||||||
parser->is_active = 1;
|
parser->is_active = 1;
|
||||||
@@ -526,12 +587,17 @@ apr_status_t acmp_prepare(ACMP *parser) {
|
|||||||
apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern,
|
apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern,
|
||||||
acmp_callback_t callback, void *data, apr_size_t len)
|
acmp_callback_t callback, void *data, apr_size_t len)
|
||||||
{
|
{
|
||||||
if (parser->is_active != 0) return APR_EGENERAL;
|
size_t length, i, j;
|
||||||
size_t length = (len == 0) ? acmp_strlen(parser, pattern) : len;
|
acmp_utf8_char_t *ucs_chars;
|
||||||
size_t i, j;
|
acmp_node_t *parent, *child;
|
||||||
acmp_utf8_char_t ucs_chars[length];
|
|
||||||
|
|
||||||
acmp_node_t *parent = parser->root_node, *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);
|
acmp_strtoucs(parser, pattern, ucs_chars, length);
|
||||||
|
|
||||||
for (i = 0; i < length; i++) {
|
for (i = 0; i < length; i++) {
|
||||||
@@ -542,10 +608,12 @@ apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern,
|
|||||||
child = acmp_child_for_code(parent, letter);
|
child = acmp_child_for_code(parent, letter);
|
||||||
if (child == NULL) {
|
if (child == NULL) {
|
||||||
child = apr_pcalloc(parser->pool, sizeof(acmp_node_t));
|
child = apr_pcalloc(parser->pool, sizeof(acmp_node_t));
|
||||||
|
/* ENH: Check alloc succeded */
|
||||||
child->pattern = "";
|
child->pattern = "";
|
||||||
child->letter = letter;
|
child->letter = letter;
|
||||||
child->depth = i;
|
child->depth = i;
|
||||||
child->text = apr_pcalloc(parser->pool, strlen(pattern) + 2);
|
child->text = apr_pcalloc(parser->pool, strlen(pattern) + 2);
|
||||||
|
/* ENH: Check alloc succeded */
|
||||||
for (j = 0; j <= i; j++) child->text[j] = pattern[j];
|
for (j = 0; j <= i; j++) child->text[j] = pattern[j];
|
||||||
}
|
}
|
||||||
if (i == length - 1) {
|
if (i == length - 1) {
|
||||||
@@ -553,6 +621,7 @@ apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern,
|
|||||||
parser->dict_count++;
|
parser->dict_count++;
|
||||||
child->is_last = 1;
|
child->is_last = 1;
|
||||||
child->pattern = apr_pcalloc(parser->pool, strlen(pattern) + 2);
|
child->pattern = apr_pcalloc(parser->pool, strlen(pattern) + 2);
|
||||||
|
/* ENH: Check alloc succeded */
|
||||||
strcpy(child->pattern, pattern);
|
strcpy(child->pattern, pattern);
|
||||||
}
|
}
|
||||||
child->callback = callback;
|
child->callback = callback;
|
||||||
@@ -573,14 +642,22 @@ apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern,
|
|||||||
* len - size of data in bytes
|
* len - size of data in bytes
|
||||||
*/
|
*/
|
||||||
apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len) {
|
apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len) {
|
||||||
if (parser->is_failtree_done == 0) acmp_prepare(parser);
|
acmp_node_t *node, *go_to;
|
||||||
acmp_node_t *node = parser->active_node, *go_to;
|
#ifdef ACMP_USE_UTF8
|
||||||
apr_size_t seq_length;
|
apr_size_t seq_length;
|
||||||
const char *end = (data + len);
|
#endif
|
||||||
|
const char *end;
|
||||||
|
|
||||||
|
if (parser->is_failtree_done == 0) acmp_prepare(parser);
|
||||||
|
|
||||||
|
node = parser->active_node;
|
||||||
|
end = data + len;
|
||||||
|
|
||||||
while (data < end) {
|
while (data < end) {
|
||||||
parser->bp_buffer[parser->char_pos % parser->bp_buff_len] = parser->byte_pos;
|
|
||||||
acmp_utf8_char_t letter;
|
acmp_utf8_char_t letter;
|
||||||
|
|
||||||
|
parser->bp_buffer[parser->char_pos % parser->bp_buff_len] = parser->byte_pos;
|
||||||
|
#ifdef ACMP_USE_UTF8
|
||||||
if (parser->is_utf8) {
|
if (parser->is_utf8) {
|
||||||
if (parser->u8buff_len > 0) {
|
if (parser->u8buff_len > 0) {
|
||||||
/* Resuming partial utf-8 sequence */
|
/* Resuming partial utf-8 sequence */
|
||||||
@@ -608,7 +685,9 @@ apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len) {
|
|||||||
parser->char_pos++;
|
parser->char_pos++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
letter = *data++;
|
letter = *data++;
|
||||||
parser->byte_pos++;
|
parser->byte_pos++;
|
||||||
parser->char_pos++;
|
parser->char_pos++;
|
||||||
@@ -668,6 +747,7 @@ void acmp_reset(ACMP *parser) {
|
|||||||
ACMPT *acmp_duplicate_quick(ACMP *parser, apr_pool_t *pool) {
|
ACMPT *acmp_duplicate_quick(ACMP *parser, apr_pool_t *pool) {
|
||||||
apr_pool_t *p = (pool != NULL) ? pool : parser->pool;
|
apr_pool_t *p = (pool != NULL) ? pool : parser->pool;
|
||||||
ACMPT *dup = apr_pcalloc(p, sizeof(ACMPT));
|
ACMPT *dup = apr_pcalloc(p, sizeof(ACMPT));
|
||||||
|
/* ENH: Check alloc succeded */
|
||||||
dup->parser = parser;
|
dup->parser = parser;
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
@@ -676,13 +756,18 @@ 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
|
* 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) {
|
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) {
|
if (acmpt->parser->is_failtree_done == 0) {
|
||||||
acmp_prepare(acmpt->parser);
|
acmp_prepare(acmpt->parser);
|
||||||
};
|
};
|
||||||
ACMP *parser = acmpt->parser;
|
|
||||||
|
parser = acmpt->parser;
|
||||||
if (acmpt->ptr == NULL) acmpt->ptr = parser->root_node;
|
if (acmpt->ptr == NULL) acmpt->ptr = parser->root_node;
|
||||||
acmp_node_t *node = acmpt->ptr, *go_to;
|
node = acmpt->ptr;
|
||||||
const char *end = (data + len);
|
end = data + len;
|
||||||
|
|
||||||
while (data < end) {
|
while (data < end) {
|
||||||
acmp_utf8_char_t letter = (unsigned char)*data++;
|
acmp_utf8_char_t letter = (unsigned char)*data++;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -15,9 +15,11 @@
|
|||||||
#include <apr_pools.h>
|
#include <apr_pools.h>
|
||||||
|
|
||||||
#define ACMP_FLAG_BYTE 0
|
#define ACMP_FLAG_BYTE 0
|
||||||
#define ACMP_FLAG_UTF8 0x100
|
|
||||||
#define ACMP_FLAG_CASE_SENSITIVE 1
|
#define ACMP_FLAG_CASE_SENSITIVE 1
|
||||||
#define ACMP_FLAG_CASE_INSENSITIVE 0
|
#define ACMP_FLAG_CASE_INSENSITIVE 0
|
||||||
|
#ifdef ACMP_USE_UTF8
|
||||||
|
#define ACMP_FLAG_UTF8 0x100
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opaque struct with parser data
|
* Opaque struct with parser data
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -13,11 +13,14 @@
|
|||||||
|
|
||||||
#include "http_core.h"
|
#include "http_core.h"
|
||||||
#include "http_request.h"
|
#include "http_request.h"
|
||||||
|
#include "httpd.h"
|
||||||
|
#include "ap_release.h"
|
||||||
|
|
||||||
#include <apr_general.h>
|
#include <apr_general.h>
|
||||||
#include <apr_optional.h>
|
#include <apr_optional.h>
|
||||||
|
|
||||||
|
|
||||||
|
#if (!defined(NO_MODSEC_API))
|
||||||
/* Optional functions. */
|
/* Optional functions. */
|
||||||
|
|
||||||
APR_DECLARE_OPTIONAL_FN(void, modsec_register_tfn, (const char *name, void *fn));
|
APR_DECLARE_OPTIONAL_FN(void, modsec_register_tfn, (const char *name, void *fn));
|
||||||
@@ -27,6 +30,20 @@ APR_DECLARE_OPTIONAL_FN(void, modsec_register_variable,
|
|||||||
unsigned int argc_min, unsigned int argc_max,
|
unsigned int argc_min, unsigned int argc_max,
|
||||||
void *fn_validate, void *fn_generate,
|
void *fn_validate, void *fn_generate,
|
||||||
unsigned int is_cacheable, unsigned int availability));
|
unsigned int is_cacheable, unsigned int availability));
|
||||||
|
#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. */
|
/* Configuration functions. */
|
||||||
@@ -52,6 +69,8 @@ apr_status_t DSOLOCAL read_request_body(modsec_rec *msr, char **error_msg);
|
|||||||
|
|
||||||
int DSOLOCAL perform_interception(modsec_rec *msr);
|
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);
|
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);
|
void DSOLOCAL record_time_checkpoint(modsec_rec *msr, int checkpoint_no);
|
||||||
@@ -63,7 +82,7 @@ char DSOLOCAL *get_env_var(request_rec *r, char *name);
|
|||||||
void DSOLOCAL internal_log(request_rec *r, directory_config *dcfg, modsec_rec *msr,
|
void DSOLOCAL internal_log(request_rec *r, directory_config *dcfg, modsec_rec *msr,
|
||||||
int level, const char *text, va_list ap);
|
int level, const char *text, va_list ap);
|
||||||
|
|
||||||
void DSOLOCAL msr_log(modsec_rec *msr, int level, const char *text, ...);
|
void DSOLOCAL msr_log(modsec_rec *msr, int level, const char *text, ...) PRINTF_ATTRIBUTE(3,4);
|
||||||
|
|
||||||
char DSOLOCAL *format_error_log_message(apr_pool_t *mp, error_message *em);
|
char DSOLOCAL *format_error_log_message(apr_pool_t *mp, error_message *em);
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -30,6 +30,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
|
|||||||
msc_data_chunk *chunk = NULL;
|
msc_data_chunk *chunk = NULL;
|
||||||
apr_bucket *bucket;
|
apr_bucket *bucket;
|
||||||
apr_status_t rc;
|
apr_status_t rc;
|
||||||
|
char *my_error_msg = NULL;
|
||||||
|
|
||||||
if (msr == NULL) {
|
if (msr == NULL) {
|
||||||
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
|
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
|
||||||
@@ -38,31 +39,42 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
|
|||||||
return APR_EGENERAL;
|
return APR_EGENERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msr->r = f->r;
|
||||||
|
|
||||||
|
if (msr->phase < PHASE_REQUEST_BODY) {
|
||||||
|
msr_log(msr, 1, "Internal error: REQUEST_BODY phase incomplete for input filter in phase %d", msr->phase);
|
||||||
|
return APR_EGENERAL;
|
||||||
|
}
|
||||||
|
|
||||||
if ((msr->if_status == IF_STATUS_COMPLETE)||(msr->if_status == IF_STATUS_NONE)) {
|
if ((msr->if_status == IF_STATUS_COMPLETE)||(msr->if_status == IF_STATUS_NONE)) {
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Input filter: Input forwarding already complete, skipping (f %x, r %x).", f, f->r);
|
msr_log(msr, 4, "Input filter: Input forwarding already complete, skipping (f %pp, r %pp).", f, f->r);
|
||||||
}
|
}
|
||||||
ap_remove_input_filter(f);
|
ap_remove_input_filter(f);
|
||||||
return ap_get_brigade(f->next, bb_out, mode, block, nbytes);
|
return ap_get_brigade(f->next, bb_out, mode, block, nbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Input filter: Forwarding input: mode=%i, block=%i, nbytes=%" APR_OFF_T_FMT
|
msr_log(msr, 4, "Input filter: Forwarding input: mode=%d, block=%d, nbytes=%" APR_OFF_T_FMT
|
||||||
" (f %x, r %x).", mode, block, nbytes, f, f->r);
|
" (f %pp, r %pp).", mode, block, nbytes, f, f->r);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr->if_started_forwarding == 0) {
|
if (msr->if_started_forwarding == 0) {
|
||||||
msr->if_started_forwarding = 1;
|
msr->if_started_forwarding = 1;
|
||||||
rc = modsecurity_request_body_retrieve_start(msr);
|
rc = modsecurity_request_body_retrieve_start(msr, &my_error_msg);
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
// TODO err
|
if (my_error_msg != NULL) {
|
||||||
|
msr_log(msr, 1, "%s", my_error_msg);
|
||||||
|
}
|
||||||
return APR_EGENERAL;
|
return APR_EGENERAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = modsecurity_request_body_retrieve(msr, &chunk, (unsigned int)nbytes);
|
rc = modsecurity_request_body_retrieve(msr, &chunk, (unsigned int)nbytes, &my_error_msg);
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
// TODO err
|
if (my_error_msg != NULL) {
|
||||||
|
msr_log(msr, 1, "%s", my_error_msg);
|
||||||
|
}
|
||||||
return APR_EGENERAL;
|
return APR_EGENERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +104,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
|
|||||||
APR_BRIGADE_INSERT_TAIL(bb_out, bucket);
|
APR_BRIGADE_INSERT_TAIL(bb_out, bucket);
|
||||||
|
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Input filter: Forwarded %lu bytes.", chunk->length);
|
msr_log(msr, 4, "Input filter: Forwarded %" APR_SIZE_T_FMT " bytes.", chunk->length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,8 +161,7 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
|
|||||||
msr_log(msr, 4, "Input filter: Reading request body.");
|
msr_log(msr, 4, "Input filter: Reading request body.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modsecurity_request_body_start(msr) < 0) {
|
if (modsecurity_request_body_start(msr, error_msg) < 0) {
|
||||||
// TODO err
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,25 +178,18 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
|
|||||||
*/
|
*/
|
||||||
switch(rc) {
|
switch(rc) {
|
||||||
case APR_TIMEUP :
|
case APR_TIMEUP :
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc));
|
||||||
return -4;
|
return -4;
|
||||||
break;
|
|
||||||
case -3 :
|
case -3 :
|
||||||
*error_msg = apr_psprintf(msr->mp, "Error reading request body: HTTP Error 413 - Request entity too large. (Most likely.)");
|
*error_msg = apr_psprintf(msr->mp, "Error reading request body: HTTP Error 413 - Request entity too large. (Most likely.)");
|
||||||
rc = -3;
|
return -3;
|
||||||
break;
|
|
||||||
case APR_EGENERAL :
|
case APR_EGENERAL :
|
||||||
*error_msg = apr_psprintf(msr->mp, "Error reading request body: Client went away.");
|
*error_msg = apr_psprintf(msr->mp, "Error reading request body: Client went away.");
|
||||||
rc = -2;
|
return -2;
|
||||||
break;
|
|
||||||
default :
|
default :
|
||||||
*error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc));
|
*error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc));
|
||||||
rc = -1;
|
return -1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*error_msg) msr_log(msr, 1, "%s", *error_msg);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop through the buckets in the brigade in order
|
/* Loop through the buckets in the brigade in order
|
||||||
@@ -200,26 +204,31 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
|
|||||||
|
|
||||||
rc = apr_bucket_read(bucket, &buf, &buflen, APR_BLOCK_READ);
|
rc = apr_bucket_read(bucket, &buf, &buflen, APR_BLOCK_READ);
|
||||||
if (rc != APR_SUCCESS) {
|
if (rc != APR_SUCCESS) {
|
||||||
msr_log(msr, 1, "Input filter: Failed reading input / bucket (%i): %s",
|
*error_msg = apr_psprintf(msr->mp, "Failed reading input / bucket (%d): %s", rc, get_apr_error(msr->mp, rc));
|
||||||
rc, get_apr_error(msr->mp, rc));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr->txcfg->debuglog_level >= 9) {
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
msr_log(msr, 9, "Input filter: Bucket type %s contains %i bytes.",
|
msr_log(msr, 9, "Input filter: Bucket type %s contains %" APR_SIZE_T_FMT " bytes.",
|
||||||
bucket->type->name, buflen);
|
bucket->type->name, buflen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check request body limit (should only trigger on chunked requests). */
|
/* Check request body limit (should only trigger on chunked requests). */
|
||||||
if (msr->reqbody_length + buflen > (apr_size_t)msr->txcfg->reqbody_limit) {
|
if (msr->reqbody_length + buflen > (apr_size_t)msr->txcfg->reqbody_limit) {
|
||||||
*error_msg = apr_psprintf(msr->mp, "Requests body is larger than the "
|
*error_msg = apr_psprintf(msr->mp, "Requests body is larger than the "
|
||||||
"configured limit (%lu).", msr->txcfg->reqbody_limit);
|
"configured limit (%ld).", msr->txcfg->reqbody_limit);
|
||||||
return -5;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buflen != 0) {
|
if (buflen != 0) {
|
||||||
if (modsecurity_request_body_store(msr, buf, buflen) < 0) {
|
int rcbs = modsecurity_request_body_store(msr, buf, buflen, error_msg);
|
||||||
// TODO err
|
if (rcbs < 0) {
|
||||||
|
if (rcbs == -5) {
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Requests body no files data length is larger than the "
|
||||||
|
"configured limit (%ld).", msr->txcfg->reqbody_no_files_limit);
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,10 +243,11 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
|
|||||||
apr_brigade_cleanup(bb_in);
|
apr_brigade_cleanup(bb_in);
|
||||||
} while(!seen_eos);
|
} while(!seen_eos);
|
||||||
|
|
||||||
modsecurity_request_body_end(msr);
|
// TODO: Why ignore the return code here?
|
||||||
|
modsecurity_request_body_end(msr, error_msg);
|
||||||
|
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Input filter: Completed receiving request body (length %lu).",
|
msr_log(msr, 4, "Input filter: Completed receiving request body (length %" APR_SIZE_T_FMT ").",
|
||||||
msr->reqbody_length);
|
msr->reqbody_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,25 +259,6 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
|
|||||||
|
|
||||||
/* -- Output filter -- */
|
/* -- Output filter -- */
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a brigade with an error bucket down the filter chain.
|
|
||||||
*/
|
|
||||||
static apr_status_t send_error_bucket(ap_filter_t *f, int status) {
|
|
||||||
apr_bucket_brigade *brigade = NULL;
|
|
||||||
apr_bucket *bucket = NULL;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
return ap_pass_brigade(f->next, brigade);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Examines the configuration and the response MIME type
|
* Examines the configuration and the response MIME type
|
||||||
* in order to determine whether output buffering should
|
* in order to determine whether output buffering should
|
||||||
@@ -281,13 +272,14 @@ static int output_filter_should_run(modsec_rec *msr, request_rec *r) {
|
|||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Output filter: Response body buffering is not enabled.");
|
msr_log(msr, 4, "Output filter: Response body buffering is not enabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check MIME type. */
|
/* Check MIME type. */
|
||||||
|
|
||||||
if ((msr->txcfg->of_mime_types == NULL)||(msr->txcfg->of_mime_types == NOT_SET_P)) {
|
if ((msr->txcfg->of_mime_types == NULL)||(msr->txcfg->of_mime_types == NOT_SET_P)) {
|
||||||
msr_log(msr, 1, "Output filter: MIME type structures are corrupted (internal error).");
|
msr_log(msr, 1, "Output filter: MIME type structures corrupted (internal error).");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +287,10 @@ static int output_filter_should_run(modsec_rec *msr, request_rec *r) {
|
|||||||
char *p = NULL;
|
char *p = NULL;
|
||||||
|
|
||||||
content_type = apr_pstrdup(msr->mp, r->content_type);
|
content_type = apr_pstrdup(msr->mp, r->content_type);
|
||||||
if (content_type == NULL) return -1;
|
if (content_type == NULL) {
|
||||||
|
msr_log(msr, 1, "Output filter: Failed to allocate memory for content type.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Hide the character encoding information
|
/* Hide the character encoding information
|
||||||
* if present. Sometimes the content type header
|
* if present. Sometimes the content type header
|
||||||
@@ -320,6 +315,8 @@ static int output_filter_should_run(modsec_rec *msr, request_rec *r) {
|
|||||||
|
|
||||||
if (apr_table_get(msr->txcfg->of_mime_types, content_type) != NULL) return 1;
|
if (apr_table_get(msr->txcfg->of_mime_types, content_type) != NULL) return 1;
|
||||||
|
|
||||||
|
msr_log(msr, 4, "Output filter: Not buffering response body for unconfigured MIME type \"%s\".", content_type);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,20 +331,31 @@ static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f,
|
|||||||
apr_status_t rc;
|
apr_status_t rc;
|
||||||
|
|
||||||
msr->of_brigade = apr_brigade_create(msr->mp, f->c->bucket_alloc);
|
msr->of_brigade = apr_brigade_create(msr->mp, f->c->bucket_alloc);
|
||||||
if (msr->of_brigade == NULL) return -1;
|
if (msr->of_brigade == NULL) {
|
||||||
|
msr_log(msr, 1, "Output filter: Failed to create brigade.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
msr->of_status = OF_STATUS_IN_PROGRESS;
|
msr->of_status = OF_STATUS_IN_PROGRESS;
|
||||||
|
|
||||||
rc = output_filter_should_run(msr, r);
|
rc = output_filter_should_run(msr, r);
|
||||||
if (rc < 0) return -1;
|
if (rc < 0) return -1; /* output_filter_should_run() generates error msg */
|
||||||
if (rc == 0) return 0;
|
if (rc == 0) return 0;
|
||||||
|
|
||||||
|
/* Do not check the output limit if we are willing to
|
||||||
|
* process partial response bodies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (msr->txcfg->of_limit_action == RESPONSE_BODY_LIMIT_ACTION_PARTIAL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Look up the Content-Length header to see if we know
|
/* Look up the Content-Length header to see if we know
|
||||||
* the amount of data coming our way. If we do and if
|
* the amount of data coming our way. If we do and if
|
||||||
* it's too much we might want to stop processing right here.
|
* it's too much we might want to stop processing right here.
|
||||||
*/
|
*/
|
||||||
s_content_length = apr_table_get(r->headers_out, "Content-Length");
|
s_content_length = apr_table_get(r->headers_out, "Content-Length");
|
||||||
if (s_content_length == NULL) {
|
if (s_content_length == NULL) {
|
||||||
/* Try this too, mod_cgi seems to put headers there */
|
/* Try this too, mod_cgi seems to put headers there. */
|
||||||
s_content_length = apr_table_get(r->err_headers_out, "Content-Length");
|
s_content_length = apr_table_get(r->err_headers_out, "Content-Length");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,26 +364,111 @@ static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f,
|
|||||||
|
|
||||||
len = strtol(s_content_length, NULL, 10);
|
len = strtol(s_content_length, NULL, 10);
|
||||||
if ((len == LONG_MIN)||(len == LONG_MAX)||(len < 0)||(len >= 1073741824)) {
|
if ((len == LONG_MIN)||(len == LONG_MAX)||(len < 0)||(len >= 1073741824)) {
|
||||||
msr_log(msr, 1, "Output filter: Invalid Content-Length: %s", log_escape_nq(r->pool, (char *)s_content_length));
|
msr_log(msr, 1, "Output filter: Invalid Content-Length: %s", log_escape_nq(r->pool,
|
||||||
return -1;
|
(char *)s_content_length));
|
||||||
|
return -1; /* Invalid. */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Output filter: Skipping response since Content-Length is zero.");
|
msr_log(msr, 4, "Output filter: Skipping response since Content-Length is zero.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len > msr->txcfg->of_limit) {
|
if (len > msr->txcfg->of_limit) {
|
||||||
msr_log(msr, 1, "Output filter: Content-Length (%s) over the limit (%lu).", log_escape_nq(r->pool, (char *)s_content_length), msr->txcfg->of_limit);
|
msr_log(msr, 1, "Output filter: Content-Length (%s) over the limit (%ld).",
|
||||||
return -2;
|
log_escape_nq(r->pool, (char *)s_content_length), msr->txcfg->of_limit);
|
||||||
|
return -2; /* Over the limit. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the accumulated content down the filter stream
|
||||||
|
* and to the client.
|
||||||
|
*/
|
||||||
|
static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) {
|
||||||
|
apr_status_t rc;
|
||||||
|
|
||||||
|
rc = ap_pass_brigade(f->next, msr->of_brigade);
|
||||||
|
if (rc != APR_SUCCESS) {
|
||||||
|
int log_level = 1;
|
||||||
|
|
||||||
|
if (APR_STATUS_IS_ECONNRESET(rc)) {
|
||||||
|
/* Message "Connection reset by peer" is common and not a sign
|
||||||
|
* of something unusual. Hence we don't want to make a big deal
|
||||||
|
* about it, logging at NOTICE level. Everything else we log
|
||||||
|
* at ERROR level.
|
||||||
|
*/
|
||||||
|
log_level = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= log_level) {
|
||||||
|
msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): %s",
|
||||||
|
rc, get_apr_error(msr->mp, rc));
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return APR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void prepend_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) {
|
||||||
|
if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (!msr->of_skipping)) {
|
||||||
|
apr_bucket *bucket_ci = NULL;
|
||||||
|
|
||||||
|
bucket_ci = apr_bucket_heap_create(msr->content_prepend,
|
||||||
|
msr->content_prepend_len, NULL, f->r->connection->bucket_alloc);
|
||||||
|
APR_BRIGADE_INSERT_HEAD(msr->of_brigade, bucket_ci);
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Content Injection (b): Added content to top: %s",
|
||||||
|
log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int flatten_response_body(modsec_rec *msr) {
|
||||||
|
apr_status_t rc;
|
||||||
|
|
||||||
|
msr->resbody_status = RESBODY_STATUS_READ_BRIGADE;
|
||||||
|
|
||||||
|
if (msr->resbody_length + 1 <= 0) {
|
||||||
|
msr_log(msr, 1, "Output filter: Invalid response length: %" APR_SIZE_T_FMT, msr->resbody_length);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msr->resbody_data = apr_palloc(msr->mp, msr->resbody_length + 1);
|
||||||
|
if (msr->resbody_data == NULL) {
|
||||||
|
msr_log(msr, 1, "Output filter: Response body data memory allocation failed. Asked for: %" APR_SIZE_T_FMT,
|
||||||
|
msr->resbody_length + 1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = apr_brigade_flatten(msr->of_brigade, msr->resbody_data, &msr->resbody_length);
|
||||||
|
if (rc != APR_SUCCESS) {
|
||||||
|
msr_log(msr, 1, "Output filter: Failed to flatten brigade (%d): %s", rc,
|
||||||
|
get_apr_error(msr->mp, rc));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msr->resbody_data[msr->resbody_length] = '\0';
|
||||||
|
msr->resbody_status = RESBODY_STATUS_READ;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Output filter.
|
* Output filter.
|
||||||
*/
|
*/
|
||||||
@@ -384,16 +477,20 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
modsec_rec *msr = (modsec_rec *)f->ctx;
|
modsec_rec *msr = (modsec_rec *)f->ctx;
|
||||||
apr_bucket *bucket = NULL, *eos_bucket = NULL;
|
apr_bucket *bucket = NULL, *eos_bucket = NULL;
|
||||||
apr_status_t rc;
|
apr_status_t rc;
|
||||||
|
int start_skipping = 0;
|
||||||
|
|
||||||
|
/* Do we have the context? */
|
||||||
if (msr == NULL) {
|
if (msr == NULL) {
|
||||||
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
|
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
|
||||||
"ModSecurity: Internal Error: msr is null in output filter.");
|
"ModSecurity: Internal Error: msr is null in output filter.");
|
||||||
ap_remove_output_filter(f);
|
ap_remove_output_filter(f);
|
||||||
return send_error_bucket(f, HTTP_INTERNAL_SERVER_ERROR);
|
return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
msr->r = r;
|
||||||
msr_log(msr, 4, "Output filter: Receiving output (f %x, r %x).", f, f->r);
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Output filter: Receiving output (f %pp, r %pp).", f, f->r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialise on first invocation */
|
/* Initialise on first invocation */
|
||||||
@@ -410,13 +507,13 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
rc = modsecurity_process_phase(msr, PHASE_RESPONSE_HEADERS);
|
rc = modsecurity_process_phase(msr, PHASE_RESPONSE_HEADERS);
|
||||||
if (rc < 0) { /* error */
|
if (rc < 0) { /* error */
|
||||||
ap_remove_output_filter(f);
|
ap_remove_output_filter(f);
|
||||||
return send_error_bucket(f, HTTP_INTERNAL_SERVER_ERROR);
|
return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
if (rc > 0) { /* transaction needs to be interrupted */
|
if (rc > 0) { /* transaction needs to be interrupted */
|
||||||
int status = perform_interception(msr);
|
int status = perform_interception(msr);
|
||||||
if (status != DECLINED) { /* DECLINED means we allow-ed the request. */
|
if (status != DECLINED) { /* DECLINED means we allow-ed the request. */
|
||||||
ap_remove_output_filter(f);
|
ap_remove_output_filter(f);
|
||||||
return send_error_bucket(f, status);
|
return send_error_bucket(msr, f, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +526,7 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
ap_remove_output_filter(f);
|
ap_remove_output_filter(f);
|
||||||
msr->of_status = OF_STATUS_COMPLETE;
|
msr->of_status = OF_STATUS_COMPLETE;
|
||||||
msr->resbody_status = RESBODY_STATUS_ERROR;
|
msr->resbody_status = RESBODY_STATUS_ERROR;
|
||||||
return send_error_bucket(f, HTTP_INTERNAL_SERVER_ERROR);
|
return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
case 0 :
|
case 0 :
|
||||||
/* We do not want to observe this response body
|
/* We do not want to observe this response body
|
||||||
* but we need to remain attached to observe
|
* but we need to remain attached to observe
|
||||||
@@ -444,7 +541,7 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If injecting content unset headers now.
|
/* If injecting content unset headers now. */
|
||||||
if (msr->txcfg->content_injection_enabled == 0) {
|
if (msr->txcfg->content_injection_enabled == 0) {
|
||||||
if (msr->txcfg->debuglog_level >= 9) {
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
msr_log(msr, 9, "Content Injection: Not enabled.");
|
msr_log(msr, 9, "Content Injection: Not enabled.");
|
||||||
@@ -466,8 +563,8 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Content injection (prepend & non-buffering).
|
/* Content injection (prepend & non-buffering). */
|
||||||
if (msr->txcfg->content_injection_enabled && msr->content_prepend && msr->of_skipping) {
|
if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (msr->of_skipping)) {
|
||||||
apr_bucket *bucket_ci = apr_bucket_heap_create(msr->content_prepend,
|
apr_bucket *bucket_ci = apr_bucket_heap_create(msr->content_prepend,
|
||||||
msr->content_prepend_len, NULL, f->r->connection->bucket_alloc);
|
msr->content_prepend_len, NULL, f->r->connection->bucket_alloc);
|
||||||
APR_BRIGADE_INSERT_HEAD(bb_in, bucket_ci);
|
APR_BRIGADE_INSERT_HEAD(bb_in, bucket_ci);
|
||||||
@@ -494,39 +591,67 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
const char *buf;
|
const char *buf;
|
||||||
apr_size_t buflen;
|
apr_size_t buflen;
|
||||||
|
|
||||||
if (msr->of_skipping == 0) {
|
/* Look into response data if configured to do so,
|
||||||
|
* unless we've already processed a partial response.
|
||||||
|
*/
|
||||||
|
if ((msr->of_skipping == 0)&&(!msr->of_partial)) { /* Observe the response data. */
|
||||||
|
/* Retrieve data from the bucket. */
|
||||||
rc = apr_bucket_read(bucket, &buf, &buflen, APR_BLOCK_READ);
|
rc = apr_bucket_read(bucket, &buf, &buflen, APR_BLOCK_READ);
|
||||||
if (rc != APR_SUCCESS) {
|
if (rc != APR_SUCCESS) {
|
||||||
msr->of_status = OF_STATUS_COMPLETE;
|
msr->of_status = OF_STATUS_COMPLETE;
|
||||||
msr->resbody_status = RESBODY_STATUS_ERROR;
|
msr->resbody_status = RESBODY_STATUS_ERROR;
|
||||||
msr_log(msr, 1, "Output filter: Failed to read bucket (rc %i): %s",
|
|
||||||
|
msr_log(msr, 1, "Output filter: Failed to read bucket (rc %d): %s",
|
||||||
rc, get_apr_error(r->pool, rc));
|
rc, get_apr_error(r->pool, rc));
|
||||||
|
|
||||||
ap_remove_output_filter(f);
|
ap_remove_output_filter(f);
|
||||||
return send_error_bucket(f, HTTP_INTERNAL_SERVER_ERROR);
|
return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr->txcfg->debuglog_level >= 9) {
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
msr_log(msr, 9, "Output filter: Bucket type %s contains %i bytes.",
|
msr_log(msr, 9, "Output filter: Bucket type %s contains %" APR_SIZE_T_FMT " bytes.",
|
||||||
bucket->type->name, buflen);
|
bucket->type->name, buflen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check the response size. */
|
||||||
if (msr->resbody_length > (apr_size_t)msr->txcfg->of_limit) {
|
if (msr->resbody_length > (apr_size_t)msr->txcfg->of_limit) {
|
||||||
msr_log(msr, 1, "Output filter: Response body too large (over limit of %lu, total length not known).",
|
/* The size of the response is larger than what we're
|
||||||
msr->txcfg->of_limit);
|
* ready to accept. We need to decide what we want to do
|
||||||
msr->of_status = OF_STATUS_COMPLETE;
|
* about it.
|
||||||
msr->resbody_status = RESBODY_STATUS_PARTIAL;
|
*/
|
||||||
ap_remove_output_filter(f);
|
if (msr->txcfg->of_limit_action == RESPONSE_BODY_LIMIT_ACTION_REJECT) {
|
||||||
return send_error_bucket(f, HTTP_INTERNAL_SERVER_ERROR);
|
/* Reject response. */
|
||||||
}
|
msr_log(msr, 1, "Output filter: Response body too large (over limit of %ld, "
|
||||||
|
"total not specified).", msr->txcfg->of_limit);
|
||||||
|
|
||||||
msr->resbody_length += buflen;
|
msr->of_status = OF_STATUS_COMPLETE;
|
||||||
|
msr->resbody_status = RESBODY_STATUS_PARTIAL;
|
||||||
|
|
||||||
|
ap_remove_output_filter(f);
|
||||||
|
return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
} else {
|
||||||
|
/* Process partial response. */
|
||||||
|
start_skipping = 1;
|
||||||
|
msr->resbody_length = msr->txcfg->of_limit;
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
|
msr_log(msr, 4, "Output filter: Processing partial response body (limit %ld)",
|
||||||
|
msr->txcfg->of_limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msr->resbody_length += buflen;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Have we reached the end of the response? */
|
||||||
if (APR_BUCKET_IS_EOS(bucket)) {
|
if (APR_BUCKET_IS_EOS(bucket)) {
|
||||||
eos_bucket = bucket;
|
eos_bucket = bucket;
|
||||||
|
|
||||||
// Inject content (append & non-buffering).
|
/* Inject content (append & non-buffering). */
|
||||||
if (msr->txcfg->content_injection_enabled && msr->content_append && msr->of_skipping) {
|
if ((msr->txcfg->content_injection_enabled) && (msr->content_append)
|
||||||
|
&& (msr->of_skipping || msr->of_partial || start_skipping))
|
||||||
|
{
|
||||||
apr_bucket *bucket_ci = NULL;
|
apr_bucket *bucket_ci = NULL;
|
||||||
|
|
||||||
bucket_ci = apr_bucket_heap_create(msr->content_append,
|
bucket_ci = apr_bucket_heap_create(msr->content_append,
|
||||||
@@ -547,90 +672,94 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
* we have in the context, but only if we actually
|
* we have in the context, but only if we actually
|
||||||
* want to keep the response body.
|
* want to keep the response body.
|
||||||
*/
|
*/
|
||||||
if (msr->of_skipping == 0) {
|
if ((msr->of_skipping == 0)&&(msr->of_partial == 0)) {
|
||||||
ap_save_brigade(f, &msr->of_brigade, &bb_in, msr->mp);
|
ap_save_brigade(f, &msr->of_brigade, &bb_in, msr->mp);
|
||||||
|
|
||||||
|
/* Do we need to process a partial response? */
|
||||||
|
if (start_skipping) {
|
||||||
|
if (flatten_response_body(msr) < 0) {
|
||||||
|
return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process phase RESPONSE_BODY */
|
||||||
|
rc = modsecurity_process_phase(msr, PHASE_RESPONSE_BODY);
|
||||||
|
if (rc < 0) {
|
||||||
|
return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
if (rc > 0) {
|
||||||
|
int status = perform_interception(msr);
|
||||||
|
if (status != DECLINED) { /* DECLINED means we allow-ed the request. */
|
||||||
|
return send_error_bucket(msr, f, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepend content as necessary. */
|
||||||
|
prepend_content_to_of_brigade(msr, f);
|
||||||
|
|
||||||
|
if ((rc = send_of_brigade(msr, f)) != APR_SUCCESS) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
msr->of_partial = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (msr->of_done_reading == 0) {
|
if (msr->of_done_reading == 0) {
|
||||||
/* We are done for now. We will be called again with more data. */
|
/* We are done for now. We will be called again with more data. */
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Output filter: Completed receiving response (length %lu).",
|
msr_log(msr, 4, "Output filter: Completed receiving response body (buffered %s - %" APR_SIZE_T_FMT " bytes).",
|
||||||
msr->resbody_length);
|
(msr->of_partial ? "partial" : "full"), msr->resbody_length);
|
||||||
}
|
}
|
||||||
} else {
|
} else { /* Not looking at response data. */
|
||||||
if (msr->of_done_reading == 0) {
|
if (msr->of_done_reading == 0) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Output filter: Sending input brigade directly.");
|
||||||
|
}
|
||||||
|
|
||||||
return ap_pass_brigade(f->next, bb_in);
|
return ap_pass_brigade(f->next, bb_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Output filter: Completed receiving response.");
|
msr_log(msr, 4, "Output filter: Completed receiving response body (non-buffering).");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We're not coming back here. */
|
/* We've done our thing; remove us from the filter list. */
|
||||||
msr->of_status = OF_STATUS_COMPLETE;
|
msr->of_status = OF_STATUS_COMPLETE;
|
||||||
ap_remove_output_filter(f);
|
ap_remove_output_filter(f);
|
||||||
|
|
||||||
if (msr->of_skipping == 0) {
|
/* Process phase RESPONSE_BODY, but
|
||||||
/* We've done with reading, it's time to inspect the data. */
|
* only if it hasn't been processed already.
|
||||||
msr->resbody_status = RESBODY_STATUS_READ_BRIGADE;
|
*/
|
||||||
|
if (msr->phase < PHASE_RESPONSE_BODY) {
|
||||||
if (msr->resbody_length + 1 <= 0) {
|
if (flatten_response_body(msr) < 0) {
|
||||||
msr_log(msr, 1, "Output filter: Invalid response length: %lu", msr->resbody_length);
|
return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
return send_error_bucket(f, HTTP_INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msr->resbody_data = apr_palloc(msr->mp, msr->resbody_length + 1);
|
rc = modsecurity_process_phase(msr, PHASE_RESPONSE_BODY);
|
||||||
if (msr->resbody_data == NULL) {
|
if (rc < 0) {
|
||||||
msr_log(msr, 1, "Output filter: Response body data memory allocation failed. Asked for: %li",
|
return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
msr->resbody_length + 1);
|
|
||||||
return send_error_bucket(f, HTTP_INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
}
|
||||||
|
if (rc > 0) {
|
||||||
// TODO Why does the function below take pointer to length? Will it modify it?
|
int status = perform_interception(msr);
|
||||||
rc = apr_brigade_flatten(msr->of_brigade, msr->resbody_data, &msr->resbody_length);
|
if (status != DECLINED) { /* DECLINED means we allow-ed the request. */
|
||||||
if (rc != APR_SUCCESS) {
|
return send_error_bucket(msr, f, status);
|
||||||
msr_log(msr, 1, "Output filter: Failed to flatten brigade (%i): %s", rc,
|
|
||||||
get_apr_error(r->pool, rc));
|
|
||||||
return send_error_bucket(f, HTTP_INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
msr->resbody_data[msr->resbody_length] = '\0';
|
|
||||||
msr->resbody_status = RESBODY_STATUS_READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Process phase RESPONSE_BODY */
|
|
||||||
rc = modsecurity_process_phase(msr, PHASE_RESPONSE_BODY);
|
|
||||||
if (rc < 0) {
|
|
||||||
return send_error_bucket(f, HTTP_INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
if (rc > 0) {
|
|
||||||
int status = perform_interception(msr);
|
|
||||||
if (status != DECLINED) { /* DECLINED means we allow-ed the request. */
|
|
||||||
return send_error_bucket(f, status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msr->of_skipping == 0) {
|
|
||||||
record_time_checkpoint(msr, 3);
|
|
||||||
|
|
||||||
// Inject content into response (prepend & buffering).
|
|
||||||
if (msr->txcfg->content_injection_enabled && msr->content_prepend && (!msr->of_skipping)) {
|
|
||||||
apr_bucket *bucket_ci = NULL;
|
|
||||||
|
|
||||||
bucket_ci = apr_bucket_heap_create(msr->content_prepend,
|
|
||||||
msr->content_prepend_len, NULL, f->r->connection->bucket_alloc);
|
|
||||||
APR_BRIGADE_INSERT_HEAD(msr->of_brigade, bucket_ci);
|
|
||||||
|
|
||||||
if (msr->txcfg->debuglog_level >= 9) {
|
|
||||||
msr_log(msr, 9, "Content Injection (b): Added content to top: %s",
|
|
||||||
log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Inject content into response (append & buffering).
|
/* Now send data down the filter stream
|
||||||
if (msr->txcfg->content_injection_enabled && msr->content_append && (!msr->of_skipping)) {
|
* (full-buffering only).
|
||||||
|
*/
|
||||||
|
if ((msr->of_skipping == 0)&&(!msr->of_partial)) {
|
||||||
|
record_time_checkpoint(msr, 3);
|
||||||
|
|
||||||
|
prepend_content_to_of_brigade(msr, f);
|
||||||
|
|
||||||
|
/* Inject content into response (append & buffering). */
|
||||||
|
if ((msr->txcfg->content_injection_enabled) && (msr->content_append)) {
|
||||||
apr_bucket *bucket_ci = NULL;
|
apr_bucket *bucket_ci = NULL;
|
||||||
|
|
||||||
bucket_ci = apr_bucket_heap_create(msr->content_append,
|
bucket_ci = apr_bucket_heap_create(msr->content_append,
|
||||||
@@ -643,22 +772,8 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ap_pass_brigade(f->next, msr->of_brigade);
|
/* Send data down the filter stream. */
|
||||||
if (rc != APR_SUCCESS) {
|
if ((rc = send_of_brigade(msr, f)) != APR_SUCCESS) {
|
||||||
int log_level = 1;
|
|
||||||
|
|
||||||
if (APR_STATUS_IS_ECONNRESET(rc)) {
|
|
||||||
/* Message "Connection reset by peer" is common and not a sign
|
|
||||||
* of something unusual. Hence we don't want to make a big deal
|
|
||||||
* about it, logging at NOTICE level. Everything else we log
|
|
||||||
* at ERROR level.
|
|
||||||
*/
|
|
||||||
log_level = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
msr_log(msr, log_level, "Output filter: Error while forwarding response data (%i): %s",
|
|
||||||
rc, get_apr_error(msr->mp, rc));
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -668,9 +783,13 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
msr_log(msr, 4, "Output filter: Output forwarding complete.");
|
msr_log(msr, 4, "Output filter: Output forwarding complete.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr->of_skipping == 0) {
|
if ((msr->of_skipping == 0)&&(msr->of_partial == 0)) {
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Output filter: Sending input brigade directly.");
|
||||||
|
}
|
||||||
|
|
||||||
return ap_pass_brigade(f->next, bb_in);
|
return ap_pass_brigade(f->next, bb_in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -13,6 +13,52 @@
|
|||||||
#include "http_core.h"
|
#include "http_core.h"
|
||||||
#include "util_script.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);
|
||||||
|
|
||||||
|
/* Force alert log for any errors that are not already marked relevant
|
||||||
|
* to prevent any missing error messages in the code from going
|
||||||
|
* unnoticed. To prevent this error, all code should either set
|
||||||
|
* is_relevant, or just use msr_log with a level <= 3 prior to
|
||||||
|
* calling this function.
|
||||||
|
*/
|
||||||
|
if ((msr != NULL) && (msr->is_relevant == 0)) {
|
||||||
|
msr_log(msr, 1, "Internal error: Issuing \"%s\" for unspecified error.",
|
||||||
|
f->r->status_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
* Execute system command. First line of the output will be returned in
|
||||||
* the "output" parameter.
|
* the "output" parameter.
|
||||||
@@ -46,7 +92,7 @@ int apache2_exec(modsec_rec *msr, const char *command, const char **argv, char *
|
|||||||
|
|
||||||
procnew = apr_pcalloc(r->pool, sizeof(*procnew));
|
procnew = apr_pcalloc(r->pool, sizeof(*procnew));
|
||||||
if (procnew == NULL) {
|
if (procnew == NULL) {
|
||||||
msr_log(msr, 1, "Exec: Unable to allocate %i bytes.", sizeof(*procnew));
|
msr_log(msr, 1, "Exec: Unable to allocate %lu bytes.", (unsigned long)sizeof(*procnew));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,17 +177,17 @@ void record_time_checkpoint(modsec_rec *msr, int checkpoint_no) {
|
|||||||
msr->time_checkpoint_3 = now;
|
msr->time_checkpoint_3 = now;
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
msr_log(msr, 1, "Internal Error: Unknown checkpoint: %i", checkpoint_no);
|
msr_log(msr, 1, "Internal Error: Unknown checkpoint: %d", checkpoint_no);
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apache-specific stuff. */
|
/* Apache-specific stuff. */
|
||||||
apr_snprintf(note, 99, "%" APR_TIME_T_FMT, (now - msr->request_time));
|
apr_snprintf(note, 99, "%" APR_TIME_T_FMT, (now - msr->request_time));
|
||||||
apr_snprintf(note_name, 99, "mod_security-time%i", checkpoint_no);
|
apr_snprintf(note_name, 99, "mod_security-time%d", checkpoint_no);
|
||||||
apr_table_set(msr->r->notes, note_name, note);
|
apr_table_set(msr->r->notes, note_name, note);
|
||||||
|
|
||||||
msr_log(msr, 4, "Time #%i: %s", checkpoint_no, note);
|
msr_log(msr, 4, "Time #%d: %s", checkpoint_no, note);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -200,9 +246,9 @@ void internal_log(request_rec *r, directory_config *dcfg, modsec_rec *msr,
|
|||||||
|
|
||||||
/* Construct the message. */
|
/* Construct the message. */
|
||||||
apr_vsnprintf(str1, sizeof(str1), text, ap);
|
apr_vsnprintf(str1, sizeof(str1), text, ap);
|
||||||
apr_snprintf(str2, sizeof(str2), "[%s] [%s/sid#%lx][rid#%lx][%s][%i] %s\n",
|
apr_snprintf(str2, sizeof(str2), "[%s] [%s/sid#%pp][rid#%pp][%s][%d] %s\n",
|
||||||
current_logtime(msr->mp), ap_get_server_name(r), (unsigned long)(r->server),
|
current_logtime(msr->mp), ap_get_server_name(r), (r->server),
|
||||||
(unsigned long)r, ((r->uri == NULL) ? "" : log_escape_nq(msr->mp, r->uri)),
|
r, ((r->uri == NULL) ? "" : log_escape_nq(msr->mp, r->uri)),
|
||||||
level, str1);
|
level, str1);
|
||||||
|
|
||||||
/* Write to the debug log. */
|
/* Write to the debug log. */
|
||||||
@@ -230,10 +276,13 @@ void internal_log(request_rec *r, directory_config *dcfg, modsec_rec *msr,
|
|||||||
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server,
|
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server,
|
||||||
"[client %s] ModSecurity: %s%s [uri \"%s\"]%s", r->connection->remote_ip, str1,
|
"[client %s] ModSecurity: %s%s [uri \"%s\"]%s", r->connection->remote_ip, str1,
|
||||||
hostname, log_escape(msr->mp, r->unparsed_uri), unique_id);
|
hostname, log_escape(msr->mp, r->uri), unique_id);
|
||||||
|
|
||||||
/* Add this message to the list. */
|
/* Add this message to the list. */
|
||||||
if (msr != NULL) {
|
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);
|
*(const char **)apr_array_push(msr->alerts) = apr_pstrdup(msr->mp, str1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,15 +320,15 @@ char *format_error_log_message(apr_pool_t *mp, error_message *em) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (em->line > 0) {
|
if (em->line > 0) {
|
||||||
s_line = apr_psprintf(mp, "[line %i] ", em->line);
|
s_line = apr_psprintf(mp, "[line %d] ", em->line);
|
||||||
if (s_line == NULL) return NULL;
|
if (s_line == NULL) return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_level = apr_psprintf(mp, "[level %i] ", em->level);
|
s_level = apr_psprintf(mp, "[level %d] ", em->level);
|
||||||
if (s_level == NULL) return NULL;
|
if (s_level == NULL) return NULL;
|
||||||
|
|
||||||
if (em->status != 0) {
|
if (em->status != 0) {
|
||||||
s_status = apr_psprintf(mp, "[status %i] ", em->status);
|
s_status = apr_psprintf(mp, "[status %d] ", em->status);
|
||||||
if (s_status == NULL) return NULL;
|
if (s_status == NULL) return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ This directory contains two examples how you can extend
|
|||||||
ModSecurity without having to touch it directly, simply
|
ModSecurity without having to touch it directly, simply
|
||||||
by creating custom Apache modules.
|
by creating custom Apache modules.
|
||||||
|
|
||||||
|
NOTE: ModSecurity must be compiled with API support
|
||||||
|
to use this feature (do not use -DNO_MODSEC_API).
|
||||||
|
|
||||||
1)
|
1)
|
||||||
|
|
||||||
Module mod_tfn_reverse.c creates a custom transformation
|
Module mod_tfn_reverse.c creates a custom transformation
|
||||||
|
|||||||
130
apache2/build/PrintPath
Executable file
130
apache2/build/PrintPath
Executable file
@@ -0,0 +1,130 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
# contributor license agreements. See the NOTICE file distributed with
|
||||||
|
# this work for additional information regarding copyright ownership.
|
||||||
|
# The ASF licenses this file to You 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.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Look for program[s] somewhere in $PATH.
|
||||||
|
#
|
||||||
|
# Options:
|
||||||
|
# -s
|
||||||
|
# Do not print out full pathname. (silent)
|
||||||
|
# -pPATHNAME
|
||||||
|
# Look in PATHNAME instead of $PATH
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# PrintPath [-s] [-pPATHNAME] program [program ...]
|
||||||
|
#
|
||||||
|
# Initially written by Jim Jagielski for the Apache configuration mechanism
|
||||||
|
# (with kudos to Kernighan/Pike)
|
||||||
|
|
||||||
|
##
|
||||||
|
# Some "constants"
|
||||||
|
##
|
||||||
|
pathname=$PATH
|
||||||
|
echo="yes"
|
||||||
|
|
||||||
|
##
|
||||||
|
# Find out what OS we are running for later on
|
||||||
|
##
|
||||||
|
os=`(uname) 2>/dev/null`
|
||||||
|
|
||||||
|
##
|
||||||
|
# Parse command line
|
||||||
|
##
|
||||||
|
for args in $*
|
||||||
|
do
|
||||||
|
case $args in
|
||||||
|
-s ) echo="no" ;;
|
||||||
|
-p* ) pathname="`echo $args | sed 's/^..//'`" ;;
|
||||||
|
* ) programs="$programs $args" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
##
|
||||||
|
# Now we make the adjustments required for OS/2 and everyone
|
||||||
|
# else :)
|
||||||
|
#
|
||||||
|
# First of all, all OS/2 programs have the '.exe' extension.
|
||||||
|
# Next, we adjust PATH (or what was given to us as PATH) to
|
||||||
|
# be whitespace separated directories.
|
||||||
|
# Finally, we try to determine the best flag to use for
|
||||||
|
# test/[] to look for an executable file. OS/2 just has '-r'
|
||||||
|
# but with other OSs, we do some funny stuff to check to see
|
||||||
|
# if test/[] knows about -x, which is the prefered flag.
|
||||||
|
##
|
||||||
|
|
||||||
|
if [ "x$os" = "xOS/2" ]
|
||||||
|
then
|
||||||
|
ext=".exe"
|
||||||
|
pathname=`echo -E $pathname |
|
||||||
|
sed 's/^;/.;/
|
||||||
|
s/;;/;.;/g
|
||||||
|
s/;$/;./
|
||||||
|
s/;/ /g
|
||||||
|
s/\\\\/\\//g' `
|
||||||
|
test_exec_flag="-r"
|
||||||
|
else
|
||||||
|
ext="" # No default extensions
|
||||||
|
pathname=`echo $pathname |
|
||||||
|
sed 's/^:/.:/
|
||||||
|
s/::/:.:/g
|
||||||
|
s/:$/:./
|
||||||
|
s/:/ /g' `
|
||||||
|
# Here is how we test to see if test/[] can handle -x
|
||||||
|
testfile="pp.t.$$"
|
||||||
|
|
||||||
|
cat > $testfile <<ENDTEST
|
||||||
|
#!/bin/sh
|
||||||
|
if [ -x / ] || [ -x /bin ] || [ -x /bin/ls ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
ENDTEST
|
||||||
|
|
||||||
|
if `/bin/sh $testfile 2>/dev/null`; then
|
||||||
|
test_exec_flag="-x"
|
||||||
|
else
|
||||||
|
test_exec_flag="-r"
|
||||||
|
fi
|
||||||
|
rm -f $testfile
|
||||||
|
fi
|
||||||
|
|
||||||
|
for program in $programs
|
||||||
|
do
|
||||||
|
for path in $pathname
|
||||||
|
do
|
||||||
|
if [ $test_exec_flag $path/${program}${ext} ] && \
|
||||||
|
[ ! -d $path/${program}${ext} ]; then
|
||||||
|
if [ "x$echo" = "xyes" ]; then
|
||||||
|
echo $path/${program}${ext}
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Next try without extension (if one was used above)
|
||||||
|
if [ "x$ext" != "x" ]; then
|
||||||
|
if [ $test_exec_flag $path/${program} ] && \
|
||||||
|
[ ! -d $path/${program} ]; then
|
||||||
|
if [ "x$echo" = "xyes" ]; then
|
||||||
|
echo $path/${program}
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
|
||||||
12
apache2/build/apxs-wrapper.in
Executable file
12
apache2/build/apxs-wrapper.in
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!@SHELL@
|
||||||
|
|
||||||
|
WRAPPED_OPTS=""
|
||||||
|
for opt in "$@"; do
|
||||||
|
case "$opt" in
|
||||||
|
# Fix for -R not working w/apxs
|
||||||
|
-R*) WRAPPED_OPTS="$WRAPPED_OPTS -Wl,$opt" ;;
|
||||||
|
*) WRAPPED_OPTS="$WRAPPED_OPTS $opt" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
exec @APXS@ $WRAPPED_OPTS
|
||||||
54
apache2/build/buildcheck.sh
Executable file
54
apache2/build/buildcheck.sh
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
echo "buildconf: checking installation..."
|
||||||
|
|
||||||
|
# autoconf 2.50 or newer
|
||||||
|
ac_version=`${AUTOCONF:-autoconf} --version 2>/dev/null|sed -e 's/^[^0-9]*//;s/[a-z]* *$//;q'`
|
||||||
|
if test -z "$ac_version"; then
|
||||||
|
echo "buildconf: autoconf not found."
|
||||||
|
echo " You need autoconf version 2.50 or newer installed"
|
||||||
|
echo " to build APR from SVN."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
IFS=.; set $ac_version; IFS=' '
|
||||||
|
if test "$1" = "2" -a "$2" -lt "50" || test "$1" -lt "2"; then
|
||||||
|
echo "buildconf: autoconf version $ac_version found."
|
||||||
|
echo " You need autoconf version 2.50 or newer installed"
|
||||||
|
echo " to build APR from SVN."
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "buildconf: autoconf version $ac_version (ok)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Sample libtool --version outputs:
|
||||||
|
# ltmain.sh (GNU libtool) 1.3.3 (1.385.2.181 1999/07/02 15:49:11)
|
||||||
|
# ltmain.sh (GNU libtool 1.1361 2004/01/02 23:10:52) 1.5a
|
||||||
|
# output is multiline from 1.5 onwards
|
||||||
|
|
||||||
|
# Require libtool 1.4 or newer
|
||||||
|
libtool=`build/PrintPath glibtool libtool libtool15 libtool14`
|
||||||
|
lt_pversion=`$libtool --version 2>/dev/null|sed -e 's/([^)]*)//g;s/^[^0-9]*//;s/[- ].*//g;q'`
|
||||||
|
if test -z "$lt_pversion"; then
|
||||||
|
echo "buildconf: libtool not found."
|
||||||
|
echo " You need libtool version 1.4 or newer installed"
|
||||||
|
echo " to build APR from SVN."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
lt_version=`echo $lt_pversion|sed -e 's/\([a-z]*\)$/.\1/'`
|
||||||
|
IFS=.; set $lt_version; IFS=' '
|
||||||
|
lt_status="good"
|
||||||
|
if test "$1" = "1"; then
|
||||||
|
if test "$2" -lt "4"; then
|
||||||
|
lt_status="bad"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if test $lt_status = "good"; then
|
||||||
|
echo "buildconf: libtool version $lt_pversion (ok)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "buildconf: libtool version $lt_pversion found."
|
||||||
|
echo " You need libtool version 1.4 or newer installed"
|
||||||
|
echo " to build APR from SVN."
|
||||||
|
|
||||||
|
exit 1
|
||||||
73
apache2/build/find_apr.m4
Normal file
73
apache2/build/find_apr.m4
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
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_LDFLAGS=""
|
||||||
|
APR_LIBS=""
|
||||||
|
APR_LINK_LD=""
|
||||||
|
|
||||||
|
AC_DEFUN([CHECK_APR],
|
||||||
|
[dnl
|
||||||
|
|
||||||
|
AC_ARG_WITH(
|
||||||
|
apr,
|
||||||
|
[AC_HELP_STRING([--with-apr=PATH],[Path to the apr prefix])],
|
||||||
|
apr_path="$withval",
|
||||||
|
:)
|
||||||
|
|
||||||
|
dnl # Determine apr lib directory
|
||||||
|
if test -z "${apr_path}"; then
|
||||||
|
test_paths="/usr/local/apr /usr/local /usr"
|
||||||
|
else
|
||||||
|
test_paths="${apr_path}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for libapr config script])
|
||||||
|
for x in ${test_paths}; do
|
||||||
|
for APR_CONFIG in apr-1-config apr-config; do
|
||||||
|
if test -e "${x}/bin/${APR_CONFIG}"; then
|
||||||
|
with_apr="${x}/bin"
|
||||||
|
break
|
||||||
|
elif test -e "${x}/${APR_CONFIG}"; then
|
||||||
|
with_apr="${x}"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
with_apr=""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -n "$with_apr"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -n "${with_apr}"; then
|
||||||
|
APR_CONFIG="${with_apr}/${APR_CONFIG}"
|
||||||
|
AC_MSG_RESULT([${APR_CONFIG}])
|
||||||
|
APR_CFLAGS="`${APR_CONFIG} --includes --cppflags --cflags`"
|
||||||
|
APR_LDFLAGS="`${APR_CONFIG} --ldflags`"
|
||||||
|
APR_LIBS="`${APR_CONFIG} --libs`"
|
||||||
|
APR_LINK_LD="`${APR_CONFIG} --link-ld`"
|
||||||
|
CFLAGS=$save_CFLAGS
|
||||||
|
LDFLAGS=$save_LDFLAGS
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_SUBST(APR_LIBS)
|
||||||
|
AC_SUBST(APR_CFLAGS)
|
||||||
|
AC_SUBST(APR_LDFLAGS)
|
||||||
|
AC_SUBST(APR_LINK_LD)
|
||||||
|
|
||||||
|
if test -z "${APR_LIBS}"; then
|
||||||
|
AC_MSG_NOTICE([*** apr library not found.])
|
||||||
|
ifelse([$2], , AC_MSG_ERROR([apr library is required]), $2)
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE([using '${APR_LIBS}' for apr Library])
|
||||||
|
ifelse([$1], , , $1)
|
||||||
|
fi
|
||||||
|
])
|
||||||
73
apache2/build/find_apu.m4
Normal file
73
apache2/build/find_apu.m4
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
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_LIBS=""
|
||||||
|
APU_LINK_LD=""
|
||||||
|
|
||||||
|
AC_DEFUN([CHECK_APU],
|
||||||
|
[dnl
|
||||||
|
|
||||||
|
AC_ARG_WITH(
|
||||||
|
apu,
|
||||||
|
[AC_HELP_STRING([--with-apu=PATH],[Path to the apu prefix])],
|
||||||
|
apu_path="$withval",
|
||||||
|
:)
|
||||||
|
|
||||||
|
dnl # Determine apu lib directory
|
||||||
|
if test -z "${apu_path}"; then
|
||||||
|
test_paths="/usr/local/apr /usr/local /usr"
|
||||||
|
else
|
||||||
|
test_paths="${apu_path}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for libapr-util config script])
|
||||||
|
for x in ${test_paths}; do
|
||||||
|
for APU_CONFIG in apu-1-config apu-config; do
|
||||||
|
if test -e "${x}/bin/${APU_CONFIG}"; then
|
||||||
|
with_apu="${x}/bin"
|
||||||
|
break
|
||||||
|
elif test -e "${x}/${APU_CONFIG}"; then
|
||||||
|
with_apu="${x}"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
with_apu=""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -n "$with_apu"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -n "${with_apu}"; then
|
||||||
|
APU_CONFIG="${with_apu}/${APU_CONFIG}"
|
||||||
|
AC_MSG_RESULT([${APU_CONFIG}])
|
||||||
|
APU_CFLAGS="`${APU_CONFIG} --includes`"
|
||||||
|
APU_LDFLAGS="`${APU_CONFIG} --ldflags`"
|
||||||
|
APU_LIBS="`${APU_CONFIG} --libs`"
|
||||||
|
APU_LINK_LD="`${APU_CONFIG} --link-ld`"
|
||||||
|
CFLAGS=$save_CFLAGS
|
||||||
|
LDFLAGS=$save_LDFLAGS
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_SUBST(APU_LIBS)
|
||||||
|
AC_SUBST(APU_CFLAGS)
|
||||||
|
AC_SUBST(APU_LDFLAGS)
|
||||||
|
AC_SUBST(APU_LINK_LD)
|
||||||
|
|
||||||
|
if test -z "${APU_LIBS}"; then
|
||||||
|
AC_MSG_NOTICE([*** apu library not found.])
|
||||||
|
ifelse([$2], , AC_MSG_ERROR([apu library is required]), $2)
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE([using '${APU_LINK_LD}' for apu Library])
|
||||||
|
ifelse([$1], , , $1)
|
||||||
|
fi
|
||||||
|
])
|
||||||
57
apache2/build/find_curl.m4
Normal file
57
apache2/build/find_curl.m4
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
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-config"
|
||||||
|
CURL_CFLAGS=""
|
||||||
|
CURL_LIBS=""
|
||||||
|
|
||||||
|
AC_DEFUN([CHECK_CURL],
|
||||||
|
[dnl
|
||||||
|
|
||||||
|
AC_ARG_WITH(
|
||||||
|
curl,
|
||||||
|
[AC_HELP_STRING([--with-curl=PATH],[Path to the curl prefix])],
|
||||||
|
curl_path="$withval",
|
||||||
|
:)
|
||||||
|
|
||||||
|
dnl # Determine curl lib directory
|
||||||
|
if test -z "${curl_path}"; then
|
||||||
|
test_paths="/usr/local /usr"
|
||||||
|
else
|
||||||
|
test_paths="${curl_path}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for libcurl config script])
|
||||||
|
for x in ${test_paths}; do
|
||||||
|
if test -e "${x}/bin/${CURL_CONFIG}"; then
|
||||||
|
with_curl="${x}/bin"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
with_curl=""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -n "${with_curl}"; then
|
||||||
|
CURL_CONFIG="${with_curl}/${CURL_CONFIG}"
|
||||||
|
AC_MSG_RESULT([${CURL_CONFIG}])
|
||||||
|
CURL_CFLAGS="`${CURL_CONFIG} --cflags`"
|
||||||
|
CURL_LIBS="`${CURL_CONFIG} --libs`"
|
||||||
|
CFLAGS=$save_CFLAGS
|
||||||
|
LDFLAGS=$save_LDFLAGS
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_SUBST(CURL_LIBS)
|
||||||
|
AC_SUBST(CURL_CFLAGS)
|
||||||
|
|
||||||
|
if test -z "${CURL_LIBS}"; 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_LIBS}' for curl Library])
|
||||||
|
ifelse([$1], , , $1)
|
||||||
|
fi
|
||||||
|
])
|
||||||
123
apache2/build/find_lua.m4
Normal file
123
apache2/build/find_lua.m4
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
dnl Check for LUA Libraries
|
||||||
|
dnl CHECK_LUA(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
|
||||||
|
dnl Sets:
|
||||||
|
dnl LUA_CFLAGS
|
||||||
|
dnl LUA_LIBS
|
||||||
|
|
||||||
|
LUA_CONFIG="pkg-config"
|
||||||
|
LUA_PKGNAMES="lua5.1 lua5 lua"
|
||||||
|
LUA_CFLAGS=""
|
||||||
|
LUA_LIBS=""
|
||||||
|
|
||||||
|
AC_DEFUN([CHECK_LUA],
|
||||||
|
[dnl
|
||||||
|
|
||||||
|
AC_ARG_WITH(
|
||||||
|
lua,
|
||||||
|
[AC_HELP_STRING([--with-lua=PATH],[Path to the lua prefix])],
|
||||||
|
lua_path="$withval",
|
||||||
|
:)
|
||||||
|
|
||||||
|
if test "${lua_path}" != "no"; then
|
||||||
|
dnl # Determine lua lib directory
|
||||||
|
if test -z "${lua_path}"; then
|
||||||
|
test_paths="/usr/local /usr"
|
||||||
|
else
|
||||||
|
test_paths="${lua_path}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for pkg-config script for lua library])
|
||||||
|
for x in ${test_paths}; do
|
||||||
|
if test -e "${x}/bin/${LUA_CONFIG}"; then
|
||||||
|
with_lua="${x}/bin"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
with_lua=""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -n "${with_lua}"; then
|
||||||
|
LUA_CONFIG="${with_lua}/${LUA_CONFIG}"
|
||||||
|
for LUA_PKGNAME in ${LUA_PKGNAMES}; do
|
||||||
|
if ${LUA_CONFIG} --exists ${LUA_PKGNAME}; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
LUA_PKGNAME=""
|
||||||
|
done
|
||||||
|
if test -n "$LUA_PKGNAME"; then
|
||||||
|
AC_MSG_RESULT([${LUA_CONFIG} ${LUA_PKGNAME}])
|
||||||
|
LUA_CFLAGS="`${LUA_CONFIG} ${LUA_PKGNAME} --cflags`"
|
||||||
|
LUA_LIBS="`${LUA_CONFIG} ${LUA_PKGNAME} --libs`"
|
||||||
|
CFLAGS=$save_CFLAGS
|
||||||
|
LDFLAGS=$save_LDFLAGS
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
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
|
||||||
|
if test -e "${x}/liblua5.1.a"; then
|
||||||
|
with_lua_lib="${x}"
|
||||||
|
lua_lib_name="lua5.1"
|
||||||
|
break
|
||||||
|
elif test -e "${x}/lib/liblua5.1.a"; then
|
||||||
|
with_lua_lib="${x}/lib"
|
||||||
|
lua_lib_name="lua5.1"
|
||||||
|
break
|
||||||
|
elif test -e "${x}/liblua.a"; then
|
||||||
|
with_lua_lib="${x}"
|
||||||
|
lua_lib_name="lua"
|
||||||
|
break
|
||||||
|
elif test -e "${x}/lib/liblua.a"; then
|
||||||
|
with_lua_lib="${x}/lib"
|
||||||
|
lua_lib_name="lua"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
with_lua_lib=""
|
||||||
|
lua_lib_name=""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
for x in ${test_paths}; do
|
||||||
|
if test -e "${x}/lua.h"; then
|
||||||
|
with_lua_inc="${x}"
|
||||||
|
break
|
||||||
|
elif test -e "${x}/include/lua.h"; then
|
||||||
|
with_lua_inc="${x}/include"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
with_lua_inc=""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -n "${with_lua_lib}" -a -n "${with_lua_inc}"; then
|
||||||
|
LUA_CONFIG=""
|
||||||
|
AC_MSG_RESULT([${with_lua_lib} ${with_lua_inc}])
|
||||||
|
LUA_CFLAGS="-I${with_lua_inc}"
|
||||||
|
LUA_LIBS="-L${with_lua_lib} -l${lua_lib_name}"
|
||||||
|
CFLAGS=$save_CFLAGS
|
||||||
|
LDFLAGS=$save_LDFLAGS
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE([not using optional lua library])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -n "${LUA_LIBS}"; then
|
||||||
|
LUA_CFLAGS="-DWITH_LUA ${LUA_CFLAGS}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_SUBST(LUA_LIBS)
|
||||||
|
AC_SUBST(LUA_CFLAGS)
|
||||||
|
|
||||||
|
if test "${lua_path}" != "no"; then
|
||||||
|
if test -z "${LUA_LIBS}"; then
|
||||||
|
ifelse([$2], , AC_MSG_NOTICE([optional lua library not found]), $2)
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE([using '${LUA_LIBS}' for lua Library])
|
||||||
|
ifelse([$1], , , $1)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
])
|
||||||
60
apache2/build/find_pcre.m4
Normal file
60
apache2/build/find_pcre.m4
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
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-config"
|
||||||
|
PCRE_CFLAGS=""
|
||||||
|
PCRE_LIBS=""
|
||||||
|
|
||||||
|
AC_DEFUN([CHECK_PCRE],
|
||||||
|
[dnl
|
||||||
|
|
||||||
|
AC_ARG_WITH(
|
||||||
|
pcre,
|
||||||
|
[AC_HELP_STRING([--with-pcre=PATH],[Path to the pcre prefix])],
|
||||||
|
pcre_path="$withval",
|
||||||
|
:)
|
||||||
|
|
||||||
|
dnl # Determine pcre lib directory
|
||||||
|
if test -z "${pcre_path}"; then
|
||||||
|
test_paths="/usr/local /usr"
|
||||||
|
else
|
||||||
|
test_paths="${pcre_path}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for libpcre config script])
|
||||||
|
for x in ${test_paths}; do
|
||||||
|
if test -e "${x}/bin/${PCRE_CONFIG}"; then
|
||||||
|
with_pcre="${x}/bin"
|
||||||
|
break
|
||||||
|
elif test -e "${x}/${PCRE_CONFIG}"; then
|
||||||
|
with_pcre="${x}"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
with_pcre=""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -n "${with_pcre}"; then
|
||||||
|
PCRE_CONFIG="${with_pcre}/${PCRE_CONFIG}"
|
||||||
|
AC_MSG_RESULT([${PCRE_CONFIG}])
|
||||||
|
PCRE_CFLAGS="`${PCRE_CONFIG} --cflags`"
|
||||||
|
PCRE_LIBS="`${PCRE_CONFIG} --libs`"
|
||||||
|
CFLAGS=$save_CFLAGS
|
||||||
|
LDFLAGS=$save_LDFLAGS
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_SUBST(PCRE_LIBS)
|
||||||
|
AC_SUBST(PCRE_CFLAGS)
|
||||||
|
|
||||||
|
if test -z "${PCRE_LIBS}"; then
|
||||||
|
AC_MSG_NOTICE([*** pcre library not found.])
|
||||||
|
ifelse([$2], , AC_MSG_ERROR([pcre library is required]), $2)
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE([using '${PCRE_LIBS}' for pcre Library])
|
||||||
|
ifelse([$1], , , $1)
|
||||||
|
fi
|
||||||
|
])
|
||||||
57
apache2/build/find_xml.m4
Normal file
57
apache2/build/find_xml.m4
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
dnl Check for XML Libraries
|
||||||
|
dnl CHECK_LIBXML(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
|
||||||
|
dnl Sets:
|
||||||
|
dnl LIBXML_CFLAGS
|
||||||
|
dnl LIBXML_LIBS
|
||||||
|
|
||||||
|
LIBXML_CONFIG="xml2-config"
|
||||||
|
LIBXML_CFLAGS=""
|
||||||
|
LIBXML_LIBS=""
|
||||||
|
|
||||||
|
AC_DEFUN([CHECK_LIBXML],
|
||||||
|
[dnl
|
||||||
|
|
||||||
|
AC_ARG_WITH(
|
||||||
|
libxml,
|
||||||
|
[AC_HELP_STRING([--with-libxml=PATH],[Path to the libxml2 prefix])],
|
||||||
|
libxml_path="$withval",
|
||||||
|
:)
|
||||||
|
|
||||||
|
dnl # Determine xml lib directory
|
||||||
|
if test -z "${libxml_path}"; then
|
||||||
|
test_paths="/usr/local /usr"
|
||||||
|
else
|
||||||
|
test_paths="${libxml_path}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for libxml2 config script])
|
||||||
|
for x in ${test_paths}; do
|
||||||
|
if test -e "${x}/bin/${LIBXML_CONFIG}"; then
|
||||||
|
with_libxml="${x}/bin"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
with_libxml=""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -n "${with_libxml}"; then
|
||||||
|
LIBXML_CONFIG="${with_libxml}/${LIBXML_CONFIG}"
|
||||||
|
AC_MSG_RESULT([${LIBXML_CONFIG}])
|
||||||
|
LIBXML_CFLAGS="`${LIBXML_CONFIG} --cflags`"
|
||||||
|
LIBXML_LIBS="`${LIBXML_CONFIG} --libs`"
|
||||||
|
CFLAGS=$save_CFLAGS
|
||||||
|
LDFLAGS=$save_LDFLAGS
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_SUBST(LIBXML_LIBS)
|
||||||
|
AC_SUBST(LIBXML_CFLAGS)
|
||||||
|
|
||||||
|
if test -z "${LIBXML_LIBS}"; then
|
||||||
|
AC_MSG_NOTICE([*** libxml2 library not found.])
|
||||||
|
ifelse([$2], , AC_MSG_ERROR([libxml2 library is required]), $2)
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE([using '${LIBXML_LIBS}' for libxml Library])
|
||||||
|
ifelse([$1], , , $1)
|
||||||
|
fi
|
||||||
|
])
|
||||||
224
apache2/build/install-sh
Executable file
224
apache2/build/install-sh
Executable file
@@ -0,0 +1,224 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
##
|
||||||
|
## install.sh -- install a program, script or datafile
|
||||||
|
##
|
||||||
|
## Based on `install-sh' from the X Consortium's X11R5 distribution
|
||||||
|
## as of 89/12/18 which is freely available.
|
||||||
|
## Cleaned up for Apache's Autoconf-style Interface (APACI)
|
||||||
|
## by Ralf S. Engelschall <rse@apache.org>
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# This script falls under the Apache License.
|
||||||
|
# See http://www.apache.org/docs/LICENSE
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# put in absolute paths if you don't have them in your path;
|
||||||
|
# or use env. vars.
|
||||||
|
#
|
||||||
|
mvprog="${MVPROG-mv}"
|
||||||
|
cpprog="${CPPROG-cp}"
|
||||||
|
chmodprog="${CHMODPROG-chmod}"
|
||||||
|
chownprog="${CHOWNPROG-chown}"
|
||||||
|
chgrpprog="${CHGRPPROG-chgrp}"
|
||||||
|
stripprog="${STRIPPROG-strip}"
|
||||||
|
rmprog="${RMPROG-rm}"
|
||||||
|
|
||||||
|
#
|
||||||
|
# parse argument line
|
||||||
|
#
|
||||||
|
instcmd="$mvprog"
|
||||||
|
chmodcmd=""
|
||||||
|
chowncmd=""
|
||||||
|
chgrpcmd=""
|
||||||
|
stripcmd=""
|
||||||
|
rmcmd="$rmprog -f"
|
||||||
|
mvcmd="$mvprog"
|
||||||
|
ext=""
|
||||||
|
src=""
|
||||||
|
dst=""
|
||||||
|
while [ "x$1" != "x" ]; do
|
||||||
|
case $1 in
|
||||||
|
-c) instcmd="$cpprog"
|
||||||
|
shift; continue
|
||||||
|
;;
|
||||||
|
-m) chmodcmd="$chmodprog $2"
|
||||||
|
shift; shift; continue
|
||||||
|
;;
|
||||||
|
-o) chowncmd="$chownprog $2"
|
||||||
|
shift; shift; continue
|
||||||
|
;;
|
||||||
|
-g) chgrpcmd="$chgrpprog $2"
|
||||||
|
shift; shift; continue
|
||||||
|
;;
|
||||||
|
-s) stripcmd="$stripprog"
|
||||||
|
shift; continue
|
||||||
|
;;
|
||||||
|
-S) stripcmd="$stripprog $2"
|
||||||
|
shift; shift; continue
|
||||||
|
;;
|
||||||
|
-e) ext="$2"
|
||||||
|
shift; shift; continue
|
||||||
|
;;
|
||||||
|
*) if [ "x$src" = "x" ]; then
|
||||||
|
src=$1
|
||||||
|
else
|
||||||
|
dst=$1
|
||||||
|
fi
|
||||||
|
shift; continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
if [ "x$src" = "x" ]; then
|
||||||
|
echo "install.sh: no input file specified"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "x$dst" = "x" ]; then
|
||||||
|
echo "install.sh: no destination specified"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# If destination is a directory, append the input filename; if
|
||||||
|
# your system does not like double slashes in filenames, you may
|
||||||
|
# need to add some logic
|
||||||
|
#
|
||||||
|
if [ -d $dst ]; then
|
||||||
|
dst="$dst/`basename $src`"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add a possible extension (such as ".exe") to src and dst
|
||||||
|
src="$src$ext"
|
||||||
|
dst="$dst$ext"
|
||||||
|
|
||||||
|
# Make a temp file name in the proper directory.
|
||||||
|
dstdir=`dirname $dst`
|
||||||
|
dsttmp=$dstdir/#inst.$$#
|
||||||
|
|
||||||
|
# Move or copy the file name to the temp name
|
||||||
|
$instcmd $src $dsttmp
|
||||||
|
|
||||||
|
# And set any options; do chmod last to preserve setuid bits
|
||||||
|
if [ "x$chowncmd" != "x" ]; then $chowncmd $dsttmp; fi
|
||||||
|
if [ "x$chgrpcmd" != "x" ]; then $chgrpcmd $dsttmp; fi
|
||||||
|
if [ "x$stripcmd" != "x" ]; then $stripcmd $dsttmp; fi
|
||||||
|
if [ "x$chmodcmd" != "x" ]; then $chmodcmd $dsttmp; fi
|
||||||
|
|
||||||
|
# Now rename the file to the real destination.
|
||||||
|
$rmcmd $dst
|
||||||
|
$mvcmd $dsttmp $dst
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
#!/bin/sh
|
||||||
|
##
|
||||||
|
## install.sh -- install a program, script or datafile
|
||||||
|
##
|
||||||
|
## Based on `install-sh' from the X Consortium's X11R5 distribution
|
||||||
|
## as of 89/12/18 which is freely available.
|
||||||
|
## Cleaned up for Apache's Autoconf-style Interface (APACI)
|
||||||
|
## by Ralf S. Engelschall <rse@apache.org>
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# This script falls under the Apache License.
|
||||||
|
# See http://www.apache.org/docs/LICENSE
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# put in absolute paths if you don't have them in your path;
|
||||||
|
# or use env. vars.
|
||||||
|
#
|
||||||
|
mvprog="${MVPROG-mv}"
|
||||||
|
cpprog="${CPPROG-cp}"
|
||||||
|
chmodprog="${CHMODPROG-chmod}"
|
||||||
|
chownprog="${CHOWNPROG-chown}"
|
||||||
|
chgrpprog="${CHGRPPROG-chgrp}"
|
||||||
|
stripprog="${STRIPPROG-strip}"
|
||||||
|
rmprog="${RMPROG-rm}"
|
||||||
|
|
||||||
|
#
|
||||||
|
# parse argument line
|
||||||
|
#
|
||||||
|
instcmd="$mvprog"
|
||||||
|
chmodcmd=""
|
||||||
|
chowncmd=""
|
||||||
|
chgrpcmd=""
|
||||||
|
stripcmd=""
|
||||||
|
rmcmd="$rmprog -f"
|
||||||
|
mvcmd="$mvprog"
|
||||||
|
ext=""
|
||||||
|
src=""
|
||||||
|
dst=""
|
||||||
|
while [ "x$1" != "x" ]; do
|
||||||
|
case $1 in
|
||||||
|
-c) instcmd="$cpprog"
|
||||||
|
shift; continue
|
||||||
|
;;
|
||||||
|
-m) chmodcmd="$chmodprog $2"
|
||||||
|
shift; shift; continue
|
||||||
|
;;
|
||||||
|
-o) chowncmd="$chownprog $2"
|
||||||
|
shift; shift; continue
|
||||||
|
;;
|
||||||
|
-g) chgrpcmd="$chgrpprog $2"
|
||||||
|
shift; shift; continue
|
||||||
|
;;
|
||||||
|
-s) stripcmd="$stripprog"
|
||||||
|
shift; continue
|
||||||
|
;;
|
||||||
|
-S) stripcmd="$stripprog $2"
|
||||||
|
shift; shift; continue
|
||||||
|
;;
|
||||||
|
-e) ext="$2"
|
||||||
|
shift; shift; continue
|
||||||
|
;;
|
||||||
|
*) if [ "x$src" = "x" ]; then
|
||||||
|
src=$1
|
||||||
|
else
|
||||||
|
dst=$1
|
||||||
|
fi
|
||||||
|
shift; continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
if [ "x$src" = "x" ]; then
|
||||||
|
echo "install.sh: no input file specified"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "x$dst" = "x" ]; then
|
||||||
|
echo "install.sh: no destination specified"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# If destination is a directory, append the input filename; if
|
||||||
|
# your system does not like double slashes in filenames, you may
|
||||||
|
# need to add some logic
|
||||||
|
#
|
||||||
|
if [ -d $dst ]; then
|
||||||
|
dst="$dst/`basename $src`"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add a possible extension (such as ".exe") to src and dst
|
||||||
|
src="$src$ext"
|
||||||
|
dst="$dst$ext"
|
||||||
|
|
||||||
|
# Make a temp file name in the proper directory.
|
||||||
|
dstdir=`dirname $dst`
|
||||||
|
dsttmp=$dstdir/#inst.$$#
|
||||||
|
|
||||||
|
# Move or copy the file name to the temp name
|
||||||
|
$instcmd $src $dsttmp
|
||||||
|
|
||||||
|
# And set any options; do chmod last to preserve setuid bits
|
||||||
|
if [ "x$chowncmd" != "x" ]; then $chowncmd $dsttmp; fi
|
||||||
|
if [ "x$chgrpcmd" != "x" ]; then $chgrpcmd $dsttmp; fi
|
||||||
|
if [ "x$stripcmd" != "x" ]; then $stripcmd $dsttmp; fi
|
||||||
|
if [ "x$chmodcmd" != "x" ]; then $chmodcmd $dsttmp; fi
|
||||||
|
|
||||||
|
# Now rename the file to the real destination.
|
||||||
|
$rmcmd $dst
|
||||||
|
$mvcmd $dsttmp $dst
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
86
apache2/buildconf
Executable file
86
apache2/buildconf
Executable file
@@ -0,0 +1,86 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
# contributor license agreements. See the NOTICE file distributed with
|
||||||
|
# this work for additional information regarding copyright ownership.
|
||||||
|
# The ASF licenses this file to You 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.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
# buildconf: Build the support scripts needed to compile from a
|
||||||
|
# checked-out version of the source code.
|
||||||
|
|
||||||
|
# Verify that the builder has the right config tools installed
|
||||||
|
#
|
||||||
|
build/buildcheck.sh || exit 1
|
||||||
|
|
||||||
|
echo "Generating config header ..."
|
||||||
|
autoheader -Wall || exit 1
|
||||||
|
|
||||||
|
libtoolize=`build/PrintPath glibtoolize libtoolize15 libtoolize14 libtoolize`
|
||||||
|
if [ "x$libtoolize" = "x" ]; then
|
||||||
|
echo "libtoolize not found in path"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create the libtool helper files
|
||||||
|
#
|
||||||
|
# Note: we copy (rather than link) them to simplify distribution.
|
||||||
|
# Note: APR supplies its own config.guess and config.sub -- we do not
|
||||||
|
# rely on libtool's versions
|
||||||
|
#
|
||||||
|
echo "Copying libtool helper files ..."
|
||||||
|
|
||||||
|
# Remove any libtool files so one can switch between libtool 1.3
|
||||||
|
# and libtool 1.4 by simply rerunning the buildconf script.
|
||||||
|
(cd build ; rm -f ltconfig ltmain.sh libtool.m4)
|
||||||
|
|
||||||
|
$libtoolize --copy --automake
|
||||||
|
|
||||||
|
if [ -f libtool.m4 ]; then
|
||||||
|
ltfile=`pwd`/libtool.m4
|
||||||
|
else
|
||||||
|
ltfindcmd="`sed -n \"/=[^\\\`]/p;/libtool_m4=/{s/.*=/echo /p;q;}\" \
|
||||||
|
< $libtoolize`"
|
||||||
|
ltfile=${LIBTOOL_M4-`eval "$ltfindcmd"`}
|
||||||
|
# Expecting the code above to be very portable, but just in case...
|
||||||
|
if [ -z "$ltfile" -o ! -f "$ltfile" ]; then
|
||||||
|
ltpath=`dirname $libtoolize`
|
||||||
|
ltfile=`cd $ltpath/../share/aclocal ; pwd`/libtool.m4
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f $ltfile ]; then
|
||||||
|
echo "$ltfile not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "buildconf: Using libtool.m4 at ${ltfile}."
|
||||||
|
|
||||||
|
cat $ltfile | sed -e 's/LIBTOOL=\(.*\)top_build/LIBTOOL=\1apr_build/' > build/libtool.m4
|
||||||
|
|
||||||
|
# libtool.m4 from 1.6 requires ltsugar.m4
|
||||||
|
if [ -f ltsugar.m4 ]; then
|
||||||
|
rm -f build/ltsugar.m4
|
||||||
|
mv ltsugar.m4 build/ltsugar.m4
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean up any leftovers
|
||||||
|
rm -f aclocal.m4 libtool.m4
|
||||||
|
|
||||||
|
echo "Creating configure ..."
|
||||||
|
${AUTOCONF:-autoconf}
|
||||||
|
|
||||||
|
# Remove autoconf 2.5x's cache directory
|
||||||
|
rm -rf autom4te*.cache
|
||||||
|
|
||||||
|
exit 0
|
||||||
258
apache2/configure.in
Normal file
258
apache2/configure.in
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
dnl
|
||||||
|
dnl Autoconf configuration for ModSecurity
|
||||||
|
dnl
|
||||||
|
dnl Use ./buildconf to produce a configure script
|
||||||
|
dnl
|
||||||
|
|
||||||
|
AC_PREREQ(2.50)
|
||||||
|
|
||||||
|
AC_INIT()
|
||||||
|
dnl AC_INIT(ModSecurity, 2.5, mod-security-users@lists.sourceforge.net, modsecurity-apache)
|
||||||
|
AC_CONFIG_SRCDIR([mod_security2.c])
|
||||||
|
AC_CONFIG_HEADER([mod_security2_config.h])
|
||||||
|
AC_CONFIG_AUX_DIR([build])
|
||||||
|
|
||||||
|
# Checks for programs.
|
||||||
|
AC_PROG_CXX
|
||||||
|
AC_PROG_CC
|
||||||
|
AC_PROG_CPP
|
||||||
|
AC_PROG_INSTALL
|
||||||
|
AC_PROG_LN_S
|
||||||
|
AC_PROG_MAKE_SET
|
||||||
|
AC_PROG_RANLIB
|
||||||
|
AC_PATH_PROGS(PERL, [perl perl5], )
|
||||||
|
|
||||||
|
# Checks for header files.
|
||||||
|
AC_HEADER_STDC
|
||||||
|
AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h])
|
||||||
|
|
||||||
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
|
AC_C_CONST
|
||||||
|
AC_C_INLINE
|
||||||
|
AC_C_RESTRICT
|
||||||
|
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 fchmod getcwd memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol])
|
||||||
|
|
||||||
|
# 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)],
|
||||||
|
[AC_MSG_ERROR(apache is too old, mmn must be at least $HTTPD_WANTED_MMN)])
|
||||||
|
fi
|
||||||
|
APXS_INCLUDES="`$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`"
|
||||||
|
APXS_CFLAGS="`$APXS -q CFLAGS` `$APXS -q EXTRA_CFLAGS`"
|
||||||
|
APXS_LDFLAGS="`$APXS -q LDFLAGS` `$APXS -q EXTRA_LDFLAGS`"
|
||||||
|
APXS_LIBS="`$APXS -q LIBS` `$APXS -q EXTRA_LIBS`"
|
||||||
|
APXS_LIBTOOL="`$APXS -q LIBTOOL`"
|
||||||
|
APXS_CC="`$APXS -q CC`"
|
||||||
|
else
|
||||||
|
AC_MSG_ERROR(couldn't find APXS)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use Apache httpd source srclib as base for pcre, apr and apu config scripts
|
||||||
|
AC_ARG_WITH(httpd-src,
|
||||||
|
[AS_HELP_STRING([[--with-httpd-src=PATH]],
|
||||||
|
[PATH is to the Apache httpd source tree where srclib will be used as a base for pcre, apr and apu config scripts.])],
|
||||||
|
[
|
||||||
|
if test -n "$withval"; then
|
||||||
|
CPPFLAGS="$CPPFLAGS -I$withval/srclib/pcre"
|
||||||
|
LDFLAGS="$LDFLAGS -L$withval/srclib/pcre"
|
||||||
|
pcre_path="$withval/srclib/pcre"
|
||||||
|
apr_path="$withval/srclib/apr"
|
||||||
|
apu_path="$withval/srclib/apr-util"
|
||||||
|
else
|
||||||
|
AC_MSG_ERROR(--with-httpd-src requires a path)
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
# Include M4 macros
|
||||||
|
sinclude(build/find_pcre.m4)
|
||||||
|
sinclude(build/find_apr.m4)
|
||||||
|
sinclude(build/find_apu.m4)
|
||||||
|
sinclude(build/find_xml.m4)
|
||||||
|
sinclude(build/find_lua.m4)
|
||||||
|
sinclude(build/find_curl.m4)
|
||||||
|
|
||||||
|
|
||||||
|
### Configure Options
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
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"
|
||||||
|
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"
|
||||||
|
else
|
||||||
|
debug_acmp=
|
||||||
|
fi
|
||||||
|
],
|
||||||
|
[
|
||||||
|
debug_acmp=
|
||||||
|
])
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
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"
|
||||||
|
else
|
||||||
|
modsec_api=
|
||||||
|
fi
|
||||||
|
],
|
||||||
|
[
|
||||||
|
modsec_api=
|
||||||
|
])
|
||||||
|
|
||||||
|
### Build *EXTRA_CFLAGS vars
|
||||||
|
|
||||||
|
EXTRA_CFLAGS="-O2 -g -Wall -Werror"
|
||||||
|
MODSEC_EXTRA_CFLAGS="$debug_conf $debug_cache $debug_acmp $perf_meas $modsec_api"
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
save_CPPFLAGS=$CPPFLAGS
|
||||||
|
CPPFLAGS="$APXS_INCLUDES $CPPFLAGS"
|
||||||
|
save_LDFLAGS=$LDFLAGS
|
||||||
|
LDFLAGS="$APXS_LDFLAGS $LDFLAGS"
|
||||||
|
|
||||||
|
AC_SUBST(EXTRA_CFLAGS)
|
||||||
|
AC_SUBST(MODSEC_EXTRA_CFLAGS)
|
||||||
|
AC_SUBST(APXS)
|
||||||
|
AC_SUBST(APXS_WRAPPER)
|
||||||
|
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)
|
||||||
|
|
||||||
|
CHECK_PCRE()
|
||||||
|
CHECK_APR()
|
||||||
|
CHECK_APU()
|
||||||
|
CHECK_LIBXML()
|
||||||
|
CHECK_LUA()
|
||||||
|
CHECK_CURL()
|
||||||
|
|
||||||
|
AC_CONFIG_FILES([Makefile])
|
||||||
|
AC_CONFIG_FILES([build/apxs-wrapper], [chmod +x build/apxs-wrapper])
|
||||||
|
if test -e "$PERL"; then
|
||||||
|
AC_CONFIG_FILES([t/run-tests.pl], [chmod +x t/run-tests.pl])
|
||||||
|
|
||||||
|
# Perl based tools
|
||||||
|
AC_CONFIG_FILES([../tools/rules-updater.pl], [chmod +x ../tools/rules-updater.pl])
|
||||||
|
fi
|
||||||
|
if test -e "mlogc-src/Makefile.in"; then
|
||||||
|
AC_CONFIG_FILES([mlogc-src/Makefile])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_OUTPUT
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "modsecurity.h"
|
#include "modsecurity.h"
|
||||||
#include "apache2.h"
|
#include "apache2.h"
|
||||||
|
#include "http_main.h"
|
||||||
#include "pdf_protect.h"
|
#include "pdf_protect.h"
|
||||||
#include "msc_logging.h"
|
#include "msc_logging.h"
|
||||||
#include "msc_util.h"
|
#include "msc_util.h"
|
||||||
@@ -24,7 +25,6 @@
|
|||||||
|
|
||||||
msc_engine DSOLOCAL *modsecurity = NULL;
|
msc_engine DSOLOCAL *modsecurity = NULL;
|
||||||
|
|
||||||
|
|
||||||
/* Global module variables; these are used for the Apache-specific functionality */
|
/* Global module variables; these are used for the Apache-specific functionality */
|
||||||
|
|
||||||
char DSOLOCAL *chroot_dir = NULL;
|
char DSOLOCAL *chroot_dir = NULL;
|
||||||
@@ -53,26 +53,9 @@ int perform_interception(modsec_rec *msr) {
|
|||||||
msre_actionset *actionset = NULL;
|
msre_actionset *actionset = NULL;
|
||||||
const char *message = NULL;
|
const char *message = NULL;
|
||||||
const char *phase_text = "";
|
const char *phase_text = "";
|
||||||
const char *intreq_text = "";
|
|
||||||
int is_initial_req = ap_is_initial_req(msr->r);
|
|
||||||
int status = DECLINED;
|
int status = DECLINED;
|
||||||
int log_level = 1;
|
int log_level = 1;
|
||||||
|
|
||||||
/* Check for an initial request */
|
|
||||||
|
|
||||||
if (is_initial_req != 1) {
|
|
||||||
if (msr->r->main != NULL) {
|
|
||||||
intreq_text = "Sub-Request: ";
|
|
||||||
}
|
|
||||||
else if (msr->r->prev != NULL) {
|
|
||||||
intreq_text = "Internal Redirect: ";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
intreq_text = "Internal Request: ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Sanity checks first. */
|
/* Sanity checks first. */
|
||||||
|
|
||||||
if (msr->was_intercepted == 0) {
|
if (msr->was_intercepted == 0) {
|
||||||
@@ -81,7 +64,7 @@ int perform_interception(modsec_rec *msr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (msr->phase > 4) {
|
if (msr->phase > 4) {
|
||||||
msr_log(msr, 1, "Internal Error: Asked to intercept request in phase %i.", msr->phase);
|
msr_log(msr, 1, "Internal Error: Asked to intercept request in phase %d.", msr->phase);
|
||||||
msr->was_intercepted = 0;
|
msr->was_intercepted = 0;
|
||||||
return DECLINED;
|
return DECLINED;
|
||||||
}
|
}
|
||||||
@@ -89,18 +72,18 @@ int perform_interception(modsec_rec *msr) {
|
|||||||
/* OK, we're good to go. */
|
/* OK, we're good to go. */
|
||||||
|
|
||||||
actionset = msr->intercept_actionset;
|
actionset = msr->intercept_actionset;
|
||||||
phase_text = apr_psprintf(msr->mp, " (phase %i)", msr->phase);
|
phase_text = apr_psprintf(msr->mp, " (phase %d)", msr->phase);
|
||||||
|
|
||||||
/* By default we log at level 1 but we switch to 4
|
/* By default we log at level 1 but we switch to 4
|
||||||
* if a nolog action was used or this is not the initial request
|
* if a nolog action was used or this is not the initial request
|
||||||
* to hide the message.
|
* to hide the message.
|
||||||
*/
|
*/
|
||||||
log_level = ((actionset->log != 1) || (is_initial_req != 1)) ? 4 : 1;
|
log_level = (actionset->log != 1) ? 4 : 1;
|
||||||
|
|
||||||
/* Pause the request first (if configured and the initial request). */
|
/* Pause the request first (if configured and the initial request). */
|
||||||
if (actionset->intercept_pause && (is_initial_req == 1)) {
|
if (actionset->intercept_pause) {
|
||||||
msr_log(msr, (log_level > 3 ? log_level : log_level + 1), "Pausing transaction for "
|
msr_log(msr, (log_level > 3 ? log_level : log_level + 1), "Pausing transaction for "
|
||||||
"%i msec.", actionset->intercept_pause);
|
"%d msec.", actionset->intercept_pause);
|
||||||
/* apr_sleep accepts microseconds */
|
/* apr_sleep accepts microseconds */
|
||||||
apr_sleep((apr_interval_time_t)(actionset->intercept_pause * 1000));
|
apr_sleep((apr_interval_time_t)(actionset->intercept_pause * 1000));
|
||||||
}
|
}
|
||||||
@@ -110,14 +93,14 @@ int perform_interception(modsec_rec *msr) {
|
|||||||
case ACTION_DENY :
|
case ACTION_DENY :
|
||||||
if (actionset->intercept_status != 0) {
|
if (actionset->intercept_status != 0) {
|
||||||
status = actionset->intercept_status;
|
status = actionset->intercept_status;
|
||||||
message = apr_psprintf(msr->mp, "%sAccess denied with code %i%s.",
|
message = apr_psprintf(msr->mp, "Access denied with code %d%s.",
|
||||||
intreq_text, status, phase_text);
|
status, phase_text);
|
||||||
} else {
|
} else {
|
||||||
log_level = 1;
|
log_level = 1;
|
||||||
status = HTTP_INTERNAL_SERVER_ERROR;
|
status = HTTP_INTERNAL_SERVER_ERROR;
|
||||||
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
|
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
|
||||||
"(Internal Error: Invalid status code requested %i).",
|
"(Internal Error: Invalid status code requested %d).",
|
||||||
intreq_text, phase_text, actionset->intercept_status);
|
phase_text, actionset->intercept_status);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -126,25 +109,25 @@ int perform_interception(modsec_rec *msr) {
|
|||||||
if (ap_find_linked_module("mod_proxy.c") == NULL) {
|
if (ap_find_linked_module("mod_proxy.c") == NULL) {
|
||||||
log_level = 1;
|
log_level = 1;
|
||||||
status = HTTP_INTERNAL_SERVER_ERROR;
|
status = HTTP_INTERNAL_SERVER_ERROR;
|
||||||
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
|
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
|
||||||
"(Configuration Error: Proxy action to %s requested but mod_proxy not found).",
|
"(Configuration Error: Proxy action to %s requested but mod_proxy not found).",
|
||||||
intreq_text, phase_text,
|
phase_text,
|
||||||
log_escape_nq(msr->mp, actionset->intercept_uri));
|
log_escape_nq(msr->mp, actionset->intercept_uri));
|
||||||
} else {
|
} else {
|
||||||
msr->r->filename = apr_psprintf(msr->mp, "proxy:%s", actionset->intercept_uri);
|
msr->r->filename = apr_psprintf(msr->mp, "proxy:%s", actionset->intercept_uri);
|
||||||
msr->r->proxyreq = PROXYREQ_REVERSE;
|
msr->r->proxyreq = PROXYREQ_REVERSE;
|
||||||
msr->r->handler = "proxy-server";
|
msr->r->handler = "proxy-server";
|
||||||
status = OK;
|
status = OK;
|
||||||
message = apr_psprintf(msr->mp, "%sAccess denied using proxy to%s %s.",
|
message = apr_psprintf(msr->mp, "Access denied using proxy to%s %s.",
|
||||||
intreq_text, phase_text,
|
phase_text,
|
||||||
log_escape_nq(msr->mp, actionset->intercept_uri));
|
log_escape_nq(msr->mp, actionset->intercept_uri));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log_level = 1;
|
log_level = 1;
|
||||||
status = HTTP_INTERNAL_SERVER_ERROR;
|
status = HTTP_INTERNAL_SERVER_ERROR;
|
||||||
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
|
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
|
||||||
"(Configuration Error: Proxy action requested but it does not work in output phases).",
|
"(Configuration Error: Proxy action requested but it does not work in output phases).",
|
||||||
intreq_text, phase_text);
|
phase_text);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -161,30 +144,30 @@ int perform_interception(modsec_rec *msr) {
|
|||||||
if (csd) {
|
if (csd) {
|
||||||
if (apr_socket_close(csd) == APR_SUCCESS) {
|
if (apr_socket_close(csd) == APR_SUCCESS) {
|
||||||
status = HTTP_FORBIDDEN;
|
status = HTTP_FORBIDDEN;
|
||||||
message = apr_psprintf(msr->mp, "%sAccess denied with connection close%s.",
|
message = apr_psprintf(msr->mp, "Access denied with connection close%s.",
|
||||||
intreq_text, phase_text);
|
phase_text);
|
||||||
} else {
|
} else {
|
||||||
log_level = 1;
|
log_level = 1;
|
||||||
status = HTTP_INTERNAL_SERVER_ERROR;
|
status = HTTP_INTERNAL_SERVER_ERROR;
|
||||||
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
|
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
|
||||||
"(Error: Connection drop requested but failed to close the "
|
"(Error: Connection drop requested but failed to close the "
|
||||||
" socket).",
|
" socket).",
|
||||||
intreq_text, phase_text);
|
phase_text);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log_level = 1;
|
log_level = 1;
|
||||||
status = HTTP_INTERNAL_SERVER_ERROR;
|
status = HTTP_INTERNAL_SERVER_ERROR;
|
||||||
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
|
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
|
||||||
"(Error: Connection drop requested but socket not found.",
|
"(Error: Connection drop requested but socket not found.",
|
||||||
intreq_text, phase_text);
|
phase_text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
log_level = 1;
|
log_level = 1;
|
||||||
status = HTTP_INTERNAL_SERVER_ERROR;
|
status = HTTP_INTERNAL_SERVER_ERROR;
|
||||||
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
|
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
|
||||||
"(Error: Connection drop not implemented on this platform).",
|
"(Error: Connection drop not implemented on this platform).",
|
||||||
intreq_text, phase_text);
|
phase_text);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -197,25 +180,39 @@ int perform_interception(modsec_rec *msr) {
|
|||||||
} else {
|
} else {
|
||||||
status = HTTP_MOVED_TEMPORARILY;
|
status = HTTP_MOVED_TEMPORARILY;
|
||||||
}
|
}
|
||||||
message = apr_psprintf(msr->mp, "%sAccess denied with redirection to %s using "
|
message = apr_psprintf(msr->mp, "Access denied with redirection to %s using "
|
||||||
"status %i%s.",
|
"status %d%s.",
|
||||||
intreq_text,
|
|
||||||
log_escape_nq(msr->mp, actionset->intercept_uri), status,
|
log_escape_nq(msr->mp, actionset->intercept_uri), status,
|
||||||
phase_text);
|
phase_text);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTION_ALLOW :
|
case ACTION_ALLOW :
|
||||||
status = DECLINED;
|
status = DECLINED;
|
||||||
message = apr_psprintf(msr->mp, "%sAccess allowed%s.", intreq_text, phase_text);
|
message = apr_psprintf(msr->mp, "Access allowed%s.", phase_text);
|
||||||
msr->was_intercepted = 0;
|
msr->was_intercepted = 0;
|
||||||
|
msr->allow_scope = ACTION_ALLOW;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACTION_ALLOW_PHASE :
|
||||||
|
status = DECLINED;
|
||||||
|
message = apr_psprintf(msr->mp, "Access to phase allowed%s.", phase_text);
|
||||||
|
msr->was_intercepted = 0;
|
||||||
|
msr->allow_scope = ACTION_ALLOW_PHASE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACTION_ALLOW_REQUEST :
|
||||||
|
status = DECLINED;
|
||||||
|
message = apr_psprintf(msr->mp, "Access to request allowed%s.", phase_text);
|
||||||
|
msr->was_intercepted = 0;
|
||||||
|
msr->allow_scope = ACTION_ALLOW_REQUEST;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default :
|
default :
|
||||||
log_level = 1;
|
log_level = 1;
|
||||||
status = HTTP_INTERNAL_SERVER_ERROR;
|
status = HTTP_INTERNAL_SERVER_ERROR;
|
||||||
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
|
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
|
||||||
"(Internal Error: invalid interception action %i).",
|
"(Internal Error: invalid interception action %d).",
|
||||||
intreq_text, phase_text, actionset->intercept_action);
|
phase_text, actionset->intercept_action);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,13 +226,14 @@ int perform_interception(modsec_rec *msr) {
|
|||||||
* Retrieves a previously stored transaction context by
|
* Retrieves a previously stored transaction context by
|
||||||
* looking at the main request, and the previous requests.
|
* looking at the main request, and the previous requests.
|
||||||
*/
|
*/
|
||||||
static modsec_rec *retrieve_tx_context(const request_rec *r) {
|
static modsec_rec *retrieve_tx_context(request_rec *r) {
|
||||||
modsec_rec *msr = NULL;
|
modsec_rec *msr = NULL;
|
||||||
request_rec *rx = NULL;
|
request_rec *rx = NULL;
|
||||||
|
|
||||||
/* Look in the current request first. */
|
/* Look in the current request first. */
|
||||||
msr = (modsec_rec *)apr_table_get(r->notes, NOTE_MSR);
|
msr = (modsec_rec *)apr_table_get(r->notes, NOTE_MSR);
|
||||||
if (msr != NULL) {
|
if (msr != NULL) {
|
||||||
|
msr->r = r;
|
||||||
return msr;
|
return msr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,6 +241,7 @@ static modsec_rec *retrieve_tx_context(const request_rec *r) {
|
|||||||
if (r->main != NULL) {
|
if (r->main != NULL) {
|
||||||
msr = (modsec_rec *)apr_table_get(r->main->notes, NOTE_MSR);
|
msr = (modsec_rec *)apr_table_get(r->main->notes, NOTE_MSR);
|
||||||
if (msr != NULL) {
|
if (msr != NULL) {
|
||||||
|
msr->r = r;
|
||||||
return msr;
|
return msr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,6 +251,7 @@ static modsec_rec *retrieve_tx_context(const request_rec *r) {
|
|||||||
while(rx != NULL) {
|
while(rx != NULL) {
|
||||||
msr = (modsec_rec *)apr_table_get(rx->notes, NOTE_MSR);
|
msr = (modsec_rec *)apr_table_get(rx->notes, NOTE_MSR);
|
||||||
if (msr != NULL) {
|
if (msr != NULL) {
|
||||||
|
msr->r = r;
|
||||||
return msr;
|
return msr;
|
||||||
}
|
}
|
||||||
rx = rx->prev;
|
rx = rx->prev;
|
||||||
@@ -344,17 +344,20 @@ static modsec_rec *create_tx_context(request_rec *r) {
|
|||||||
msr->request_headers = apr_table_copy(msr->mp, r->headers_in);
|
msr->request_headers = apr_table_copy(msr->mp, r->headers_in);
|
||||||
msr->hostname = ap_get_server_name(r);
|
msr->hostname = ap_get_server_name(r);
|
||||||
|
|
||||||
|
msr->msc_rule_mptmp = NULL;
|
||||||
|
|
||||||
/* Invoke the engine to continue with initialisation */
|
/* Invoke the engine to continue with initialisation */
|
||||||
if (modsecurity_tx_init(msr) < 0) return NULL;
|
if (modsecurity_tx_init(msr) < 0) {
|
||||||
|
msr_log(msr, 1, "Failed to initialise transaction (txid %s).", msr->txid);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
store_tx_context(msr, r);
|
store_tx_context(msr, r);
|
||||||
|
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Transaction context created (dcfg %x).", msr->dcfg1);
|
msr_log(msr, 4, "Transaction context created (dcfg %pp).", msr->dcfg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
msr->msc_rule_mptmp = NULL;
|
|
||||||
|
|
||||||
return msr;
|
return msr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,7 +374,8 @@ static apr_status_t change_server_signature(server_rec *s) {
|
|||||||
|
|
||||||
if (new_server_signature == NULL) return 0;
|
if (new_server_signature == NULL) return 0;
|
||||||
|
|
||||||
server_version = (char *)ap_get_server_version();
|
server_version = (char *)apache_get_server_version();
|
||||||
|
|
||||||
if (server_version == NULL) {
|
if (server_version == NULL) {
|
||||||
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
|
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
|
||||||
"SecServerSignature: Apache returned null as signature.");
|
"SecServerSignature: Apache returned null as signature.");
|
||||||
@@ -388,6 +392,18 @@ static apr_status_t change_server_signature(server_rec *s) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check that it really changed. This assumes that what we got was
|
||||||
|
* not a copy and this could change in future versions of Apache.
|
||||||
|
*/
|
||||||
|
server_version = (char *)apache_get_server_version();
|
||||||
|
if ((server_version == NULL) || (strcmp(server_version, new_server_signature) != 0)) {
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s, "SecServerSignature: Failed to change server signature to \"%s\".", new_server_signature);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, s, "SecServerSignature: Changed server signature to \"%s\".", server_version);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,10 +422,8 @@ static int hook_pre_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_te
|
|||||||
/* Initialise ModSecurity engine */
|
/* Initialise ModSecurity engine */
|
||||||
modsecurity = modsecurity_create(mp, MODSEC_ONLINE);
|
modsecurity = modsecurity_create(mp, MODSEC_ONLINE);
|
||||||
if (modsecurity == NULL) {
|
if (modsecurity == NULL) {
|
||||||
/* ENH Since s not available, how do we log from here? stderr?
|
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
|
||||||
* ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
|
"ModSecurity: Failed to initialise engine.");
|
||||||
* "ModSecurity: Failed to initialise engine.");
|
|
||||||
*/
|
|
||||||
return HTTP_INTERNAL_SERVER_ERROR;
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,6 +437,10 @@ static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_t
|
|||||||
void *init_flag = NULL;
|
void *init_flag = NULL;
|
||||||
int first_time = 0;
|
int first_time = 0;
|
||||||
|
|
||||||
|
/* ENH Figure out a way to validate config before we start
|
||||||
|
* - skipafter: need to make sure we found all of our targets
|
||||||
|
*/
|
||||||
|
|
||||||
/* Figure out if we are here for the first time */
|
/* Figure out if we are here for the first time */
|
||||||
apr_pool_userdata_get(&init_flag, "modsecurity-init-flag", s->process->pool);
|
apr_pool_userdata_get(&init_flag, "modsecurity-init-flag", s->process->pool);
|
||||||
if (init_flag == NULL) {
|
if (init_flag == NULL) {
|
||||||
@@ -434,7 +452,7 @@ static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Store the original server signature */
|
/* Store the original server signature */
|
||||||
real_server_signature = apr_pstrdup(mp, ap_get_server_version());
|
real_server_signature = apr_pstrdup(mp, apache_get_server_version());
|
||||||
|
|
||||||
/* Make some space in the server signature for later */
|
/* Make some space in the server signature for later */
|
||||||
if (new_server_signature != NULL) {
|
if (new_server_signature != NULL) {
|
||||||
@@ -454,7 +472,7 @@ static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_t
|
|||||||
|
|
||||||
if (first_time == 0) {
|
if (first_time == 0) {
|
||||||
ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
|
ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
|
||||||
"ModSecurity: chroot checkpoint #2 (pid=%i ppid=%i)", getpid(), getppid());
|
"ModSecurity: chroot checkpoint #2 (pid=%ld ppid=%ld)", (long)getpid(), (long)getppid());
|
||||||
|
|
||||||
if (chdir(chroot_dir) < 0) {
|
if (chdir(chroot_dir) < 0) {
|
||||||
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
|
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
|
||||||
@@ -483,7 +501,7 @@ static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_t
|
|||||||
"ModSecurity: chroot successful, path=%s", chroot_dir);
|
"ModSecurity: chroot successful, path=%s", chroot_dir);
|
||||||
} else {
|
} else {
|
||||||
ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
|
ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
|
||||||
"ModSecurity: chroot checkpoint #1 (pid=%i ppid=%i)", getpid(), getppid());
|
"ModSecurity: chroot checkpoint #1 (pid=%ld ppid=%ld)", (long)getpid(), (long)getppid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -493,13 +511,13 @@ static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_t
|
|||||||
|
|
||||||
/* Log our presence to the error log. */
|
/* Log our presence to the error log. */
|
||||||
if (first_time) {
|
if (first_time) {
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
|
||||||
|
"%s configured.", MODULE_NAME_FULL);
|
||||||
|
|
||||||
|
/* If we've changed the server signature make note of the original. */
|
||||||
if (new_server_signature != NULL) {
|
if (new_server_signature != NULL) {
|
||||||
ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
|
ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
|
||||||
"ModSecurity for Apache %s configured - %s", MODULE_RELEASE, real_server_signature);
|
"Original server signature: %s", real_server_signature);
|
||||||
}
|
|
||||||
else {
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
|
|
||||||
"ModSecurity for Apache %s configured", MODULE_RELEASE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,7 +565,7 @@ static int hook_request_early(request_rec *r) {
|
|||||||
/* Check request body limit (should only trigger on non-chunked requests). */
|
/* Check request body limit (should only trigger on non-chunked requests). */
|
||||||
if (msr->request_content_length > msr->txcfg->reqbody_limit) {
|
if (msr->request_content_length > msr->txcfg->reqbody_limit) {
|
||||||
msr_log(msr, 1, "Request body is larger than the "
|
msr_log(msr, 1, "Request body is larger than the "
|
||||||
"configured limit (%lu).", msr->txcfg->reqbody_limit);
|
"configured limit (%ld).", msr->txcfg->reqbody_limit);
|
||||||
return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,6 +587,13 @@ static int hook_request_late(request_rec *r) {
|
|||||||
modsec_rec *msr = NULL;
|
modsec_rec *msr = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
/* This function needs to run only once per transaction
|
||||||
|
* (i.e. subrequests and redirects are excluded).
|
||||||
|
*/
|
||||||
|
if ((r->main != NULL)||(r->prev != NULL)) {
|
||||||
|
return DECLINED;
|
||||||
|
}
|
||||||
|
|
||||||
/* Find the transaction context and make sure
|
/* Find the transaction context and make sure
|
||||||
* we are supposed to proceed.
|
* we are supposed to proceed.
|
||||||
*/
|
*/
|
||||||
@@ -579,22 +604,16 @@ static int hook_request_late(request_rec *r) {
|
|||||||
*/
|
*/
|
||||||
return DECLINED;
|
return DECLINED;
|
||||||
}
|
}
|
||||||
msr->r = r;
|
|
||||||
msr->remote_user = r->user;
|
|
||||||
|
|
||||||
/* Has this phase been completed already? */
|
/* Has this phase been completed already? */
|
||||||
if (msr->phase_request_body_complete) {
|
if (msr->phase_request_body_complete) {
|
||||||
if (msr->was_intercepted) {
|
msr_log(msr, 1, "Internal Error: Attempted to process the request body more than once.");
|
||||||
msr_log(msr, 4, "Phase REQUEST_BODY request already intercepted. Intercepting additional request.");
|
|
||||||
return perform_interception(msr);
|
|
||||||
}
|
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
|
||||||
msr_log(msr, 4, "Phase REQUEST_BODY already complete, skipping.");
|
|
||||||
}
|
|
||||||
return DECLINED;
|
return DECLINED;
|
||||||
}
|
}
|
||||||
msr->phase_request_body_complete = 1;
|
msr->phase_request_body_complete = 1;
|
||||||
|
|
||||||
|
msr->remote_user = r->user;
|
||||||
|
|
||||||
/* Get the second configuration context. */
|
/* Get the second configuration context. */
|
||||||
msr->dcfg2 = (directory_config *)ap_get_module_config(r->per_dir_config,
|
msr->dcfg2 = (directory_config *)ap_get_module_config(r->per_dir_config,
|
||||||
&security2_module);
|
&security2_module);
|
||||||
@@ -629,7 +648,7 @@ static int hook_request_late(request_rec *r) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Second phase starting (dcfg %x).", msr->dcfg2);
|
msr_log(msr, 4, "Second phase starting (dcfg %pp).", msr->dcfg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Figure out whether or not to extract multipart files. */
|
/* Figure out whether or not to extract multipart files. */
|
||||||
@@ -644,14 +663,22 @@ static int hook_request_late(request_rec *r) {
|
|||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
switch(rc) {
|
switch(rc) {
|
||||||
case -1 :
|
case -1 :
|
||||||
msr_log(msr, 1, "%s", my_error_msg);
|
if (my_error_msg != NULL) {
|
||||||
|
msr_log(msr, 1, "%s", my_error_msg);
|
||||||
|
}
|
||||||
return HTTP_INTERNAL_SERVER_ERROR;
|
return HTTP_INTERNAL_SERVER_ERROR;
|
||||||
break;
|
break;
|
||||||
case -4 : /* Timeout. */
|
case -4 : /* Timeout. */
|
||||||
|
if (my_error_msg != NULL) {
|
||||||
|
msr_log(msr, 4, "%s", my_error_msg);
|
||||||
|
}
|
||||||
r->connection->keepalive = AP_CONN_CLOSE;
|
r->connection->keepalive = AP_CONN_CLOSE;
|
||||||
return HTTP_REQUEST_TIME_OUT;
|
return HTTP_REQUEST_TIME_OUT;
|
||||||
break;
|
break;
|
||||||
case -5 : /* Request body limit reached. */
|
case -5 : /* Request body limit reached. */
|
||||||
|
if (my_error_msg != NULL) {
|
||||||
|
msr_log(msr, 1, "%s", my_error_msg);
|
||||||
|
}
|
||||||
r->connection->keepalive = AP_CONN_CLOSE;
|
r->connection->keepalive = AP_CONN_CLOSE;
|
||||||
return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||||
break;
|
break;
|
||||||
@@ -667,8 +694,9 @@ static int hook_request_late(request_rec *r) {
|
|||||||
/* Update the request headers. They might have changed after
|
/* Update the request headers. They might have changed after
|
||||||
* the body was read (trailers).
|
* the body was read (trailers).
|
||||||
*/
|
*/
|
||||||
// TODO We still need to keep a copy of the original headers
|
/* NOTE We still need to keep a copy of the original headers
|
||||||
// to log in the audit log.
|
* to log in the audit log.
|
||||||
|
*/
|
||||||
msr->request_headers = apr_table_copy(msr->mp, r->headers_in);
|
msr->request_headers = apr_table_copy(msr->mp, r->headers_in);
|
||||||
|
|
||||||
/* Process phase REQUEST_BODY */
|
/* Process phase REQUEST_BODY */
|
||||||
@@ -694,7 +722,24 @@ static void hook_error_log(const char *file, int line, int level, apr_status_t s
|
|||||||
error_message *em = NULL;
|
error_message *em = NULL;
|
||||||
|
|
||||||
if (r == NULL) return;
|
if (r == NULL) return;
|
||||||
msr = retrieve_tx_context(r);
|
msr = retrieve_tx_context((request_rec *)r);
|
||||||
|
|
||||||
|
/* Create a context for requests we never had the chance to process */
|
||||||
|
if ((msr == NULL)
|
||||||
|
&& ((level & APLOG_LEVELMASK) < APLOG_DEBUG)
|
||||||
|
&& apr_table_get(r->subprocess_env, "UNIQUE_ID"))
|
||||||
|
{
|
||||||
|
msr = create_tx_context((request_rec *)r);
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
if (msr == NULL) {
|
||||||
|
msr_log(msr, 9, "Failed to create context after request failure.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
msr_log(msr, 9, "Context created after request failure.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (msr == NULL) return;
|
if (msr == NULL) return;
|
||||||
|
|
||||||
/* Store the error message for later */
|
/* Store the error message for later */
|
||||||
@@ -760,7 +805,7 @@ static void sec_guardian_logger(request_rec *r, request_rec *origr, modsec_rec *
|
|||||||
* The fields SESSION_ID, MODSEC_MESSAGE, and MODSEC_RATING are not used at the moment.
|
* The fields SESSION_ID, MODSEC_MESSAGE, and MODSEC_RATING are not used at the moment.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
str2 = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT " %" APR_TIME_T_FMT " \"%s\" %i",
|
str2 = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT " %" APR_TIME_T_FMT " \"%s\" %d",
|
||||||
duration, apr_time_sec(duration), log_escape(msr->mp, modsec_message), modsec_rating);
|
duration, apr_time_sec(duration), log_escape(msr->mp, modsec_message), modsec_rating);
|
||||||
if (str2 == NULL) return;
|
if (str2 == NULL) return;
|
||||||
|
|
||||||
@@ -781,7 +826,7 @@ static void sec_guardian_logger(request_rec *r, request_rec *origr, modsec_rec *
|
|||||||
|
|
||||||
limit = limit - strlen(str2) - 5;
|
limit = limit - strlen(str2) - 5;
|
||||||
if (limit <= 0) {
|
if (limit <= 0) {
|
||||||
msr_log(msr, 1, "Audit Log: Atomic PIPE write buffer too small: %i", PIPE_BUF);
|
msr_log(msr, 1, "Audit Log: Atomic PIPE write buffer too small: %d", PIPE_BUF);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -871,9 +916,25 @@ static void hook_insert_filter(request_rec *r) {
|
|||||||
msr = retrieve_tx_context(r);
|
msr = retrieve_tx_context(r);
|
||||||
if (msr == NULL) return;
|
if (msr == NULL) return;
|
||||||
|
|
||||||
|
/* Add the input filter, but only if we need it to run. */
|
||||||
|
if (msr->if_status == IF_STATUS_WANTS_TO_RUN) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
|
msr_log(msr, 4, "Hook insert_filter: Adding input forwarding filter %s(r %pp).", (((r->main != NULL)||(r->prev != NULL)) ? "for subrequest " : ""), r);
|
||||||
|
}
|
||||||
|
|
||||||
|
ap_add_input_filter("MODSECURITY_IN", msr, r, r->connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The output filters only need to be added only once per transaction
|
||||||
|
* (i.e. subrequests and redirects are excluded).
|
||||||
|
*/
|
||||||
|
if ((r->main != NULL)||(r->prev != NULL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* We always add the PDF XSS protection filter. */
|
/* We always add the PDF XSS protection filter. */
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Hook insert_filter: Adding PDF XSS protection output filter (r %x).", r);
|
msr_log(msr, 4, "Hook insert_filter: Adding PDF XSS protection output filter (r %pp).", r);
|
||||||
}
|
}
|
||||||
|
|
||||||
ap_add_output_filter("PDFP_OUT", msr, r, r->connection);
|
ap_add_output_filter("PDFP_OUT", msr, r, r->connection);
|
||||||
@@ -883,32 +944,23 @@ static void hook_insert_filter(request_rec *r) {
|
|||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Hook insert_filter: Processing disabled, skipping.");
|
msr_log(msr, 4, "Hook insert_filter: Processing disabled, skipping.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the input filter, but only if we need it to run. */
|
|
||||||
if (msr->if_status == IF_STATUS_WANTS_TO_RUN) {
|
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
|
||||||
msr_log(msr, 4, "Hook insert_filter: Adding input forwarding filter (r %x).", r);
|
|
||||||
}
|
|
||||||
|
|
||||||
ap_add_input_filter("MODSECURITY_IN", msr, r, r->connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We always add the output filter because that's where we need to
|
/* We always add the output filter because that's where we need to
|
||||||
* initiate our 3rd and 4th processing phases from. The filter is
|
* initiate our 3rd and 4th processing phases from. The filter is
|
||||||
* smart enough not to buffer the data if it is not supposed to.
|
* smart enough not to buffer the data if it is not supposed to.
|
||||||
*/
|
*/
|
||||||
if (msr->of_status != OF_STATUS_COMPLETE) {
|
if (msr->of_status != OF_STATUS_COMPLETE) {
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Hook insert_filter: Adding output filter (r %x).", r);
|
msr_log(msr, 4, "Hook insert_filter: Adding output filter (r %pp).", r);
|
||||||
}
|
}
|
||||||
|
|
||||||
ap_add_output_filter("MODSECURITY_OUT", msr, r, r->connection);
|
ap_add_output_filter("MODSECURITY_OUT", msr, r, r->connection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/**
|
/**
|
||||||
* Invoked whenever Apache starts processing an error. A chance
|
* Invoked whenever Apache starts processing an error. A chance
|
||||||
* to insert ourselves into the output filter chain.
|
* to insert ourselves into the output filter chain.
|
||||||
@@ -919,14 +971,10 @@ static void hook_insert_error_filter(request_rec *r) {
|
|||||||
/* Find the transaction context and make sure we are
|
/* Find the transaction context and make sure we are
|
||||||
* supposed to proceed.
|
* supposed to proceed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* TODO Insert filter but make a note that it's the error
|
|
||||||
* response the filter would be receiving.
|
|
||||||
*/
|
|
||||||
|
|
||||||
msr = retrieve_tx_context(r);
|
msr = retrieve_tx_context(r);
|
||||||
if (msr == NULL) return;
|
if (msr == NULL) return;
|
||||||
|
|
||||||
|
/* Do not run if not enabled. */
|
||||||
if (msr->txcfg->is_enabled == 0) {
|
if (msr->txcfg->is_enabled == 0) {
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Hook insert_error_filter: Processing disabled, skipping.");
|
msr_log(msr, 4, "Hook insert_error_filter: Processing disabled, skipping.");
|
||||||
@@ -934,10 +982,19 @@ static void hook_insert_error_filter(request_rec *r) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Do not run if the output filter already completed. This will
|
||||||
|
* happen if we intercept in phase 4.
|
||||||
|
*/
|
||||||
if (msr->of_status != OF_STATUS_COMPLETE) {
|
if (msr->of_status != OF_STATUS_COMPLETE) {
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "Hook insert_error_filter: Adding output filter (r %x).", r);
|
msr_log(msr, 4, "Hook insert_error_filter: Adding output filter (r %pp).", r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make a note that the output we will be receiving is a
|
||||||
|
* result of error processing.
|
||||||
|
*/
|
||||||
|
msr->of_is_error = 1;
|
||||||
|
|
||||||
ap_add_output_filter("MODSECURITY_OUT", msr, r, r->connection);
|
ap_add_output_filter("MODSECURITY_OUT", msr, r, r->connection);
|
||||||
} else {
|
} else {
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
@@ -945,15 +1002,15 @@ static void hook_insert_error_filter(request_rec *r) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#if (!defined(NO_MODSEC_API))
|
||||||
/**
|
/**
|
||||||
* This function is exported for other Apache modules to
|
* This function is exported for other Apache modules to
|
||||||
* register new transformation functions.
|
* register new transformation functions.
|
||||||
*/
|
*/
|
||||||
static void modsec_register_tfn(const char *name, void *fn) {
|
static void modsec_register_tfn(const char *name, void *fn) {
|
||||||
if (modsecurity != NULL) {
|
if (modsecurity != NULL) {
|
||||||
msre_engine_tfn_register(modsecurity->msre, name, fn);
|
msre_engine_tfn_register(modsecurity->msre, name, (fn_tfn_execute_t)fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -963,7 +1020,7 @@ static void modsec_register_tfn(const char *name, void *fn) {
|
|||||||
*/
|
*/
|
||||||
static void modsec_register_operator(const char *name, void *fn_init, void *fn_exec) {
|
static void modsec_register_operator(const char *name, void *fn_init, void *fn_exec) {
|
||||||
if (modsecurity != NULL) {
|
if (modsecurity != NULL) {
|
||||||
msre_engine_op_register(modsecurity->msre, name, fn_init, fn_exec);
|
msre_engine_op_register(modsecurity->msre, name, (fn_op_param_init_t)fn_init, (fn_op_execute_t)fn_exec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -982,6 +1039,7 @@ static void modsec_register_variable(const char *name, unsigned int type,
|
|||||||
fprintf(stderr,"modsecurity is NULL\n");
|
fprintf(stderr,"modsecurity is NULL\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers module hooks with Apache.
|
* Registers module hooks with Apache.
|
||||||
@@ -998,6 +1056,10 @@ static void register_hooks(apr_pool_t *mp) {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static const char *postread_beforeme_list[] = {
|
static const char *postread_beforeme_list[] = {
|
||||||
|
"mod_rpaf.c",
|
||||||
|
"mod_extract_forwarded2.c",
|
||||||
|
"mod_breach_realip.c",
|
||||||
|
"mod_breach_trans.c",
|
||||||
"mod_unique_id.c",
|
"mod_unique_id.c",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
@@ -1006,10 +1068,15 @@ static void register_hooks(apr_pool_t *mp) {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Add the MODSEC_a.b define */
|
||||||
|
*(char **)apr_array_push(ap_server_config_defines) = apr_psprintf(mp, "MODSEC_%s.%s", MODSEC_VERSION_MAJOR, MODSEC_VERSION_MINOR);
|
||||||
|
|
||||||
|
#if (!defined(NO_MODSEC_API))
|
||||||
/* Export optional functions. */
|
/* Export optional functions. */
|
||||||
APR_REGISTER_OPTIONAL_FN(modsec_register_tfn);
|
APR_REGISTER_OPTIONAL_FN(modsec_register_tfn);
|
||||||
APR_REGISTER_OPTIONAL_FN(modsec_register_operator);
|
APR_REGISTER_OPTIONAL_FN(modsec_register_operator);
|
||||||
APR_REGISTER_OPTIONAL_FN(modsec_register_variable);
|
APR_REGISTER_OPTIONAL_FN(modsec_register_variable);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Main hooks */
|
/* Main hooks */
|
||||||
ap_hook_pre_config(hook_pre_config, NULL, NULL, APR_HOOK_FIRST);
|
ap_hook_pre_config(hook_pre_config, NULL, NULL, APR_HOOK_FIRST);
|
||||||
@@ -1033,7 +1100,7 @@ static void register_hooks(apr_pool_t *mp) {
|
|||||||
|
|
||||||
/* Filter hooks */
|
/* Filter hooks */
|
||||||
ap_hook_insert_filter(hook_insert_filter, NULL, NULL, APR_HOOK_FIRST);
|
ap_hook_insert_filter(hook_insert_filter, NULL, NULL, APR_HOOK_FIRST);
|
||||||
/* ap_hook_insert_error_filter(hook_insert_error_filter, NULL, NULL, APR_HOOK_FIRST); */
|
ap_hook_insert_error_filter(hook_insert_error_filter, NULL, NULL, APR_HOOK_FIRST);
|
||||||
|
|
||||||
ap_register_input_filter("MODSECURITY_IN", input_filter,
|
ap_register_input_filter("MODSECURITY_IN", input_filter,
|
||||||
NULL, AP_FTYPE_CONTENT_SET);
|
NULL, AP_FTYPE_CONTENT_SET);
|
||||||
|
|||||||
123
apache2/mod_security2_config.h.in
Normal file
123
apache2/mod_security2_config.h.in
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/* mod_security2_config.h.in. Generated from configure.in by autoheader. */
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `atexit' function. */
|
||||||
|
#undef HAVE_ATEXIT
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `fchmod' function. */
|
||||||
|
#undef HAVE_FCHMOD
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||||
|
#undef HAVE_FCNTL_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `getcwd' function. */
|
||||||
|
#undef HAVE_GETCWD
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||||
|
#undef HAVE_INTTYPES_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <limits.h> header file. */
|
||||||
|
#undef HAVE_LIMITS_H
|
||||||
|
|
||||||
|
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||||
|
to 0 otherwise. */
|
||||||
|
#undef HAVE_MALLOC
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <memory.h> header file. */
|
||||||
|
#undef HAVE_MEMORY_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `memset' function. */
|
||||||
|
#undef HAVE_MEMSET
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdint.h> header file. */
|
||||||
|
#undef HAVE_STDINT_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||||
|
#undef HAVE_STDLIB_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strcasecmp' function. */
|
||||||
|
#undef HAVE_STRCASECMP
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strchr' function. */
|
||||||
|
#undef HAVE_STRCHR
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strdup' function. */
|
||||||
|
#undef HAVE_STRDUP
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strerror' function. */
|
||||||
|
#undef HAVE_STRERROR
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <strings.h> header file. */
|
||||||
|
#undef HAVE_STRINGS_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <string.h> header file. */
|
||||||
|
#undef HAVE_STRING_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strncasecmp' function. */
|
||||||
|
#undef HAVE_STRNCASECMP
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strrchr' function. */
|
||||||
|
#undef HAVE_STRRCHR
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strstr' function. */
|
||||||
|
#undef HAVE_STRSTR
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strtol' function. */
|
||||||
|
#undef HAVE_STRTOL
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||||
|
#undef HAVE_SYS_STAT_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||||
|
#undef HAVE_SYS_TYPES_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <unistd.h> header file. */
|
||||||
|
#undef HAVE_UNISTD_H
|
||||||
|
|
||||||
|
/* Define to the address where bug reports for this package should be sent. */
|
||||||
|
#undef PACKAGE_BUGREPORT
|
||||||
|
|
||||||
|
/* Define to the full name of this package. */
|
||||||
|
#undef PACKAGE_NAME
|
||||||
|
|
||||||
|
/* Define to the full name and version of this package. */
|
||||||
|
#undef PACKAGE_STRING
|
||||||
|
|
||||||
|
/* Define to the one symbol short name of this package. */
|
||||||
|
#undef PACKAGE_TARNAME
|
||||||
|
|
||||||
|
/* Define to the version of this package. */
|
||||||
|
#undef PACKAGE_VERSION
|
||||||
|
|
||||||
|
/* Define to 1 if you have the ANSI C header files. */
|
||||||
|
#undef STDC_HEADERS
|
||||||
|
|
||||||
|
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
|
||||||
|
#undef TM_IN_SYS_TIME
|
||||||
|
|
||||||
|
/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
|
||||||
|
<pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
|
||||||
|
#define below would cause a syntax error. */
|
||||||
|
#undef _UINT8_T
|
||||||
|
|
||||||
|
/* Define to empty if `const' does not conform to ANSI C. */
|
||||||
|
#undef const
|
||||||
|
|
||||||
|
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||||
|
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#undef inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define to rpl_malloc if the replacement function should be used. */
|
||||||
|
#undef malloc
|
||||||
|
|
||||||
|
/* Define to equivalent of C99 restrict keyword, or to nothing if this is not
|
||||||
|
supported. Do not define if restrict is supported directly. */
|
||||||
|
#undef restrict
|
||||||
|
|
||||||
|
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||||
|
#undef size_t
|
||||||
|
|
||||||
|
/* Define to the type of an unsigned integer type of width exactly 8 bits if
|
||||||
|
such a type exists and the standard includes do not define it. */
|
||||||
|
#undef uint8_t
|
||||||
1
apache2/mod_security2_config.hw
Normal file
1
apache2/mod_security2_config.hw
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/* This file is left empty for building on Windows. */
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -16,6 +16,15 @@
|
|||||||
#include "msc_parsers.h"
|
#include "msc_parsers.h"
|
||||||
#include "msc_util.h"
|
#include "msc_util.h"
|
||||||
|
|
||||||
|
modsec_build_type_rec DSOLOCAL modsec_build_type[] = {
|
||||||
|
{ "dev", 1 }, /* Development build */
|
||||||
|
{ "rc", 3 }, /* Release Candidate build */
|
||||||
|
{ "", 9 }, /* Production build */
|
||||||
|
{ "breach", 9 }, /* Breach build */
|
||||||
|
{ "trunk", 9 }, /* Trunk build */
|
||||||
|
{ NULL, -1 } /* terminator */
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log an alert message to the log, adding the rule metadata at the end.
|
* Log an alert message to the log, adding the rule metadata at the end.
|
||||||
*/
|
*/
|
||||||
@@ -136,6 +145,7 @@ static apr_status_t modsecurity_tx_cleanup(void *data) {
|
|||||||
apr_table_entry_t *te;
|
apr_table_entry_t *te;
|
||||||
int collect_garbage = 0;
|
int collect_garbage = 0;
|
||||||
int i;
|
int i;
|
||||||
|
char *my_error_msg = NULL;
|
||||||
|
|
||||||
if (msr == NULL) return APR_SUCCESS;
|
if (msr == NULL) return APR_SUCCESS;
|
||||||
|
|
||||||
@@ -162,12 +172,14 @@ static apr_status_t modsecurity_tx_cleanup(void *data) {
|
|||||||
/* Multipart processor cleanup. */
|
/* Multipart processor cleanup. */
|
||||||
if (msr->mpd != NULL) multipart_cleanup(msr);
|
if (msr->mpd != NULL) multipart_cleanup(msr);
|
||||||
|
|
||||||
#ifdef WITH_LIBXML2
|
|
||||||
/* XML processor cleanup. */
|
/* XML processor cleanup. */
|
||||||
if (msr->xml != NULL) xml_cleanup(msr);
|
if (msr->xml != NULL) xml_cleanup(msr);
|
||||||
#endif
|
|
||||||
|
|
||||||
modsecurity_request_body_clear(msr);
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -295,9 +307,21 @@ apr_status_t modsecurity_tx_init(modsec_rec *msr) {
|
|||||||
msr->collections_dirty = apr_table_make(msr->mp, 8);
|
msr->collections_dirty = apr_table_make(msr->mp, 8);
|
||||||
if (msr->collections_dirty == NULL) return -1;
|
if (msr->collections_dirty == NULL) return -1;
|
||||||
|
|
||||||
|
/* Other */
|
||||||
msr->tcache = apr_hash_make(msr->mp);
|
msr->tcache = apr_hash_make(msr->mp);
|
||||||
if (msr->tcache == NULL) return -1;
|
if (msr->tcache == NULL) return -1;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,19 +333,23 @@ static int is_response_status_relevant(modsec_rec *msr, int status) {
|
|||||||
apr_status_t rc;
|
apr_status_t rc;
|
||||||
char buf[32];
|
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)
|
if ((msr->txcfg->auditlog_relevant_regex == NULL)
|
||||||
||(msr->txcfg->auditlog_relevant_regex == NOT_SET_P))
|
||(msr->txcfg->auditlog_relevant_regex == NOT_SET_P))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_snprintf(buf, sizeof(buf), "%i", status);
|
apr_snprintf(buf, sizeof(buf), "%d", status);
|
||||||
|
|
||||||
rc = msc_regexec(msr->txcfg->auditlog_relevant_regex, buf, strlen(buf), &my_error_msg);
|
rc = msc_regexec(msr->txcfg->auditlog_relevant_regex, buf, strlen(buf), &my_error_msg);
|
||||||
if (rc >= 0) return 1;
|
if (rc >= 0) return 1;
|
||||||
if (rc == PCRE_ERROR_NOMATCH) return 0;
|
if (rc == PCRE_ERROR_NOMATCH) return 0;
|
||||||
|
|
||||||
msr_log(msr, 1, "Regex processing failed (rc %i): %s", rc, my_error_msg);
|
msr_log(msr, 1, "Regex processing failed (rc %d): %s", rc, my_error_msg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,7 +370,12 @@ static apr_status_t modsecurity_process_phase_request_headers(modsec_rec *msr) {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static apr_status_t modsecurity_process_phase_request_body(modsec_rec *msr) {
|
static apr_status_t modsecurity_process_phase_request_body(modsec_rec *msr) {
|
||||||
msr_log(msr, 4, "Starting phase REQUEST_BODY.");
|
if ((msr->allow_scope == ACTION_ALLOW_REQUEST)||(msr->allow_scope == ACTION_ALLOW)) {
|
||||||
|
msr_log(msr, 4, "Skipping phase REQUEST_BODY (allow used).");
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
msr_log(msr, 4, "Starting phase REQUEST_BODY.");
|
||||||
|
}
|
||||||
|
|
||||||
if (msr->txcfg->ruleset != NULL) {
|
if (msr->txcfg->ruleset != NULL) {
|
||||||
return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
|
return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
|
||||||
@@ -355,7 +388,12 @@ static apr_status_t modsecurity_process_phase_request_body(modsec_rec *msr) {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static apr_status_t modsecurity_process_phase_response_headers(modsec_rec *msr) {
|
static apr_status_t modsecurity_process_phase_response_headers(modsec_rec *msr) {
|
||||||
msr_log(msr, 4, "Starting phase RESPONSE_HEADERS.");
|
if (msr->allow_scope == ACTION_ALLOW) {
|
||||||
|
msr_log(msr, 4, "Skipping phase RESPONSE_HEADERS (allow used).");
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
msr_log(msr, 4, "Starting phase RESPONSE_HEADERS.");
|
||||||
|
}
|
||||||
|
|
||||||
if (msr->txcfg->ruleset != NULL) {
|
if (msr->txcfg->ruleset != NULL) {
|
||||||
return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
|
return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
|
||||||
@@ -368,7 +406,12 @@ static apr_status_t modsecurity_process_phase_response_headers(modsec_rec *msr)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static apr_status_t modsecurity_process_phase_response_body(modsec_rec *msr) {
|
static apr_status_t modsecurity_process_phase_response_body(modsec_rec *msr) {
|
||||||
msr_log(msr, 4, "Starting phase RESPONSE_BODY.");
|
if (msr->allow_scope == ACTION_ALLOW) {
|
||||||
|
msr_log(msr, 4, "Skipping phase RESPONSE_BODY (allow used).");
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
msr_log(msr, 4, "Starting phase RESPONSE_BODY.");
|
||||||
|
}
|
||||||
|
|
||||||
if (msr->txcfg->ruleset != NULL) {
|
if (msr->txcfg->ruleset != NULL) {
|
||||||
return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
|
return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
|
||||||
@@ -428,7 +471,7 @@ static apr_status_t modsecurity_process_phase_logging(modsec_rec *msr) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default :
|
default :
|
||||||
return HTTP_INTERNAL_SERVER_ERROR;
|
msr_log(msr, 1, "Internal error: Could not determine if auditing is needed, so forcing auditing.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,10 +508,9 @@ apr_status_t modsecurity_process_phase(modsec_rec *msr, int phase) {
|
|||||||
return modsecurity_process_phase_logging(msr);
|
return modsecurity_process_phase_logging(msr);
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
msr_log(msr, 1, "Invalid processing phase: %i", msr->phase);
|
msr_log(msr, 1, "Invalid processing phase: %d", msr->phase);
|
||||||
return -1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -30,13 +30,18 @@ typedef struct msc_string msc_string;
|
|||||||
#define DSOLOCAL
|
#define DSOLOCAL
|
||||||
#endif
|
#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
|
||||||
|
|
||||||
#include "msc_logging.h"
|
#include "msc_logging.h"
|
||||||
#include "msc_multipart.h"
|
#include "msc_multipart.h"
|
||||||
#include "msc_pcre.h"
|
#include "msc_pcre.h"
|
||||||
#include "msc_util.h"
|
#include "msc_util.h"
|
||||||
#ifdef WITH_LIBXML2
|
|
||||||
#include "msc_xml.h"
|
#include "msc_xml.h"
|
||||||
#endif
|
|
||||||
#include "msc_geo.h"
|
#include "msc_geo.h"
|
||||||
#include "re.h"
|
#include "re.h"
|
||||||
|
|
||||||
@@ -49,9 +54,23 @@ typedef struct msc_string msc_string;
|
|||||||
#include "http_log.h"
|
#include "http_log.h"
|
||||||
#include "http_protocol.h"
|
#include "http_protocol.h"
|
||||||
|
|
||||||
#define MODULE_NAME "ModSecurity"
|
typedef struct modsec_build_type_rec {
|
||||||
#define MODULE_RELEASE "2.5.0-dev2"
|
const char * name;
|
||||||
#define MODULE_NAME_FULL (MODULE_NAME " v" MODULE_RELEASE " (Apache 2.x)")
|
int val;
|
||||||
|
} modsec_build_type_rec;
|
||||||
|
extern DSOLOCAL modsec_build_type_rec modsec_build_type[];
|
||||||
|
|
||||||
|
#define MODSEC_VERSION_MAJOR "2"
|
||||||
|
#define MODSEC_VERSION_MINOR "5"
|
||||||
|
#define MODSEC_VERSION_MAINT "0"
|
||||||
|
#define MODSEC_VERSION_TYPE ""
|
||||||
|
#define MODSEC_VERSION_RELEASE ""
|
||||||
|
|
||||||
|
#define MODULE_NAME "ModSecurity for Apache"
|
||||||
|
#define MODULE_RELEASE \
|
||||||
|
MODSEC_VERSION_MAJOR "." MODSEC_VERSION_MINOR "." MODSEC_VERSION_MAINT \
|
||||||
|
"-" MODSEC_VERSION_TYPE MODSEC_VERSION_RELEASE
|
||||||
|
#define MODULE_NAME_FULL MODULE_NAME "/" MODULE_RELEASE " (http://www.modsecurity.org/)"
|
||||||
|
|
||||||
#define PHASE_REQUEST_HEADERS 1
|
#define PHASE_REQUEST_HEADERS 1
|
||||||
#define PHASE_REQUEST_BODY 2
|
#define PHASE_REQUEST_BODY 2
|
||||||
@@ -61,8 +80,8 @@ typedef struct msc_string msc_string;
|
|||||||
#define PHASE_FIRST PHASE_REQUEST_HEADERS
|
#define PHASE_FIRST PHASE_REQUEST_HEADERS
|
||||||
#define PHASE_LAST PHASE_LOGGING
|
#define PHASE_LAST PHASE_LOGGING
|
||||||
|
|
||||||
#define NOT_SET -1
|
#define NOT_SET -1l
|
||||||
#define NOT_SET_P (void *)-1
|
#define NOT_SET_P ((void *)-1l)
|
||||||
|
|
||||||
#define CREATEMODE ( APR_UREAD | APR_UWRITE | APR_GREAD )
|
#define CREATEMODE ( APR_UREAD | APR_UWRITE | APR_GREAD )
|
||||||
#define CREATEMODE_DIR ( APR_UREAD | APR_UWRITE | APR_UEXECUTE | APR_GREAD | APR_GEXECUTE )
|
#define CREATEMODE_DIR ( APR_UREAD | APR_UWRITE | APR_UEXECUTE | APR_GREAD | APR_GEXECUTE )
|
||||||
@@ -86,9 +105,20 @@ typedef struct msc_string msc_string;
|
|||||||
#define REQUEST_BODY_HARD_LIMIT 1073741824L
|
#define REQUEST_BODY_HARD_LIMIT 1073741824L
|
||||||
#define REQUEST_BODY_DEFAULT_INMEMORY_LIMIT 131072
|
#define REQUEST_BODY_DEFAULT_INMEMORY_LIMIT 131072
|
||||||
#define REQUEST_BODY_DEFAULT_LIMIT 134217728
|
#define REQUEST_BODY_DEFAULT_LIMIT 134217728
|
||||||
|
#define REQUEST_BODY_NO_FILES_DEFAULT_LIMIT 1048576
|
||||||
#define RESPONSE_BODY_DEFAULT_LIMIT 524288
|
#define RESPONSE_BODY_DEFAULT_LIMIT 524288
|
||||||
#define RESPONSE_BODY_HARD_LIMIT 1073741824L
|
#define RESPONSE_BODY_HARD_LIMIT 1073741824L
|
||||||
|
|
||||||
|
#define RESPONSE_BODY_LIMIT_ACTION_REJECT 0
|
||||||
|
#define RESPONSE_BODY_LIMIT_ACTION_PARTIAL 1
|
||||||
|
|
||||||
|
#define SECACTION_TARGETS "REQUEST_URI"
|
||||||
|
#define SECACTION_ARGS "@unconditionalMatch"
|
||||||
|
|
||||||
|
#define SECMARKER_TARGETS "REQUEST_URI"
|
||||||
|
#define SECMARKER_ARGS "@noMatch"
|
||||||
|
#define SECMARKER_BASE_ACTIONS "t:none,pass,id:"
|
||||||
|
|
||||||
#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
|
#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
|
||||||
#include "unixd.h"
|
#include "unixd.h"
|
||||||
#define __SET_MUTEX_PERMS
|
#define __SET_MUTEX_PERMS
|
||||||
@@ -140,11 +170,16 @@ extern DSOLOCAL const command_rec module_directives[];
|
|||||||
#define ACTION_PROXY 3
|
#define ACTION_PROXY 3
|
||||||
#define ACTION_DROP 4
|
#define ACTION_DROP 4
|
||||||
#define ACTION_ALLOW 5
|
#define ACTION_ALLOW 5
|
||||||
|
#define ACTION_ALLOW_REQUEST 6
|
||||||
|
#define ACTION_ALLOW_PHASE 7
|
||||||
|
|
||||||
#define MODSEC_DISABLED 0
|
#define MODSEC_DISABLED 0
|
||||||
#define MODSEC_DETECTION_ONLY 1
|
#define MODSEC_DETECTION_ONLY 1
|
||||||
#define MODSEC_ENABLED 2
|
#define MODSEC_ENABLED 2
|
||||||
|
|
||||||
|
#define MODSEC_CACHE_DISABLED 0
|
||||||
|
#define MODSEC_CACHE_ENABLED 1
|
||||||
|
|
||||||
#define MODSEC_OFFLINE 0
|
#define MODSEC_OFFLINE 0
|
||||||
#define MODSEC_ONLINE 1
|
#define MODSEC_ONLINE 1
|
||||||
|
|
||||||
@@ -190,12 +225,13 @@ struct modsec_rec {
|
|||||||
unsigned int if_started_forwarding;
|
unsigned int if_started_forwarding;
|
||||||
|
|
||||||
apr_size_t reqbody_length;
|
apr_size_t reqbody_length;
|
||||||
unsigned int reqbody_status;
|
|
||||||
|
|
||||||
apr_bucket_brigade *of_brigade;
|
apr_bucket_brigade *of_brigade;
|
||||||
unsigned int of_status;
|
unsigned int of_status;
|
||||||
unsigned int of_done_reading;
|
unsigned int of_done_reading;
|
||||||
unsigned int of_skipping;
|
unsigned int of_skipping;
|
||||||
|
unsigned int of_partial;
|
||||||
|
unsigned int of_is_error;
|
||||||
|
|
||||||
unsigned int resbody_status;
|
unsigned int resbody_status;
|
||||||
apr_size_t resbody_length;
|
apr_size_t resbody_length;
|
||||||
@@ -278,11 +314,11 @@ struct modsec_rec {
|
|||||||
int msc_reqbody_error;
|
int msc_reqbody_error;
|
||||||
const char *msc_reqbody_error_msg;
|
const char *msc_reqbody_error_msg;
|
||||||
|
|
||||||
|
apr_size_t msc_reqbody_no_files_length;
|
||||||
|
|
||||||
multipart_data *mpd; /* MULTIPART processor data structure */
|
multipart_data *mpd; /* MULTIPART processor data structure */
|
||||||
|
|
||||||
#ifdef WITH_LIBXML2
|
|
||||||
xml_data *xml; /* XML processor data structure */
|
xml_data *xml; /* XML processor data structure */
|
||||||
#endif
|
|
||||||
|
|
||||||
/* audit logging */
|
/* audit logging */
|
||||||
char *new_auditlog_boundary;
|
char *new_auditlog_boundary;
|
||||||
@@ -292,6 +328,7 @@ struct modsec_rec {
|
|||||||
apr_md5_ctx_t new_auditlog_md5ctx;
|
apr_md5_ctx_t new_auditlog_md5ctx;
|
||||||
|
|
||||||
unsigned int was_intercepted;
|
unsigned int was_intercepted;
|
||||||
|
unsigned int rule_was_intercepted;
|
||||||
unsigned int intercept_phase;
|
unsigned int intercept_phase;
|
||||||
msre_actionset *intercept_actionset;
|
msre_actionset *intercept_actionset;
|
||||||
const char *intercept_message;
|
const char *intercept_message;
|
||||||
@@ -302,7 +339,9 @@ struct modsec_rec {
|
|||||||
apr_time_t time_checkpoint_2;
|
apr_time_t time_checkpoint_2;
|
||||||
apr_time_t time_checkpoint_3;
|
apr_time_t time_checkpoint_3;
|
||||||
|
|
||||||
const char *matched_var;
|
apr_array_header_t *matched_rules;
|
||||||
|
msc_string *matched_var;
|
||||||
|
int highest_severity;
|
||||||
|
|
||||||
/* upload */
|
/* upload */
|
||||||
int upload_extract_files;
|
int upload_extract_files;
|
||||||
@@ -323,6 +362,17 @@ struct modsec_rec {
|
|||||||
|
|
||||||
/* data cache */
|
/* data cache */
|
||||||
apr_hash_t *tcache;
|
apr_hash_t *tcache;
|
||||||
|
|
||||||
|
/* removed rules */
|
||||||
|
apr_array_header_t *removed_rules;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct directory_config {
|
struct directory_config {
|
||||||
@@ -334,11 +384,13 @@ struct directory_config {
|
|||||||
int reqbody_access;
|
int reqbody_access;
|
||||||
long int reqbody_inmemory_limit;
|
long int reqbody_inmemory_limit;
|
||||||
long int reqbody_limit;
|
long int reqbody_limit;
|
||||||
|
long int reqbody_no_files_limit;
|
||||||
int resbody_access;
|
int resbody_access;
|
||||||
|
|
||||||
long int of_limit;
|
long int of_limit;
|
||||||
apr_table_t *of_mime_types;
|
apr_table_t *of_mime_types;
|
||||||
int of_mime_types_cleared;
|
int of_mime_types_cleared;
|
||||||
|
int of_limit_action;
|
||||||
|
|
||||||
const char *debuglog_name;
|
const char *debuglog_name;
|
||||||
int debuglog_level;
|
int debuglog_level;
|
||||||
@@ -392,10 +444,12 @@ struct directory_config {
|
|||||||
const char *upload_dir;
|
const char *upload_dir;
|
||||||
int upload_keep_files;
|
int upload_keep_files;
|
||||||
int upload_validates_files;
|
int upload_validates_files;
|
||||||
|
int upload_filemode;
|
||||||
|
|
||||||
/* Used only in the configuration phase. */
|
/* Used only in the configuration phase. */
|
||||||
msre_rule *tmp_chain_starter;
|
msre_rule *tmp_chain_starter;
|
||||||
msre_actionset *tmp_default_actionset;
|
msre_actionset *tmp_default_actionset;
|
||||||
|
apr_table_t *tmp_rule_placeholders;
|
||||||
|
|
||||||
/* Misc */
|
/* Misc */
|
||||||
const char *data_dir;
|
const char *data_dir;
|
||||||
@@ -414,6 +468,19 @@ struct directory_config {
|
|||||||
|
|
||||||
/* Geo Lookup */
|
/* Geo Lookup */
|
||||||
geo_db *geo;
|
geo_db *geo;
|
||||||
|
|
||||||
|
/* Cache */
|
||||||
|
int cache_trans;
|
||||||
|
apr_size_t cache_trans_min;
|
||||||
|
apr_size_t cache_trans_max;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct error_message {
|
struct error_message {
|
||||||
@@ -474,14 +541,14 @@ apr_status_t DSOLOCAL modsecurity_process_phase(modsec_rec *msr, int phase);
|
|||||||
|
|
||||||
/* Request body functions */
|
/* Request body functions */
|
||||||
|
|
||||||
apr_status_t DSOLOCAL modsecurity_request_body_start(modsec_rec *msr);
|
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,
|
apr_status_t DSOLOCAL modsecurity_request_body_store(modsec_rec *msr,
|
||||||
const char *data, apr_size_t length);
|
const char *data, apr_size_t length, char **error_msg);
|
||||||
|
|
||||||
apr_status_t DSOLOCAL modsecurity_request_body_end(modsec_rec *msr);
|
apr_status_t DSOLOCAL modsecurity_request_body_end(modsec_rec *msr, char **error_msg);
|
||||||
|
|
||||||
apr_status_t DSOLOCAL modsecurity_request_body_retrieve_start(modsec_rec *msr);
|
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);
|
apr_status_t DSOLOCAL modsecurity_request_body_retrieve_end(modsec_rec *msr);
|
||||||
|
|
||||||
@@ -490,7 +557,7 @@ apr_status_t DSOLOCAL modsecurity_request_body_retrieve_end(modsec_rec *msr);
|
|||||||
* nbytes will contain the number of bytes stored in the buffer.
|
* 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,
|
apr_status_t DSOLOCAL modsecurity_request_body_retrieve(modsec_rec *msr, msc_data_chunk **chunk,
|
||||||
long int nbytes);
|
long int nbytes, char **error_msg);
|
||||||
|
|
||||||
void DSOLOCAL msc_add(modsec_rec *msr, int level, msre_actionset *actionset,
|
void DSOLOCAL msc_add(modsec_rec *msr, int level, msre_actionset *actionset,
|
||||||
const char *action_message, const char *rule_message);
|
const char *action_message, const char *rule_message);
|
||||||
@@ -498,6 +565,6 @@ void DSOLOCAL msc_add(modsec_rec *msr, int level, msre_actionset *actionset,
|
|||||||
void DSOLOCAL msc_alert(modsec_rec *msr, int level, msre_actionset *actionset, const char *action_message,
|
void DSOLOCAL msc_alert(modsec_rec *msr, int level, msre_actionset *actionset, const char *action_message,
|
||||||
const char *rule_message);
|
const char *rule_message);
|
||||||
|
|
||||||
apr_status_t DSOLOCAL modsecurity_request_body_clear(modsec_rec *msr);
|
apr_status_t DSOLOCAL modsecurity_request_body_clear(modsec_rec *msr, char **error_msg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
|
|
||||||
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
|
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
|
||||||
re re_operators re_actions re_tfns re_variables \
|
re re_operators re_actions re_tfns re_variables \
|
||||||
msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \
|
msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \
|
||||||
persist_dbm msc_reqbody pdf_protect msc_geo acmp
|
persist_dbm msc_reqbody pdf_protect msc_geo acmp msc_lua
|
||||||
|
|
||||||
H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h \
|
H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h \
|
||||||
msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \
|
msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \
|
||||||
msc_geo.h acmp.h utf8tables.h
|
msc_geo.h acmp.h utf8tables.h msc_lua.h
|
||||||
|
|
||||||
${MOD_SECURITY2:=.slo}: ${H}
|
${MOD_SECURITY2:=.slo}: ${H}
|
||||||
${MOD_SECURITY2:=.lo}: ${H}
|
${MOD_SECURITY2:=.lo}: ${H}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -165,7 +165,7 @@ static int db_open(directory_config *dcfg, char **error_msg)
|
|||||||
fprintf(stderr, "GEO: read 0x%02x%02x%02x\n", buf[0], buf[1], buf[2]);
|
fprintf(stderr, "GEO: read 0x%02x%02x%02x\n", buf[0], buf[1], buf[2]);
|
||||||
#endif
|
#endif
|
||||||
if ((rc != APR_SUCCESS) || (nbytes != 3)) {
|
if ((rc != APR_SUCCESS) || (nbytes != 3)) {
|
||||||
*error_msg = apr_psprintf(mp, "Could not read from geo database \"%s\" (%d/3 bytes read): %s", geo->dbfn, nbytes, apr_strerror(rc, errstr, 1024));
|
*error_msg = apr_psprintf(mp, "Could not read from geo database \"%s\" (%" APR_SIZE_T_FMT "/3 bytes read): %s", geo->dbfn, nbytes, apr_strerror(rc, errstr, 1024));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff)) {
|
if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff)) {
|
||||||
@@ -190,7 +190,7 @@ static int db_open(directory_config *dcfg, char **error_msg)
|
|||||||
memset(buf, 0, 3);
|
memset(buf, 0, 3);
|
||||||
rc = apr_file_read_full(geo->db, &buf, 3, &nbytes);
|
rc = apr_file_read_full(geo->db, &buf, 3, &nbytes);
|
||||||
if ((rc != APR_SUCCESS) || (nbytes != 3)) {
|
if ((rc != APR_SUCCESS) || (nbytes != 3)) {
|
||||||
*error_msg = apr_psprintf(mp, "Could not read geo database \"%s\" country offset (%d/3 bytes read): %s", geo->dbfn, nbytes, apr_strerror(rc, errstr, 1024));
|
*error_msg = apr_psprintf(mp, "Could not read geo database \"%s\" country offset (%" APR_SIZE_T_FMT "/3 bytes read): %s", geo->dbfn, nbytes, apr_strerror(rc, errstr, 1024));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_CONF
|
#ifdef DEBUG_CONF
|
||||||
@@ -300,34 +300,35 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
|
|||||||
georec->dma_code = 0;
|
georec->dma_code = 0;
|
||||||
georec->area_code = 0;
|
georec->area_code = 0;
|
||||||
|
|
||||||
msr_log(msr, 9, "GEO: Looking up \"%s\".", target);
|
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 */
|
/* NOTE: This only works with ipv4 */
|
||||||
if ((rc = apr_sockaddr_info_get(&addr, target, APR_INET, 0, 0, msr->mp)) != APR_SUCCESS) {
|
if ((rc = apr_sockaddr_info_get(&addr, target, APR_INET, 0, 0, msr->mp)) != APR_SUCCESS) {
|
||||||
|
|
||||||
*error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" failed: %s", target, apr_strerror(rc, errstr, 1024));
|
*error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" failed: %s", log_escape(msr->mp, target), apr_strerror(rc, errstr, 1024));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ((rc = apr_sockaddr_ip_get(&targetip, addr)) != APR_SUCCESS) {
|
if ((rc = apr_sockaddr_ip_get(&targetip, addr)) != APR_SUCCESS) {
|
||||||
*error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" failed: %s", target, apr_strerror(rc, errstr, 1024));
|
*error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" failed: %s", log_escape(msr->mp, target), apr_strerror(rc, errstr, 1024));
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Why is this in host byte order? */
|
/* Why is this in host byte order? */
|
||||||
ipnum = ntohl(addr->sa.sin.sin_addr.s_addr);
|
ipnum = ntohl(addr->sa.sin.sin_addr.s_addr);
|
||||||
|
|
||||||
msr_log(msr, 9, "GEO: Using address \"%s\" (0x%08x).", targetip, ipnum);
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "GEO: Using address \"%s\" (0x%08lx).", targetip, ipnum);
|
||||||
|
}
|
||||||
|
|
||||||
for (level = 31; level >= 0; level--) {
|
for (level = 31; level >= 0; level--) {
|
||||||
|
|
||||||
/* Read the record */
|
/* Read the record */
|
||||||
seekto = 2 * reclen * rec_val;
|
seekto = 2 * reclen * rec_val;
|
||||||
apr_file_seek(geo->db, APR_SET, &seekto);
|
apr_file_seek(geo->db, APR_SET, &seekto);
|
||||||
/* TODO: check rc */
|
/* TODO: check rc */
|
||||||
rc = apr_file_read_full(geo->db, &buf, (2 * reclen), &nbytes);
|
rc = apr_file_read_full(geo->db, &buf, (2 * reclen), &nbytes);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* NOTE: This is hard-coded for size 3 records */
|
/* NOTE: This is hard-coded for size 3 records */
|
||||||
/* Left */
|
/* Left */
|
||||||
if ((ipnum & (1 << level)) == 0) {
|
if ((ipnum & (1 << level)) == 0) {
|
||||||
@@ -352,13 +353,11 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
|
|||||||
country = rec_val;
|
country = rec_val;
|
||||||
country -= geo->ctry_offset;
|
country -= geo->ctry_offset;
|
||||||
if (country <= 0) {
|
if (country <= 0) {
|
||||||
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\".", target);
|
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\".", log_escape(msr->mp, target));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
msr_log(msr, 9, "GEO: rec=\"%s\"", log_escape_raw(msr->mp, buf, sizeof(buf)));
|
|
||||||
|
|
||||||
/* Country */
|
/* Country */
|
||||||
msr_log(msr, 9, "GEO: country=\"%.*s\"", (1*4), log_escape_raw(msr->mp, (unsigned char *)&rec_val, 1));
|
|
||||||
georec->country_code = geo_country_code[country];
|
georec->country_code = geo_country_code[country];
|
||||||
georec->country_code3 = geo_country_code3[country];
|
georec->country_code3 = geo_country_code3[country];
|
||||||
georec->country_name = geo_country_name[country];
|
georec->country_name = geo_country_name[country];
|
||||||
@@ -377,13 +376,17 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
|
|||||||
|
|
||||||
country = cbuf[0];
|
country = cbuf[0];
|
||||||
if (country <= 0) {
|
if (country <= 0) {
|
||||||
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\".", target);
|
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\".", log_escape(msr->mp, target));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
msr_log(msr, 9, "GEO: rec=\"%s\"", log_escape_raw(msr->mp, cbuf, sizeof(cbuf)));
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "GEO: rec=\"%s\"", log_escape_raw(msr->mp, cbuf, sizeof(cbuf)));
|
||||||
|
}
|
||||||
|
|
||||||
/* Country */
|
/* Country */
|
||||||
msr_log(msr, 9, "GEO: country=\"%.*s\"", (1*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf)));
|
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_code = geo_country_code[country];
|
||||||
georec->country_code3 = geo_country_code3[country];
|
georec->country_code3 = geo_country_code3[country];
|
||||||
georec->country_name = geo_country_name[country];
|
georec->country_name = geo_country_name[country];
|
||||||
@@ -393,27 +396,35 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
|
|||||||
|
|
||||||
/* Region */
|
/* Region */
|
||||||
field_len = field_length((const char *)cbuf+rec_offset, remaining);
|
field_len = field_length((const char *)cbuf+rec_offset, remaining);
|
||||||
msr_log(msr, 9, "GEO: region=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
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));
|
georec->region = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
|
||||||
rec_offset += field_len + 1;
|
rec_offset += field_len + 1;
|
||||||
remaining -= field_len + 1;
|
remaining -= field_len + 1;
|
||||||
|
|
||||||
/* City */
|
/* City */
|
||||||
field_len = field_length((const char *)cbuf+rec_offset, remaining);
|
field_len = field_length((const char *)cbuf+rec_offset, remaining);
|
||||||
msr_log(msr, 9, "GEO: city=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
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));
|
georec->city = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
|
||||||
rec_offset += field_len + 1;
|
rec_offset += field_len + 1;
|
||||||
remaining -= field_len + 1;
|
remaining -= field_len + 1;
|
||||||
|
|
||||||
/* Postal Code */
|
/* Postal Code */
|
||||||
field_len = field_length((const char *)cbuf+rec_offset, remaining);
|
field_len = field_length((const char *)cbuf+rec_offset, remaining);
|
||||||
msr_log(msr, 9, "GEO: postal_code=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
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));
|
georec->postal_code = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
|
||||||
rec_offset += field_len + 1;
|
rec_offset += field_len + 1;
|
||||||
remaining -= field_len + 1;
|
remaining -= field_len + 1;
|
||||||
|
|
||||||
/* Latitude */
|
/* Latitude */
|
||||||
msr_log(msr, 9, "GEO: latitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
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] +
|
dtmp = cbuf[rec_offset] +
|
||||||
(cbuf[rec_offset+1] << 8) +
|
(cbuf[rec_offset+1] << 8) +
|
||||||
(cbuf[rec_offset+2] << 16);
|
(cbuf[rec_offset+2] << 16);
|
||||||
@@ -423,7 +434,9 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
|
|||||||
|
|
||||||
|
|
||||||
/* Longitude */
|
/* Longitude */
|
||||||
msr_log(msr, 9, "GEO: longitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
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] +
|
dtmp = cbuf[rec_offset] +
|
||||||
(cbuf[rec_offset+1] << 8) +
|
(cbuf[rec_offset+1] << 8) +
|
||||||
(cbuf[rec_offset+2] << 16);
|
(cbuf[rec_offset+2] << 16);
|
||||||
@@ -432,7 +445,9 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
|
|||||||
remaining -= 3;
|
remaining -= 3;
|
||||||
|
|
||||||
/* dma/area codes are in city rev1 and US only */
|
/* dma/area codes are in city rev1 and US only */
|
||||||
msr_log(msr, 9, "GEO: dma/area=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
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
|
if (geo->dbtype == GEO_CITY_DATABASE_1
|
||||||
&& georec->country_code[0] == 'U'
|
&& georec->country_code[0] == 'U'
|
||||||
&& georec->country_code[1] == 'S')
|
&& georec->country_code[1] == 'S')
|
||||||
@@ -449,7 +464,7 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" succeeded.", target);
|
*error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" succeeded.", log_escape(msr->mp, target));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
* write to Breach Security, Inc. at support@breach.com.
|
* write to Breach Security, Inc. at support@breach.com.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
#include "re.h"
|
||||||
#include "msc_logging.h"
|
#include "msc_logging.h"
|
||||||
#include "httpd.h"
|
#include "httpd.h"
|
||||||
#include "apr_strings.h"
|
#include "apr_strings.h"
|
||||||
@@ -23,22 +24,39 @@ static int sec_auditlog_write(modsec_rec *msr, const char *data, unsigned int le
|
|||||||
apr_size_t nbytes_written, nbytes = len;
|
apr_size_t nbytes_written, nbytes = len;
|
||||||
apr_status_t rc;
|
apr_status_t rc;
|
||||||
|
|
||||||
if ((msr->new_auditlog_fd == NULL)||(data == NULL)) return -1;
|
/* Do nothing if there's no data. */
|
||||||
|
if (data == NULL) return -1;
|
||||||
|
|
||||||
|
/* Update size counters and the hash calculation. We always do this,
|
||||||
|
* even in cases where write fails. That will make it easier to detect
|
||||||
|
* problems with partial writes.
|
||||||
|
*/
|
||||||
|
msr->new_auditlog_size += len;
|
||||||
|
apr_md5_update(&msr->new_auditlog_md5ctx, data, len);
|
||||||
|
|
||||||
|
/* Do not write if we do not have a file descriptor. */
|
||||||
|
if (msr->new_auditlog_fd == NULL) return -1;
|
||||||
|
|
||||||
|
/* Write data to file. */
|
||||||
rc = apr_file_write_full(msr->new_auditlog_fd, data, nbytes, &nbytes_written);
|
rc = apr_file_write_full(msr->new_auditlog_fd, data, nbytes, &nbytes_written);
|
||||||
if (rc != APR_SUCCESS) {
|
if (rc != APR_SUCCESS) {
|
||||||
msr_log(msr, 1, "Audit log: Failed writing (requested %" APR_SIZE_T_FMT
|
msr_log(msr, 1, "Audit log: Failed writing (requested %" APR_SIZE_T_FMT
|
||||||
" bytes, written %" APR_SIZE_T_FMT ")", nbytes, nbytes_written);
|
" bytes, written %" APR_SIZE_T_FMT ")", nbytes, nbytes_written);
|
||||||
|
|
||||||
|
/* Set to NULL to prevent more than one error message on
|
||||||
|
* out-of-disk-space events and to prevent further attempts
|
||||||
|
* to write to the same file in this request.
|
||||||
|
*
|
||||||
|
* Note that, as we opened the file through the pool mechanism of
|
||||||
|
* the APR, we do not need to close the file here. It will be closed
|
||||||
|
* automatically at the end of the request.
|
||||||
|
*/
|
||||||
|
msr->new_auditlog_fd = NULL;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note the following will only take into account the actual
|
return 1;
|
||||||
* amount of bytes we've written.
|
|
||||||
*/
|
|
||||||
msr->new_auditlog_size += nbytes_written;
|
|
||||||
apr_md5_update(&msr->new_auditlog_md5ctx, data, nbytes_written);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,7 +96,7 @@ char *construct_log_vcombinedus(modsec_rec *msr) {
|
|||||||
/* sessionid */
|
/* sessionid */
|
||||||
sessionid = (msr->sessionid == NULL ? "-" : msr->sessionid);
|
sessionid = (msr->sessionid == NULL ? "-" : msr->sessionid);
|
||||||
|
|
||||||
return apr_psprintf(msr->mp, "%s %s %s %s [%s] \"%s\" %i %" APR_OFF_T_FMT " \"%s\" \"%s\" %s \"%s\"",
|
return apr_psprintf(msr->mp, "%s %s %s %s [%s] \"%s\" %u %" APR_OFF_T_FMT " \"%s\" \"%s\" %s \"%s\"",
|
||||||
log_escape_nq(msr->mp, msr->hostname), msr->remote_addr, log_escape_nq(msr->mp, remote_user),
|
log_escape_nq(msr->mp, msr->hostname), msr->remote_addr, log_escape_nq(msr->mp, remote_user),
|
||||||
log_escape_nq(msr->mp, local_user), current_logtime(msr->mp),
|
log_escape_nq(msr->mp, local_user), current_logtime(msr->mp),
|
||||||
((msr->request_line == NULL) ? "" : log_escape(msr->mp, msr->request_line)),
|
((msr->request_line == NULL) ? "" : log_escape(msr->mp, msr->request_line)),
|
||||||
@@ -149,7 +167,7 @@ char *construct_log_vcombinedus_limited(modsec_rec *msr, int _limit, int *was_li
|
|||||||
limit -= strlen(sessionid); /* session id */
|
limit -= strlen(sessionid); /* session id */
|
||||||
|
|
||||||
if (limit <= 0) {
|
if (limit <= 0) {
|
||||||
msr_log(msr, 1, "GuardianLog: Atomic pipe write size too small: %i", PIPE_BUF);
|
msr_log(msr, 1, "GuardianLog: Atomic pipe write size too small: %d", PIPE_BUF);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,21 +207,21 @@ char *construct_log_vcombinedus_limited(modsec_rec *msr, int _limit, int *was_li
|
|||||||
limit -= strlen(user_agent);
|
limit -= strlen(user_agent);
|
||||||
|
|
||||||
if (limit <= 0) {
|
if (limit <= 0) {
|
||||||
msr_log(msr, 1, "GuardianLog: Atomic pipe write size too small: %i.", PIPE_BUF);
|
msr_log(msr, 1, "GuardianLog: Atomic pipe write size too small: %d.", PIPE_BUF);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* use what's left for the request line */
|
/* use what's left for the request line */
|
||||||
if ((int)strlen(the_request) > limit) {
|
if ((int)strlen(the_request) > limit) {
|
||||||
the_request[limit] = '\0';
|
the_request[limit] = '\0';
|
||||||
msr_log(msr, 9, "GuardianLog: Reduced the_request to %i bytes.", limit);
|
msr_log(msr, 9, "GuardianLog: Reduced the_request to %d bytes.", limit);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Yay! We have enough space! */
|
/* Yay! We have enough space! */
|
||||||
*was_limited = 0;
|
*was_limited = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return apr_psprintf(msr->mp, "%s %s %s %s [%s] \"%s\" %i %s \"%s\" \"%s\" %s \"%s\"",
|
return apr_psprintf(msr->mp, "%s %s %s %s [%s] \"%s\" %u %s \"%s\" \"%s\" %s \"%s\"",
|
||||||
hostname, msr->remote_addr, remote_user,
|
hostname, msr->remote_addr, remote_user,
|
||||||
local_user, current_logtime(msr->mp), the_request,
|
local_user, current_logtime(msr->mp), the_request,
|
||||||
msr->response_status, bytes_sent, referer, user_agent,
|
msr->response_status, bytes_sent, referer, user_agent,
|
||||||
@@ -217,7 +235,7 @@ char *construct_log_vcombinedus_limited(modsec_rec *msr, int _limit, int *was_li
|
|||||||
int is_valid_parts_specification(char *p) {
|
int is_valid_parts_specification(char *p) {
|
||||||
char c, *t = p;
|
char c, *t = p;
|
||||||
|
|
||||||
while((c = *t++) != '\0') {
|
while((c = *(t++)) != '\0') {
|
||||||
if ((c != AUDITLOG_PART_ENDMARKER)&&((c < AUDITLOG_PART_FIRST)||(c > AUDITLOG_PART_LAST))) {
|
if ((c != AUDITLOG_PART_ENDMARKER)&&((c < AUDITLOG_PART_FIRST)||(c > AUDITLOG_PART_LAST))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -284,7 +302,7 @@ static void sanitise_request_line(modsec_rec *msr) {
|
|||||||
j = arg->value_origin_offset;
|
j = arg->value_origin_offset;
|
||||||
while((*p != '\0')&&(j--)) p++;
|
while((*p != '\0')&&(j--)) p++;
|
||||||
if (*p == '\0') {
|
if (*p == '\0') {
|
||||||
msr_log(msr, 1, "Unable to sanitise variable \"%s\" at offset %i of QUERY_STRING"
|
msr_log(msr, 1, "Unable to sanitise variable \"%s\" at offset %u of QUERY_STRING"
|
||||||
"because the request line is too short.",
|
"because the request line is too short.",
|
||||||
log_escape_ex(msr->mp, arg->name, arg->name_len),
|
log_escape_ex(msr->mp, arg->name, arg->name_len),
|
||||||
arg->value_origin_offset);
|
arg->value_origin_offset);
|
||||||
@@ -297,7 +315,7 @@ static void sanitise_request_line(modsec_rec *msr) {
|
|||||||
*p++ = '*';
|
*p++ = '*';
|
||||||
}
|
}
|
||||||
if (*p == '\0') {
|
if (*p == '\0') {
|
||||||
msr_log(msr, 1, "Unable to sanitise variable \"%s\" at offset %i (size %i) "
|
msr_log(msr, 1, "Unable to sanitise variable \"%s\" at offset %u (size %d) "
|
||||||
"of QUERY_STRING because the request line is too short.",
|
"of QUERY_STRING because the request line is too short.",
|
||||||
log_escape_ex(msr->mp, arg->name, arg->name_len),
|
log_escape_ex(msr->mp, arg->name, arg->name_len),
|
||||||
arg->value_origin_offset, arg->value_origin_len);
|
arg->value_origin_offset, arg->value_origin_len);
|
||||||
@@ -307,6 +325,37 @@ static void sanitise_request_line(modsec_rec *msr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output the Producer header.
|
||||||
|
*/
|
||||||
|
static void sec_auditlog_write_producer_header(modsec_rec *msr) {
|
||||||
|
char **signatures = NULL;
|
||||||
|
char *text = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Try to write everything in one go. */
|
||||||
|
if (msr->txcfg->component_signatures->nelts == 0) {
|
||||||
|
text = apr_psprintf(msr->mp, "Producer: %s.\n", MODULE_NAME_FULL);
|
||||||
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start with the ModSecurity signature. */
|
||||||
|
text = apr_psprintf(msr->mp, "Producer: %s", MODULE_NAME_FULL);
|
||||||
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
|
|
||||||
|
|
||||||
|
/* Then loop through the components and output individual signatures. */
|
||||||
|
signatures = (char **)msr->txcfg->component_signatures->elts;
|
||||||
|
for(i = 0; i < msr->txcfg->component_signatures->nelts; i++) {
|
||||||
|
text = apr_psprintf(msr->mp, "; %s", (char *)signatures[i]);
|
||||||
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
sec_auditlog_write(msr, ".\n", 2);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produce an audit log entry.
|
* Produce an audit log entry.
|
||||||
*/
|
*/
|
||||||
@@ -314,6 +363,7 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
const apr_array_header_t *arr = NULL;
|
const apr_array_header_t *arr = NULL;
|
||||||
apr_table_entry_t *te = NULL;
|
apr_table_entry_t *te = NULL;
|
||||||
char *str1 = NULL, *str2 = NULL, *text = NULL;
|
char *str1 = NULL, *str2 = NULL, *text = NULL;
|
||||||
|
const msre_rule *rule = NULL;
|
||||||
apr_size_t nbytes, nbytes_written;
|
apr_size_t nbytes, nbytes_written;
|
||||||
unsigned char md5hash[APR_MD5_DIGESTSIZE];
|
unsigned char md5hash[APR_MD5_DIGESTSIZE];
|
||||||
int was_limited = 0;
|
int was_limited = 0;
|
||||||
@@ -361,7 +411,7 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
* writing to but it's not us that's causing the problem
|
* writing to but it's not us that's causing the problem
|
||||||
* and there isn't anything we can do about that.
|
* and there isn't anything we can do about that.
|
||||||
*
|
*
|
||||||
* TODO Actually there is something we can do! We will make
|
* ENH Actually there is something we can do! We will make
|
||||||
* SecAuditStorageDir mandatory, ask the user to explicitly
|
* SecAuditStorageDir mandatory, ask the user to explicitly
|
||||||
* define the storage location *and* refuse to work if the
|
* define the storage location *and* refuse to work if the
|
||||||
* index and the storage location are in the same folder.
|
* index and the storage location are in the same folder.
|
||||||
@@ -413,12 +463,12 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
|
|
||||||
/* AUDITLOG_PART_HEADER */
|
/* AUDITLOG_PART_HEADER */
|
||||||
|
|
||||||
text = apr_psprintf(msr->mp, "--%s-A--\n", msr->new_auditlog_boundary);
|
text = apr_psprintf(msr->mp, "--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_HEADER);
|
||||||
sec_auditlog_write(msr, text, strlen(text));
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
|
|
||||||
/* Format: time transaction_id remote_addr remote_port local_addr local_port */
|
/* Format: time transaction_id remote_addr remote_port local_addr local_port */
|
||||||
|
|
||||||
text = apr_psprintf(msr->mp, "[%s] %s %s %i %s %i",
|
text = apr_psprintf(msr->mp, "[%s] %s %s %u %s %u",
|
||||||
current_logtime(msr->mp), msr->txid, msr->remote_addr, msr->remote_port,
|
current_logtime(msr->mp), msr->txid, msr->remote_addr, msr->remote_port,
|
||||||
msr->local_addr, msr->local_port);
|
msr->local_addr, msr->local_port);
|
||||||
sec_auditlog_write(msr, text, strlen(text));
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
@@ -427,7 +477,7 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
/* AUDITLOG_PART_REQUEST_HEADERS */
|
/* AUDITLOG_PART_REQUEST_HEADERS */
|
||||||
|
|
||||||
if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_REQUEST_HEADERS) != NULL) {
|
if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_REQUEST_HEADERS) != NULL) {
|
||||||
text = apr_psprintf(msr->mp, "\n--%s-B--\n", msr->new_auditlog_boundary);
|
text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_REQUEST_HEADERS);
|
||||||
sec_auditlog_write(msr, text, strlen(text));
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
|
|
||||||
sanitise_request_line(msr);
|
sanitise_request_line(msr);
|
||||||
@@ -465,6 +515,7 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
unsigned int offset = 0, last_offset = 0;
|
unsigned int offset = 0, last_offset = 0;
|
||||||
msc_arg *nextarg = NULL;
|
msc_arg *nextarg = NULL;
|
||||||
int sanitise = 0; /* IMP1 Use constants for "sanitise" values. */
|
int sanitise = 0; /* IMP1 Use constants for "sanitise" values. */
|
||||||
|
char *my_error_msg = NULL;
|
||||||
|
|
||||||
sorted_args = apr_array_make(msr->mp, 25, sizeof(const msc_arg *));
|
sorted_args = apr_array_make(msr->mp, 25, sizeof(const msc_arg *));
|
||||||
|
|
||||||
@@ -521,20 +572,20 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
* sanitise data in pieces.
|
* sanitise data in pieces.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
rc = modsecurity_request_body_retrieve_start(msr);
|
rc = modsecurity_request_body_retrieve_start(msr, &my_error_msg);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
msr_log(msr, 1, "Audit log: Failed retrieving request body.");
|
msr_log(msr, 1, "Audit log: %s", my_error_msg);
|
||||||
} else {
|
} else {
|
||||||
msc_data_chunk *chunk = NULL;
|
msc_data_chunk *chunk = NULL;
|
||||||
unsigned int chunk_offset = 0;
|
unsigned int chunk_offset = 0;
|
||||||
unsigned int sanitise_offset = 0;
|
unsigned int sanitise_offset = 0;
|
||||||
unsigned int sanitise_length = 0;
|
unsigned int sanitise_length = 0;
|
||||||
|
|
||||||
text = apr_psprintf(msr->mp, "\n--%s-C--\n", msr->new_auditlog_boundary);
|
text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_REQUEST_BODY);
|
||||||
sec_auditlog_write(msr, text, strlen(text));
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
rc = modsecurity_request_body_retrieve(msr, &chunk, -1);
|
rc = modsecurity_request_body_retrieve(msr, &chunk, -1, &my_error_msg);
|
||||||
if (chunk != NULL) {
|
if (chunk != NULL) {
|
||||||
/* Anything greater than 1 means we have more data to sanitise. */
|
/* Anything greater than 1 means we have more data to sanitise. */
|
||||||
while (sanitise > 1) {
|
while (sanitise > 1) {
|
||||||
@@ -594,7 +645,13 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
chunk_offset += chunk->length;
|
chunk_offset += chunk->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc <= 0) break;
|
if (rc <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc < 0) {
|
||||||
|
msr_log(msr, 1, "Audit log: %s", my_error_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
modsecurity_request_body_retrieve_end(msr);
|
modsecurity_request_body_retrieve_end(msr);
|
||||||
@@ -612,7 +669,7 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
msr_log(msr, 1, "Audit log: Failed to reconstruct request body.");
|
msr_log(msr, 1, "Audit log: Failed to reconstruct request body.");
|
||||||
} else {
|
} else {
|
||||||
text = apr_psprintf(msr->mp, "\n--%s-I--\n", msr->new_auditlog_boundary);
|
text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_FAKE_REQUEST_BODY);
|
||||||
sec_auditlog_write(msr, text, strlen(text));
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
sec_auditlog_write(msr, buffer, strlen(buffer));
|
sec_auditlog_write(msr, buffer, strlen(buffer));
|
||||||
}
|
}
|
||||||
@@ -622,7 +679,7 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
/* AUDITLOG_PART_A_RESPONSE_HEADERS */
|
/* AUDITLOG_PART_A_RESPONSE_HEADERS */
|
||||||
|
|
||||||
if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_A_RESPONSE_HEADERS) != NULL) {
|
if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_A_RESPONSE_HEADERS) != NULL) {
|
||||||
text = apr_psprintf(msr->mp, "\n--%s-F--\n", msr->new_auditlog_boundary);
|
text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_A_RESPONSE_HEADERS);
|
||||||
sec_auditlog_write(msr, text, strlen(text));
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
|
|
||||||
/* There are no response headers (or the status line) in HTTP 0.9 */
|
/* There are no response headers (or the status line) in HTTP 0.9 */
|
||||||
@@ -631,7 +688,7 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
text = apr_psprintf(msr->mp, "%s %s\n", msr->response_protocol,
|
text = apr_psprintf(msr->mp, "%s %s\n", msr->response_protocol,
|
||||||
msr->status_line);
|
msr->status_line);
|
||||||
} else {
|
} else {
|
||||||
text = apr_psprintf(msr->mp, "%s %i\n", msr->response_protocol,
|
text = apr_psprintf(msr->mp, "%s %u\n", msr->response_protocol,
|
||||||
msr->response_status);
|
msr->response_status);
|
||||||
}
|
}
|
||||||
sec_auditlog_write(msr, text, strlen(text));
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
@@ -656,7 +713,7 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
|
|
||||||
if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_RESPONSE_BODY) != NULL) {
|
if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_RESPONSE_BODY) != NULL) {
|
||||||
if (msr->resbody_data != NULL) {
|
if (msr->resbody_data != NULL) {
|
||||||
text = apr_psprintf(msr->mp, "\n--%s-E--\n", msr->new_auditlog_boundary);
|
text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_RESPONSE_BODY);
|
||||||
sec_auditlog_write(msr, text, strlen(text));
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
sec_auditlog_write(msr, msr->resbody_data, msr->resbody_length);
|
sec_auditlog_write(msr, msr->resbody_data, msr->resbody_length);
|
||||||
wrote_response_body = 1;
|
wrote_response_body = 1;
|
||||||
@@ -668,7 +725,7 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_TRAILER) != NULL) {
|
if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_TRAILER) != NULL) {
|
||||||
apr_time_t now = apr_time_now();
|
apr_time_t now = apr_time_now();
|
||||||
|
|
||||||
text = apr_psprintf(msr->mp, "\n--%s-H--\n", msr->new_auditlog_boundary);
|
text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_TRAILER);
|
||||||
sec_auditlog_write(msr, text, strlen(text));
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
|
|
||||||
/* Messages */
|
/* Messages */
|
||||||
@@ -687,7 +744,7 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
|
|
||||||
/* Action */
|
/* Action */
|
||||||
if (msr->was_intercepted) {
|
if (msr->was_intercepted) {
|
||||||
text = apr_psprintf(msr->mp, "Action: Intercepted (phase %i)\n", msr->intercept_phase);
|
text = apr_psprintf(msr->mp, "Action: Intercepted (phase %d)\n", msr->intercept_phase);
|
||||||
sec_auditlog_write(msr, text, strlen(text));
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -735,9 +792,7 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
sec_auditlog_write(msr, text, strlen(text));
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Producer */
|
sec_auditlog_write_producer_header(msr);
|
||||||
text = apr_psprintf(msr->mp, "Producer: %s\n", MODULE_NAME_FULL);
|
|
||||||
sec_auditlog_write(msr, text, strlen(text));
|
|
||||||
|
|
||||||
/* Server */
|
/* Server */
|
||||||
if (msr->server_software != NULL) {
|
if (msr->server_software != NULL) {
|
||||||
@@ -818,10 +873,28 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* AUDITLOG_PART_UPLOADS */
|
||||||
|
/* ENH: Implement */
|
||||||
|
|
||||||
|
|
||||||
|
/* AUDITLOG_PART_MATCHEDRULES */
|
||||||
|
|
||||||
|
if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_MATCHEDRULES) != NULL) {
|
||||||
|
text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_MATCHEDRULES);
|
||||||
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
|
|
||||||
|
/* Matched Rules */
|
||||||
|
for(i = 0; i < msr->matched_rules->nelts; i++) {
|
||||||
|
rule = ((msre_rule **)msr->matched_rules->elts)[i];
|
||||||
|
text = apr_psprintf(msr->mp, "%s\n", rule->unparsed);
|
||||||
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* AUDITLOG_PART_ENDMARKER */
|
/* AUDITLOG_PART_ENDMARKER */
|
||||||
|
|
||||||
text = apr_psprintf(msr->mp, "\n--%s-Z--\n", msr->new_auditlog_boundary);
|
text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_ENDMARKER);
|
||||||
sec_auditlog_write(msr, text, strlen(text));
|
sec_auditlog_write(msr, text, strlen(text));
|
||||||
|
|
||||||
/* Return here if we were writing to a serial log
|
/* Return here if we were writing to a serial log
|
||||||
@@ -849,7 +922,7 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
/* Calculate hash of the entry. */
|
/* Calculate hash of the entry. */
|
||||||
apr_md5_final(md5hash, &msr->new_auditlog_md5ctx);
|
apr_md5_final(md5hash, &msr->new_auditlog_md5ctx);
|
||||||
|
|
||||||
str2 = apr_psprintf(msr->mp, "%s %i %i md5:%s", msr->new_auditlog_filename, 0,
|
str2 = apr_psprintf(msr->mp, "%s %d %d md5:%s", msr->new_auditlog_filename, 0,
|
||||||
msr->new_auditlog_size, bytes2hex(msr->mp, md5hash, 16));
|
msr->new_auditlog_size, bytes2hex(msr->mp, md5hash, 16));
|
||||||
if (str2 == NULL) return;
|
if (str2 == NULL) return;
|
||||||
|
|
||||||
@@ -869,7 +942,7 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
|
|
||||||
limit = limit - strlen(str2) - 5;
|
limit = limit - strlen(str2) - 5;
|
||||||
if (limit <= 0) {
|
if (limit <= 0) {
|
||||||
msr_log(msr, 1, "Audit Log: Atomic PIPE write buffer too small: %i", PIPE_BUF);
|
msr_log(msr, 1, "Audit Log: Atomic PIPE write buffer too small: %d", PIPE_BUF);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -885,14 +958,14 @@ void sec_audit_logger(modsec_rec *msr) {
|
|||||||
|
|
||||||
nbytes = strlen(text);
|
nbytes = strlen(text);
|
||||||
if (msr->txcfg->debuglog_level >= 9) {
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
msr_log(msr, 9, "Audit Log: Writing %d bytes to primary concurrent index", nbytes);
|
msr_log(msr, 9, "Audit Log: Writing %" APR_SIZE_T_FMT " bytes to primary concurrent index", nbytes);
|
||||||
}
|
}
|
||||||
apr_file_write_full(msr->txcfg->auditlog_fd, text, nbytes, &nbytes_written);
|
apr_file_write_full(msr->txcfg->auditlog_fd, text, nbytes, &nbytes_written);
|
||||||
|
|
||||||
/* Write to the secondary audit log if we have one */
|
/* Write to the secondary audit log if we have one */
|
||||||
if (msr->txcfg->auditlog2_fd != NULL) {
|
if (msr->txcfg->auditlog2_fd != NULL) {
|
||||||
if (msr->txcfg->debuglog_level >= 9) {
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
msr_log(msr, 9, "Audit Log: Writing %d bytes to secondary concurrent index", nbytes);
|
msr_log(msr, 9, "Audit Log: Writing %" APR_SIZE_T_FMT " bytes to secondary concurrent index", nbytes);
|
||||||
}
|
}
|
||||||
apr_file_write_full(msr->txcfg->auditlog2_fd, text, nbytes, &nbytes_written);
|
apr_file_write_full(msr->txcfg->auditlog2_fd, text, nbytes, &nbytes_written);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -28,7 +28,9 @@
|
|||||||
#define AUDITLOG_PART_A_RESPONSE_BODY 'G'
|
#define AUDITLOG_PART_A_RESPONSE_BODY 'G'
|
||||||
#define AUDITLOG_PART_TRAILER 'H'
|
#define AUDITLOG_PART_TRAILER 'H'
|
||||||
#define AUDITLOG_PART_FAKE_REQUEST_BODY 'I'
|
#define AUDITLOG_PART_FAKE_REQUEST_BODY 'I'
|
||||||
#define AUDITLOG_PART_LAST 'I'
|
#define AUDITLOG_PART_UPLOADS 'J'
|
||||||
|
#define AUDITLOG_PART_MATCHEDRULES 'K'
|
||||||
|
#define AUDITLOG_PART_LAST 'K'
|
||||||
#define AUDITLOG_PART_ENDMARKER 'Z'
|
#define AUDITLOG_PART_ENDMARKER 'Z'
|
||||||
|
|
||||||
#include "modsecurity.h"
|
#include "modsecurity.h"
|
||||||
|
|||||||
413
apache2/msc_lua.c
Normal file
413
apache2/msc_lua.c
Normal file
@@ -0,0 +1,413 @@
|
|||||||
|
/*
|
||||||
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
|
*
|
||||||
|
* You should have received a copy of the licence along with this
|
||||||
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
|
* or if you have any other questions related to the licence, please
|
||||||
|
* write to Breach Security, Inc. at support@breach.com.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#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;
|
||||||
|
|
||||||
|
/* Allocate new part, copy the data into it. */
|
||||||
|
part = apr_palloc(dump->pool, sizeof(msc_script_part));
|
||||||
|
part->data = apr_palloc(dump->pool, len);
|
||||||
|
part->len = len;
|
||||||
|
memcpy((void *)part->data, data, 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;
|
||||||
|
|
||||||
|
return lua_load(L, dump_reader, &dumpr, script->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
char *lua_compile(msc_script **script, const char *filename, apr_pool_t *pool) {
|
||||||
|
lua_State *L = NULL;
|
||||||
|
msc_lua_dumpw_t dump;
|
||||||
|
|
||||||
|
/* Initialise state. */
|
||||||
|
L = lua_open();
|
||||||
|
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? */
|
||||||
|
int i, n = lua_objlen(L, idx);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct luaL_Reg mylib[] = {
|
||||||
|
{ "log", l_log },
|
||||||
|
{ "getvar", l_getvar },
|
||||||
|
{ "getvars", l_getvars },
|
||||||
|
{ 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;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
/* Create new state. */
|
||||||
|
L = lua_open();
|
||||||
|
|
||||||
|
luaL_openlibs(L);
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
luaL_register(L, "m", mylib);
|
||||||
|
|
||||||
|
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));
|
||||||
|
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);
|
||||||
|
lua_close(L);
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
43
apache2/msc_lua.h
Normal file
43
apache2/msc_lua.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
|
*
|
||||||
|
* You should have received a copy of the licence along with this
|
||||||
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
|
* or if you have any other questions related to the licence, please
|
||||||
|
* write to Breach Security, Inc. at support@breach.com.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#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);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* WITH_LUA */
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -9,9 +9,12 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "mod_security2_config.h"
|
||||||
#include "msc_multipart.h"
|
#include "msc_multipart.h"
|
||||||
#include "msc_util.h"
|
#include "msc_util.h"
|
||||||
|
#include "msc_parsers.h"
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@@ -123,7 +126,7 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
*t++ = *p++;
|
*(t++) = *(p++);
|
||||||
}
|
}
|
||||||
if (*p == '\0') return -10;
|
if (*p == '\0') return -10;
|
||||||
|
|
||||||
@@ -142,15 +145,21 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value)
|
|||||||
if (strcmp(name, "name") == 0) {
|
if (strcmp(name, "name") == 0) {
|
||||||
if (msr->mpd->mpp->name != NULL) return -14;
|
if (msr->mpd->mpp->name != NULL) return -14;
|
||||||
msr->mpd->mpp->name = value;
|
msr->mpd->mpp->name = value;
|
||||||
msr_log(msr, 9, "Multipart: Content-Disposition name: %s",
|
|
||||||
log_escape_nq(msr->mp, value));
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Multipart: Content-Disposition name: %s",
|
||||||
|
log_escape_nq(msr->mp, value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (strcmp(name, "filename") == 0) {
|
if (strcmp(name, "filename") == 0) {
|
||||||
if (msr->mpd->mpp->filename != NULL) return -15;
|
if (msr->mpd->mpp->filename != NULL) return -15;
|
||||||
msr->mpd->mpp->filename = value;
|
msr->mpd->mpp->filename = value;
|
||||||
msr_log(msr, 9, "Multipart: Content-Disposition filename: %s",
|
|
||||||
log_escape_nq(msr->mp, value));
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Multipart: Content-Disposition filename: %s",
|
||||||
|
log_escape_nq(msr->mp, value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else return -11;
|
else return -11;
|
||||||
|
|
||||||
@@ -172,38 +181,70 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int multipart_process_part_header(modsec_rec *msr, char **error_msg) {
|
static int multipart_process_part_header(modsec_rec *msr, char **error_msg) {
|
||||||
int rc;
|
int i, len, rc;
|
||||||
|
|
||||||
if (error_msg == NULL) return -1;
|
if (error_msg == NULL) return -1;
|
||||||
*error_msg = NULL;
|
*error_msg = NULL;
|
||||||
|
|
||||||
if ((msr->mpd->buf[0] == '\r')
|
/* Check for nul bytes. */
|
||||||
&&(msr->mpd->buf[1] == '\n')
|
len = MULTIPART_BUF_SIZE - msr->mpd->bufleft;
|
||||||
&&(msr->mpd->buf[2] == '\0'))
|
for(i = 0; i < len; i++) {
|
||||||
{
|
if (msr->mpd->buf[i] == '\0') {
|
||||||
char *header_value;
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Nul byte in part headers.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* empty line */
|
/* The buffer is data so increase the data length counter. */
|
||||||
|
msr->msc_reqbody_no_files_length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
||||||
|
|
||||||
|
if (len > 1) {
|
||||||
|
if (msr->mpd->buf[len - 2] == '\r') {
|
||||||
|
msr->mpd->flag_crlf_line = 1;
|
||||||
|
} else {
|
||||||
|
msr->mpd->flag_lf_line = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msr->mpd->flag_lf_line = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is this an empty line? */
|
||||||
|
if ( ((msr->mpd->buf[0] == '\r')
|
||||||
|
&&(msr->mpd->buf[1] == '\n')
|
||||||
|
&&(msr->mpd->buf[2] == '\0') )
|
||||||
|
|| ((msr->mpd->buf[0] == '\n')
|
||||||
|
&&(msr->mpd->buf[1] == '\0') ) )
|
||||||
|
{ /* Empty line. */
|
||||||
|
char *header_value = NULL;
|
||||||
|
|
||||||
header_value = (char *)apr_table_get(msr->mpd->mpp->headers, "Content-Disposition");
|
header_value = (char *)apr_table_get(msr->mpd->mpp->headers, "Content-Disposition");
|
||||||
if (header_value == NULL) {
|
if (header_value == NULL) {
|
||||||
*error_msg = apr_psprintf(msr->mp, "Multipart: Part is missing the Content-Disposition header");
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Part missing Content-Disposition header.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = multipart_parse_content_disposition(msr, header_value);
|
rc = multipart_parse_content_disposition(msr, header_value);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid Content-Disposition header (%i): %s",
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid Content-Disposition header (%d): %s.",
|
||||||
rc, log_escape_nq(msr->mp, header_value));
|
rc, log_escape_nq(msr->mp, header_value));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr->mpd->mpp->name == NULL) {
|
if (msr->mpd->mpp->name == NULL) {
|
||||||
*error_msg = apr_psprintf(msr->mp, "Multipart: Part name missing");
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Content-Disposition header missing name field.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr->mpd->mpp->filename != NULL) {
|
if (msr->mpd->mpp->filename != NULL) {
|
||||||
|
/* Some parsers use crude methods to extract the name and filename
|
||||||
|
* values from the C-D header. We need to check for the case where they
|
||||||
|
* didn't understand C-D but we did.
|
||||||
|
*/
|
||||||
|
if (strstr(header_value, "filename=") == NULL) {
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid Content-Disposition header (filename).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
msr->mpd->mpp->type = MULTIPART_FILE;
|
msr->mpd->mpp->type = MULTIPART_FILE;
|
||||||
} else {
|
} else {
|
||||||
msr->mpd->mpp->type = MULTIPART_FORMDATA;
|
msr->mpd->mpp->type = MULTIPART_FORMDATA;
|
||||||
@@ -212,19 +253,21 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) {
|
|||||||
msr->mpd->mpp_state = 1;
|
msr->mpd->mpp_state = 1;
|
||||||
msr->mpd->mpp->last_header_name = NULL;
|
msr->mpd->mpp->last_header_name = NULL;
|
||||||
} else {
|
} else {
|
||||||
/* header line */
|
/* Header line. */
|
||||||
|
|
||||||
if ((msr->mpd->buf[0] == '\t')||(msr->mpd->buf[0] == ' ')) {
|
if ((msr->mpd->buf[0] == '\t')||(msr->mpd->buf[0] == ' ')) {
|
||||||
char *header_value, *new_value, *data;
|
char *header_value, *new_value, *data;
|
||||||
|
|
||||||
/* header folding, add data to the header we are building */
|
/* header folding, add data to the header we are building */
|
||||||
|
msr->mpd->flag_header_folding = 1;
|
||||||
|
|
||||||
if (msr->mpd->mpp->last_header_name == NULL) {
|
if (msr->mpd->mpp->last_header_name == NULL) {
|
||||||
/* we are not building a header at this moment */
|
/* we are not building a header at this moment */
|
||||||
*error_msg = apr_psprintf(msr->mp, "Multipart: invalid part header (invalid folding)");
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid part header (folding error).");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* locate the beginning of the data */
|
/* locate the beginning of data */
|
||||||
data = msr->mpd->buf;
|
data = msr->mpd->buf;
|
||||||
while((*data == '\t')||(*data == ' ')) data++;
|
while((*data == '\t')||(*data == ' ')) data++;
|
||||||
|
|
||||||
@@ -236,12 +279,14 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) {
|
|||||||
new_value = apr_pstrcat(msr->mp, header_value, " ", new_value, NULL);
|
new_value = apr_pstrcat(msr->mp, header_value, " ", new_value, NULL);
|
||||||
apr_table_set(msr->mpd->mpp->headers, msr->mpd->mpp->last_header_name, new_value);
|
apr_table_set(msr->mpd->mpp->headers, msr->mpd->mpp->last_header_name, new_value);
|
||||||
|
|
||||||
msr_log(msr, 9, "Multipart: Continued folder header \"%s\" with \"%s\"",
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
log_escape(msr->mp, msr->mpd->mpp->last_header_name),
|
msr_log(msr, 9, "Multipart: Continued folder header \"%s\" with \"%s\"",
|
||||||
log_escape(msr->mp, data));
|
log_escape(msr->mp, msr->mpd->mpp->last_header_name),
|
||||||
|
log_escape(msr->mp, data));
|
||||||
|
}
|
||||||
|
|
||||||
if (strlen(new_value) > 4096) {
|
if (strlen(new_value) > MULTIPART_BUF_SIZE) {
|
||||||
*error_msg = apr_psprintf(msr->mp, "Multpart: invalid part header (too long)");
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Part header too long.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -252,7 +297,7 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) {
|
|||||||
data = msr->mpd->buf;
|
data = msr->mpd->buf;
|
||||||
while((*data != ':')&&(*data != '\0')) data++;
|
while((*data != ':')&&(*data != '\0')) data++;
|
||||||
if (*data == '\0') {
|
if (*data == '\0') {
|
||||||
*error_msg = apr_psprintf(msr->mp, "Multipart: invalid part header (missing colon): %s",
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid part header (colon missing): %s.",
|
||||||
log_escape_nq(msr->mp, msr->mpd->buf));
|
log_escape_nq(msr->mp, msr->mpd->buf));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -267,7 +312,7 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) {
|
|||||||
|
|
||||||
/* error if the name already exists */
|
/* error if the name already exists */
|
||||||
if (apr_table_get(msr->mpd->mpp->headers, header_name) != NULL) {
|
if (apr_table_get(msr->mpd->mpp->headers, header_name) != NULL) {
|
||||||
*error_msg = apr_psprintf(msr->mp, "Multipart: part header already exists: %s",
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Duplicate part header: %s.",
|
||||||
log_escape_nq(msr->mp, header_name));
|
log_escape_nq(msr->mp, header_name));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -275,9 +320,11 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) {
|
|||||||
apr_table_setn(msr->mpd->mpp->headers, header_name, header_value);
|
apr_table_setn(msr->mpd->mpp->headers, header_name, header_value);
|
||||||
msr->mpd->mpp->last_header_name = header_name;
|
msr->mpd->mpp->last_header_name = header_name;
|
||||||
|
|
||||||
msr_log(msr, 9, "Multipart: Added part header \"%s\" \"%s\"",
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
log_escape(msr->mp, header_name),
|
msr_log(msr, 9, "Multipart: Added part header \"%s\" \"%s\"",
|
||||||
log_escape(msr->mp, header_value));
|
log_escape(msr->mp, header_name),
|
||||||
|
log_escape(msr->mp, header_value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,20 +335,34 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int multipart_process_part_data(modsec_rec *msr, char **error_msg) {
|
static int multipart_process_part_data(modsec_rec *msr, char **error_msg) {
|
||||||
char *p = msr->mpd->buf + (MULTIPART_BUF_SIZE - msr->mpd->bufleft) - 2;
|
char *p = msr->mpd->buf + (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
||||||
char localreserve[2] = { '\0', '\0' }; /* initialized to quiet warning */
|
char localreserve[2] = { '\0', '\0' }; /* initialized to quiet warning */
|
||||||
int bytes_reserved = 0;
|
int bytes_reserved = 0;
|
||||||
|
|
||||||
if (error_msg == NULL) return -1;
|
if (error_msg == NULL) return -1;
|
||||||
*error_msg = NULL;
|
*error_msg = NULL;
|
||||||
|
|
||||||
/* preserve the last two bytes for later */
|
/* Preserve some bytes for later. */
|
||||||
if (MULTIPART_BUF_SIZE - msr->mpd->bufleft >= 2) {
|
if ( ((MULTIPART_BUF_SIZE - msr->mpd->bufleft) >= 1)
|
||||||
bytes_reserved = 1;
|
&& (*(p - 1) == '\n') )
|
||||||
localreserve[0] = *p;
|
{
|
||||||
localreserve[1] = *(p + 1);
|
if ( ((MULTIPART_BUF_SIZE - msr->mpd->bufleft) >= 2)
|
||||||
msr->mpd->bufleft += 2;
|
&& (*(p - 2) == '\r') )
|
||||||
*p = 0;
|
{
|
||||||
|
/* Two bytes. */
|
||||||
|
bytes_reserved = 2;
|
||||||
|
localreserve[0] = *(p - 2);
|
||||||
|
localreserve[1] = *(p - 1);
|
||||||
|
msr->mpd->bufleft += 2;
|
||||||
|
*(p - 2) = 0;
|
||||||
|
} else {
|
||||||
|
/* Only one byte. */
|
||||||
|
bytes_reserved = 1;
|
||||||
|
localreserve[0] = *(p - 1);
|
||||||
|
localreserve[1] = 0;
|
||||||
|
msr->mpd->bufleft += 1;
|
||||||
|
*(p - 1) = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add data to the part we are building */
|
/* add data to the part we are building */
|
||||||
@@ -318,8 +379,6 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) {
|
|||||||
if (msr->upload_extract_files) {
|
if (msr->upload_extract_files) {
|
||||||
/* first create a temporary file if we don't have it already */
|
/* first create a temporary file if we don't have it already */
|
||||||
if (msr->mpd->mpp->tmp_file_fd == 0) {
|
if (msr->mpd->mpp->tmp_file_fd == 0) {
|
||||||
// char *filename = multipart_construct_filename(msr);
|
|
||||||
|
|
||||||
/* construct temporary file name */
|
/* construct temporary file name */
|
||||||
msr->mpd->mpp->tmp_file_name = apr_psprintf(msr->mp, "%s/%s-%s-file-XXXXXX",
|
msr->mpd->mpp->tmp_file_name = apr_psprintf(msr->mp, "%s/%s-%s-file-XXXXXX",
|
||||||
msr->txcfg->tmp_dir, current_filetime(msr->mp), msr->txid);
|
msr->txcfg->tmp_dir, current_filetime(msr->mp), msr->txid);
|
||||||
@@ -332,19 +391,37 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
msr_log(msr, 4, "Multipart: Created temporary file: %s",
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
log_escape_nq(msr->mp, msr->mpd->mpp->tmp_file_name));
|
msr_log(msr, 4, "Multipart: Created temporary file: %s",
|
||||||
|
log_escape_nq(msr->mp, msr->mpd->mpp->tmp_file_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_FCHMOD
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Multipart: Changing file mode to %04o: %s", msr->txcfg->upload_filemode, log_escape_nq(msr->mp, msr->mpd->mpp->tmp_file_name));
|
||||||
|
}
|
||||||
|
if (fchmod(msr->mpd->mpp->tmp_file_fd, msr->txcfg->upload_filemode) < 0) {
|
||||||
|
|
||||||
|
char errbuf[256];
|
||||||
|
if (msr->txcfg->debuglog_level >= 3) {
|
||||||
|
msr_log(msr, 3, "Multipart: Could not change mode on \"%s\" (%d): %s",
|
||||||
|
log_escape_nq(msr->mp, msr->mpd->mpp->tmp_file_name),
|
||||||
|
errno, apr_strerror(APR_FROM_OS_ERROR(errno), errbuf, 256));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write the reserve first */
|
/* write the reserve first */
|
||||||
if (msr->mpd->reserve[0] == 1) {
|
if (msr->mpd->reserve[0] != 0) {
|
||||||
if (write(msr->mpd->mpp->tmp_file_fd, &msr->mpd->reserve[1], 2) != 2) {
|
if (write(msr->mpd->mpp->tmp_file_fd, &msr->mpd->reserve[1], msr->mpd->reserve[0]) != msr->mpd->reserve[0]) {
|
||||||
*error_msg = apr_psprintf(msr->mp, "Multipart: writing to \"%s\" failed",
|
*error_msg = apr_psprintf(msr->mp, "Multipart: writing to \"%s\" failed",
|
||||||
log_escape(msr->mp, msr->mpd->mpp->tmp_file_name));
|
log_escape(msr->mp, msr->mpd->mpp->tmp_file_name));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
msr->mpd->mpp->tmp_file_size += 2;
|
|
||||||
msr->mpd->mpp->length += 2;
|
msr->mpd->mpp->tmp_file_size += msr->mpd->reserve[0];
|
||||||
|
msr->mpd->mpp->length += msr->mpd->reserve[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write data to the file */
|
/* write data to the file */
|
||||||
@@ -360,16 +437,16 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) {
|
|||||||
msr->mpd->mpp->length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
msr->mpd->mpp->length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
||||||
} else {
|
} else {
|
||||||
/* just keep track of the file size */
|
/* just keep track of the file size */
|
||||||
if (msr->mpd->reserve[0] == 1) {
|
msr->mpd->mpp->tmp_file_size += (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0];
|
||||||
msr->mpd->mpp->tmp_file_size += 2;
|
msr->mpd->mpp->length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0];
|
||||||
}
|
|
||||||
msr->mpd->mpp->tmp_file_size += (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
|
||||||
msr->mpd->mpp->length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (msr->mpd->mpp->type == MULTIPART_FORMDATA) {
|
else if (msr->mpd->mpp->type == MULTIPART_FORMDATA) {
|
||||||
value_part_t *value_part = apr_pcalloc(msr->mp, sizeof(value_part_t));
|
value_part_t *value_part = apr_pcalloc(msr->mp, sizeof(value_part_t));
|
||||||
|
|
||||||
|
/* The buffer contains data so increase the data length counter. */
|
||||||
|
msr->msc_reqbody_no_files_length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0];
|
||||||
|
|
||||||
/* add this part to the list of parts */
|
/* add this part to the list of parts */
|
||||||
|
|
||||||
/* remember where we started */
|
/* remember where we started */
|
||||||
@@ -377,11 +454,12 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) {
|
|||||||
msr->mpd->mpp->offset = msr->mpd->buf_offset;
|
msr->mpd->mpp->offset = msr->mpd->buf_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr->mpd->reserve[0] == 1) {
|
if (msr->mpd->reserve[0] != 0) {
|
||||||
value_part->data = apr_palloc(msr->mp, (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + 2);
|
value_part->data = apr_palloc(msr->mp, (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0]);
|
||||||
memcpy(value_part->data, &(msr->mpd->reserve[1]), 2);
|
memcpy(value_part->data, &(msr->mpd->reserve[1]), msr->mpd->reserve[0]);
|
||||||
memcpy(value_part->data + 2, msr->mpd->buf, (MULTIPART_BUF_SIZE - msr->mpd->bufleft));
|
memcpy(value_part->data + msr->mpd->reserve[0], msr->mpd->buf, (MULTIPART_BUF_SIZE - msr->mpd->bufleft));
|
||||||
value_part->length = (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + 2;
|
|
||||||
|
value_part->length = (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0];
|
||||||
msr->mpd->mpp->length += value_part->length;
|
msr->mpd->mpp->length += value_part->length;
|
||||||
} else {
|
} else {
|
||||||
value_part->length = (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
value_part->length = (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
||||||
@@ -391,11 +469,13 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) {
|
|||||||
|
|
||||||
*(value_part_t **)apr_array_push(msr->mpd->mpp->value_parts) = value_part;
|
*(value_part_t **)apr_array_push(msr->mpd->mpp->value_parts) = value_part;
|
||||||
|
|
||||||
msr_log(msr, 9, "Multipart: Added data to variable: %s",
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
log_escape_nq_ex(msr->mp, value_part->data, value_part->length));
|
msr_log(msr, 9, "Multipart: Added data to variable: %s",
|
||||||
|
log_escape_nq_ex(msr->mp, value_part->data, value_part->length));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*error_msg = apr_psprintf(msr->mp, "Multipart: unknown part type %i", msr->mpd->mpp->type);
|
*error_msg = apr_psprintf(msr->mp, "Multipart: unknown part type %d", msr->mpd->mpp->type);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,14 +483,14 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) {
|
|||||||
* context so that they don't get lost
|
* context so that they don't get lost
|
||||||
*/
|
*/
|
||||||
if (bytes_reserved) {
|
if (bytes_reserved) {
|
||||||
msr->mpd->reserve[0] = 1;
|
msr->mpd->reserve[0] = bytes_reserved;
|
||||||
msr->mpd->reserve[1] = localreserve[0];
|
msr->mpd->reserve[1] = localreserve[0];
|
||||||
msr->mpd->reserve[2] = localreserve[1];
|
msr->mpd->reserve[2] = localreserve[1];
|
||||||
msr->mpd->buf_offset += 2;
|
msr->mpd->buf_offset += bytes_reserved;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
msr->mpd->buf_offset -= msr->mpd->reserve[0];
|
||||||
msr->mpd->reserve[0] = 0;
|
msr->mpd->reserve[0] = 0;
|
||||||
msr->mpd->buf_offset -= 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -463,17 +543,22 @@ static int multipart_process_boundary(modsec_rec *msr, int last_part, char **err
|
|||||||
/* add the part to the list of parts */
|
/* add the part to the list of parts */
|
||||||
*(multipart_part **)apr_array_push(msr->mpd->parts) = msr->mpd->mpp;
|
*(multipart_part **)apr_array_push(msr->mpd->parts) = msr->mpd->mpp;
|
||||||
if (msr->mpd->mpp->type == MULTIPART_FILE) {
|
if (msr->mpd->mpp->type == MULTIPART_FILE) {
|
||||||
msr_log(msr, 9, "Multipart: Added file part %x to the list: name \"%s\" "
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
"file name \"%s\" (offset %u, length %u)",
|
msr_log(msr, 9, "Multipart: Added file part %pp to the list: name \"%s\" "
|
||||||
msr->mpd->mpp, log_escape(msr->mp, msr->mpd->mpp->name),
|
"file name \"%s\" (offset %u, length %u)",
|
||||||
log_escape(msr->mp, msr->mpd->mpp->filename),
|
msr->mpd->mpp, log_escape(msr->mp, msr->mpd->mpp->name),
|
||||||
msr->mpd->mpp->offset, msr->mpd->mpp->length);
|
log_escape(msr->mp, msr->mpd->mpp->filename),
|
||||||
|
msr->mpd->mpp->offset, msr->mpd->mpp->length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
msr_log(msr, 9, "Multipart: Added part %x to the list: name \"%s\" "
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
"(offset %u, length %u)", msr->mpd->mpp, log_escape(msr->mp, msr->mpd->mpp->name),
|
msr_log(msr, 9, "Multipart: Added part %pp to the list: name \"%s\" "
|
||||||
msr->mpd->mpp->offset, msr->mpd->mpp->length);
|
"(offset %u, length %u)", msr->mpd->mpp, log_escape(msr->mp, msr->mpd->mpp->name),
|
||||||
|
msr->mpd->mpp->offset, msr->mpd->mpp->length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msr->mpd->mpp = NULL;
|
msr->mpd->mpp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,6 +584,77 @@ static int multipart_process_boundary(modsec_rec *msr, int last_part, char **err
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int multipart_boundary_characters_valid(char *boundary) {
|
||||||
|
unsigned char *p = (unsigned char *)boundary;
|
||||||
|
unsigned char c;
|
||||||
|
|
||||||
|
if (p == NULL) return -1;
|
||||||
|
|
||||||
|
while((c = *p) != '\0') {
|
||||||
|
/* Control characters and space not allowed. */
|
||||||
|
if (c < 32) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Non-ASCII characters not allowed. */
|
||||||
|
if (c > 126) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(c) {
|
||||||
|
/* Special characters not allowed. */
|
||||||
|
case '(' :
|
||||||
|
case ')' :
|
||||||
|
case '<' :
|
||||||
|
case '>' :
|
||||||
|
case '@' :
|
||||||
|
case ',' :
|
||||||
|
case ';' :
|
||||||
|
case ':' :
|
||||||
|
case '\\' :
|
||||||
|
case '"' :
|
||||||
|
case '/' :
|
||||||
|
case '[' :
|
||||||
|
case ']' :
|
||||||
|
case '?' :
|
||||||
|
case '=' :
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default :
|
||||||
|
/* Do nothing. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int multipart_count_boundary_params(apr_pool_t *mp, const char *header_value) {
|
||||||
|
char *duplicate = NULL;
|
||||||
|
char *s = NULL;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
if (header_value == NULL) return -1;
|
||||||
|
duplicate = apr_pstrdup(mp, header_value);
|
||||||
|
if (duplicate == NULL) return -1;
|
||||||
|
|
||||||
|
/* Performing a case-insensitive search. */
|
||||||
|
strtolower_inplace((unsigned char *)duplicate);
|
||||||
|
|
||||||
|
s = duplicate;
|
||||||
|
while((s = strstr(s, "boundary")) != NULL) {
|
||||||
|
s += 8;
|
||||||
|
|
||||||
|
if (strchr(s, '=') != NULL) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -510,26 +666,156 @@ int multipart_init(modsec_rec *msr, char **error_msg) {
|
|||||||
msr->mpd = (multipart_data *)apr_pcalloc(msr->mp, sizeof(multipart_data));
|
msr->mpd = (multipart_data *)apr_pcalloc(msr->mp, sizeof(multipart_data));
|
||||||
if (msr->mpd == NULL) return -1;
|
if (msr->mpd == NULL) return -1;
|
||||||
|
|
||||||
if (msr->request_content_type == NULL) {
|
|
||||||
*error_msg = apr_psprintf(msr->mp, "Multipart: Content-Type header not available.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
msr->mpd->boundary = strstr(msr->request_content_type, "boundary=");
|
|
||||||
if ((msr->mpd->boundary != NULL)&&(*(msr->mpd->boundary + 9) != 0)) {
|
|
||||||
msr->mpd->boundary = msr->mpd->boundary + 9;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*error_msg = apr_psprintf(msr->mp, "Multipart Boundary not found or invalid.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
msr->mpd->parts = apr_array_make(msr->mp, 10, sizeof(multipart_part *));
|
msr->mpd->parts = apr_array_make(msr->mp, 10, sizeof(multipart_part *));
|
||||||
msr->mpd->bufleft = MULTIPART_BUF_SIZE;
|
msr->mpd->bufleft = MULTIPART_BUF_SIZE;
|
||||||
msr->mpd->bufptr = msr->mpd->buf;
|
msr->mpd->bufptr = msr->mpd->buf;
|
||||||
msr->mpd->buf_contains_line = 1;
|
msr->mpd->buf_contains_line = 1;
|
||||||
msr->mpd->mpp = NULL;
|
msr->mpd->mpp = NULL;
|
||||||
|
|
||||||
|
if (msr->request_content_type == NULL) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Content-Type header not available.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(msr->request_content_type) > 1024) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (length).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncasecmp(msr->request_content_type, "multipart/form-data", 19) != 0) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid MIME type.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Count how many times the word "boundary" appears in the C-T header. */
|
||||||
|
if (multipart_count_boundary_params(msr->mp, msr->request_content_type) > 1) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Multiple boundary parameters in C-T.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msr->mpd->boundary = strstr(msr->request_content_type, "boundary");
|
||||||
|
if (msr->mpd->boundary != NULL) {
|
||||||
|
char *p = NULL;
|
||||||
|
char *b = NULL;
|
||||||
|
int seen_semicolon = 0;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
/* Check for extra characters before the boundary. */
|
||||||
|
for (p = (char *)(msr->request_content_type + 19); p < msr->mpd->boundary; p++) {
|
||||||
|
if (!isspace(*p)) {
|
||||||
|
if ((seen_semicolon == 0)&&(*p == ';')) {
|
||||||
|
seen_semicolon = 1; /* It is OK to have one semicolon. */
|
||||||
|
} else {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (malformed).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Have we seen the semicolon in the header? */
|
||||||
|
if (seen_semicolon == 0) {
|
||||||
|
msr->mpd->flag_missing_semicolon = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
b = strchr(msr->mpd->boundary + 8, '=');
|
||||||
|
if (b == NULL) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (malformed).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check parameter name ends well. */
|
||||||
|
if (b != (msr->mpd->boundary + 8)) {
|
||||||
|
/* Check all characters between the end of the boundary
|
||||||
|
* and the = character.
|
||||||
|
*/
|
||||||
|
for (p = msr->mpd->boundary + 8; p < b; p++) {
|
||||||
|
if (isspace(*p)) {
|
||||||
|
/* Flag for whitespace after parameter name. */
|
||||||
|
msr->mpd->flag_boundary_whitespace = 1;
|
||||||
|
} else {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (parameter name).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b++; /* Go over the = character. */
|
||||||
|
len = strlen(b);
|
||||||
|
|
||||||
|
/* Flag for whitespace before parameter value. */
|
||||||
|
if (isspace(*b)) {
|
||||||
|
msr->mpd->flag_boundary_whitespace = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is the boundary quoted? */
|
||||||
|
if ((len >= 2)&&(*b == '"')&&(*(b + len - 1) == '"')) {
|
||||||
|
/* Quoted. */
|
||||||
|
msr->mpd->boundary = apr_pstrndup(msr->mp, b + 1, len - 2);
|
||||||
|
if (msr->mpd->boundary == NULL) return -1;
|
||||||
|
msr->mpd->flag_boundary_quoted = 1;
|
||||||
|
} else {
|
||||||
|
/* Not quoted. */
|
||||||
|
|
||||||
|
/* Test for partial quoting. */
|
||||||
|
if ( (*b == '"')
|
||||||
|
|| ((len >= 2)&&(*(b + len - 1) == '"')) )
|
||||||
|
{
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (quote).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msr->mpd->boundary = apr_pstrdup(msr->mp, b);
|
||||||
|
if (msr->mpd->boundary == NULL) return -1;
|
||||||
|
msr->mpd->flag_boundary_quoted = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Case-insensitive test for the string "boundary" in the boundary. */
|
||||||
|
if (multipart_count_boundary_params(msr->mp, msr->mpd->boundary) != 0) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (content).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate the characters used in the boundary. */
|
||||||
|
if (multipart_boundary_characters_valid(msr->mpd->boundary) != 1) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (characters).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Multipart: Boundary%s: %s",
|
||||||
|
(msr->mpd->flag_boundary_quoted ? " (quoted)" : ""),
|
||||||
|
log_escape_nq(msr->mp, msr->mpd->boundary));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(msr->mpd->boundary) == 0) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (empty).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { /* Could not find boundary in the C-T header. */
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
|
||||||
|
/* Test for case-insensitive boundary. Allowed by the RFC but highly unusual. */
|
||||||
|
if (multipart_count_boundary_params(msr->mp, msr->request_content_type) > 0) {
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (case sensitivity).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Boundary not found in C-T.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,7 +826,11 @@ int multipart_complete(modsec_rec *msr, char **error_log) {
|
|||||||
if (msr->mpd == NULL) return 1;
|
if (msr->mpd == NULL) return 1;
|
||||||
|
|
||||||
if ((msr->mpd->seen_data != 0)&&(msr->mpd->is_complete == 0)) {
|
if ((msr->mpd->seen_data != 0)&&(msr->mpd->is_complete == 0)) {
|
||||||
*error_log = apr_psprintf(msr->mp, "Multipart: final boundary missing");
|
if (msr->mpd->boundary_count > 0) {
|
||||||
|
*error_log = apr_psprintf(msr->mp, "Multipart: Final boundary missing.");
|
||||||
|
} else {
|
||||||
|
*error_log = apr_psprintf(msr->mp, "Multipart: No boundaries found in payload.");
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,26 +851,32 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf,
|
|||||||
|
|
||||||
if (size == 0) return 1;
|
if (size == 0) return 1;
|
||||||
|
|
||||||
if (msr->mpd->seen_data == 0) msr->mpd->seen_data = 1;
|
msr->mpd->seen_data = 1;
|
||||||
|
|
||||||
if (msr->mpd->is_complete) {
|
if (msr->mpd->is_complete) {
|
||||||
msr_log(msr, 4, "Multipart: Ignoring data after last boundary (received %i bytes)", size);
|
msr->mpd->flag_data_before = 1;
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
|
msr_log(msr, 4, "Multipart: Ignoring data after last boundary (received %u bytes)", size);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr->mpd->bufleft == 0) {
|
if (msr->mpd->bufleft == 0) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
*error_msg = apr_psprintf(msr->mp,
|
*error_msg = apr_psprintf(msr->mp,
|
||||||
"Multipart: Internal error in process_chunk: no space left in the buffer");
|
"Multipart: Internal error in process_chunk: no space left in the buffer");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* here we loop through the data available, byte by byte */
|
/* here we loop through the available data, one byte at a time */
|
||||||
while(inleft > 0) {
|
while(inleft > 0) {
|
||||||
char c = *inptr;
|
char c = *inptr;
|
||||||
int process_buffer = 0;
|
int process_buffer = 0;
|
||||||
|
|
||||||
if ((c == 0x0d)&&(msr->mpd->bufleft == 1)) {
|
if ((c == '\r')&&(msr->mpd->bufleft == 1)) {
|
||||||
/* we don't want to take 0x0d as the last byte in the buffer */
|
/* we don't want to take \r as the last byte in the buffer */
|
||||||
process_buffer = 1;
|
process_buffer = 1;
|
||||||
} else {
|
} else {
|
||||||
inptr++;
|
inptr++;
|
||||||
@@ -594,63 +890,149 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf,
|
|||||||
/* until we either reach the end of the line
|
/* until we either reach the end of the line
|
||||||
* or the end of our internal buffer
|
* or the end of our internal buffer
|
||||||
*/
|
*/
|
||||||
if ((c == 0x0a)||(msr->mpd->bufleft == 0)||(process_buffer)) {
|
if ((c == '\n')||(msr->mpd->bufleft == 0)||(process_buffer)) {
|
||||||
|
int processed_as_boundary = 0;
|
||||||
|
|
||||||
*(msr->mpd->bufptr) = 0;
|
*(msr->mpd->bufptr) = 0;
|
||||||
|
|
||||||
/* boundary preconditions: length of the line greater than
|
/* Do we have something that looks like a boundary? */
|
||||||
* the length of the boundary + the first two characters
|
if (msr->mpd->buf_contains_line
|
||||||
* are dashes "-"
|
&& (strlen(msr->mpd->buf) > 3)
|
||||||
*/
|
&& (((*(msr->mpd->buf) == '-'))&&(*(msr->mpd->buf + 1) == '-')) )
|
||||||
if ( msr->mpd->buf_contains_line
|
{
|
||||||
&& (strlen(msr->mpd->buf) > strlen(msr->mpd->boundary) + 2)
|
/* Does it match our boundary? */
|
||||||
&& (((*(msr->mpd->buf) == '-'))&&(*(msr->mpd->buf + 1) == '-'))
|
if ((strlen(msr->mpd->buf) >= strlen(msr->mpd->boundary) + 2)
|
||||||
&& (strncmp(msr->mpd->buf + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) ) {
|
&& (strncmp(msr->mpd->buf + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) )
|
||||||
|
{
|
||||||
|
char *boundary_end = msr->mpd->buf + 2 + strlen(msr->mpd->boundary);
|
||||||
|
int is_final = 0;
|
||||||
|
|
||||||
char *boundary_end = msr->mpd->buf + 2 + strlen(msr->mpd->boundary);
|
/* Is this the final boundary? */
|
||||||
|
if ((*boundary_end == '-')&&(*(boundary_end + 1)== '-')) {
|
||||||
|
is_final = 1;
|
||||||
|
boundary_end += 2;
|
||||||
|
|
||||||
if ( (*boundary_end == '\r')
|
if (msr->mpd->is_complete != 0) {
|
||||||
&&(*(boundary_end + 1) == '\n')
|
msr->mpd->flag_error = 1;
|
||||||
&&(*(boundary_end + 2) == '\0')
|
*error_msg = apr_psprintf(msr->mp,
|
||||||
) {
|
"Multipart: Invalid boundary (final duplicate).");
|
||||||
/* simple boundary */
|
return -1;
|
||||||
if (multipart_process_boundary(msr, 0, error_msg) < 0) return -1;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allow for CRLF and LF line endings. */
|
||||||
|
if ( ( (*boundary_end == '\r')
|
||||||
|
&& (*(boundary_end + 1) == '\n')
|
||||||
|
&& (*(boundary_end + 2) == '\0') )
|
||||||
|
|| ( (*boundary_end == '\n')
|
||||||
|
&& (*(boundary_end + 1) == '\0') ) )
|
||||||
|
{
|
||||||
|
if (*boundary_end == '\n') {
|
||||||
|
msr->mpd->flag_lf_line = 1;
|
||||||
|
} else {
|
||||||
|
msr->mpd->flag_crlf_line = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (multipart_process_boundary(msr, (is_final ? 1 : 0), error_msg) < 0) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_final) {
|
||||||
|
msr->mpd->is_complete = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
processed_as_boundary = 1;
|
||||||
|
msr->mpd->boundary_count++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* error */
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp,
|
||||||
|
"Multipart: Invalid boundary: %s",
|
||||||
|
log_escape_nq(msr->mp, msr->mpd->buf));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else { /* It looks like a boundary but we couldn't match it. */
|
||||||
|
char *p = NULL;
|
||||||
|
|
||||||
|
/* Check if an attempt to use quotes around the boundary was made. */
|
||||||
|
if ( (msr->mpd->flag_boundary_quoted)
|
||||||
|
&& (strlen(msr->mpd->buf) >= strlen(msr->mpd->boundary) + 3)
|
||||||
|
&& (*(msr->mpd->buf + 2) == '"')
|
||||||
|
&& (strncmp(msr->mpd->buf + 3, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0)
|
||||||
|
) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary (quotes).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the beginning of the boundary for whitespace. */
|
||||||
|
p = msr->mpd->buf + 2;
|
||||||
|
while(isspace(*p)) {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (p != msr->mpd->buf + 2)
|
||||||
|
&& (strncmp(p, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0)
|
||||||
|
) {
|
||||||
|
/* Found whitespace in front of a boundary. */
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary (whitespace).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msr->mpd->flag_unmatched_boundary = 1;
|
||||||
}
|
}
|
||||||
else
|
} else { /* We do not think the buffer contains a boundary. */
|
||||||
if ( (*boundary_end == '-')
|
/* Look into the buffer to see if there's anything
|
||||||
&&(*(boundary_end + 1) == '-')
|
* there that resembles a boundary.
|
||||||
&&(*(boundary_end + 2) == '\r')
|
*/
|
||||||
&&(*(boundary_end + 3) == '\n')
|
if (msr->mpd->buf_contains_line) {
|
||||||
&&(*(boundary_end + 4) == '\0')
|
int i, len = (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
||||||
) {
|
char *p = msr->mpd->buf;
|
||||||
/* final boundary */
|
|
||||||
msr->mpd->is_complete = 1;
|
for(i = 0; i < len; i++) {
|
||||||
if (multipart_process_boundary(msr, 1, error_msg) < 0) return -1;
|
if ((p[i] == '-')&&(i + 1 < len)&&(p[i + 1] == '-')) {
|
||||||
}
|
if (strncmp(p + i + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) {
|
||||||
else {
|
msr->mpd->flag_unmatched_boundary = 1;
|
||||||
/* error */
|
break;
|
||||||
*error_msg = apr_psprintf(msr->mp,
|
}
|
||||||
"Multipart: Invalid boundary detected: %s",
|
}
|
||||||
log_escape_nq(msr->mp, msr->mpd->buf));
|
}
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
/* Process as data if it was not a boundary. */
|
||||||
|
if (processed_as_boundary == 0) {
|
||||||
if (msr->mpd->mpp == NULL) {
|
if (msr->mpd->mpp == NULL) {
|
||||||
msr_log(msr, 4, "Multipart: Ignoring data before first boundary.");
|
msr->mpd->flag_data_before = 1;
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
|
msr_log(msr, 4, "Multipart: Ignoring data before first boundary.");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (msr->mpd->mpp_state == 0) {
|
if (msr->mpd->mpp_state == 0) {
|
||||||
if ((msr->mpd->bufleft == 0)||(process_buffer)) {
|
if ((msr->mpd->bufleft == 0)||(process_buffer)) {
|
||||||
/* part header lines must be shorter than
|
/* part header lines must be shorter than
|
||||||
* MULTIPART_BUF_SIZE bytes
|
* MULTIPART_BUF_SIZE bytes
|
||||||
*/
|
*/
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
*error_msg = apr_psprintf(msr->mp,
|
*error_msg = apr_psprintf(msr->mp,
|
||||||
"Multipart: Part header line over %i bytes long",
|
"Multipart: Part header line over %d bytes long",
|
||||||
MULTIPART_BUF_SIZE);
|
MULTIPART_BUF_SIZE);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (multipart_process_part_header(msr, error_msg) < 0) return -1;
|
|
||||||
|
if (multipart_process_part_header(msr, error_msg) < 0) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (multipart_process_part_data(msr, error_msg) < 0) return -1;
|
if (multipart_process_part_data(msr, error_msg) < 0) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -670,7 +1052,12 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((msr->mpd->is_complete)&&(inleft != 0)) {
|
if ((msr->mpd->is_complete)&&(inleft != 0)) {
|
||||||
msr_log(msr, 4, "Multipart: Ignoring data after last boundary (%i bytes left)", inleft);
|
msr->mpd->flag_data_after = 1;
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
|
msr_log(msr, 4, "Multipart: Ignoring data after last boundary (%u bytes left)", inleft);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -686,7 +1073,9 @@ apr_status_t multipart_cleanup(modsec_rec *msr) {
|
|||||||
|
|
||||||
if (msr->mpd == NULL) return -1;
|
if (msr->mpd == NULL) return -1;
|
||||||
|
|
||||||
msr_log(msr, 4, "Multipart: Cleanup started (remove files %i).", msr->upload_remove_files);
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
|
msr_log(msr, 4, "Multipart: Cleanup started (remove files %d).", msr->upload_remove_files);
|
||||||
|
}
|
||||||
|
|
||||||
if (msr->upload_remove_files == 0) {
|
if (msr->upload_remove_files == 0) {
|
||||||
if (msr->txcfg->upload_dir == NULL) {
|
if (msr->txcfg->upload_dir == NULL) {
|
||||||
@@ -715,8 +1104,10 @@ apr_status_t multipart_cleanup(modsec_rec *msr) {
|
|||||||
msr_log(msr, 1, "Multipart: Failed to delete file (part) \"%s\" because %d(%s)",
|
msr_log(msr, 1, "Multipart: Failed to delete file (part) \"%s\" because %d(%s)",
|
||||||
log_escape(msr->mp, parts[i]->tmp_file_name), errno, strerror(errno));
|
log_escape(msr->mp, parts[i]->tmp_file_name), errno, strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
msr_log(msr, 4, "Multipart: Deleted file (part) \"%s\"",
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
log_escape(msr->mp, parts[i]->tmp_file_name));
|
msr_log(msr, 4, "Multipart: Deleted file (part) \"%s\"",
|
||||||
|
log_escape(msr->mp, parts[i]->tmp_file_name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -735,8 +1126,10 @@ apr_status_t multipart_cleanup(modsec_rec *msr) {
|
|||||||
msr_log(msr, 1, "Multipart: Failed to delete empty file (part) \"%s\" because %d(%s)",
|
msr_log(msr, 1, "Multipart: Failed to delete empty file (part) \"%s\" because %d(%s)",
|
||||||
log_escape(msr->mp, parts[i]->tmp_file_name), errno, strerror(errno));
|
log_escape(msr->mp, parts[i]->tmp_file_name), errno, strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
msr_log(msr, 4, "Multipart: Deleted empty file (part) \"%s\"",
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
log_escape(msr->mp, parts[i]->tmp_file_name));
|
msr_log(msr, 4, "Multipart: Deleted empty file (part) \"%s\"",
|
||||||
|
log_escape(msr->mp, parts[i]->tmp_file_name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -759,9 +1152,11 @@ apr_status_t multipart_cleanup(modsec_rec *msr) {
|
|||||||
log_escape(msr->mp, new_filename));
|
log_escape(msr->mp, new_filename));
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
msr_log(msr, 4, "Input filter: Moved file from \"%s\" to \"%s\".",
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
log_escape(msr->mp, parts[i]->tmp_file_name),
|
msr_log(msr, 4, "Input filter: Moved file from \"%s\" to \"%s\".",
|
||||||
log_escape(msr->mp, new_filename));
|
log_escape(msr->mp, parts[i]->tmp_file_name),
|
||||||
|
log_escape(msr->mp, new_filename));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -785,14 +1180,14 @@ int multipart_get_arguments(modsec_rec *msr, char *origin, apr_table_t *argument
|
|||||||
if (arg == NULL) return -1;
|
if (arg == NULL) return -1;
|
||||||
|
|
||||||
arg->name = parts[i]->name;
|
arg->name = parts[i]->name;
|
||||||
arg->name_len = strlen(parts[i]->name); // TODO
|
arg->name_len = strlen(parts[i]->name);
|
||||||
arg->value = parts[i]->value;
|
arg->value = parts[i]->value;
|
||||||
arg->value_len = parts[i]->length;
|
arg->value_len = parts[i]->length;
|
||||||
arg->value_origin_offset = parts[i]->offset;
|
arg->value_origin_offset = parts[i]->offset;
|
||||||
arg->value_origin_len = parts[i]->length;
|
arg->value_origin_len = parts[i]->length;
|
||||||
arg->origin = origin;
|
arg->origin = origin;
|
||||||
|
|
||||||
apr_table_addn(arguments, arg->name, (void *)arg);
|
add_argument(msr, arguments, arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -810,8 +1205,6 @@ char *multipart_reconstruct_urlencoded_body_sanitise(modsec_rec *msr) {
|
|||||||
|
|
||||||
if (msr->mpd == NULL) return NULL;
|
if (msr->mpd == NULL) return NULL;
|
||||||
|
|
||||||
// TODO Cache this data somewhere in the structure
|
|
||||||
|
|
||||||
/* calculate the size of the buffer */
|
/* calculate the size of the buffer */
|
||||||
body_len = 1;
|
body_len = 1;
|
||||||
parts = (multipart_part **)msr->mpd->parts->elts;
|
parts = (multipart_part **)msr->mpd->parts->elts;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -45,7 +45,7 @@ struct multipart_part {
|
|||||||
/* files only, the name of the temporary file holding data */
|
/* files only, the name of the temporary file holding data */
|
||||||
char *tmp_file_name;
|
char *tmp_file_name;
|
||||||
int tmp_file_fd;
|
int tmp_file_fd;
|
||||||
unsigned tmp_file_size;
|
unsigned int tmp_file_size;
|
||||||
/* files only, filename as supplied by the browser */
|
/* files only, filename as supplied by the browser */
|
||||||
char *filename;
|
char *filename;
|
||||||
|
|
||||||
@@ -61,9 +61,10 @@ struct multipart_data {
|
|||||||
apr_array_header_t *parts;
|
apr_array_header_t *parts;
|
||||||
|
|
||||||
/* mime boundary used to detect when
|
/* mime boundary used to detect when
|
||||||
* parts end and new begin
|
* parts end and begin
|
||||||
*/
|
*/
|
||||||
char *boundary;
|
char *boundary;
|
||||||
|
int boundary_count;
|
||||||
|
|
||||||
/* internal buffer and other variables
|
/* internal buffer and other variables
|
||||||
* used while parsing
|
* used while parsing
|
||||||
@@ -84,7 +85,7 @@ struct multipart_data {
|
|||||||
/* part parsing state; 0 means we are reading
|
/* part parsing state; 0 means we are reading
|
||||||
* headers, 1 means we are collecting data
|
* headers, 1 means we are collecting data
|
||||||
*/
|
*/
|
||||||
int mpp_state;
|
int mpp_state;
|
||||||
|
|
||||||
/* because of the way this parsing algorithm
|
/* because of the way this parsing algorithm
|
||||||
* works we hold back the last two bytes of
|
* works we hold back the last two bytes of
|
||||||
@@ -93,10 +94,21 @@ struct multipart_data {
|
|||||||
* a boundary; the first byte is an indicator
|
* a boundary; the first byte is an indicator
|
||||||
* 0 - no content, 1 - two data bytes available
|
* 0 - no content, 1 - two data bytes available
|
||||||
*/
|
*/
|
||||||
char reserve[4];
|
char reserve[4];
|
||||||
|
|
||||||
int seen_data;
|
int seen_data;
|
||||||
int is_complete;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -206,6 +206,7 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength,
|
|||||||
char *value = NULL;
|
char *value = NULL;
|
||||||
char *buf;
|
char *buf;
|
||||||
int status;
|
int status;
|
||||||
|
int changed;
|
||||||
|
|
||||||
if (s == NULL) return -1;
|
if (s == NULL) return -1;
|
||||||
if (inputlength == 0) return 1;
|
if (inputlength == 0) return 1;
|
||||||
@@ -247,7 +248,7 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
arg->name_len = urldecode_nonstrict_inplace_ex((unsigned char *)buf, arg->name_origin_len, invalid_count);
|
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);
|
arg->name = apr_pstrmemdup(msr->mp, buf, arg->name_len);
|
||||||
|
|
||||||
if (s[i] == argument_separator) {
|
if (s[i] == argument_separator) {
|
||||||
@@ -255,10 +256,7 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength,
|
|||||||
arg->value_len = 0;
|
arg->value_len = 0;
|
||||||
arg->value = "";
|
arg->value = "";
|
||||||
|
|
||||||
apr_table_addn(arguments, arg->name, (void *)arg);
|
add_argument(msr, arguments, arg);
|
||||||
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));
|
|
||||||
|
|
||||||
arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg));
|
arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg));
|
||||||
arg->origin = origin;
|
arg->origin = origin;
|
||||||
@@ -271,13 +269,10 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
arg->value_len = urldecode_nonstrict_inplace_ex((unsigned char *)value, arg->value_origin_len, invalid_count);
|
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);
|
arg->value = apr_pstrmemdup(msr->mp, value, arg->value_len);
|
||||||
|
|
||||||
apr_table_addn(arguments, arg->name, (void *)arg);
|
add_argument(msr, arguments, arg);
|
||||||
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));
|
|
||||||
|
|
||||||
arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg));
|
arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg));
|
||||||
arg->origin = origin;
|
arg->origin = origin;
|
||||||
@@ -294,12 +289,22 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength,
|
|||||||
arg->value_len = 0;
|
arg->value_len = 0;
|
||||||
arg->value = "";
|
arg->value = "";
|
||||||
|
|
||||||
apr_table_addn(arguments, arg->name, (void *)arg);
|
add_argument(msr, arguments, arg);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void add_argument(modsec_rec *msr, apr_table_t *arguments, msc_arg *arg) {
|
||||||
|
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,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -20,4 +20,6 @@ int DSOLOCAL parse_cookies_v1(modsec_rec *msr, char *_cookie_header, apr_table_t
|
|||||||
int DSOLOCAL parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength,
|
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);
|
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
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -63,6 +63,20 @@ void *msc_pregcomp(apr_pool_t *pool, const char *pattern, int options,
|
|||||||
return regex;
|
return regex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Executes regular expression, capturing subexpressions in the given
|
||||||
* vector. Returns PCRE_ERROR_NOMATCH when there is no match, error code < -1
|
* vector. Returns PCRE_ERROR_NOMATCH when there is no match, error code < -1
|
||||||
@@ -74,7 +88,7 @@ int msc_regexec_capture(msc_regex_t *regex, const char *s, unsigned int slen,
|
|||||||
if (error_msg == NULL) return -1000; /* To differentiate from PCRE as it already uses -1. */
|
if (error_msg == NULL) return -1000; /* To differentiate from PCRE as it already uses -1. */
|
||||||
*error_msg = NULL;
|
*error_msg = NULL;
|
||||||
|
|
||||||
return pcre_exec(regex->re, regex->pe, s, slen, 0, 0, ovector, ovecsize);
|
return msc_regexec_ex(regex, s, slen, 0, 0, ovector, ovecsize, error_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,7 +101,7 @@ int msc_regexec(msc_regex_t *regex, const char *s, unsigned int slen,
|
|||||||
if (error_msg == NULL) return -1000; /* To differentiate from PCRE as it already uses -1. */
|
if (error_msg == NULL) return -1000; /* To differentiate from PCRE as it already uses -1. */
|
||||||
*error_msg = NULL;
|
*error_msg = NULL;
|
||||||
|
|
||||||
return msc_regexec_capture(regex, s, slen, NULL, 0, error_msg);
|
return msc_regexec_ex(regex, s, slen, 0, 0, NULL, 0, error_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -28,6 +28,9 @@ apr_status_t DSOLOCAL msc_pcre_cleanup(msc_regex_t *regex);
|
|||||||
void DSOLOCAL *msc_pregcomp(apr_pool_t *pool, const char *pattern, int options,
|
void DSOLOCAL *msc_pregcomp(apr_pool_t *pool, const char *pattern, int options,
|
||||||
const char **_errptr, int *_erroffset);
|
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,
|
int DSOLOCAL msc_regexec_capture(msc_regex_t *regex, const char *s,
|
||||||
unsigned int slen, int *ovector, int ovecsize, char **error_msg);
|
unsigned int slen, int *ovector, int ovecsize, char **error_msg);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -16,23 +16,31 @@
|
|||||||
/**
|
/**
|
||||||
* Prepare to accept the request body (part 2).
|
* Prepare to accept the request body (part 2).
|
||||||
*/
|
*/
|
||||||
static apr_status_t modsecurity_request_body_start_init(modsec_rec *msr) {
|
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) {
|
if(msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
||||||
/* Prepare to store request body in memory. */
|
/* Prepare to store request body in memory. */
|
||||||
|
|
||||||
msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp,
|
msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp,
|
||||||
32, sizeof(msc_data_chunk *));
|
32, sizeof(msc_data_chunk *));
|
||||||
if (msr->msc_reqbody_chunks == NULL) return -1;
|
if (msr->msc_reqbody_chunks == NULL) {
|
||||||
|
*error_msg = apr_pstrdup(msr->mp, "Input filter: Failed to prepare in-memory storage.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Prepare to store request body on disk. */
|
/* Prepare to store request body on disk. */
|
||||||
|
|
||||||
msr->msc_reqbody_filename = apr_psprintf(msr->mp, "%s/%s-%s-request_body-XXXXXX",
|
msr->msc_reqbody_filename = apr_psprintf(msr->mp, "%s/%s-%s-request_body-XXXXXX",
|
||||||
msr->txcfg->tmp_dir, current_filetime(msr->mp), msr->txid);
|
msr->txcfg->tmp_dir, current_filetime(msr->mp), msr->txid);
|
||||||
if (msr->msc_reqbody_filename == NULL) return -1;
|
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);
|
msr->msc_reqbody_fd = msc_mkstemp((char *)msr->msc_reqbody_filename);
|
||||||
if (msr->msc_reqbody_fd < 0) {
|
if (msr->msc_reqbody_fd < 0) {
|
||||||
msr_log(msr, 1, "Input filter: Failed to create temporary file: %s",
|
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to create temporary file: %s",
|
||||||
msr->msc_reqbody_filename);
|
msr->msc_reqbody_filename);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -47,14 +55,15 @@ static apr_status_t modsecurity_request_body_start_init(modsec_rec *msr) {
|
|||||||
/**
|
/**
|
||||||
* Prepare to accept the request body (part 1).
|
* Prepare to accept the request body (part 1).
|
||||||
*/
|
*/
|
||||||
apr_status_t modsecurity_request_body_start(modsec_rec *msr) {
|
apr_status_t modsecurity_request_body_start(modsec_rec *msr, char **error_msg) {
|
||||||
|
*error_msg = NULL;
|
||||||
msr->msc_reqbody_length = 0;
|
msr->msc_reqbody_length = 0;
|
||||||
|
|
||||||
/* Create a separate memory pool that will be used
|
/* Create a separate memory pool that will be used
|
||||||
* to allocate structures from (not data, which is allocated
|
* to allocate structures from (not data, which is allocated
|
||||||
* via malloc).
|
* via malloc).
|
||||||
*/
|
*/
|
||||||
apr_pool_create(&msr->msc_reqbody_mp, msr->mp);
|
apr_pool_create(&msr->msc_reqbody_mp, NULL);
|
||||||
|
|
||||||
/* Initialise request body processors, if any. */
|
/* Initialise request body processors, if any. */
|
||||||
|
|
||||||
@@ -63,43 +72,47 @@ apr_status_t modsecurity_request_body_start(modsec_rec *msr) {
|
|||||||
|
|
||||||
if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
|
if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
|
||||||
if (multipart_init(msr, &my_error_msg) < 0) {
|
if (multipart_init(msr, &my_error_msg) < 0) {
|
||||||
msr_log(msr, 1, "Multipart parser init failed: %s", my_error_msg);
|
*error_msg = apr_psprintf(msr->mp, "Multipart parser init failed: %s", my_error_msg);
|
||||||
msr->msc_reqbody_error = 1;
|
msr->msc_reqbody_error = 1;
|
||||||
msr->msc_reqbody_error_msg = my_error_msg;
|
msr->msc_reqbody_error_msg = my_error_msg;
|
||||||
|
msr_log(msr, 2, "Multipart parser init failed: %s", my_error_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef WITH_LIBXML2
|
|
||||||
else
|
else
|
||||||
if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
|
if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
|
||||||
if (xml_init(msr, &my_error_msg) < 0) {
|
if (xml_init(msr, &my_error_msg) < 0) {
|
||||||
msr_log(msr, 1, "XML parser init failed: %s", my_error_msg);
|
*error_msg = apr_psprintf(msr->mp, "XML parser init failed: %s", my_error_msg);
|
||||||
msr->msc_reqbody_error = 1;
|
msr->msc_reqbody_error = 1;
|
||||||
msr->msc_reqbody_error_msg = my_error_msg;
|
msr->msc_reqbody_error_msg = my_error_msg;
|
||||||
|
msr_log(msr, 2, "Multipart parser init failed: %s", my_error_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
else
|
else
|
||||||
if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
||||||
/* Do nothing, URLENCODED processor does not support streaming yet. */
|
/* Do nothing, URLENCODED processor does not support streaming yet. */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
msr_log(msr, 1, "Unknown request body processor: %s", msr->msc_reqbody_processor);
|
*error_msg = apr_psprintf(msr->mp, "Unknown request body processor: %s", msr->msc_reqbody_processor);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return modsecurity_request_body_start_init(msr);
|
return modsecurity_request_body_start_init(msr, error_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a chunk of request body data to disk.
|
* Stores a chunk of request body data to disk.
|
||||||
*/
|
*/
|
||||||
static apr_status_t modsecurity_request_body_store_disk(modsec_rec *msr,
|
static apr_status_t modsecurity_request_body_store_disk(modsec_rec *msr,
|
||||||
const char *data, apr_size_t length)
|
const char *data, apr_size_t length, char **error_msg)
|
||||||
{
|
{
|
||||||
apr_size_t i = write(msr->msc_reqbody_fd, data, length);
|
apr_size_t i;
|
||||||
|
|
||||||
|
*error_msg = NULL;
|
||||||
|
|
||||||
|
i = write(msr->msc_reqbody_fd, data, length);
|
||||||
if (i != length) {
|
if (i != length) {
|
||||||
msr_log(msr, 1, "Input filter: Failed writing %lu bytes to temporary file (rc %lu).", i);
|
*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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,8 +123,10 @@ static apr_status_t modsecurity_request_body_store_disk(modsec_rec *msr,
|
|||||||
* Stores one chunk of request body data in memory.
|
* Stores one chunk of request body data in memory.
|
||||||
*/
|
*/
|
||||||
static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr,
|
static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr,
|
||||||
const char *data, apr_size_t length)
|
const char *data, apr_size_t length, char **error_msg)
|
||||||
{
|
{
|
||||||
|
*error_msg = NULL;
|
||||||
|
|
||||||
/* Would storing this chunk mean going over the limit? */
|
/* Would storing this chunk mean going over the limit? */
|
||||||
if ((msr->msc_reqbody_spilltodisk)
|
if ((msr->msc_reqbody_spilltodisk)
|
||||||
&& (msr->msc_reqbody_length + length > (apr_size_t)msr->txcfg->reqbody_inmemory_limit))
|
&& (msr->msc_reqbody_length + length > (apr_size_t)msr->txcfg->reqbody_inmemory_limit))
|
||||||
@@ -129,14 +144,14 @@ static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr,
|
|||||||
|
|
||||||
/* Initialise disk storage */
|
/* Initialise disk storage */
|
||||||
msr->msc_reqbody_storage = MSC_REQBODY_DISK;
|
msr->msc_reqbody_storage = MSC_REQBODY_DISK;
|
||||||
if (modsecurity_request_body_start_init(msr) < 0) return -1;
|
if (modsecurity_request_body_start_init(msr, error_msg) < 0) return -1;
|
||||||
|
|
||||||
/* Write the data we keep in memory */
|
/* Write the data we keep in memory */
|
||||||
chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
||||||
for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
|
for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
|
||||||
disklen += chunks[i]->length;
|
disklen += chunks[i]->length;
|
||||||
|
|
||||||
if (modsecurity_request_body_store_disk(msr, chunks[i]->data, chunks[i]->length) < 0) {
|
if (modsecurity_request_body_store_disk(msr, chunks[i]->data, chunks[i]->length, error_msg) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,10 +167,10 @@ static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr,
|
|||||||
msr->msc_reqbody_chunks = NULL;
|
msr->msc_reqbody_chunks = NULL;
|
||||||
apr_pool_clear(msr->msc_reqbody_mp);
|
apr_pool_clear(msr->msc_reqbody_mp);
|
||||||
|
|
||||||
msr_log(msr, 4, "Input filter: Wrote %lu bytes from memory to disk.", disklen);
|
msr_log(msr, 4, "Input filter: Wrote %u bytes from memory to disk.", disklen);
|
||||||
|
|
||||||
/* Continue with disk storage from now on */
|
/* Continue with disk storage from now on */
|
||||||
return modsecurity_request_body_store_disk(msr, data, length);
|
return modsecurity_request_body_store_disk(msr, data, length, error_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we're here that means we are not over the
|
/* If we're here that means we are not over the
|
||||||
@@ -180,10 +195,16 @@ static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr,
|
|||||||
if (msr->msc_reqbody_chunk_current == NULL) {
|
if (msr->msc_reqbody_chunk_current == NULL) {
|
||||||
msr->msc_reqbody_chunk_current = (msc_data_chunk *)
|
msr->msc_reqbody_chunk_current = (msc_data_chunk *)
|
||||||
apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
||||||
if (msr->msc_reqbody_chunk_current == NULL) return -1;
|
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);
|
msr->msc_reqbody_chunk_current->data = malloc(CHUNK_CAPACITY);
|
||||||
if (msr->msc_reqbody_chunk_current->data == NULL) return -1;
|
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->length = 0;
|
||||||
msr->msc_reqbody_chunk_current->is_permanent = 1;
|
msr->msc_reqbody_chunk_current->is_permanent = 1;
|
||||||
@@ -227,8 +248,10 @@ static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr,
|
|||||||
* Stores one chunk of request body data. Returns -1 on error.
|
* Stores one chunk of request body data. Returns -1 on error.
|
||||||
*/
|
*/
|
||||||
apr_status_t modsecurity_request_body_store(modsec_rec *msr,
|
apr_status_t modsecurity_request_body_store(modsec_rec *msr,
|
||||||
const char *data, apr_size_t length)
|
const char *data, apr_size_t length, char **error_msg)
|
||||||
{
|
{
|
||||||
|
*error_msg = NULL;
|
||||||
|
|
||||||
/* If we have a processor for this request body send
|
/* If we have a processor for this request body send
|
||||||
* data to it first (but only if it did not report an
|
* data to it first (but only if it did not report an
|
||||||
* error on previous invocations).
|
* error on previous invocations).
|
||||||
@@ -237,43 +260,61 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr,
|
|||||||
char *my_error_msg = NULL;
|
char *my_error_msg = NULL;
|
||||||
|
|
||||||
if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
|
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) {
|
if (multipart_process_chunk(msr, data, length, &my_error_msg) < 0) {
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Request body processor error: %s", my_error_msg);
|
||||||
msr->msc_reqbody_error = 1;
|
msr->msc_reqbody_error = 1;
|
||||||
msr->msc_reqbody_error_msg = my_error_msg;
|
msr->msc_reqbody_error_msg = my_error_msg;
|
||||||
msr_log(msr, 4, "%s", my_error_msg);
|
msr_log(msr, 2, "Request body processor error: %s", my_error_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef WITH_LIBXML2
|
|
||||||
else
|
else
|
||||||
if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
|
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) {
|
if (xml_process_chunk(msr, data, length, &my_error_msg) < 0) {
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Request body processor error: %s", my_error_msg);
|
||||||
msr->msc_reqbody_error = 1;
|
msr->msc_reqbody_error = 1;
|
||||||
msr->msc_reqbody_error_msg = my_error_msg;
|
msr->msc_reqbody_error_msg = my_error_msg;
|
||||||
msr_log(msr, 4, "%s", my_error_msg);
|
msr_log(msr, 2, "Request body processor error: %s", my_error_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
else
|
else
|
||||||
if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
||||||
/* Do nothing, URLENCODED processor does not support streaming. */
|
/* Increase per-request data length counter. */
|
||||||
|
msr->msc_reqbody_no_files_length += length;
|
||||||
|
|
||||||
|
/* Do nothing else, URLENCODED processor does not support streaming. */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
msr_log(msr, 1, "Unknown request body processor: %s", msr->msc_reqbody_processor);
|
*error_msg = apr_psprintf(msr->mp, "Unknown request body processor: %s",
|
||||||
|
msr->msc_reqbody_processor);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check that we are not over the request body no files limit. */
|
||||||
|
if (msr->msc_reqbody_no_files_length >= (unsigned long) msr->txcfg->reqbody_no_files_limit) {
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
|
||||||
/* Store data. */
|
/* Store data. */
|
||||||
if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
||||||
return modsecurity_request_body_store_memory(msr, data, length);
|
return modsecurity_request_body_store_memory(msr, data, length, error_msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
||||||
return modsecurity_request_body_store_disk(msr, data, length);
|
return modsecurity_request_body_store_disk(msr, data, length, error_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Should never happen. */
|
/* Should never happen. */
|
||||||
msr_log(msr, 1, "Internal Error: Unknown value for msc_reqbody_storage: %i",
|
*error_msg = apr_psprintf(msr->mp, "Internal error, unknown value for msc_reqbody_storage: %u",
|
||||||
msr->msc_reqbody_storage);
|
msr->msc_reqbody_storage);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -281,18 +322,23 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr,
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr) {
|
static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr, char **error_msg) {
|
||||||
msc_data_chunk **chunks, *one_chunk;
|
msc_data_chunk **chunks, *one_chunk;
|
||||||
char *d;
|
char *d;
|
||||||
int i, sofar;
|
int i, sofar;
|
||||||
int invalid_count = 0;
|
int invalid_count = 0;
|
||||||
|
|
||||||
|
*error_msg = NULL;
|
||||||
|
|
||||||
/* Allocate a buffer large enough to hold the request body. */
|
/* Allocate a buffer large enough to hold the request body. */
|
||||||
|
|
||||||
if (msr->msc_reqbody_length + 1 == 0) return -1;
|
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);
|
msr->msc_reqbody_buffer = malloc(msr->msc_reqbody_length + 1);
|
||||||
if (msr->msc_reqbody_buffer == NULL) {
|
if (msr->msc_reqbody_buffer == NULL) {
|
||||||
msr_log(msr, 1, "Unable to allocate memory to hold request body. Asked for %lu bytes.",
|
*error_msg = apr_psprintf(msr->mp, "Unable to allocate memory to hold request body. Asked for %u bytes.",
|
||||||
msr->msc_reqbody_length + 1);
|
msr->msc_reqbody_length + 1);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -309,7 +355,7 @@ static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr) {
|
|||||||
d += chunks[i]->length;
|
d += chunks[i]->length;
|
||||||
sofar += chunks[i]->length;
|
sofar += chunks[i]->length;
|
||||||
} else {
|
} else {
|
||||||
msr_log(msr, 1, "Internal error, request body buffer overflow.");
|
*error_msg = apr_psprintf(msr->mp, "Internal error, request body buffer overflow.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,7 +371,10 @@ static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr) {
|
|||||||
/* Create a new array with only one chunk in it. */
|
/* 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 *));
|
msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp, 2, sizeof(msc_data_chunk *));
|
||||||
if (msr->msc_reqbody_chunks == NULL) return -1;
|
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 = (msc_data_chunk *)apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
||||||
one_chunk->data = msr->msc_reqbody_buffer;
|
one_chunk->data = msr->msc_reqbody_buffer;
|
||||||
one_chunk->length = msr->msc_reqbody_length;
|
one_chunk->length = msr->msc_reqbody_length;
|
||||||
@@ -337,7 +386,7 @@ static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr) {
|
|||||||
if (parse_arguments(msr, msr->msc_reqbody_buffer, msr->msc_reqbody_length,
|
if (parse_arguments(msr, msr->msc_reqbody_buffer, msr->msc_reqbody_length,
|
||||||
msr->txcfg->argument_separator, "BODY", msr->arguments, &invalid_count) < 0)
|
msr->txcfg->argument_separator, "BODY", msr->arguments, &invalid_count) < 0)
|
||||||
{
|
{
|
||||||
msr_log(msr, 1, "Initialisation: Error occurred while parsing BODY arguments.");
|
*error_msg = apr_pstrdup(msr->mp, "Initialisation: Error occurred while parsing BODY arguments.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +396,8 @@ static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr) {
|
|||||||
/**
|
/**
|
||||||
* Stops receiving the request body.
|
* Stops receiving the request body.
|
||||||
*/
|
*/
|
||||||
apr_status_t modsecurity_request_body_end(modsec_rec *msr) {
|
apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) {
|
||||||
|
*error_msg = NULL;
|
||||||
|
|
||||||
/* Close open file descriptors, if any. */
|
/* Close open file descriptors, if any. */
|
||||||
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
||||||
@@ -357,31 +407,32 @@ apr_status_t modsecurity_request_body_end(modsec_rec *msr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note that we've read the body. */
|
||||||
msr->msc_reqbody_read = 1;
|
msr->msc_reqbody_read = 1;
|
||||||
|
|
||||||
|
/* Finalise body processing. */
|
||||||
if ((msr->msc_reqbody_processor != NULL)&&(msr->msc_reqbody_error == 0)) {
|
if ((msr->msc_reqbody_processor != NULL)&&(msr->msc_reqbody_error == 0)) {
|
||||||
char *my_error_msg = NULL;
|
char *my_error_msg = NULL;
|
||||||
|
|
||||||
if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
|
if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
|
||||||
if (multipart_complete(msr, &my_error_msg) < 0) {
|
if (multipart_complete(msr, &my_error_msg) < 0) {
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart error: %s", my_error_msg);
|
||||||
msr->msc_reqbody_error = 1;
|
msr->msc_reqbody_error = 1;
|
||||||
msr->msc_reqbody_error_msg = my_error_msg;
|
msr->msc_reqbody_error_msg = my_error_msg;
|
||||||
msr_log(msr, 1, "Multipart error: %s", my_error_msg);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (multipart_get_arguments(msr, "BODY", msr->arguments) < 0) {
|
if (multipart_get_arguments(msr, "BODY", msr->arguments) < 0) {
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart error: %s", my_error_msg);
|
||||||
msr->msc_reqbody_error = 1;
|
msr->msc_reqbody_error = 1;
|
||||||
msr->msc_reqbody_error_msg = "Error retrieving arguments.";
|
msr->msc_reqbody_error_msg = "Error retrieving arguments.";
|
||||||
msr_log(msr, 1, "Multipart error: %s", my_error_msg);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
||||||
return modsecurity_request_body_end_urlencoded(msr);
|
return modsecurity_request_body_end_urlencoded(msr, error_msg);
|
||||||
}
|
}
|
||||||
#ifdef WITH_LIBXML2
|
|
||||||
else
|
else
|
||||||
if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
|
if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
|
||||||
if (xml_complete(msr, &my_error_msg) < 0) {
|
if (xml_complete(msr, &my_error_msg) < 0) {
|
||||||
@@ -391,36 +442,49 @@ apr_status_t modsecurity_request_body_end(modsec_rec *msr) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note the request body no files length. */
|
||||||
|
msr_log(msr, 4, "Reqest body no files length: %" APR_SIZE_T_FMT, msr->msc_reqbody_no_files_length);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares to forward the request body.
|
* Prepares to forward the request body.
|
||||||
*/
|
*/
|
||||||
apr_status_t modsecurity_request_body_retrieve_start(modsec_rec *msr) {
|
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) {
|
if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
||||||
msr->msc_reqbody_chunk_position = 0;
|
msr->msc_reqbody_chunk_position = 0;
|
||||||
msr->msc_reqbody_chunk_offset = 0;
|
msr->msc_reqbody_chunk_offset = 0;
|
||||||
|
|
||||||
msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
||||||
if (msr->msc_reqbody_disk_chunk == NULL) return -1;
|
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;
|
msr->msc_reqbody_disk_chunk->is_permanent = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
||||||
msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
||||||
if (msr->msc_reqbody_disk_chunk == NULL) return -1;
|
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->is_permanent = 0;
|
||||||
msr->msc_reqbody_disk_chunk->data = apr_palloc(msr->msc_reqbody_mp, CHUNK_CAPACITY);
|
msr->msc_reqbody_disk_chunk->data = apr_palloc(msr->msc_reqbody_mp, CHUNK_CAPACITY);
|
||||||
if (msr->msc_reqbody_disk_chunk->data == NULL) return -1;
|
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);
|
msr->msc_reqbody_fd = open(msr->msc_reqbody_filename, O_RDONLY | O_BINARY);
|
||||||
if (msr->msc_reqbody_fd < 0) {
|
if (msr->msc_reqbody_fd < 0) {
|
||||||
msr_log(msr, 1, "Input filter: Failed to open temporary file for reading: %s",
|
*error_msg = apr_psprintf(msr->mp, "Failed to open temporary file for reading: %s",
|
||||||
msr->msc_reqbody_filename);
|
msr->msc_reqbody_filename);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -453,11 +517,16 @@ apr_status_t modsecurity_request_body_retrieve_end(modsec_rec *msr) {
|
|||||||
* a non-negative value in nbytes.
|
* a non-negative value in nbytes.
|
||||||
*/
|
*/
|
||||||
apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr,
|
apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr,
|
||||||
msc_data_chunk **chunk, long int nbytes)
|
msc_data_chunk **chunk, long int nbytes, char **error_msg)
|
||||||
{
|
{
|
||||||
msc_data_chunk **chunks;
|
msc_data_chunk **chunks;
|
||||||
|
|
||||||
if (chunk == NULL) return -1;
|
*error_msg = NULL;
|
||||||
|
|
||||||
|
if (chunk == NULL) {
|
||||||
|
*error_msg = apr_pstrdup(msr->mp, "Internal error, retrieving request body chunk.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
*chunk = NULL;
|
*chunk = NULL;
|
||||||
|
|
||||||
if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
||||||
@@ -527,7 +596,7 @@ apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr,
|
|||||||
|
|
||||||
i = read(msr->msc_reqbody_fd, msr->msc_reqbody_disk_chunk->data, my_nbytes);
|
i = read(msr->msc_reqbody_fd, msr->msc_reqbody_disk_chunk->data, my_nbytes);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
msr_log(msr, 1, "Input filter: Error reading from temporary file: %s",
|
*error_msg = apr_psprintf(msr->mp, "Input filter: Error reading from temporary file: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -540,7 +609,8 @@ apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr,
|
|||||||
return 1; /* More data available. */
|
return 1; /* More data available. */
|
||||||
}
|
}
|
||||||
|
|
||||||
msr_log(msr, 1, "Internal error, invalid msc_reqbody_storage value: %i",
|
/* Should never happen. */
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Internal error, invalid msc_reqbody_storage value: %u",
|
||||||
msr->msc_reqbody_storage);
|
msr->msc_reqbody_storage);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@@ -549,7 +619,9 @@ apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr,
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
apr_status_t modsecurity_request_body_clear(modsec_rec *msr) {
|
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. */
|
/* Release memory we used to store request body data. */
|
||||||
if (msr->msc_reqbody_chunks != NULL) {
|
if (msr->msc_reqbody_chunks != NULL) {
|
||||||
msc_data_chunk **chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
msc_data_chunk **chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
||||||
@@ -574,7 +646,7 @@ apr_status_t modsecurity_request_body_clear(modsec_rec *msr) {
|
|||||||
if (msr->txcfg->upload_dir != NULL) {
|
if (msr->txcfg->upload_dir != NULL) {
|
||||||
keep_body = 1;
|
keep_body = 1;
|
||||||
} else {
|
} else {
|
||||||
msr_log(msr, 1, "Input filter: SecUploadDir is undefined, "
|
*error_msg = apr_psprintf(msr->mp, "Input filter: SecUploadDir is undefined, "
|
||||||
"unable to store PUT file.");
|
"unable to store PUT file.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -589,20 +661,26 @@ apr_status_t modsecurity_request_body_clear(modsec_rec *msr) {
|
|||||||
|
|
||||||
/* Construct the new filename. */
|
/* Construct the new filename. */
|
||||||
put_basename = file_basename(msr->msc_reqbody_mp, msr->msc_reqbody_filename);
|
put_basename = file_basename(msr->msc_reqbody_mp, msr->msc_reqbody_filename);
|
||||||
if (put_basename == NULL) return -1;
|
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",
|
put_filename = apr_psprintf(msr->msc_reqbody_mp, "%s/%s",
|
||||||
msr->txcfg->upload_dir, put_basename);
|
msr->txcfg->upload_dir, put_basename);
|
||||||
if (put_filename == NULL) return -1;
|
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,
|
if (apr_file_rename(msr->msc_reqbody_filename, put_filename,
|
||||||
msr->msc_reqbody_mp) != APR_SUCCESS)
|
msr->msc_reqbody_mp) != APR_SUCCESS)
|
||||||
{
|
{
|
||||||
msr_log(msr, 1, "Failed to rename file from \"%s\" to \"%s\".",
|
*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, msr->msc_reqbody_filename),
|
||||||
log_escape(msr->msc_reqbody_mp, put_filename));
|
log_escape(msr->msc_reqbody_mp, put_filename));
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
msr_log(msr, 4, "Moved file from \"%s\" to \"%s\".",
|
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, msr->msc_reqbody_filename),
|
||||||
log_escape(msr->msc_reqbody_mp, put_filename));
|
log_escape(msr->msc_reqbody_mp, put_filename));
|
||||||
}
|
}
|
||||||
@@ -611,8 +689,8 @@ apr_status_t modsecurity_request_body_clear(modsec_rec *msr) {
|
|||||||
if (apr_file_remove(msr->msc_reqbody_filename,
|
if (apr_file_remove(msr->msc_reqbody_filename,
|
||||||
msr->msc_reqbody_mp) != APR_SUCCESS)
|
msr->msc_reqbody_mp) != APR_SUCCESS)
|
||||||
{
|
{
|
||||||
msr_log(msr, 1, "Failed to delete temporary file: %s",
|
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to delete temporary file: %s",
|
||||||
msr->msc_reqbody_filename);
|
log_escape(msr->mp, msr->msc_reqbody_filename));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,11 +702,10 @@ apr_status_t modsecurity_request_body_clear(modsec_rec *msr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE No need to clear the pool as it has already been destroyed
|
if (msr->msc_reqbody_mp != NULL) {
|
||||||
* if (msr->msc_reqbody_mp != NULL) {
|
apr_pool_destroy(msr->msc_reqbody_mp);
|
||||||
* apr_pool_clear(msr->msc_reqbody_mp);
|
msr->msc_reqbody_mp = NULL;
|
||||||
* }
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
475
apache2/msc_test.c
Normal file
475
apache2/msc_test.c
Normal file
@@ -0,0 +1,475 @@
|
|||||||
|
/*
|
||||||
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
|
*
|
||||||
|
* You should have received a copy of the licence along with this
|
||||||
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
|
* or if you have any other questions related to the licence, please
|
||||||
|
* write to Breach Security, Inc. at support@breach.com.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <apr.h>
|
||||||
|
|
||||||
|
#include "modsecurity.h"
|
||||||
|
#include "re.h"
|
||||||
|
#include "pdf_protect.h"
|
||||||
|
|
||||||
|
#define ISHEX(X) (((X >= '0')&&(X <= '9')) || ((X >= 'a')&&(X <= 'f')) || ((X >= 'A')&&(X <= 'F')))
|
||||||
|
|
||||||
|
#define BUFLEN 8192
|
||||||
|
|
||||||
|
#define RESULT_SUCCESS 0
|
||||||
|
#define RESULT_ERROR -1
|
||||||
|
#define RESULT_MISMATCHED -2
|
||||||
|
#define RESULT_WRONGSIZE -3
|
||||||
|
#define RESULT_WRONGRET -4
|
||||||
|
|
||||||
|
/* Globals */
|
||||||
|
static char *test_name = NULL;
|
||||||
|
static apr_pool_t *g_mp = NULL;
|
||||||
|
static modsec_rec *g_msr = NULL;
|
||||||
|
msc_engine *modsecurity = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/* Stubs */
|
||||||
|
char *format_error_log_message(apr_pool_t *mp, error_message *em) {
|
||||||
|
return "FAKE ERROR LOG MESSAGE";
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_status_t send_error_bucket(modsec_rec *msr, ap_filter_t *f, int status) {
|
||||||
|
return APR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int apache2_exec(modsec_rec *msr, const char *command, const char **argv, char **output) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *get_apr_error(apr_pool_t *p, apr_status_t rc) {
|
||||||
|
return "FAKE APR ERROR";
|
||||||
|
}
|
||||||
|
|
||||||
|
void msr_log(modsec_rec *msr, int level, const char *text, ...) {
|
||||||
|
va_list ap;
|
||||||
|
char str1[1024] = "";
|
||||||
|
char str2[1256] = "";
|
||||||
|
|
||||||
|
if ((msr == NULL) || (level > msr->txcfg->debuglog_level)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (msr->txcfg->debuglog_fd == NOT_SET_P) {
|
||||||
|
if (apr_file_open(&msr->txcfg->debuglog_fd, msr->txcfg->debuglog_name, APR_READ|APR_WRITE|APR_CREATE|APR_APPEND|APR_BINARY, APR_OS_DEFAULT, g_mp) != APR_SUCCESS) {
|
||||||
|
fprintf(stderr, "ERROR: failed to create unit test debug log \"%s\".\n", msr->txcfg->debuglog_name);
|
||||||
|
msr->txcfg->debuglog_fd = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start(ap, text);
|
||||||
|
if (msr->txcfg->debuglog_fd != NULL) {
|
||||||
|
apr_size_t nbytes_written = 0;
|
||||||
|
apr_vsnprintf(str1, sizeof(str1), text, ap);
|
||||||
|
apr_snprintf(str2, sizeof(str2), "[%d] [%s] %s\n", level, test_name, str1);
|
||||||
|
|
||||||
|
apr_file_write_full(msr->txcfg->debuglog_fd, str2, strlen(str2), &nbytes_written);
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ap_get_remote_host(conn_rec *conn, void *dir_config, int type, int *str_is_ip) {
|
||||||
|
return "FAKE-REMOTE-HOST";
|
||||||
|
}
|
||||||
|
|
||||||
|
char *get_env_var(request_rec *r, char *name) {
|
||||||
|
return "FAKE-ENV-VAR";
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_status_t unixd_set_global_mutex_perms(apr_global_mutex_t *gmutex) {
|
||||||
|
return APR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_status_t unixd_set_proc_mutex_perms(apr_proc_mutex_t *pmutex) {
|
||||||
|
return APR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Escaping functions */
|
||||||
|
|
||||||
|
static unsigned char hex2dec(unsigned char *what) {
|
||||||
|
register unsigned char digit;
|
||||||
|
|
||||||
|
digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
|
||||||
|
digit *= 16;
|
||||||
|
digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
|
||||||
|
|
||||||
|
return digit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char *unescape_inplace(unsigned char *str, apr_size_t *len)
|
||||||
|
{
|
||||||
|
apr_size_t i, j;
|
||||||
|
for (i = j = 0; i < *len; j++) {
|
||||||
|
if ((str[i] == '\\') && (i + 3 < *len) && (str[i + 1] == 'x') && ISHEX(str[i + 2]) && ISHEX(str[i + 3]) ) {
|
||||||
|
str[j] = hex2dec(str + i + 2);
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
str[j] = str[i++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*len = j;
|
||||||
|
|
||||||
|
while (j < i) {
|
||||||
|
str[j++] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *escape(unsigned char *str, apr_size_t *len)
|
||||||
|
{
|
||||||
|
char *new = apr_pcalloc(g_mp, (*len * 4) + 1);
|
||||||
|
apr_size_t i, j;
|
||||||
|
for (i = j = 0; i < *len; i++) {
|
||||||
|
if ((str[i] >= 0x20) && (str[i] <= 0x7e)) {
|
||||||
|
new[j++] = str[i];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sprintf(new + j, "\\x%02x", str[i]);
|
||||||
|
j += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*len = j;
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Testing functions */
|
||||||
|
|
||||||
|
static int test_tfn(const char *name, unsigned char *input, apr_size_t input_len, unsigned char **rval, apr_size_t *rval_len, char **errmsg)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
msre_tfn_metadata *metadata = NULL;
|
||||||
|
|
||||||
|
*errmsg = NULL;
|
||||||
|
|
||||||
|
/* Lookup the tfn */
|
||||||
|
metadata = msre_engine_tfn_resolve(modsecurity->msre, name);
|
||||||
|
|
||||||
|
if (metadata == NULL) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to fetch tfn \"%s\".", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Execute the tfn */
|
||||||
|
rc = metadata->execute(g_mp, input, (long)input_len, (char **)rval, (long *)rval_len);
|
||||||
|
if (rc < 0) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to execute tfn \"%s\".", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_op(const char *name, const char *param, const unsigned char *input, apr_size_t input_len, char **errmsg)
|
||||||
|
{
|
||||||
|
const char *args = apr_psprintf(g_mp, "@%s %s", name, param);
|
||||||
|
char *conf_fn;
|
||||||
|
msre_ruleset *ruleset = NULL;
|
||||||
|
msre_rule *rule = NULL;
|
||||||
|
msre_var *var = NULL;
|
||||||
|
msre_op_metadata *metadata = NULL;
|
||||||
|
int rc = -1;
|
||||||
|
|
||||||
|
*errmsg = NULL;
|
||||||
|
|
||||||
|
if ( apr_filepath_merge(&conf_fn, NULL, "t/unit-test.conf", APR_FILEPATH_TRUENAME, g_mp) != APR_SUCCESS) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to build a conf filename.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register UNIT_TEST variable */
|
||||||
|
msre_engine_variable_register(modsecurity->msre,
|
||||||
|
"UNIT_TEST",
|
||||||
|
VAR_SIMPLE,
|
||||||
|
0, 0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
VAR_DONT_CACHE,
|
||||||
|
PHASE_REQUEST_HEADERS
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Lookup the operator */
|
||||||
|
metadata = msre_engine_op_resolve(modsecurity->msre, name);
|
||||||
|
if (metadata == NULL) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to fetch op \"%s\".", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a ruleset/rule */
|
||||||
|
ruleset = msre_ruleset_create(modsecurity->msre, g_mp);
|
||||||
|
if (ruleset == NULL) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to create ruleset for op \"%s\".", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
rule = msre_rule_create(ruleset, RULE_TYPE_NORMAL, conf_fn, 1, "UNIT_TEST", args, "t:none,pass,nolog", errmsg);
|
||||||
|
if (rule == NULL) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to create rule for op \"%s\": %s", name, *errmsg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a fake variable */
|
||||||
|
var = (msre_var *)apr_pcalloc(g_mp, sizeof(msre_var));
|
||||||
|
var->name = "UNIT_TEST";
|
||||||
|
var->value = apr_pstrmemdup(g_mp, (char *)input, input_len);
|
||||||
|
var->value_len = input_len;
|
||||||
|
var->metadata = msre_resolve_var(modsecurity->msre, var->name);
|
||||||
|
if (var->metadata == NULL) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to resolve variable for op \"%s\": %s", name, var->name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the operator parameter */
|
||||||
|
if (metadata->param_init != NULL) {
|
||||||
|
rc = metadata->param_init(rule, errmsg);
|
||||||
|
if (rc <= 0) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to init op \"%s\": %s", name, *errmsg);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Execute the operator */
|
||||||
|
if (metadata->execute != NULL) {
|
||||||
|
rc = metadata->execute(g_msr, rule, var, errmsg);
|
||||||
|
if (rc < 0) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to execute op \"%s\": %s", name, *errmsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Initialization */
|
||||||
|
static void init_msr() {
|
||||||
|
directory_config *dcfg = NULL;
|
||||||
|
request_rec *r = NULL;
|
||||||
|
r = (request_rec *)apr_pcalloc(g_mp, sizeof(request_rec));
|
||||||
|
|
||||||
|
dcfg = (directory_config *)apr_pcalloc(g_mp, sizeof(directory_config));
|
||||||
|
dcfg->is_enabled = 0;
|
||||||
|
dcfg->reqbody_access = 0;
|
||||||
|
dcfg->reqbody_inmemory_limit = REQUEST_BODY_DEFAULT_INMEMORY_LIMIT;
|
||||||
|
dcfg->reqbody_limit = REQUEST_BODY_DEFAULT_LIMIT;
|
||||||
|
dcfg->reqbody_no_files_limit = REQUEST_BODY_NO_FILES_DEFAULT_LIMIT;
|
||||||
|
dcfg->resbody_access = 0;
|
||||||
|
dcfg->of_limit = RESPONSE_BODY_DEFAULT_LIMIT;
|
||||||
|
dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
|
||||||
|
dcfg->debuglog_fd = NOT_SET_P;
|
||||||
|
dcfg->debuglog_name = "msc-test-debug.log";
|
||||||
|
dcfg->debuglog_level = 9;
|
||||||
|
dcfg->cookie_format = 0;
|
||||||
|
dcfg->argument_separator = '&';
|
||||||
|
dcfg->rule_inheritance = 0;
|
||||||
|
dcfg->auditlog_flag = 0;
|
||||||
|
dcfg->auditlog_type = AUDITLOG_SERIAL;
|
||||||
|
dcfg->auditlog_fd = NULL;
|
||||||
|
dcfg->auditlog2_fd = NULL;
|
||||||
|
dcfg->auditlog_name = NULL;
|
||||||
|
dcfg->auditlog2_name = NULL;
|
||||||
|
dcfg->auditlog_storage_dir = NULL;
|
||||||
|
dcfg->auditlog_parts = "ABCFHZ";
|
||||||
|
dcfg->auditlog_relevant_regex = NULL;
|
||||||
|
dcfg->tmp_dir = guess_tmp_dir(g_mp);
|
||||||
|
dcfg->upload_dir = NULL;
|
||||||
|
dcfg->upload_keep_files = KEEP_FILES_OFF;
|
||||||
|
dcfg->upload_validates_files = 0;
|
||||||
|
dcfg->data_dir = NULL;
|
||||||
|
dcfg->webappid = "default";
|
||||||
|
dcfg->content_injection_enabled = 0;
|
||||||
|
dcfg->pdfp_enabled = 0;
|
||||||
|
dcfg->pdfp_secret = NULL;
|
||||||
|
dcfg->pdfp_timeout = 10;
|
||||||
|
dcfg->pdfp_token_name = "PDFPTOKEN";
|
||||||
|
dcfg->pdfp_only_get = 1;
|
||||||
|
dcfg->pdfp_method = PDF_PROTECT_METHOD_TOKEN_REDIRECTION;
|
||||||
|
dcfg->geo = NULL;
|
||||||
|
dcfg->cache_trans = MODSEC_CACHE_ENABLED;
|
||||||
|
dcfg->cache_trans_min = 15;
|
||||||
|
dcfg->cache_trans_max = 0;
|
||||||
|
dcfg->request_encoding = NULL;
|
||||||
|
|
||||||
|
g_msr = (modsec_rec *)apr_pcalloc(g_mp, sizeof(modsec_rec));
|
||||||
|
g_msr->modsecurity = modsecurity;
|
||||||
|
g_msr->mp = g_mp;
|
||||||
|
g_msr->r = r;
|
||||||
|
g_msr->r_early = r;
|
||||||
|
g_msr->request_time = apr_time_now();
|
||||||
|
g_msr->dcfg1 = NULL;
|
||||||
|
g_msr->usercfg = NULL;
|
||||||
|
g_msr->txcfg = dcfg;
|
||||||
|
g_msr->txid = "FAKE-TXID";
|
||||||
|
g_msr->error_messages = NULL;
|
||||||
|
g_msr->alerts = NULL;
|
||||||
|
g_msr->server_software = "FAKE-SERVER-SOFTWARE";
|
||||||
|
g_msr->local_addr = "127.0.0.1";
|
||||||
|
g_msr->local_port = 80;
|
||||||
|
g_msr->remote_addr = "127.0.0.1";
|
||||||
|
g_msr->remote_port = 1080;
|
||||||
|
g_msr->request_line = "GET /unit-tests HTTP/1.1";
|
||||||
|
g_msr->request_uri = "http://localhost/unit-tests";
|
||||||
|
g_msr->request_method = "GET";
|
||||||
|
g_msr->query_string = "";
|
||||||
|
g_msr->request_protocol = "HTTP/1.1";
|
||||||
|
g_msr->request_headers = NULL;
|
||||||
|
g_msr->hostname = "localhost";
|
||||||
|
g_msr->msc_rule_mptmp = g_mp;
|
||||||
|
g_msr->tx_vars = apr_table_make(g_mp, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Main */
|
||||||
|
|
||||||
|
int main(int argc, const char * const argv[])
|
||||||
|
{
|
||||||
|
apr_file_t *fd;
|
||||||
|
unsigned char buf[BUFLEN];
|
||||||
|
apr_size_t nbytes = BUFLEN;
|
||||||
|
unsigned char input[BUFLEN];
|
||||||
|
const char *type = NULL;
|
||||||
|
const char *name = NULL;
|
||||||
|
unsigned char *param = NULL;
|
||||||
|
const char *returnval = NULL;
|
||||||
|
char *errmsg = NULL;
|
||||||
|
unsigned char *out = NULL;
|
||||||
|
apr_size_t input_len = 0;
|
||||||
|
apr_size_t param_len = 0;
|
||||||
|
apr_size_t out_len = 0;
|
||||||
|
int rc = 0;
|
||||||
|
int result = 0;
|
||||||
|
int ec = 0;
|
||||||
|
|
||||||
|
apr_app_initialize(&argc, &argv, NULL);
|
||||||
|
atexit(apr_terminate);
|
||||||
|
|
||||||
|
if (argc < 4) {
|
||||||
|
fprintf(stderr, "Usage: %s <type> <name> <param> [<returnval>]\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_pool_create(&g_mp, NULL);
|
||||||
|
modsecurity = modsecurity_create(g_mp, MODSEC_OFFLINE);
|
||||||
|
|
||||||
|
type = argv[1];
|
||||||
|
name = argv[2];
|
||||||
|
param_len = strlen(argv[3]);
|
||||||
|
param = apr_pmemdup(g_mp, argv[3], param_len + 1);
|
||||||
|
unescape_inplace(param, ¶m_len);
|
||||||
|
if (argc >= 5) {
|
||||||
|
returnval = argv[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
test_name = apr_psprintf(g_mp, "%s/%s", type, name);
|
||||||
|
|
||||||
|
if (apr_file_open_stdin(&fd, g_mp) != APR_SUCCESS) {
|
||||||
|
fprintf(stderr, "Failed to open stdin\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buf, 0, BUFLEN);
|
||||||
|
rc = apr_file_read(fd, buf, &nbytes);
|
||||||
|
if ((rc != APR_EOF) && (rc != APR_SUCCESS)) {
|
||||||
|
fprintf(stderr, "Failed to read data\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbytes < 0) {
|
||||||
|
fprintf(stderr, "Error reading data\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_file_close(fd);
|
||||||
|
|
||||||
|
/* Make a copy as transformations are done in-place */
|
||||||
|
memcpy(input, buf, BUFLEN);
|
||||||
|
input_len = nbytes;
|
||||||
|
|
||||||
|
if (strcmp("tfn", type) == 0) {
|
||||||
|
/* Transformations */
|
||||||
|
int ret = returnval ? atoi(returnval) : -8888;
|
||||||
|
rc = test_tfn(name, input, input_len, &out, &out_len, &errmsg);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "ERROR: %s\n", errmsg);
|
||||||
|
result = RESULT_ERROR;
|
||||||
|
}
|
||||||
|
else if ((ret != -8888) && (rc != ret)) {
|
||||||
|
fprintf(stderr, "Returned %d (expected %d)\n", rc, ret);
|
||||||
|
result = RESULT_WRONGRET;
|
||||||
|
}
|
||||||
|
else if (param_len != out_len) {
|
||||||
|
fprintf(stderr, "Lenth %" APR_SIZE_T_FMT " (expected %" APR_SIZE_T_FMT ")\n", out_len, param_len);
|
||||||
|
result = RESULT_WRONGSIZE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = memcmp(param, out, param_len) ? RESULT_MISMATCHED : RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != RESULT_SUCCESS) {
|
||||||
|
apr_size_t s0len = nbytes;
|
||||||
|
const char *s0 = escape(buf, &s0len);
|
||||||
|
apr_size_t s1len = out_len;
|
||||||
|
const char *s1 = escape(out, &s1len);
|
||||||
|
apr_size_t s2len = param_len;
|
||||||
|
const char *s2 = escape(param, &s2len);
|
||||||
|
|
||||||
|
fprintf(stderr, " Input: '%s' len=%" APR_SIZE_T_FMT "\n"
|
||||||
|
"Output: '%s' len=%" APR_SIZE_T_FMT "\n"
|
||||||
|
"Expect: '%s' len=%" APR_SIZE_T_FMT "\n",
|
||||||
|
s0, nbytes, s1, out_len, s2, param_len);
|
||||||
|
ec = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp("op", type) == 0) {
|
||||||
|
/* Operators */
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!returnval) {
|
||||||
|
fprintf(stderr, "Return value required for type \"%s\"\n", type);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ret = atoi(returnval);
|
||||||
|
|
||||||
|
init_msr();
|
||||||
|
|
||||||
|
rc = test_op(name, (const char *)param, (const unsigned char *)input, input_len, &errmsg);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "ERROR: %s\n", errmsg);
|
||||||
|
result = RESULT_ERROR;
|
||||||
|
}
|
||||||
|
else if (rc != ret) {
|
||||||
|
fprintf(stderr, "Returned %d (expected %d)\n", rc, ret);
|
||||||
|
result = RESULT_WRONGRET;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != RESULT_SUCCESS) {
|
||||||
|
apr_size_t s0len = nbytes;
|
||||||
|
const char *s0 = escape(buf, &s0len);
|
||||||
|
|
||||||
|
fprintf(stderr, " Test: '@%s %s'\n"
|
||||||
|
"Input: '%s' len=%" APR_SIZE_T_FMT "\n",
|
||||||
|
name, param, s0, nbytes);
|
||||||
|
ec = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Unknown type: \"%s\"\n", type);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stdout, "%s\n", errmsg ? errmsg : "");
|
||||||
|
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -16,6 +16,15 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <apr_lib.h>
|
||||||
|
|
||||||
|
/* NOTE: Be careful as these can ONLY be used on static values for X.
|
||||||
|
* (i.e. VALID_HEX(c++) will NOT work)
|
||||||
|
*/
|
||||||
|
#define VALID_HEX(X) (((X >= '0')&&(X <= '9')) || ((X >= 'a')&&(X <= 'f')) || ((X >= 'A')&&(X <= 'F')))
|
||||||
|
#define ISODIGIT(X) ((X >= '0')&&(X <= '7'))
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -63,11 +72,14 @@ int parse_name_eq_value(apr_pool_t *mp, const char *input, char **name, char **v
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
* IMP1 Assumes NUL-terminated
|
||||||
*/
|
*/
|
||||||
char *url_encode(apr_pool_t *mp, char *input, unsigned int input_len) {
|
char *url_encode(apr_pool_t *mp, char *input, unsigned int input_len, int *changed) {
|
||||||
char *rval, *d;
|
char *rval, *d;
|
||||||
unsigned int i, len;
|
unsigned int i, len;
|
||||||
|
|
||||||
|
*changed = 0;
|
||||||
|
|
||||||
len = input_len * 3 + 1;
|
len = input_len * 3 + 1;
|
||||||
d = rval = apr_palloc(mp, len);
|
d = rval = apr_palloc(mp, len);
|
||||||
if (rval == NULL) return NULL;
|
if (rval == NULL) return NULL;
|
||||||
@@ -79,6 +91,7 @@ char *url_encode(apr_pool_t *mp, char *input, unsigned int input_len) {
|
|||||||
|
|
||||||
if (c == ' ') {
|
if (c == ' ') {
|
||||||
*d++ = '+';
|
*d++ = '+';
|
||||||
|
*changed = 1;
|
||||||
} else
|
} else
|
||||||
if ( (c == 42) || ((c >= 48)&&(c <= 57)) || ((c >= 65)&&(c <= 90))
|
if ( (c == 42) || ((c >= 48)&&(c <= 57)) || ((c >= 65)&&(c <= 90))
|
||||||
|| ((c >= 97)&&(c <= 122))
|
|| ((c >= 97)&&(c <= 122))
|
||||||
@@ -88,6 +101,7 @@ char *url_encode(apr_pool_t *mp, char *input, unsigned int input_len) {
|
|||||||
*d++ = '%';
|
*d++ = '%';
|
||||||
c2x(c, (unsigned char *)d);
|
c2x(c, (unsigned char *)d);
|
||||||
d += 2;
|
d += 2;
|
||||||
|
*changed = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,13 +464,43 @@ char *log_escape_raw(apr_pool_t *mp, const unsigned char *text, unsigned long in
|
|||||||
unsigned long int i, j;
|
unsigned long int i, j;
|
||||||
|
|
||||||
for (i = 0, j = 0; i < text_length; i++, j += 4) {
|
for (i = 0, j = 0; i < text_length; i++, j += 4) {
|
||||||
apr_snprintf((char *)ret+j, 5, "\\x%02x", text[i]);
|
ret[j] = '\\';
|
||||||
|
ret[j+1] = 'x';
|
||||||
|
c2x(text[i], ret+j+2);
|
||||||
}
|
}
|
||||||
ret[text_length * 4] = '\0';
|
ret[text_length * 4] = '\0';
|
||||||
|
|
||||||
return (char *)ret;
|
return (char *)ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform text to ASCII printable or hex escaped
|
||||||
|
*/
|
||||||
|
char *log_escape_hex(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length) {
|
||||||
|
unsigned char *ret = apr_palloc(mp, text_length * 4 + 1);
|
||||||
|
unsigned long int i, j;
|
||||||
|
|
||||||
|
for (i = 0, j = 0; i < text_length; i++) {
|
||||||
|
if ( (text[i] == '"')
|
||||||
|
||(text[i] == '\\')
|
||||||
|
||(text[i] <= 0x1f)
|
||||||
|
||(text[i] >= 0x7f))
|
||||||
|
{
|
||||||
|
ret[j] = '\\';
|
||||||
|
ret[j+1] = 'x';
|
||||||
|
c2x(text[i], ret+j+2);
|
||||||
|
j += 4;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret[j] = text[i];
|
||||||
|
j ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret[j] = '\0';
|
||||||
|
|
||||||
|
return (char *)ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform input into a form safe for logging.
|
* Transform input into a form safe for logging.
|
||||||
*/
|
*/
|
||||||
@@ -536,15 +580,136 @@ char *_log_escape(apr_pool_t *mp, const unsigned char *input, unsigned long int
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define VALID_HEX(X) (((X >= '0')&&(X <= '9')) || ((X >= 'a')&&(X <= 'f')) || ((X >= 'A')&&(X <= 'F')))
|
/**
|
||||||
|
* JavaScript decoding.
|
||||||
|
* IMP1 Assumes NUL-terminated
|
||||||
|
*/
|
||||||
|
|
||||||
|
int js_decode_nonstrict_inplace(unsigned char *input, long int input_len) {
|
||||||
|
unsigned char *d = (unsigned char *)input;
|
||||||
|
long int i, count;
|
||||||
|
|
||||||
|
if (input == NULL) return -1;
|
||||||
|
|
||||||
|
i = count = 0;
|
||||||
|
while (i < input_len) {
|
||||||
|
if (input[i] == '\\') {
|
||||||
|
/* Character is an escape. */
|
||||||
|
|
||||||
|
if ( (i + 5 < input_len) && (input[i + 1] == 'u')
|
||||||
|
&& (VALID_HEX(input[i + 2])) && (VALID_HEX(input[i + 3]))
|
||||||
|
&& (VALID_HEX(input[i + 4])) && (VALID_HEX(input[i + 5])) )
|
||||||
|
{
|
||||||
|
/* \uHHHH */
|
||||||
|
|
||||||
|
/* Use only the lower byte. */
|
||||||
|
*d = x2c(&input[i + 4]);
|
||||||
|
|
||||||
|
/* Full width ASCII (ff01 - ff5e) needs 0x20 added */
|
||||||
|
if ( (*d > 0x00) && (*d < 0x5f)
|
||||||
|
&& ((input[i + 2] == 'f') || (input[i + 2] == 'F'))
|
||||||
|
&& ((input[i + 3] == 'f') || (input[i + 3] == 'F')))
|
||||||
|
{
|
||||||
|
(*d) += 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
d++;
|
||||||
|
count++;
|
||||||
|
i += 6;
|
||||||
|
}
|
||||||
|
else if ( (i + 3 < input_len) && (input[i + 1] == 'x')
|
||||||
|
&& VALID_HEX(input[i + 2]) && VALID_HEX(input[i + 3])) {
|
||||||
|
/* \xHH */
|
||||||
|
*d++ = x2c(&input[i + 2]);
|
||||||
|
count++;
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
else if ((i + 1 < input_len) && ISODIGIT(input[i + 1])) {
|
||||||
|
/* \OOO (only one byte, \000 - \377) */
|
||||||
|
char buf[4];
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
while((i + 1 + j < input_len)&&(j < 3)) {
|
||||||
|
buf[j] = input[i + 1 + j];
|
||||||
|
j++;
|
||||||
|
if (!ISODIGIT(input[i + 1 + j])) break;
|
||||||
|
}
|
||||||
|
buf[j] = '\0';
|
||||||
|
|
||||||
|
if (j > 0) {
|
||||||
|
/* Do not use 3 characters if we will be > 1 byte */
|
||||||
|
if ((j == 3) && (buf[0] > '3')) {
|
||||||
|
j = 2;
|
||||||
|
buf[j] = '\0';
|
||||||
|
}
|
||||||
|
*d++ = strtol(buf, NULL, 8);
|
||||||
|
i += 1 + j;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (i + 1 < input_len) {
|
||||||
|
/* \C */
|
||||||
|
unsigned char c = input[i + 1];
|
||||||
|
switch(input[i + 1]) {
|
||||||
|
case 'a' :
|
||||||
|
c = '\a';
|
||||||
|
break;
|
||||||
|
case 'b' :
|
||||||
|
c = '\b';
|
||||||
|
break;
|
||||||
|
case 'f' :
|
||||||
|
c = '\f';
|
||||||
|
break;
|
||||||
|
case 'n' :
|
||||||
|
c = '\n';
|
||||||
|
break;
|
||||||
|
case 'r' :
|
||||||
|
c = '\r';
|
||||||
|
break;
|
||||||
|
case 't' :
|
||||||
|
c = '\t';
|
||||||
|
break;
|
||||||
|
case 'v' :
|
||||||
|
c = '\v';
|
||||||
|
break;
|
||||||
|
/* The remaining (\?,\\,\',\") are just a removal
|
||||||
|
* of the escape char which is default.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
*d++ = c;
|
||||||
|
i += 2;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Not enough bytes */
|
||||||
|
while(i < input_len) {
|
||||||
|
*d++ = input[i++];
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*d++ = input[i++];
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*d = '\0';
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
* IMP1 Assumes NUL-terminated
|
||||||
*/
|
*/
|
||||||
int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len) {
|
int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len, int *changed) {
|
||||||
unsigned char *d = input;
|
unsigned char *d = input;
|
||||||
long int i, count;
|
long int i, count;
|
||||||
|
|
||||||
|
*changed = 0;
|
||||||
|
|
||||||
if (input == NULL) return -1;
|
if (input == NULL) return -1;
|
||||||
|
|
||||||
i = count = 0;
|
i = count = 0;
|
||||||
@@ -567,27 +732,24 @@ int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len)
|
|||||||
&& ((input[i + 2] == 'f') || (input[i + 2] == 'F'))
|
&& ((input[i + 2] == 'f') || (input[i + 2] == 'F'))
|
||||||
&& ((input[i + 3] == 'f') || (input[i + 3] == 'F')))
|
&& ((input[i + 3] == 'f') || (input[i + 3] == 'F')))
|
||||||
{
|
{
|
||||||
*d += 0x20;
|
(*d) += 0x20;
|
||||||
}
|
}
|
||||||
|
|
||||||
d++;
|
d++;
|
||||||
count++;
|
count++;
|
||||||
i += 6;
|
i += 6;
|
||||||
|
*changed = 1;
|
||||||
} else {
|
} else {
|
||||||
/* Invalid data. */
|
/* Invalid data, skip %u. */
|
||||||
int j;
|
*d++ = input[i++];
|
||||||
|
*d++ = input[i++];
|
||||||
for(j = 0; (j < 6)&&(i < input_len); j++) {
|
count += 2;
|
||||||
*d++ = input[i++];
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Not enough bytes available (4 data bytes were needed). */
|
/* Not enough bytes (4 data bytes), skip %u. */
|
||||||
while(i < input_len) {
|
*d++ = input[i++];
|
||||||
*d++ = input[i++];
|
*d++ = input[i++];
|
||||||
count++;
|
count += 2;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -602,35 +764,20 @@ int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len)
|
|||||||
char c1 = input[i + 1];
|
char c1 = input[i + 1];
|
||||||
char c2 = input[i + 2];
|
char c2 = input[i + 2];
|
||||||
|
|
||||||
/* ENH Use VALID_HEX? */
|
if (VALID_HEX(c1) && VALID_HEX(c2)) {
|
||||||
if ( (((c1 >= '0')&&(c1 <= '9')) || ((c1 >= 'a')&&(c1 <= 'f')) ||
|
|
||||||
((c1 >= 'A')&&(c1 <= 'F')))
|
|
||||||
&& (((c2 >= '0')&&(c2 <= '9')) || ((c2 >= 'a')&&(c2 <= 'f')) ||
|
|
||||||
((c2 >= 'A')&&(c2 <= 'F'))) )
|
|
||||||
{
|
|
||||||
*d++ = x2c(&input[i + 1]);
|
*d++ = x2c(&input[i + 1]);
|
||||||
count++;
|
count++;
|
||||||
i += 3;
|
i += 3;
|
||||||
|
*changed = 1;
|
||||||
} else {
|
} else {
|
||||||
/* Not a valid encoding, copy the raw input bytes. */
|
/* Not a valid encoding, skip this % */
|
||||||
*d++ = '%';
|
*d++ = input[i++];
|
||||||
*d++ = c1;
|
count++;
|
||||||
*d++ = c2;
|
|
||||||
count += 3;
|
|
||||||
i += 3;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Not enough bytes available. */
|
/* Not enough bytes available, skip this % */
|
||||||
|
*d++ = input[i++];
|
||||||
*d++ = '%';
|
|
||||||
count++;
|
count++;
|
||||||
i++;
|
|
||||||
|
|
||||||
if (i + 1 < input_len) {
|
|
||||||
*d++ = input[i];
|
|
||||||
count++;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -638,6 +785,7 @@ int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len)
|
|||||||
/* Character is not a percent sign. */
|
/* Character is not a percent sign. */
|
||||||
if (input[i] == '+') {
|
if (input[i] == '+') {
|
||||||
*d++ = ' ';
|
*d++ = ' ';
|
||||||
|
*changed = 1;
|
||||||
} else {
|
} else {
|
||||||
*d++ = input[i];
|
*d++ = input[i];
|
||||||
}
|
}
|
||||||
@@ -654,11 +802,14 @@ int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
* IMP1 Assumes NUL-terminated
|
||||||
*/
|
*/
|
||||||
int urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_len, int *invalid_count) {
|
int urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_len, int *invalid_count, int *changed) {
|
||||||
unsigned char *d = (unsigned char *)input;
|
unsigned char *d = (unsigned char *)input;
|
||||||
long int i, count;
|
long int i, count;
|
||||||
|
|
||||||
|
*changed = 0;
|
||||||
|
|
||||||
if (input == NULL) return -1;
|
if (input == NULL) return -1;
|
||||||
|
|
||||||
i = count = 0;
|
i = count = 0;
|
||||||
@@ -671,41 +822,29 @@ int urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_len, int
|
|||||||
char c1 = input[i + 1];
|
char c1 = input[i + 1];
|
||||||
char c2 = input[i + 2];
|
char c2 = input[i + 2];
|
||||||
|
|
||||||
/* ENH Use VALID_HEX? */
|
if (VALID_HEX(c1) && VALID_HEX(c2)) {
|
||||||
if ( (((c1 >= '0')&&(c1 <= '9')) || ((c1 >= 'a')&&(c1 <= 'f')) || ((c1 >= 'A')&&(c1 <= 'F')))
|
|
||||||
&& (((c2 >= '0')&&(c2 <= '9')) || ((c2 >= 'a')&&(c2 <= 'f')) || ((c2 >= 'A')&&(c2 <= 'F'))) )
|
|
||||||
{
|
|
||||||
/* Valid encoding - decode it. */
|
/* Valid encoding - decode it. */
|
||||||
*d++ = x2c(&input[i + 1]);
|
*d++ = x2c(&input[i + 1]);
|
||||||
count++;
|
count++;
|
||||||
i += 3;
|
i += 3;
|
||||||
|
*changed = 1;
|
||||||
} else {
|
} else {
|
||||||
/* Invalid encoding, just copy the raw bytes. */
|
/* Not a valid encoding, skip this % */
|
||||||
*d++ = '%';
|
*d++ = input[i++];
|
||||||
*d++ = c1;
|
count ++;
|
||||||
*d++ = c2;
|
(*invalid_count)++;
|
||||||
count += 3;
|
|
||||||
i += 3;
|
|
||||||
(*invalid_count)++; /* parens quiet compiler warning */
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Not enough bytes available, copy the raw bytes. */
|
/* Not enough bytes available, copy the raw bytes. */
|
||||||
(*invalid_count)++; /* parens quiet compiler warning */
|
*d++ = input[i++];
|
||||||
|
count ++;
|
||||||
*d++ = '%';
|
(*invalid_count)++;
|
||||||
count++;
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (i + 1 < input_len) {
|
|
||||||
*d++ = input[i];
|
|
||||||
count++;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Character is not a percent sign. */
|
/* Character is not a percent sign. */
|
||||||
if (input[i] == '+') {
|
if (input[i] == '+') {
|
||||||
*d++ = ' ';
|
*d++ = ' ';
|
||||||
|
*changed = 1;
|
||||||
} else {
|
} else {
|
||||||
*d++ = input[i];
|
*d++ = input[i];
|
||||||
}
|
}
|
||||||
@@ -721,6 +860,7 @@ int urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_len, int
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
* IMP1 Assumes NUL-terminated
|
||||||
*/
|
*/
|
||||||
int html_entities_decode_inplace(apr_pool_t *mp, unsigned char *input, int input_len) {
|
int html_entities_decode_inplace(apr_pool_t *mp, unsigned char *input, int input_len) {
|
||||||
unsigned char *d = input;
|
unsigned char *d = input;
|
||||||
@@ -756,7 +896,7 @@ int html_entities_decode_inplace(apr_pool_t *mp, unsigned char *input, int input
|
|||||||
while((j < input_len)&&(isxdigit(input[j]))) j++;
|
while((j < input_len)&&(isxdigit(input[j]))) j++;
|
||||||
if (j > k) { /* Do we have at least one digit? */
|
if (j > k) { /* Do we have at least one digit? */
|
||||||
/* Decode the entity. */
|
/* Decode the entity. */
|
||||||
char *x = apr_pstrmemdup(mp, (const char*)&input[k], j - k);
|
char *x = apr_pstrmemdup(mp, (const char *)&input[k], j - k);
|
||||||
*d++ = (unsigned char)strtol(x, NULL, 16);
|
*d++ = (unsigned char)strtol(x, NULL, 16);
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
@@ -774,7 +914,7 @@ int html_entities_decode_inplace(apr_pool_t *mp, unsigned char *input, int input
|
|||||||
while((j < input_len)&&(isdigit(input[j]))) j++;
|
while((j < input_len)&&(isdigit(input[j]))) j++;
|
||||||
if (j > k) { /* Do we have at least one digit? */
|
if (j > k) { /* Do we have at least one digit? */
|
||||||
/* Decode the entity. */
|
/* Decode the entity. */
|
||||||
char *x = apr_pstrmemdup(mp, (const char*)&input[k], j - k);
|
char *x = apr_pstrmemdup(mp, (const char *)&input[k], j - k);
|
||||||
*d++ = (unsigned char)strtol(x, NULL, 10);
|
*d++ = (unsigned char)strtol(x, NULL, 10);
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
@@ -793,9 +933,10 @@ int html_entities_decode_inplace(apr_pool_t *mp, unsigned char *input, int input
|
|||||||
k = j;
|
k = j;
|
||||||
while((j < input_len)&&(isalnum(input[j]))) j++;
|
while((j < input_len)&&(isalnum(input[j]))) j++;
|
||||||
if (j > k) { /* Do we have at least one digit? */
|
if (j > k) { /* Do we have at least one digit? */
|
||||||
char *x = apr_pstrmemdup(mp, (const char*)&input[k], j - k);
|
char *x = apr_pstrmemdup(mp, (const char *)&input[k], j - k);
|
||||||
|
|
||||||
/* Decode the entity. */
|
/* Decode the entity. */
|
||||||
|
/* ENH What about others? */
|
||||||
if (strcasecmp(x, "quot") == 0) *d++ = '"';
|
if (strcasecmp(x, "quot") == 0) *d++ = '"';
|
||||||
else
|
else
|
||||||
if (strcasecmp(x, "amp") == 0) *d++ = '&';
|
if (strcasecmp(x, "amp") == 0) *d++ = '&';
|
||||||
@@ -835,8 +976,10 @@ int html_entities_decode_inplace(apr_pool_t *mp, unsigned char *input, int input
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ISODIGIT(X) ((X >= '0')&&(X <= '7'))
|
/**
|
||||||
|
*
|
||||||
|
* IMP1 Assumes NUL-terminated
|
||||||
|
*/
|
||||||
int ansi_c_sequences_decode_inplace(unsigned char *input, int input_len) {
|
int ansi_c_sequences_decode_inplace(unsigned char *input, int input_len) {
|
||||||
unsigned char *d = input;
|
unsigned char *d = input;
|
||||||
int i, count;
|
int i, count;
|
||||||
@@ -846,10 +989,6 @@ int ansi_c_sequences_decode_inplace(unsigned char *input, int input_len) {
|
|||||||
if ((input[i] == '\\')&&(i + 1 < input_len)) {
|
if ((input[i] == '\\')&&(i + 1 < input_len)) {
|
||||||
int c = -1;
|
int c = -1;
|
||||||
|
|
||||||
/* ENH Should we handle \c as well?
|
|
||||||
* See http://www.opengroup.org/onlinepubs/009695399/utilities/printf.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
switch(input[i + 1]) {
|
switch(input[i + 1]) {
|
||||||
case 'a' :
|
case 'a' :
|
||||||
c = '\a';
|
c = '\a';
|
||||||
@@ -901,14 +1040,11 @@ int ansi_c_sequences_decode_inplace(unsigned char *input, int input_len) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (isdigit(input[i + 1])) { /* Octal. */
|
if (ISODIGIT(input[i + 1])) { /* Octal. */
|
||||||
char buf[10];
|
char buf[4];
|
||||||
int j = 0, l = 3;
|
int j = 0;
|
||||||
|
|
||||||
/* Up to 4 digits if the first digit is a zero. */
|
while((i + 1 + j < input_len)&&(j < 3)) {
|
||||||
if (input[i + 1] == '0') l = 4;
|
|
||||||
|
|
||||||
while((i + 1 + j < input_len)&&(j <= l)) {
|
|
||||||
buf[j] = input[i + 1 + j];
|
buf[j] = input[i + 1 + j];
|
||||||
j++;
|
j++;
|
||||||
if (!ISODIGIT(input[i + 1 + j])) break;
|
if (!ISODIGIT(input[i + 1 + j])) break;
|
||||||
@@ -944,16 +1080,25 @@ int ansi_c_sequences_decode_inplace(unsigned char *input, int input_len) {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int normalise_path_inplace(unsigned char *input, int input_len, int win) {
|
/**
|
||||||
|
*
|
||||||
|
* IMP1 Assumes NUL-terminated
|
||||||
|
*/
|
||||||
|
int normalise_path_inplace(unsigned char *input, int input_len, int win, int *changed) {
|
||||||
unsigned char *d = input;
|
unsigned char *d = input;
|
||||||
int i, count;
|
int i, count;
|
||||||
|
|
||||||
|
*changed = 0;
|
||||||
|
|
||||||
i = count = 0;
|
i = count = 0;
|
||||||
while ((i < input_len)&&(count < input_len)) {
|
while ((i < input_len)&&(count < input_len)) {
|
||||||
char c = input[i];
|
char c = input[i];
|
||||||
|
|
||||||
/* Convert backslash to forward slash on Windows only. */
|
/* Convert backslash to forward slash on Windows only. */
|
||||||
if ((win)&&(c == '\\')) c = '/';
|
if ((win)&&(c == '\\')) {
|
||||||
|
c = '/';
|
||||||
|
*changed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (c == '/') {
|
if (c == '/') {
|
||||||
/* Is there a directory back-reference? Yes, we
|
/* Is there a directory back-reference? Yes, we
|
||||||
@@ -964,6 +1109,8 @@ int normalise_path_inplace(unsigned char *input, int input_len, int win) {
|
|||||||
unsigned char *cd = d - 4;
|
unsigned char *cd = d - 4;
|
||||||
int ccount = count - 4;
|
int ccount = count - 4;
|
||||||
|
|
||||||
|
*changed = 1;
|
||||||
|
|
||||||
/* Go back until we reach the beginning or a forward slash. */
|
/* Go back until we reach the beginning or a forward slash. */
|
||||||
while ((ccount > 0)&&(*cd != '/')) {
|
while ((ccount > 0)&&(*cd != '/')) {
|
||||||
ccount--;
|
ccount--;
|
||||||
@@ -980,12 +1127,14 @@ int normalise_path_inplace(unsigned char *input, int input_len, int win) {
|
|||||||
/* Ignore the last two bytes. */
|
/* Ignore the last two bytes. */
|
||||||
d -= 2;
|
d -= 2;
|
||||||
count -= 2;
|
count -= 2;
|
||||||
|
*changed = 1;
|
||||||
} else
|
} else
|
||||||
/* Or are there just multiple occurences of forward slash? */
|
/* Or are there just multiple occurences of forward slash? */
|
||||||
if ((count >= 1)&&(*(d - 1) == '/')) {
|
if ((count >= 1)&&(*(d - 1) == '/')) {
|
||||||
/* Ignore the last one byte. */
|
/* Ignore the last one byte. */
|
||||||
d--;
|
d--;
|
||||||
count--;
|
count--;
|
||||||
|
*changed = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -999,3 +1148,46 @@ int normalise_path_inplace(unsigned char *input, int input_len, int win) {
|
|||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *modsec_build(apr_pool_t *mp) {
|
||||||
|
int build_type = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; modsec_build_type[i].name != NULL; i++) {
|
||||||
|
if (strcmp(MODSEC_VERSION_TYPE, modsec_build_type[i].name) == 0) {
|
||||||
|
build_type = modsec_build_type[i].val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return apr_psprintf(mp, "%02i%02i%02i%1i%02i",
|
||||||
|
atoi(MODSEC_VERSION_MAJOR),
|
||||||
|
atoi(MODSEC_VERSION_MINOR),
|
||||||
|
atoi(MODSEC_VERSION_MAINT),
|
||||||
|
build_type,
|
||||||
|
atoi(MODSEC_VERSION_RELEASE));
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_empty_string(const char *string) {
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (string == NULL) return 1;
|
||||||
|
|
||||||
|
for(i = 0; string[i] != '\0'; i++) {
|
||||||
|
if (!isspace(string[i])) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *resolve_relative_path(apr_pool_t *pool, const char *parent_filename, const char *filename) {
|
||||||
|
if (filename == NULL) return NULL;
|
||||||
|
// TODO Support paths on operating systems other than Unix.
|
||||||
|
if (filename[0] == '/') return (char *)filename;
|
||||||
|
|
||||||
|
return apr_pstrcat(pool, apr_pstrndup(pool, parent_filename,
|
||||||
|
strlen(parent_filename) - strlen(apr_filepath_name_get(parent_filename))),
|
||||||
|
filename, NULL);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -13,13 +13,13 @@
|
|||||||
|
|
||||||
#include "modsecurity.h"
|
#include "modsecurity.h"
|
||||||
|
|
||||||
int DSOLOCAL normalise_path_inplace(unsigned char *input, int len, int win);
|
int DSOLOCAL normalise_path_inplace(unsigned char *input, int len, int win, int *changed);
|
||||||
|
|
||||||
int DSOLOCAL parse_boolean(const char *input);
|
int DSOLOCAL parse_boolean(const char *input);
|
||||||
|
|
||||||
int DSOLOCAL parse_name_eq_value(apr_pool_t *mp, const char *input, char **name, char **value);
|
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);
|
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 *strnurlencat(char *destination, char *source, unsigned int maxlen);
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ int DSOLOCAL is_token_char(unsigned char c);
|
|||||||
|
|
||||||
int DSOLOCAL remove_lf_crlf_inplace(char *text);
|
int DSOLOCAL remove_lf_crlf_inplace(char *text);
|
||||||
|
|
||||||
unsigned DSOLOCAL char x2c(unsigned char *what);
|
unsigned char DSOLOCAL x2c(unsigned char *what);
|
||||||
|
|
||||||
char DSOLOCAL *guess_tmp_dir(apr_pool_t *p);
|
char DSOLOCAL *guess_tmp_dir(apr_pool_t *p);
|
||||||
|
|
||||||
@@ -59,17 +59,27 @@ char DSOLOCAL *log_escape_nq_ex(apr_pool_t *p, const char *text, unsigned long i
|
|||||||
|
|
||||||
char DSOLOCAL *log_escape_header_name(apr_pool_t *p, const char *text);
|
char DSOLOCAL *log_escape_header_name(apr_pool_t *p, const char *text);
|
||||||
|
|
||||||
char *log_escape_raw(apr_pool_t *mp, const unsigned 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(apr_pool_t *p, const unsigned char *input,
|
char DSOLOCAL *_log_escape(apr_pool_t *p, const unsigned char *input,
|
||||||
unsigned long int input_length, int escape_quotes, int escape_colon);
|
unsigned long int input_length, int escape_quotes, int escape_colon);
|
||||||
|
|
||||||
int DSOLOCAL urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_length);
|
int DSOLOCAL js_decode_nonstrict_inplace(unsigned char *input, long int input_len);
|
||||||
|
|
||||||
int DSOLOCAL urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_length, int *invalid_count);
|
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 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);
|
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);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -8,8 +8,6 @@
|
|||||||
* write to Breach Security, Inc. at support@breach.com.
|
* write to Breach Security, Inc. at support@breach.com.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#ifdef WITH_LIBXML2
|
|
||||||
|
|
||||||
#include "msc_xml.h"
|
#include "msc_xml.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -33,7 +31,7 @@ static void xml_receive_sax_error(void *data, const char *msg, ...) {
|
|||||||
|
|
||||||
if (msr == NULL) return;
|
if (msr == NULL) return;
|
||||||
|
|
||||||
apr_snprintf(message, sizeof(message), "%s (line %i pos %i)",
|
apr_snprintf(message, sizeof(message), "%s (line %d offset %d)",
|
||||||
log_escape_nq(msr->mp, msr->xml->parsing_ctx->lastError.message),
|
log_escape_nq(msr->mp, msr->xml->parsing_ctx->lastError.message),
|
||||||
msr->xml->parsing_ctx->lastError.line,
|
msr->xml->parsing_ctx->lastError.line,
|
||||||
msr->xml->parsing_ctx->lastError.int2);
|
msr->xml->parsing_ctx->lastError.int2);
|
||||||
@@ -109,7 +107,7 @@ int xml_complete(modsec_rec *msr, char **error_msg) {
|
|||||||
/* Clean up everything else. */
|
/* Clean up everything else. */
|
||||||
xmlFreeParserCtxt(msr->xml->parsing_ctx);
|
xmlFreeParserCtxt(msr->xml->parsing_ctx);
|
||||||
msr->xml->parsing_ctx = NULL;
|
msr->xml->parsing_ctx = NULL;
|
||||||
msr_log(msr, 4, "XML: Parsing complete (well_formed %i).", msr->xml->well_formed);
|
msr_log(msr, 4, "XML: Parsing complete (well_formed %u).", msr->xml->well_formed);
|
||||||
|
|
||||||
if (msr->xml->well_formed != 1) {
|
if (msr->xml->well_formed != 1) {
|
||||||
*error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document.");
|
*error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document.");
|
||||||
@@ -131,5 +129,3 @@ apr_status_t xml_cleanup(modsec_rec *msr) {
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "modsecurity.h"
|
#include "modsecurity.h"
|
||||||
|
#include "apache2.h"
|
||||||
#include "pdf_protect.h"
|
#include "pdf_protect.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -63,7 +64,7 @@ static char *create_hash(modsec_rec *msr,
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static char *create_token(modsec_rec *msr) {
|
static char *create_token(modsec_rec *msr) {
|
||||||
unsigned int current_time;
|
apr_time_t current_time;
|
||||||
const char *time_string = NULL;
|
const char *time_string = NULL;
|
||||||
const char *hash = NULL;
|
const char *hash = NULL;
|
||||||
int timeout = DEFAULT_TIMEOUT;
|
int timeout = DEFAULT_TIMEOUT;
|
||||||
@@ -73,7 +74,7 @@ static char *create_token(modsec_rec *msr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
current_time = apr_time_sec(apr_time_now());
|
current_time = apr_time_sec(apr_time_now());
|
||||||
time_string = apr_psprintf(msr->mp, "%i", current_time + timeout);
|
time_string = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(current_time + timeout));
|
||||||
if (time_string == NULL) return NULL;
|
if (time_string == NULL) return NULL;
|
||||||
|
|
||||||
hash = create_hash(msr, time_string);
|
hash = create_hash(msr, time_string);
|
||||||
@@ -197,23 +198,6 @@ static int verify_token(modsec_rec *msr, const char *token, char **error_msg) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static apr_status_t send_error_bucket(ap_filter_t *f, int status) {
|
|
||||||
apr_bucket_brigade *brigade = NULL;
|
|
||||||
apr_bucket *bucket = NULL;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
f->r->connection->keepalive = AP_CONN_CLOSE;
|
|
||||||
return ap_pass_brigade(f->next, brigade);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -226,7 +210,7 @@ apr_status_t pdfp_output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
|
|
||||||
ap_remove_output_filter(f);
|
ap_remove_output_filter(f);
|
||||||
|
|
||||||
return send_error_bucket(f, HTTP_INTERNAL_SERVER_ERROR);
|
return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msr->txcfg->pdfp_enabled == 1) {
|
if (msr->txcfg->pdfp_enabled == 1) {
|
||||||
@@ -328,7 +312,9 @@ apr_status_t pdfp_output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
|
|
||||||
apr_table_set(r->headers_out, "Location", new_uri);
|
apr_table_set(r->headers_out, "Location", new_uri);
|
||||||
|
|
||||||
return send_error_bucket(f, REDIRECT_STATUS);
|
ap_remove_output_filter(f);
|
||||||
|
|
||||||
|
return send_error_bucket(msr, f, REDIRECT_STATUS);
|
||||||
}
|
}
|
||||||
} else { /* Token found. */
|
} else { /* Token found. */
|
||||||
char *my_error_msg = NULL;
|
char *my_error_msg = NULL;
|
||||||
@@ -436,7 +422,7 @@ int pdfp_check(modsec_rec *msr) {
|
|||||||
if ((msr->r->method_number != M_GET)&&(cfg->pdfp_only_get != 0)) {
|
if ((msr->r->method_number != M_GET)&&(cfg->pdfp_only_get != 0)) {
|
||||||
if (msr->txcfg->debuglog_level >= 4) {
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
msr_log(msr, 4, "PdfProtect: Not intercepting a GET/HEAD request "
|
msr_log(msr, 4, "PdfProtect: Not intercepting a GET/HEAD request "
|
||||||
"(method=%s/%i).", log_escape_nq(msr->mp, msr->r->method), msr->r->method_number);
|
"(method=%s/%d).", log_escape_nq(msr->mp, msr->r->method), msr->r->method_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -46,7 +46,7 @@ static apr_table_t *collection_unpack(modsec_rec *msr, char *blob, unsigned int
|
|||||||
blob_offset += var->value_len;
|
blob_offset += var->value_len;
|
||||||
var->value_len--;
|
var->value_len--;
|
||||||
|
|
||||||
if (log_vars) {
|
if (log_vars && (msr->txcfg->debuglog_level >= 9)) {
|
||||||
msr_log(msr, 9, "Read variable: name \"%s\", value \"%s\".",
|
msr_log(msr, 9, "Read variable: name \"%s\", value \"%s\".",
|
||||||
log_escape_ex(msr->mp, var->name, var->name_len),
|
log_escape_ex(msr->mp, var->name, var->name_len),
|
||||||
log_escape_ex(msr->mp, var->value, var->value_len));
|
log_escape_ex(msr->mp, var->value, var->value_len));
|
||||||
@@ -72,40 +72,47 @@ apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
|
|||||||
apr_table_t *col = NULL;
|
apr_table_t *col = NULL;
|
||||||
const apr_array_header_t *arr;
|
const apr_array_header_t *arr;
|
||||||
apr_table_entry_t *te;
|
apr_table_entry_t *te;
|
||||||
|
int expired = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (msr->txcfg->data_dir == NULL) {
|
if (msr->txcfg->data_dir == NULL) {
|
||||||
msr_log(msr, 1, "Unable to retrieve collection (name \"%s\", key \"%s\"). Use "
|
msr_log(msr, 1, "Unable to retrieve collection (name \"%s\", key \"%s\"). Use "
|
||||||
"SecDataDir to define data directory first.", log_escape(msr->mp, col_name),
|
"SecDataDir to define data directory first.", log_escape(msr->mp, col_name),
|
||||||
log_escape(msr->mp, col_key));
|
log_escape_ex(msr->mp, col_key, col_key_len));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", col_name, NULL);
|
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", col_name, NULL);
|
||||||
|
|
||||||
|
key.dptr = (char *)col_key;
|
||||||
|
key.dsize = col_key_len + 1;
|
||||||
|
|
||||||
rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK,
|
rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK,
|
||||||
CREATEMODE, msr->mp);
|
CREATEMODE, msr->mp);
|
||||||
if (rc != APR_SUCCESS) {
|
if (rc != APR_SUCCESS) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
key.dptr = (char *)col_key;
|
|
||||||
key.dsize = col_key_len + 1;
|
|
||||||
|
|
||||||
value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t));
|
value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t));
|
||||||
rc = apr_sdbm_fetch(dbm, value, key);
|
rc = apr_sdbm_fetch(dbm, value, key);
|
||||||
|
|
||||||
|
apr_sdbm_close(dbm);
|
||||||
|
|
||||||
if (rc != APR_SUCCESS) {
|
if (rc != APR_SUCCESS) {
|
||||||
apr_sdbm_close(dbm);
|
|
||||||
msr_log(msr, 1, "Failed to read from DBM file \"%s\": %s", log_escape(msr->mp,
|
msr_log(msr, 1, "Failed to read from DBM file \"%s\": %s", log_escape(msr->mp,
|
||||||
dbm_filename), get_apr_error(msr->mp, rc));
|
dbm_filename), get_apr_error(msr->mp, rc));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value->dptr == NULL) { /* Key not found in DBM file. */
|
if (value->dptr == NULL) { /* Key not found in DBM file. */
|
||||||
apr_sdbm_close(dbm);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ENH Need expiration (and perhaps other metadata) accessible in blob
|
||||||
|
* form so we can determine if we need to convert to a table. This will
|
||||||
|
* save some cycles.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Transform raw data into a table. */
|
/* Transform raw data into a table. */
|
||||||
col = collection_unpack(msr, value->dptr, value->dsize, 1);
|
col = collection_unpack(msr, value->dptr, value->dsize, 1);
|
||||||
if (col == NULL) return NULL;
|
if (col == NULL) return NULL;
|
||||||
@@ -119,22 +126,63 @@ apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
|
|||||||
msc_string *var = (msc_string *)te[i].val;
|
msc_string *var = (msc_string *)te[i].val;
|
||||||
int expiry_time = atoi(var->value);
|
int expiry_time = atoi(var->value);
|
||||||
|
|
||||||
/* Do not remove the record itself. */
|
|
||||||
if (strcmp(te[i].key, "__expire_KEY") == 0) continue;
|
|
||||||
|
|
||||||
if (expiry_time <= apr_time_sec(msr->request_time)) {
|
if (expiry_time <= apr_time_sec(msr->request_time)) {
|
||||||
char *key_to_expire = apr_pstrdup(msr->mp, te[i].key);
|
char *key_to_expire = te[i].key;
|
||||||
msr_log(msr, 9, "Removing key \"%s\" from collection.", key_to_expire + 9);
|
|
||||||
|
/* 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, "Removing key \"%s\" from collection.", key_to_expire + 9);
|
||||||
|
msr_log(msr, 9, "Removing key \"%s\" from collection.", key_to_expire);
|
||||||
|
}
|
||||||
apr_table_unset(col, key_to_expire + 9);
|
apr_table_unset(col, key_to_expire + 9);
|
||||||
msr_log(msr, 9, "Removing key \"%s\" from collection.", key_to_expire);
|
|
||||||
apr_table_unset(col, key_to_expire);
|
apr_table_unset(col, key_to_expire);
|
||||||
msr_log(msr, 4, "Removed expired variable \"%s\".", key_to_expire + 9);
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
|
msr_log(msr, 4, "Removed expired variable \"%s\".", key_to_expire + 9);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while(i != arr->nelts);
|
} 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 we determine if it needs deleted than to open a second
|
||||||
|
* time.
|
||||||
|
*/
|
||||||
|
if (apr_table_get(col, "KEY") == 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, "Failed to access DBM file \"%s\": %s",
|
||||||
|
log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = apr_sdbm_delete(dbm, key);
|
||||||
|
|
||||||
|
apr_sdbm_close(dbm);
|
||||||
|
|
||||||
|
if (rc != APR_SUCCESS) {
|
||||||
|
msr_log(msr, 1, "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));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expired && (msr->txcfg->debuglog_level >= 9)) {
|
||||||
|
msr_log(msr, 9, "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, "Deleted collection (name \"%s\", key \"%s\").",
|
||||||
|
log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len));
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Update UPDATE_RATE */
|
/* Update UPDATE_RATE */
|
||||||
{
|
{
|
||||||
@@ -150,34 +198,33 @@ apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
|
|||||||
if (var == NULL) {
|
if (var == NULL) {
|
||||||
/* Error. */
|
/* Error. */
|
||||||
} else {
|
} else {
|
||||||
int td;
|
apr_time_t td;
|
||||||
counter = atoi(var->value);
|
counter = atoi(var->value);
|
||||||
var = (msc_string *)apr_table_get(col, "UPDATE_RATE");
|
|
||||||
if (var == NULL) {
|
/* UPDATE_RATE is removed on store, so we add it back here */
|
||||||
var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||||
var->name = "UPDATE_RATE";
|
var->name = "UPDATE_RATE";
|
||||||
var->name_len = strlen(var->name);
|
var->name_len = strlen(var->name);
|
||||||
apr_table_setn(col, var->name, (void *)var);
|
apr_table_setn(col, var->name, (void *)var);
|
||||||
}
|
|
||||||
|
|
||||||
/* NOTE: No rate if there has been no time elapsed */
|
/* NOTE: No rate if there has been no time elapsed */
|
||||||
td = (apr_time_sec(apr_time_now()) - create_time);
|
td = (apr_time_sec(apr_time_now()) - create_time);
|
||||||
if (td == 0) {
|
if (td == 0) {
|
||||||
var->value = apr_psprintf(msr->mp, "%i", 0);
|
var->value = apr_psprintf(msr->mp, "%d", 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var->value = apr_psprintf(msr->mp, "%i",
|
var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT,
|
||||||
(int)((60 * counter)/td));
|
(apr_time_t)((60 * counter)/td));
|
||||||
}
|
}
|
||||||
var->value_len = strlen(var->value);
|
var->value_len = strlen(var->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_sdbm_close(dbm);
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
|
msr_log(msr, 4, "Retrieved collection (name \"%s\", key \"%s\").",
|
||||||
msr_log(msr, 4, "Retrieved collection (name \"%s\", key \"%s\").",
|
log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len));
|
||||||
log_escape(msr->mp, col_name), log_escape(msr->mp, col_key));
|
}
|
||||||
|
|
||||||
return col;
|
return col;
|
||||||
}
|
}
|
||||||
@@ -211,66 +258,17 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
|
|||||||
if (msr->txcfg->data_dir == NULL) {
|
if (msr->txcfg->data_dir == NULL) {
|
||||||
msr_log(msr, 1, "Unable to store collection (name \"%s\", key \"%s\"). Use "
|
msr_log(msr, 1, "Unable to store collection (name \"%s\", key \"%s\"). Use "
|
||||||
"SecDataDir to define data directory first.",
|
"SecDataDir to define data directory first.",
|
||||||
log_escape(msr->mp, var_name->value), log_escape(msr->mp, var_key->value));
|
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 -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", var_name->value, NULL);
|
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", var_name->value, NULL);
|
||||||
|
|
||||||
/* Remove expired variables. */
|
/* Delete IS_NEW on store. */
|
||||||
do {
|
apr_table_unset(col, "IS_NEW");
|
||||||
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);
|
|
||||||
|
|
||||||
/* Do not remove the record itself. */
|
/* Delete UPDATE_RATE on store to save space as it is calculated */
|
||||||
if (strcmp(te[i].key, "__expire_KEY") == 0) continue;
|
apr_table_unset(col, "UPDATE_RATE");
|
||||||
|
|
||||||
if (expiry_time <= apr_time_sec(msr->request_time)) {
|
|
||||||
char *key_to_expire = apr_pstrdup(msr->mp, te[i].key);
|
|
||||||
msr_log(msr, 9, "Removing key \"%s\" from collection.", key_to_expire + 9);
|
|
||||||
apr_table_unset(col, key_to_expire + 9);
|
|
||||||
msr_log(msr, 9, "Removing key \"%s\" from collection.", key_to_expire);
|
|
||||||
apr_table_unset(col, key_to_expire);
|
|
||||||
msr_log(msr, 4, "Removed expired variable \"%s\".", key_to_expire + 9);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while(i != arr->nelts);
|
|
||||||
|
|
||||||
/* Delete the collection if the variable "KEY" does not exist. */
|
|
||||||
if (apr_table_get(col, "KEY") == 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, "Failed to access DBM file \"%s\": %s",
|
|
||||||
log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
key.dptr = var_key->value;
|
|
||||||
key.dsize = var_key->value_len + 1;
|
|
||||||
|
|
||||||
rc = apr_sdbm_delete(dbm, key);
|
|
||||||
if (rc != APR_SUCCESS) {
|
|
||||||
msr_log(msr, 1, "Failed deleting collection (name \"%s\", "
|
|
||||||
"key \"%s\"): %s", log_escape(msr->mp, var_name->value),
|
|
||||||
log_escape(msr->mp, var_key->value), get_apr_error(msr->mp, rc));
|
|
||||||
apr_sdbm_close(dbm);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
msr_log(msr, 4, "Deleted collection (name \"%s\", key \"%s\").",
|
|
||||||
log_escape(msr->mp, var_name->value), log_escape(msr->mp, var_key->value));
|
|
||||||
apr_sdbm_close(dbm);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the timeout value. */
|
/* Update the timeout value. */
|
||||||
{
|
{
|
||||||
@@ -279,7 +277,7 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
|
|||||||
int timeout = atoi(var->value);
|
int timeout = atoi(var->value);
|
||||||
var = (msc_string *)apr_table_get(col, "__expire_KEY");
|
var = (msc_string *)apr_table_get(col, "__expire_KEY");
|
||||||
if (var != NULL) {
|
if (var != NULL) {
|
||||||
var->value = apr_psprintf(msr->mp, "%i", (int)(apr_time_sec(apr_time_now()) + timeout));
|
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);
|
var->value_len = strlen(var->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,7 +292,7 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
|
|||||||
var->name_len = strlen(var->name);
|
var->name_len = strlen(var->name);
|
||||||
apr_table_setn(col, var->name, (void *)var);
|
apr_table_setn(col, var->name, (void *)var);
|
||||||
}
|
}
|
||||||
var->value = apr_psprintf(msr->mp, "%i", (int)(apr_time_sec(apr_time_now())));
|
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);
|
var->value_len = strlen(var->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,10 +308,15 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
|
|||||||
} else {
|
} else {
|
||||||
counter = atoi(var->value);
|
counter = atoi(var->value);
|
||||||
}
|
}
|
||||||
var->value = apr_psprintf(msr->mp, "%i", counter + 1);
|
var->value = apr_psprintf(msr->mp, "%d", counter + 1);
|
||||||
var->value_len = strlen(var->value);
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
/* Calculate the size first. */
|
/* Calculate the size first. */
|
||||||
blob_size = 3 + 2;
|
blob_size = 3 + 2;
|
||||||
arr = apr_table_elts(col);
|
arr = apr_table_elts(col);
|
||||||
@@ -366,9 +369,11 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
|
|||||||
blob[blob_offset + 2 + len - 1] = '\0';
|
blob[blob_offset + 2 + len - 1] = '\0';
|
||||||
blob_offset += 2 + len;
|
blob_offset += 2 + len;
|
||||||
|
|
||||||
msr_log(msr, 9, "Wrote variable: name \"%s\", value \"%s\".",
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
log_escape_ex(msr->mp, var->name, var->name_len),
|
msr_log(msr, 9, "Wrote variable: name \"%s\", value \"%s\".",
|
||||||
log_escape_ex(msr->mp, var->value, var->value_len));
|
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] = 0;
|
||||||
@@ -377,6 +382,12 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
|
|||||||
/* And, finally, store it. */
|
/* And, finally, store it. */
|
||||||
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", var_name->value, NULL);
|
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", var_name->value, NULL);
|
||||||
|
|
||||||
|
key.dptr = var_key->value;
|
||||||
|
key.dsize = var_key->value_len + 1;
|
||||||
|
|
||||||
|
value.dptr = (char *)blob;
|
||||||
|
value.dsize = blob_size;
|
||||||
|
|
||||||
rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK,
|
rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK,
|
||||||
CREATEMODE, msr->mp);
|
CREATEMODE, msr->mp);
|
||||||
if (rc != APR_SUCCESS) {
|
if (rc != APR_SUCCESS) {
|
||||||
@@ -385,24 +396,20 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE);
|
||||||
|
|
||||||
|
apr_sdbm_close(dbm);
|
||||||
|
|
||||||
if (rc != APR_SUCCESS) {
|
if (rc != APR_SUCCESS) {
|
||||||
msr_log(msr, 1, "Failed to write to DBM file \"%s\": %s", dbm_filename,
|
msr_log(msr, 1, "Failed to write to DBM file \"%s\": %s", dbm_filename,
|
||||||
get_apr_error(msr->mp, rc));
|
get_apr_error(msr->mp, rc));
|
||||||
apr_sdbm_close(dbm);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
msr_log(msr, 4, "Persisted collection (name \"%s\", key \"%s\").",
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
log_escape(msr->mp, var_name->value), log_escape(msr->mp, var_key->value));
|
msr_log(msr, 4, "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));
|
||||||
apr_sdbm_close(dbm);
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -418,7 +425,7 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) {
|
|||||||
apr_array_header_t *keys_arr;
|
apr_array_header_t *keys_arr;
|
||||||
char **keys;
|
char **keys;
|
||||||
int i;
|
int i;
|
||||||
unsigned int now = (unsigned int)apr_time_sec(msr->request_time);
|
apr_time_t now = apr_time_sec(msr->request_time);
|
||||||
|
|
||||||
if (msr->txcfg->data_dir == NULL) {
|
if (msr->txcfg->data_dir == NULL) {
|
||||||
/* The user has been warned about this problem enough times already by now.
|
/* The user has been warned about this problem enough times already by now.
|
||||||
@@ -453,14 +460,16 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) {
|
|||||||
*/
|
*/
|
||||||
rc = apr_sdbm_firstkey(dbm, &key);
|
rc = apr_sdbm_firstkey(dbm, &key);
|
||||||
while(rc == APR_SUCCESS) {
|
while(rc == APR_SUCCESS) {
|
||||||
char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize);
|
char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1);
|
||||||
*(char **)apr_array_push(keys_arr) = s;
|
*(char **)apr_array_push(keys_arr) = s;
|
||||||
rc = apr_sdbm_nextkey(dbm, &key);
|
rc = apr_sdbm_nextkey(dbm, &key);
|
||||||
}
|
}
|
||||||
apr_sdbm_unlock(dbm);
|
apr_sdbm_unlock(dbm);
|
||||||
|
|
||||||
msr_log(msr, 9, "Found %i record(s) in file \"%s\".", keys_arr->nelts,
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
log_escape(msr->mp, dbm_filename));
|
msr_log(msr, 9, "Found %d record(s) in file \"%s\".", keys_arr->nelts,
|
||||||
|
log_escape(msr->mp, dbm_filename));
|
||||||
|
}
|
||||||
|
|
||||||
/* Now retrieve the entires one by one. */
|
/* Now retrieve the entires one by one. */
|
||||||
keys = (char **)keys_arr->elts;
|
keys = (char **)keys_arr->elts;
|
||||||
@@ -482,6 +491,7 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) {
|
|||||||
|
|
||||||
col = collection_unpack(msr, value.dptr, value.dsize, 0);
|
col = collection_unpack(msr, value.dptr, value.dsize, 0);
|
||||||
if (col == NULL) {
|
if (col == NULL) {
|
||||||
|
apr_sdbm_close(dbm);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,25 +499,30 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) {
|
|||||||
if (var == NULL) {
|
if (var == NULL) {
|
||||||
msr_log(msr, 1, "Collection cleanup discovered entry with no "
|
msr_log(msr, 1, "Collection cleanup discovered entry with no "
|
||||||
"__expire_KEY (name \"%s\", key \"%s\").",
|
"__expire_KEY (name \"%s\", key \"%s\").",
|
||||||
log_escape(msr->mp, col_name), log_escape(msr->mp, key.dptr));
|
log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1));
|
||||||
} else {
|
} else {
|
||||||
unsigned int expiry_time = atoi(var->value);
|
unsigned int expiry_time = atoi(var->value);
|
||||||
|
|
||||||
msr_log(msr, 9, "Record (name \"%s\", key \"%s\") set to expire in %i seconds.",
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
log_escape(msr->mp, col_name), log_escape(msr->mp, key.dptr),
|
msr_log(msr, 9, "Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.",
|
||||||
expiry_time - now);
|
log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1),
|
||||||
|
expiry_time - now);
|
||||||
|
}
|
||||||
|
|
||||||
if (expiry_time <= now) {
|
if (expiry_time <= now) {
|
||||||
rc = apr_sdbm_delete(dbm, key);
|
rc = apr_sdbm_delete(dbm, key);
|
||||||
if (rc != APR_SUCCESS) {
|
if (rc != APR_SUCCESS) {
|
||||||
msr_log(msr, 1, "Failed deleting collection (name \"%s\", "
|
msr_log(msr, 1, "Failed deleting collection (name \"%s\", "
|
||||||
"key \"%s\"): %s", log_escape(msr->mp, col_name),
|
"key \"%s\"): %s", log_escape(msr->mp, col_name),
|
||||||
log_escape(msr->mp, key.dptr), get_apr_error(msr->mp, rc));
|
log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc));
|
||||||
|
apr_sdbm_close(dbm);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
msr_log(msr, 4, "Removed stale collection (name \"%s\", "
|
if (msr->txcfg->debuglog_level >= 4) {
|
||||||
"key \"%s\").", log_escape(msr->mp, col_name),
|
msr_log(msr, 4, "Removed stale collection (name \"%s\", "
|
||||||
log_escape(msr->mp, key.dptr));
|
"key \"%s\").", log_escape(msr->mp, col_name),
|
||||||
|
log_escape_ex(msr->mp, key.dptr, key.dsize - 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
|
|||||||
1047
apache2/re.c
1047
apache2/re.c
File diff suppressed because it is too large
Load Diff
108
apache2/re.h
108
apache2/re.h
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -35,6 +35,10 @@ typedef struct msre_cache_rec msre_cache_rec;
|
|||||||
#include "persist_dbm.h"
|
#include "persist_dbm.h"
|
||||||
#include "apache2.h"
|
#include "apache2.h"
|
||||||
|
|
||||||
|
#if defined(WITH_LUA)
|
||||||
|
#include "msc_lua.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Actions, variables, functions and operator functions */
|
/* Actions, variables, functions and operator functions */
|
||||||
|
|
||||||
int DSOLOCAL expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t *mptmp);
|
int DSOLOCAL expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t *mptmp);
|
||||||
@@ -63,6 +67,11 @@ int DSOLOCAL msre_parse_generic(apr_pool_t *pool, const char *text, apr_table_t
|
|||||||
|
|
||||||
int DSOLOCAL rule_id_in_range(int ruleid, const char *range);
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
/* Structures with the corresponding functions */
|
/* Structures with the corresponding functions */
|
||||||
|
|
||||||
@@ -99,6 +108,8 @@ 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);
|
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 DSOLOCAL msre_ruleset_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re);
|
int DSOLOCAL msre_ruleset_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -109,6 +120,17 @@ int DSOLOCAL msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset
|
|||||||
#define RULE_NO_MATCH 0
|
#define RULE_NO_MATCH 0
|
||||||
#define RULE_MATCH 1
|
#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 {
|
struct msre_rule {
|
||||||
apr_array_header_t *targets;
|
apr_array_header_t *targets;
|
||||||
const char *op_name;
|
const char *op_name;
|
||||||
@@ -117,18 +139,38 @@ struct msre_rule {
|
|||||||
msre_op_metadata *op_metadata;
|
msre_op_metadata *op_metadata;
|
||||||
unsigned int op_negated;
|
unsigned int op_negated;
|
||||||
msre_actionset *actionset;
|
msre_actionset *actionset;
|
||||||
|
const char *p1;
|
||||||
|
const char *unparsed;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
int line_num;
|
int line_num;
|
||||||
|
int placeholder;
|
||||||
|
int type;
|
||||||
|
|
||||||
msre_ruleset *ruleset;
|
msre_ruleset *ruleset;
|
||||||
msre_rule *chain_starter;
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
msre_rule DSOLOCAL *msre_rule_create(msre_ruleset *ruleset,
|
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 *fn, int line, const char *targets,
|
||||||
const char *args, const char *actions, char **error_msg);
|
const char *args, const char *actions, char **error_msg);
|
||||||
|
|
||||||
void DSOLOCAL msre_rule_actionset_init(msre_rule *rule);
|
#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
|
||||||
|
|
||||||
apr_status_t DSOLOCAL msre_rule_process(msre_rule *rule, modsec_rec *msr);
|
apr_status_t DSOLOCAL msre_rule_process(msre_rule *rule, modsec_rec *msr);
|
||||||
|
|
||||||
@@ -141,17 +183,16 @@ apr_status_t DSOLOCAL msre_rule_process(msre_rule *rule, modsec_rec *msr);
|
|||||||
#define PHASE_RESPONSE_BODY 4
|
#define PHASE_RESPONSE_BODY 4
|
||||||
#define PHASE_LOGGING 5
|
#define PHASE_LOGGING 5
|
||||||
|
|
||||||
#define FN_OP_PARAM_INIT(X) int (*X)(msre_rule *rule, char **error_msg)
|
typedef int (*fn_op_param_init_t)(msre_rule *rule, char **error_msg);
|
||||||
#define FN_OP_EXECUTE(X) int (*X)(modsec_rec *msr, msre_rule *rule, msre_var *var, 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 {
|
struct msre_op_metadata {
|
||||||
const char *name;
|
const char *name;
|
||||||
FN_OP_PARAM_INIT (param_init);
|
fn_op_param_init_t param_init;
|
||||||
FN_OP_EXECUTE (execute);
|
fn_op_execute_t execute;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FN_TFN_EXECUTE(X) int (*X)(apr_pool_t *pool, unsigned char *input, long int input_length, char **rval, long int *rval_length)
|
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 {
|
struct msre_tfn_metadata {
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -167,14 +208,14 @@ struct msre_tfn_metadata {
|
|||||||
*
|
*
|
||||||
* NOTE Strict transformation functions not supported yet.
|
* NOTE Strict transformation functions not supported yet.
|
||||||
*/
|
*/
|
||||||
FN_TFN_EXECUTE(execute);
|
fn_tfn_execute_t execute;
|
||||||
};
|
};
|
||||||
|
|
||||||
void DSOLOCAL msre_engine_tfn_register(msre_engine *engine, const char *name,
|
void DSOLOCAL msre_engine_tfn_register(msre_engine *engine, const char *name,
|
||||||
FN_TFN_EXECUTE(execute));
|
fn_tfn_execute_t execute);
|
||||||
|
|
||||||
void DSOLOCAL msre_engine_op_register(msre_engine *engine, const char *name,
|
void DSOLOCAL msre_engine_op_register(msre_engine *engine, const char *name,
|
||||||
FN_OP_PARAM_INIT(fn1), FN_OP_EXECUTE(fn2));
|
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_tfns(msre_engine *engine);
|
||||||
|
|
||||||
@@ -189,16 +230,16 @@ msre_tfn_metadata DSOLOCAL *msre_engine_tfn_resolve(msre_engine *engine, const c
|
|||||||
#define VAR_DONT_CACHE 0
|
#define VAR_DONT_CACHE 0
|
||||||
#define VAR_CACHE 1
|
#define VAR_CACHE 1
|
||||||
|
|
||||||
#define FN_VAR_VALIDATE(X) char *(*X)(msre_ruleset *ruleset, msre_var *var)
|
typedef char *(*fn_var_validate_t)(msre_ruleset *ruleset, msre_var *var);
|
||||||
#define FN_VAR_GENERATE(X) int (*X)(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *table, apr_pool_t *mptmp)
|
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 {
|
struct msre_var_metadata {
|
||||||
const char *name;
|
const char *name;
|
||||||
unsigned int type; /* VAR_TYPE_ constants */
|
unsigned int type; /* VAR_TYPE_ constants */
|
||||||
unsigned int argc_min;
|
unsigned int argc_min;
|
||||||
unsigned int argc_max;
|
unsigned int argc_max;
|
||||||
FN_VAR_VALIDATE (validate);
|
fn_var_validate_t validate;
|
||||||
FN_VAR_GENERATE (generate);
|
fn_var_generate_t generate;
|
||||||
unsigned int is_cacheable; /* 0 - no, 1 - yes */
|
unsigned int is_cacheable; /* 0 - no, 1 - yes */
|
||||||
unsigned int availability; /* when does this variable become available? */
|
unsigned int availability; /* when does this variable become available? */
|
||||||
};
|
};
|
||||||
@@ -223,6 +264,7 @@ struct msre_actionset {
|
|||||||
const char *id;
|
const char *id;
|
||||||
const char *rev;
|
const char *rev;
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
const char *logdata;
|
||||||
int severity;
|
int severity;
|
||||||
int phase;
|
int phase;
|
||||||
msre_rule *rule;
|
msre_rule *rule;
|
||||||
@@ -230,6 +272,7 @@ struct msre_actionset {
|
|||||||
/* Flow */
|
/* Flow */
|
||||||
int is_chained;
|
int is_chained;
|
||||||
int skip_count;
|
int skip_count;
|
||||||
|
const char *skip_after;
|
||||||
|
|
||||||
/* Disruptive */
|
/* Disruptive */
|
||||||
int intercept_action;
|
int intercept_action;
|
||||||
@@ -237,14 +280,22 @@ struct msre_actionset {
|
|||||||
int intercept_status;
|
int intercept_status;
|
||||||
int intercept_pause;
|
int 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 */
|
/* Other */
|
||||||
int log;
|
int log;
|
||||||
int auditlog;
|
int auditlog;
|
||||||
|
int block;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
char DSOLOCAL *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_actionset *actionset);
|
||||||
|
|
||||||
void DSOLOCAL msre_engine_variable_register(msre_engine *engine, const char *name,
|
void DSOLOCAL msre_engine_variable_register(msre_engine *engine, const char *name,
|
||||||
unsigned int type, unsigned int argc_min, unsigned int argc_max,
|
unsigned int type, unsigned int argc_min, unsigned int argc_max,
|
||||||
FN_VAR_VALIDATE(validate), FN_VAR_GENERATE(generate),
|
fn_var_validate_t validate, fn_var_generate_t generate,
|
||||||
unsigned int is_cacheable, unsigned int availability);
|
unsigned int is_cacheable, unsigned int availability);
|
||||||
|
|
||||||
msre_actionset DSOLOCAL *msre_actionset_create(msre_engine *engine, const char *text,
|
msre_actionset DSOLOCAL *msre_actionset_create(msre_engine *engine, const char *text,
|
||||||
@@ -255,11 +306,13 @@ msre_actionset DSOLOCAL *msre_actionset_merge(msre_engine *engine, msre_actionse
|
|||||||
|
|
||||||
msre_actionset DSOLOCAL *msre_actionset_create_default(msre_engine *engine);
|
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);
|
void DSOLOCAL msre_actionset_init(msre_actionset *actionset, msre_rule *rule);
|
||||||
|
|
||||||
#define FN_ACTION_VALIDATE(X) char *(*X)(msre_engine *engine, msre_action *action)
|
typedef char *(*fn_action_validate_t)(msre_engine *engine, msre_action *action);
|
||||||
#define FN_ACTION_INIT(X) apr_status_t (*X)(msre_engine *engine, msre_actionset *actionset, msre_action *action)
|
typedef apr_status_t (*fn_action_init_t)(msre_engine *engine, msre_actionset *actionset, msre_action *action);
|
||||||
#define FN_ACTION_EXECUTE(X) apr_status_t (*X)(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, 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_DISRUPTIVE 1
|
||||||
#define ACTION_NON_DISRUPTIVE 2
|
#define ACTION_NON_DISRUPTIVE 2
|
||||||
@@ -272,6 +325,11 @@ void DSOLOCAL msre_actionset_init(msre_actionset *actionset, msre_rule *rule);
|
|||||||
#define ACTION_CARDINALITY_ONE 1
|
#define ACTION_CARDINALITY_ONE 1
|
||||||
#define ACTION_CARDINALITY_MANY 2
|
#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 {
|
struct msre_action_metadata {
|
||||||
const char *name;
|
const char *name;
|
||||||
unsigned int type;
|
unsigned int type;
|
||||||
@@ -279,9 +337,10 @@ struct msre_action_metadata {
|
|||||||
unsigned int argc_max;
|
unsigned int argc_max;
|
||||||
unsigned int allow_param_plusminus;
|
unsigned int allow_param_plusminus;
|
||||||
unsigned int cardinality;
|
unsigned int cardinality;
|
||||||
FN_ACTION_VALIDATE (validate);
|
unsigned int cardinality_group;
|
||||||
FN_ACTION_INIT (init);
|
fn_action_validate_t validate;
|
||||||
FN_ACTION_EXECUTE (execute);
|
fn_action_init_t init;
|
||||||
|
fn_action_execute_t execute;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct msre_action {
|
struct msre_action {
|
||||||
@@ -309,7 +368,8 @@ char DSOLOCAL *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset);
|
|||||||
struct msre_cache_rec {
|
struct msre_cache_rec {
|
||||||
int hits;
|
int hits;
|
||||||
int changed;
|
int changed;
|
||||||
const char *key;
|
int num;
|
||||||
|
const char *path;
|
||||||
const char *val;
|
const char *val;
|
||||||
apr_size_t val_len;
|
apr_size_t val_len;
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
|
* Copyright (c) 2004-2008 Breach Security, Inc. (http://www.breach.com/)
|
||||||
*
|
*
|
||||||
* You should have received a copy of the licence along with this
|
* You should have received a copy of the licence along with this
|
||||||
* program (stored in the file "LICENSE"). If the file is missing,
|
* program (stored in the file "LICENSE"). If the file is missing,
|
||||||
@@ -158,13 +158,16 @@ static int msre_fn_compressWhitespace_execute(apr_pool_t *mptmp, unsigned char *
|
|||||||
{
|
{
|
||||||
long int i, j, count;
|
long int i, j, count;
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
|
int inwhitespace = 0;
|
||||||
|
|
||||||
i = j = count = 0;
|
i = j = count = 0;
|
||||||
while(i < input_len) {
|
while(i < input_len) {
|
||||||
if (isspace(input[i])||(input[i] == NBSP)) {
|
if (isspace(input[i])||(input[i] == NBSP)) {
|
||||||
changed = 1;
|
if (inwhitespace) changed = 1;
|
||||||
|
inwhitespace = 1;
|
||||||
count++;
|
count++;
|
||||||
} else {
|
} else {
|
||||||
|
inwhitespace = 0;
|
||||||
if (count) {
|
if (count) {
|
||||||
input[j] = ' ';
|
input[j] = ' ';
|
||||||
count = 0;
|
count = 0;
|
||||||
@@ -245,12 +248,30 @@ static int msre_fn_replaceComments_execute(apr_pool_t *mptmp, unsigned char *inp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (incomment) {
|
||||||
|
input[j++] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
*rval = (char *)input;
|
*rval = (char *)input;
|
||||||
*rval_len = j;
|
*rval_len = j;
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* jsDecode */
|
||||||
|
|
||||||
|
static int msre_fn_jsDecode_execute(apr_pool_t *mptmp, unsigned char *input,
|
||||||
|
long int input_len, char **rval, long int *rval_len)
|
||||||
|
{
|
||||||
|
long int length;
|
||||||
|
|
||||||
|
length = js_decode_nonstrict_inplace(input, input_len);
|
||||||
|
*rval = (char *)input;
|
||||||
|
*rval_len = length;
|
||||||
|
|
||||||
|
return (*rval_len == input_len ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* urlDecode */
|
/* urlDecode */
|
||||||
|
|
||||||
static int msre_fn_urlDecode_execute(apr_pool_t *mptmp, unsigned char *input,
|
static int msre_fn_urlDecode_execute(apr_pool_t *mptmp, unsigned char *input,
|
||||||
@@ -258,12 +279,13 @@ static int msre_fn_urlDecode_execute(apr_pool_t *mptmp, unsigned char *input,
|
|||||||
{
|
{
|
||||||
long int length;
|
long int length;
|
||||||
int invalid_count;
|
int invalid_count;
|
||||||
|
int changed;
|
||||||
|
|
||||||
length = urldecode_nonstrict_inplace_ex(input, input_len, &invalid_count);
|
length = urldecode_nonstrict_inplace_ex(input, input_len, &invalid_count, &changed);
|
||||||
*rval = (char *)input;
|
*rval = (char *)input;
|
||||||
*rval_len = length;
|
*rval_len = length;
|
||||||
|
|
||||||
return (*rval_len == input_len ? 0 : 1);
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* urlDecodeUni */
|
/* urlDecodeUni */
|
||||||
@@ -272,12 +294,13 @@ static int msre_fn_urlDecodeUni_execute(apr_pool_t *mptmp, unsigned char *input,
|
|||||||
long int input_len, char **rval, long int *rval_len)
|
long int input_len, char **rval, long int *rval_len)
|
||||||
{
|
{
|
||||||
long int length;
|
long int length;
|
||||||
|
int changed;
|
||||||
|
|
||||||
length = urldecode_uni_nonstrict_inplace_ex(input, input_len);
|
length = urldecode_uni_nonstrict_inplace_ex(input, input_len, &changed);
|
||||||
*rval = (char *)input;
|
*rval = (char *)input;
|
||||||
*rval_len = length;
|
*rval_len = length;
|
||||||
|
|
||||||
return (*rval_len == input_len ? 0 : 1);
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* urlEncode */
|
/* urlEncode */
|
||||||
@@ -285,10 +308,12 @@ static int msre_fn_urlDecodeUni_execute(apr_pool_t *mptmp, unsigned char *input,
|
|||||||
static int msre_fn_urlEncode_execute(apr_pool_t *mptmp, unsigned char *input,
|
static int msre_fn_urlEncode_execute(apr_pool_t *mptmp, unsigned char *input,
|
||||||
long int input_len, char **rval, long int *rval_len)
|
long int input_len, char **rval, long int *rval_len)
|
||||||
{
|
{
|
||||||
*rval = url_encode(mptmp, (char *)input, input_len);
|
int changed;
|
||||||
|
|
||||||
|
*rval = url_encode(mptmp, (char *)input, input_len, &changed);
|
||||||
*rval_len = strlen(*rval);
|
*rval_len = strlen(*rval);
|
||||||
|
|
||||||
return (*rval_len == input_len ? 0 : 1);
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* base64Encode */
|
/* base64Encode */
|
||||||
@@ -301,7 +326,7 @@ static int msre_fn_base64Encode_execute(apr_pool_t *mptmp, unsigned char *input,
|
|||||||
apr_base64_encode(*rval, (const char *)input, input_len);
|
apr_base64_encode(*rval, (const char *)input, input_len);
|
||||||
(*rval_len)--;
|
(*rval_len)--;
|
||||||
|
|
||||||
return 1;
|
return *rval_len ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* base64Decode */
|
/* base64Decode */
|
||||||
@@ -311,10 +336,9 @@ static int msre_fn_base64Decode_execute(apr_pool_t *mptmp, unsigned char *input,
|
|||||||
{
|
{
|
||||||
*rval_len = apr_base64_decode_len((const char *)input); /* returns len with NULL byte included */
|
*rval_len = apr_base64_decode_len((const char *)input); /* returns len with NULL byte included */
|
||||||
*rval = apr_palloc(mptmp, *rval_len);
|
*rval = apr_palloc(mptmp, *rval_len);
|
||||||
apr_base64_decode(*rval, (const char *)input);
|
*rval_len = apr_base64_decode(*rval, (const char *)input);
|
||||||
(*rval_len)--;
|
|
||||||
|
|
||||||
return 1;
|
return *rval_len ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* length */
|
/* length */
|
||||||
@@ -410,10 +434,12 @@ static int msre_fn_escapeSeqDecode_execute(apr_pool_t *mptmp, unsigned char *inp
|
|||||||
static int msre_fn_normalisePath_execute(apr_pool_t *mptmp, unsigned char *input,
|
static int msre_fn_normalisePath_execute(apr_pool_t *mptmp, unsigned char *input,
|
||||||
long int input_len, char **rval, long int *rval_len)
|
long int input_len, char **rval, long int *rval_len)
|
||||||
{
|
{
|
||||||
*rval_len = normalise_path_inplace(input, input_len, 0);
|
int changed;
|
||||||
|
|
||||||
|
*rval_len = normalise_path_inplace(input, input_len, 0, &changed);
|
||||||
*rval = (char *)input;
|
*rval = (char *)input;
|
||||||
|
|
||||||
return (*rval_len == input_len ? 0 : 1);
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* normalisePathWin */
|
/* normalisePathWin */
|
||||||
@@ -421,10 +447,12 @@ static int msre_fn_normalisePath_execute(apr_pool_t *mptmp, unsigned char *input
|
|||||||
static int msre_fn_normalisePathWin_execute(apr_pool_t *mptmp, unsigned char *input,
|
static int msre_fn_normalisePathWin_execute(apr_pool_t *mptmp, unsigned char *input,
|
||||||
long int input_len, char **rval, long int *rval_len)
|
long int input_len, char **rval, long int *rval_len)
|
||||||
{
|
{
|
||||||
*rval_len = normalise_path_inplace(input, input_len, 1);
|
int changed;
|
||||||
|
|
||||||
|
*rval_len = normalise_path_inplace(input, input_len, 1, &changed);
|
||||||
*rval = (char *)input;
|
*rval = (char *)input;
|
||||||
|
|
||||||
return (*rval_len == input_len ? 0 : 1);
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------------ */
|
||||||
@@ -433,7 +461,7 @@ static int msre_fn_normalisePathWin_execute(apr_pool_t *mptmp, unsigned char *in
|
|||||||
* Registers one transformation function with the engine.
|
* Registers one transformation function with the engine.
|
||||||
*/
|
*/
|
||||||
void msre_engine_tfn_register(msre_engine *engine, const char *name,
|
void msre_engine_tfn_register(msre_engine *engine, const char *name,
|
||||||
FN_TFN_EXECUTE(execute))
|
fn_tfn_execute_t execute)
|
||||||
{
|
{
|
||||||
msre_tfn_metadata *metadata = (msre_tfn_metadata *)apr_pcalloc(engine->mp,
|
msre_tfn_metadata *metadata = (msre_tfn_metadata *)apr_pcalloc(engine->mp,
|
||||||
sizeof(msre_tfn_metadata));
|
sizeof(msre_tfn_metadata));
|
||||||
@@ -505,6 +533,12 @@ void msre_engine_register_default_tfns(msre_engine *engine) {
|
|||||||
msre_fn_htmlEntityDecode_execute
|
msre_fn_htmlEntityDecode_execute
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* jsDecode */
|
||||||
|
msre_engine_tfn_register(engine,
|
||||||
|
"jsDecode",
|
||||||
|
msre_fn_jsDecode_execute
|
||||||
|
);
|
||||||
|
|
||||||
/* length */
|
/* length */
|
||||||
msre_engine_tfn_register(engine,
|
msre_engine_tfn_register(engine,
|
||||||
"length",
|
"length",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
45
apache2/t/op/beginsWith.t
Normal file
45
apache2/t/op/beginsWith.t
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "beginsWith",
|
||||||
|
param => "",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "beginsWith",
|
||||||
|
param => "TestCase",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "beginsWith",
|
||||||
|
param => "",
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "beginsWith",
|
||||||
|
param => "abcdef",
|
||||||
|
input => "abcdef",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "beginsWith",
|
||||||
|
param => "abcdef",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "beginsWith",
|
||||||
|
param => "abcdef",
|
||||||
|
input => "abc",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
73
apache2/t/op/contains.t
Normal file
73
apache2/t/op/contains.t
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "contains",
|
||||||
|
param => "",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "contains",
|
||||||
|
param => "TestCase",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "contains",
|
||||||
|
param => "",
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "contains",
|
||||||
|
param => "abc",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "contains",
|
||||||
|
param => "def",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "contains",
|
||||||
|
param => "ghi",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "contains",
|
||||||
|
param => "ghij",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "contains",
|
||||||
|
param => "x",
|
||||||
|
input => "x",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "contains",
|
||||||
|
param => "y",
|
||||||
|
input => "xyz",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "contains",
|
||||||
|
param => "hiding",
|
||||||
|
input => "hidinX<-not quite, but is later on->hiding",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
108
apache2/t/op/containsWord.t
Normal file
108
apache2/t/op/containsWord.t
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "TestCase",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "",
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "abc",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "def",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "ghi",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "abc",
|
||||||
|
input => "abc def ghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "def",
|
||||||
|
input => "abc def ghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "ghi",
|
||||||
|
input => "abc def ghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "abc",
|
||||||
|
input => "abc\0def ghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "def",
|
||||||
|
input => "abc\0def ghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "x",
|
||||||
|
input => "x",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "x",
|
||||||
|
input => " x ",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "y",
|
||||||
|
input => "xyz",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "containsWord",
|
||||||
|
param => "hiding",
|
||||||
|
input => "hidingX<-not on word boundary, but is later on->hiding",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
52
apache2/t/op/endsWith.t
Normal file
52
apache2/t/op/endsWith.t
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "endsWith",
|
||||||
|
param => "",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "endsWith",
|
||||||
|
param => "TestCase",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "endsWith",
|
||||||
|
param => "",
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "endsWith",
|
||||||
|
param => "abc",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "endsWith",
|
||||||
|
param => "def",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "endsWith",
|
||||||
|
param => "ghi",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "endsWith",
|
||||||
|
param => "ghi",
|
||||||
|
input => "abcdef\0ghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
101
apache2/t/op/eq.t
Normal file
101
apache2/t/op/eq.t
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "eq",
|
||||||
|
param => "0",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "eq",
|
||||||
|
param => "5",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Invalid
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "eq",
|
||||||
|
param => "xxx",
|
||||||
|
input => "0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "eq",
|
||||||
|
param => "xxx",
|
||||||
|
input => "5",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "eq",
|
||||||
|
param => "xxx",
|
||||||
|
input => "-1",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "eq",
|
||||||
|
param => "0",
|
||||||
|
input => "xxx",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "eq",
|
||||||
|
param => "5",
|
||||||
|
input => "xxx",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "eq",
|
||||||
|
param => "0",
|
||||||
|
input => "-5",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "eq",
|
||||||
|
param => "0",
|
||||||
|
input => "0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "eq",
|
||||||
|
param => "0",
|
||||||
|
input => "5",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "eq",
|
||||||
|
param => "5",
|
||||||
|
input => "0",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "eq",
|
||||||
|
param => "5",
|
||||||
|
input => "5",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "eq",
|
||||||
|
param => "5",
|
||||||
|
input => "10",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
93
apache2/t/op/ge.t
Normal file
93
apache2/t/op/ge.t
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "ge",
|
||||||
|
param => "0",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "ge",
|
||||||
|
param => "5",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Invalid
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "ge",
|
||||||
|
param => "xxx",
|
||||||
|
input => "5",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "ge",
|
||||||
|
param => "xxx",
|
||||||
|
input => "-1",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "ge",
|
||||||
|
param => "0",
|
||||||
|
input => "xxx",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "ge",
|
||||||
|
param => "5",
|
||||||
|
input => "xxx",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "ge",
|
||||||
|
param => "0",
|
||||||
|
input => "-5",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "ge",
|
||||||
|
param => "0",
|
||||||
|
input => "0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "ge",
|
||||||
|
param => "0",
|
||||||
|
input => "5",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "ge",
|
||||||
|
param => "5",
|
||||||
|
input => "0",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "ge",
|
||||||
|
param => "5",
|
||||||
|
input => "5",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "ge",
|
||||||
|
param => "5",
|
||||||
|
input => "10",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
1
apache2/t/op/geoLookup.t
Normal file
1
apache2/t/op/geoLookup.t
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
93
apache2/t/op/gt.t
Normal file
93
apache2/t/op/gt.t
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "gt",
|
||||||
|
param => "0",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "gt",
|
||||||
|
param => "5",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Invalid
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "gt",
|
||||||
|
param => "xxx",
|
||||||
|
input => "5",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "gt",
|
||||||
|
param => "xxx",
|
||||||
|
input => "-1",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "gt",
|
||||||
|
param => "-1",
|
||||||
|
input => "xxx",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "gt",
|
||||||
|
param => "5",
|
||||||
|
input => "xxx",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "gt",
|
||||||
|
param => "0",
|
||||||
|
input => "-5",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "gt",
|
||||||
|
param => "0",
|
||||||
|
input => "0",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "gt",
|
||||||
|
param => "0",
|
||||||
|
input => "5",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "gt",
|
||||||
|
param => "5",
|
||||||
|
input => "0",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "gt",
|
||||||
|
param => "5",
|
||||||
|
input => "5",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "gt",
|
||||||
|
param => "5",
|
||||||
|
input => "10",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
1
apache2/t/op/inspectFile.t
Normal file
1
apache2/t/op/inspectFile.t
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
93
apache2/t/op/le.t
Normal file
93
apache2/t/op/le.t
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "le",
|
||||||
|
param => "0",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "le",
|
||||||
|
param => "5",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Invalid
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "le",
|
||||||
|
param => "xxx",
|
||||||
|
input => "5",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "le",
|
||||||
|
param => "xxx",
|
||||||
|
input => "-1",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "le",
|
||||||
|
param => "0",
|
||||||
|
input => "xxx",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "le",
|
||||||
|
param => "5",
|
||||||
|
input => "xxx",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "le",
|
||||||
|
param => "0",
|
||||||
|
input => "-5",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "le",
|
||||||
|
param => "0",
|
||||||
|
input => "0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "le",
|
||||||
|
param => "0",
|
||||||
|
input => "5",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "le",
|
||||||
|
param => "5",
|
||||||
|
input => "0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "le",
|
||||||
|
param => "5",
|
||||||
|
input => "5",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "le",
|
||||||
|
param => "5",
|
||||||
|
input => "10",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
93
apache2/t/op/lt.t
Normal file
93
apache2/t/op/lt.t
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "lt",
|
||||||
|
param => "0",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "lt",
|
||||||
|
param => "5",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Invalid
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "lt",
|
||||||
|
param => "xxx",
|
||||||
|
input => "5",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "lt",
|
||||||
|
param => "xxx",
|
||||||
|
input => "-1",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "lt",
|
||||||
|
param => "-1",
|
||||||
|
input => "xxx",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# xxx interpreted as 0
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "lt",
|
||||||
|
param => "5",
|
||||||
|
input => "xxx",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "lt",
|
||||||
|
param => "0",
|
||||||
|
input => "-5",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "lt",
|
||||||
|
param => "0",
|
||||||
|
input => "0",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "lt",
|
||||||
|
param => "0",
|
||||||
|
input => "5",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "lt",
|
||||||
|
param => "5",
|
||||||
|
input => "0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "lt",
|
||||||
|
param => "5",
|
||||||
|
input => "5",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "lt",
|
||||||
|
param => "5",
|
||||||
|
input => "10",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
52
apache2/t/op/m.t
Normal file
52
apache2/t/op/m.t
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "m",
|
||||||
|
param => "",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "m",
|
||||||
|
param => "TestCase",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "m",
|
||||||
|
param => "",
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "m",
|
||||||
|
param => "abc",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "m",
|
||||||
|
param => "def",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "m",
|
||||||
|
param => "ghi",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "m",
|
||||||
|
param => "ghij",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
23
apache2/t/op/noMatch.t
Normal file
23
apache2/t/op/noMatch.t
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "noMatch",
|
||||||
|
param => "",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "noMatch",
|
||||||
|
param => "TestCase",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "noMatch",
|
||||||
|
param => "",
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
112
apache2/t/op/pm.t
Normal file
112
apache2/t/op/pm.t
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "TestCase",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "abc",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "def",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "ghi",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "ghij",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Multiple
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "abc def ghi",
|
||||||
|
input => "abcxxxyyy",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "abc def ghi",
|
||||||
|
input => "xxxabcyyy",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "abc def ghi",
|
||||||
|
input => "xxxyyyabc",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "abc def ghi",
|
||||||
|
input => "defxxxyyy",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "abc def ghi",
|
||||||
|
input => "xxxdefyyy",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "abc def ghi",
|
||||||
|
input => "xxxyyydef",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "abc def ghi",
|
||||||
|
input => "ghixxxyyy",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "abc def ghi",
|
||||||
|
input => "xxxghiyyy",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "abc def ghi",
|
||||||
|
input => "xxxyyyghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Long
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pm",
|
||||||
|
param => "000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999",
|
||||||
|
input => "xxxyyy999",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
4
apache2/t/op/pmFromFile-01.dat
Normal file
4
apache2/t/op/pmFromFile-01.dat
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
abc
|
||||||
|
def
|
||||||
|
ghi
|
||||||
|
xxx yyy zzz
|
||||||
45
apache2/t/op/pmFromFile.t
Normal file
45
apache2/t/op/pmFromFile.t
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
### No Match
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pmFromFile",
|
||||||
|
param => "op/pmFromFile-01.dat",
|
||||||
|
input => "xxxyyyzzz",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Multiple
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pmFromFile",
|
||||||
|
param => "op/pmFromFile-01.dat",
|
||||||
|
input => "defxxxyyy",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pmFromFile",
|
||||||
|
param => "op/pmFromFile-01.dat",
|
||||||
|
input => "xxxdefyyy",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pmFromFile",
|
||||||
|
param => "op/pmFromFile-01.dat",
|
||||||
|
input => "xxxyyydef",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pmFromFile",
|
||||||
|
param => "op/pmFromFile-01.dat",
|
||||||
|
input => "xxx yyy zzz",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "pmFromFile",
|
||||||
|
param => "op/pmFromFile-01.dat",
|
||||||
|
input => "xxx yyy",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
1
apache2/t/op/rbl.t
Normal file
1
apache2/t/op/rbl.t
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
62
apache2/t/op/rx.t
Normal file
62
apache2/t/op/rx.t
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "rx",
|
||||||
|
param => "",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "rx",
|
||||||
|
param => "TestCase",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "rx",
|
||||||
|
param => "",
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "rx",
|
||||||
|
param => "abc",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "rx",
|
||||||
|
param => "def",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "rx",
|
||||||
|
param => "ghi",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "rx",
|
||||||
|
param => "ghij",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Complex regex
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "rx",
|
||||||
|
param => qr/^([^=])\s*=\s*((?:abc)+(?:def|ghi){2})$/i,
|
||||||
|
input => "x =AbCDeFgHi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
52
apache2/t/op/streq.t
Normal file
52
apache2/t/op/streq.t
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "streq",
|
||||||
|
param => "",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "streq",
|
||||||
|
param => "TestCase",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "streq",
|
||||||
|
param => "",
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "streq",
|
||||||
|
param => "abc",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "streq",
|
||||||
|
param => "def",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "streq",
|
||||||
|
param => "ghi",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "streq",
|
||||||
|
param => "abcdefghi",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
23
apache2/t/op/unconditionalMatch.t
Normal file
23
apache2/t/op/unconditionalMatch.t
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "unconditionalMatch",
|
||||||
|
param => "",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "unconditionalMatch",
|
||||||
|
param => "TestCase",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "unconditionalMatch",
|
||||||
|
param => "",
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
54
apache2/t/op/validateByteRange.t
Normal file
54
apache2/t/op/validateByteRange.t
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateByteRange",
|
||||||
|
param => "0-255",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateByteRange",
|
||||||
|
param => "",
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Invalid
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateByteRange",
|
||||||
|
param => "xxx",
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateByteRange",
|
||||||
|
param => "xxx",
|
||||||
|
input => "\x00",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateByteRange",
|
||||||
|
param => "0-255",
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateByteRange",
|
||||||
|
param => ord("a")."-".ord("i"),
|
||||||
|
input => "abcdefghi",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateByteRange",
|
||||||
|
param => ord("a")."-".ord("i"),
|
||||||
|
input => "abcdefghij",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
1
apache2/t/op/validateDTD.t
Normal file
1
apache2/t/op/validateDTD.t
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
apache2/t/op/validateSchema.t
Normal file
1
apache2/t/op/validateSchema.t
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
101
apache2/t/op/validateUrlEncoding.t
Normal file
101
apache2/t/op/validateUrlEncoding.t
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "Hello%20World!",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "Hello+World!",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "HelloWorld!",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "%00Hello%20World!",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "Hello%20World!%00",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "%00",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "%ff",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "%0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "%f",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "%",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "%0z",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "%z0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUrlEncoding",
|
||||||
|
param => "",
|
||||||
|
input => "%0%",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
260
apache2/t/op/validateUtf8Encoding.t
Normal file
260
apache2/t/op/validateUtf8Encoding.t
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Valid "I can eat glass and it does not hurt me."
|
||||||
|
# Greek
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# French
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Je peux manger du verre, ça ne me fait pas de mal.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Spanish
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Puedo comer vidrio, no me hace daño.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Esparanto
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Mi povas manĝi vitron, ĝi ne damaĝas min.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Latin
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Ic mæg glæs eotan ond hit ne hearmiað me.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Serbian
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Могу јести стакло а да ми не шкоди.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Russian
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Я могу есть стекло, оно мне не вредит.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Armenian
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Կրնամ ապակի ուտել և ինծի անհանգիստ չըներ։",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Turkish
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "جام ييه بلورم بڭا ضررى طوقونمز",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Hindi
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "मैं काँच खा सकता हूँ, मुझे उस से कोई पीडा नहीं होती.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Arabic
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "أنا قادر على أكل الزجاج و هذا لا يؤلمني.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Hebrew
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "אני יכול לאכול זכוכית וזה לא מזיק לי.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Japanese
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "私はガラスを食べられます。それは私を傷つけません。",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Thai
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Korean
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "나는 유리를 먹을 수 있어요. 그래도 아프지 않아요",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Navajo
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Tsésǫʼ yishą́ągo bííníshghah dóó doo shił neezgai da.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Icelandic
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Ég get etið gler án þess að meiða mig.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Sanskrit
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम् ॥",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# English Braille
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "⠊⠀⠉⠁⠝⠀⠑⠁⠞⠀⠛⠇⠁⠎⠎⠀⠁⠝⠙⠀⠊⠞⠀⠙⠕⠑⠎⠝⠞⠀⠓⠥⠗⠞⠀⠍⠑",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Danish
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Jeg kan spise glas, det gør ikke ondt på mig.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Hungarian
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Meg tudom enni az üveget, nem lesz tőle bajom.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Estonian
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Ma võin klaasi süüa, see ei tee mulle midagi.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Czech
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Mohu jíst sklo, neublíží mi.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Slovak
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Môžem jesť sklo. Nezraní ma.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Polish
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "Mogę jeść szkło i mi nie szkodzi.",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# Symbols
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input=>"∮E⋅da=Qn→∞∑f(i)=∏g(i)∀x∈ℝ:⌈x⌉=−⌊−x⌋α∧¬β=¬(¬α∨β)ℕ⊆ℕ₀⊂ℤ⊂ℚ⊂ℝ⊂ℂ⊥<a≠b≡c≤d≪⊤⇒(A⇔B)2H₂+O₂⇌2H₂OR=4.7kΩ⌀200mm‘’“”'´`‚‘„“†‡‰•3–4—−5/+5™…1lI|0OD8B€",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
### Invalid
|
||||||
|
# Umlauted a
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "\x00\xe4",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# Umlauted a
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "\xe4",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
#
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "\x03\xbf",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
#
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "\xc9\x3b",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
### Invalid Full width
|
||||||
|
#
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "validateUtf8Encoding",
|
||||||
|
param => "",
|
||||||
|
input => "\xFF\x00",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
514
apache2/t/op/verifyCC.t
Normal file
514
apache2/t/op/verifyCC.t
Normal file
@@ -0,0 +1,514 @@
|
|||||||
|
### Empty
|
||||||
|
# empty w/re not matching empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => "\d+",
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# empty w/re matching empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '\d*',
|
||||||
|
input => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Non-matching
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### No digits in match
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => 'TestCase',
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Too generic RE w/no matchs (Luhn will be called until all fail)
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '.*',
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Test Good CC#
|
||||||
|
# Mastercard
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "5484605089158216",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "5574407071707154",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "5351341509714210",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "5585166974020647",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "5492180332479256",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "5111178142162816",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "5511424748431031",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "5259964281562326",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "5138342589974385",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "5362069587634979",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# VISA 16 digit
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4916545704601136",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4539501231827691",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4556338049595394",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4929326438756024",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4485432027326322",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4532104980682081",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4485974616349298",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4916580487207199",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4532009746910413",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4024007144622932",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# VISA 13 digit
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4556324125126",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4067482954141",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4532402654980",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4539709679875",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "4024007182237",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# American Express
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "343918934573386",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "344881778330710",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "345439478558905",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "346465614421111",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "372263817755618",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# Discover
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "6011402777433576",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "6011890045362751",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "6011439091242416",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# Diners Club
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "30162519308318",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "30311556856867",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "36850112043985",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# enRoute
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "201427829075664",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "201434726660424",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "201453368666085",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# JCB 15 digit
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "210091499965007",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "210072739882947",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "180013970064072",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# JCB 16 digit
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "3096676276259096",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "3158726040010070",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "3096531217494742",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# Voyager
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "869974262335041",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "869905005856398",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "869950500085465",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Test Bad CC#
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d+)(?:[^\d]|$)',
|
||||||
|
input => "1234567890012345",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Test regex + Luhn
|
||||||
|
# from http://www.merriampark.com/anatomycc.htm
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "4417123456789113",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "4408041234567893",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "4408041234567890",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "4417123456789112",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# on word boundary
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "a5484605089158216",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "a5484605089158216b",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "5484605089158216b",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# valid patterns
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "5484-6050-8915-8216",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# changed digit from table above
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "5484605089158217",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "5574407071807154",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# wrong patterns
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "5-484-6050-8915-8216",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "5484 6050 8915 8216",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# not on digits boundary
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "15484605089158216",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "154846050891582162",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "verifyCC",
|
||||||
|
param => '(?:^|[^\d])(\d{4}\-?\d{4}\-?\d{2}\-?\d{2}\-?\d{1,4})(?:[^\d]|$)',
|
||||||
|
input => "54846050891582162",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
52
apache2/t/op/within.t
Normal file
52
apache2/t/op/within.t
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "within",
|
||||||
|
param => "",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "within",
|
||||||
|
param => "TestCase",
|
||||||
|
input => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "within",
|
||||||
|
param => "",
|
||||||
|
input => "TestCase",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### General
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "within",
|
||||||
|
param => "abcdefghi",
|
||||||
|
input => "abc",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "within",
|
||||||
|
param => "abcdefghi",
|
||||||
|
input => "def",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "within",
|
||||||
|
param => "abcdefghi",
|
||||||
|
input => "ghi",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "op",
|
||||||
|
name => "within",
|
||||||
|
param => "abcdefghi",
|
||||||
|
input => "ghij",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
157
apache2/t/run-tests.pl.in
Executable file
157
apache2/t/run-tests.pl.in
Executable file
@@ -0,0 +1,157 @@
|
|||||||
|
#!@PERL@
|
||||||
|
#
|
||||||
|
# Run unit tests.
|
||||||
|
#
|
||||||
|
# Syntax:
|
||||||
|
# All: run-tests.pl
|
||||||
|
# All in file: run-tests.pl file
|
||||||
|
# Nth in file: run-tests.pl file N
|
||||||
|
#
|
||||||
|
use strict;
|
||||||
|
use POSIX qw(WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG);
|
||||||
|
use File::Basename qw(basename dirname);
|
||||||
|
use FileHandle;
|
||||||
|
use IPC::Open2 qw(open2);
|
||||||
|
|
||||||
|
my @TYPES = qw(tfn op);
|
||||||
|
my $TEST = "./msc_test";
|
||||||
|
my $SCRIPT = basename($0);
|
||||||
|
my $SCRIPTDIR = dirname($0);
|
||||||
|
my $PASSED = 0;
|
||||||
|
my $TOTAL = 0;
|
||||||
|
|
||||||
|
if (defined $ARGV[0]) {
|
||||||
|
runfile(dirname($ARGV[0]), basename($ARGV[0]), $ARGV[1]);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
|
for my $type (sort @TYPES) {
|
||||||
|
my $dir = "$SCRIPTDIR/$type";
|
||||||
|
my @cfg = ();
|
||||||
|
|
||||||
|
# Get test names
|
||||||
|
opendir(DIR, "$dir") or quit(1, "Failed to open \"$dir\": $!");
|
||||||
|
@cfg = grep { /\.t$/ && -f "$dir/$_" } readdir(DIR);
|
||||||
|
closedir(DIR);
|
||||||
|
|
||||||
|
for my $cfg (sort @cfg) {
|
||||||
|
runfile($dir, $cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
|
||||||
|
|
||||||
|
sub runfile {
|
||||||
|
my($dir, $cfg, $testnum) = @_;
|
||||||
|
my $fn = "$dir/$cfg";
|
||||||
|
my @data = ();
|
||||||
|
my $edata;
|
||||||
|
my @C = ();
|
||||||
|
my @test = ();
|
||||||
|
my $teststr;
|
||||||
|
my $n = 0;
|
||||||
|
my $pass = 0;
|
||||||
|
|
||||||
|
open(CFG, "<$fn") or quit(1, "Failed to open \"$fn\": $!");
|
||||||
|
@data = <CFG>;
|
||||||
|
|
||||||
|
$edata = q/@C = (/ . join("", @data) . q/)/;
|
||||||
|
eval $edata;
|
||||||
|
quit(1, "Failed to read test data \"$cfg\": $@") if ($@);
|
||||||
|
|
||||||
|
unless (@C) {
|
||||||
|
msg("\nNo tests defined for $fn");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg("\nLoaded ".@C." tests from $fn");
|
||||||
|
for my $t (@C) {
|
||||||
|
$n++;
|
||||||
|
next if (defined $testnum and $n != $testnum);
|
||||||
|
|
||||||
|
my %t = %{$t || {}};
|
||||||
|
my $id = sprintf("%6d", $n);
|
||||||
|
my $in = $t{input};
|
||||||
|
my $out;
|
||||||
|
my $test_in = new FileHandle();
|
||||||
|
my $test_out = new FileHandle();
|
||||||
|
my $test_pid;
|
||||||
|
my $rc = 0;
|
||||||
|
my $param;
|
||||||
|
|
||||||
|
if ($t{type} eq "tfn") {
|
||||||
|
$param = escape($t{output});
|
||||||
|
}
|
||||||
|
elsif ($t{type} eq "op") {
|
||||||
|
$param = escape($t{param});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
quit(1, "Unknown type \"$t{type}\" - should be one of: " . join(",",@TYPES));
|
||||||
|
}
|
||||||
|
|
||||||
|
@test = ($t{type}, $t{name}, $param, (exists($t{ret}) ? ($t{ret}) : ()));
|
||||||
|
$teststr = "$TEST " . join(" ", map { "\"$_\"" } @test);
|
||||||
|
$test_pid = open2($test_out, $test_in, $TEST, @test) or quit(1, "Failed to execute test: $teststr\": $!");
|
||||||
|
print $test_in "$in";
|
||||||
|
close $test_in;
|
||||||
|
$out = join("\\n", split(/\n/, <$test_out>));
|
||||||
|
close $test_out;
|
||||||
|
waitpid($test_pid, 0);
|
||||||
|
|
||||||
|
$rc = $?;
|
||||||
|
if ( WIFEXITED($rc) ) {
|
||||||
|
$rc = WEXITSTATUS($rc);
|
||||||
|
}
|
||||||
|
elsif( WIFSIGNALED($rc) ) {
|
||||||
|
msg("Test exited with signal " . WTERMSIG($rc) . ".");
|
||||||
|
msg("Executed: $teststr");
|
||||||
|
$rc = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
msg("Test exited with unknown error.");
|
||||||
|
$rc = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($rc == 0) {
|
||||||
|
$pass++;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg(sprintf("%s) %s \"%s\": %s%s", $id, $t{type}, $t{name}, ($rc ? "failed" : "passed"), ((defined($out) && $out ne "")? " ($out)" : "")));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$TOTAL += $testnum ? 1 : $n;
|
||||||
|
$PASSED += $pass;
|
||||||
|
|
||||||
|
msg(sprintf("Passed: %2d; Failed: %2d", $pass, $testnum ? (1 - $pass) : ($n - $pass)));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub escape {
|
||||||
|
my @new = ();
|
||||||
|
for my $c (split(//, $_[0])) {
|
||||||
|
push @new, ((ord($c) >= 0x20 and ord($c) <= 0x7e) ? $c : sprintf("\\x%02x", ord($c)));
|
||||||
|
}
|
||||||
|
join('', @new);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub msg {
|
||||||
|
print STDOUT "@_\n" if (@_);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub quit {
|
||||||
|
my($ec,$msg) = @_;
|
||||||
|
$ec = 0 unless (defined $_[0]);
|
||||||
|
|
||||||
|
msg("$msg") if (defined $msg);
|
||||||
|
|
||||||
|
exit $ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub done {
|
||||||
|
if ($PASSED != $TOTAL) {
|
||||||
|
quit(1, "\n$PASSED/$TOTAL tests passed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
quit(0, "\nAll tests passed ($TOTAL).");
|
||||||
|
}
|
||||||
51
apache2/t/tfn/base64Decode.t
Normal file
51
apache2/t/tfn/base64Decode.t
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "base64Decode",
|
||||||
|
input => "",
|
||||||
|
output => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Test values with varying lengths to check padding
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "base64Decode",
|
||||||
|
input => "VGVzdENhc2U=",
|
||||||
|
output => "TestCase",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "base64Decode",
|
||||||
|
input => "VGVzdENhc2Ux",
|
||||||
|
output => "TestCase1",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "base64Decode",
|
||||||
|
input => "VGVzdENhc2UxMg==",
|
||||||
|
output => "TestCase12",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
### Check with a NUL
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "base64Decode",
|
||||||
|
input => "VGVzdABDYXNl",
|
||||||
|
output => "Test\0Case",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Invalid
|
||||||
|
# What should happen here? Probably just fail and leave alone.
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "base64Decode",
|
||||||
|
input => "VGVzdENhc2U=\0VGVzdENhc2U=",
|
||||||
|
output => "TestCase",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
40
apache2/t/tfn/base64Encode.t
Normal file
40
apache2/t/tfn/base64Encode.t
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "base64Encode",
|
||||||
|
input => "",
|
||||||
|
output => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Test values with varying lengths to check padding
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "base64Encode",
|
||||||
|
input => "TestCase",
|
||||||
|
output => "VGVzdENhc2U=",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "base64Encode",
|
||||||
|
input => "TestCase1",
|
||||||
|
output => "VGVzdENhc2Ux",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "base64Encode",
|
||||||
|
input => "TestCase12",
|
||||||
|
output => "VGVzdENhc2UxMg==",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Check with a NUL
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "base64Encode",
|
||||||
|
input => "Test\0Case",
|
||||||
|
output => "VGVzdABDYXNl",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
50
apache2/t/tfn/compressWhitespace.t
Normal file
50
apache2/t/tfn/compressWhitespace.t
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "compressWhitespace",
|
||||||
|
input => "",
|
||||||
|
output => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Nothing
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "compressWhitespace",
|
||||||
|
input => "TestCase",
|
||||||
|
output => "TestCase",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "compressWhitespace",
|
||||||
|
input => "Test\0Case",
|
||||||
|
output => "Test\0Case",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "compressWhitespace",
|
||||||
|
input => "Test Case",
|
||||||
|
output => "Test Case",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
### Compress space/tab
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "compressWhitespace",
|
||||||
|
input => " Test \t Case ",
|
||||||
|
output => " Test Case ",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Pretty much everything in one
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "compressWhitespace",
|
||||||
|
input => "This is a test case with a tab \t, vtab \x0b, newline \x0a, return \x0d, formfeed \f, and a NUL\0 in it with a CRLF at the end.\x0d\x0a",
|
||||||
|
output => "This is a test case with a tab , vtab , newline , return , formfeed , and a NUL\0 in it with a CRLF at the end. ",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
114
apache2/t/tfn/escapeSeqDecode.t
Normal file
114
apache2/t/tfn/escapeSeqDecode.t
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "",
|
||||||
|
output => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Nothing
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "TestCase",
|
||||||
|
output => "TestCase",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "Test\0Case",
|
||||||
|
output => "Test\0Case",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Valid Sequences
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "\\a\\b\\f\\n\\r\\t\\v\\?\\'\\\"\\0\\12\\123\\x00\\xff",
|
||||||
|
output => "\a\b\f\x0a\x0d\t\x0b?'\"\x00\x0a\x53\x00\xff",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "\\a\\b\\f\\n\\r\\t\\v\0\\?\\'\\\"\\0\\12\\123\\x00\\xff",
|
||||||
|
output => "\a\b\f\x0a\x0d\t\x0b\0?'\"\x00\x0a\x53\x00\xff",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Invalid Sequences
|
||||||
|
# \8 and \9 are not octal
|
||||||
|
# \666 is a byte overflow (0x1b6) and should be truncated to a byte as 0xb6
|
||||||
|
# \xag and \xga are not hex,
|
||||||
|
# \0123 is \012 + '3'
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "\\8\\9\\666\\xag\\xga\\0123",
|
||||||
|
output => "89\xb6xagxga\x0a3",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
# \x, \x0 lack enough hex digits
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "\\x",
|
||||||
|
output => "x",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "\\x\\x0",
|
||||||
|
output => "xx0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "\\x\\x0\0",
|
||||||
|
output => "xx0\0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# Octal at end
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "\\0",
|
||||||
|
output => "\x00",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "\\01",
|
||||||
|
output => "\x01",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "\\012",
|
||||||
|
output => "\x0a",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# A forward slash with nothing after
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "\\",
|
||||||
|
output => "\\",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# A forward slash with NUL after
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "escapeSeqDecode",
|
||||||
|
input => "\\\0",
|
||||||
|
output => "\0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
50
apache2/t/tfn/hexDecode.t
Normal file
50
apache2/t/tfn/hexDecode.t
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "hexDecode",
|
||||||
|
input => "",
|
||||||
|
output => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Basic
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "hexDecode",
|
||||||
|
input => "5465737443617365",
|
||||||
|
output => "TestCase",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Basic w/NULL
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "hexDecode",
|
||||||
|
input => "546573740043617365",
|
||||||
|
output => "Test\0Case",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Invalid
|
||||||
|
# What should happen here? Probably just fail and leave alone.
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "hexDecode",
|
||||||
|
input => "01234567890a0z01234567890a",
|
||||||
|
output => "\x01#Eg\x89\x0a#\x01#Eg\x89\x0a",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "hexDecode",
|
||||||
|
input => "01234567890az",
|
||||||
|
output => "\x01#Eg\x89\x0a",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "hexDecode",
|
||||||
|
input => "01234567890a0",
|
||||||
|
output => "\x01#Eg\x89\x0a",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
26
apache2/t/tfn/hexEncode.t
Normal file
26
apache2/t/tfn/hexEncode.t
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "hexEncode",
|
||||||
|
input => "",
|
||||||
|
output => "",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Basic
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "hexEncode",
|
||||||
|
input => "TestCase",
|
||||||
|
output => "5465737443617365",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Basic w/NULL
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "hexEncode",
|
||||||
|
input => "Test\0Case",
|
||||||
|
output => "546573740043617365",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
58
apache2/t/tfn/htmlEntityDecode.t
Normal file
58
apache2/t/tfn/htmlEntityDecode.t
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "htmlEntityDecode",
|
||||||
|
input => "",
|
||||||
|
output => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Nothing
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "htmlEntityDecode",
|
||||||
|
input => "TestCase",
|
||||||
|
output => "TestCase",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "htmlEntityDecode",
|
||||||
|
input => "Test\0Case",
|
||||||
|
output => "Test\0Case",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Valid
|
||||||
|
# With ;
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "htmlEntityDecode",
|
||||||
|
input => "��  � \0d"&<> ",
|
||||||
|
output => "\0\0\x20\x20\0\x20\0\x64\"&<>\xa0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# Without ;
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "htmlEntityDecode",
|
||||||
|
input => "��  � \0d"&<> ",
|
||||||
|
output => "\0\0\x20\x20\0\x20\0\x64\"&<>\xa0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Invalid
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "htmlEntityDecode",
|
||||||
|
input => "&#xg;&#Xg;&#xg0;g;&#a;\0&#a2;a&#a00;a0;
a;&foo;",
|
||||||
|
output => "&#xg;&#Xg;&#xg0;\x02g;&#a;\0&#a2;\x03a&#a00;\x01a0;\x0aa;&foo;",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "htmlEntityDecode",
|
||||||
|
input => "&#xg&#Xg&#xg0g&#a\0&#a2a&#a00a0
a&foo",
|
||||||
|
output => "&#xg&#Xg&#xg0\x02g&#a\0&#a2\x03a&#a00\x01a0\x0aa&foo",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
129
apache2/t/tfn/jsDecode.t
Normal file
129
apache2/t/tfn/jsDecode.t
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "",
|
||||||
|
output => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Nothing
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "TestCase",
|
||||||
|
output => "TestCase",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "Test\0Case",
|
||||||
|
output => "Test\0Case",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Valid Sequences
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "\\a\\b\\f\\n\\r\\t\\v\\?\\'\\\"\\0\\12\\123\\x00\\xff\\u0021\\uff01",
|
||||||
|
output => "\a\b\f\x0a\x0d\t\x0b?'\"\x00\x0a\x53\x00\xff\x21\x21",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "\\a\\b\\f\\n\\r\\t\\v\0\\?\\'\\\"\\0\\12\\123\\x00\\xff\\u0021\\uff01",
|
||||||
|
output => "\a\b\f\x0a\x0d\t\x0b\0?'\"\x00\x0a\x53\x00\xff\x21\x21",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Invalid Sequences
|
||||||
|
# \8 and \9 are not octal
|
||||||
|
# \666 is \66 + '6' (JS does not allow the overflow as C does)
|
||||||
|
# \u00ag, \u00ga, \u0zaa, \uz0aa are not hex
|
||||||
|
# \xag and \xga are not hex,
|
||||||
|
# \0123 is \012 + '3'
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "\\8\\9\\666\\u00ag\\u00ga\\u0zaa\\uz0aa\\xag\\xga\\0123\\u00a",
|
||||||
|
output => "89\x366u00agu00gau0zaauz0aaxagxga\x0a3u00a",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
# \x, \x0 lack enough hex digits
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "\\x",
|
||||||
|
output => "x",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "\\x\\x0",
|
||||||
|
output => "xx0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "\\x\\x0\0",
|
||||||
|
output => "xx0\0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# \u, \u0 \u01, \u012 lack enough hex digits
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "\\u",
|
||||||
|
output => "u",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "\\u\\u0",
|
||||||
|
output => "uu0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "\\u\\u0\\u01",
|
||||||
|
output => "uu0u01",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "\\u\\u0\\u01\\u012",
|
||||||
|
output => "uu0u01u012",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "\\u\\u0\\u01\\u012\0",
|
||||||
|
output => "uu0u01u012\0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
# A forward slash with nothing after
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "\\",
|
||||||
|
output => "\\",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
# A forward slash with NUL after
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "jsDecode",
|
||||||
|
input => "\\\0",
|
||||||
|
output => "\0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
43
apache2/t/tfn/length.t
Normal file
43
apache2/t/tfn/length.t
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "length",
|
||||||
|
input => "",
|
||||||
|
output => "0",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
### Basic normal and large
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "length",
|
||||||
|
input => "0123456789abcdef",
|
||||||
|
output => "16",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "length",
|
||||||
|
input => ('x' x 8192),
|
||||||
|
output => "8192",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### With TAB
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "length",
|
||||||
|
input => "0123456789\tabcdef",
|
||||||
|
output => "17",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
### With NUL
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "length",
|
||||||
|
input => "Test\0Case",
|
||||||
|
output => "9",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
40
apache2/t/tfn/lowercase.t
Normal file
40
apache2/t/tfn/lowercase.t
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
### Empty
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "lowercase",
|
||||||
|
input => "",
|
||||||
|
output => "",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Nothing
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "lowercase",
|
||||||
|
input => "testcase",
|
||||||
|
output => "testcase",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "lowercase",
|
||||||
|
input => "test\0case",
|
||||||
|
output => "test\0case",
|
||||||
|
ret => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
### Basic
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "lowercase",
|
||||||
|
input => "TestCase",
|
||||||
|
output => "testcase",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type => "tfn",
|
||||||
|
name => "lowercase",
|
||||||
|
input => "Test\0Case",
|
||||||
|
output => "test\0case",
|
||||||
|
ret => 1,
|
||||||
|
},
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user