From c55c46ac0c25e8ea3e5c8bfde2d9ab75cd3470d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Thu, 31 Aug 2017 18:49:14 +0300 Subject: [PATCH] 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. --- .../modules/filter/dbfwfilter/dbfwfilter.cc | 149 +----------------- .../modules/filter/dbfwfilter/dbfwfilter.hh | 11 ++ server/modules/filter/dbfwfilter/users.cc | 124 +++++++++++++++ server/modules/filter/dbfwfilter/users.hh | 30 +++- 4 files changed, 164 insertions(+), 150 deletions(-) diff --git a/server/modules/filter/dbfwfilter/dbfwfilter.cc b/server/modules/filter/dbfwfilter/dbfwfilter.cc index f9092f571..83d4bd277 100644 --- a/server/modules/filter/dbfwfilter/dbfwfilter.cc +++ b/server/modules/filter/dbfwfilter/dbfwfilter.cc @@ -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) { diff --git a/server/modules/filter/dbfwfilter/dbfwfilter.hh b/server/modules/filter/dbfwfilter/dbfwfilter.hh index 839374e08..e6f57684a 100644 --- a/server/modules/filter/dbfwfilter/dbfwfilter.hh +++ b/server/modules/filter/dbfwfilter/dbfwfilter.hh @@ -199,5 +199,16 @@ typedef struct /** Typedef for a list of strings */ typedef std::list ValueList; +/** Temporary typedef for SRule */ +class Rule; +typedef std::tr1::shared_ptr 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); \ No newline at end of file diff --git a/server/modules/filter/dbfwfilter/users.cc b/server/modules/filter/dbfwfilter/users.cc index 8be054f61..0248de761 100644 --- a/server/modules/filter/dbfwfilter/users.cc +++ b/server/modules/filter/dbfwfilter/users.cc @@ -13,6 +13,10 @@ #include "users.hh" +#include +#include +#include + 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); +} diff --git a/server/modules/filter/dbfwfilter/users.hh b/server/modules/filter/dbfwfilter/users.hh index 789bc144c..451ae928e 100644 --- a/server/modules/filter/dbfwfilter/users.hh +++ b/server/modules/filter/dbfwfilter/users.hh @@ -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 SUser;