MXS-1346: Allow combination of function
and columns
rules
The `function` type rule can now be combined with the `columns` type rule to form a new rule which matches if specific columns use specific functions.
This commit is contained in:
@ -104,11 +104,11 @@ logged. The log messages are logged at the notice level.
|
|||||||
The rules are defined by using the following syntax:
|
The rules are defined by using the following syntax:
|
||||||
|
|
||||||
```
|
```
|
||||||
rule NAME deny { wildcard | columns VALUE... |
|
rule NAME deny RULE [at_times VALUE...] [on_queries {select|update|insert|delete|grant|revoke|drop|create|alter|use|load}]
|
||||||
regex REGEX | limit_queries COUNT TIMEPERIOD HOLDOFF |
|
|
||||||
no_where_clause} [at_times VALUE...] [on_queries [select|update|insert|delete|grant|revoke|drop|create|alter|use|load]]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Where _NAME_ is the identifier for this rule and _RULE_ is the mandatory rule definition.
|
||||||
|
|
||||||
Rules are identified by their name and have mandatory parts and optional parts.
|
Rules are identified by their name and have mandatory parts and optional parts.
|
||||||
You can add comments to the rule files by adding the `#` character at
|
You can add comments to the rule files by adding the `#` character at
|
||||||
the beginning of the line. Trailing comments are not supported.
|
the beginning of the line. Trailing comments are not supported.
|
||||||
@ -197,6 +197,20 @@ Deny function usage with _name_ and _address_ columns:
|
|||||||
rule examplerule deny uses_function name address
|
rule examplerule deny uses_function name address
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `function` and `columns`
|
||||||
|
|
||||||
|
This rule combines the `function` and `columns` type rules to match if one
|
||||||
|
of the listed columns uses one of the listed functions. The rule expects
|
||||||
|
the `function` and `columns` keywords both followed by a list of values.
|
||||||
|
|
||||||
|
##### Example
|
||||||
|
|
||||||
|
Deny use of the _sum_ function with _name_ or _address_ columns:
|
||||||
|
|
||||||
|
```
|
||||||
|
rule examplerule deny function sum columns name address
|
||||||
|
```
|
||||||
|
|
||||||
#### `regex`
|
#### `regex`
|
||||||
|
|
||||||
This rule blocks all queries matching a regex enclosed in single or double
|
This rule blocks all queries matching a regex enclosed in single or double
|
||||||
|
@ -627,6 +627,7 @@ struct parser_stack
|
|||||||
enum match_type active_mode;
|
enum match_type active_mode;
|
||||||
TemplateList templates;
|
TemplateList templates;
|
||||||
ValueList values;
|
ValueList values;
|
||||||
|
ValueList auxiliary_values;
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -714,6 +715,13 @@ void push_value(void* scanner, char* value)
|
|||||||
rstack->values.push_back(strip_backticks(value));
|
rstack->values.push_back(strip_backticks(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void push_auxiliary_value(void* scanner, char* value)
|
||||||
|
{
|
||||||
|
struct parser_stack* rstack = (struct parser_stack*)dbfw_yyget_extra((yyscan_t)scanner);
|
||||||
|
ss_dassert(rstack);
|
||||||
|
rstack->auxiliary_values.push_back(strip_backticks(value));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a user to the current rule linking expression
|
* Add a user to the current rule linking expression
|
||||||
* @param scanner Current scanner
|
* @param scanner Current scanner
|
||||||
@ -849,6 +857,19 @@ void define_function_usage_rule(void* scanner)
|
|||||||
rstack->rule.push_front(SRule(new FunctionUsageRule(rstack->name, rstack->values)));
|
rstack->rule.push_front(SRule(new FunctionUsageRule(rstack->name, rstack->values)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the current rule as a function rule
|
||||||
|
* @param scanner Current scanner
|
||||||
|
* @param columns List of function names
|
||||||
|
*/
|
||||||
|
void define_column_function_rule(void* scanner)
|
||||||
|
{
|
||||||
|
struct parser_stack* rstack = (struct parser_stack*)dbfw_yyget_extra((yyscan_t) scanner);
|
||||||
|
ss_dassert(rstack);
|
||||||
|
rstack->rule.push_front(SRule(new ColumnFunctionRule(rstack->name, rstack->values,
|
||||||
|
rstack->auxiliary_values)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the topmost rule as a no_where_clause rule
|
* Define the topmost rule as a no_where_clause rule
|
||||||
* @param scanner Current scanner
|
* @param scanner Current scanner
|
||||||
|
@ -37,12 +37,14 @@ void dbfw_yyerror(void* scanner, const char* error);
|
|||||||
/** Rule creation and definition functions */
|
/** Rule creation and definition functions */
|
||||||
bool set_rule_name(void* scanner, char* name);
|
bool set_rule_name(void* scanner, char* name);
|
||||||
void push_value(void* scanner, char* value);
|
void push_value(void* scanner, char* value);
|
||||||
|
void push_auxiliary_value(void* scanner, char* value);
|
||||||
void define_wildcard_rule(void* scanner);
|
void define_wildcard_rule(void* scanner);
|
||||||
void define_where_clause_rule(void* scanner);
|
void define_where_clause_rule(void* scanner);
|
||||||
bool define_regex_rule(void* scanner, char* pattern);
|
bool define_regex_rule(void* scanner, char* pattern);
|
||||||
void define_columns_rule(void* scanner);
|
void define_columns_rule(void* scanner);
|
||||||
void define_function_rule(void* scanner);
|
void define_function_rule(void* scanner);
|
||||||
void define_function_usage_rule(void* scanner);
|
void define_function_usage_rule(void* scanner);
|
||||||
|
void define_column_function_rule(void* scanner);
|
||||||
void define_limit_queries_rule(void* scanner, int max, int timeperiod, int holdoff);
|
void define_limit_queries_rule(void* scanner, int max, int timeperiod, int holdoff);
|
||||||
bool add_at_times_rule(void* scanner, const char* range);
|
bool add_at_times_rule(void* scanner, const char* range);
|
||||||
void add_on_queries_rule(void* scanner, const char* sql);
|
void add_on_queries_rule(void* scanner, const char* sql);
|
||||||
|
@ -126,6 +126,7 @@ mandatory
|
|||||||
| FWTOK_COLUMNS valuelist {define_columns_rule(scanner);}
|
| FWTOK_COLUMNS valuelist {define_columns_rule(scanner);}
|
||||||
| FWTOK_FUNCTION valuelist {define_function_rule(scanner);}
|
| FWTOK_FUNCTION valuelist {define_function_rule(scanner);}
|
||||||
| FWTOK_FUNCTION {define_function_rule(scanner);}
|
| FWTOK_FUNCTION {define_function_rule(scanner);}
|
||||||
|
| FWTOK_FUNCTION valuelist FWTOK_COLUMNS auxiliaryvaluelist {define_column_function_rule(scanner);}
|
||||||
| FWTOK_USES_FUNCTION valuelist {define_function_usage_rule(scanner);}
|
| FWTOK_USES_FUNCTION valuelist {define_function_usage_rule(scanner);}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -140,6 +141,17 @@ valuelist
|
|||||||
| valuelist value
|
| valuelist value
|
||||||
;
|
;
|
||||||
|
|
||||||
|
auxiliaryvalue
|
||||||
|
: FWTOK_CMP {push_auxiliary_value(scanner, $1);}
|
||||||
|
| FWTOK_STR {push_auxiliary_value(scanner, $1);}
|
||||||
|
| FWTOK_BTSTR {push_auxiliary_value(scanner, $1);}
|
||||||
|
;
|
||||||
|
|
||||||
|
auxiliaryvaluelist
|
||||||
|
: auxiliaryvalue
|
||||||
|
| auxiliaryvaluelist auxiliaryvalue
|
||||||
|
;
|
||||||
|
|
||||||
/** Optional parts of a rule */
|
/** Optional parts of a rule */
|
||||||
optional
|
optional
|
||||||
: FWTOK_AT_TIMES timelist
|
: FWTOK_AT_TIMES timelist
|
||||||
|
@ -239,6 +239,47 @@ bool FunctionUsageRule::matches_query(DbfwSession* session, GWBUF* buffer, char*
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ColumnFunctionRule::matches_query(DbfwSession* session, GWBUF* buffer, char** msg) const
|
||||||
|
{
|
||||||
|
if (query_is_sql(buffer))
|
||||||
|
{
|
||||||
|
const QC_FUNCTION_INFO* infos;
|
||||||
|
size_t n_infos;
|
||||||
|
qc_get_function_info(buffer, &infos, &n_infos);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n_infos; ++i)
|
||||||
|
{
|
||||||
|
ValueList::const_iterator func_it = std::find(m_values.begin(),
|
||||||
|
m_values.end(),
|
||||||
|
infos[i].name);
|
||||||
|
|
||||||
|
if (func_it != m_values.end())
|
||||||
|
{
|
||||||
|
/** The function matches, now check if the column matches */
|
||||||
|
|
||||||
|
for (size_t j = 0; j < infos[i].n_fields; j++)
|
||||||
|
{
|
||||||
|
ValueList::const_iterator col_it = std::find(m_columns.begin(),
|
||||||
|
m_columns.end(),
|
||||||
|
infos[i].fields[j].column);
|
||||||
|
|
||||||
|
if (col_it != m_columns.end())
|
||||||
|
{
|
||||||
|
MXS_NOTICE("rule '%s': query uses function '%s' with forbidden column: %s",
|
||||||
|
name().c_str(), func_it->c_str(), col_it->c_str());
|
||||||
|
*msg = create_error("Permission denied to column '%s' with function '%s'.",
|
||||||
|
col_it->c_str(), func_it->c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool LimitQueriesRule::matches_query(DbfwSession* session, GWBUF* buffer, char** msg) const
|
bool LimitQueriesRule::matches_query(DbfwSession* session, GWBUF* buffer, char** msg) const
|
||||||
{
|
{
|
||||||
QuerySpeed* queryspeed = session->query_speed();
|
QuerySpeed* queryspeed = session->query_speed();
|
||||||
|
@ -158,7 +158,6 @@ public:
|
|||||||
bool matches_query(DbfwSession* session, GWBUF* buffer, char** msg) const;
|
bool matches_query(DbfwSession* session, GWBUF* buffer, char** msg) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches if a query uses any functions
|
* Matches if a query uses any functions
|
||||||
*/
|
*/
|
||||||
@ -176,6 +175,26 @@ public:
|
|||||||
bool matches_query(DbfwSession* session, GWBUF* buffer, char** msg) const;
|
bool matches_query(DbfwSession* session, GWBUF* buffer, char** msg) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches if a query uses a function with a specific column
|
||||||
|
*/
|
||||||
|
class ColumnFunctionRule: public ValueListRule
|
||||||
|
{
|
||||||
|
ColumnFunctionRule(const ColumnFunctionRule&);
|
||||||
|
ColumnFunctionRule& operator=(const ColumnFunctionRule&);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ColumnFunctionRule(std::string name, const ValueList& values, const ValueList& columns):
|
||||||
|
ValueListRule(name, "COLUMN_FUNCTION", values),
|
||||||
|
m_columns(columns)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matches_query(DbfwSession* session, GWBUF* buffer, char** msg) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValueList m_columns; /*< List of columns to match */
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches if a queries are executed too quickly
|
* Matches if a queries are executed too quickly
|
||||||
|
Reference in New Issue
Block a user