mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Fix for BUG#9504: Stored procedures: execute privilege doesn't
make 'use database' okay. The problem was that we didn't check stored-routine privileges in check_grant_db(). The patch adds this check. mysql-test/r/grant.result: Update result file. mysql-test/r/sp-security.result: Update result fil. mysql-test/t/grant.test: Added test case for BUG#9504. mysql-test/t/sp-security.test: Update test. sql/sql_acl.cc: Check stored routines privileges.
This commit is contained in:
@ -972,4 +972,51 @@ REVOKE EXECUTE ON PROCEDURE t1 FROM some_user_name@1234567890abcdefghij123456789
|
||||
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
|
||||
GRANT PROCESS ON * TO user@localhost;
|
||||
ERROR 3D000: No database selected
|
||||
DROP DATABASE IF EXISTS mysqltest1;
|
||||
DROP DATABASE IF EXISTS mysqltest2;
|
||||
DROP DATABASE IF EXISTS mysqltest3;
|
||||
DROP DATABASE IF EXISTS mysqltest4;
|
||||
CREATE DATABASE mysqltest1;
|
||||
CREATE DATABASE mysqltest2;
|
||||
CREATE DATABASE mysqltest3;
|
||||
CREATE DATABASE mysqltest4;
|
||||
CREATE PROCEDURE mysqltest1.p_def() SQL SECURITY DEFINER
|
||||
SELECT 1;
|
||||
CREATE PROCEDURE mysqltest2.p_inv() SQL SECURITY INVOKER
|
||||
SELECT 1;
|
||||
CREATE FUNCTION mysqltest3.f_def() RETURNS INT SQL SECURITY DEFINER
|
||||
RETURN 1;
|
||||
CREATE FUNCTION mysqltest4.f_inv() RETURNS INT SQL SECURITY INVOKER
|
||||
RETURN 1;
|
||||
GRANT EXECUTE ON PROCEDURE mysqltest1.p_def TO mysqltest_1@localhost;
|
||||
GRANT EXECUTE ON PROCEDURE mysqltest2.p_inv TO mysqltest_1@localhost;
|
||||
GRANT EXECUTE ON FUNCTION mysqltest3.f_def TO mysqltest_1@localhost;
|
||||
GRANT EXECUTE ON FUNCTION mysqltest4.f_inv TO mysqltest_1@localhost;
|
||||
GRANT ALL PRIVILEGES ON test.* TO mysqltest_1@localhost;
|
||||
|
||||
---> connection: bug9504_con1
|
||||
use mysqltest1;
|
||||
use mysqltest2;
|
||||
use mysqltest3;
|
||||
use mysqltest4;
|
||||
use test;
|
||||
CALL mysqltest1.p_def();
|
||||
1
|
||||
1
|
||||
CALL mysqltest2.p_inv();
|
||||
1
|
||||
1
|
||||
SELECT mysqltest3.f_def();
|
||||
mysqltest3.f_def()
|
||||
1
|
||||
SELECT mysqltest4.f_inv();
|
||||
mysqltest4.f_inv()
|
||||
1
|
||||
|
||||
---> connection: default
|
||||
DROP DATABASE mysqltest1;
|
||||
DROP DATABASE mysqltest2;
|
||||
DROP DATABASE mysqltest3;
|
||||
DROP DATABASE mysqltest4;
|
||||
DROP USER mysqltest_1@localhost;
|
||||
End of 5.0 tests
|
||||
|
@ -8,22 +8,29 @@ create procedure db1_secret.dummy() begin end;
|
||||
drop procedure db1_secret.dummy;
|
||||
use db1_secret;
|
||||
create table t1 ( u varchar(64), i int );
|
||||
insert into t1 values('test', 0);
|
||||
create procedure stamp(i int)
|
||||
insert into db1_secret.t1 values (user(), i);
|
||||
show procedure status like 'stamp';
|
||||
Db Name Type Definer Modified Created Security_type Comment
|
||||
db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||
create function db() returns varchar(64) return database();
|
||||
create function db() returns varchar(64)
|
||||
begin
|
||||
declare v varchar(64);
|
||||
select u into v from t1 limit 1;
|
||||
return v;
|
||||
end|
|
||||
show function status like 'db';
|
||||
Db Name Type Definer Modified Created Security_type Comment
|
||||
db1_secret db FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||
call stamp(1);
|
||||
select * from t1;
|
||||
u i
|
||||
test 0
|
||||
root@localhost 1
|
||||
select db();
|
||||
db()
|
||||
db1_secret
|
||||
test
|
||||
grant execute on procedure db1_secret.stamp to user1@'%';
|
||||
grant execute on function db1_secret.db to user1@'%';
|
||||
grant execute on procedure db1_secret.stamp to ''@'%';
|
||||
@ -31,25 +38,34 @@ grant execute on function db1_secret.db to ''@'%';
|
||||
call db1_secret.stamp(2);
|
||||
select db1_secret.db();
|
||||
db1_secret.db()
|
||||
db1_secret
|
||||
test
|
||||
select * from db1_secret.t1;
|
||||
ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
|
||||
create procedure db1_secret.dummy() begin end;
|
||||
ERROR 42000: Access denied for user 'user1'@'localhost' to database 'db1_secret'
|
||||
drop procedure db1_secret.dummy;
|
||||
ERROR 42000: PROCEDURE db1_secret.dummy does not exist
|
||||
drop procedure db1_secret.stamp;
|
||||
ERROR 42000: alter routine command denied to user 'user1'@'localhost' for routine 'db1_secret.stamp'
|
||||
drop function db1_secret.db;
|
||||
ERROR 42000: alter routine command denied to user 'user1'@'localhost' for routine 'db1_secret.db'
|
||||
call db1_secret.stamp(3);
|
||||
select db1_secret.db();
|
||||
db1_secret.db()
|
||||
db1_secret
|
||||
test
|
||||
select * from db1_secret.t1;
|
||||
ERROR 42000: SELECT command denied to user ''@'localhost' for table 't1'
|
||||
create procedure db1_secret.dummy() begin end;
|
||||
ERROR 42000: Access denied for user ''@'%' to database 'db1_secret'
|
||||
drop procedure db1_secret.dummy;
|
||||
ERROR 42000: PROCEDURE db1_secret.dummy does not exist
|
||||
drop procedure db1_secret.stamp;
|
||||
ERROR 42000: alter routine command denied to user ''@'%' for routine 'db1_secret.stamp'
|
||||
drop function db1_secret.db;
|
||||
ERROR 42000: alter routine command denied to user ''@'%' for routine 'db1_secret.db'
|
||||
select * from t1;
|
||||
u i
|
||||
test 0
|
||||
root@localhost 1
|
||||
user1@localhost 2
|
||||
anon@localhost 3
|
||||
@ -64,21 +80,22 @@ db1_secret db FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 IN
|
||||
call stamp(4);
|
||||
select * from t1;
|
||||
u i
|
||||
test 0
|
||||
root@localhost 1
|
||||
user1@localhost 2
|
||||
anon@localhost 3
|
||||
root@localhost 4
|
||||
select db();
|
||||
db()
|
||||
db1_secret
|
||||
test
|
||||
call db1_secret.stamp(5);
|
||||
ERROR 42000: Access denied for user 'user1'@'localhost' to database 'db1_secret'
|
||||
ERROR 42000: INSERT command denied to user 'user1'@'localhost' for table 't1'
|
||||
select db1_secret.db();
|
||||
ERROR 42000: Access denied for user 'user1'@'localhost' to database 'db1_secret'
|
||||
ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
|
||||
call db1_secret.stamp(6);
|
||||
ERROR 42000: Access denied for user ''@'%' to database 'db1_secret'
|
||||
ERROR 42000: INSERT command denied to user ''@'localhost' for table 't1'
|
||||
select db1_secret.db();
|
||||
ERROR 42000: Access denied for user ''@'%' to database 'db1_secret'
|
||||
ERROR 42000: SELECT command denied to user ''@'localhost' for table 't1'
|
||||
drop database if exists db2;
|
||||
create database db2;
|
||||
use db2;
|
||||
|
@ -875,4 +875,87 @@ GRANT PROCESS ON * TO user@localhost;
|
||||
disconnect con1;
|
||||
connection default;
|
||||
|
||||
|
||||
#
|
||||
# BUG#9504: Stored procedures: execute privilege doesn't make 'use database'
|
||||
# okay.
|
||||
#
|
||||
|
||||
# Prepare.
|
||||
|
||||
--disable_warnings
|
||||
DROP DATABASE IF EXISTS mysqltest1;
|
||||
DROP DATABASE IF EXISTS mysqltest2;
|
||||
DROP DATABASE IF EXISTS mysqltest3;
|
||||
DROP DATABASE IF EXISTS mysqltest4;
|
||||
--enable_warnings
|
||||
|
||||
CREATE DATABASE mysqltest1;
|
||||
CREATE DATABASE mysqltest2;
|
||||
CREATE DATABASE mysqltest3;
|
||||
CREATE DATABASE mysqltest4;
|
||||
|
||||
CREATE PROCEDURE mysqltest1.p_def() SQL SECURITY DEFINER
|
||||
SELECT 1;
|
||||
|
||||
CREATE PROCEDURE mysqltest2.p_inv() SQL SECURITY INVOKER
|
||||
SELECT 1;
|
||||
|
||||
CREATE FUNCTION mysqltest3.f_def() RETURNS INT SQL SECURITY DEFINER
|
||||
RETURN 1;
|
||||
|
||||
CREATE FUNCTION mysqltest4.f_inv() RETURNS INT SQL SECURITY INVOKER
|
||||
RETURN 1;
|
||||
|
||||
GRANT EXECUTE ON PROCEDURE mysqltest1.p_def TO mysqltest_1@localhost;
|
||||
GRANT EXECUTE ON PROCEDURE mysqltest2.p_inv TO mysqltest_1@localhost;
|
||||
GRANT EXECUTE ON FUNCTION mysqltest3.f_def TO mysqltest_1@localhost;
|
||||
GRANT EXECUTE ON FUNCTION mysqltest4.f_inv TO mysqltest_1@localhost;
|
||||
|
||||
GRANT ALL PRIVILEGES ON test.* TO mysqltest_1@localhost;
|
||||
|
||||
# Test.
|
||||
|
||||
--connect (bug9504_con1,localhost,mysqltest_1,,)
|
||||
--echo
|
||||
--echo ---> connection: bug9504_con1
|
||||
|
||||
# - Check that we can switch to the db;
|
||||
|
||||
use mysqltest1;
|
||||
|
||||
use mysqltest2;
|
||||
|
||||
use mysqltest3;
|
||||
|
||||
use mysqltest4;
|
||||
|
||||
# - Check that we can call stored routines;
|
||||
|
||||
use test;
|
||||
|
||||
CALL mysqltest1.p_def();
|
||||
|
||||
CALL mysqltest2.p_inv();
|
||||
|
||||
SELECT mysqltest3.f_def();
|
||||
|
||||
SELECT mysqltest4.f_inv();
|
||||
|
||||
# Cleanup.
|
||||
|
||||
--connection default
|
||||
--echo
|
||||
--echo ---> connection: default
|
||||
|
||||
--disconnect bug9504_con1
|
||||
|
||||
DROP DATABASE mysqltest1;
|
||||
DROP DATABASE mysqltest2;
|
||||
DROP DATABASE mysqltest3;
|
||||
DROP DATABASE mysqltest4;
|
||||
|
||||
DROP USER mysqltest_1@localhost;
|
||||
|
||||
|
||||
--echo End of 5.0 tests
|
||||
|
@ -28,6 +28,7 @@ drop procedure db1_secret.dummy;
|
||||
use db1_secret;
|
||||
|
||||
create table t1 ( u varchar(64), i int );
|
||||
insert into t1 values('test', 0);
|
||||
|
||||
# A test procedure and function
|
||||
create procedure stamp(i int)
|
||||
@ -35,7 +36,16 @@ create procedure stamp(i int)
|
||||
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
|
||||
show procedure status like 'stamp';
|
||||
|
||||
create function db() returns varchar(64) return database();
|
||||
delimiter |;
|
||||
create function db() returns varchar(64)
|
||||
begin
|
||||
declare v varchar(64);
|
||||
|
||||
select u into v from t1 limit 1;
|
||||
|
||||
return v;
|
||||
end|
|
||||
delimiter ;|
|
||||
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
|
||||
show function status like 'db';
|
||||
|
||||
@ -63,14 +73,18 @@ call db1_secret.stamp(2);
|
||||
select db1_secret.db();
|
||||
|
||||
# ...but not this
|
||||
--error 1142
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
select * from db1_secret.t1;
|
||||
|
||||
# ...and not this
|
||||
--error 1044
|
||||
--error ER_DBACCESS_DENIED_ERROR
|
||||
create procedure db1_secret.dummy() begin end;
|
||||
--error 1305
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
drop procedure db1_secret.dummy;
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
drop procedure db1_secret.stamp;
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
drop function db1_secret.db;
|
||||
|
||||
|
||||
#
|
||||
@ -83,14 +97,18 @@ call db1_secret.stamp(3);
|
||||
select db1_secret.db();
|
||||
|
||||
# ...but not this
|
||||
--error 1142
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
select * from db1_secret.t1;
|
||||
|
||||
# ...and not this
|
||||
--error 1044
|
||||
--error ER_DBACCESS_DENIED_ERROR
|
||||
create procedure db1_secret.dummy() begin end;
|
||||
--error 1305
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
drop procedure db1_secret.dummy;
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
drop procedure db1_secret.stamp;
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
drop function db1_secret.db;
|
||||
|
||||
|
||||
#
|
||||
@ -121,9 +139,9 @@ select db();
|
||||
connection con2user1;
|
||||
|
||||
# This should not work
|
||||
--error 1044
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
call db1_secret.stamp(5);
|
||||
--error 1044
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
select db1_secret.db();
|
||||
|
||||
#
|
||||
@ -132,9 +150,9 @@ select db1_secret.db();
|
||||
connection con3anon;
|
||||
|
||||
# This should not work
|
||||
--error 1044
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
call db1_secret.stamp(6);
|
||||
--error 1044
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
select db1_secret.db();
|
||||
|
||||
#
|
||||
@ -165,7 +183,7 @@ use db2;
|
||||
create procedure p () insert into t2 values (1);
|
||||
|
||||
# Check that this doesn't work.
|
||||
--error 1142
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
call p();
|
||||
|
||||
connect (con4user2,localhost,user2,,);
|
||||
@ -174,7 +192,7 @@ connection con4user2;
|
||||
use db2;
|
||||
|
||||
# This should not work, since p is executed with definer's (user1's) rights.
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
call p();
|
||||
select * from t2;
|
||||
|
||||
@ -207,9 +225,9 @@ alter procedure p modifies sql data;
|
||||
drop procedure p;
|
||||
|
||||
# This should NOT work
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
alter procedure q modifies sql data;
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
drop procedure q;
|
||||
|
||||
connection con1root;
|
||||
@ -260,30 +278,30 @@ connect (con4userc,localhost,userc,,);
|
||||
|
||||
connection con2usera;
|
||||
call sptest.p1(1);
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
grant execute on procedure sptest.p1 to userb@localhost;
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
drop procedure sptest.p1;
|
||||
|
||||
connection con3userb;
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
call sptest.p1(2);
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
grant execute on procedure sptest.p1 to userb@localhost;
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
drop procedure sptest.p1;
|
||||
|
||||
connection con4userc;
|
||||
call sptest.p1(3);
|
||||
grant execute on procedure sptest.p1 to userb@localhost;
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
drop procedure sptest.p1;
|
||||
|
||||
connection con3userb;
|
||||
call sptest.p1(4);
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
grant execute on procedure sptest.p1 to userb@localhost;
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
drop procedure sptest.p1;
|
||||
|
||||
connection con1root;
|
||||
@ -332,7 +350,7 @@ delimiter ;//
|
||||
connect (user1,localhost,user1,,test);
|
||||
connection user1;
|
||||
use mysqltest;
|
||||
-- error 1370
|
||||
-- error ER_PROCACCESS_DENIED_ERROR
|
||||
select bug_9503();
|
||||
|
||||
connection root;
|
||||
@ -401,13 +419,13 @@ grant usage on *.* to mysqltest_1@localhost;
|
||||
|
||||
connect (n1,localhost,mysqltest_1,,information_schema,$MASTER_MYPORT,$MASTER_MYSOCK);
|
||||
connection n1;
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
call mysqltest_1.p1();
|
||||
disconnect n1;
|
||||
# Test also without a current database
|
||||
connect (n2,localhost,mysqltest_1,,*NO-ONE*,$MASTER_MYPORT,$MASTER_MYSOCK);
|
||||
connection n2;
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
call mysqltest_1.p1();
|
||||
disconnect n2;
|
||||
|
||||
@ -433,9 +451,9 @@ end;
|
||||
create user user_bug12812@localhost IDENTIFIED BY 'ABC'|
|
||||
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
|
||||
connect (test_user_12812,localhost,user_bug12812,ABC,test)|
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
SELECT test.bug12812()|
|
||||
--error 1370
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
CREATE VIEW v1 AS SELECT test.bug12812()|
|
||||
# Cleanup
|
||||
connection default|
|
||||
@ -489,7 +507,8 @@ drop database db_bug14834;
|
||||
|
||||
|
||||
#
|
||||
# BUG#14533: 'desc tbl' in stored procedure causes error 1142
|
||||
# BUG#14533: 'desc tbl' in stored procedure causes error
|
||||
# ER_TABLEACCESS_DENIED_ERROR
|
||||
#
|
||||
create database db_bug14533;
|
||||
use db_bug14533;
|
||||
|
@ -3893,6 +3893,26 @@ err2:
|
||||
}
|
||||
|
||||
|
||||
static bool check_grant_db_routine(THD *thd, const char *db, HASH *hash)
|
||||
{
|
||||
Security_context *sctx= thd->security_ctx;
|
||||
|
||||
for (uint idx= 0; idx < hash->records; ++idx)
|
||||
{
|
||||
GRANT_NAME *item= (GRANT_NAME*) hash_element(hash, idx);
|
||||
|
||||
if (strcmp(item->user, sctx->priv_user) == 0 &&
|
||||
strcmp(item->db, db) == 0 &&
|
||||
compare_hostname(&item->host, sctx->host, sctx->ip))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Check if a user has the right to access a database
|
||||
Access is accepted if he has a grant for any table/routine in the database
|
||||
@ -3904,9 +3924,10 @@ bool check_grant_db(THD *thd,const char *db)
|
||||
Security_context *sctx= thd->security_ctx;
|
||||
char helping [NAME_LEN+USERNAME_LENGTH+2];
|
||||
uint len;
|
||||
bool error= 1;
|
||||
bool error= TRUE;
|
||||
|
||||
len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1;
|
||||
|
||||
rw_rdlock(&LOCK_grant);
|
||||
|
||||
for (uint idx=0 ; idx < column_priv_hash.records ; idx++)
|
||||
@ -3917,11 +3938,17 @@ bool check_grant_db(THD *thd,const char *db)
|
||||
!memcmp(grant_table->hash_key,helping,len) &&
|
||||
compare_hostname(&grant_table->host, sctx->host, sctx->ip))
|
||||
{
|
||||
error=0; // Found match
|
||||
error= FALSE; /* Found match. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (error)
|
||||
error= check_grant_db_routine(thd, db, &proc_priv_hash) &&
|
||||
check_grant_db_routine(thd, db, &func_priv_hash);
|
||||
|
||||
rw_unlock(&LOCK_grant);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user