diff --git a/mysql-test/suite/roles/set_and_drop.result b/mysql-test/suite/roles/set_and_drop.result new file mode 100644 index 00000000000..17ee34d018f --- /dev/null +++ b/mysql-test/suite/roles/set_and_drop.result @@ -0,0 +1,69 @@ +create database mysqltest1; +create table mysqltest1.t1 (a int, b int); +create table mysqltest1.t2 (a int, b int); +insert mysqltest1.t1 values (1,2),(3,4); +insert mysqltest1.t2 values (5,6),(7,8); +create procedure mysqltest1.pr1() select "pr1"; +create user foo@localhost; +create role role1; +create role role2; +grant role2 to role1; +grant role1 to foo@localhost; +grant reload on *.* to role2; +grant select on mysql.* to role2; +grant execute on procedure mysqltest1.pr1 to role2; +grant select on mysqltest1.t1 to role2; +grant select (a) on mysqltest1.t2 to role2; +flush tables; +ERROR 42000: Access denied; you need (at least one of) the RELOAD privilege(s) for this operation +select * from mysql.roles_mapping; +ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 'roles_mapping' +show tables from mysqltest1; +ERROR 42000: Access denied for user 'foo'@'localhost' to database 'mysqltest1' +set role role1; +flush tables; +select * from mysql.roles_mapping; +Host User Role Admin_option + role1 role2 N +localhost foo role1 N +localhost root role1 Y +localhost root role2 Y +show tables from mysqltest1; +Tables_in_mysqltest1 +t1 +t2 +select * from mysqltest1.t1; +a b +1 2 +3 4 +select * from mysqltest1.t2; +ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't2' +select a from mysqltest1.t2; +a +5 +7 +call mysqltest1.pr1(); +pr1 +pr1 +revoke execute on procedure mysqltest1.pr1 from role2; +call mysqltest1.pr1(); +ERROR 42000: execute command denied to user 'foo'@'localhost' for routine 'mysqltest1.pr1' +drop role role2; +show grants; +Grants for foo@localhost +GRANT role1 TO 'foo'@'localhost' +GRANT USAGE ON *.* TO 'foo'@'localhost' +GRANT USAGE ON *.* TO 'role1' +select * from information_schema.enabled_roles; +ROLE_NAME +role1 +flush tables; +select * from mysql.roles_mapping; +ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 'roles_mapping' +select * from mysqltest1.t1; +ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't1' +select a from mysqltest1.t2; +ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't2' +drop role role1; +drop user foo@localhost; +drop database mysqltest1; diff --git a/mysql-test/suite/roles/set_and_drop.test b/mysql-test/suite/roles/set_and_drop.test new file mode 100644 index 00000000000..d79d385b84c --- /dev/null +++ b/mysql-test/suite/roles/set_and_drop.test @@ -0,0 +1,74 @@ +--source include/not_embedded.inc +# +# test setting and dropping a role +# + +create database mysqltest1; +create table mysqltest1.t1 (a int, b int); +create table mysqltest1.t2 (a int, b int); +insert mysqltest1.t1 values (1,2),(3,4); +insert mysqltest1.t2 values (5,6),(7,8); + +create procedure mysqltest1.pr1() select "pr1"; + +create user foo@localhost; +create role role1; +create role role2; + +grant role2 to role1; +grant role1 to foo@localhost; +grant reload on *.* to role2; +grant select on mysql.* to role2; +grant execute on procedure mysqltest1.pr1 to role2; +grant select on mysqltest1.t1 to role2; +grant select (a) on mysqltest1.t2 to role2; + +connect (foo,localhost,foo); + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +flush tables; +--error ER_TABLEACCESS_DENIED_ERROR +select * from mysql.roles_mapping; +--error ER_DBACCESS_DENIED_ERROR +show tables from mysqltest1; + +set role role1; + +flush tables; +--sorted_result +select * from mysql.roles_mapping; +show tables from mysqltest1; +select * from mysqltest1.t1; +--error ER_TABLEACCESS_DENIED_ERROR +select * from mysqltest1.t2; +select a from mysqltest1.t2; +call mysqltest1.pr1(); + +connection default; +revoke execute on procedure mysqltest1.pr1 from role2; +connection foo; + +--error ER_PROCACCESS_DENIED_ERROR +call mysqltest1.pr1(); + +connection default; +drop role role2; +connection foo; + +show grants; +select * from information_schema.enabled_roles; + +flush tables; +--error ER_TABLEACCESS_DENIED_ERROR +select * from mysql.roles_mapping; +--error ER_TABLEACCESS_DENIED_ERROR +select * from mysqltest1.t1; +--error ER_TABLEACCESS_DENIED_ERROR +select a from mysqltest1.t2; + +connection default; +disconnect foo; + +drop role role1; +drop user foo@localhost; +drop database mysqltest1; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index db89d32cbc7..2ed7c748eb2 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8539,6 +8539,9 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, size_t old_key_length= acl_role->user.length; if (drop) { + /* all grants must be revoked from this role by now. propagate this */ + propagate_role_grants(acl_role, PRIVS_TO_MERGE::ALL, 0, 0); + // delete the role from cross-reference arrays for (uint i=0; i < acl_role->role_grants.elements; i++) { @@ -8847,46 +8850,20 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop, int result= 0; int found; bool handle_as_role= user_from->is_role(); + bool search_only= !drop && !user_to; DBUG_ENTER("handle_grant_data"); if (user_to) DBUG_ASSERT(handle_as_role == user_to->is_role()); - /* Handle user table. */ - if ((found= handle_grant_table(tables, 0, drop, user_from, user_to)) < 0) + if (search_only) { - /* Handle of table failed, don't touch the in-memory array. */ - result= -1; - } - else - { - if (handle_as_role) - { - if ((handle_grant_struct(ROLE_ACL, drop, user_from, user_to)) || found) - { - result= 1; /* At least one record/element found. */ - /* If search is requested, we do not need to search further. */ - if (! drop && ! user_to) - goto end; - } - else - if (find_user_exact(user_from->host.str, user_from->user.str)) - goto end; // looking for a role, found a user - } - else - { - /* Handle user array. */ - if ((handle_grant_struct(USER_ACL, drop, user_from, user_to)) || found) - { - result= 1; /* At least one record/element found. */ - /* If search is requested, we do not need to search further. */ - if (! drop && ! user_to) - goto end; - } - else - if (find_acl_role(user_from->user.str)) - goto end; // looking for a user, found a role - } + /* quickly search in-memory structures first */ + if (handle_as_role && find_acl_role(user_from->user.str)) + DBUG_RETURN(1); // found + + if (!handle_as_role && find_user_exact(user_from->host.str, user_from->user.str)) + DBUG_RETURN(1); // found } /* Handle db table. */ @@ -8898,12 +8875,12 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop, else { /* Handle db array. */ - if (((handle_grant_struct(DB_ACL, drop, user_from, user_to) && ! result) || - found) && ! result) + if ((handle_grant_struct(DB_ACL, drop, user_from, user_to) || found) + && ! result) { result= 1; /* At least one record/element found. */ /* If search is requested, we do not need to search further. */ - if (! drop && ! user_to) + if (search_only) goto end; } } @@ -8917,21 +8894,21 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop, else { /* Handle procs array. */ - if (((handle_grant_struct(PROC_PRIVILEGES_HASH, drop, user_from, user_to) && ! result) || - found) && ! result) + if ((handle_grant_struct(PROC_PRIVILEGES_HASH, drop, user_from, user_to) || found) + && ! result) { result= 1; /* At least one record/element found. */ /* If search is requested, we do not need to search further. */ - if (! drop && ! user_to) + if (search_only) goto end; } /* Handle funcs array. */ - if (((handle_grant_struct(FUNC_PRIVILEGES_HASH, drop, user_from, user_to) && ! result) || - found) && ! result) + if ((handle_grant_struct(FUNC_PRIVILEGES_HASH, drop, user_from, user_to) || found) + && ! result) { result= 1; /* At least one record/element found. */ /* If search is requested, we do not need to search further. */ - if (! drop && ! user_to) + if (search_only) goto end; } } @@ -8948,7 +8925,7 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop, { result= 1; /* At least one record found. */ /* If search is requested, we do not need to search further. */ - if (! drop && ! user_to) + if (search_only) goto end; } @@ -8961,9 +8938,11 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop, else { /* Handle columns hash. */ - if (((handle_grant_struct(COLUMN_PRIVILEGES_HASH, drop, user_from, user_to) && ! result) || - found) && ! result) + if ((handle_grant_struct(COLUMN_PRIVILEGES_HASH, drop, user_from, user_to) || found) + && ! result) result= 1; /* At least one record/element found. */ + if (search_only) + goto end; } } @@ -8978,9 +8957,11 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop, else { /* Handle proxies_priv array. */ - if ((handle_grant_struct(PROXY_USERS_ACL, drop, user_from, user_to) && !result) || - found) + if ((handle_grant_struct(PROXY_USERS_ACL, drop, user_from, user_to) || found) + && ! result) result= 1; /* At least one record/element found. */ + if (search_only) + goto end; } } @@ -8995,13 +8976,31 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop, else { /* Handle acl_roles_mappings array */ - if ((handle_grant_struct(ROLES_MAPPINGS_HASH, drop, user_from, user_to) && !result) || - found) + if ((handle_grant_struct(ROLES_MAPPINGS_HASH, drop, user_from, user_to) || found) + && ! result) result= 1; /* At least one record/element found */ + if (search_only) + goto end; } } - end: + /* Handle user table. */ + if ((found= handle_grant_table(tables, 0, drop, user_from, user_to)) < 0) + { + /* Handle of table failed, don't touch the in-memory array. */ + result= -1; + } + else + { + enum enum_acl_lists what= handle_as_role ? ROLE_ACL : USER_ACL; + if (((handle_grant_struct(what, drop, user_from, user_to)) || found) && !result) + { + result= 1; /* At least one record/element found. */ + DBUG_ASSERT(! search_only); + } + } + +end: DBUG_RETURN(result); }