MXS-2403 Check only what is necessary
The amount of checking is minimized and what can be checked in one go, is checked in one go.
This commit is contained in:
@ -82,43 +82,45 @@ bool MaskingFilterSession::check_query(GWBUF* pPacket)
|
||||
zHost = "";
|
||||
}
|
||||
|
||||
bool rv = true;
|
||||
bool acceptable = true;
|
||||
|
||||
const MaskingFilter::Config& config = m_filter.config();
|
||||
|
||||
if (rv && config.prevent_function_usage())
|
||||
if (qc_query_is_type(qc_get_type_mask(pPacket), QUERY_TYPE_USERVAR_WRITE))
|
||||
{
|
||||
if (is_function_used(pPacket, zUser, zHost))
|
||||
if (config.check_user_variables())
|
||||
{
|
||||
rv = false;
|
||||
if (is_variable_defined(pPacket, zUser, zHost))
|
||||
{
|
||||
acceptable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qc_query_op_t op = qc_get_operation(pPacket);
|
||||
|
||||
if (op == QUERY_OP_SELECT)
|
||||
{
|
||||
if (config.check_unions() || config.check_subqueries())
|
||||
{
|
||||
if (is_union_or_subquery_used(pPacket, zUser, zHost))
|
||||
{
|
||||
acceptable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (acceptable && config.prevent_function_usage())
|
||||
{
|
||||
if (is_function_used(pPacket, zUser, zHost))
|
||||
{
|
||||
acceptable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rv && config.check_user_variables())
|
||||
{
|
||||
if (is_variable_defined(pPacket, zUser, zHost))
|
||||
{
|
||||
rv = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (rv && config.check_unions())
|
||||
{
|
||||
if (is_union_used(pPacket, zUser, zHost))
|
||||
{
|
||||
rv = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (rv && config.check_subqueries())
|
||||
{
|
||||
if (is_subquery_used(pPacket, zUser, zHost))
|
||||
{
|
||||
rv = false;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
return acceptable;
|
||||
}
|
||||
|
||||
bool MaskingFilterSession::check_textual_query(GWBUF* pPacket)
|
||||
@ -569,10 +571,7 @@ bool MaskingFilterSession::is_function_used(GWBUF* pPacket, const char* zUser, c
|
||||
|
||||
bool MaskingFilterSession::is_variable_defined(GWBUF* pPacket, const char* zUser, const char* zHost)
|
||||
{
|
||||
if (!qc_query_is_type(qc_get_type_mask(pPacket), QUERY_TYPE_USERVAR_WRITE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
mxb_assert(qc_query_is_type(qc_get_type_mask(pPacket), QUERY_TYPE_USERVAR_WRITE));
|
||||
|
||||
bool is_defined = false;
|
||||
|
||||
@ -628,21 +627,34 @@ bool MaskingFilterSession::is_variable_defined(GWBUF* pPacket, const char* zUser
|
||||
return is_defined;
|
||||
}
|
||||
|
||||
bool MaskingFilterSession::is_union_used(GWBUF* pPacket, const char* zUser, const char* zHost)
|
||||
bool MaskingFilterSession::is_union_or_subquery_used(GWBUF* pPacket, const char* zUser, const char* zHost)
|
||||
{
|
||||
if (qc_get_operation(pPacket) != QUERY_OP_SELECT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
mxb_assert(qc_get_operation(pPacket) == QUERY_OP_SELECT);
|
||||
|
||||
const MaskingFilter::Config& config = m_filter.config();
|
||||
|
||||
mxb_assert(config.check_unions() || config.check_subqueries());
|
||||
|
||||
bool is_used = false;
|
||||
|
||||
SMaskingRules sRules = m_filter.rules();
|
||||
|
||||
auto pred = [&sRules, zUser, zHost](const QC_FIELD_INFO& field_info) {
|
||||
uint32_t mask = 0;
|
||||
|
||||
if (config.check_unions())
|
||||
{
|
||||
mask |= QC_FIELD_UNION;
|
||||
}
|
||||
|
||||
if (config.check_subqueries())
|
||||
{
|
||||
mask |= QC_FIELD_SUBQUERY;
|
||||
}
|
||||
|
||||
auto pred = [&sRules, mask, zUser, zHost](const QC_FIELD_INFO& field_info) {
|
||||
bool rv = false;
|
||||
|
||||
if (field_info.context & QC_FIELD_UNION)
|
||||
if (field_info.context & mask)
|
||||
{
|
||||
if (strcmp(field_info.column, "*") == 0)
|
||||
{
|
||||
@ -674,79 +686,35 @@ bool MaskingFilterSession::is_union_used(GWBUF* pPacket, const char* zUser, cons
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
if (strcmp(zColumn, "*") == 0)
|
||||
if (config.check_unions() && (i->context & QC_FIELD_UNION))
|
||||
{
|
||||
ss << "'*' is used in the second or subsequent SELECT of a UNION 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 the second or subsequent SELECT of a UNION, access is denied.";
|
||||
}
|
||||
|
||||
set_response(create_error_response(ss.str().c_str()));
|
||||
is_used = true;
|
||||
}
|
||||
|
||||
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 (strcmp(zColumn, "*") == 0)
|
||||
{
|
||||
// If "*" is used, then we must block if there is any rule for the current user.
|
||||
rv = sRules->has_rule_for(zUser, zHost);
|
||||
ss << "'*' is used in the second or subsequent SELECT of a UNION and there are "
|
||||
<< "masking rules for '" << zUser << "'@'" << zHost << "', access is denied.";
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = sRules->get_rule_for(field_info, zUser, zHost) ? true : false;
|
||||
ss << "The field " << zColumn << " that should be masked for '" << zUser << "'@'" << zHost
|
||||
<< "' is used in the second or subsequent SELECT of a UNION, access is denied.";
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
else if (config.check_subqueries() && (i->context & QC_FIELD_SUBQUERY))
|
||||
{
|
||||
ss << "'*' is used in a subquery and there are masking rules for '"
|
||||
<< zUser << "'@'" << zHost << "', access is denied.";
|
||||
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.";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "The field " << zColumn << " that should be masked for '"
|
||||
<< zUser << "'@'" << zHost << "' is used in a subquery, access is denied.";
|
||||
mxb_assert(!true);
|
||||
}
|
||||
|
||||
set_response(create_error_response(ss.str().c_str()));
|
||||
|
@ -67,8 +67,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);
|
||||
bool is_union_or_subquery_used(GWBUF* pPacket, const char* zUser, const char* zHost);
|
||||
|
||||
private:
|
||||
typedef std::shared_ptr<MaskingRules> SMaskingRules;
|
||||
|
Reference in New Issue
Block a user