Skip to content

Commit 2fced9e

Browse files
committed
MDEV-13655: Set role does not properly grant privileges.
When granting a role to another role, DB privileges get propagated. If the grantee had no previous DB privileges, an extra ACL_DB entry is created to house those "indirectly received" privileges. If, afterwards, DB privileges are granted to the grantee directly, we must make sure to not create a duplicate ACL_DB entry.
1 parent 40088bf commit 2fced9e

File tree

4 files changed

+132
-16
lines changed

4 files changed

+132
-16
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#
2+
# MDEV-13655: SET ROLE does not properly grant privileges.
3+
#
4+
# We must test that if aditional db privileges get granted to a role
5+
# which previously inherited privileges from another granted role
6+
# keep the internal memory structures intact.
7+
#
8+
create role simple;
9+
#
10+
# First we create an entry with privileges for databases for the simple role.
11+
#
12+
grant select, insert, update, delete, lock tables, execute on t.* to simple;
13+
create role admin;
14+
#
15+
# Now we grant the simple role to admin. This means that db privileges
16+
# should propagate to admin.
17+
#
18+
grant simple to admin;
19+
show grants for admin;
20+
Grants for admin
21+
GRANT simple TO 'admin'
22+
GRANT USAGE ON *.* TO 'admin'
23+
GRANT USAGE ON *.* TO 'simple'
24+
GRANT SELECT, INSERT, UPDATE, DELETE, LOCK TABLES, EXECUTE ON `t`.* TO 'simple'
25+
#
26+
# Finally, we give the admin all the available privileges for the db.
27+
#
28+
grant all on t.* to admin;
29+
#
30+
# Create a user to test out the new roles;
31+
#
32+
create user foo;
33+
grant admin to foo;
34+
create database t;
35+
ERROR 42000: Access denied for user 'foo'@'%' to database 't'
36+
set role admin;
37+
show grants;
38+
Grants for foo@%
39+
GRANT admin TO 'foo'@'%'
40+
GRANT USAGE ON *.* TO 'foo'@'%'
41+
GRANT simple TO 'admin'
42+
GRANT USAGE ON *.* TO 'admin'
43+
GRANT ALL PRIVILEGES ON `t`.* TO 'admin'
44+
GRANT USAGE ON *.* TO 'simple'
45+
GRANT SELECT, INSERT, UPDATE, DELETE, LOCK TABLES, EXECUTE ON `t`.* TO 'simple'
46+
create database t;
47+
drop database t;
48+
drop role simple;
49+
drop role admin;
50+
drop user foo;
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
source include/not_embedded.inc;
2+
3+
--echo #
4+
--echo # MDEV-13655: SET ROLE does not properly grant privileges.
5+
--echo #
6+
--echo # We must test that if aditional db privileges get granted to a role
7+
--echo # which previously inherited privileges from another granted role
8+
--echo # keep the internal memory structures intact.
9+
--echo #
10+
11+
create role simple;
12+
13+
--echo #
14+
--echo # First we create an entry with privileges for databases for the simple role.
15+
--echo #
16+
grant select, insert, update, delete, lock tables, execute on t.* to simple;
17+
create role admin;
18+
19+
--echo #
20+
--echo # Now we grant the simple role to admin. This means that db privileges
21+
--echo # should propagate to admin.
22+
--echo #
23+
grant simple to admin;
24+
show grants for admin;
25+
26+
--echo #
27+
--echo # Finally, we give the admin all the available privileges for the db.
28+
--echo #
29+
grant all on t.* to admin;
30+
31+
--echo #
32+
--echo # Create a user to test out the new roles;
33+
--echo #
34+
create user foo;
35+
grant admin to foo;
36+
37+
connect (foo,localhost,foo,,,,,);
38+
--error ER_DBACCESS_DENIED_ERROR
39+
create database t;
40+
set role admin;
41+
show grants;
42+
create database t;
43+
drop database t;
44+
45+
connection default;
46+
47+
drop role simple;
48+
drop role admin;
49+
drop user foo;

sql/sql_acl.cc

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2129,37 +2129,42 @@ static void acl_insert_user(const char *user, const char *host,
21292129
}
21302130

21312131

2132-
static void acl_update_db(const char *user, const char *host, const char *db,
2132+
static bool acl_update_db(const char *user, const char *host, const char *db,
21332133
ulong privileges)
21342134
{
21352135
mysql_mutex_assert_owner(&acl_cache->lock);
21362136

2137+
bool updated= false;
2138+
21372139
for (uint i=0 ; i < acl_dbs.elements ; i++)
21382140
{
21392141
ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
21402142
if ((!acl_db->user && !user[0]) ||
2141-
(acl_db->user &&
2142-
!strcmp(user,acl_db->user)))
2143+
(acl_db->user &&
2144+
!strcmp(user,acl_db->user)))
21432145
{
21442146
if ((!acl_db->host.hostname && !host[0]) ||
2145-
(acl_db->host.hostname &&
2146-
!strcmp(host, acl_db->host.hostname)))
2147+
(acl_db->host.hostname &&
2148+
!strcmp(host, acl_db->host.hostname)))
21472149
{
2148-
if ((!acl_db->db && !db[0]) ||
2149-
(acl_db->db && !strcmp(db,acl_db->db)))
2150+
if ((!acl_db->db && !db[0]) ||
2151+
(acl_db->db && !strcmp(db,acl_db->db)))
21502152

2151-
{
2152-
if (privileges)
2153+
{
2154+
if (privileges)
21532155
{
21542156
acl_db->access= privileges;
21552157
acl_db->initial_access= acl_db->access;
21562158
}
2157-
else
2158-
delete_dynamic_element(&acl_dbs,i);
2159-
}
2159+
else
2160+
delete_dynamic_element(&acl_dbs,i);
2161+
updated= true;
2162+
}
21602163
}
21612164
}
21622165
}
2166+
2167+
return updated;
21632168
}
21642169

21652170

@@ -3428,9 +3433,21 @@ static int replace_db_table(TABLE *table, const char *db,
34283433
acl_cache->clear(1);// Clear privilege cache
34293434
if (old_row_exists)
34303435
acl_update_db(combo.user.str,combo.host.str,db,rights);
3431-
else
3432-
if (rights)
3433-
acl_insert_db(combo.user.str,combo.host.str,db,rights);
3436+
else if (rights)
3437+
{
3438+
/*
3439+
If we did not have an already existing row, for users, we must always
3440+
insert an ACL_DB entry. For roles however, it is possible that one was
3441+
already created when DB privileges were propagated from other granted
3442+
roles onto the current role. For this case, first try to update the
3443+
existing entry, otherwise insert a new one.
3444+
*/
3445+
if (!combo.is_role() ||
3446+
!acl_update_db(combo.user.str, combo.host.str, db, rights))
3447+
{
3448+
acl_insert_db(combo.user.str,combo.host.str,db,rights);
3449+
}
3450+
}
34343451
DBUG_RETURN(0);
34353452

34363453
/* This could only happen if the grant tables got corrupted */

sql/structs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ typedef int *(*update_var)(THD *, struct st_mysql_show_var *);
191191

192192
typedef structst_lex_user {
193193
LEX_STRING user, host, password, plugin, auth;
194-
bool is_role() { return user.str[0] && !host.str[0]; }
194+
bool is_role() const { return user.str[0] && !host.str[0]; }
195195
void set_lex_string(LEX_STRING *l, char *buf)
196196
{
197197
if (is_role())

0 commit comments

Comments
 (0)