Commit b221ec65 authored by Sergei Golubchik's avatar Sergei Golubchik

enforce privileges for GRANT role

parent 2f2699f9
...@@ -19,7 +19,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp ...@@ -19,7 +19,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp
grant role1 to foo@localhost with admin option; grant role1 to foo@localhost with admin option;
grant role2 to foo@localhost; grant role2 to foo@localhost;
grant role2 to role1; grant role2 to role1;
grant role3 to role4 with admin option; grant role4 to role3 with admin option;
grant select on *.* to foo@localhost with admin option; grant select on *.* to foo@localhost with admin option;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'admin option' at line 1 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'admin option' at line 1
show grants for foo@localhost; show grants for foo@localhost;
...@@ -33,18 +33,18 @@ Grants for role1 ...@@ -33,18 +33,18 @@ Grants for role1
GRANT USAGE ON *.* TO 'role1' GRANT USAGE ON *.* TO 'role1'
GRANT USAGE ON *.* TO 'role2' GRANT USAGE ON *.* TO 'role2'
GRANT USAGE ON *.* TO 'role3' GRANT USAGE ON *.* TO 'role3'
GRANT USAGE ON *.* TO 'role4'
GRANT role2 TO 'role1' GRANT role2 TO 'role1'
GRANT role3 TO 'role1' WITH ADMIN OPTION GRANT role3 TO 'role1' WITH ADMIN OPTION
GRANT role4 TO 'role3' WITH ADMIN OPTION
show grants for role4; show grants for role4;
Grants for role4 Grants for role4
GRANT USAGE ON *.* TO 'role3'
GRANT USAGE ON *.* TO 'role4' GRANT USAGE ON *.* TO 'role4'
GRANT role3 TO 'role4' WITH ADMIN OPTION
select * from mysql.roles_mapping; select * from mysql.roles_mapping;
Host User Role Admin_option Host User Role Admin_option
role1 role2 N role1 role2 N
role1 role3 Y role1 role3 Y
role4 role3 Y role3 role4 Y
bar foo role6 Y bar foo role6 Y
localhost foo role1 Y localhost foo role1 Y
localhost foo role2 N localhost foo role2 N
...@@ -64,25 +64,26 @@ Grants for role1 ...@@ -64,25 +64,26 @@ Grants for role1
GRANT USAGE ON *.* TO 'role1' GRANT USAGE ON *.* TO 'role1'
GRANT USAGE ON *.* TO 'role2' GRANT USAGE ON *.* TO 'role2'
GRANT USAGE ON *.* TO 'role3' GRANT USAGE ON *.* TO 'role3'
GRANT USAGE ON *.* TO 'role4'
GRANT role2 TO 'role1' GRANT role2 TO 'role1'
GRANT role3 TO 'role1' WITH ADMIN OPTION GRANT role3 TO 'role1' WITH ADMIN OPTION
GRANT role4 TO 'role3' WITH ADMIN OPTION
show grants for role4; show grants for role4;
Grants for role4 Grants for role4
GRANT USAGE ON *.* TO 'role3'
GRANT USAGE ON *.* TO 'role4' GRANT USAGE ON *.* TO 'role4'
GRANT role3 TO 'role4' WITH ADMIN OPTION
select * from information_schema.applicable_roles; select * from information_schema.applicable_roles;
GRANTEE ROLE_NAME IS_GRANTABLE GRANTEE ROLE_NAME IS_GRANTABLE
role1 role2 NO role1 role2 NO
role1 role3 YES role1 role3 YES
role4 role3 YES role3 role4 YES
root@localhost role1 YES root@localhost role1 YES
root@localhost role2 YES root@localhost role2 YES
root@localhost role4 YES root@localhost role4 YES
grant role2 to role1 with admin option; grant role2 to role1 with admin option;
revoke role1 from foo@localhost; revoke role1 from foo@localhost;
revoke admin option for role3 from role4; revoke admin option for role4 from role3;
revoke admin option for role2 from foo@localhost; revoke admin option for role2 from foo@localhost;
revoke admin option for role1 from root@localhost;
show grants for foo@localhost; show grants for foo@localhost;
Grants for foo@localhost Grants for foo@localhost
GRANT CREATE USER ON *.* TO 'foo'@'localhost' GRANT CREATE USER ON *.* TO 'foo'@'localhost'
...@@ -93,22 +94,22 @@ Grants for role1 ...@@ -93,22 +94,22 @@ Grants for role1
GRANT USAGE ON *.* TO 'role1' GRANT USAGE ON *.* TO 'role1'
GRANT USAGE ON *.* TO 'role2' GRANT USAGE ON *.* TO 'role2'
GRANT USAGE ON *.* TO 'role3' GRANT USAGE ON *.* TO 'role3'
GRANT USAGE ON *.* TO 'role4'
GRANT role2 TO 'role1' WITH ADMIN OPTION GRANT role2 TO 'role1' WITH ADMIN OPTION
GRANT role3 TO 'role1' WITH ADMIN OPTION GRANT role3 TO 'role1' WITH ADMIN OPTION
GRANT role4 TO 'role3'
show grants for role4; show grants for role4;
Grants for role4 Grants for role4
GRANT USAGE ON *.* TO 'role3'
GRANT USAGE ON *.* TO 'role4' GRANT USAGE ON *.* TO 'role4'
GRANT role3 TO 'role4'
select * from mysql.roles_mapping; select * from mysql.roles_mapping;
Host User Role Admin_option Host User Role Admin_option
role1 role2 Y role1 role2 Y
role1 role3 Y role1 role3 Y
role4 role3 N role3 role4 N
bar foo role6 Y bar foo role6 Y
localhost foo role2 N localhost foo role2 N
localhost foo role5 Y localhost foo role5 Y
localhost root role1 Y localhost root role1 N
localhost root role2 Y localhost root role2 Y
localhost root role4 Y localhost root role4 Y
flush privileges; flush privileges;
...@@ -122,20 +123,30 @@ Grants for role1 ...@@ -122,20 +123,30 @@ Grants for role1
GRANT USAGE ON *.* TO 'role1' GRANT USAGE ON *.* TO 'role1'
GRANT USAGE ON *.* TO 'role2' GRANT USAGE ON *.* TO 'role2'
GRANT USAGE ON *.* TO 'role3' GRANT USAGE ON *.* TO 'role3'
GRANT USAGE ON *.* TO 'role4'
GRANT role2 TO 'role1' WITH ADMIN OPTION GRANT role2 TO 'role1' WITH ADMIN OPTION
GRANT role3 TO 'role1' WITH ADMIN OPTION GRANT role3 TO 'role1' WITH ADMIN OPTION
GRANT role4 TO 'role3'
show grants for role4; show grants for role4;
Grants for role4 Grants for role4
GRANT USAGE ON *.* TO 'role3'
GRANT USAGE ON *.* TO 'role4' GRANT USAGE ON *.* TO 'role4'
GRANT role3 TO 'role4'
select * from information_schema.applicable_roles; select * from information_schema.applicable_roles;
GRANTEE ROLE_NAME IS_GRANTABLE GRANTEE ROLE_NAME IS_GRANTABLE
role1 role2 YES role1 role2 YES
role1 role3 YES role1 role3 YES
role4 role3 NO role3 role4 NO
root@localhost role1 YES root@localhost role1 NO
root@localhost role2 YES root@localhost role2 YES
root@localhost role4 YES root@localhost role4 YES
grant role1 to role4;
ERROR 28000: Access denied for user 'root'@'localhost'
grant role1 to role4 with admin option;
ERROR 28000: Access denied for user 'root'@'localhost'
grant role3 to role2;
revoke role3 from role2;
grant role4 to role2 with admin option;
revoke role2 from current_user;
revoke role4 from current_user;
grant role4 to current_user;
drop role role1, role2, role3, role4, role5, role6; drop role role1, role2, role3, role4, role5, role6;
drop user foo@localhost; drop user foo@localhost;
...@@ -30,7 +30,7 @@ create user bar with admin current_user; ...@@ -30,7 +30,7 @@ create user bar with admin current_user;
grant role1 to foo@localhost with admin option; grant role1 to foo@localhost with admin option;
grant role2 to foo@localhost; grant role2 to foo@localhost;
grant role2 to role1; grant role2 to role1;
grant role3 to role4 with admin option; grant role4 to role3 with admin option;
--error ER_PARSE_ERROR --error ER_PARSE_ERROR
grant select on *.* to foo@localhost with admin option; grant select on *.* to foo@localhost with admin option;
...@@ -54,8 +54,9 @@ select * from information_schema.applicable_roles; ...@@ -54,8 +54,9 @@ select * from information_schema.applicable_roles;
grant role2 to role1 with admin option; grant role2 to role1 with admin option;
revoke role1 from foo@localhost; revoke role1 from foo@localhost;
revoke admin option for role3 from role4; revoke admin option for role4 from role3;
revoke admin option for role2 from foo@localhost; revoke admin option for role2 from foo@localhost;
revoke admin option for role1 from root@localhost;
--sorted_result --sorted_result
show grants for foo@localhost; show grants for foo@localhost;
...@@ -75,6 +76,22 @@ show grants for role4; ...@@ -75,6 +76,22 @@ show grants for role4;
--sorted_result --sorted_result
select * from information_schema.applicable_roles; select * from information_schema.applicable_roles;
# Now, root@localhost don't have admin option for role1:
--error ER_ACCESS_DENIED_NO_PASSWORD_ERROR
grant role1 to role4;
--error ER_ACCESS_DENIED_NO_PASSWORD_ERROR
grant role1 to role4 with admin option;
# but role3 is grantable
grant role3 to role2;
revoke role3 from role2;
# now, a diamond
grant role4 to role2 with admin option;
revoke role2 from current_user;
revoke role4 from current_user;
grant role4 to current_user;
######################################## ########################################
# cleanup # cleanup
######################################## ########################################
......
...@@ -5322,6 +5322,67 @@ static void append_user(String *str, const char *u, const char *h) ...@@ -5322,6 +5322,67 @@ static void append_user(String *str, const char *u, const char *h)
str->append('\''); str->append('\'');
} }
struct IS_GRANTABLE_DATA
{
ACL_ROLE *role;
bool grantable;
};
static void can_grant_role_callback(ACL_ROLE *unuser __attribute__((unused)),
ACL_ROLE *grantee, void *context_data)
{
IS_GRANTABLE_DATA *data= (IS_GRANTABLE_DATA*)context_data;
for (uint i= 0; i < grantee->role_grants.elements; i++)
{
ACL_ROLE *r= *(dynamic_element(&grantee->role_grants, i, ACL_ROLE**));
if (r == data->role)
{
ROLE_GRANT_PAIR *pair=
find_role_grant_pair(&grantee->user, &empty_lex_str, &r->user);
if (pair->with_admin)
data->grantable= true;
}
}
}
/*
One can only grant a role if SELECT * FROM I_S.APPLICABLE_ROLES shows this
role as grantable.
What this really means - we need to traverse role graph for the current user
looking for our role being granted with the admin option.
*/
static bool can_grant_role(THD *thd, ACL_ROLE *role)
{
Security_context *sctx= thd->security_ctx;
ACL_USER *grantee= find_user_no_anon(sctx->priv_host, sctx->priv_user, true);
if (!grantee)
return false;
LEX_STRING host= { grantee->host.hostname, grantee->hostname_length };
IS_GRANTABLE_DATA data= { role, false };
for (uint i= 0; i < grantee->role_grants.elements; i++)
{
ACL_ROLE *r= *(dynamic_element(&grantee->role_grants, i, ACL_ROLE**));
if (r == role)
{
ROLE_GRANT_PAIR *pair=
find_role_grant_pair(&grantee->user, &host, &r->user);
if (pair->with_admin)
return true;
}
traverse_role_graph(r, &data, NULL, NULL, NULL, can_grant_role_callback);
if (data.grantable)
return true;
}
return false;
}
bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke) bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke)
{ {
...@@ -5371,6 +5432,15 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke) ...@@ -5371,6 +5432,15 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
if (!can_grant_role(thd, role))
{
mysql_mutex_unlock(&acl_cache->lock);
mysql_rwlock_unlock(&LOCK_grant);
my_error(ER_ACCESS_DENIED_NO_PASSWORD_ERROR, MYF(0),
thd->security_ctx->priv_user, thd->security_ctx->priv_host);
DBUG_RETURN(TRUE);
}
if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
{ // Should never happen { // Should never happen
mysql_mutex_unlock(&acl_cache->lock); mysql_mutex_unlock(&acl_cache->lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment