Commit a6f85eea authored by unknown's avatar unknown

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.
parent 8630ca9a
...@@ -280,4 +280,15 @@ create function bug1654() ...@@ -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;
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 ...@@ -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 ...@@ -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; ...@@ -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 ...@@ -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) ...@@ -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() ...@@ -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 ;|
#
# 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| ...@@ -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) ...@@ -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
......
...@@ -121,10 +121,10 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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));
......
...@@ -19,6 +19,7 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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: ...@@ -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
{ {
......
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