enforce privileges for GRANT role
This commit is contained in:
parent
2f2699f97b
commit
b221ec6529
@ -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 role2 to foo@localhost;
|
||||
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;
|
||||
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;
|
||||
@ -33,18 +33,18 @@ Grants for role1
|
||||
GRANT USAGE ON *.* TO 'role1'
|
||||
GRANT USAGE ON *.* TO 'role2'
|
||||
GRANT USAGE ON *.* TO 'role3'
|
||||
GRANT USAGE ON *.* TO 'role4'
|
||||
GRANT role2 TO 'role1'
|
||||
GRANT role3 TO 'role1' WITH ADMIN OPTION
|
||||
GRANT role4 TO 'role3' WITH ADMIN OPTION
|
||||
show grants for role4;
|
||||
Grants for role4
|
||||
GRANT USAGE ON *.* TO 'role3'
|
||||
GRANT USAGE ON *.* TO 'role4'
|
||||
GRANT role3 TO 'role4' WITH ADMIN OPTION
|
||||
select * from mysql.roles_mapping;
|
||||
Host User Role Admin_option
|
||||
role1 role2 N
|
||||
role1 role3 Y
|
||||
role4 role3 Y
|
||||
role3 role4 Y
|
||||
bar foo role6 Y
|
||||
localhost foo role1 Y
|
||||
localhost foo role2 N
|
||||
@ -64,25 +64,26 @@ Grants for role1
|
||||
GRANT USAGE ON *.* TO 'role1'
|
||||
GRANT USAGE ON *.* TO 'role2'
|
||||
GRANT USAGE ON *.* TO 'role3'
|
||||
GRANT USAGE ON *.* TO 'role4'
|
||||
GRANT role2 TO 'role1'
|
||||
GRANT role3 TO 'role1' WITH ADMIN OPTION
|
||||
GRANT role4 TO 'role3' WITH ADMIN OPTION
|
||||
show grants for role4;
|
||||
Grants for role4
|
||||
GRANT USAGE ON *.* TO 'role3'
|
||||
GRANT USAGE ON *.* TO 'role4'
|
||||
GRANT role3 TO 'role4' WITH ADMIN OPTION
|
||||
select * from information_schema.applicable_roles;
|
||||
GRANTEE ROLE_NAME IS_GRANTABLE
|
||||
role1 role2 NO
|
||||
role1 role3 YES
|
||||
role4 role3 YES
|
||||
role3 role4 YES
|
||||
root@localhost role1 YES
|
||||
root@localhost role2 YES
|
||||
root@localhost role4 YES
|
||||
grant role2 to role1 with admin option;
|
||||
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 role1 from root@localhost;
|
||||
show grants for foo@localhost;
|
||||
Grants for foo@localhost
|
||||
GRANT CREATE USER ON *.* TO 'foo'@'localhost'
|
||||
@ -93,22 +94,22 @@ Grants for role1
|
||||
GRANT USAGE ON *.* TO 'role1'
|
||||
GRANT USAGE ON *.* TO 'role2'
|
||||
GRANT USAGE ON *.* TO 'role3'
|
||||
GRANT USAGE ON *.* TO 'role4'
|
||||
GRANT role2 TO 'role1' WITH ADMIN OPTION
|
||||
GRANT role3 TO 'role1' WITH ADMIN OPTION
|
||||
GRANT role4 TO 'role3'
|
||||
show grants for role4;
|
||||
Grants for role4
|
||||
GRANT USAGE ON *.* TO 'role3'
|
||||
GRANT USAGE ON *.* TO 'role4'
|
||||
GRANT role3 TO 'role4'
|
||||
select * from mysql.roles_mapping;
|
||||
Host User Role Admin_option
|
||||
role1 role2 Y
|
||||
role1 role3 Y
|
||||
role4 role3 N
|
||||
role3 role4 N
|
||||
bar foo role6 Y
|
||||
localhost foo role2 N
|
||||
localhost foo role5 Y
|
||||
localhost root role1 Y
|
||||
localhost root role1 N
|
||||
localhost root role2 Y
|
||||
localhost root role4 Y
|
||||
flush privileges;
|
||||
@ -122,20 +123,30 @@ Grants for role1
|
||||
GRANT USAGE ON *.* TO 'role1'
|
||||
GRANT USAGE ON *.* TO 'role2'
|
||||
GRANT USAGE ON *.* TO 'role3'
|
||||
GRANT USAGE ON *.* TO 'role4'
|
||||
GRANT role2 TO 'role1' WITH ADMIN OPTION
|
||||
GRANT role3 TO 'role1' WITH ADMIN OPTION
|
||||
GRANT role4 TO 'role3'
|
||||
show grants for role4;
|
||||
Grants for role4
|
||||
GRANT USAGE ON *.* TO 'role3'
|
||||
GRANT USAGE ON *.* TO 'role4'
|
||||
GRANT role3 TO 'role4'
|
||||
select * from information_schema.applicable_roles;
|
||||
GRANTEE ROLE_NAME IS_GRANTABLE
|
||||
role1 role2 YES
|
||||
role1 role3 YES
|
||||
role4 role3 NO
|
||||
root@localhost role1 YES
|
||||
role3 role4 NO
|
||||
root@localhost role1 NO
|
||||
root@localhost role2 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 user foo@localhost;
|
||||
|
@ -30,7 +30,7 @@ create user bar with admin current_user;
|
||||
grant role1 to foo@localhost with admin option;
|
||||
grant role2 to foo@localhost;
|
||||
grant role2 to role1;
|
||||
grant role3 to role4 with admin option;
|
||||
grant role4 to role3 with admin option;
|
||||
--error ER_PARSE_ERROR
|
||||
grant select on *.* to foo@localhost with admin option;
|
||||
|
||||
@ -54,8 +54,9 @@ select * from information_schema.applicable_roles;
|
||||
|
||||
grant role2 to role1 with admin option;
|
||||
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 role1 from root@localhost;
|
||||
|
||||
--sorted_result
|
||||
show grants for foo@localhost;
|
||||
@ -75,6 +76,22 @@ show grants for role4;
|
||||
--sorted_result
|
||||
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
|
||||
########################################
|
||||
|
@ -5322,6 +5322,67 @@ static void append_user(String *str, const char *u, const char *h)
|
||||
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)
|
||||
{
|
||||
@ -5371,6 +5432,15 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke)
|
||||
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))
|
||||
{ // Should never happen
|
||||
mysql_mutex_unlock(&acl_cache->lock);
|
||||
|
Loading…
x
Reference in New Issue
Block a user