Implemented SecRuleUpdateActionById. See #442.

This commit is contained in:
brectanus 2008-01-19 02:23:41 +00:00
parent be096d8f7c
commit 0d24a08f33
6 changed files with 220 additions and 5 deletions

View File

@ -1,6 +1,8 @@
02 Jan 2008 - 2.5.0-rc2
-----------------------
* Implemented SecRuleUpdateActionById.
* Phase 5 rules can now be removed via SecRuleRemoveBy* directives.
* Build is now 'configure' based (autotools).

View File

@ -98,11 +98,13 @@ test: t/run-tests.pl msc_test
mlogc:
@$(MAKE) -C mlogc-src mlogc \
&& cp -p mlogc-src/mlogc . \
&& echo "mlogc-src/INSTALL" \
&& echo \
&& echo "See: mlogc-src/INSTALL" \
&& echo
mlogc-static:
@$(MAKE) -C mlogc-src static \
&& cp -p mlogc-src/mlogc mlogc-static \
&& echo "mlogc-src/INSTALL" \
&& echo \
&& echo "See: mlogc-src/INSTALL" \
&& echo

View File

@ -742,6 +742,120 @@ static const char *add_marker(cmd_parms *cmd, directory_config *dcfg, const char
return NULL;
}
/**
*
*/
static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg,
const char *p1, const char *p2)
{
char *my_error_msg = NULL;
msre_rule *rule = NULL;
msre_actionset *new_actionset = NULL;
msre_ruleset *ruleset = dcfg->ruleset;
extern msc_engine *modsecurity;
/* Get the ruleset if one exists */
if ((ruleset == NULL)||(ruleset == NOT_SET_P)) {
return NULL;
}
#ifdef DEBUG_CONF
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
"Looking to update rule id=\"%s\" with \"%s\".", p1, p2);
#endif
/* Fetch the rule */
rule = msre_ruleset_fetch_rule(ruleset, p1);
if (rule == NULL) {
#ifdef DEBUG_CONF
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
"Failed to update rule id=\"%s\" with \"%s\": Rule not found.", p1, p2);
#endif
return NULL;
}
/* Check the rule actionset */
/* ENH: Can this happen? */
if (rule->actionset == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Attempt to update action for rule \"%s\" failed: Rule does not have an actionset.", p1);
}
/* Create a new actionset */
new_actionset = msre_actionset_create(modsecurity->msre, p2, &my_error_msg);
if (dcfg->tmp_default_actionset == NULL) return FATAL_ERROR;
if (my_error_msg != NULL) return my_error_msg;
/* Must NOT change an id */
if ((new_actionset->id != NOT_SET_P) && (rule->actionset->id != NULL) && (strcmp(rule->actionset->id, new_actionset->id) != 0)) {
return apr_psprintf(cmd->pool, "ModSecurity: Rule IDs cannot be updated via SecRuleUpdateActionById.");
}
/* Must NOT alter the phase */
if ((new_actionset->phase != NOT_SET) && (rule->actionset->phase != new_actionset->phase)) {
return apr_psprintf(cmd->pool, "ModSecurity: Rule phases cannot be updated via SecRuleUpdateActionById.");
}
#ifdef DEBUG_CONF
{
const apr_array_header_t *tarr = apr_table_elts(rule->actionset->actions);
const apr_table_entry_t *telts = (const apr_table_entry_t*)tarr->elts;
char *actions = NULL;
int i;
for (i = 0; i < tarr->nelts; i++) {
msre_action *action = (msre_action *)telts[i].val;
actions = apr_pstrcat(ruleset->mp,
(actions == NULL) ? "" : actions,
(actions == NULL) ? "" : ",",
action->metadata->name,
(action->param == NULL) ? "" : ":'",
(action->param == NULL) ? "" : action->param,
(action->param == NULL) ? "" : "'",
NULL);
}
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
"Updating rule %pp id=\"%s\" action: \"%s\"",
rule,
(rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
actions);
}
#endif
/* Merge new actions with the rule */
/* ENH: Will this leak the old actionset? */
rule->actionset = msre_actionset_merge(modsecurity->msre, rule->actionset,
new_actionset, 1);
msre_actionset_set_defaults(rule->actionset);
/* ENH: Change the unparsed string, but may be impossible. */
#ifdef DEBUG_CONF
{
const apr_array_header_t *tarr = apr_table_elts(rule->actionset->actions);
const apr_table_entry_t *telts = (const apr_table_entry_t*)tarr->elts;
char *actions = NULL;
int i;
for (i = 0; i < tarr->nelts; i++) {
msre_action *action = (msre_action *)telts[i].val;
actions = apr_pstrcat(ruleset->mp,
(actions == NULL) ? "" : actions,
(actions == NULL) ? "" : ",",
action->metadata->name,
(action->param == NULL) ? "" : ":'",
(action->param == NULL) ? "" : action->param,
(action->param == NULL) ? "" : "'",
NULL);
}
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
"Updated rule %pp id=\"%s\" action: \"%s\"",
rule,
(rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
actions);
}
#endif
return NULL;
}
/* -- Configuration directives -- */
static const char *cmd_action(cmd_parms *cmd, void *_dcfg, const char *p1) {
@ -1334,6 +1448,12 @@ static const char *cmd_rule_remove_by_msg(cmd_parms *cmd, void *_dcfg, const cha
return NULL;
}
static const char *cmd_rule_update_action_by_id(cmd_parms *cmd, void *_dcfg,
const char *p1, const char *p2)
{
return update_rule_action(cmd, (directory_config *)_dcfg, p1, p2);
}
static const char *cmd_server_signature(cmd_parms *cmd, void *_dcfg, const char *p1) {
if (cmd->server->is_virtual) {
return "ModSecurity: SecServerSignature not allowed in VirtualHost";
@ -1916,6 +2036,14 @@ const command_rec module_directives[] = {
"rule message for removal"
),
AP_INIT_TAKE2 (
"SecRuleUpdateActionById",
cmd_rule_update_action_by_id,
NULL,
CMD_SCOPE_ANY,
"updated action list"
),
AP_INIT_TAKE1 (
"SecServerSignature",
cmd_server_signature,

View File

@ -559,7 +559,7 @@ msre_actionset *msre_actionset_create_default(msre_engine *engine) {
/**
* Sets the default values for the hard-coded actionset configuration.
*/
static void msre_actionset_set_defaults(msre_actionset *actionset) {
void msre_actionset_set_defaults(msre_actionset *actionset) {
/* Metadata */
if (actionset->id == NOT_SET_P) actionset->id = NULL;
if (actionset->rev == NOT_SET_P) actionset->rev = NULL;
@ -1027,6 +1027,53 @@ int msre_ruleset_rule_add(msre_ruleset *ruleset, msre_rule *rule, int phase) {
return 1;
}
static msre_rule * msre_ruleset_fetch_phase_rule(const msre_ruleset *ruleset, const char *id,
const apr_array_header_t *phase_arr)
{
msre_rule **rules = (msre_rule **)phase_arr->elts;
int i;
for (i = 0; i < phase_arr->nelts; i++) {
msre_rule *rule = (msre_rule *)rules[i];
if ( (rule->actionset != NULL)
&& !rule->actionset->is_chained
&& (rule->actionset->id != NULL)
&& (strcmp(rule->actionset->id, id) == 0))
{
/* Return rule that matched unless it is a placeholder */
return (rule->placeholder == RULE_PH_NONE) ? rule : NULL;
}
}
return NULL;
}
/**
* Fetches rule from the ruleset all rules that match the given exception.
*/
msre_rule * msre_ruleset_fetch_rule(msre_ruleset *ruleset, const char *id) {
msre_rule *rule = NULL;
if (ruleset == NULL) return NULL;
rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_request_headers);
if (rule != NULL) return rule;
rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_request_body);
if (rule != NULL) return rule;
rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_response_headers);
if (rule != NULL) return rule;
rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_response_body);
if (rule != NULL) return rule;
rule = msre_ruleset_fetch_phase_rule(ruleset, id, ruleset->phase_logging);
return rule;
}
static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re,
apr_array_header_t *phase_arr)
{

View File

@ -106,6 +106,8 @@ msre_ruleset DSOLOCAL *msre_ruleset_create(msre_engine *engine, apr_pool_t *mp);
int DSOLOCAL msre_ruleset_rule_add(msre_ruleset *ruleset, msre_rule *rule, int phase);
msre_rule DSOLOCAL *msre_ruleset_fetch_rule(msre_ruleset *ruleset, const char *id);
int DSOLOCAL msre_ruleset_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re);
/*
@ -159,8 +161,6 @@ msre_rule DSOLOCAL *msre_rule_lua_create(msre_ruleset *ruleset,
const char *fn, int line, const char *script_filename,
const char *actions, char **error_msg);
void DSOLOCAL msre_rule_actionset_init(msre_rule *rule);
apr_status_t DSOLOCAL msre_rule_process(msre_rule *rule, modsec_rec *msr);
#define VAR_SIMPLE 0 /* REQUEST_URI */
@ -287,6 +287,8 @@ msre_actionset DSOLOCAL *msre_actionset_merge(msre_engine *engine, msre_actionse
msre_actionset DSOLOCAL *msre_actionset_create_default(msre_engine *engine);
void DSOLOCAL msre_actionset_set_defaults(msre_actionset *actionset);
void DSOLOCAL msre_actionset_init(msre_actionset *actionset, msre_rule *rule);
typedef char *(*fn_action_validate_t)(msre_engine *engine, msre_action *action);

View File

@ -1897,6 +1897,40 @@ end</programlisting>
</note>
</section>
<section>
<title><literal>SecRuleUpdateActionById</literal></title>
<para><emphasis>Description:</emphasis> Updates the action list of the
specified rule.</para>
<para><emphasis>Syntax:</emphasis> <literal
moreinfo="none">SecRuleRemoveById RULEID ACTIONLIST</literal></para>
<para><emphasis>Example Usage:</emphasis> <literal
moreinfo="none">SecRuleUpdateActionById 12345
deny,status:403</literal></para>
<para><emphasis>Processing Phase:</emphasis> Any</para>
<para><emphasis>Scope:</emphasis> Any</para>
<para><emphasis>Dependencies/Notes:</emphasis> This directive merges the
specified action list with the rule's action list. There are two
limitations. The rule ID cannot be changed, nor can the phase. Further
note that actions that may be specified multiple times are appended to
the original.</para>
<programlisting format="linespecific">SecAction \
"t:lowercase,phase:2,id:12345,pass,msg:'The Message',log,auditlog"
SecRuleUpdateActionById 12345 "t:compressWhitespace,deny,status:403,msg:'A new message'</programlisting>
<para>The example above will cause the rule to be executed as if it was
specified as follows:</para>
<programlisting format="linespecific">SecAction \
"t:lowercase,phase:2,id:12345,log,auditlog,t:compressWhitespace,deny,status:403,msg:'A new message'"</programlisting>
</section>
<section>
<title><literal>SecServerSignature</literal></title>