diff --git a/server/modules/filter/masking/maskingfilter.cc b/server/modules/filter/masking/maskingfilter.cc index 639e08c24..5a3eb5be2 100644 --- a/server/modules/filter/masking/maskingfilter.cc +++ b/server/modules/filter/masking/maskingfilter.cc @@ -133,6 +133,12 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE() Config::check_unions_default, MXS_MODULE_OPT_NONE, }, + { + Config::check_subqueries_name, + MXS_MODULE_PARAM_BOOL, + Config::check_subqueries_default, + MXS_MODULE_OPT_NONE, + }, {MXS_END_MODULE_PARAMS} } }; diff --git a/server/modules/filter/masking/maskingfiltersession.cc b/server/modules/filter/masking/maskingfiltersession.cc index 483347e40..2f6b7bb23 100644 --- a/server/modules/filter/masking/maskingfiltersession.cc +++ b/server/modules/filter/masking/maskingfiltersession.cc @@ -110,6 +110,14 @@ bool MaskingFilterSession::check_query(GWBUF* pPacket) } } + if (rv && config.check_subqueries()) + { + if (is_subquery_used(pPacket, zUser, zHost)) + { + rv = false; + } + } + return rv; } @@ -683,3 +691,67 @@ bool MaskingFilterSession::is_union_used(GWBUF* pPacket, const char* zUser, cons return is_used; } + +bool MaskingFilterSession::is_subquery_used(GWBUF* pPacket, const char* zUser, const char* zHost) +{ + if (qc_get_operation(pPacket) != QUERY_OP_SELECT) + { + return false; + } + + bool is_used = false; + + SMaskingRules sRules = m_filter.rules(); + + auto pred = [&sRules, zUser, zHost](const QC_FIELD_INFO& field_info) { + bool rv = false; + + if (field_info.context & QC_FIELD_SUBQUERY) + { + if (strcmp(field_info.column, "*") == 0) + { + // If "*" is used, then we must block if there is any rule for the current user. + rv = sRules->has_rule_for(zUser, zHost); + } + else + { + rv = sRules->get_rule_for(field_info, zUser, zHost) ? true : false; + } + } + + return rv; + }; + + const QC_FIELD_INFO* pInfos; + size_t nInfos; + + qc_get_field_info(pPacket, &pInfos, &nInfos); + + const QC_FIELD_INFO* begin = pInfos; + const QC_FIELD_INFO* end = begin + nInfos; + + auto i = std::find_if(begin, end, pred); + + if (i != end) + { + const char* zColumn = i->column; + + std::stringstream ss; + + if (strcmp(zColumn, "*") == 0) + { + ss << "'*' is used in a subquery and there are masking rules for '" + << zUser << "'@'" << zHost << "', access is denied."; + } + else + { + ss << "The field " << zColumn << " that should be masked for '" + << zUser << "'@'" << zHost << "' is used in a subquery, access is denied."; + } + + set_response(create_error_response(ss.str().c_str())); + is_used = true; + } + + return is_used; +} diff --git a/server/modules/filter/masking/maskingfiltersession.hh b/server/modules/filter/masking/maskingfiltersession.hh index 74c0cc5c9..7b930bebd 100644 --- a/server/modules/filter/masking/maskingfiltersession.hh +++ b/server/modules/filter/masking/maskingfiltersession.hh @@ -68,6 +68,7 @@ private: bool is_function_used(GWBUF* pPacket, const char* zUser, const char* zHost); bool is_variable_defined(GWBUF* pPacket, const char* zUser, const char* zHost); bool is_union_used(GWBUF* pPacket, const char* zUser, const char* zHost); + bool is_subquery_used(GWBUF* pPacket, const char* zUser, const char* zHost); private: typedef std::shared_ptr SMaskingRules;