MXS-1346: Move rule matching into the User class
The User class now only exposes the `match` method which can be used to check if any of the rules for a user match a query. Further cleanup is required once individual rule classes have been implemented.
This commit is contained in:
@ -1917,146 +1917,6 @@ queryresolved:
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the query matches any of the rules in the user's rules.
|
||||
* @param my_instance Fwfilter instance
|
||||
* @param my_session Fwfilter session
|
||||
* @param queue The GWBUF containing the query
|
||||
* @param user The user whose rules are checked
|
||||
* @return True if the query matches at least one of the rules otherwise false
|
||||
*/
|
||||
bool check_match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||
GWBUF *queue, SUser user, char** rulename)
|
||||
{
|
||||
|
||||
bool rval = false;
|
||||
|
||||
if (!user->rules_or.empty() &&
|
||||
(modutil_is_SQL(queue) || modutil_is_SQL_prepare(queue) ||
|
||||
MYSQL_IS_COM_INIT_DB((uint8_t*)GWBUF_DATA(queue))))
|
||||
{
|
||||
char *fullquery = modutil_get_SQL(queue);
|
||||
|
||||
if (fullquery)
|
||||
{
|
||||
for (RuleList::iterator it = user->rules_or.begin(); it != user->rules_or.end(); it++)
|
||||
{
|
||||
if (rule_is_active(*it))
|
||||
{
|
||||
if (rule_matches(my_instance, my_session, queue, *it, fullquery))
|
||||
{
|
||||
*rulename = MXS_STRDUP_A((*it)->name.c_str());
|
||||
rval = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MXS_FREE(fullquery);
|
||||
}
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append and possibly reallocate string
|
||||
* @param dest Destination where the string is appended or NULL if nothing has
|
||||
* been allocated yet
|
||||
* @param size Size of @c dest
|
||||
* @param src String to append to @c dest
|
||||
*/
|
||||
void append_string(char** dest, size_t* size, const char* src)
|
||||
{
|
||||
if (*dest == NULL)
|
||||
{
|
||||
*dest = MXS_STRDUP_A(src);
|
||||
*size = strlen(src);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*size < strlen(*dest) + strlen(src) + 3)
|
||||
{
|
||||
size_t newsize = strlen(*dest) + strlen(src) + 3;
|
||||
char* tmp = (char*)MXS_REALLOC(*dest, newsize);
|
||||
if (tmp)
|
||||
{
|
||||
*size = newsize;
|
||||
*dest = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
strcat(*dest, ", ");
|
||||
strcat(*dest, src);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the query matches all rules in the user's rules
|
||||
*
|
||||
* @param my_instance Filter instance
|
||||
* @param my_session Filter session
|
||||
* @param queue Buffer containing the query
|
||||
* @param user The user whose rules are checked
|
||||
* @param strict_all Whether the first match stops the processing
|
||||
* @param rulename Pointer where error messages are stored
|
||||
*
|
||||
* @return True if the query matches all of the rules otherwise false
|
||||
*/
|
||||
bool check_match_all(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||
GWBUF *queue, SUser user, bool strict_all, char** rulename)
|
||||
{
|
||||
bool rval = false;
|
||||
bool have_active_rule = false;
|
||||
RuleList& rules = strict_all ? user->rules_strict_and : user->rules_and;
|
||||
char *matched_rules = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
if (!rules.empty() && (modutil_is_SQL(queue) || modutil_is_SQL_prepare(queue)))
|
||||
{
|
||||
char *fullquery = modutil_get_SQL(queue);
|
||||
|
||||
if (fullquery)
|
||||
{
|
||||
rval = true;
|
||||
for (RuleList::iterator it = rules.begin(); it != rules.end(); it++)
|
||||
{
|
||||
if (!rule_is_active(*it))
|
||||
{
|
||||
have_active_rule = true;
|
||||
|
||||
if (rule_matches(my_instance, my_session, queue, *it, fullquery))
|
||||
{
|
||||
append_string(&matched_rules, &size, (*it)->name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
rval = false;
|
||||
if (strict_all)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!have_active_rule)
|
||||
{
|
||||
/** No active rules */
|
||||
rval = false;
|
||||
}
|
||||
MXS_FREE(fullquery);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set the list of matched rule names */
|
||||
*rulename = matched_rules;
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the user specific data for this session
|
||||
*
|
||||
@ -2178,15 +2038,8 @@ routeQuery(MXS_FILTER *instance, MXS_FILTER_SESSION *session, GWBUF *queue)
|
||||
|
||||
if (user)
|
||||
{
|
||||
bool match = false;
|
||||
char* rname = NULL;
|
||||
|
||||
if (check_match_any(my_instance, my_session, analyzed_queue, user, &rname) ||
|
||||
check_match_all(my_instance, my_session, analyzed_queue, user, false, &rname) ||
|
||||
check_match_all(my_instance, my_session, analyzed_queue, user, true, &rname))
|
||||
{
|
||||
match = true;
|
||||
}
|
||||
bool match = user->match(my_instance, my_session, analyzed_queue, &rname);
|
||||
|
||||
switch (my_instance->action)
|
||||
{
|
||||
|
@ -199,5 +199,16 @@ typedef struct
|
||||
/** Typedef for a list of strings */
|
||||
typedef std::list<std::string> ValueList;
|
||||
|
||||
/** Temporary typedef for SRule */
|
||||
class Rule;
|
||||
typedef std::tr1::shared_ptr<Rule> SRule;
|
||||
|
||||
/** Helper function for strdup'ing in printf style */
|
||||
char* create_error(const char* format, ...);
|
||||
|
||||
/**
|
||||
* Check if a rule matches
|
||||
*/
|
||||
bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||
GWBUF *queue, SRule rule, char* query);
|
||||
bool rule_is_active(SRule rule);
|
@ -13,6 +13,10 @@
|
||||
|
||||
#include "users.hh"
|
||||
|
||||
#include <maxscale/alloc.h>
|
||||
#include <maxscale/modutil.h>
|
||||
#include <maxscale/protocol/mysql.h>
|
||||
|
||||
User::User(std::string name):
|
||||
m_name(name)
|
||||
{
|
||||
@ -48,3 +52,123 @@ void User::append_rules(match_type mode, const RuleList& rules)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool should_match(GWBUF* buffer)
|
||||
{
|
||||
return modutil_is_SQL(buffer) || modutil_is_SQL_prepare(buffer) ||
|
||||
MYSQL_IS_COM_INIT_DB(GWBUF_DATA(buffer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the query matches any of the rules in the user's rules.
|
||||
* @param my_instance Fwfilter instance
|
||||
* @param my_session Fwfilter session
|
||||
* @param queue The GWBUF containing the query
|
||||
* @param user The user whose rules are checked
|
||||
* @return True if the query matches at least one of the rules otherwise false
|
||||
*/
|
||||
bool User::match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||
GWBUF *queue, char** rulename)
|
||||
{
|
||||
|
||||
bool rval = false;
|
||||
|
||||
if (rules_or.size() > 0 && should_match(queue))
|
||||
{
|
||||
char *fullquery = modutil_get_SQL(queue);
|
||||
|
||||
if (fullquery)
|
||||
{
|
||||
for (RuleList::iterator it = rules_or.begin(); it != rules_or.end(); it++)
|
||||
{
|
||||
if (rule_is_active(*it))
|
||||
{
|
||||
if (rule_matches(my_instance, my_session, queue, *it, fullquery))
|
||||
{
|
||||
*rulename = MXS_STRDUP_A((*it)->name.c_str());
|
||||
rval = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MXS_FREE(fullquery);
|
||||
}
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the query matches all rules in the user's rules
|
||||
*
|
||||
* @param my_instance Filter instance
|
||||
* @param my_session Filter session
|
||||
* @param queue Buffer containing the query
|
||||
* @param user The user whose rules are checked
|
||||
* @param strict_all Whether the first match stops the processing
|
||||
* @param rulename Pointer where error messages are stored
|
||||
*
|
||||
* @return True if the query matches all of the rules otherwise false
|
||||
*/
|
||||
bool User::do_match(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||
GWBUF *queue, match_mode mode, char** rulename)
|
||||
{
|
||||
bool rval = false;
|
||||
bool have_active_rule = false;
|
||||
std::string matching_rules;
|
||||
RuleList& rules = mode == User::ALL ? rules_and : rules_strict_and;
|
||||
|
||||
if (rules.size() > 0 && should_match(queue))
|
||||
{
|
||||
char *fullquery = modutil_get_SQL(queue);
|
||||
|
||||
if (fullquery)
|
||||
{
|
||||
rval = true;
|
||||
for (RuleList::iterator it = rules.begin(); it != rules.end(); it++)
|
||||
{
|
||||
if (!rule_is_active(*it))
|
||||
{
|
||||
have_active_rule = true;
|
||||
|
||||
if (rule_matches(my_instance, my_session, queue, *it, fullquery))
|
||||
{
|
||||
matching_rules += (*it)->name;
|
||||
matching_rules += " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
rval = false;
|
||||
|
||||
if (mode == User::STRICT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!have_active_rule)
|
||||
{
|
||||
/** No active rules */
|
||||
rval = false;
|
||||
}
|
||||
MXS_FREE(fullquery);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set the list of matched rule names */
|
||||
if (matching_rules.length() > 0)
|
||||
{
|
||||
*rulename = MXS_STRDUP_A(matching_rules.c_str());
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
bool User::match(FW_INSTANCE* instance, FW_SESSION* session, GWBUF* buffer, char** rulename)
|
||||
{
|
||||
return match_any(instance, session, buffer, rulename) ||
|
||||
do_match(instance, session, buffer, User::ALL, rulename) ||
|
||||
do_match(instance, session, buffer, User::STRICT, rulename);
|
||||
}
|
||||
|
@ -57,13 +57,39 @@ public:
|
||||
*/
|
||||
void append_rules(match_type mode, const RuleList& rules);
|
||||
|
||||
/**
|
||||
* Check if a query matches some rule
|
||||
*
|
||||
* @param instance Filter instance
|
||||
* @param session Filter session
|
||||
* @param buffer Buffer containing the query
|
||||
* @param rulename Names of rules that this query matched
|
||||
*
|
||||
* @return True if query matches
|
||||
*/
|
||||
bool match(FW_INSTANCE* instance, FW_SESSION* session, GWBUF* buffer, char** rulename);
|
||||
|
||||
private:
|
||||
|
||||
enum match_mode
|
||||
{
|
||||
ALL,
|
||||
STRICT
|
||||
};
|
||||
|
||||
RuleList rules_or; /*< If any of these rules match the action is triggered */
|
||||
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
|
||||
* fails. This is only for rules paired with 'match strict_all'. */
|
||||
std::string m_name; /*< Name of the user */
|
||||
|
||||
private:
|
||||
std::string m_name; /*< Name of the user */
|
||||
/**
|
||||
* Functions for matching rules
|
||||
*/
|
||||
bool match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||
GWBUF *queue, char** rulename);
|
||||
bool do_match(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||
GWBUF *queue, match_mode mode, char** rulename);
|
||||
};
|
||||
|
||||
typedef std::tr1::shared_ptr<User> SUser;
|
||||
|
Reference in New Issue
Block a user