MXS-1583 Treat independent 'users' line in OR-fashion

If there are several 'users' lines in a rule file, for a particular
user, the rules each matching line will be checked independently
until a rule match is found.

That is, the rules of each 'users' line are treated in an OR-fashion
with respect to each other.
This commit is contained in:
Johan Wikman
2018-01-29 11:48:13 +02:00
parent cf0d745c14
commit 0db538db9a
4 changed files with 76 additions and 47 deletions

View File

@ -355,6 +355,12 @@ After the matching part comes the rules keyword after which a list of rule names
is expected. This allows reusing of the rules and enables varying levels of is expected. This allows reusing of the rules and enables varying levels of
query restriction. query restriction.
If a particular _NAME_ appears on several `users` lines, then when an
actual user matches that name, the rules of each line are checked
independently until there is a match for the statement in question. That
is, the rules of each `users` line are treated in an _OR_ fashion with
respect to each other.
## Module commands ## Module commands
Read [Module Commands](../Reference/Module-Commands.md) documentation for Read [Module Commands](../Reference/Module-Commands.md) documentation for

View File

@ -1029,7 +1029,7 @@ static bool process_user_templates(UserMap& users, const TemplateList& templates
if (newrules.size() > 0) if (newrules.size() > 0)
{ {
user->append_rules(ut->type, newrules); user->add_rules(ut->type, newrules);
} }
} }

View File

@ -31,20 +31,20 @@ const char* User::name() const
return m_name.c_str(); return m_name.c_str();
} }
void User::append_rules(match_type mode, const RuleList& rules) void User::add_rules(match_type mode, const RuleList& rules)
{ {
switch (mode) switch (mode)
{ {
case FWTOK_MATCH_ANY: case FWTOK_MATCH_ANY:
rules_or.insert(rules_or.end(), rules.begin(), rules.end()); rules_or_vector.push_back(rules);
break; break;
case FWTOK_MATCH_ALL: case FWTOK_MATCH_ALL:
rules_and.insert(rules_and.end(), rules.begin(), rules.end()); rules_and_vector.push_back(rules);
break; break;
case FWTOK_MATCH_STRICT_ALL: case FWTOK_MATCH_STRICT_ALL:
rules_strict_and.insert(rules_strict_and.end(), rules.begin(), rules.end()); rules_strict_and_vector.push_back(rules);
break; break;
default: default:
@ -73,28 +73,39 @@ bool User::match_any(Dbfw* my_instance, DbfwSession* my_session,
bool rval = false; bool rval = false;
if (rules_or.size() > 0 && should_match(queue)) for (RuleListVector::iterator i = rules_or_vector.begin(); i != rules_or_vector.end(); ++i)
{ {
char *fullquery = modutil_get_SQL(queue); RuleList& rules_or = *i;
if (fullquery) if (rules_or.size() > 0 && should_match(queue))
{ {
for (RuleList::iterator it = rules_or.begin(); it != rules_or.end(); it++) char *fullquery = modutil_get_SQL(queue);
if (fullquery)
{ {
if (rule_is_active(*it)) for (RuleList::iterator j = rules_or.begin(); j != rules_or.end(); j++)
{ {
if (rule_matches(my_instance, my_session, queue, *it, fullquery)) if (rule_is_active(*j))
{ {
*rulename = MXS_STRDUP_A((*it)->name().c_str()); if (rule_matches(my_instance, my_session, queue, *j, fullquery))
rval = true; {
break; *rulename = MXS_STRDUP_A((*j)->name().c_str());
rval = true;
break;
}
} }
} }
}
MXS_FREE(fullquery); MXS_FREE(fullquery);
}
}
if (rval)
{
break;
} }
} }
return rval; return rval;
} }
@ -116,44 +127,54 @@ bool User::do_match(Dbfw* my_instance, DbfwSession* my_session,
bool rval = false; bool rval = false;
bool have_active_rule = false; bool have_active_rule = false;
std::string matching_rules; std::string matching_rules;
RuleList& rules = mode == User::ALL ? rules_and : rules_strict_and; RuleListVector& rules_vector = (mode == User::ALL ? rules_and_vector : rules_strict_and_vector);
if (rules.size() > 0 && should_match(queue)) for (RuleListVector::iterator i = rules_vector.begin(); i != rules_vector.end(); ++i)
{ {
char *fullquery = modutil_get_SQL(queue); RuleList& rules = *i;
if (fullquery) if (rules.size() > 0 && should_match(queue))
{ {
rval = true; char *fullquery = modutil_get_SQL(queue);
for (RuleList::iterator it = rules.begin(); it != rules.end(); it++)
if (fullquery)
{ {
if (rule_is_active(*it)) rval = true;
for (RuleList::iterator j = rules.begin(); j != rules.end(); j++)
{ {
have_active_rule = true; if (rule_is_active(*j))
if (rule_matches(my_instance, my_session, queue, *it, fullquery))
{ {
matching_rules += (*it)->name(); have_active_rule = true;
matching_rules += " ";
}
else
{
rval = false;
if (mode == User::STRICT) if (rule_matches(my_instance, my_session, queue, *j, fullquery))
{ {
break; matching_rules += (*j)->name();
matching_rules += " ";
}
else
{
rval = false;
if (mode == User::STRICT)
{
break;
}
} }
} }
} }
}
if (!have_active_rule) if (!have_active_rule)
{ {
/** No active rules */ /** No active rules */
rval = false; rval = false;
}
MXS_FREE(fullquery);
} }
MXS_FREE(fullquery); }
if (rval)
{
break;
} }
} }

View File

@ -57,12 +57,12 @@ public:
const char* name() const; const char* name() const;
/** /**
* Append new rules to existing rules * Add new rules to existing rules
* *
* @param mode Matching mode for the rule * @param mode Matching mode for the rule
* @param rules Rules to append * @param rules Rules to append
*/ */
void append_rules(match_type mode, const RuleList& rules); void add_rules(match_type mode, const RuleList& rules);
/** /**
* Check if a query matches some rule * Check if a query matches some rule
@ -84,11 +84,13 @@ private:
STRICT STRICT
}; };
RuleList rules_or; /*< If any of these rules match the action is triggered */ typedef std::vector<RuleList> RuleListVector;
RuleList rules_and; /*< All of these rules must match for the action to trigger */
RuleList rules_strict_and; /*< rules that skip the rest of the rules if one of them RuleListVector rules_or_vector; /*< If any of these rules match the action is triggered */
* fails. This is only for rules paired with 'match strict_all'. */ RuleListVector rules_and_vector; /*< All of these rules must match for the action to trigger */
std::string m_name; /*< Name of the user */ RuleListVector rules_strict_and_vector;/*< rules that skip the rest of the rules if one of them
* fails. This is only for rules paired with 'match strict_all'. */
std::string m_name; /*< Name of the user */
/** /**
* Functions for matching rules * Functions for matching rules