From c28bf2a3449eab22ed0349972e97bc7ae3765ef9 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 18 Oct 2013 12:21:37 -0700 Subject: [PATCH] bugfix: propagate grant changes through the role graph after table/column/routine grants --- .../acl_roles_set_role-routine-simple.result | 3 - ...cl_roles_set_role-table-column-priv.result | 1 - .../r/acl_roles_set_role-table-simple.result | 1 - .../t/acl_roles_set_role-routine-simple.test | 2 - .../acl_roles_set_role-table-column-priv.test | 2 - .../t/acl_roles_set_role-table-simple.test | 2 - sql/sql_acl.cc | 65 +++++++++---------- 7 files changed, 32 insertions(+), 44 deletions(-) diff --git a/mysql-test/r/acl_roles_set_role-routine-simple.result b/mysql-test/r/acl_roles_set_role-routine-simple.result index 11655544423..b791e87d724 100644 --- a/mysql-test/r/acl_roles_set_role-routine-simple.result +++ b/mysql-test/r/acl_roles_set_role-routine-simple.result @@ -26,7 +26,6 @@ end| grant execute on function mysql.test_func to test_role2; grant execute on procedure mysql.test_proc to test_role2; grant execute on mysql.* to test_role3; -flush privileges; show grants; Grants for test_user@localhost GRANT USAGE ON *.* TO 'test_user'@'localhost' @@ -98,6 +97,4 @@ delete from mysql.user where user like'test_%'; delete from mysql.roles_mapping where Role like 'test%'; drop function mysql.test_func; drop procedure mysql.test_proc; -Warnings: -Warning 1403 There is no such grant defined for user 'test_role1' on host '' on routine 'test_proc' flush privileges; diff --git a/mysql-test/r/acl_roles_set_role-table-column-priv.result b/mysql-test/r/acl_roles_set_role-table-column-priv.result index 8ff7bed6bca..058b8b43f76 100644 --- a/mysql-test/r/acl_roles_set_role-table-column-priv.result +++ b/mysql-test/r/acl_roles_set_role-table-column-priv.result @@ -13,7 +13,6 @@ Host User Role Admin_option test_role1 test_role2 N localhost test_user test_role1 N grant select (Role) on mysql.roles_mapping to test_role2; -flush privileges; select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'roles_mapping' show grants; diff --git a/mysql-test/r/acl_roles_set_role-table-simple.result b/mysql-test/r/acl_roles_set_role-table-simple.result index 74e4dd87d04..f2f88185047 100644 --- a/mysql-test/r/acl_roles_set_role-table-simple.result +++ b/mysql-test/r/acl_roles_set_role-table-simple.result @@ -13,7 +13,6 @@ Host User Role Admin_option test_role1 test_role2 N localhost test_user test_role1 N grant select on mysql.roles_mapping to test_role2; -flush privileges; select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'roles_mapping' show grants; diff --git a/mysql-test/t/acl_roles_set_role-routine-simple.test b/mysql-test/t/acl_roles_set_role-routine-simple.test index b076903b0bf..43feec4faf8 100644 --- a/mysql-test/t/acl_roles_set_role-routine-simple.test +++ b/mysql-test/t/acl_roles_set_role-routine-simple.test @@ -29,8 +29,6 @@ grant execute on procedure mysql.test_proc to test_role2; grant execute on mysql.* to test_role3; -flush privileges; - change_user 'test_user'; --sorted_result show grants; diff --git a/mysql-test/t/acl_roles_set_role-table-column-priv.test b/mysql-test/t/acl_roles_set_role-table-column-priv.test index dfc21bd4eb9..f02ac206e5b 100644 --- a/mysql-test/t/acl_roles_set_role-table-column-priv.test +++ b/mysql-test/t/acl_roles_set_role-table-column-priv.test @@ -11,8 +11,6 @@ select * from mysql.roles_mapping; grant select (Role) on mysql.roles_mapping to test_role2; -flush privileges; - change_user 'test_user'; --error ER_TABLEACCESS_DENIED_ERROR diff --git a/mysql-test/t/acl_roles_set_role-table-simple.test b/mysql-test/t/acl_roles_set_role-table-simple.test index dd86f0c11e6..d51ddf46aac 100644 --- a/mysql-test/t/acl_roles_set_role-table-simple.test +++ b/mysql-test/t/acl_roles_set_role-table-simple.test @@ -11,8 +11,6 @@ select * from mysql.roles_mapping; grant select on mysql.roles_mapping to test_role2; -flush privileges; - change_user 'test_user'; --error ER_TABLEACCESS_DENIED_ERROR diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index e224669c75f..1ba5d71918a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -709,41 +709,24 @@ static bool update_user_table(THD *thd, TABLE *table, const char *host, static my_bool acl_load(THD *thd, TABLE_LIST *tables); static my_bool grant_load(THD *thd, TABLE_LIST *tables); static inline void get_grantor(THD *thd, char* grantor); -static my_bool acl_user_reset_grant(ACL_USER *user, - void * not_used __attribute__((unused))); -static my_bool acl_role_reset_grant(ACL_ROLE *role, - void * not_used __attribute__((unused))); -static my_bool acl_role_propagate_grants(ACL_ROLE *role, - void * not_used __attribute__((unused))); +static my_bool acl_user_reset_grant(ACL_USER *, void *); +static my_bool acl_role_reset_grant(ACL_ROLE *, void *); +static my_bool acl_role_propagate_grants(ACL_ROLE *, void *); static int add_role_user_mapping(ROLE_GRANT_PAIR *mapping); static void reset_role_db_privileges(ACL_ROLE *role); static void reset_role_table_and_column_privileges(ACL_ROLE *role); static void reset_role_routine_grant_privileges(ACL_ROLE *role); -static void role_explore_create_list(ACL_ROLE *unused, - ACL_ROLE *role, - void *context_data); +static void role_explore_create_list(ACL_ROLE *, ACL_ROLE *, void *); static bool role_explore_start_access_check(ACL_ROLE *role, void *unused); -static bool role_explore_merge_if_final(ACL_ROLE *current, ACL_ROLE *neighbour, - void *unused); -static void role_explore_set_final_access_bits(ACL_ROLE *parent, - ACL_ROLE *current, - void *unused); -static bool role_explore_detect_cycle(ACL_ROLE *current, - ACL_ROLE *neighbour, - void *context_data); -static int traverse_role_graph(ACL_ROLE *role, void *context_data, - bool (*on_start) (ACL_ROLE *role, - void *context_data), - bool (*on_open) (ACL_ROLE *current, - ACL_ROLE *neighbour, - void *context_data), - bool (*on_cycle) (ACL_ROLE *current, - ACL_ROLE *neighbour, - void *context_data), - void (*on_finish)(ACL_ROLE *parent, - ACL_ROLE *current, - void *context_data)); +static bool role_explore_merge_if_final(ACL_ROLE *, ACL_ROLE *, void *); +static void role_explore_set_final_access_bits(ACL_ROLE *, ACL_ROLE *, void *); +static bool role_explore_detect_cycle(ACL_ROLE *, ACL_ROLE *, void *); +static int traverse_role_graph(ACL_ROLE *, void *, + bool (*)(ACL_ROLE *, void *), + bool (*)(ACL_ROLE *, ACL_ROLE *, void *), + bool (*)(ACL_ROLE *, ACL_ROLE *, void *), + void (*)(ACL_ROLE *, ACL_ROLE *, void *)); static void merge_role_grant_privileges(ACL_ROLE *target, ACL_ROLE *source); @@ -1999,15 +1982,22 @@ static void acl_update_role_entry(ACL_ROLE *role, ulong privileges) } -static void acl_update_role(const char *rolename, - ulong privileges) +static void acl_update_role(const char *rolename) +{ + mysql_mutex_assert_owner(&acl_cache->lock); + ACL_ROLE *role= find_acl_role(rolename); + if (!role) + return; + acl_update_role_entry(role, role->initial_role_access); +} + + +static void acl_update_role(const char *rolename, ulong privileges) { mysql_mutex_assert_owner(&acl_cache->lock); ACL_ROLE *role= find_acl_role(rolename); if (!role) - { return; - } acl_update_role_entry(role, privileges); } @@ -5117,7 +5107,10 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, result= TRUE; } } + if (Str->is_role()) + acl_update_role(Str->user.str); } + thd->mem_root= old_root; mysql_mutex_unlock(&acl_cache->lock); @@ -5278,6 +5271,8 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, result= TRUE; continue; } + if (Str->is_role()) + acl_update_role(Str->user.str); } thd->mem_root= old_root; mysql_mutex_unlock(&acl_cache->lock); @@ -7903,6 +7898,10 @@ static int modify_grant_table(TABLE *table, Field *host_field, It creates data structures if they don't exist for the grantee. This includes data structures related to database privileges, tables privileges, column privileges, function and procedures privileges + + TODO only merge those privileges that were changed + (e.g. only table/column privileges after mysql_table_grant, only routine + privileges after mysql_routine_grant) */ static void merge_role_grant_privileges(ACL_ROLE *target, ACL_ROLE *source)