This commit is contained in:
brenosilva 2012-05-10 23:18:39 +00:00
Родитель 4bebeb6dd7
Коммит 866cb6d6b4
24 изменённых файлов: 4188 добавлений и 619 удалений

116
CHANGES
Просмотреть файл

@ -1,3 +1,117 @@
XX NNN 2012 - 2.7.0-rc1
-------------------
* Added SecEncryptionEngine. Initial crypt engine support, at the momment it will sign some Html
and Response Header options.
* Added SecEncryptionKey to define the a rand or static key for crypt engine.
* Added SecEncryptionParam to define the new parameter name.
* Added SecEncryptionMethodRx used with a regular expression to inspect the html in response
body/header and decide what to protect.
* Added SecEncryptionMethodPm used with multiple or single strings to inspect the html in response
body/header and decide what to protect.
* Added ctl encryptionEngine as a per transaction version of SecEncryptionEgine diretive.
* Added ctl encryptionEnforcement that will allow the engine to sign the data but the enforcement is
disabled.
* Added validateEncryption operator to enforce the signed elements.
* Added rsub operator supports the syntax |hex| allowing users to use special chars like \n \r.
* Added SecRuleUpdateTargetById now supports id range.
* Added SecRuleUpdateTargetByMsg and its ctl version (Thanks Scott Gifford).
* Added SecRuleUpdateTargetByTag and its ctl version (Thanks Scott Gifford).
* Added SecRulePerfTime when greater than zero it will fill rule id's execution time into PERF_RULE
and log id=usec information in the new Perf-rule-info: line in part H.
* Added PERF_RULES variable that contains rule execution time.
* Added Engine-mode: section in part H.
* Added ruleRemoveByMsg ctl version.
* Added removeCommentsChar and removeComments now can work with <!-- --> style.
* Added SecArgumentSeparator and SecCookieFormat can be used in different scope locations.
* Added Rules must have ID action and must be numeric.
* Added The use of tfns are deprecated in SecDefaultAction. Should be forbid in the future.
* Added Macro expansion support to the action pause.
* Added IpmatchFromFile/IpmatchF operator.
* Added New setrsc action, the RESOURCE collection used SecWebAppId Name Space
* Added Configure option --enable-cache-lua that allows reuse of Lua VM per transaction.
It will only take any effect when ModSecurity has multiple scripts to run per transaction.
* Added Configure option --enable-pcre-jit that allows ModSecurity regex engine to use PCRE Jit support.
* Added Configure option --enable-request-early that allows ModSecurity run phase 1 in post_read_request hook.
* Added RBL operator now support the httpBl api (http://www.projecthoneypot.org/httpbl_api.php).
* Added SecHttpBlKey to be used with httpBl api.
* Added SecSensorId will specify the modsecurity sensor name into audit log part H.
* Added aliases to phase:2 (phase:request), phase:4 (phase:response) and phase:5 (phase:logging).
* Added USERAGENT_IP variable. Created when Apache24 is used with mod_remoteip to know the real
client ip address.
* Fixed Variable DURATION contains the elapsed time in microseconds for compatible reasons with apache and
other variables.
* Fixed Preserve names/identity of the variables going into MATCHED_VARS.
* Fixed Redirect macro expansion does not work in SecDefaultAction when SecRule uses block action.
* Fixed rsub operator does not work as expect if regex contains parentheses (Thanks Jerome Freilinger).
* Current Google Safe Browsing implementation is deprecated. Google changed the API and does not allow
anymore the malware database for download.
20 Mar 2012 - 2.6.5
-------------------
* Fixed increased a specific message debug level in SBDM code (MODSEC-293).
* Cleanup build system.
09 Mar 2012 - 2.6.4
-------------------
* Fixed Mlogc 100% CPU consume (Thanks Klaubert Herr and Ebrahim Khalilzadeh).
* Fixed ModSecurity cannot load session and user sdbm data.
* Fixed updateTargetById was creating rule unparsed content making apache memory grow.
* Code cleanup.
23 Feb 2012 - 2.6.4-rc1
-------------------
* Fixed @rsub adding garbage data into stream variables.
* Fixed regex for section A into mlogc-batch-load.pl (Thanks Ebrahim Khalilzadeh).
* Fixed logdata cuts message without closing it with final chars.
* Added sanitizeMatchedBytes support to verifyCPF, verifyCC and verifySSN.
06 Dec 2011 - 2.6.3-rc1
-------------------
@ -29,7 +143,7 @@
* Added new transformations removeComments and removeCommentsChars
* Fixed collection names are not case-sensitive anymore.
* Fixed colletion names are not case-sensitive anymore.
* Fixed compilation errors with apache 2.0.

Просмотреть файл

@ -26,8 +26,9 @@ MAINTAINERCLEANFILES += $(CLEANFILES) \
ext/Makefile.in \
mlogc/Makefile.in \
modsecurity_config_auto.h.in~ \
tests/Makefile.in \
tools/Makefile.in
config.log \
Makefile \
config.status
# Alias for "check"
test: check

Просмотреть файл

@ -18,6 +18,9 @@
#include "msc_logging.h"
#include "msc_util.h"
#include "http_log.h"
#include "apr_lib.h"
#include "acmp.h"
#include "msc_crypt.h"
#if defined(WITH_LUA)
#include "msc_lua.h"
@ -64,10 +67,12 @@ void *create_directory_config(apr_pool_t *mp, char *path)
dcfg->rule_inheritance = NOT_SET;
dcfg->rule_exceptions = apr_array_make(mp, 16, sizeof(rule_exception *));
dcfg->encryption_method = apr_array_make(mp, 16, sizeof(encryption_method *));
/* audit log variables */
dcfg->auditlog_flag = NOT_SET;
dcfg->auditlog_type = NOT_SET;
dcfg->max_rule_time = NOT_SET;
dcfg->auditlog_dirperms = NOT_SET;
dcfg->auditlog_fileperms = NOT_SET;
dcfg->auditlog_name = NOT_SET_P;
@ -96,6 +101,7 @@ void *create_directory_config(apr_pool_t *mp, char *path)
/* Misc */
dcfg->data_dir = NOT_SET_P;
dcfg->webappid = NOT_SET_P;
dcfg->sensor_id = NOT_SET_P;
dcfg->httpBlkey = NOT_SET_P;
/* Content injection. */
@ -129,6 +135,23 @@ void *create_directory_config(apr_pool_t *mp, char *path)
/* Collection timeout */
dcfg->col_timeout = NOT_SET;
dcfg->crypto_key = NOT_SET_P;
dcfg->crypto_key_add = NOT_SET;
dcfg->crypto_param_name = NOT_SET_P;
dcfg->encryption_is_enabled = NOT_SET;
dcfg->encryption_enforcement = NOT_SET;
dcfg->crypto_hash_href_rx = NOT_SET;
dcfg->crypto_hash_faction_rx = NOT_SET;
dcfg->crypto_hash_location_rx = NOT_SET;
dcfg->crypto_hash_iframesrc_rx = NOT_SET;
dcfg->crypto_hash_framesrc_rx = NOT_SET;
dcfg->crypto_hash_href_pm = NOT_SET;
dcfg->crypto_hash_faction_pm = NOT_SET;
dcfg->crypto_hash_location_pm = NOT_SET;
dcfg->crypto_hash_iframesrc_pm = NOT_SET;
dcfg->crypto_hash_framesrc_pm = NOT_SET;
return dcfg;
}
@ -422,11 +445,16 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child)
merged->rule_exceptions = apr_array_append(mp, parent->rule_exceptions,
child->rule_exceptions);
merged->encryption_method = apr_array_append(mp, parent->encryption_method,
child->encryption_method);
/* audit log variables */
merged->auditlog_flag = (child->auditlog_flag == NOT_SET
? parent->auditlog_flag : child->auditlog_flag);
merged->auditlog_type = (child->auditlog_type == NOT_SET
? parent->auditlog_type : child->auditlog_type);
merged->max_rule_time = (child->max_rule_time == NOT_SET
? parent->max_rule_time : child->max_rule_time);
merged->auditlog_dirperms = (child->auditlog_dirperms == NOT_SET
? parent->auditlog_dirperms : child->auditlog_dirperms);
merged->auditlog_fileperms = (child->auditlog_fileperms == NOT_SET
@ -471,6 +499,8 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child)
? parent->data_dir : child->data_dir);
merged->webappid = (child->webappid == NOT_SET_P
? parent->webappid : child->webappid);
merged->sensor_id = (child->sensor_id == NOT_SET_P
? parent->sensor_id : child->sensor_id);
merged->httpBlkey = (child->httpBlkey == NOT_SET_P
? parent->httpBlkey : child->httpBlkey);
@ -521,6 +551,38 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child)
merged->col_timeout = (child->col_timeout == NOT_SET
? parent->col_timeout : child->col_timeout);
/* Encryption */
merged->crypto_key = (child->crypto_key == NOT_SET_P
? parent->crypto_key : child->crypto_key);
merged->crypto_key_add = (child->crypto_key_add == NOT_SET
? parent->crypto_key_add : child->crypto_key_add);
merged->crypto_param_name = (child->crypto_param_name == NOT_SET_P
? parent->crypto_param_name : child->crypto_param_name);
merged->encryption_is_enabled = (child->encryption_is_enabled == NOT_SET
? parent->encryption_is_enabled : child->encryption_is_enabled);
merged->encryption_enforcement = (child->encryption_enforcement == NOT_SET
? parent->encryption_enforcement : child->encryption_enforcement);
merged->crypto_hash_href_rx = (child->crypto_hash_href_rx == NOT_SET
? parent->crypto_hash_href_rx : child->crypto_hash_href_rx);
merged->crypto_hash_faction_rx = (child->crypto_hash_faction_rx == NOT_SET
? parent->crypto_hash_faction_rx : child->crypto_hash_faction_rx);
merged->crypto_hash_location_rx = (child->crypto_hash_location_rx == NOT_SET
? parent->crypto_hash_location_rx : child->crypto_hash_location_rx);
merged->crypto_hash_iframesrc_rx = (child->crypto_hash_iframesrc_rx == NOT_SET
? parent->crypto_hash_iframesrc_rx : child->crypto_hash_iframesrc_rx);
merged->crypto_hash_framesrc_rx = (child->crypto_hash_framesrc_rx == NOT_SET
? parent->crypto_hash_framesrc_rx : child->crypto_hash_framesrc_rx);
merged->crypto_hash_href_pm = (child->crypto_hash_href_pm == NOT_SET
? parent->crypto_hash_href_pm : child->crypto_hash_href_pm);
merged->crypto_hash_faction_pm = (child->crypto_hash_faction_pm == NOT_SET
? parent->crypto_hash_faction_pm : child->crypto_hash_faction_pm);
merged->crypto_hash_location_pm = (child->crypto_hash_location_pm == NOT_SET
? parent->crypto_hash_location_pm : child->crypto_hash_location_pm);
merged->crypto_hash_iframesrc_pm = (child->crypto_hash_iframesrc_pm == NOT_SET
? parent->crypto_hash_iframesrc_pm : child->crypto_hash_iframesrc_pm);
merged->crypto_hash_framesrc_pm = (child->crypto_hash_framesrc_pm == NOT_SET
? parent->crypto_hash_framesrc_pm : child->crypto_hash_framesrc_pm);
return merged;
}
@ -568,6 +630,7 @@ void init_directory_config(directory_config *dcfg)
/* audit log variables */
if (dcfg->auditlog_flag == NOT_SET) dcfg->auditlog_flag = 0;
if (dcfg->auditlog_type == NOT_SET) dcfg->auditlog_type = AUDITLOG_SERIAL;
if (dcfg->max_rule_time == NOT_SET) dcfg->max_rule_time = 0;
if (dcfg->auditlog_dirperms == NOT_SET) dcfg->auditlog_dirperms = CREATEMODE_DIR;
if (dcfg->auditlog_fileperms == NOT_SET) dcfg->auditlog_fileperms = CREATEMODE;
if (dcfg->auditlog_fd == NOT_SET_P) dcfg->auditlog_fd = NULL;
@ -589,6 +652,7 @@ void init_directory_config(directory_config *dcfg)
/* Misc */
if (dcfg->data_dir == NOT_SET_P) dcfg->data_dir = NULL;
if (dcfg->webappid == NOT_SET_P) dcfg->webappid = "default";
if (dcfg->sensor_id == NOT_SET_P) dcfg->sensor_id = "default";
if (dcfg->httpBlkey == NOT_SET_P) dcfg->httpBlkey = NULL;
/* Content injection. */
@ -619,6 +683,24 @@ void init_directory_config(directory_config *dcfg)
if (dcfg->disable_backend_compression == NOT_SET) dcfg->disable_backend_compression = 0;
if (dcfg->col_timeout == NOT_SET) dcfg->col_timeout = 3600;
/* Encryption */
if (dcfg->crypto_key == NOT_SET_P) dcfg->crypto_key = getkey(dcfg->mp);
if (dcfg->crypto_key_add == NOT_SET) dcfg->crypto_key_add = ENCRYPTION_KEYONLY;
if (dcfg->crypto_param_name == NOT_SET_P) dcfg->crypto_param_name = "crypt";
if (dcfg->encryption_is_enabled == NOT_SET) dcfg->encryption_is_enabled = ENCRYPTION_DISABLED;
if (dcfg->encryption_enforcement == NOT_SET) dcfg->encryption_enforcement = ENCRYPTION_DISABLED;
if (dcfg->crypto_hash_href_rx == NOT_SET) dcfg->crypto_hash_href_rx = 0;
if (dcfg->crypto_hash_faction_rx == NOT_SET) dcfg->crypto_hash_faction_rx = 0;
if (dcfg->crypto_hash_location_rx == NOT_SET) dcfg->crypto_hash_location_rx = 0;
if (dcfg->crypto_hash_iframesrc_rx == NOT_SET) dcfg->crypto_hash_iframesrc_rx = 0;
if (dcfg->crypto_hash_framesrc_rx == NOT_SET) dcfg->crypto_hash_framesrc_rx = 0;
if (dcfg->crypto_hash_href_pm == NOT_SET) dcfg->crypto_hash_href_pm = 0;
if (dcfg->crypto_hash_faction_pm == NOT_SET) dcfg->crypto_hash_faction_pm = 0;
if (dcfg->crypto_hash_location_pm == NOT_SET) dcfg->crypto_hash_location_pm = 0;
if (dcfg->crypto_hash_iframesrc_pm == NOT_SET) dcfg->crypto_hash_iframesrc_pm = 0;
if (dcfg->crypto_hash_framesrc_pm == NOT_SET) dcfg->crypto_hash_framesrc_pm = 0;
}
/**
@ -628,8 +710,9 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
const char *p1, const char *p2, const char *p3)
{
char *my_error_msg = NULL;
msre_rule *rule = NULL;
msre_rule *rule = NULL, *tmp_rule = NULL;
extern msc_engine *modsecurity;
int offset = 0;
#ifdef DEBUG_CONF
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
@ -660,6 +743,32 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
return my_error_msg;
}
/* Rules must have uniq ID */
if (
#if defined(WITH_LUA)
type != RULE_TYPE_LUA &&
#endif
(dcfg->tmp_chain_starter == NULL))
if(rule->actionset == NULL)
return "Rules must have at least id action";
if(rule->actionset != NULL && (dcfg->tmp_chain_starter == NULL)) {
if(rule->actionset->id == NOT_SET_P
#if defined(WITH_LUA)
&& (type != RULE_TYPE_LUA)
#endif
)
return "No action id present within the rule";
#if defined(WITH_LUA)
if(type != RULE_TYPE_LUA)
#endif
{
tmp_rule = msre_ruleset_fetch_rule(dcfg->ruleset, rule->actionset->id, offset);
if(tmp_rule != NULL)
return "Found another rule with the same id";
}
}
/* Create default actionset if one does not already exist. */
if (dcfg->tmp_default_actionset == NULL) {
dcfg->tmp_default_actionset = msre_actionset_create_default(modsecurity->msre);
@ -1261,6 +1370,16 @@ static const char *cmd_debug_log(cmd_parms *cmd, void *_dcfg, const char *p1)
return NULL;
}
/**
* \brief Add SecCollectionTimeout configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On Success
*/
static const char *cmd_collection_timeout(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
@ -1329,6 +1448,14 @@ static const char *cmd_default_action(cmd_parms *cmd, void *_dcfg,
cmd->directive->filename, cmd->directive->line_num);
}
if (apr_table_get(dcfg->tmp_default_actionset->actions, "t")) {
ap_log_perror(APLOG_MARK,
APLOG_STARTUP|APLOG_WARNING|APLOG_NOERRNO, 0, cmd->pool,
"ModSecurity: WARNING Using transformations in "
"SecDefaultAction is deprecated (%s:%d).",
cmd->directive->filename, cmd->directive->line_num);
}
/* Must not use chain. */
if (dcfg->tmp_default_actionset->is_chained != NOT_SET) {
return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
@ -1409,7 +1536,7 @@ static const char *cmd_guardian_log(cmd_parms *cmd, void *_dcfg,
return NULL;
}
/*
/**
* \brief Add SecStreamInBodyInspection configuration option
*
* \param cmd Pointer to configuration data
@ -1428,7 +1555,7 @@ static const char *cmd_stream_inbody_inspection(cmd_parms *cmd, void *_dcfg, int
}
/*
/**
* \brief Add SecStreamOutBodyInspection configuration option
*
* \param cmd Pointer to configuration data
@ -1445,8 +1572,35 @@ static const char *cmd_stream_outbody_inspection(cmd_parms *cmd, void *_dcfg, in
dcfg->stream_outbody_inspection = flag;
return NULL;
}
/**
* \brief Add SecRulePerfTime configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On Success
*/
static const char *cmd_rule_perf_time(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
directory_config *dcfg = (directory_config *)_dcfg;
long int limit;
/*
if (dcfg == NULL) return NULL;
limit = strtol(p1, NULL, 10);
if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRulePerfTime: %s", p1);
}
dcfg->max_rule_time = limit;
return NULL;
}
/**
* \brief Add SecReadStateLimit configuration option
*
* \param cmd Pointer to configuration data
@ -1474,7 +1628,7 @@ static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg,
return NULL;
}
/*
/**
* \brief Add SecWriteStateLimit configuration option
*
* \param cmd Pointer to configuration data
@ -1572,6 +1726,16 @@ static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg,
return NULL;
}
/**
* \brief Add SecInterceptOnError configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On success
*/
static const char *cmd_request_intercept_on_error(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
@ -1656,6 +1820,16 @@ static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg,
return NULL;
}
/**
* \brief Add SecRequestBodyLimitAction configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On success
*/
static const char *cmd_resquest_body_limit_action(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
@ -1709,23 +1883,107 @@ static const char *cmd_response_body_mime_types_clear(cmd_parms *cmd,
return NULL;
}
/*
* \brief Add SecRuleUpdateTargetById
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
* \param p2 Pointer to configuration option
* \param p3 Pointer to configuration option
*
* \retval NULL On failure|Success
*/
/**
* \brief Add SecRuleUpdateTargetById
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
* \param p2 Pointer to configuration option
* \param p3 Pointer to configuration option
*
* \retval NULL On failure|Success
*/
static const char *cmd_rule_update_target_by_id(cmd_parms *cmd, void *_dcfg,
const char *p1, const char *p2, const char *p3)
{
return update_rule_target(cmd, (directory_config *)_dcfg, NULL, p1, p2, p3);
directory_config *dcfg = (directory_config *)_dcfg;
rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
if (dcfg == NULL) return NULL;
if(p1 == NULL) {
return apr_psprintf(cmd->pool, "Updating target by ID with no ID");
}
re->type = RULE_EXCEPTION_REMOVE_ID;
/* TODO: Validate the range here, while we can still tell the user if it's invalid */
re->param = p1;
return msre_ruleset_rule_update_target_matching_exception(NULL, dcfg->ruleset, re, p2, p3);
}
/**
* \brief Add SecRuleUpdateTargetByTag configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option RULETAG
* \param p2 Pointer to configuration option TARGET
* \param p3 Pointer to configuration option REPLACED_TARGET
* \todo Finish documenting
*
* \retval NULL On success
* \retval apr_psprintf On failure
*
* \todo Figure out error checking
*/
static const char *cmd_rule_update_target_by_tag(cmd_parms *cmd, void *_dcfg,
const char *p1, const char *p2, const char *p3)
{
directory_config *dcfg = (directory_config *)_dcfg;
rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
if (dcfg == NULL) return NULL;
if(p1 == NULL) {
return apr_psprintf(cmd->pool, "Updating target by tag with no tag");
}
re->type = RULE_EXCEPTION_REMOVE_TAG;
re->param = p1;
re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
if (re->param_data == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
}
return msre_ruleset_rule_update_target_matching_exception(NULL, dcfg->ruleset, re, p2, p3);
}
/**
* \brief Add SecRuleUpdateTargetByMsg configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option RULEMSG
* \param p2 Pointer to configuration option TARGET
* \param p3 Pointer to configuration option REPLACED_TARGET
* \todo Finish documenting
*
* \retval NULL On success
* \retval apr_psprintf On failure
*
* \todo Figure out error checking
*/
static const char *cmd_rule_update_target_by_msg(cmd_parms *cmd, void *_dcfg,
const char *p1, const char *p2, const char *p3)
{
directory_config *dcfg = (directory_config *)_dcfg;
rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
if (dcfg == NULL) return NULL;
if(p1 == NULL) {
return apr_psprintf(cmd->pool, "Updating target by message with no message");
}
re->type = RULE_EXCEPTION_REMOVE_MSG;
re->param = p1;
re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
if (re->param_data == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
}
return msre_ruleset_rule_update_target_matching_exception(NULL, dcfg->ruleset, re, p2, p3);
}
static const char *cmd_rule(cmd_parms *cmd, void *_dcfg,
const char *p1, const char *p2, const char *p3)
{
@ -1788,6 +2046,16 @@ static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg,
return NULL;
}
/**
* \brief Add SecRuleRemoveByTag configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On success
*/
static const char *cmd_rule_remove_by_tag(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
@ -1965,6 +2233,277 @@ static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1)
return NULL;
}
static const char *cmd_sensor_id(cmd_parms *cmd, void *_dcfg, const char *p1)
{
directory_config *dcfg = (directory_config *)_dcfg;
/* ENH enforce format (letters, digits, ., _, -) */
dcfg->sensor_id = p1;
return NULL;
}
/**
* \brief Add SecEncryption configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On Success
*/
static const char *cmd_encryption_engine(cmd_parms *cmd, void *_dcfg, const char *p1)
{
directory_config *dcfg = (directory_config *)_dcfg;
if (dcfg == NULL) return NULL;
if (strcasecmp(p1, "on") == 0) {
dcfg->encryption_is_enabled = ENCRYPTION_ENABLED;
dcfg->encryption_enforcement = ENCRYPTION_ENABLED;
}
else if (strcasecmp(p1, "off") == 0) {
dcfg->encryption_is_enabled = ENCRYPTION_DISABLED;
dcfg->encryption_enforcement = ENCRYPTION_DISABLED;
}
else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRuleEngine: %s", p1);
return NULL;
}
/**
* \brief Add SecEncryptionPram configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On success
*/
static const char *cmd_encryption_param(cmd_parms *cmd, void *_dcfg, const char *p1)
{
directory_config *dcfg = (directory_config *)_dcfg;
if (dcfg == NULL) return NULL;
if (p1 == NULL) return NULL;
dcfg->crypto_param_name = p1;
return NULL;
}
/**
* \brief Add SecEncryptionKey configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param _p1 Pointer to configuration option
* \param _p2 Pointer to configuration option
*
* \retval NULL On success
*/
static const char *cmd_encryption_key(cmd_parms *cmd, void *_dcfg, const char *_p1, const char *_p2)
{
directory_config *dcfg = (directory_config *)_dcfg;
char *p1 = NULL;
if (dcfg == NULL) return NULL;
if (p1 == NULL) return NULL;
if (strcasecmp(p1, "Rand") == 0) {
p1 = apr_pstrdup(cmd->pool, getkey(cmd->pool));
dcfg->crypto_key = p1;
dcfg->crypto_key_len = strlen(dcfg->crypto_key);
} else {
p1 = apr_pstrdup(cmd->pool, _p1);
dcfg->crypto_key = p1;
dcfg->crypto_key_len = strlen(p1);
}
if(_p2 == NULL) {
return NULL;
} else {
if (strcasecmp(_p2, "KeyOnly") == 0)
dcfg->crypto_key_add = ENCRYPTION_KEYONLY;
else if (strcasecmp(_p2, "SessionID") == 0)
dcfg->crypto_key_add = ENCRYPTION_SESSIONID;
else if (strcasecmp(_p2, "RemoteIP") == 0)
dcfg->crypto_key_add = ENCRYPTION_REMOTEIP;
}
return NULL;
}
/**
* \brief Add SecEncryptionMethodPm configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
* \param p2 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On Success
*/
static const char *cmd_encryption_method_pm(cmd_parms *cmd, void *_dcfg,
const char *p1, const char *p2)
{
directory_config *dcfg = (directory_config *)_dcfg;
rule_exception *re = apr_pcalloc(cmd->pool, sizeof(encryption_method));
const char *_p2 = apr_pstrdup(cmd->pool, p2);
ACMP *p = NULL;
const char *phrase = NULL;
const char *next = NULL;
if (dcfg == NULL) return NULL;
p = acmp_create(0, cmd->pool);
if (p == NULL) return NULL;
if(phrase == NULL)
phrase = apr_pstrdup(cmd->pool, _p2);
for (;;) {
while((apr_isspace(*phrase) != 0) && (*phrase != '\0')) phrase++;
if (*phrase == '\0') break;
next = phrase;
while((apr_isspace(*next) == 0) && (*next != 0)) next++;
acmp_add_pattern(p, phrase, NULL, NULL, next - phrase);
phrase = next;
}
acmp_prepare(p);
if (strcasecmp(p1, "HashHref") == 0) {
re->type = ENCRYPTION_URL_HREF_HASH_PM;
re->param = _p2;
re->param_data = (void *)p;
if (re->param_data == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2);
}
dcfg->crypto_hash_href_pm = 1;
}
else if (strcasecmp(p1, "HashFormAction") == 0) {
re->type = ENCRYPTION_URL_FACTION_HASH_PM;
re->param = _p2;
re->param_data = (void *)p;
if (re->param_data == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2);
}
dcfg->crypto_hash_faction_pm = 1;
}
else if (strcasecmp(p1, "HashLocation") == 0) {
re->type = ENCRYPTION_URL_LOCATION_HASH_PM;
re->param = _p2;
re->param_data = (void *)p;
if (re->param_data == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2);
}
dcfg->crypto_hash_location_pm = 1;
}
else if (strcasecmp(p1, "HashIframeSrc") == 0) {
re->type = ENCRYPTION_URL_IFRAMESRC_HASH_PM;
re->param = _p2;
re->param_data = (void *)p;
if (re->param_data == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2);
}
dcfg->crypto_hash_iframesrc_pm = 1;
}
else if (strcasecmp(p1, "HashFrameSrc") == 0) {
re->type = ENCRYPTION_URL_FRAMESRC_HASH_PM;
re->param = _p2;
re->param_data = (void *)p;
if (re->param_data == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2);
}
dcfg->crypto_hash_framesrc_pm = 1;
}
*(encryption_method **)apr_array_push(dcfg->encryption_method) = re;
return NULL;
}
/**
* \brief Add SecEncryptionMethodRx configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
* \param p2 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On Success
*/
static const char *cmd_encryption_method_rx(cmd_parms *cmd, void *_dcfg,
const char *p1, const char *p2)
{
directory_config *dcfg = (directory_config *)_dcfg;
rule_exception *re = apr_pcalloc(cmd->pool, sizeof(encryption_method));
const char *_p2 = apr_pstrdup(cmd->pool, p2);
if (dcfg == NULL) return NULL;
if (strcasecmp(p1, "HashHref") == 0) {
re->type = ENCRYPTION_URL_HREF_HASH_RX;
re->param = _p2;
re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL);
if (re->param_data == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2);
}
dcfg->crypto_hash_href_rx = 1;
}
else if (strcasecmp(p1, "HashFormAction") == 0) {
re->type = ENCRYPTION_URL_FACTION_HASH_RX;
re->param = _p2;
re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL);
if (re->param_data == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2);
}
dcfg->crypto_hash_faction_rx = 1;
}
else if (strcasecmp(p1, "HashLocation") == 0) {
re->type = ENCRYPTION_URL_LOCATION_HASH_RX;
re->param = _p2;
re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL);
if (re->param_data == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2);
}
dcfg->crypto_hash_location_rx = 1;
}
else if (strcasecmp(p1, "HashIframeSrc") == 0) {
re->type = ENCRYPTION_URL_IFRAMESRC_HASH_RX;
re->param = _p2;
re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL);
if (re->param_data == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2);
}
dcfg->crypto_hash_iframesrc_rx = 1;
}
else if (strcasecmp(p1, "HashFrameSrc") == 0) {
re->type = ENCRYPTION_URL_FRAMESRC_HASH_RX;
re->param = _p2;
re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL);
if (re->param_data == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2);
}
dcfg->crypto_hash_framesrc_rx = 1;
}
*(encryption_method **)apr_array_push(dcfg->encryption_method) = re;
return NULL;
}
/**
* \brief Add SecHttpBlKey configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On success
*/
static const char *cmd_httpBl_key(cmd_parms *cmd, void *_dcfg, const char *p1)
{
directory_config *dcfg = (directory_config *)_dcfg;
@ -1980,7 +2519,7 @@ static const char *cmd_httpBl_key(cmd_parms *cmd, void *_dcfg, const char *p1)
/* PCRE Limits */
static const char *cmd_pcre_match_limit(cmd_parms *cmd,
void *_dcfg, const char *p1)
void *_dcfg, const char *p1)
{
long val;
@ -1991,7 +2530,7 @@ static const char *cmd_pcre_match_limit(cmd_parms *cmd,
val = atol(p1);
if (val <= 0) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
"SecPcreMatchLimit: %s", p1);
"SecPcreMatchLimit: %s", p1);
}
msc_pcre_match_limit = (unsigned long int)val;
@ -1999,7 +2538,7 @@ static const char *cmd_pcre_match_limit(cmd_parms *cmd,
}
static const char *cmd_pcre_match_limit_recursion(cmd_parms *cmd,
void *_dcfg, const char *p1)
void *_dcfg, const char *p1)
{
long val;
@ -2010,7 +2549,7 @@ static const char *cmd_pcre_match_limit_recursion(cmd_parms *cmd,
val = atol(p1);
if (val <= 0) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
"SecPcreMatchLimitRecursion: %s", p1);
"SecPcreMatchLimitRecursion: %s", p1);
}
msc_pcre_match_limit_recursion = (unsigned long int)val;
@ -2021,7 +2560,7 @@ static const char *cmd_pcre_match_limit_recursion(cmd_parms *cmd,
/* -- Geo Lookup configuration -- */
static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg,
const char *p1)
const char *p1)
{
const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
char *error_msg;
@ -2035,8 +2574,15 @@ static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg,
return NULL;
}
/* Unicode CodePage */
/**
* \brief Add SecUnicodeCodePage configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On success
*/
static const char *cmd_unicode_codepage(cmd_parms *cmd,
void *_dcfg, const char *p1)
{
@ -2053,8 +2599,15 @@ static const char *cmd_unicode_codepage(cmd_parms *cmd,
return NULL;
}
/* Unicode Map */
/**
* \brief Add SecUnicodeMapFile configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On success
*/
static const char *cmd_unicode_map(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
@ -2070,8 +2623,15 @@ static const char *cmd_unicode_map(cmd_parms *cmd, void *_dcfg,
return NULL;
}
/* Google safe browsing */
/**
* \brief Add SecGsbLookupDb configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
*
* \retval NULL On success
*/
static const char *cmd_gsb_lookup_db(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
@ -2211,7 +2771,7 @@ const command_rec module_directives[] = {
"SecArgumentSeparator",
cmd_argument_separator,
NULL,
CMD_SCOPE_MAIN,
CMD_SCOPE_ANY,
"character that will be used as separator when parsing application/x-www-form-urlencoded content."
),
@ -2472,6 +3032,14 @@ const command_rec module_directives[] = {
"On or Off"
),
AP_INIT_TAKE1 (
"SecRulePerfTime",
cmd_rule_perf_time,
NULL,
CMD_SCOPE_ANY,
"Threshold to log slow rules in usecs."
),
AP_INIT_TAKE1 (
"SecReadStateLimit",
cmd_conn_read_state_limit,
@ -2624,6 +3192,22 @@ const command_rec module_directives[] = {
"rule message for removal"
),
AP_INIT_TAKE2 (
"SecEncryptionMethodPm",
cmd_encryption_method_pm,
NULL,
CMD_SCOPE_ANY,
"Encryption method and pattern"
),
AP_INIT_TAKE2 (
"SecEncryptionMethodRx",
cmd_encryption_method_rx,
NULL,
CMD_SCOPE_ANY,
"Encryption method and regex"
),
AP_INIT_TAKE2 (
"SecRuleUpdateActionById",
cmd_rule_update_action_by_id,
@ -2640,6 +3224,23 @@ const command_rec module_directives[] = {
"updated target list"
),
AP_INIT_TAKE23 (
"SecRuleUpdateTargetByTag",
cmd_rule_update_target_by_tag,
NULL,
CMD_SCOPE_ANY,
"rule tag pattern and updated target list"
),
AP_INIT_TAKE23 (
"SecRuleUpdateTargetByMsg",
cmd_rule_update_target_by_msg,
NULL,
CMD_SCOPE_ANY,
"rule message pattern and updated target list"
),
AP_INIT_TAKE1 (
"SecServerSignature",
cmd_server_signature,
@ -2696,6 +3297,14 @@ const command_rec module_directives[] = {
"id"
),
AP_INIT_TAKE1 (
"SecSensorId",
cmd_sensor_id,
NULL,
CMD_SCOPE_MAIN,
"sensor id"
),
AP_INIT_TAKE1 (
"SecHttpBlKey",
cmd_httpBl_key,
@ -2704,5 +3313,29 @@ const command_rec module_directives[] = {
"httpBl access key"
),
AP_INIT_TAKE1 (
"SecEncryptionEngine",
cmd_encryption_engine,
NULL,
CMD_SCOPE_ANY,
"On or Off"
),
AP_INIT_TAKE2 (
"SecEncryptionKey",
cmd_encryption_key,
NULL,
CMD_SCOPE_ANY,
"Set Encrytion key"
),
AP_INIT_TAKE1 (
"SecEncryptionParam",
cmd_encryption_param,
NULL,
CMD_SCOPE_ANY,
"Set Encryption parameter"
),
{ NULL }
};

Просмотреть файл

@ -1,21 +1,22 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2011 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*/
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2011 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*/
#include <util_filter.h>
#include "modsecurity.h"
#include "apache2.h"
#include "msc_crypt.h"
/* -- Input filter -- */
@ -29,7 +30,7 @@ static void dummy_free_func(void *data) {}
* processing module).
*/
apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes)
ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes)
{
modsec_rec *msr = (modsec_rec *)f->ctx;
msc_data_chunk *chunk = NULL;
@ -39,7 +40,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
if (msr == NULL) {
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
"ModSecurity: Internal error in input filter: msr is null.");
"ModSecurity: Internal error in input filter: msr is null.");
ap_remove_input_filter(f);
return APR_EGENERAL;
}
@ -48,8 +49,8 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
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;
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)) {
@ -62,7 +63,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Input filter: Forwarding input: mode=%d, block=%d, nbytes=%" APR_OFF_T_FMT
" (f %pp, r %pp).", mode, block, nbytes, f, f->r);
" (f %pp, r %pp).", mode, block, nbytes, f, f->r);
}
if (msr->if_started_forwarding == 0) {
@ -87,24 +88,24 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
if (chunk && (!msr->txcfg->stream_inbody_inspection || (msr->txcfg->stream_inbody_inspection && msr->if_stream_changed == 0))) {
/* Copy the data we received in the chunk */
bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL,
f->r->connection->bucket_alloc);
f->r->connection->bucket_alloc);
#if 0
#if 0
It would seem that we cannot prevent other filters in the chain
from modifying data in-place. Hence we copy.
from modifying data in-place. Hence we copy.
if (chunk->is_permanent) {
/* Do not make a copy of the data we received in the chunk. */
bucket = apr_bucket_heap_create(chunk->data, chunk->length, dummy_free_func,
f->r->connection->bucket_alloc);
} else {
/* Copy the data we received in the chunk. */
bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL,
f->r->connection->bucket_alloc);
}
if (chunk->is_permanent) {
/* Do not make a copy of the data we received in the chunk. */
bucket = apr_bucket_heap_create(chunk->data, chunk->length, dummy_free_func,
f->r->connection->bucket_alloc);
} else {
/* Copy the data we received in the chunk. */
bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL,
f->r->connection->bucket_alloc);
}
#endif
#endif
if (bucket == NULL) return APR_EGENERAL;
APR_BRIGADE_INSERT_TAIL(bb_out, bucket);
@ -226,8 +227,8 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
* to extract the size of the data available.
*/
for(bucket = APR_BRIGADE_FIRST(bb_in);
bucket != APR_BRIGADE_SENTINEL(bb_in);
bucket = APR_BUCKET_NEXT(bucket))
bucket != APR_BRIGADE_SENTINEL(bb_in);
bucket = APR_BUCKET_NEXT(bucket))
{
const char *buf;
apr_size_t buflen;
@ -240,7 +241,7 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Input filter: Bucket type %s contains %" APR_SIZE_T_FMT " bytes.",
bucket->type->name, buflen);
bucket->type->name, buflen);
}
/* Check request body limit (should only trigger on chunked requests). */
@ -393,7 +394,7 @@ static int output_filter_should_run(modsec_rec *msr, request_rec *r) {
* Initialises the output filter.
*/
static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f,
apr_bucket_brigade *bb_in)
apr_bucket_brigade *bb_in)
{
request_rec *r = f->r;
const char *s_content_length = NULL;
@ -434,7 +435,7 @@ static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f,
len = strtol(s_content_length, NULL, 10);
if ((len == LONG_MIN)||(len == LONG_MAX)||(len < 0)||(len >= 1073741824)) {
msr_log(msr, 1, "Output filter: Invalid Content-Length: %s", log_escape_nq(r->pool,
(char *)s_content_length));
(char *)s_content_length));
return -1; /* Invalid. */
}
@ -448,7 +449,7 @@ static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f,
if (len > msr->txcfg->of_limit) {
msr_log(msr, 1, "Output filter: Content-Length (%s) over the limit (%ld).",
log_escape_nq(r->pool, (char *)s_content_length), msr->txcfg->of_limit);
log_escape_nq(r->pool, (char *)s_content_length), msr->txcfg->of_limit);
msr->outbound_error = 1;
return -2; /* Over the limit. */
}
@ -480,12 +481,12 @@ static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) {
/* Look like this is caused by the error
* already being handled, so we should ignore it
*
msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): Filter error", rc);
msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): Filter error", rc);
*/
break;
default :
msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): %s",
rc, get_apr_error(msr->mp, rc));
rc, get_apr_error(msr->mp, rc));
break;
}
}
@ -496,6 +497,12 @@ static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) {
return APR_SUCCESS;
}
/** \brief Inject data into brigade
*
* \param msr ModSecurity transation resource
* \param ap_filter_t Apache filter
*
*/
static void inject_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) {
apr_bucket *b;
@ -567,7 +574,7 @@ static int flatten_response_body(modsec_rec *msr) {
msr->resbody_data[msr->resbody_length] = '\0';
msr->resbody_status = RESBODY_STATUS_READ;
if (msr->txcfg->stream_outbody_inspection) {
if (msr->txcfg->stream_outbody_inspection && msr->txcfg->encryption_is_enabled == ENCRYPTION_DISABLED) {
msr->stream_output_length = msr->resbody_length;
@ -580,6 +587,36 @@ static int flatten_response_body(modsec_rec *msr) {
memset(msr->stream_output_data, 0, msr->stream_output_length+1);
strncpy(msr->stream_output_data, msr->resbody_data, msr->stream_output_length);
msr->stream_output_data[msr->stream_output_length] = '\0';
} else if (msr->txcfg->stream_outbody_inspection && msr->txcfg->encryption_is_enabled == ENCRYPTION_ENABLED) {
int retval = 0;
apr_time_t time1 = apr_time_now();
retval = init_response_body_html_parser(msr);
if(retval == 1) {
retval = encrypt_response_body_links(msr);
if(retval > 0) {
retval = inject_encrypted_response_body(msr, retval);
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Encryption completed in %" APR_TIME_T_FMT " usec.", (apr_time_now() - time1));
}
}
}
if(msr->of_stream_changed == 0) {
msr->stream_output_length = msr->resbody_length;
if (msr->stream_output_data == NULL) {
msr_log(msr, 1, "Output filter: Stream Response body data memory allocation failed. Asked for: %" APR_SIZE_T_FMT,
msr->stream_output_length + 1);
return -1;
}
memset(msr->stream_output_data, 0, msr->stream_output_length+1);
strncpy(msr->stream_output_data, msr->resbody_data, msr->stream_output_length);
msr->stream_output_data[msr->stream_output_length] = '\0';
}
}
return 1;
@ -598,7 +635,7 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
/* Do we have the context? */
if (msr == NULL) {
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
"ModSecurity: Internal Error: msr is null in output filter.");
"ModSecurity: Internal Error: msr is null in output filter.");
ap_remove_output_filter(f);
return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
}
@ -631,8 +668,12 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
msr->r = r;
msr->response_status = r->status;
msr->status_line = ((r->status_line != NULL)
? r->status_line : ap_get_status_line(r->status));
? r->status_line : ap_get_status_line(r->status));
msr->response_protocol = get_response_protocol(r);
if(msr->txcfg->crypto_hash_location_rx == 1 || msr->txcfg->crypto_hash_location_pm == 1)
rc = modify_response_header(msr);
msr->response_headers = apr_table_overlay(msr->mp, r->err_headers_out, r->headers_out);
/* Process phase RESPONSE_HEADERS */
@ -702,28 +743,28 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
/* Content injection (prepend & non-buffering). */
if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (msr->of_skipping)) {
apr_bucket *bucket_ci = apr_bucket_heap_create(msr->content_prepend,
msr->content_prepend_len, NULL, f->r->connection->bucket_alloc);
msr->content_prepend_len, NULL, f->r->connection->bucket_alloc);
APR_BRIGADE_INSERT_HEAD(bb_in, bucket_ci);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Content Injection (nb): Added content to top: %s",
log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len));
log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len));
}
}
} else
if (msr->of_status == OF_STATUS_COMPLETE) {
msr_log(msr, 1, "Output filter: Internal error: output filtering complete yet filter was invoked.");
ap_remove_output_filter(f);
return APR_EGENERAL;
}
if (msr->of_status == OF_STATUS_COMPLETE) {
msr_log(msr, 1, "Output filter: Internal error: output filtering complete yet filter was invoked.");
ap_remove_output_filter(f);
return APR_EGENERAL;
}
/* Loop through the buckets in the brigade in order
* to extract the size of the data available.
*/
for(bucket = APR_BRIGADE_FIRST(bb_in);
bucket != APR_BRIGADE_SENTINEL(bb_in);
bucket = APR_BUCKET_NEXT(bucket)) {
bucket != APR_BRIGADE_SENTINEL(bb_in);
bucket = APR_BUCKET_NEXT(bucket)) {
const char *buf;
apr_size_t buflen;
@ -738,7 +779,7 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
msr->resbody_status = RESBODY_STATUS_ERROR;
msr_log(msr, 1, "Output filter: Failed to read bucket (rc %d): %s",
rc, get_apr_error(r->pool, rc));
rc, get_apr_error(r->pool, rc));
ap_remove_output_filter(f);
return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
@ -746,7 +787,7 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Output filter: Bucket type %s contains %" APR_SIZE_T_FMT " bytes.",
bucket->type->name, buflen);
bucket->type->name, buflen);
}
/* Check the response size. */
@ -759,7 +800,7 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
if (msr->txcfg->of_limit_action == RESPONSE_BODY_LIMIT_ACTION_REJECT) {
/* Reject response. */
msr_log(msr, 1, "Output filter: Response body too large (over limit of %ld, "
"total not specified).", msr->txcfg->of_limit);
"total not specified).", msr->txcfg->of_limit);
msr->of_status = OF_STATUS_COMPLETE;
msr->resbody_status = RESBODY_STATUS_PARTIAL;
@ -773,7 +814,7 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Output filter: Processing partial response body (limit %ld)",
msr->txcfg->of_limit);
msr->txcfg->of_limit);
}
}
} else {
@ -787,17 +828,17 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
/* Inject content (append & non-buffering). */
if ((msr->txcfg->content_injection_enabled) && (msr->content_append)
&& (msr->of_skipping || msr->of_partial || start_skipping))
&& (msr->of_skipping || msr->of_partial || start_skipping))
{
apr_bucket *bucket_ci = NULL;
bucket_ci = apr_bucket_heap_create(msr->content_append,
msr->content_append_len, NULL, f->r->connection->bucket_alloc);
msr->content_append_len, NULL, f->r->connection->bucket_alloc);
APR_BUCKET_INSERT_BEFORE(bucket, bucket_ci);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Content-Injection (nb): Added content to bottom: %s",
log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len));
log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len));
}
}
@ -867,7 +908,7 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Output filter: Completed receiving response body (buffered %s - %" APR_SIZE_T_FMT " bytes).",
(msr->of_partial ? "partial" : "full"), msr->resbody_length);
(msr->of_partial ? "partial" : "full"), msr->resbody_length);
}
} else { /* Not looking at response data. */
if (msr->of_done_reading == 0) {
@ -950,12 +991,12 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
apr_bucket *bucket_ci = NULL;
bucket_ci = apr_bucket_heap_create(msr->content_append,
msr->content_append_len, NULL, f->r->connection->bucket_alloc);
msr->content_append_len, NULL, f->r->connection->bucket_alloc);
APR_BUCKET_INSERT_BEFORE(eos_bucket, bucket_ci);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Content-Injection (b): Added content to bottom: %s",
log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len));
log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len));
}
}

Просмотреть файл

@ -33,6 +33,11 @@
#include "apr_version.h"
#if defined(WITH_LUA)
#include "msc_lua.h"
#endif
/* ModSecurity structure */
msc_engine DSOLOCAL *modsecurity = NULL;
@ -68,7 +73,7 @@ typedef struct {
/* -- Miscellaneous functions -- */
/*
/**
* \brief Print informations from used libraries
*
* \param mp Pointer to memory pool
@ -114,6 +119,7 @@ int perform_interception(modsec_rec *msr) {
msre_actionset *actionset = NULL;
const char *message = NULL;
const char *phase_text = "";
unsigned int pause = 0;
int status = DECLINED;
int log_level = 1;
@ -142,11 +148,31 @@ int perform_interception(modsec_rec *msr) {
log_level = (actionset->log != 1) ? 4 : 1;
/* Pause the request first (if configured and the initial request). */
if (actionset->intercept_pause) {
msr_log(msr, (log_level > 3 ? log_level : log_level + 1), "Pausing transaction for "
"%d msec.", actionset->intercept_pause);
/* apr_sleep accepts microseconds */
apr_sleep((apr_interval_time_t)(actionset->intercept_pause * 1000));
if (actionset->intercept_pause != NULL) {
if(strstr(actionset->intercept_pause,"%{") != NULL) {
msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
var->value = (char *)actionset->intercept_pause;
var->value_len = strlen(actionset->intercept_pause);
expand_macros(msr, var, NULL, msr->mp);
pause = atoi(var->value);
if ((pause == LONG_MAX)||(pause == LONG_MIN)||(pause <= 0))
pause = 0;
msr_log(msr, (log_level > 3 ? log_level : log_level + 1), "Pausing transaction for "
"%d msec.", pause);
/* apr_sleep accepts microseconds */
apr_sleep((apr_interval_time_t)(pause * 1000));
} else {
pause = atoi(actionset->intercept_pause);
if ((pause == LONG_MAX)||(pause == LONG_MIN)||(pause <= 0))
pause = 0;
msr_log(msr, (log_level > 3 ? log_level : log_level + 1), "Pausing transaction for "
"%d msec.", pause);
/* apr_sleep accepts microseconds */
apr_sleep((apr_interval_time_t)(pause * 1000));
}
}
/* Determine how to respond and prepare the log message. */
@ -155,13 +181,13 @@ int perform_interception(modsec_rec *msr) {
if (actionset->intercept_status != 0) {
status = actionset->intercept_status;
message = apr_psprintf(msr->mp, "Access denied with code %d%s.",
status, phase_text);
status, phase_text);
} else {
log_level = 1;
status = HTTP_INTERNAL_SERVER_ERROR;
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
"(Internal Error: Invalid status code requested %d).",
phase_text, actionset->intercept_status);
"(Internal Error: Invalid status code requested %d).",
phase_text, actionset->intercept_status);
}
break;
@ -233,18 +259,39 @@ int perform_interception(modsec_rec *msr) {
break;
case ACTION_REDIRECT :
apr_table_setn(msr->r->headers_out, "Location", actionset->intercept_uri);
if ((actionset->intercept_status == 301)||(actionset->intercept_status == 302)
||(actionset->intercept_status == 303)||(actionset->intercept_status == 307))
{
status = actionset->intercept_status;
if(strstr(actionset->intercept_uri,"%{") != NULL) {
msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
var->value = (char *)actionset->intercept_uri;
var->value_len = strlen(actionset->intercept_uri);
expand_macros(msr, var, NULL, msr->mp);
apr_table_setn(msr->r->headers_out, "Location", var->value);
if ((actionset->intercept_status == 301)||(actionset->intercept_status == 302)
||(actionset->intercept_status == 303)||(actionset->intercept_status == 307))
{
status = actionset->intercept_status;
} else {
status = HTTP_MOVED_TEMPORARILY;
}
message = apr_psprintf(msr->mp, "Access denied with redirection to %s using "
"status %d%s.",
log_escape_nq(msr->mp, var->value), status,
phase_text);
} else {
status = HTTP_MOVED_TEMPORARILY;
apr_table_setn(msr->r->headers_out, "Location", actionset->intercept_uri);
if ((actionset->intercept_status == 301)||(actionset->intercept_status == 302)
||(actionset->intercept_status == 303)||(actionset->intercept_status == 307))
{
status = actionset->intercept_status;
} else {
status = HTTP_MOVED_TEMPORARILY;
}
message = apr_psprintf(msr->mp, "Access denied with redirection to %s using "
"status %d%s.",
log_escape_nq(msr->mp, actionset->intercept_uri), status,
phase_text);
}
message = apr_psprintf(msr->mp, "Access denied with redirection to %s using "
"status %d%s.",
log_escape_nq(msr->mp, actionset->intercept_uri), status,
phase_text);
break;
case ACTION_ALLOW :
@ -272,8 +319,8 @@ int perform_interception(modsec_rec *msr) {
log_level = 1;
status = HTTP_INTERNAL_SERVER_ERROR;
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
"(Internal Error: invalid interception action %d).",
phase_text, actionset->intercept_action);
"(Internal Error: invalid interception action %d).",
phase_text, actionset->intercept_action);
break;
}
@ -365,7 +412,15 @@ static modsec_rec *create_tx_context(request_rec *r) {
msr->r_early = r;
msr->request_time = r->request_time;
msr->dcfg1 = (directory_config *)ap_get_module_config(r->per_dir_config,
&security2_module);
&security2_module);
#if defined(WITH_LUA)
#ifdef CACHE_LUA
msr->L = lua_open();
luaL_openlibs(msr->L);
#endif
#endif
/**
* Create a special user configuration. This is where
@ -393,7 +448,7 @@ static modsec_rec *create_tx_context(request_rec *r) {
msr->txid = get_env_var(r, "UNIQUE_ID");
if (msr->txid == NULL) {
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server,
"ModSecurity: ModSecurity requires mod_unique_id to be installed.");
"ModSecurity: ModSecurity requires mod_unique_id to be installed.");
return NULL;
}
@ -409,12 +464,13 @@ static modsec_rec *create_tx_context(request_rec *r) {
msr->local_addr = r->connection->local_ip;
msr->local_port = r->connection->local_addr->port;
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
msr->remote_addr = r->connection->client_ip;
msr->remote_port = r->connection->client_addr->port;
#else
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
msr->remote_addr = r->connection->remote_ip;
msr->remote_port = r->connection->remote_addr->port;
#else
msr->remote_addr = r->connection->client_ip;
msr->remote_port = r->connection->client_addr->port;
msr->useragent_ip = r->useragent_ip;
#endif
msr->request_line = r->the_request;
@ -459,7 +515,7 @@ static apr_status_t change_server_signature(server_rec *s) {
if (server_version == NULL) {
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
"SecServerSignature: Apache returned null as signature.");
"SecServerSignature: Apache returned null as signature.");
return -1;
}
@ -468,8 +524,8 @@ static apr_status_t change_server_signature(server_rec *s) {
}
else {
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
"SecServerSignature: original signature too short. Please set "
"ServerTokens to Full.");
"SecServerSignature: original signature too short. Please set "
"ServerTokens to Full.");
return -1;
}
@ -520,7 +576,7 @@ static int hook_pre_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_te
modsecurity = modsecurity_create(mp, MODSEC_ONLINE);
if (modsecurity == NULL) {
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
"ModSecurity: Failed to initialise engine.");
"ModSecurity: Failed to initialise engine.");
return HTTP_INTERNAL_SERVER_ERROR;
}
@ -548,7 +604,7 @@ static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_t
if (init_flag == NULL) {
first_time = 1;
apr_pool_userdata_set((const void *)1, "modsecurity-init-flag",
apr_pool_cleanup_null, s->process->pool);
apr_pool_cleanup_null, s->process->pool);
} else {
modsecurity_init(modsecurity, mp);
}
@ -562,7 +618,7 @@ static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_t
change_server_signature(s);
}
#if (!(defined(WIN32) || defined(NETWARE)))
#if (!(defined(WIN32) || defined(NETWARE)))
/* Internal chroot functionality */
@ -574,37 +630,37 @@ static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_t
if (first_time == 0) {
ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
"ModSecurity: chroot checkpoint #2 (pid=%ld ppid=%ld)", (long)getpid(), (long)getppid());
"ModSecurity: chroot checkpoint #2 (pid=%ld ppid=%ld)", (long)getpid(), (long)getppid());
if (chdir(chroot_dir) < 0) {
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
"ModSecurity: chroot failed, unable to chdir to %s, errno=%d (%s)",
chroot_dir, errno, strerror(errno));
"ModSecurity: chroot failed, unable to chdir to %s, errno=%d (%s)",
chroot_dir, errno, strerror(errno));
exit(1);
}
if (chroot(chroot_dir) < 0) {
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
"ModSecurity: chroot failed, path=%s, errno=%d(%s)",
chroot_dir, errno, strerror(errno));
"ModSecurity: chroot failed, path=%s, errno=%d(%s)",
chroot_dir, errno, strerror(errno));
exit(1);
}
if (chdir("/") < 0) {
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, s,
"ModSecurity: chdoot failed, unable to chdir to /, errno=%d (%s)",
errno, strerror(errno));
"ModSecurity: chdoot failed, unable to chdir to /, errno=%d (%s)",
errno, strerror(errno));
exit(1);
}
ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
"ModSecurity: chroot successful, path=%s", chroot_dir);
"ModSecurity: chroot successful, path=%s", chroot_dir);
} else {
ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
"ModSecurity: chroot checkpoint #1 (pid=%ld ppid=%ld)", (long)getpid(), (long)getppid());
"ModSecurity: chroot checkpoint #1 (pid=%ld ppid=%ld)", (long)getpid(), (long)getppid());
}
}
#endif
#endif
/* Schedule main cleanup for later, when the main pool is destroyed. */
apr_pool_cleanup_register(mp, (void *)s, module_cleanup, apr_pool_cleanup_null);
@ -619,7 +675,7 @@ static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_t
/* If we've changed the server signature make note of the original. */
if (new_server_signature != NULL) {
ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s,
"Original server signature: %s", real_server_signature);
"Original server signature: %s", real_server_signature);
}
}
@ -642,6 +698,7 @@ static void hook_child_init(apr_pool_t *mp, server_rec *s) {
*/
static int hook_request_early(request_rec *r) {
modsec_rec *msr = NULL;
int rc = DECLINED;
/* This function needs to run only once per transaction
* (i.e. subrequests and redirects are excluded).
@ -656,22 +713,35 @@ static int hook_request_early(request_rec *r) {
msr = create_tx_context(r);
if (msr == NULL) return DECLINED;
#if 0
/* NOTE This check is not currently needed, but it may be needed in the
* future when we add another early phase.
*/
#ifdef REQUEST_EARLY
/* Are we allowed to continue? */
if (msr->txcfg->is_enabled == MODSEC_DISABLED) {
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Processing disabled, skipping (hook request_early).");
}
return DECLINED;
}
#endif
}
return DECLINED;
/* Process phase REQUEST_HEADERS */
if (modsecurity_process_phase(msr, PHASE_REQUEST_HEADERS) > 0) {
rc = perform_interception(msr);
}
if ( (msr->txcfg->is_enabled != MODSEC_DISABLED)
&& (msr->txcfg->reqbody_access == 1)
&& (rc == DECLINED))
{
/* Check request body limit (non-chunked requests only). */
if (msr->request_content_length > msr->txcfg->reqbody_limit) {
msr_log(msr, 1, "Request body (Content-Length) is larger than the "
"configured limit (%ld).", msr->txcfg->reqbody_limit);
if(msr->txcfg->is_enabled != MODSEC_DETECTION_ONLY)
return HTTP_REQUEST_ENTITY_TOO_LARGE;
}
}
#endif
return rc;
}
/**
@ -712,7 +782,7 @@ static int hook_request_late(request_rec *r) {
/* Get the second configuration context. */
msr->dcfg2 = (directory_config *)ap_get_module_config(r->per_dir_config,
&security2_module);
&security2_module);
/* Create a transaction context. */
msr->txcfg = create_directory_config(msr->mp, NULL);
@ -731,10 +801,10 @@ static int hook_request_late(request_rec *r) {
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Processing disabled, skipping (hook request_late).");
}
return DECLINED;
}
#ifndef REQUEST_EARLY
/* Phase 1 */
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "First phase starting (dcfg %pp).", msr->dcfg2);
@ -749,6 +819,7 @@ static int hook_request_late(request_rec *r) {
return rc;
}
}
#endif
/* The rule engine could have been disabled in phase 1. */
if (msr->txcfg->is_enabled == MODSEC_DISABLED) {
@ -933,8 +1004,8 @@ static void hook_error_log(const char *file, int line, int level, apr_status_t s
}
}
}
if (msr == NULL) return;
/* Store the error message for later */
em = (error_message *)apr_pcalloc(msr->mp, sizeof(error_message));
if (em == NULL) return;
@ -952,7 +1023,6 @@ static void hook_error_log(const char *file, int line, int level, apr_status_t s
em->status = status;
if (fmt != NULL) em->message = apr_pstrdup(msr->mp, fmt);
#endif
/* Remove \n from the end of the message */
if (em->message != NULL) {
char *p = (char *)em->message;
@ -968,6 +1038,7 @@ static void hook_error_log(const char *file, int line, int level, apr_status_t s
*(const error_message **)apr_array_push(msr->error_messages) = em;
}
/**
* Guardian logger is used to interface to the external
* script for web server protection - httpd_guardian.
@ -1007,7 +1078,7 @@ static void sec_guardian_logger(request_rec *r, request_rec *origr, modsec_rec *
*/
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;
/* We do not want the index line to be longer than 3980 bytes. */
@ -1087,7 +1158,7 @@ static int hook_log_transaction(request_rec *r) {
msr->r = r;
msr->response_status = r->status;
msr->status_line = ((r->status_line != NULL)
? r->status_line : ap_get_status_line(r->status));
? r->status_line : ap_get_status_line(r->status));
msr->response_protocol = get_response_protocol(origr);
msr->response_headers = apr_table_copy(msr->mp, r->headers_out);
if (!r->assbackwards) msr->response_headers_sent = 1;
@ -1121,7 +1192,7 @@ static void hook_insert_filter(request_rec *r) {
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);
(((r->main != NULL)||(r->prev != NULL)) ? "for subrequest " : ""), r);
}
ap_add_input_filter("MODSECURITY_IN", msr, r, r->connection);
@ -1220,15 +1291,15 @@ static void modsec_register_operator(const char *name, void *fn_init, void *fn_e
}
}
/*
* \brief Connetion hook to limit the number of
* connections in BUSY state
*
* \param conn Pointer to connection struct
*
* \retval DECLINED On failure
* \retval OK On Success
*/
/**
* \brief Connetion hook to limit the number of
* connections in BUSY state
*
* \param conn Pointer to connection struct
*
* \retval DECLINED On failure
* \retval OK On Success
*/
static int hook_connection_early(conn_rec *conn)
{
sb_handle *sb = conn->sbh;

Просмотреть файл

@ -260,6 +260,12 @@ static apr_status_t modsecurity_tx_cleanup(void *data) {
msr_log(msr, 1, "%s", my_error_msg);
}
#if defined(WITH_LUA)
#ifdef CACHE_LUA
if(msr->L != NULL) lua_close(msr->L);
#endif
#endif
return APR_SUCCESS;
}
@ -378,6 +384,12 @@ apr_status_t modsecurity_tx_init(modsec_rec *msr) {
if (msr->matched_vars == NULL) return -1;
apr_table_clear(msr->matched_vars);
if(msr->txcfg->max_rule_time > 0) {
msr->perf_rules = apr_table_make(msr->mp, 8);
if (msr->perf_rules == NULL) return -1;
apr_table_clear(msr->perf_rules);
}
/* Locate the cookie headers and parse them */
arr = apr_table_elts(msr->request_headers);
te = (apr_table_entry_t *)arr->elts;
@ -423,6 +435,9 @@ apr_status_t modsecurity_tx_init(modsec_rec *msr) {
msr->removed_rules_tag = apr_array_make(msr->mp, 16, sizeof(char *));
if (msr->removed_rules_tag == NULL) return -1;
msr->removed_rules_msg = apr_array_make(msr->mp, 16, sizeof(char *));
if (msr->removed_rules_msg == NULL) return -1;
return 1;
}

Просмотреть файл

@ -19,8 +19,11 @@
#include <stdlib.h>
#include <limits.h>
#include <libxml/tree.h>
#include <libxml/HTMLparser.h>
typedef struct rule_exception rule_exception;
typedef struct rule_exception encryption_method;
typedef struct modsec_rec modsec_rec;
typedef struct directory_config directory_config;
typedef struct error_message error_message;
@ -40,6 +43,7 @@ typedef struct msc_parm msc_parm;
#include "msc_gsb.h"
#include "msc_unicode.h"
#include "re.h"
#include "msc_crypt.h"
#include "ap_config.h"
#include "apr_md5.h"
@ -50,6 +54,11 @@ typedef struct msc_parm msc_parm;
#include "http_log.h"
#include "http_protocol.h"
#if defined(WITH_LUA)
#include "msc_lua.h"
#endif
#define PHASE_REQUEST_HEADERS 1
#define PHASE_REQUEST_BODY 2
#define PHASE_RESPONSE_HEADERS 3
@ -101,7 +110,7 @@ typedef struct msc_parm msc_parm;
#define SECMARKER_TARGETS "REMOTE_ADDR"
#define SECMARKER_ARGS "@noMatch"
#define SECMARKER_BASE_ACTIONS "t:none,pass,id:"
#define SECMARKER_BASE_ACTIONS "t:none,pass,marker:"
#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
#include "unixd.h"
@ -172,6 +181,24 @@ extern DSOLOCAL int *unicode_map_table;
#define MODSEC_DETECTION_ONLY 1
#define MODSEC_ENABLED 2
#define ENCRYPTION_DISABLED 0
#define ENCRYPTION_ENABLED 1
#define ENCRYPTION_URL_HREF_HASH_RX 0
#define ENCRYPTION_URL_HREF_HASH_PM 1
#define ENCRYPTION_URL_FACTION_HASH_RX 2
#define ENCRYPTION_URL_FACTION_HASH_PM 3
#define ENCRYPTION_URL_LOCATION_HASH_RX 4
#define ENCRYPTION_URL_LOCATION_HASH_PM 5
#define ENCRYPTION_URL_IFRAMESRC_HASH_RX 6
#define ENCRYPTION_URL_IFRAMESRC_HASH_PM 7
#define ENCRYPTION_URL_FRAMESRC_HASH_RX 8
#define ENCRYPTION_URL_FRAMESRC_HASH_PM 9
#define ENCRYPTION_KEYONLY 0
#define ENCRYPTION_SESSIONID 1
#define ENCRYPTION_REMOTEIP 2
#define MODSEC_CACHE_DISABLED 0
#define MODSEC_CACHE_ENABLED 1
@ -259,6 +286,9 @@ struct modsec_rec {
unsigned int remote_port;
const char *remote_user;
/* useragent */
const char *useragent_ip;
/* request */
const char *request_line;
@ -342,7 +372,7 @@ struct modsec_rec {
const char *intercept_message;
/* performance measurement */
apr_time_t request_time;
apr_time_t request_time;
apr_time_t time_phase1;
apr_time_t time_phase2;
apr_time_t time_phase3;
@ -352,7 +382,8 @@ struct modsec_rec {
apr_time_t time_storage_write;
apr_time_t time_logging;
apr_time_t time_gc;
apr_table_t *perf_rules;
apr_array_header_t *matched_rules;
msc_string *matched_var;
int highest_severity;
@ -383,6 +414,7 @@ struct modsec_rec {
/* removed rules */
apr_array_header_t *removed_rules;
apr_array_header_t *removed_rules_tag;
apr_array_header_t *removed_rules_msg;
/* When "allow" is executed the variable below is
* updated to contain the scope of the allow action. Set
@ -397,6 +429,13 @@ struct modsec_rec {
/* Generic request body processor context to be used by custom parsers. */
void *reqbody_processor_ctx;
htmlDocPtr crypto_html_tree;
#if defined(WITH_LUA)
#ifdef CACHE_LUA
lua_State *L;
#endif
#endif
};
struct directory_config {
@ -432,6 +471,9 @@ struct directory_config {
/* -- Audit log -- */
/* Max rule time */
int max_rule_time;
/* Whether audit log should be enabled in the context or not */
int auditlog_flag;
@ -486,6 +528,7 @@ struct directory_config {
/* Misc */
const char *data_dir;
const char *webappid;
const char *sensor_id;
const char *httpBlkey;
/* Content injection. */
@ -523,6 +566,25 @@ struct directory_config {
/* Collection timeout */
int col_timeout;
/* Encryption */
apr_array_header_t *encryption_method;
const char *crypto_key;
int crypto_key_len;
const char *crypto_param_name;
int encryption_is_enabled;
int encryption_enforcement;
int crypto_key_add;
int crypto_hash_href_rx;
int crypto_hash_faction_rx;
int crypto_hash_location_rx;
int crypto_hash_iframesrc_rx;
int crypto_hash_framesrc_rx;
int crypto_hash_href_pm;
int crypto_hash_faction_pm;
int crypto_hash_location_pm;
int crypto_hash_iframesrc_pm;
int crypto_hash_framesrc_pm;
};
struct error_message {

1369
apache2/msc_crypt.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

42
apache2/msc_crypt.h Normal file
Просмотреть файл

@ -0,0 +1,42 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2011 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*/
#ifndef _MSC_CRYPT_H_
#define _MSC_CRYPT_H_
#include "modsecurity.h"
#include <libxml/HTMLparser.h>
#include <libxml/xpath.h>
#define HMAC_PAD_SIZE 65
#define HASH_ONLY 0
#define FULL_LINK 1
#ifndef INT32_MAX
#define INT32_MAX (2147483647)
#endif
char DSOLOCAL *hmac(modsec_rec *msr,const unsigned char *key, int key_len,
char *msg, int msglen);
unsigned char DSOLOCAL *do_hash_link(modsec_rec *msr, char *link,
int type);
unsigned char DSOLOCAL *getkey(apr_pool_t *mp);
int DSOLOCAL init_response_body_html_parser(modsec_rec *msr);
int DSOLOCAL encrypt_response_body_links(modsec_rec *msr);
int DSOLOCAL inject_encrypted_response_body(modsec_rec *msr, int elts);
int DSOLOCAL do_encryption_method(modsec_rec *msr, char *link, int type);
int DSOLOCAL modify_response_header(modsec_rec *msr);
char DSOLOCAL *normalize_path(modsec_rec *msr, char *input);
#endif

Просмотреть файл

@ -14,6 +14,14 @@
#include "msc_gsb.h"
/** \brief Load GSB database
*
* \param dcfg Pointer to directory configuration
* \param error_msg Error message
*
* \retval 1 On Success
* \retval 0 On Fail
*/
static int gsb_db_create(directory_config *dcfg, char **error_msg)
{
char errstr[1024];
@ -89,8 +97,14 @@ static int gsb_db_create(directory_config *dcfg, char **error_msg)
}
/**
* Initialise Gsb malware data structure
/** \brief Init GSB database
*
* \param dcfg Pointer to directory configuration
* \param dbfn Database filename
* \param error_msg Error message
*
* \retval gsb_db_create On Success
* \retval -1 On Fail
*/
int gsb_db_init(directory_config *dcfg, const char *dbfn, char **error_msg)
{

Просмотреть файл

@ -1050,6 +1050,41 @@ void sec_audit_logger(modsec_rec *msr) {
msr->userid == NULL ? "-" : log_escape(msr->mp, msr->userid));
sec_auditlog_write(msr, text, strlen(text));
}
if ( ((msr->txcfg->sensor_id != NULL)&&(strcmp(msr->txcfg->sensor_id, "default") != 0)))
{
text = apr_psprintf(msr->mp, "Sensor-Id: \"%s\"\n",
msr->txcfg->sensor_id == NULL ? "-" : log_escape(msr->mp, msr->txcfg->sensor_id)),
sec_auditlog_write(msr, text, strlen(text));
}
if (msr->txcfg->is_enabled > 0) {
text = apr_psprintf(msr->mp, "Engine-Mode: \"%s\"\n",
msr->txcfg->is_enabled == 1 ? "DETECTION_ONLY" : "ENABLED"),
sec_auditlog_write(msr, text, strlen(text));
}
/* Rule performance time */
if(msr->txcfg->max_rule_time > 0) {
const apr_array_header_t *tarr;
const apr_table_entry_t *telts;
tarr = apr_table_elts(msr->perf_rules);
telts = (const apr_table_entry_t*)tarr->elts;
if (tarr->nelts > 0) {
text = apr_psprintf(msr->mp, "Rules-Performance-Info: ");
sec_auditlog_write(msr, text, strlen(text));
}
for(i = 0; i < tarr->nelts; i++) {
text = apr_psprintf(msr->mp, "%s\"%s=%s\"%s", ((i == 0) ? "" : ", "),
log_escape(msr->mp, telts[i].key), log_escape(msr->mp, telts[i].val), ((i == (tarr->nelts - 1)) ? ".\n" : ""));
sec_auditlog_write(msr, text, strlen(text));
}
}
}
/* AUDITLOG_PART_UPLOADS */

Просмотреть файл

@ -393,7 +393,7 @@ static const struct luaL_Reg mylib[] = {
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;
int rc = 0;
if (error_msg == NULL) return -1;
*error_msg = NULL;
@ -404,10 +404,19 @@ int lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rul
time_before = apr_time_now();
#ifdef CACHE_LUA
L = msr->L;
rc = lua_gettop(L);
if(rc)
lua_pop(L, rc);
#else
/* Create new state. */
L = lua_open();
luaL_openlibs(L);
#endif
if(L == NULL)
return -1;
/* Associate msr with the state. */
lua_pushlightuserdata(L, (void *)msr);
@ -441,6 +450,11 @@ int lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rul
if (lua_pcall(L, ((param != NULL) ? 1 : 0), 1, 0)) {
*error_msg = apr_psprintf(msr->mp, "Lua: Script execution failed: %s", lua_tostring(L, -1));
if (msr->txcfg->debuglog_level >= 8) {
msr_log(msr, 8, "Lua: Script execution failed: %s", lua_tostring(L, -1));
}
return -1;
}
@ -452,7 +466,9 @@ int lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rul
/* Destroy state. */
lua_pop(L, 1);
#ifndef CACHE_LUA
lua_close(L);
#endif
/* Returns status code to caller. */
if (msr->txcfg->debuglog_level >= 8) {

Просмотреть файл

@ -39,8 +39,8 @@
#define MODSEC_VERSION_MAJOR "2"
#define MODSEC_VERSION_MINOR "7"
#define MODSEC_VERSION_MAINT "0"
#define MODSEC_VERSION_TYPE "trunk"
#define MODSEC_VERSION_RELEASE ""
#define MODSEC_VERSION_TYPE "-rc"
#define MODSEC_VERSION_RELEASE "1"
#define MODSEC_VERSION_SUFFIX MODSEC_VERSION_TYPE MODSEC_VERSION_RELEASE

Просмотреть файл

@ -16,6 +16,14 @@
#define CODEPAGE_SEPARATORS " \t\n\r"
/** \brief Load Unicode file
*
* \param dcfg Pointer to directory configuration
* \param error_msg Error message
*
* \retval 1 On Success
* \retval 0 On Fail
*/
static int unicode_map_create(directory_config *dcfg, char **error_msg)
{
char errstr[1024];
@ -129,8 +137,14 @@ static int unicode_map_create(directory_config *dcfg, char **error_msg)
}
/**
* Initialise Unicode Map data structure
/** \brief Init unicode map
*
* \param dcfg Pointer to directory configuration
* \param mapfn Unicode map filename
* \param error_msg Error message
*
* \retval unicode_map_create On Success
* \retval -1 On Fail
*/
int unicode_map_init(directory_config *dcfg, const char *mapfn, char **error_msg)
{

Просмотреть файл

@ -74,7 +74,151 @@ static unsigned char *c2x(unsigned what, unsigned char *where);
static unsigned char x2c(unsigned char *what);
static unsigned char xsingle2c(unsigned char *what);
/* \brief Remove escape char
/** \brief Interpret |HEX| syntax
*
* \param op_parm Pointer to operator input
* \param op_len Operator input lenght
* \param rule Pointer to rule struct
* \param error_msg Pointer to error message
*
* \retval string On Success
*/
char *parse_pm_content(const char *op_parm, unsigned short int op_len, msre_rule *rule, char **error_msg) {
char *parm = NULL;
char *content = NULL;
unsigned short int offset = 0;
char converted = 0;
int i, x;
unsigned char bin = 0, esc = 0, bin_offset = 0;
unsigned char bin_parm[3], c = 0;
char *processed = NULL;
content = apr_pstrdup(rule->ruleset->mp, op_parm);
if (content == NULL) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
return NULL;
}
while (offset < op_len && apr_isspace(content[offset])) {
offset++;
};
op_len = strlen(content);
if (content[offset] == '\"' && content[op_len-1] == '\"') {
parm = apr_pstrdup(rule->ruleset->mp, content + offset + 1);
if (parm == NULL) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
return NULL;
}
parm[op_len - offset - 2] = '\0';
} else {
parm = apr_pstrdup(rule->ruleset->mp, content + offset);
if (parm == NULL) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
return NULL;
}
}
op_len = strlen(parm);
if (op_len == 0) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Content length is 0.");
return NULL;
}
for (i = 0, x = 0; i < op_len; i++) {
if (parm[i] == '|') {
if (bin) {
bin = 0;
} else {
bin = 1;
}
} else if(!esc && parm[i] == '\\') {
esc = 1;
} else {
if (bin) {
if (apr_isdigit(parm[i]) ||
parm[i] == 'A' || parm[i] == 'a' ||
parm[i] == 'B' || parm[i] == 'b' ||
parm[i] == 'C' || parm[i] == 'c' ||
parm[i] == 'D' || parm[i] == 'd' ||
parm[i] == 'E' || parm[i] == 'e' ||
parm[i] == 'F' || parm[i] == 'f')
{
bin_parm[bin_offset] = (char)parm[i];
bin_offset++;
if (bin_offset == 2) {
c = strtol((char *)bin_parm, (char **) NULL, 16) & 0xFF;
bin_offset = 0;
parm[x] = c;
x++;
converted = 1;
}
} else if (parm[i] == ' ') {
}
} else if (esc) {
if (parm[i] == ':' ||
parm[i] == ';' ||
parm[i] == '\\' ||
parm[i] == '\"')
{
parm[x] = parm[i];
x++;
} else {
*error_msg = apr_psprintf(rule->ruleset->mp, "Unsupported escape sequence.");
return NULL;
}
esc = 0;
converted = 1;
} else {
parm[x] = parm[i];
x++;
}
}
}
if (converted) {
op_len = x;
}
processed = apr_pstrmemdup(rule->ruleset->mp, parm, op_len);
if (processed == NULL) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
return NULL;
}
return processed;
}
/** \brief Remove quotes
*
* \param mptmp Pointer to the pool
* \param input Pointer to input string
* \param input_len Input data length
*
* \retval string On Success
*/
char *remove_quotes(apr_pool_t *mptmp, const char *input, int input_len) {
char *parm = apr_palloc(mptmp, input_len);
char *ret = parm;
int len = input_len;
for(; *input !='\0' && len >=0; input++, len--) {
if(*input != '\'' && *input != '\"') {
*parm++ = *input;
}
}
*parm = '\0';
return ret;
}
/** \brief Remove escape char
*
* \param mptmp Pointer to the pool
* \param input Pointer to input string
@ -112,7 +256,7 @@ int parse_boolean(const char *input) {
return -1;
}
/* \brief Decode Base64 data with special chars
/** \brief Decode Base64 data with special chars
*
* \param plain_text Pointer to plain text data
* \param input Pointer to input data
@ -121,8 +265,7 @@ int parse_boolean(const char *input) {
* \retval 0 On failure
* \retval string length On Success
*/
int decode_base64_ext(char *plain_text, const unsigned char *input, int input_len)
{
int decode_base64_ext(char *plain_text, const unsigned char *input, int input_len) {
const unsigned char *encoded = input;
int i = 0, j = 0, k = 0;
int ch = 0;
@ -177,13 +320,14 @@ int decode_base64_ext(char *plain_text, const unsigned char *input, int input_le
return j;
}
/* \brief Convert const char to int
/** \brief Convert const char to int
*
* \param c number string
*
* \retval n The converted number
*/
int convert_to_int(const char c) {
int convert_to_int(const char c)
{
int n;
if ((c>='0') && (c<='9'))
n = c - '0';
@ -196,7 +340,7 @@ int convert_to_int(const char c) {
return n;
}
/* \brief Set a match to tx.N
/** \brief Set a match to tx.N
*
* \param msr Pointer to modsec resource
* \param capture If ON match will be saved
@ -223,6 +367,7 @@ int set_match_to_tx(modsec_rec *msr, int capture, const char *match, int tx_n)
msr_log(msr, 9, "Added phrase match to TX.%d: %s",
tx_n, log_escape_nq_ex(msr->mp, s->value, s->value_len));
}
}
return 0;
@ -437,7 +582,7 @@ int sql_hex2bytes_inplace(unsigned char *data, int len) {
}
*d = '\0';
return strlen(begin);
return strlen((char *)begin);
}
/**
@ -632,13 +777,13 @@ char *current_filetime(apr_pool_t *mp) {
/**
*
*/
int msc_mkstemp_ex(char *template, int mode) {
int msc_mkstemp_ex(char *templat, int mode) {
int fd = -1;
/* ENH Use apr_file_mktemp instead. */
#if !(defined(WIN32)||defined(NETWARE))
fd = mkstemp(template);
fd = mkstemp(templat);
#ifdef HAVE_FCHMOD
if ((fd != -1) && (mode != 0)) {
if (fchmod(fd, mode) == -1) {
@ -647,8 +792,8 @@ int msc_mkstemp_ex(char *template, int mode) {
}
#endif /* HAVE_FCHMOD */
#else
if (mktemp(template) == NULL) return -1;
fd = open(template, O_WRONLY | O_APPEND | O_CREAT | O_BINARY, mode);
if (mktemp(templat) == NULL) return -1;
fd = open(templat, O_WRONLY | O_APPEND | O_CREAT | O_BINARY, mode);
#endif /* !(defined(WIN32)||defined(NETWARE)) */
return fd;
@ -657,8 +802,8 @@ int msc_mkstemp_ex(char *template, int mode) {
/**
*
*/
int msc_mkstemp(char *template) {
return msc_mkstemp_ex(template, CREATEMODE_UNISTD);
int msc_mkstemp(char *templat) {
return msc_mkstemp_ex(templat, CREATEMODE_UNISTD);
}
/**

Просмотреть файл

@ -26,11 +26,16 @@
#endif
#include "modsecurity.h"
#include "re.h"
int DSOLOCAL normalize_path_inplace(unsigned char *input, int len, int win, int *changed);
int DSOLOCAL parse_boolean(const char *input);
char DSOLOCAL *remove_quotes(apr_pool_t *mptmp, const char *input, int input_len);
char DSOLOCAL *parse_pm_content(const char *op_parm, unsigned short int op_len, msre_rule *rule, char **error_msg);
char DSOLOCAL *remove_escape(apr_pool_t *mptmp, const char *input, int input_len);
int DSOLOCAL parse_name_eq_value(apr_pool_t *mp, const char *input, char **name, char **value);
@ -59,9 +64,9 @@ char DSOLOCAL *current_logtime(apr_pool_t *mp);
char DSOLOCAL *current_filetime(apr_pool_t *mp);
int DSOLOCAL msc_mkstemp_ex(char *template, int mode);
int DSOLOCAL msc_mkstemp_ex(char *templat, int mode);
int DSOLOCAL msc_mkstemp(char *template);
int DSOLOCAL msc_mkstemp(char *templat);
char DSOLOCAL *strtolower_inplace(unsigned char *str);

Просмотреть файл

@ -108,10 +108,12 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec
goto cleanup;
}
if(strstr(col_name,"USER") || strstr(col_name,"SESSION"))
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", msr->txcfg->webappid, "_", col_name, NULL);
else
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", col_name, NULL);
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", col_name, NULL);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name),
log_escape(msr->mp, dbm_filename));
}
key.dptr = (char *)col_key;
key.dsize = col_key_len + 1;
@ -353,6 +355,11 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
// ENH: lowercase the var name in the filename
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", var_name->value, NULL);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value),
log_escape(msr->mp, dbm_filename));
}
/* Delete IS_NEW on store. */
apr_table_unset(col, "IS_NEW");
@ -579,16 +586,21 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) {
goto error;
}
if(strstr(col_name,"USER") || strstr(col_name,"SESSION"))
if(strcasestr(col_name,"user") || strcasestr(col_name,"session") || strcasestr(col_name,"resource"))
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", msr->txcfg->webappid, "_", col_name, NULL);
else
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", col_name, NULL);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name),
log_escape(msr->mp, dbm_filename));
}
rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK,
CREATEMODE, msr->mp);
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));
get_apr_error(msr->mp, rc));
dbm = NULL;
goto error;
}

Просмотреть файл

@ -42,147 +42,137 @@ static msre_action *msre_create_action(msre_engine *engine, const char *name,
static apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr);
/* -- Actions, variables, functions and operator functions ----------------- */
/**
* \brief Update target for all matching rules in set, in any phase
*
* \param msr ModSecurity transaction resource
* \param ruleset Pointer to set of rules to modify
* \param re Pointer to exception object describing which rules to modify
* \param p2 Pointer to configuration option TARGET
* \param p3 Pointer to configuration option REPLACED_TARGET
*/
char *msre_ruleset_rule_update_target_matching_exception(modsec_rec *msr, msre_ruleset *ruleset, rule_exception *re, const char *p2, const char *p3) {
char *err;
char *update_rule_target(cmd_parms *cmd, directory_config *dcfg,
msre_ruleset *rset, const char *p1, const char *p2, const char *p3)
if(ruleset == NULL)
return apr_psprintf(ruleset->mp, "No ruleset present");
if(p2 == NULL) {
return apr_psprintf(ruleset->mp, "Trying to update without a target");
}
if (NULL != (err = msre_ruleset_phase_rule_update_target_matching_exception(msr, ruleset, re, ruleset->phase_request_headers, p2, p3)))
return err;
if (NULL != (err = msre_ruleset_phase_rule_update_target_matching_exception(msr, ruleset, re, ruleset->phase_request_body, p2, p3)))
return err;
if (NULL != (err = msre_ruleset_phase_rule_update_target_matching_exception(msr, ruleset, re, ruleset->phase_response_headers, p2, p3)))
return err;
if (NULL != (err = msre_ruleset_phase_rule_update_target_matching_exception(msr, ruleset, re, ruleset->phase_response_body, p2, p3)))
return err;
if (NULL != (err = msre_ruleset_phase_rule_update_target_matching_exception(msr, ruleset, re, ruleset->phase_logging, p2, p3)))
return err;
/* Everything worked! */
return NULL;
}
/**
* \brief Update target for all matching rules in set for a specific phase
*
* \param msr ModSecurity transaction resource
* \param ruleset Pointer to set of rules to modify
* \param re Pointer to exception object describing which rules to modify
* \param phase_arr Pointer to phase that should be edited
* \param p2 Pointer to configuration option TARGET
* \param p3 Pointer to configuration option REPLACED_TARGET
*
* \todo Figure out error checking
*/
char *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, msre_ruleset *ruleset, rule_exception *re,
apr_array_header_t *phase_arr, const char *p2,
const char *p3)
{
msre_rule **rules;
int i, j, mode;
char *err;
j = 0;
mode = 0;
rules = (msre_rule **)phase_arr->elts;
for (i = 0; i < phase_arr->nelts; i++) {
msre_rule *rule = (msre_rule *)rules[i];
if (mode == 0) { /* Looking for next rule. */
if (msre_ruleset_rule_matches_exception(rule, re)) {
err = update_rule_target_ex(NULL, ruleset, rule, p2, p3);
if (err) return err;
if (rule->actionset->is_chained) mode = 2; /* Match all rules in this chain. */
} else {
if (rule->actionset->is_chained) mode = 1; /* Skip all rules in this chain. */
}
} else { /* Handling rule that is part of a chain. */
if (mode == 2) { /* We want to change the rule. */
err = update_rule_target_ex(msr, ruleset, rule, p2, p3);
if (err) return err;
} else {
rules[j++] = rules[i];
}
if ((rule->actionset == NULL)||(rule->actionset->is_chained == 0)) mode = 0;
}
}
return NULL;
}
char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *rule, const char *p2,
const char *p3) {
msre_var **targets = NULL;
msre_rule *rule = NULL;
msre_ruleset *ruleset = NULL;
const char *curr_targets = NULL;
const char *current_targets = NULL;
char *my_error_msg = NULL, *target = NULL;
char *p = NULL, *savedptr = NULL;
char *target_list = NULL, *replace = NULL;
unsigned int is_negated = 0, is_counting = 0;
int name_len = 0, value_len = 0;
char *name = NULL, *value = NULL;
char *opt = NULL, *param = NULL;
char *target_list = NULL, *replace = NULL;
int i, rc, match = 0;
int offset = 0;
if(p1 == NULL || p2 == NULL || (dcfg == NULL && rset == NULL)) {
return NULL;
}
if(rule != NULL) {
if(dcfg != NULL)
ruleset = dcfg->ruleset;
else if (rset != NULL)
ruleset = rset;
/* Get the ruleset if one exists */
if ((ruleset == NULL)||(ruleset == NOT_SET_P)) {
return NULL;
}
rule = msre_ruleset_fetch_rule(ruleset, p1, offset);
if (rule == NULL) {
return NULL;
}
target_list = strdup(p2);
if(target_list == NULL)
return NULL;
if(p3 != NULL) {
replace = strdup(p3);
if(replace == NULL) {
free(target_list);
target_list = NULL;
return NULL;
}
}
if(replace != NULL) {
opt = strchr(replace,'!');
if(opt != NULL) {
*opt = '\0';
opt++;
param = opt;
is_negated = 1;
} else if ((opt = strchr(replace,'&')) != NULL) {
*opt = '\0';
opt++;
param = opt;
is_counting = 1;
} else {
param = replace;
}
opt = strchr(param,':');
if(opt != NULL) {
name = apr_strtok(param,":",&value);
} else {
name = param;
}
name_len = strlen(name);
if(value != NULL)
value_len = strlen(value);
targets = (msre_var **)rule->targets->elts;
// TODO need a good way to remove the element from array, maybe change array by tables or rings
for (i = 0; i < rule->targets->nelts; i++) {
if((strlen(targets[i]->name) == strlen(name)) &&
(strncasecmp(targets[i]->name,name,strlen(targets[i]->name)) == 0) &&
(targets[i]->is_negated == is_negated) &&
(targets[i]->is_counting == is_counting)) {
if(value != NULL && targets[i]->param != NULL) {
if((strlen(targets[i]->param) == strlen(value)) &&
strncasecmp(targets[i]->param,value,strlen(targets[i]->param)) == 0) {
memset(targets[i]->name,0,strlen(targets[i]->name));
memset(targets[i]->param,0,strlen(targets[i]->param));
match = 1;
}
} else if (value == NULL && targets[i]->param == NULL){
memset(targets[i]->name,0,strlen(targets[i]->name));
match = 1;
} else
continue;
target_list = strdup(p2);
if(target_list == NULL)
return apr_psprintf(ruleset->mp, "Error to update target - memory allocation");;
if(p3 != NULL) {
replace = strdup(p3);
if(replace == NULL) {
free(target_list);
target_list = NULL;
return apr_psprintf(ruleset->mp, "Error to update target - memory allocation");;
}
}
}
p = apr_strtok(target_list, ",", &savedptr);
while(p != NULL) {
if(replace != NULL) {
if(match == 1) {
rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg);
if (rc < 0) {
goto end;
}
} else {
goto end;
}
} else {
target = strdup(p);
if(target == NULL)
return NULL;
is_negated = is_counting = 0;
param = name = value = NULL;
opt = strchr(target,'!');
opt = strchr(replace,'!');
if(opt != NULL) {
*opt = '\0';
opt++;
param = opt;
is_negated = 1;
} else if ((opt = strchr(target,'&')) != NULL) {
} else if ((opt = strchr(replace,'&')) != NULL) {
*opt = '\0';
opt++;
param = opt;
is_counting = 1;
} else {
param = target;
param = replace;
}
opt = strchr(param,':');
@ -193,14 +183,33 @@ char *update_rule_target(cmd_parms *cmd, directory_config *dcfg,
name = param;
}
if(apr_table_get(ruleset->engine->variables, name) == NULL) {
if(target_list != NULL)
free(target_list);
if(replace != NULL)
free(replace);
if(msr) {
msr_log(msr, 9, "Error to update target - [%s] is not valid target", name);
}
return apr_psprintf(ruleset->mp, "Error to update target - [%s] is not valid target", name);
}
name_len = strlen(name);
if(value != NULL)
value_len = strlen(value);
match = 0;
if(msr) {
msr_log(msr, 9, "Trying to replace by variable name [%s] value [%s]", name, value);
}
#if !defined(MSC_TEST)
else {
ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, " ModSecurity: Trying to replace by variable name [%s] value [%s]", name, value);
}
#endif
targets = (msre_var **)rule->targets->elts;
// TODO need a good way to remove the element from array, maybe change array by tables or rings
for (i = 0; i < rule->targets->nelts; i++) {
if((strlen(targets[i]->name) == strlen(name)) &&
(strncasecmp(targets[i]->name,name,strlen(targets[i]->name)) == 0) &&
@ -209,48 +218,258 @@ char *update_rule_target(cmd_parms *cmd, directory_config *dcfg,
if(value != NULL && targets[i]->param != NULL) {
if((strlen(targets[i]->param) == strlen(value)) &&
strncasecmp(targets[i]->param,value,strlen(targets[i]->param)) == 0) {
strncasecmp(targets[i]->param,value,strlen(targets[i]->param)) == 0) {
memset(targets[i]->name,0,strlen(targets[i]->name));
memset(targets[i]->param,0,strlen(targets[i]->param));
match = 1;
}
} else if (value == NULL && targets[i]->param == NULL){
memset(targets[i]->name,0,strlen(targets[i]->name));
match = 1;
} else
continue;
}
}
if(target != NULL) {
free(target);
target = NULL;
}
if(match == 0 ) {
rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg);
if (rc < 0) {
goto end;
}
}
}
p = apr_strtok(NULL,",",&savedptr);
p = apr_strtok(target_list, ",", &savedptr);
while(p != NULL) {
if(replace != NULL) {
if(match == 1) {
rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg);
if (rc < 0) {
if(msr) {
msr_log(msr, 9, "Error parsing rule targets to replace variable");
}
#if !defined(MSC_TEST)
else {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Error parseing rule targets to replace variable");
}
#endif
goto end;
}
if(msr) {
msr_log(msr, 9, "Successfuly replaced variable");
}
#if !defined(MSC_TEST)
else {
ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, " ModSecurity: Successfuly replaced variable");
}
#endif
} else {
if(msr) {
msr_log(msr, 9, "Cannot find variable to replace");
}
#if !defined(MSC_TEST)
else {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Cannot find varibale to replace");
}
#endif
goto end;
}
} else {
target = strdup(p);
if(target == NULL)
return NULL;
is_negated = is_counting = 0;
param = name = value = NULL;
opt = strchr(target,'!');
if(opt != NULL) {
*opt = '\0';
opt++;
param = opt;
is_negated = 1;
} else if ((opt = strchr(target,'&')) != NULL) {
*opt = '\0';
opt++;
param = opt;
is_counting = 1;
} else {
param = target;
}
opt = strchr(param,':');
if(opt != NULL) {
name = apr_strtok(param,":",&value);
} else {
name = param;
}
if(apr_table_get(ruleset->engine->variables, name) == NULL) {
if(target_list != NULL)
free(target_list);
if(replace != NULL)
free(replace);
if(msr) {
msr_log(msr, 9, "Error to update target - [%s] is not valid target", name);
}
return apr_psprintf(ruleset->mp, "Error to update target - [%s] is not valid target", name);
}
name_len = strlen(name);
if(value != NULL)
value_len = strlen(value);
if(msr) {
msr_log(msr, 9, "Trying to append variable name [%s] value [%s]", name, value);
}
#if !defined(MSC_TEST)
else {
ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, " ModSecurity: Trying to append variable name [%s] value [%s]", name, value);
}
#endif
match = 0;
targets = (msre_var **)rule->targets->elts;
for (i = 0; i < rule->targets->nelts; i++) {
if((strlen(targets[i]->name) == strlen(name)) &&
(strncasecmp(targets[i]->name,name,strlen(targets[i]->name)) == 0) &&
(targets[i]->is_negated == is_negated) &&
(targets[i]->is_counting == is_counting)) {
if(value != NULL && targets[i]->param != NULL) {
if((strlen(targets[i]->param) == strlen(value)) &&
strncasecmp(targets[i]->param,value,strlen(targets[i]->param)) == 0) {
match = 1;
}
} else if (value == NULL && targets[i]->param == NULL){
match = 1;
} else
continue;
}
}
if(target != NULL) {
free(target);
target = NULL;
}
if(match == 0 ) {
rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg);
if (rc < 0) {
if(msr) {
msr_log(msr, 9, "Error parsing rule targets to append variable");
}
#if !defined(MSC_TEST)
else {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Error parseing rule targets to append variable");
}
#endif
goto end;
}
} else {
if(msr) {
msr_log(msr, 9, "Skipping variable, already appended");
}
#if !defined(MSC_TEST)
else {
ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, " ModSecurity: Skipping variable, already appended");
}
#endif
}
}
p = apr_strtok(NULL,",",&savedptr);
}
if(match == 0) {
current_targets = msre_generate_target_string(ruleset->mp, rule);
rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, current_targets, NULL, NULL);
if(msr) {
msr_log(msr, 9, "Successfuly appended variable");
}
#if !defined(MSC_TEST)
else {
ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, " ModSecurity: Successfuly appended variable");
}
#endif
}
}
curr_targets = msre_generate_target_string(ruleset->mp, rule);
rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, curr_targets, NULL, NULL);
end:
if(target_list != NULL)
if(target_list != NULL) {
free(target_list);
if(replace != NULL)
target_list = NULL;
}
if(replace != NULL) {
free(replace);
if(target != NULL)
replace = NULL;
}
if(target != NULL) {
free(target);
target = NULL;
}
return NULL;
}
int msre_ruleset_rule_matches_exception(msre_rule *rule, rule_exception *re) {
int match = 0;
/* Only remove non-placeholder rules */
if (rule->placeholder == RULE_PH_NONE) {
switch(re->type) {
case RULE_EXCEPTION_REMOVE_ID :
if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) {
int ruleid = atoi(rule->actionset->id);
if (rule_id_in_range(ruleid, re->param)) {
match = 1;
}
}
break;
case RULE_EXCEPTION_REMOVE_MSG :
if ((rule->actionset != NULL)&&(rule->actionset->msg != NULL)) {
char *my_error_msg = NULL;
int rc = msc_regexec(re->param_data,
rule->actionset->msg, strlen(rule->actionset->msg),
&my_error_msg);
if (rc >= 0) {
match = 1;
}
}
break;
case RULE_EXCEPTION_REMOVE_TAG :
if ((rule->actionset != NULL)&&(apr_is_empty_table(rule->actionset->actions) == 0)) {
char *my_error_msg = NULL;
const apr_array_header_t *tarr = NULL;
const apr_table_entry_t *telts = NULL;
int act;
tarr = apr_table_elts(rule->actionset->actions);
telts = (const apr_table_entry_t*)tarr->elts;
for (act = 0; act < tarr->nelts; act++) {
msre_action *action = (msre_action *)telts[act].val;
if((action != NULL) && (action->metadata != NULL) && (strcmp("tag", action->metadata->name) == 0)) {
int rc = msc_regexec(re->param_data,
action->param, strlen(action->param),
&my_error_msg);
if (rc >= 0) {
match = 1;
}
}
}
}
break;
}
}
return match;
}
/**
* Remove actions with the same cardinality group from the actionset.
@ -824,7 +1043,7 @@ msre_actionset *msre_actionset_create(msre_engine *engine, const char *text,
actionset->intercept_action = NOT_SET;
actionset->intercept_uri = NOT_SET_P;
actionset->intercept_status = NOT_SET;
actionset->intercept_pause = NOT_SET;
actionset->intercept_pause = NOT_SET_P;
/* Other */
actionset->auditlog = NOT_SET;
@ -907,7 +1126,7 @@ msre_actionset *msre_actionset_merge(msre_engine *engine, msre_actionset *parent
}
if (child->intercept_status != NOT_SET) merged->intercept_status = child->intercept_status;
if (child->intercept_pause != NOT_SET) merged->intercept_pause = child->intercept_pause;
if (child->intercept_pause != NOT_SET_P) merged->intercept_pause = child->intercept_pause;
/* Other */
if (child->auditlog != NOT_SET) merged->auditlog = child->auditlog;
@ -962,7 +1181,7 @@ void msre_actionset_set_defaults(msre_actionset *actionset) {
if (actionset->intercept_action == NOT_SET) actionset->intercept_action = ACTION_NONE;
if (actionset->intercept_uri == NOT_SET_P) actionset->intercept_uri = NULL;
if (actionset->intercept_status == NOT_SET) actionset->intercept_status = 403;
if (actionset->intercept_pause == NOT_SET) actionset->intercept_pause = 0;
if (actionset->intercept_pause == NOT_SET_P) actionset->intercept_pause = NULL;
/* Other */
if (actionset->auditlog == NOT_SET) actionset->auditlog = 1;
@ -1222,13 +1441,35 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re
}
/* Check if this rule was removed at runtime */
if (((rule->actionset->id !=NULL) && !apr_is_empty_array(msr->removed_rules)) || (apr_is_empty_array(msr->removed_rules_tag)==0)) {
int j, act;
if (((rule->actionset->id !=NULL) && !apr_is_empty_array(msr->removed_rules)) ||
(apr_is_empty_array(msr->removed_rules_tag)==0) || (apr_is_empty_array(msr->removed_rules_msg)==0)) {
int j, act, rc;
int do_process = 1;
const char *range;
const char *range = NULL;
rule_exception *re = NULL;
char *my_error_msg, *error_msg;
const apr_array_header_t *tag_tarr = NULL;
const apr_table_entry_t *tag_telts = NULL;
for(j = 0; j < msr->removed_rules_msg->nelts; j++) {
re = ((rule_exception **)msr->removed_rules_msg->elts)[j];
if(rule->actionset->msg !=NULL) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Checking removal of rule msg=\"%s\" against: %s", rule->actionset->msg, re->param);
}
rc = msc_regexec(re->param_data,
rule->actionset->msg, strlen(rule->actionset->msg),
&my_error_msg);
if (rc >= 0) {
do_process = 0;
break;
}
}
}
for(j = 0; j < msr->removed_rules->nelts; j++) {
range = ((const char**)msr->removed_rules->elts)[j];
@ -1254,7 +1495,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re
if((action != NULL) && (action->metadata != NULL ) && strcmp("tag", action->metadata->name) == 0) {
for(j = 0; j < msr->removed_rules_tag->nelts; j++) {
range = ((const char**)msr->removed_rules_tag->elts)[j];
re = ((rule_exception **)msr->removed_rules_tag->elts)[j];
if(action->param != NULL) {
@ -1266,13 +1507,17 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re
expand_macros(msr, var, NULL, msr->mp);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Checking removal of rule tag=\"%s\" against: %s", var->value, range);
msr_log(msr, 9, "Checking removal of rule tag=\"%s\" against: %s", var->value, re->param);
}
if (strncasecmp(var->value, range, strlen(range)) == 0) {
rc = msc_regexec(re->param_data,
var->value, strlen(var->value),
&my_error_msg);
if (rc >= 0) {
do_process = 0;
break;
}
}
}
}
@ -1785,8 +2030,9 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) {
var->value_len = strlen(actionset->logdata);
expand_macros(msr, var, NULL, msr->mp);
logdata = apr_psprintf(msr->mp, " [data \"%s\"]",
logdata = apr_psprintf(msr->mp, " [data \"%s",
log_escape_hex(msr->mp, (unsigned char *)var->value, var->value_len));
logdata = apr_pstrcat(msr->mp, logdata, "\"]", NULL);
/* If it is > 512 bytes, then truncate at 512 with ellipsis.
* NOTE: 512 actual data + 9 bytes of label = 521
@ -1892,7 +2138,7 @@ msre_rule *msre_rule_create(msre_ruleset *ruleset, int type,
msre_rule *rule;
char *my_error_msg;
const char *argsp;
int rc;
int rc, idx;
if (error_msg == NULL) return NULL;
*error_msg = NULL;
@ -2125,7 +2371,6 @@ static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr,
apr_time_t time_before_op = 0;
char *my_error_msg = NULL;
const char *full_varname = NULL;
char *parm = NULL;
int rc;
/* determine the full var name if not already resolved
@ -2161,7 +2406,7 @@ static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr,
#if defined(PERFORMANCE_MEASUREMENT)
time_before_op = apr_time_now();
#else
if (msr->txcfg->debuglog_level >= 4) {
if (msr->txcfg->debuglog_level >= 4 || msr->txcfg->max_rule_time > 0) {
time_before_op = apr_time_now();
}
#endif
@ -2179,7 +2424,26 @@ static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr,
apr_time_t t1 = apr_time_now();
msr_log(msr, 4, "Operator completed in %" APR_TIME_T_FMT " usec.", (t1 - time_before_op));
}
#endif
if(msr->txcfg->max_rule_time > 0) {
apr_time_t t1 = apr_time_now();
apr_time_t rule_time = 0;
const char *rt_time = NULL;
if(rule->actionset->id != NULL) {
rt_time = apr_table_get(msr->perf_rules, rule->actionset->id);
if(rt_time == NULL) {
rt_time = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (t1 - time_before_op));
apr_table_setn(msr->perf_rules, rule->actionset->id, rt_time);
} else {
rule_time = (apr_time_t)atoi(rt_time);
rule_time += (t1 - time_before_op);
rt_time = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, rule_time);
apr_table_setn(msr->perf_rules, rule->actionset->id, rt_time);
}
}
}
#endif
if (rc < 0) {
msr_log(msr, 4, "Operator error: %s", my_error_msg);
@ -2211,36 +2475,20 @@ static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr,
/* Save the last matched var data */
if(var != NULL && msr != NULL) {
msc_string *mvar = NULL;
msr->matched_var->name = apr_pstrdup(msr->mp, var->name);
msr->matched_var->name_len = strlen(msr->matched_var->name);
msr->matched_var->value = apr_pmemdup(msr->mp, var->value, var->value_len);
msr->matched_var->value_len = var->value_len;
parm = strchr(msr->matched_var->name,':');
mvar = apr_palloc(msr->mp, sizeof(msc_string));
mvar->name = apr_pstrdup(msr->mp, var->name);
mvar->name_len = strlen(mvar->name);
mvar->value = apr_pmemdup(msr->mp, var->value, var->value_len);
mvar->value_len = var->value_len;
if(parm) {
msc_string *mvar = NULL;
parm++;
mvar = apr_palloc(msr->mp, sizeof(msc_string));
mvar->name = apr_pstrdup(msr->mp, parm);
mvar->name_len = strlen(mvar->name);
mvar->value = apr_pmemdup(msr->mp, var->value, var->value_len);
mvar->value_len = var->value_len;
apr_table_addn(msr->matched_vars, parm, (void *)mvar);
} else {
msc_string *mvar = apr_palloc(msr->mp, sizeof(msc_string));
mvar->name = apr_pstrdup(msr->mp, var->name);
mvar->name_len = strlen(mvar->name);
mvar->value = apr_pmemdup(msr->mp, var->value, var->value_len);
mvar->value_len = var->value_len;
apr_table_addn(msr->matched_vars, mvar->name, (void *)mvar);
}
apr_table_addn(msr->matched_vars, mvar->name, (void *)mvar);
}

Просмотреть файл

@ -47,7 +47,16 @@ typedef struct msre_cache_rec msre_cache_rec;
#endif
/* Actions, variables, functions and operator functions */
char DSOLOCAL *update_rule_target(cmd_parms *cmd, directory_config *dcfg, msre_ruleset *rset, const char *p1, const char *p2, const char *p3);
char DSOLOCAL *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *rule, const char *p2,
const char *p3);
int DSOLOCAL msre_ruleset_rule_matches_exception(msre_rule *rule, rule_exception *re);
char DSOLOCAL *msre_ruleset_rule_update_target_matching_exception(modsec_rec *msr, msre_ruleset *ruleset, rule_exception *re,
const char *p2, const char *p3);
char DSOLOCAL *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, msre_ruleset *ruleset, rule_exception *re,
apr_array_header_t *phase_arr, const char *p2, const char *p3);
apr_status_t DSOLOCAL collection_original_setvar(modsec_rec *msr, const char *col_name, const msc_string *orig_var);
@ -295,7 +304,7 @@ struct msre_actionset {
int intercept_action;
const char *intercept_uri;
int intercept_status;
int intercept_pause;
const char *intercept_pause;
/* "block" needs parent action to reset it */
msre_action *parent_intercept_action_rec;

Просмотреть файл

@ -370,6 +370,14 @@ apr_status_t collection_original_setvar(modsec_rec *msr, const char *col_name, c
return 0;
}
/* marker */
static apr_status_t msre_action_marker_init(msre_engine *engine, msre_actionset *actionset,
msre_action *action)
{
actionset->id = action->param;
return 1;
}
/* id */
static apr_status_t msre_action_id_init(msre_engine *engine, msre_actionset *actionset,
@ -379,10 +387,27 @@ static apr_status_t msre_action_id_init(msre_engine *engine, msre_actionset *act
return 1;
}
static char *msre_action_id_validate(msre_engine *engine, msre_action *action) {
int id;
if(action != NULL && action->param != NULL) {
for(id=0;id<strlen(action->param);id++) {
if(!apr_isdigit(action->param[id]))
return apr_psprintf(engine->mp, "ModSecurity: Invalid value for action ID: %s", action->param);
}
id = atoi(action->param);
if ((id == LONG_MAX)||(id == LONG_MIN)||(id <= 0)) {
return apr_psprintf(engine->mp, "ModSecurity: Invalid value for action ID: %s", action->param);
}
}
return NULL;
}
/* rev */
static apr_status_t msre_action_rev_init(msre_engine *engine, msre_actionset *actionset,
msre_action *action)
msre_action *action)
{
actionset->rev = action->param;
return 1;
@ -534,7 +559,7 @@ static char *msre_action_pause_validate(msre_engine *engine, msre_action *action
static apr_status_t msre_action_pause_init(msre_engine *engine, msre_actionset *actionset,
msre_action *action)
{
actionset->intercept_pause = atoi(action->param);
actionset->intercept_pause = action->param;
return 1;
}
@ -686,7 +711,15 @@ static char *msre_action_phase_validate(msre_engine *engine, msre_action *action
static apr_status_t msre_action_phase_init(msre_engine *engine, msre_actionset *actionset,
msre_action *action)
{
actionset->phase = atoi(action->param);
if(strcasecmp(action->param,"request") == 0)
actionset->phase = 2;
else if(strcasecmp(action->param,"response") == 0)
actionset->phase = 4;
else if(strcasecmp(action->param,"logging") == 0)
actionset->phase = 5;
else
actionset->phase = atoi(action->param);
return 1;
}
@ -734,7 +767,13 @@ static char *msre_action_ctl_validate(msre_engine *engine, msre_action *action)
return NULL;
} else
if (strcasecmp(name, "ruleRemoveByTag") == 0) {
/* ENH nothing yet */
if (!msc_pregcomp(engine->mp, value, 0, NULL, NULL))
return apr_psprintf(engine->mp, "ModSecurity: Invalid regular expression \"%s\"", value);
return NULL;
} else
if (strcasecmp(name, "ruleRemoveByMsg") == 0) {
if (!msc_pregcomp(engine->mp, value, 0, NULL, NULL))
return apr_psprintf(engine->mp, "ModSecurity: Invalid regular expression \"%s\"", value);
return NULL;
} else
if (strcasecmp(name, "requestBodyAccess") == 0) {
@ -828,11 +867,44 @@ static char *msre_action_ctl_validate(msre_engine *engine, msre_action *action)
if(parm == NULL && savedptr == NULL)
return apr_psprintf(engine->mp, "ruleUpdateTargetById must has at least id;append_value");
return NULL;
}
else {
return NULL;
} else
if (strcasecmp(name,"ruleUpdateTargetByTag") == 0) {
char *parm = NULL;
char *savedptr = NULL;
parm = apr_strtok(value,";",&savedptr);
if(parm == NULL && savedptr == NULL)
return apr_psprintf(engine->mp, "ruleUpdateTargetByTag must has at least tag;append_value");
if (!msc_pregcomp(engine->mp, parm, 0, NULL, NULL)) {
return apr_psprintf(engine->mp, "ModSecurity: Invalid regular expression \"%s\"", parm);
}
return NULL;
} else
if (strcasecmp(name,"ruleUpdateTargetByMsg") == 0) {
char *parm = NULL;
char *savedptr = NULL;
parm = apr_strtok(value,";",&savedptr);
if(parm == NULL && savedptr == NULL)
return apr_psprintf(engine->mp, "ruleUpdateTargetByMsg must has at least msg;append_value");
if (!msc_pregcomp(engine->mp, parm, 0, NULL, NULL)) {
return apr_psprintf(engine->mp, "ModSecurity: Invalid regular expression \"%s\"", parm);
}
return NULL;
} else
if (strcasecmp(name, "EncryptionEnforcement") == 0) {
if (strcasecmp(value, "on") == 0) return NULL;
if (strcasecmp(value, "off") == 0) return NULL;
return apr_psprintf(engine->mp, "Invalid setting for ctl name EncryptionEnforcement: %s", value);
} else
if (strcasecmp(name, "EncryptionEngine") == 0) {
if (strcasecmp(value, "on") == 0) return NULL;
if (strcasecmp(value, "off") == 0) return NULL;
return apr_psprintf(engine->mp, "Invalid setting for ctl name EncryptionEngine: %s", value);
} else {
return apr_psprintf(engine->mp, "Invalid ctl name setting: %s", name);
}
}
}
static apr_status_t msre_action_ctl_init(msre_engine *engine, msre_actionset *actionset,
@ -879,17 +951,51 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp,
return 1;
} else
if (strcasecmp(name, "EncryptionEnforcement") == 0) {
if (strcasecmp(value, "on") == 0) {
msr->txcfg->encryption_enforcement = ENCRYPTION_ENABLED;
msr->usercfg->encryption_enforcement = ENCRYPTION_ENABLED;
}
if (strcasecmp(value, "off") == 0) {
msr->txcfg->encryption_enforcement = ENCRYPTION_DISABLED;
msr->usercfg->encryption_enforcement = ENCRYPTION_DISABLED;
}
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Ctl: Set EncryptionEnforcement to %s.", value);
}
} else
if (strcasecmp(name, "EncryptionEngine") == 0) {
if (strcasecmp(value, "on") == 0) {
msr->txcfg->encryption_is_enabled = ENCRYPTION_ENABLED;
msr->usercfg->encryption_is_enabled = ENCRYPTION_ENABLED;
}
if (strcasecmp(value, "off") == 0) {
msr->txcfg->encryption_is_enabled = ENCRYPTION_DISABLED;
msr->usercfg->encryption_is_enabled = ENCRYPTION_DISABLED;
}
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Ctl: Set EncryptionEngine to %s.", value);
}
} else
if (strcasecmp(name, "ruleRemoveById") == 0) {
*(const char **)apr_array_push(msr->removed_rules) = (const char *)apr_pstrdup(msr->mp, value);
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Ctl: Removed rule by id : %s.", value);
}
return 1;
} else
if (strcasecmp(name, "ruleRemoveByTag") == 0) {
*(const char **)apr_array_push(msr->removed_rules_tag) = (const char *)apr_pstrdup(msr->mp, value);
rule_exception *re = apr_pcalloc(mptmp, sizeof(rule_exception));
re->type = RULE_EXCEPTION_REMOVE_TAG;
re->param = (const char *)apr_pstrdup(msr->mp, value);;
re->param_data = msc_pregcomp(msr->mp, re->param, 0, NULL, NULL);
if (re->param_data == NULL) {
msr_log(msr, 1, "ModSecurity: Invalid regular expression \"%s\"", re->param);
return -1;
}
*(rule_exception **)apr_array_push(msr->removed_rules_tag) = re;
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Ctl: Removed rule by tag : %s.", value);
@ -897,6 +1003,24 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp,
return 1;
} else
if (strcasecmp(name, "ruleRemoveByMsg") == 0) {
rule_exception *re = apr_pcalloc(mptmp, sizeof(rule_exception));
re->type = RULE_EXCEPTION_REMOVE_MSG;
re->param = (const char *)apr_pstrdup(msr->mp, value);;
re->param_data = msc_pregcomp(msr->mp, re->param, 0, NULL, NULL);
if (re->param_data == NULL) {
msr_log(msr, 1, "ModSecurity: Invalid regular expression \"%s\"", re->param);
return -1;
}
*(rule_exception **)apr_array_push(msr->removed_rules_msg) = re;
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Ctl: Removed rule by msg : %s.", value);
}
return 1;
} else
if (strcasecmp(name, "requestBodyAccess") == 0) {
int pv = parse_boolean(value);
@ -1047,6 +1171,7 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp,
return 1;
} else
if (strcasecmp(name, "ruleUpdateTargetById") == 0) {
rule_exception *re = NULL;
char *p1 = NULL, *p2 = NULL, *p3 = NULL;
char *savedptr = NULL;
@ -1059,10 +1184,63 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp,
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Ctl: ruleUpdateTargetById id=%s append=%s replace=%s", p1, p2, p3);
}
re = apr_pcalloc(mptmp, sizeof(rule_exception));
re->type = RULE_EXCEPTION_REMOVE_ID;
re->param = p1;
msre_ruleset_rule_update_target_matching_exception(msr, rule->ruleset, re, p2, p3);
return 1;
} else
if (strcasecmp(name, "ruleUpdateTargetByTag") == 0) {
rule_exception *re = NULL;
char *p1 = NULL, *p2 = NULL, *p3 = NULL;
char *savedptr = NULL;
update_rule_target(NULL, NULL, rule->ruleset, p1, p2, p3);
p1 = apr_strtok(value,";",&savedptr);
return 1;
p2 = apr_strtok(NULL,";",&savedptr);
p3 = apr_strtok(NULL,";",&savedptr);
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Ctl: ruleUpdateTargetByTag tag=%s append=%s replace=%s", p1, p2, p3);
}
re = apr_pcalloc(mptmp, sizeof(rule_exception));
re->type = RULE_EXCEPTION_REMOVE_TAG;
re->param = p1;
re->param_data = msc_pregcomp(mptmp, p1, 0, NULL, NULL);
if (re->param_data == NULL) {
msr_log(msr, 1, "ModSecurity: Invalid regular expression \"%s\"", p1);
return -1;
}
msre_ruleset_rule_update_target_matching_exception(msr, rule->ruleset, re, p2, p3);
return 1;
} else
if (strcasecmp(name, "ruleUpdateTargetByMsg") == 0) {
rule_exception *re = NULL;
char *p1 = NULL, *p2 = NULL, *p3 = NULL;
char *savedptr = NULL;
p1 = apr_strtok(value,";",&savedptr);
p2 = apr_strtok(NULL,";",&savedptr);
p3 = apr_strtok(NULL,";",&savedptr);
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Ctl: ruleUpdateTargetByMsg tag=%s append=%s replace=%s", p1, p2, p3);
}
re = apr_pcalloc(mptmp, sizeof(rule_exception));
re->type = RULE_EXCEPTION_REMOVE_MSG;
re->param = p1;
re->param_data = msc_pregcomp(mptmp, p1, 0, NULL, NULL);
if (re->param_data == NULL) {
msr_log(msr, 1, "ModSecurity: Invalid regular expression \"%s\"", p1);
return -1;
}
msre_ruleset_rule_update_target_matching_exception(msr, rule->ruleset, re, p2, p3);
return 1;
}
else {
/* Should never happen, but log if it does. */
@ -1855,7 +2033,7 @@ static apr_status_t msre_action_initcol_execute(modsec_rec *msr, apr_pool_t *mpt
/* IMP1 We have a function for this now, parse_name_eq_value? */
s = strstr(data, "=");
if (s == NULL) return 0;
col_name = strtolower_inplace(data);
col_name = strtolower_inplace((unsigned char *)data);
col_key = s + 1;
*s = '\0';
@ -1919,6 +2097,29 @@ static apr_status_t msre_action_setuid_execute(modsec_rec *msr, apr_pool_t *mptm
return init_collection(msr, real_col_name, "USER", col_key, col_key_len);
}
/* setrsc */
static apr_status_t msre_action_setrsc_execute(modsec_rec *msr, apr_pool_t *mptmp,
msre_rule *rule, msre_action *action)
{
msc_string *var = NULL;
char *real_col_name = NULL, *col_key = NULL;
unsigned int col_key_len;
/* Construct user ID. */
var = apr_pcalloc(mptmp, sizeof(msc_string));
var->value = (char *)action->param;
var->value_len = strlen(var->value);
expand_macros(msr, var, rule, mptmp);
/* Construct collection name. */
col_key = var->value;
col_key_len = var->value_len;
real_col_name = apr_psprintf(mptmp, "%s_RESOURCE", msr->txcfg->webappid);
/* Initialise collection. */
return init_collection(msr, real_col_name, "RESOURCE", col_key, col_key_len);
}
/* exec */
static char *msre_action_exec_validate(msre_engine *engine, msre_action *action) {
#if defined(WITH_LUA)
@ -2027,11 +2228,24 @@ void msre_engine_register_default_actions(msre_engine *engine) {
NO_PLUS_MINUS,
ACTION_CARDINALITY_ONE,
ACTION_CGROUP_NONE,
NULL,
msre_action_id_validate,
msre_action_id_init,
NULL
);
/* marker */
msre_engine_action_register(engine,
"marker",
ACTION_METADATA,
1, 1,
NO_PLUS_MINUS,
ACTION_CARDINALITY_ONE,
ACTION_CGROUP_NONE,
NULL,
msre_action_marker_init,
NULL
);
/* rev */
msre_engine_action_register(engine,
"rev",
@ -2566,6 +2780,19 @@ void msre_engine_register_default_actions(msre_engine *engine) {
msre_action_setsid_execute
);
/* setuid */
msre_engine_action_register(engine,
"setrsc",
ACTION_NON_DISRUPTIVE,
1, 1,
NO_PLUS_MINUS,
ACTION_CARDINALITY_ONE,
ACTION_CGROUP_NONE,
NULL,
NULL,
msre_action_setrsc_execute
);
/* setuid */
msre_engine_action_register(engine,
"setuid",

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -24,6 +24,18 @@
/* cmdline */
/**
* \brief cmdline transformation function
*
* \param mptmp Pointer to resource pool
* \param input Pointer to input data
* \param input_len Input data length
* \param rval Pointer to decoded buffer
* \param rval_len Decoded buffer length
*
* \retval 0 On failure
* \retval 1 On Success
*/
static int msre_fn_cmdline_execute(apr_pool_t *mptmp, unsigned char *input,
long int input_len, char **rval, long int *rval_len)
{
@ -302,6 +314,15 @@ static int msre_fn_removeCommentsChar_execute(apr_pool_t *mptmp, unsigned char *
} else if ((input[i] == '*')&&(i + 1 < input_len)&&(input[i + 1] == '/')) {
changed = 1;
i += 2;
} else if ((input[i] == '<')&&(i + 1 < input_len)&&(input[i + 1] == '!')&&
(i + 2 < input_len)&&(input[i+2] == '-')&&(i + 3 < input_len)&&
(input[i + 3] == '-')) {
changed = 1;
i += 4;
} else if ((input[i] == '-')&&(i + 1 < input_len)&&(input[i + 1] == '-')&&
(i + 2 < input_len)&&(input[i+2] == '>')) {
changed = 1;
i += 3;
} else if ((input[i] == '-')&&(i + 1 < input_len)&&(input[i + 1] == '-')) {
changed = 1;
i += 2;
@ -337,16 +358,21 @@ static int msre_fn_removeComments_execute(apr_pool_t *mptmp, unsigned char *inpu
changed = 1;
incomment = 1;
i += 2;
} else if ((input[i] == '-')&&(i + 1 < input_len)&&(input[i + 1] == '-')) {
} else if ((input[i] == '<')&&(i + 1 < input_len)&&(input[i + 1] == '!')&&
(i + 2 < input_len)&&(input[i+2] == '-')&&(i + 3 < input_len)&&
(input[i + 3] == '-') && (incomment == 0)) {
incomment = 1;
changed = 1;
i += 4;
} else if ((input[i] == '-')&&(i + 1 < input_len)&&(input[i + 1] == '-')
&& (incomment == 0)) {
changed = 1;
input[i] = ' ';
break;
i += 2;
} else if (input[i] == '#') {
} else if (input[i] == '#' && (incomment == 0)) {
changed = 1;
input[i] = ' ';
break;
i++;
} else {
input[j] = input[i];
i++;
@ -359,6 +385,13 @@ static int msre_fn_removeComments_execute(apr_pool_t *mptmp, unsigned char *inpu
input[j] = input[i];
i++;
j++;
} else if ((input[i] == '-')&&(i + 1 < input_len)&&(input[i + 1] == '-')&&
(i + 2 < input_len)&&(input[i+2] == '>')) {
incomment = 0;
i += 3;
input[j] = input[i];
i++;
j++;
} else {
i++;
}
@ -544,8 +577,18 @@ static int msre_fn_sha1_execute(apr_pool_t *mptmp, unsigned char *input,
return 1;
}
/* sqlHexDecode */
/**
* \brief SqlHexDecode transformation function. Transform xNN data.
*
* \param mptmp Pointer to resource pool
* \param input Pointer to input data
* \param input_len Input data length
* \param rval Pointer to decoded buffer
* \param rval_len Decoded buffer length
*
* \retval 0 On failure
* \retval 1 On Success
*/
static int msre_fn_sqlHexDecode_execute(apr_pool_t *mptmp, unsigned char *input,
long int input_len, char **rval, long int *rval_len)
{
@ -720,10 +763,10 @@ static int msre_fn_parityOdd7bit_execute(apr_pool_t *mptmp, unsigned char *input
return changed;
}
/*
/**
* \brief Base64 transformation function based on RFC2045
*
* \param mptmp Pointer to resource poil
* \param mptmp Pointer to resource pool
* \param input Pointer to input data
* \param input_len Input data length
* \param rval Pointer to decoded buffer

Просмотреть файл

@ -675,6 +675,14 @@ static int var_webserver_error_log_generate(modsec_rec *msr, msre_var *var, msre
return count;
}
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
static int var_useragent_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
apr_table_t *vartab, apr_pool_t *mptmp)
{
return var_simple_generate(var, vartab, mptmp, msr->useragent_ip ? msr->useragent_ip : "0.0.0.0");
}
#endif
/* REMOTE_ADDR */
static int var_remote_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
@ -1613,6 +1621,50 @@ static int var_perf_logging_generate(modsec_rec *msr, msre_var *var, msre_rule *
return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_logging);
}
/* PERF_RULES */
static int var_perf_rules_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
apr_table_t *vartab, apr_pool_t *mptmp)
{
const apr_array_header_t *arr = NULL;
const apr_table_entry_t *te = NULL;
int i, count = 0;
arr = apr_table_elts(msr->perf_rules);
te = (apr_table_entry_t *)arr->elts;
for (i = 0; i < arr->nelts; i++) {
int match = 0;
/* Figure out if we want to include this variable. */
if (var->param == NULL) match = 1;
else {
if (var->param_data != NULL) { /* Regex. */
char *my_error_msg = NULL;
if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key,
strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1;
} else { /* Simple comparison. */
if (strcasecmp(te[i].key, var->param) == 0) match = 1;
}
}
/* If we had a match add this argument to the collection. */
if (match) {
msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
rvar->value = te[i].val;
rvar->value_len = strlen(rvar->value);
rvar->name = apr_psprintf(mptmp, "PERF_RULES:%s",
log_escape_nq(mptmp, te[i].key));
apr_table_addn(vartab, rvar->name, (void *)rvar);
count++;
}
}
return count;
}
/* DURATION */
static int var_duration_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
@ -1622,9 +1674,8 @@ static int var_duration_generate(modsec_rec *msr, msre_var *var, msre_rule *rule
rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
rvar->value = apr_psprintf(mptmp, "%" APR_TIME_T_FMT,
(apr_time_msec(apr_time_now() - msr->r->request_time)));
(apr_time_usec(apr_time_now() - msr->r->request_time)));
rvar->value_len = strlen(rvar->value);
apr_table_addn(vartab, rvar->name, (void *)rvar);
return 1;
@ -1875,7 +1926,7 @@ static int var_matched_vars_names_generate(modsec_rec *msr, msre_var *var, msre_
rvar->value = apr_pstrndup(mptmp, str->name, strlen(str->name));
rvar->value_len = strlen(rvar->value);
rvar->name = apr_psprintf(mptmp, "MATCHED_VARS_NAMES:%s",
rvar->name = apr_psprintf(mptmp, "%s",
log_escape_nq(mptmp, str->name));
if(var->is_counting == 0)
@ -1891,7 +1942,7 @@ static int var_matched_vars_names_generate(modsec_rec *msr, msre_var *var, msre_
apr_table_addn(vartab, rvar->name, (void *)rvar);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Set variable \"%s\" value \"%s\" size %d to collection.", rvar->name, rvar->value, rvar->value_len);
msr_log(msr, 9, "Set variable \"%s\" size %d to collection.", rvar->name,rvar->value_len);
}
count++;
@ -1935,7 +1986,7 @@ static int var_matched_vars_generate(modsec_rec *msr, msre_var *var, msre_rule *
rvar->value = apr_pstrndup(mptmp, str->value, str->value_len);
rvar->value_len = str->value_len;
rvar->name = apr_psprintf(mptmp, "MATCHED_VARS:%s",
rvar->name = apr_psprintf(mptmp, "%s",
log_escape_nq(mptmp, str->name));
if(var->is_counting == 0)
@ -2913,6 +2964,19 @@ void msre_engine_register_default_variables(msre_engine *engine) {
PHASE_REQUEST_HEADERS
);
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
/* USERAGENT_IP */
msre_engine_variable_register(engine,
"USERAGENT_IP",
VAR_SIMPLE,
0, 0,
NULL,
var_useragent_ip_generate,
VAR_CACHE,
PHASE_REQUEST_HEADERS
);
#endif
/* REMOTE_ADDR */
msre_engine_variable_register(engine,
"REMOTE_ADDR",
@ -3508,7 +3572,18 @@ void msre_engine_register_default_variables(msre_engine *engine) {
VAR_DONT_CACHE, /* dynamic */
PHASE_RESPONSE_HEADERS
);
/* PERF_RULES */
msre_engine_variable_register(engine,
"PERF_RULES",
VAR_LIST,
0, 1,
var_generic_list_validate,
var_perf_rules_generate,
VAR_DONT_CACHE,
PHASE_REQUEST_HEADERS
);
/* PERF_ALL */
msre_engine_variable_register(engine,
"PERF_ALL",
@ -3519,7 +3594,7 @@ void msre_engine_register_default_variables(msre_engine *engine) {
VAR_DONT_CACHE,
PHASE_REQUEST_HEADERS
);
/* PERF_COMBINED */
msre_engine_variable_register(engine,
"PERF_COMBINED",
@ -3530,7 +3605,7 @@ void msre_engine_register_default_variables(msre_engine *engine) {
VAR_DONT_CACHE,
PHASE_REQUEST_HEADERS
);
/* PERF_GC */
msre_engine_variable_register(engine,
"PERF_GC",
@ -3541,7 +3616,7 @@ void msre_engine_register_default_variables(msre_engine *engine) {
VAR_DONT_CACHE,
PHASE_REQUEST_HEADERS
);
/* PERF_LOGGING */
msre_engine_variable_register(engine,
"PERF_LOGGING",
@ -3552,7 +3627,7 @@ void msre_engine_register_default_variables(msre_engine *engine) {
VAR_DONT_CACHE,
PHASE_REQUEST_HEADERS
);
/* PERF_PHASE1 */
msre_engine_variable_register(engine,
"PERF_PHASE1",
@ -3563,7 +3638,7 @@ void msre_engine_register_default_variables(msre_engine *engine) {
VAR_DONT_CACHE,
PHASE_REQUEST_HEADERS
);
/* PERF_PHASE2 */
msre_engine_variable_register(engine,
"PERF_PHASE2",
@ -3574,7 +3649,7 @@ void msre_engine_register_default_variables(msre_engine *engine) {
VAR_DONT_CACHE,
PHASE_REQUEST_HEADERS
);
/* PERF_PHASE3 */
msre_engine_variable_register(engine,
"PERF_PHASE3",
@ -3585,7 +3660,7 @@ void msre_engine_register_default_variables(msre_engine *engine) {
VAR_DONT_CACHE,
PHASE_REQUEST_HEADERS
);
/* PERF_PHASE4 */
msre_engine_variable_register(engine,
"PERF_PHASE4",
@ -3596,7 +3671,7 @@ void msre_engine_register_default_variables(msre_engine *engine) {
VAR_DONT_CACHE,
PHASE_REQUEST_HEADERS
);
/* PERF_PHASE5 */
msre_engine_variable_register(engine,
"PERF_PHASE5",
@ -3607,7 +3682,7 @@ void msre_engine_register_default_variables(msre_engine *engine) {
VAR_DONT_CACHE,
PHASE_REQUEST_HEADERS
);
/* PERF_SREAD */
msre_engine_variable_register(engine,
"PERF_SREAD",
@ -3618,7 +3693,7 @@ void msre_engine_register_default_variables(msre_engine *engine) {
VAR_DONT_CACHE,
PHASE_REQUEST_HEADERS
);
/* PERF_SWRITE */
msre_engine_variable_register(engine,
"PERF_SWRITE",
@ -3629,7 +3704,7 @@ void msre_engine_register_default_variables(msre_engine *engine) {
VAR_DONT_CACHE,
PHASE_REQUEST_HEADERS
);
/* DURATION */
msre_engine_variable_register(engine,
"DURATION",

Просмотреть файл

@ -6,7 +6,7 @@ dnl
AC_PREREQ(2.63)
AC_INIT([modsecurity], [2.6], [support@modsecurity.org])
AC_INIT([modsecurity], [2.7], [support@modsecurity.org])
AC_CONFIG_MACRO_DIR([build])
AC_CONFIG_SRCDIR([LICENSE])
@ -304,6 +304,38 @@ AC_ARG_ENABLE(pcre-match-limit-recursion,
pcre_match_limit_recursion='-DMODSEC_PCRE_MATCH_LIMIT_RECURSION=1500'
])
# Enable Lua per transaction cache
AC_ARG_ENABLE(lua-cache,
AS_HELP_STRING([--enable-lua-cache],
[Enable Lua per transaction cache.]),
[
if test "$enableval" != "no"; then
lua_cache="-DCACHE_LUA"
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $lua_cache"
else
lua_cache=
fi
],
[
lua_cache=
])
# Enable phase-1 in post_read_request
AC_ARG_ENABLE(request-early,
AS_HELP_STRING([--enable-request-early],
[Place phase1 into post_read_request hook.]),
[
if test "$enableval" != "no"; then
request_early="-DREQUEST_EARLY"
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $request_early"
else
request_early=
fi
],
[
request_early='-DREQUEST_EARLY'
])
# Ignore configure errors
AC_ARG_ENABLE(errors,
AS_HELP_STRING([--disable-errors],
@ -567,7 +599,7 @@ else
fi
fi
MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api"
MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api"
APXS_WRAPPER=build/apxs-wrapper
APXS_EXTRA_CFLAGS=""