mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
WL#1365: Implement definer's rights execution of stored procedures.
(Also put the hostpart back in the definer column.) mysql-test/r/sp-error.result: Moved error test from sp.test mysql-test/r/sp.result: Moved error test to sp-error.test. Put hostpart back into definer column in mysql.proc. mysql-test/t/sp-error.test: Moved error test from sp.test mysql-test/t/sp.test: Moved error test to sp-error.test. Put hostpart back into definer column in mysql.proc. sql/item_func.cc: (Maybe) switch security context before invoking a stored function. sql/sp.cc: Renamed creator into definer, for more consistent terminology, and put the hostpart back. sql/sp_head.cc: Some fixes in the way things are allocated, and moved set_info() definition here from sp_head.h. creator is now called definer, and is split into a user and host part. Added functions for (possible) change and restore of privileges, for sql security definer calls. sql/sp_head.h: Moved set_info() definition here from sp_head.h. creator is now called definer, and is split into a user and host part. Added functions for (possible) change and restore of privileges, for sql security definer calls. sql/sql_acl.cc: New function acl_getroot_no_password() for getting the privileges used when calling an SP with sql security definer. sql/sql_acl.h: New function acl_getroot_no_password() for getting the privileges used when calling an SP with sql security definer. sql/sql_parse.cc: (Maybe) switch security context before invoking a stored procedure. sql/sql_yacc.yy: Fixed typo.
This commit is contained in:
@ -280,4 +280,15 @@ create function bug1654()
|
|||||||
returns int
|
returns int
|
||||||
return (select sum(t.data) from test.t2 t);
|
return (select sum(t.data) from test.t2 t);
|
||||||
ERROR 0A000: Statements like SELECT, INSERT, UPDATE (and others) are not allowed in a FUNCTION
|
ERROR 0A000: Statements like SELECT, INSERT, UPDATE (and others) are not allowed in a FUNCTION
|
||||||
|
drop table if exists table_1;
|
||||||
|
create table t3 (column_1_0 int);
|
||||||
|
create procedure bug1653()
|
||||||
|
update t3 set column_1 = 0;
|
||||||
|
call bug1653();
|
||||||
|
ERROR 42S22: Unknown column 'column_1' in 'field list'
|
||||||
|
drop table t3;
|
||||||
|
create table t3 (column_1 int);
|
||||||
|
call bug1653();
|
||||||
|
drop procedure bug1653;
|
||||||
|
drop table t3;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
44
mysql-test/r/sp-security.result
Normal file
44
mysql-test/r/sp-security.result
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
use test;
|
||||||
|
grant usage on *.* to dummy@localhost;
|
||||||
|
drop database if exists db1_secret;
|
||||||
|
create database db1_secret;
|
||||||
|
use db1_secret;
|
||||||
|
create table t1 ( u varchar(64), i int );
|
||||||
|
create procedure stamp(i int)
|
||||||
|
insert into db1_secret.t1 values (user(), i);
|
||||||
|
show procedure status like 'stamp';
|
||||||
|
Name Type Definer Modified Created Security_type Comment
|
||||||
|
stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||||
|
call stamp(1);
|
||||||
|
select * from t1;
|
||||||
|
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'
|
||||||
|
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
|
||||||
|
anon@localhost 3
|
||||||
|
alter procedure stamp sql security invoker;
|
||||||
|
show procedure status like 'stamp';
|
||||||
|
Name Type Definer Modified Created Security_type Comment
|
||||||
|
stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER
|
||||||
|
call stamp(4);
|
||||||
|
select * from t1;
|
||||||
|
u i
|
||||||
|
root@localhost 1
|
||||||
|
dummy@localhost 2
|
||||||
|
anon@localhost 3
|
||||||
|
root@localhost 4
|
||||||
|
call stamp(5);
|
||||||
|
ERROR 42000: Access denied for user: 'dummy'@'localhost' to database 'db1_secret'
|
||||||
|
call stamp(6);
|
||||||
|
ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
|
||||||
|
use test;
|
||||||
|
drop database db1_secret;
|
||||||
|
delete from mysql.user where user='dummy';
|
@ -866,17 +866,6 @@ avg 0 4.4
|
|||||||
delete from t1;
|
delete from t1;
|
||||||
delete from t2;
|
delete from t2;
|
||||||
drop procedure bug1874;
|
drop procedure bug1874;
|
||||||
drop table if exists table_1;
|
|
||||||
create table t3 (column_1_0 int);
|
|
||||||
create procedure bug1653()
|
|
||||||
update t3 set column_1 = 0;
|
|
||||||
call bug1653();
|
|
||||||
ERROR 42S22: Unknown column 'column_1' in 'field list'
|
|
||||||
drop table t3;
|
|
||||||
create table t3 (column_1 int);
|
|
||||||
call bug1653();
|
|
||||||
drop procedure bug1653;
|
|
||||||
drop table t3;
|
|
||||||
drop table if exists fac;
|
drop table if exists fac;
|
||||||
create table fac (n int unsigned not null primary key, f bigint unsigned);
|
create table fac (n int unsigned not null primary key, f bigint unsigned);
|
||||||
create procedure ifac(n int unsigned)
|
create procedure ifac(n int unsigned)
|
||||||
@ -918,7 +907,7 @@ n f
|
|||||||
drop table fac;
|
drop table fac;
|
||||||
show function status like '%f%';
|
show function status like '%f%';
|
||||||
Name Type Definer Modified Created Security_type Comment
|
Name Type Definer Modified Created Security_type Comment
|
||||||
fac FUNCTION root 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||||
drop procedure ifac;
|
drop procedure ifac;
|
||||||
drop function fac;
|
drop function fac;
|
||||||
show function status like '%f%';
|
show function status like '%f%';
|
||||||
@ -1011,8 +1000,8 @@ end loop;
|
|||||||
end
|
end
|
||||||
show procedure status like '%p%';
|
show procedure status like '%p%';
|
||||||
Name Type Definer Modified Created Security_type Comment
|
Name Type Definer Modified Created Security_type Comment
|
||||||
ip PROCEDURE root 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
ip PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||||
opp PROCEDURE root 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
opp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||||
call ip(200);
|
call ip(200);
|
||||||
select * from primes where i=45 or i=100 or i=199;
|
select * from primes where i=45 or i=100 or i=199;
|
||||||
i p
|
i p
|
||||||
@ -1074,7 +1063,7 @@ comment "111111111111" sql security invoker
|
|||||||
insert into test.t1 values (x, y);
|
insert into test.t1 values (x, y);
|
||||||
show procedure status like 'bar';
|
show procedure status like 'bar';
|
||||||
Name Type Definer Modified Created Security_type Comment
|
Name Type Definer Modified Created Security_type Comment
|
||||||
bar PROCEDURE root 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER 111111111111
|
bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER 111111111111
|
||||||
alter procedure bar name bar2 comment "2222222222" sql security definer;
|
alter procedure bar name bar2 comment "2222222222" sql security definer;
|
||||||
alter procedure bar2 name bar comment "3333333333";
|
alter procedure bar2 name bar comment "3333333333";
|
||||||
alter procedure bar;
|
alter procedure bar;
|
||||||
@ -1085,7 +1074,7 @@ bar CREATE PROCEDURE bar(x char(16), y int)
|
|||||||
insert into test.t1 values (x, y)
|
insert into test.t1 values (x, y)
|
||||||
show procedure status like 'bar';
|
show procedure status like 'bar';
|
||||||
Name Type Definer Modified Created Security_type Comment
|
Name Type Definer Modified Created Security_type Comment
|
||||||
bar PROCEDURE root 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER 3333333333
|
bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER 3333333333
|
||||||
drop procedure bar;
|
drop procedure bar;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
drop table t2;
|
drop table t2;
|
||||||
|
@ -379,6 +379,27 @@ create function bug1654()
|
|||||||
returns int
|
returns int
|
||||||
return (select sum(t.data) from test.t2 t)|
|
return (select sum(t.data) from test.t2 t)|
|
||||||
|
|
||||||
|
#
|
||||||
|
# BUG#1653
|
||||||
|
#
|
||||||
|
--disable_warnings
|
||||||
|
drop table if exists table_1|
|
||||||
|
--enable_warnings
|
||||||
|
create table t3 (column_1_0 int)|
|
||||||
|
|
||||||
|
create procedure bug1653()
|
||||||
|
update t3 set column_1 = 0|
|
||||||
|
|
||||||
|
--error 1054
|
||||||
|
call bug1653()|
|
||||||
|
drop table t3|
|
||||||
|
create table t3 (column_1 int)|
|
||||||
|
call bug1653()|
|
||||||
|
|
||||||
|
drop procedure bug1653|
|
||||||
|
drop table t3|
|
||||||
|
|
||||||
|
|
||||||
drop table t1|
|
drop table t1|
|
||||||
|
|
||||||
delimiter ;|
|
delimiter ;|
|
||||||
|
99
mysql-test/t/sp-security.test
Normal file
99
mysql-test/t/sp-security.test
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#
|
||||||
|
# Testing SQL SECURITY of stored procedures
|
||||||
|
#
|
||||||
|
|
||||||
|
connect (con1root,localhost,root,,);
|
||||||
|
|
||||||
|
connection con1root;
|
||||||
|
use test;
|
||||||
|
|
||||||
|
# Create dummy user with no particular access rights
|
||||||
|
grant usage on *.* to dummy@localhost;
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
drop database if exists db1_secret;
|
||||||
|
--enable_warnings
|
||||||
|
# Create our secret database
|
||||||
|
create database db1_secret;
|
||||||
|
|
||||||
|
use db1_secret;
|
||||||
|
|
||||||
|
create table t1 ( u varchar(64), i int );
|
||||||
|
|
||||||
|
# Our test procedure
|
||||||
|
create procedure stamp(i int)
|
||||||
|
insert into db1_secret.t1 values (user(), i);
|
||||||
|
--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00'
|
||||||
|
show procedure status like 'stamp';
|
||||||
|
|
||||||
|
# root can, of course
|
||||||
|
call stamp(1);
|
||||||
|
select * from t1;
|
||||||
|
|
||||||
|
connect (con2dummy,localhost,dummy,,);
|
||||||
|
connect (con3anon,localhost,anon,,);
|
||||||
|
|
||||||
|
#
|
||||||
|
# Dummy can
|
||||||
|
#
|
||||||
|
connection con2dummy;
|
||||||
|
|
||||||
|
# This should work...
|
||||||
|
call stamp(2);
|
||||||
|
|
||||||
|
# ...but not this
|
||||||
|
--error 1044
|
||||||
|
select * from db1_secret.t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Anonymous can
|
||||||
|
#
|
||||||
|
connection con3anon;
|
||||||
|
|
||||||
|
# This should work...
|
||||||
|
call stamp(3);
|
||||||
|
|
||||||
|
# ...but not this
|
||||||
|
--error 1044
|
||||||
|
select * from db1_secret.t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check it out
|
||||||
|
#
|
||||||
|
connection con1root;
|
||||||
|
select * from t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Change to invoker's rights
|
||||||
|
#
|
||||||
|
alter procedure stamp sql security invoker;
|
||||||
|
--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00'
|
||||||
|
show procedure status like 'stamp';
|
||||||
|
|
||||||
|
# root still can
|
||||||
|
call stamp(4);
|
||||||
|
select * from t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Dummy cannot
|
||||||
|
#
|
||||||
|
connection con2dummy;
|
||||||
|
|
||||||
|
# This should not work
|
||||||
|
--error 1044
|
||||||
|
call stamp(5);
|
||||||
|
|
||||||
|
#
|
||||||
|
# Anonymous cannot
|
||||||
|
#
|
||||||
|
connection con3anon;
|
||||||
|
|
||||||
|
# This should not work
|
||||||
|
--error 1044
|
||||||
|
call stamp(6);
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
connection con1root;
|
||||||
|
use test;
|
||||||
|
drop database db1_secret;
|
||||||
|
delete from mysql.user where user='dummy';
|
@ -1013,26 +1013,6 @@ delete from t1|
|
|||||||
delete from t2|
|
delete from t2|
|
||||||
drop procedure bug1874|
|
drop procedure bug1874|
|
||||||
|
|
||||||
#
|
|
||||||
# BUG#1653
|
|
||||||
#
|
|
||||||
--disable_warnings
|
|
||||||
drop table if exists table_1|
|
|
||||||
--enable_warnings
|
|
||||||
create table t3 (column_1_0 int)|
|
|
||||||
|
|
||||||
create procedure bug1653()
|
|
||||||
update t3 set column_1 = 0|
|
|
||||||
|
|
||||||
--error 1054
|
|
||||||
call bug1653()|
|
|
||||||
drop table t3|
|
|
||||||
create table t3 (column_1 int)|
|
|
||||||
call bug1653()|
|
|
||||||
|
|
||||||
drop procedure bug1653|
|
|
||||||
drop table t3|
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Some "real" examples
|
# Some "real" examples
|
||||||
|
@ -3069,13 +3069,21 @@ Item_func_sp::execute(Item **itp)
|
|||||||
{
|
{
|
||||||
DBUG_ENTER("Item_func_sp::execute");
|
DBUG_ENTER("Item_func_sp::execute");
|
||||||
THD *thd= current_thd;
|
THD *thd= current_thd;
|
||||||
|
st_sp_security_context save_ctx;
|
||||||
|
int res;
|
||||||
|
|
||||||
if (! m_sp)
|
if (! m_sp)
|
||||||
m_sp= sp_find_function(thd, &m_name);
|
m_sp= sp_find_function(thd, &m_name);
|
||||||
if (! m_sp)
|
if (! m_sp)
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
DBUG_RETURN(m_sp->execute_function(thd, args, arg_count, itp));
|
sp_change_security_context(thd, m_sp, &save_ctx);
|
||||||
|
|
||||||
|
res= m_sp->execute_function(thd, args, arg_count, itp);
|
||||||
|
|
||||||
|
sp_restore_security_context(thd, m_sp, &save_ctx);
|
||||||
|
|
||||||
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum enum_field_types
|
enum enum_field_types
|
||||||
|
28
sql/sp.cc
28
sql/sp.cc
@ -121,10 +121,10 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
|
|||||||
const char *params, *returns, *body;
|
const char *params, *returns, *body;
|
||||||
int ret;
|
int ret;
|
||||||
bool opened;
|
bool opened;
|
||||||
const char *creator;
|
const char *definer;
|
||||||
longlong created;
|
longlong created;
|
||||||
longlong modified;
|
longlong modified;
|
||||||
st_sp_chistics *chistics;
|
st_sp_chistics chistics;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
uint length;
|
uint length;
|
||||||
char buff[65];
|
char buff[65];
|
||||||
@ -147,8 +147,8 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
|
|||||||
ret= SP_GET_FIELD_FAILED;
|
ret= SP_GET_FIELD_FAILED;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
chistics= (st_sp_chistics *)thd->alloc(sizeof(st_sp_chistics));
|
bzero((char *)&chistics, sizeof(chistics));
|
||||||
chistics->detistic= (ptr[0] == 'N' ? FALSE : TRUE);
|
chistics.detistic= (ptr[0] == 'N' ? FALSE : TRUE);
|
||||||
|
|
||||||
if ((ptr= get_field(&thd->mem_root,
|
if ((ptr= get_field(&thd->mem_root,
|
||||||
table->field[MYSQL_PROC_FIELD_SECURITY_TYPE])) == NULL)
|
table->field[MYSQL_PROC_FIELD_SECURITY_TYPE])) == NULL)
|
||||||
@ -156,7 +156,7 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
|
|||||||
ret= SP_GET_FIELD_FAILED;
|
ret= SP_GET_FIELD_FAILED;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
chistics->suid= (ptr[0] == 'I' ? IS_NOT_SUID : IS_SUID);
|
chistics.suid= (ptr[0] == 'I' ? IS_NOT_SUID : IS_SUID);
|
||||||
|
|
||||||
if ((params= get_field(&thd->mem_root,
|
if ((params= get_field(&thd->mem_root,
|
||||||
table->field[MYSQL_PROC_FIELD_PARAM_LIST])) == NULL)
|
table->field[MYSQL_PROC_FIELD_PARAM_LIST])) == NULL)
|
||||||
@ -181,7 +181,7 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get additional information
|
// Get additional information
|
||||||
if ((creator= get_field(&thd->mem_root,
|
if ((definer= get_field(&thd->mem_root,
|
||||||
table->field[MYSQL_PROC_FIELD_DEFINER])) == NULL)
|
table->field[MYSQL_PROC_FIELD_DEFINER])) == NULL)
|
||||||
{
|
{
|
||||||
ret= SP_GET_FIELD_FAILED;
|
ret= SP_GET_FIELD_FAILED;
|
||||||
@ -198,8 +198,8 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
|
|||||||
ptr= 0;
|
ptr= 0;
|
||||||
if ((length= str.length()))
|
if ((length= str.length()))
|
||||||
ptr= thd->strmake(str.ptr(), length);
|
ptr= thd->strmake(str.ptr(), length);
|
||||||
chistics->comment.str= ptr;
|
chistics.comment.str= ptr;
|
||||||
chistics->comment.length= length;
|
chistics.comment.length= length;
|
||||||
|
|
||||||
if (opened)
|
if (opened)
|
||||||
{
|
{
|
||||||
@ -224,7 +224,7 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
|
|||||||
params, strlen(params),
|
params, strlen(params),
|
||||||
returns, strlen(returns),
|
returns, strlen(returns),
|
||||||
body, strlen(body),
|
body, strlen(body),
|
||||||
chistics);
|
&chistics);
|
||||||
lex_start(thd, (uchar*)defstr, deflen);
|
lex_start(thd, (uchar*)defstr, deflen);
|
||||||
if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL)
|
if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL)
|
||||||
{
|
{
|
||||||
@ -243,8 +243,8 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
*sphp= thd->lex->sphead;
|
*sphp= thd->lex->sphead;
|
||||||
(*sphp)->set_info((char *) creator, (uint) strlen(creator),
|
(*sphp)->set_info((char *)definer, (uint)strlen(definer),
|
||||||
created, modified, chistics);
|
created, modified, &chistics);
|
||||||
}
|
}
|
||||||
thd->lex->sql_command= oldcmd;
|
thd->lex->sql_command= oldcmd;
|
||||||
thd->variables.sql_mode= old_sql_mode;
|
thd->variables.sql_mode= old_sql_mode;
|
||||||
@ -265,6 +265,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
|
|||||||
int ret;
|
int ret;
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
TABLE_LIST tables;
|
TABLE_LIST tables;
|
||||||
|
char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
|
||||||
|
|
||||||
memset(&tables, 0, sizeof(tables));
|
memset(&tables, 0, sizeof(tables));
|
||||||
tables.db= (char*)"mysql";
|
tables.db= (char*)"mysql";
|
||||||
@ -275,6 +276,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
restore_record(table, default_values); // Get default values for fields
|
restore_record(table, default_values); // Get default values for fields
|
||||||
|
strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS);
|
||||||
|
|
||||||
if (table->fields != MYSQL_PROC_FIELD_COUNT)
|
if (table->fields != MYSQL_PROC_FIELD_COUNT)
|
||||||
{
|
{
|
||||||
@ -300,7 +302,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
|
|||||||
table->field[MYSQL_PROC_FIELD_BODY]->
|
table->field[MYSQL_PROC_FIELD_BODY]->
|
||||||
store(sp->m_body.str, sp->m_body.length, system_charset_info);
|
store(sp->m_body.str, sp->m_body.length, system_charset_info);
|
||||||
table->field[MYSQL_PROC_FIELD_DEFINER]->
|
table->field[MYSQL_PROC_FIELD_DEFINER]->
|
||||||
store(thd->user, (uint)strlen(thd->user), system_charset_info);
|
store(definer, (uint)strlen(definer), system_charset_info);
|
||||||
((Field_timestamp *)table->field[MYSQL_PROC_FIELD_CREATED])->set_time();
|
((Field_timestamp *)table->field[MYSQL_PROC_FIELD_CREATED])->set_time();
|
||||||
table->field[MYSQL_PROC_FIELD_SQL_MODE]->
|
table->field[MYSQL_PROC_FIELD_SQL_MODE]->
|
||||||
store((longlong)thd->variables.sql_mode);
|
store((longlong)thd->variables.sql_mode);
|
||||||
@ -853,7 +855,7 @@ create_string(THD *thd, ulong *lenp,
|
|||||||
ptr+= my_sprintf(ptr, (ptr, (char *)" DETERMINISTIC\n"));
|
ptr+= my_sprintf(ptr, (ptr, (char *)" DETERMINISTIC\n"));
|
||||||
if (chistics->suid == IS_NOT_SUID)
|
if (chistics->suid == IS_NOT_SUID)
|
||||||
ptr+= my_sprintf(ptr, (ptr, (char *)" SQL SECURITY INVOKER\n"));
|
ptr+= my_sprintf(ptr, (ptr, (char *)" SQL SECURITY INVOKER\n"));
|
||||||
if (chistics->comment.str)
|
if (chistics->comment.length)
|
||||||
ptr+= my_sprintf(ptr, (ptr, (char *)" COMMENT '%*s'\n",
|
ptr+= my_sprintf(ptr, (ptr, (char *)" COMMENT '%*s'\n",
|
||||||
chistics->comment.length,
|
chistics->comment.length,
|
||||||
chistics->comment.str));
|
chistics->comment.str));
|
||||||
|
102
sql/sp_head.cc
102
sql/sp_head.cc
@ -19,6 +19,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
|
#include "sql_acl.h"
|
||||||
#include "sp_head.h"
|
#include "sp_head.h"
|
||||||
#include "sp.h"
|
#include "sp.h"
|
||||||
#include "sp_pcontext.h"
|
#include "sp_pcontext.h"
|
||||||
@ -183,9 +184,10 @@ sp_head::init_strings(LEX_STRING *name, LEX *lex)
|
|||||||
|
|
||||||
DBUG_PRINT("info", ("name: %*s", name->length, name->str));
|
DBUG_PRINT("info", ("name: %*s", name->length, name->str));
|
||||||
m_name.length= name->length;
|
m_name.length= name->length;
|
||||||
m_name.str= lex->thd->strmake(name->str, name->length);
|
m_name.str= strmake_root(&m_mem_root, name->str, name->length);
|
||||||
m_params.length= m_param_end- m_param_begin;
|
m_params.length= m_param_end- m_param_begin;
|
||||||
m_params.str= lex->thd->strmake((char *)m_param_begin, m_params.length);
|
m_params.str= strmake_root(&m_mem_root,
|
||||||
|
(char *)m_param_begin, m_params.length);
|
||||||
if (m_returns_begin && m_returns_end)
|
if (m_returns_begin && m_returns_end)
|
||||||
{
|
{
|
||||||
/* QQ KLUDGE: We can't seem to cut out just the type in the parser
|
/* QQ KLUDGE: We can't seem to cut out just the type in the parser
|
||||||
@ -202,12 +204,13 @@ sp_head::init_strings(LEX_STRING *name, LEX *lex)
|
|||||||
p-= 1;
|
p-= 1;
|
||||||
m_returns_end= (uchar *)p+1;
|
m_returns_end= (uchar *)p+1;
|
||||||
m_retstr.length= m_returns_end - m_returns_begin;
|
m_retstr.length= m_returns_end - m_returns_begin;
|
||||||
m_retstr.str= lex->thd->strmake((char *)m_returns_begin, m_retstr.length);
|
m_retstr.str= strmake_root(&m_mem_root,
|
||||||
|
(char *)m_returns_begin, m_retstr.length);
|
||||||
}
|
}
|
||||||
m_body.length= lex->end_of_query - m_body_begin;
|
m_body.length= lex->end_of_query - m_body_begin;
|
||||||
m_body.str= lex->thd->strmake((char *)m_body_begin, m_body.length);
|
m_body.str= strmake_root(&m_mem_root, (char *)m_body_begin, m_body.length);
|
||||||
m_defstr.length= lex->end_of_query - lex->buf;
|
m_defstr.length= lex->end_of_query - lex->buf;
|
||||||
m_defstr.str= lex->thd->strmake((char *)lex->buf, m_defstr.length);
|
m_defstr.str= strmake_root(&m_mem_root, (char *)lex->buf, m_defstr.length);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -664,6 +667,34 @@ sp_head::backpatch(sp_label_t *lab)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sp_head::set_info(char *definer, uint definerlen,
|
||||||
|
longlong created, longlong modified,
|
||||||
|
st_sp_chistics *chistics)
|
||||||
|
{
|
||||||
|
char *p= strchr(definer, '@');
|
||||||
|
uint len;
|
||||||
|
|
||||||
|
if (! p)
|
||||||
|
p= definer; // Weird...
|
||||||
|
len= p-definer;
|
||||||
|
m_definer_user.str= strmake_root(&m_mem_root, definer, len);
|
||||||
|
m_definer_user.length= len;
|
||||||
|
len= definerlen-len-1;
|
||||||
|
m_definer_host.str= strmake_root(&m_mem_root, p+1, len);
|
||||||
|
m_definer_host.length= len;
|
||||||
|
m_created= created;
|
||||||
|
m_modified= modified;
|
||||||
|
m_chistics= (st_sp_chistics *)alloc_root(&m_mem_root, sizeof(st_sp_chistics));
|
||||||
|
memcpy(m_chistics, chistics, sizeof(st_sp_chistics));
|
||||||
|
if (m_chistics->comment.length == 0)
|
||||||
|
m_chistics->comment.str= 0;
|
||||||
|
else
|
||||||
|
m_chistics->comment.str= strmake_root(&m_mem_root,
|
||||||
|
m_chistics->comment.str,
|
||||||
|
m_chistics->comment.length);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
sp_head::show_create_procedure(THD *thd)
|
sp_head::show_create_procedure(THD *thd)
|
||||||
{
|
{
|
||||||
@ -1041,3 +1072,64 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp)
|
|||||||
*nextp= m_ip+1;
|
*nextp= m_ip+1;
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Security context swapping
|
||||||
|
//
|
||||||
|
|
||||||
|
void
|
||||||
|
sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
|
||||||
|
{
|
||||||
|
ctxp->changed= (sp->m_chistics->suid != IS_NOT_SUID &&
|
||||||
|
(strcmp(sp->m_definer_user.str, thd->priv_user) ||
|
||||||
|
strcmp(sp->m_definer_host.str, thd->priv_host)));
|
||||||
|
|
||||||
|
if (ctxp->changed)
|
||||||
|
{
|
||||||
|
ctxp->master_access= thd->master_access;
|
||||||
|
ctxp->db_access= thd->db_access;
|
||||||
|
ctxp->db= thd->db;
|
||||||
|
ctxp->db_length= thd->db_length;
|
||||||
|
ctxp->priv_user= thd->priv_user;
|
||||||
|
strncpy(ctxp->priv_host, thd->priv_host, sizeof(ctxp->priv_host));
|
||||||
|
ctxp->user= thd->user;
|
||||||
|
ctxp->host= thd->host;
|
||||||
|
ctxp->ip= thd->ip;
|
||||||
|
|
||||||
|
/* Change thise just to do the acl_getroot_no_password */
|
||||||
|
thd->user= sp->m_definer_user.str;
|
||||||
|
thd->host= thd->ip = sp->m_definer_host.str;
|
||||||
|
|
||||||
|
if (acl_getroot_no_password(thd))
|
||||||
|
{ // Failed, run as invoker for now
|
||||||
|
ctxp->changed= FALSE;
|
||||||
|
thd->master_access= ctxp->master_access;
|
||||||
|
thd->db_access= ctxp->db_access;
|
||||||
|
thd->db= ctxp->db;
|
||||||
|
thd->db_length= ctxp->db_length;
|
||||||
|
thd->priv_user= ctxp->priv_user;
|
||||||
|
strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore these immiediately */
|
||||||
|
thd->user= ctxp->user;
|
||||||
|
thd->host= ctxp->host;
|
||||||
|
thd->ip= ctxp->ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
|
||||||
|
{
|
||||||
|
if (ctxp->changed)
|
||||||
|
{
|
||||||
|
ctxp->changed= FALSE;
|
||||||
|
thd->master_access= ctxp->master_access;
|
||||||
|
thd->db_access= ctxp->db_access;
|
||||||
|
thd->db= ctxp->db;
|
||||||
|
thd->db_length= ctxp->db_length;
|
||||||
|
thd->priv_user= ctxp->priv_user;
|
||||||
|
strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -61,8 +61,8 @@ public:
|
|||||||
LEX_STRING m_retstr; // For FUNCTIONs only
|
LEX_STRING m_retstr; // For FUNCTIONs only
|
||||||
LEX_STRING m_body;
|
LEX_STRING m_body;
|
||||||
LEX_STRING m_defstr;
|
LEX_STRING m_defstr;
|
||||||
char *m_creator;
|
LEX_STRING m_definer_user;
|
||||||
uint m_creatorlen;
|
LEX_STRING m_definer_host;
|
||||||
longlong m_created;
|
longlong m_created;
|
||||||
longlong m_modified;
|
longlong m_modified;
|
||||||
// Pointers set during parsing
|
// Pointers set during parsing
|
||||||
@ -159,16 +159,9 @@ public:
|
|||||||
return sp_map_result_type(m_returns);
|
return sp_map_result_type(m_returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_info(char *creator, uint creatorlen,
|
void set_info(char *definer, uint definerlen,
|
||||||
longlong created, longlong modified,
|
longlong created, longlong modified,
|
||||||
st_sp_chistics *chistics)
|
st_sp_chistics *chistics);
|
||||||
{
|
|
||||||
m_creator= creator;
|
|
||||||
m_creatorlen= creatorlen;
|
|
||||||
m_created= created;
|
|
||||||
m_modified= modified;
|
|
||||||
m_chistics= chistics;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void reset_thd_mem_root(THD *thd)
|
inline void reset_thd_mem_root(THD *thd)
|
||||||
{
|
{
|
||||||
@ -642,4 +635,24 @@ private:
|
|||||||
}; // class sp_instr_cfetch : public sp_instr
|
}; // class sp_instr_cfetch : public sp_instr
|
||||||
|
|
||||||
|
|
||||||
|
struct st_sp_security_context
|
||||||
|
{
|
||||||
|
bool changed;
|
||||||
|
uint master_access;
|
||||||
|
uint db_access;
|
||||||
|
char *db;
|
||||||
|
uint db_length;
|
||||||
|
char *priv_user;
|
||||||
|
char priv_host[MAX_HOSTNAME];
|
||||||
|
char *user;
|
||||||
|
char *host;
|
||||||
|
char *ip;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp);
|
||||||
|
|
||||||
|
void
|
||||||
|
sp_restore_security_context(THD *thd, sp_head *sp,st_sp_security_context *ctxp);
|
||||||
|
|
||||||
#endif /* _SP_HEAD_H_ */
|
#endif /* _SP_HEAD_H_ */
|
||||||
|
@ -778,6 +778,66 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is like acl_getroot() above, but it doesn't check password,
|
||||||
|
* and we don't care about the user resources.
|
||||||
|
* Used to get access rights for SQL SECURITY DEFINER invokation of
|
||||||
|
* stored procedures.
|
||||||
|
*/
|
||||||
|
int acl_getroot_no_password(THD *thd)
|
||||||
|
{
|
||||||
|
ulong user_access= NO_ACCESS;
|
||||||
|
int res= 1;
|
||||||
|
ACL_USER *acl_user= 0;
|
||||||
|
DBUG_ENTER("acl_getroot_no_password");
|
||||||
|
|
||||||
|
if (!initialized)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
here if mysqld's been started with --skip-grant-tables option.
|
||||||
|
*/
|
||||||
|
thd->priv_user= (char *) ""; // privileges for
|
||||||
|
*thd->priv_host= '\0'; // the user are unknown
|
||||||
|
thd->master_access= ~NO_ACCESS; // everything is allowed
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID(pthread_mutex_lock(&acl_cache->lock));
|
||||||
|
|
||||||
|
/*
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
acl_user= dynamic_element(&acl_users,i,ACL_USER*);
|
||||||
|
if ((!acl_user->user && (!thd->user || !thd->user[0])) ||
|
||||||
|
(acl_user->user && strcmp(thd->user, acl_user->user) == 0))
|
||||||
|
{
|
||||||
|
if (compare_hostname(&acl_user->host, thd->host, thd->ip))
|
||||||
|
{
|
||||||
|
res= 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acl_user)
|
||||||
|
{
|
||||||
|
thd->master_access= acl_user->access;
|
||||||
|
thd->priv_user= acl_user->user ? thd->user : (char *) "";
|
||||||
|
|
||||||
|
if (acl_user->host.hostname)
|
||||||
|
strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
|
||||||
|
else
|
||||||
|
*thd->priv_host= 0;
|
||||||
|
}
|
||||||
|
VOID(pthread_mutex_unlock(&acl_cache->lock));
|
||||||
|
DBUG_RETURN(res);
|
||||||
|
}
|
||||||
|
|
||||||
static byte* check_get_key(ACL_USER *buff,uint *length,
|
static byte* check_get_key(ACL_USER *buff,uint *length,
|
||||||
my_bool not_used __attribute__((unused)))
|
my_bool not_used __attribute__((unused)))
|
||||||
{
|
{
|
||||||
|
@ -139,6 +139,7 @@ ulong acl_get(const char *host, const char *ip,
|
|||||||
const char *user, const char *db, my_bool db_is_pattern);
|
const char *user, const char *db, my_bool db_is_pattern);
|
||||||
int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd,
|
int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd,
|
||||||
uint passwd_len);
|
uint passwd_len);
|
||||||
|
int acl_getroot_no_password(THD *thd);
|
||||||
bool acl_check_host(const char *host, const char *ip);
|
bool acl_check_host(const char *host, const char *ip);
|
||||||
bool check_change_password(THD *thd, const char *host, const char *user);
|
bool check_change_password(THD *thd, const char *host, const char *user);
|
||||||
bool change_password(THD *thd, const char *host, const char *user,
|
bool change_password(THD *thd, const char *host, const char *user,
|
||||||
|
@ -3495,6 +3495,7 @@ mysql_execute_command(THD *thd)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
st_sp_security_context save_ctx;
|
||||||
uint smrx;
|
uint smrx;
|
||||||
LINT_INIT(smrx);
|
LINT_INIT(smrx);
|
||||||
|
|
||||||
@ -3526,8 +3527,12 @@ mysql_execute_command(THD *thd)
|
|||||||
thd->server_status |= SERVER_MORE_RESULTS_EXISTS;
|
thd->server_status |= SERVER_MORE_RESULTS_EXISTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sp_change_security_context(thd, sp, &save_ctx);
|
||||||
|
|
||||||
res= sp->execute_procedure(thd, &lex->value_list);
|
res= sp->execute_procedure(thd, &lex->value_list);
|
||||||
|
|
||||||
|
sp_restore_security_context(thd, sp, &save_ctx);
|
||||||
|
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
thd->net.no_send_ok= nsok;
|
thd->net.no_send_ok= nsok;
|
||||||
#endif
|
#endif
|
||||||
|
@ -2712,7 +2712,7 @@ alter:
|
|||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
|
|
||||||
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
|
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
|
||||||
Lex->name= 0;
|
lex->name= 0;
|
||||||
}
|
}
|
||||||
sp_a_chistics
|
sp_a_chistics
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user