Commit a175fc12 authored by unknown's avatar unknown

Fixed BUG#2777: Stored procedure doesn't observe definer's rights.

SQL SECURITY DEFINER must enforce reduced rights too, not just additional rights.


mysql-test/r/sp-security.result:
  Test case for BUG#2777: Make sure that SQL SECURITY DEFINER enforces reduced rights.
mysql-test/t/sp-security.test:
  Test case for BUG#2777: Make sure that SQL SECURITY DEFINER enforces reduced rights.
sql/sql_acl.cc:
  Clear rights before changing them in acl_getroot_no_password so that
  reduced rights work too, and take care of db acls as well.
parent f6b85330
use test;
grant usage on *.* to dummy@localhost;
grant usage on *.* to user1@localhost;
flush privileges;
drop database if exists db1_secret;
create database db1_secret;
use db1_secret;
......@@ -15,14 +16,14 @@ u i
root@localhost 1
call stamp(2);
select * from db1_secret.t1;
ERROR 42000: Access denied for user: 'dummy'@'localhost' to database 'db1_secret'
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret'
call stamp(3);
select * from db1_secret.t1;
ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
select * from t1;
u i
root@localhost 1
dummy@localhost 2
user1@localhost 2
anon@localhost 3
alter procedure stamp sql security invoker;
show procedure status like 'stamp';
......@@ -32,14 +33,50 @@ call stamp(4);
select * from t1;
u i
root@localhost 1
dummy@localhost 2
user1@localhost 2
anon@localhost 3
root@localhost 4
call stamp(5);
ERROR 42000: Access denied for user: 'dummy'@'localhost' to database 'db1_secret'
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret'
call stamp(6);
ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
drop database if exists db2;
create database db2;
use db2;
create table t2 (s1 int);
insert into t2 values (0);
grant usage on db2.* to user1@localhost;
grant select on db2.* to user1@localhost;
grant usage on db2.* to user2@localhost;
grant select,insert,update,delete on db2.* to user2@localhost;
flush privileges;
use db2;
create procedure p () insert into t2 values (1);
call p();
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db2'
use db2;
call p();
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db2'
select * from t2;
s1
0
create procedure q () insert into t2 values (2);
call q();
select * from t2;
s1
0
2
use db2;
call q();
select * from t2;
s1
0
2
2
drop procedure stamp;
drop procedure p;
drop procedure q;
use test;
drop database db1_secret;
delete from mysql.user where user='dummy';
drop database db2;
delete from mysql.user where user='user1' or user='user2';
......@@ -7,8 +7,9 @@ connect (con1root,localhost,root,,);
connection con1root;
use test;
# Create dummy user with no particular access rights
grant usage on *.* to dummy@localhost;
# Create user user1 with no particular access rights
grant usage on *.* to user1@localhost;
flush privileges;
--disable_warnings
drop database if exists db1_secret;
......@@ -30,13 +31,13 @@ show procedure status like 'stamp';
call stamp(1);
select * from t1;
connect (con2dummy,localhost,dummy,,);
connect (con2user1,localhost,user1,,);
connect (con3anon,localhost,anon,,);
#
# Dummy can
# User1 can
#
connection con2dummy;
connection con2user1;
# This should work...
call stamp(2);
......@@ -75,9 +76,9 @@ call stamp(4);
select * from t1;
#
# Dummy cannot
# User1 cannot
#
connection con2dummy;
connection con2user1;
# This should not work
--error 1044
......@@ -92,9 +93,65 @@ connection con3anon;
--error 1044
call stamp(6);
#
# BUG#2777
#
connection con1root;
--disable_warnings
drop database if exists db2;
--enable_warnings
create database db2;
use db2;
create table t2 (s1 int);
insert into t2 values (0);
grant usage on db2.* to user1@localhost;
grant select on db2.* to user1@localhost;
grant usage on db2.* to user2@localhost;
grant select,insert,update,delete on db2.* to user2@localhost;
flush privileges;
connection con2user1;
use db2;
create procedure p () insert into t2 values (1);
# Check that this doesn't work.
--error 1044
call p();
connect (con4user2,localhost,user2,,);
connection con4user2;
use db2;
# This should not work, since p is executed with definer's (user1's) rights.
--error 1044
call p();
select * from t2;
create procedure q () insert into t2 values (2);
call q();
select * from t2;
connection con2user1;
use db2;
# This should work
call q();
select * from t2;
# Clean up
connection con1root;
drop procedure stamp;
drop procedure p;
drop procedure q;
use test;
drop database db1_secret;
delete from mysql.user where user='dummy';
drop database db2;
delete from mysql.user where user='user1' or user='user2';
......@@ -794,6 +794,7 @@ int acl_getroot_no_password(THD *thd)
{
ulong user_access= NO_ACCESS;
int res= 1;
uint i;
ACL_USER *acl_user= 0;
DBUG_ENTER("acl_getroot_no_password");
......@@ -810,13 +811,16 @@ int acl_getroot_no_password(THD *thd)
VOID(pthread_mutex_lock(&acl_cache->lock));
thd->master_access= 0;
thd->db_access= 0;
/*
Find acl entry in user database.
This is specially tailored to suit the check we do for CALL of
a stored procedure; thd->user is set to what is actually a
priv_user, which can be ''.
*/
for (uint i=0 ; i < acl_users.elements ; i++)
for (i=0 ; i < acl_users.elements ; i++)
{
acl_user= dynamic_element(&acl_users,i,ACL_USER*);
if ((!acl_user->user && (!thd->user || !thd->user[0])) ||
......@@ -832,6 +836,22 @@ int acl_getroot_no_password(THD *thd)
if (acl_user)
{
for (i=0 ; i < acl_dbs.elements ; i++)
{
ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
if (!acl_db->user ||
(thd->user && thd->user[0] && !strcmp(thd->user, acl_db->user)))
{
if (compare_hostname(&acl_db->host, thd->host, thd->ip))
{
if (!acl_db->db || (thd->db && !strcmp(acl_db->db, thd->db)))
{
thd->db_access= acl_db->access;
break;
}
}
}
}
thd->master_access= acl_user->access;
thd->priv_user= acl_user->user ? thd->user : (char *) "";
......
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