Skip to content

Commit 07de0ac

Browse files
committed
MDEV-20299 SET SESSION AUTHORIZATION
a.k.a. "sudo"
1 parent 0f4a35a commit 07de0ac

File tree

12 files changed

+438
-11
lines changed

12 files changed

+438
-11
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#
2+
# MDEV-20299 SET SESSION AUTHORIZATION
3+
#
4+
create user foo@bar identified via mysql_native_password using password('foo');
5+
connect con1, localhost, root;
6+
select user(), current_user(), database();
7+
user() current_user() database()
8+
root@localhost root@localhost test
9+
set session authorization bar@foo;
10+
ERROR HY000: The user 'bar'@'foo' does not exist
11+
select user(), current_user(), database();
12+
user() current_user() database()
13+
root@localhost root@localhost test
14+
set session authorization foo@bar;
15+
select user(), current_user(), database();
16+
user() current_user() database()
17+
foo@bar foo@bar NULL
18+
set @a:='not changed';
19+
set session authorization bar@foo;
20+
ERROR 28000: Access denied trying to change to user 'bar'@'foo'
21+
select @a;
22+
@a
23+
not changed
24+
set session authorization foo@bar;
25+
select @a;
26+
@a
27+
NULL
28+
disconnect con1;
29+
connection default;
30+
drop user foo@bar;
31+
create user ''@'l%t' identified via mysql_native_password using password('foo');
32+
connect con1, localhost, root;
33+
select user(), current_user(), database();
34+
user() current_user() database()
35+
root@localhost root@localhost test
36+
set session authorization fist@list;
37+
select user(), current_user(), database();
38+
user() current_user() database()
39+
fist@list @l%t NULL
40+
set @a:='not changed';
41+
set session authorization first@last;
42+
ERROR 28000: Access denied trying to change to user 'first'@'last'
43+
select @a;
44+
@a
45+
not changed
46+
set session authorization fist@list;
47+
select @a;
48+
@a
49+
NULL
50+
disconnect con1;
51+
connection default;
52+
drop user ''@'l%t';
53+
create user ''@'%' identified via mysql_native_password using password('foo');
54+
connect con1, localhost, root;
55+
select user(), current_user(), database();
56+
user() current_user() database()
57+
root@localhost root@localhost test
58+
set session authorization ''@last;
59+
ERROR HY000: The user ''@'last' does not exist
60+
set session authorization foo@'';
61+
ERROR HY000: The user 'foo'@'' does not exist
62+
start transaction;
63+
select user(), current_user(), database(), @@in_transaction;
64+
user() current_user() database() @@in_transaction
65+
root@localhost root@localhost test 1
66+
set session authorization foo@bar;
67+
ERROR 25001: SESSION AUTHORIZATION can't be set while a transaction is in progress
68+
select user(), current_user(), database(), @@in_transaction;
69+
user() current_user() database() @@in_transaction
70+
root@localhost root@localhost test 1
71+
disconnect con1;
72+
connection default;
73+
prepare s from 'set session authorization foo@bar';
74+
ERROR HY000: This command is not supported in the prepared statement protocol yet
75+
create procedure sudo_foobar() set session authorization foo@bar;
76+
ERROR 0A000: SET SESSION AUTHORIZATION is not allowed in stored procedures
77+
create procedure sudo_foobar()
78+
execute immediate 'set session authorization foo@bar';
79+
call sudo_foobar();
80+
ERROR HY000: This command is not supported in the prepared statement protocol yet
81+
drop procedure sudo_foobar;
82+
drop user ''@'%';
83+
# restart: --skip-grant-tables
84+
set session authorization u@localhost;
85+
ERROR HY000: The MariaDB server is running with the --skip-grant-tables option so it cannot execute this statement
86+
flush privileges;
87+
create user u1@localhost with max_statement_time 1;
88+
connect u1,localhost,u1;
89+
select @@max_statement_time;
90+
@@max_statement_time
91+
1.000000
92+
disconnect u1;
93+
connect u1,localhost,root;
94+
select @@max_statement_time;
95+
@@max_statement_time
96+
0.000000
97+
set session authorization u1@localhost;
98+
select @@max_statement_time;
99+
@@max_statement_time
100+
1.000000
101+
disconnect u1;
102+
connection default;
103+
drop user u1@localhost;
104+
#
105+
# MDEV-36399 SET SESSION AUTHORIZATION allows an unrpivileged user to bypass resource limits
106+
#
107+
create user u1 with max_queries_per_hour 2;
108+
connect u1,localhost,u1;
109+
set session authorization u1@localhost;
110+
select 1;
111+
1
112+
1
113+
select 2;
114+
ERROR 42000: User 'u1' has exceeded the 'max_queries_per_hour' resource (current value: 2)
115+
disconnect u1;
116+
connection default;
117+
drop user u1;
118+
#
119+
# MDEV-36401 Access denied errors produced by SET SESSION AUTHORIZATION not reflected in status values
120+
#
121+
flush global status;
122+
set session authorization u1@localhost;
123+
ERROR HY000: The user 'u1'@'localhost' does not exist
124+
create user u1;
125+
connect u1,localhost,u1;
126+
set session authorization root@localhost;
127+
ERROR 28000: Access denied trying to change to user 'root'@'localhost'
128+
set session authorization foo@bar;
129+
ERROR 28000: Access denied trying to change to user 'foo'@'bar'
130+
disconnect u1;
131+
connection default;
132+
show global status like 'access_denied_errors';
133+
Variable_name Value
134+
Access_denied_errors 2
135+
drop user u1;
136+
# End of 11.8 tests
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
source include/not_embedded.inc;
2+
source include/no_protocol.inc;
3+
4+
--echo #
5+
--echo # MDEV-20299 SET SESSION AUTHORIZATION
6+
--echo #
7+
8+
# simple tests
9+
create user foo@bar identified via mysql_native_password using password('foo');
10+
connect con1, localhost, root;
11+
select user(), current_user(), database();
12+
# sudo, with SET USER privilege, nonexistent user
13+
--error ER_NO_SUCH_USER
14+
set session authorization bar@foo;
15+
select user(), current_user(), database();
16+
# sudo, with SET USER privilege
17+
set session authorization foo@bar;
18+
select user(), current_user(), database();
19+
set @a:='not changed';
20+
# sudo without SET USER privilege
21+
--error ER_ACCESS_DENIED_CHANGE_USER_ERROR
22+
set session authorization bar@foo;
23+
select @a;
24+
# to self, no privileges needed
25+
set session authorization foo@bar;
26+
select @a;
27+
disconnect con1;
28+
connection default;
29+
drop user foo@bar;
30+
31+
# user() != current_user() (w/ wildcards)
32+
create user ''@'l%t' identified via mysql_native_password using password('foo');
33+
connect con1, localhost, root;
34+
select user(), current_user(), database();
35+
# sudo, with SET USER privilege
36+
set session authorization fist@list;
37+
select user(), current_user(), database();
38+
set @a:='not changed';
39+
# sudo without SET USER privilege (note, same CURRENT_USER)
40+
--error ER_ACCESS_DENIED_CHANGE_USER_ERROR
41+
set session authorization first@last;
42+
select @a;
43+
# to self, no privileges needed
44+
set session authorization fist@list;
45+
select @a;
46+
disconnect con1;
47+
connection default;
48+
drop user ''@'l%t';
49+
50+
create user ''@'%' identified via mysql_native_password using password('foo');
51+
connect con1, localhost, root;
52+
select user(), current_user(), database();
53+
# empty username
54+
--error ER_NO_SUCH_USER
55+
set session authorization ''@last;
56+
# empty hostname
57+
--error ER_NO_SUCH_USER
58+
set session authorization foo@'';
59+
# in a transaction - an error
60+
start transaction;
61+
select user(), current_user(), database(), @@in_transaction;
62+
--error ER_CANT_SET_IN_TRANSACTION
63+
set session authorization foo@bar;
64+
select user(), current_user(), database(), @@in_transaction;
65+
disconnect con1;
66+
connection default;
67+
68+
# cannot be prepared
69+
--error ER_UNSUPPORTED_PS
70+
prepare s from 'set session authorization foo@bar';
71+
72+
# cannot be in a stored routine
73+
--error ER_SP_BADSTATEMENT
74+
create procedure sudo_foobar() set session authorization foo@bar;
75+
76+
create procedure sudo_foobar()
77+
execute immediate 'set session authorization foo@bar';
78+
--error ER_UNSUPPORTED_PS
79+
call sudo_foobar();
80+
drop procedure sudo_foobar;
81+
82+
drop user ''@'%';
83+
84+
# doesn't work if --skip-grant-tables
85+
--let $restart_parameters= --skip-grant-tables
86+
--source include/restart_mysqld.inc
87+
--error ER_OPTION_PREVENTS_STATEMENT
88+
set session authorization u@localhost;
89+
flush privileges;
90+
91+
# max_statement_time -> @@max_statement_time
92+
create user u1@localhost with max_statement_time 1;
93+
connect u1,localhost,u1;
94+
select @@max_statement_time;
95+
disconnect u1;
96+
connect u1,localhost,root;
97+
select @@max_statement_time;
98+
set session authorization u1@localhost;
99+
select @@max_statement_time;
100+
disconnect u1;
101+
connection default;
102+
drop user u1@localhost;
103+
104+
--echo #
105+
--echo # MDEV-36399 SET SESSION AUTHORIZATION allows an unrpivileged user to bypass resource limits
106+
--echo #
107+
108+
create user u1 with max_queries_per_hour 2;
109+
connect u1,localhost,u1;
110+
111+
set session authorization u1@localhost;
112+
select 1;
113+
--error ER_USER_LIMIT_REACHED
114+
select 2;
115+
disconnect u1;
116+
connection default;
117+
drop user u1;
118+
119+
--echo #
120+
--echo # MDEV-36401 Access denied errors produced by SET SESSION AUTHORIZATION not reflected in status values
121+
--echo #
122+
flush global status;
123+
124+
--error ER_NO_SUCH_USER
125+
set session authorization u1@localhost;
126+
127+
create user u1;
128+
129+
connect u1,localhost,u1;
130+
--error ER_ACCESS_DENIED_CHANGE_USER_ERROR
131+
set session authorization root@localhost;
132+
--error ER_ACCESS_DENIED_CHANGE_USER_ERROR
133+
set session authorization foo@bar;
134+
disconnect u1;
135+
connection default;
136+
show global status like 'access_denied_errors';
137+
drop user u1;
138+
139+
--echo # End of 11.8 tests

sql/lex.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ SYMBOL symbols[] = {
7676
{ "AT", SYM(AT_SYM)},
7777
{ "ATOMIC", SYM(ATOMIC_SYM)},
7878
{ "AUTHORS", SYM(AUTHORS_SYM)},
79+
{ "AUTHORIZATION", SYM(AUTHORIZATION_SYM)},
7980
{ "AUTO", SYM(AUTO_SYM)},
8081
{ "AUTO_INCREMENT", SYM(AUTO_INC)},
8182
{ "AVG", SYM(AVG_SYM)},

sql/privilege.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ constexpr privilege_t PRIV_DEFINER_CLAUSE= SET_USER_ACL;
332332
*/
333333
constexpr privilege_t PRIV_REVEAL_MISSING_DEFINER= SET_USER_ACL;
334334

335+
constexpr privilege_t PRIV_SUDO_CHANGE_USER= SET_USER_ACL;
336+
335337
/* Actions that require only the SUPER privilege */
336338
constexpr privilege_t PRIV_DES_DECRYPT_ONE_ARG= SUPER_ACL;
337339
constexpr privilege_t PRIV_LOG_BIN_TRUSTED_SP_CREATOR= SUPER_ACL;

sql/set_var.cc

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,39 @@ int set_var_password::update(THD *thd)
973973
#endif
974974
}
975975

976+
/*****************************************************************************
977+
Functions to handle SET SESSION AUTHORIZATION
978+
*****************************************************************************/
979+
980+
int set_var_authorization::check(THD *thd)
981+
{
982+
/*
983+
SET SESSION AUTHORIZATION cannot be combined with other variables,
984+
so most of the checks are only done in update.
985+
*/
986+
if (!thd->stmt_arena->is_conventional())
987+
my_error(ER_UNSUPPORTED_PS, MYF(0));
988+
else
989+
if (thd->in_active_multi_stmt_transaction())
990+
my_error(ER_CANT_SET_IN_TRANSACTION, MYF(0), "SESSION AUTHORIZATION");
991+
else
992+
return 0;
993+
994+
return 1;
995+
}
996+
997+
int set_var_authorization::update(THD *thd)
998+
{
999+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1000+
int res= acl_setauthorization(thd, user);
1001+
if (!res)
1002+
thd->session_tracker.state_change.mark_as_changed(thd);
1003+
return res;
1004+
#else
1005+
return 0;
1006+
#endif
1007+
}
1008+
9761009
/*****************************************************************************
9771010
Functions to handle SET ROLE
9781011
*****************************************************************************/

sql/set_var.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,17 @@ class set_var_password: public set_var_base
363363
int update(THD *thd) override;
364364
};
365365

366+
/* For SET SESSION AUTHORIZATION */
367+
368+
class set_var_authorization: public set_var_base
369+
{
370+
LEX_USER *user;
371+
public:
372+
set_var_authorization(LEX_USER *user_arg) : user(user_arg) {}
373+
int check(THD *thd) override;
374+
int update(THD *thd) override;
375+
};
376+
366377
/* For SET ROLE */
367378

368379
class set_var_role: public set_var_base

sql/share/errmsg-utf8.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10102,11 +10102,11 @@ ER_SLAVE_RLI_INIT_REPOSITORY
1010210102
sw "Mtumwa alishindwa kuanzisha muundo wa habari ya relay wa logi kutoka kwa hazina"
1010310103

1010410104
ER_ACCESS_DENIED_CHANGE_USER_ERROR 28000
10105-
bgn "Отказан достъп при опит за смяна към потребител %-.48s'@'%-.64s' (използвана парола: %s). Затваряне на връзката"
10106-
chi "访问拒绝尝试更改为用户'%-.48s'@'%-.64s'(使用密码:%s)。断开连接"
10107-
eng "Access denied trying to change to user '%-.48s'@'%-.64s' (using password: %s). Disconnecting"
10108-
spa "Acceso denegado intentando cambiar a usuario '%-.48s'@'%-.64s' (usando contraseña: %s). Desconectando"
10109-
sw "Ufikiaji umekataliwa kujaribu kubadilisha hadi mtumiaji '%-.48s'@'%-.64s' (kwa kutumia nenosiri: %s). Inatenganisha"
10105+
bgn "Отказан достъп при опит за смяна към потребител %-.48s'@'%-.64s'"
10106+
chi "访问拒绝尝试更改为用户'%-.48s'@'%-.64s'"
10107+
eng "Access denied trying to change to user '%-.48s'@'%-.64s'"
10108+
spa "Acceso denegado intentando cambiar a usuario '%-.48s'@'%-.64s'"
10109+
sw "Ufikiaji umekataliwa kujaribu kubadilisha hadi mtumiaji '%-.48s'@'%-.64s'"
1011010110

1011110111
ER_INNODB_READ_ONLY
1011210112
chi "innodb是只读模式"

0 commit comments

Comments
 (0)