mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Bug#20570: CURRENT_USER() in a VIEW with SQL SECURITY DEFINER returns
invoker name The bug was fixed similar to how context switch is handled in Item_func_sp::execute_impl(): we store pointer to current Name_resolution_context in Item_func_current_user class, and use its Security_context in Item_func_current_user::fix_fields(). mysql-test/r/view_grant.result: Add result for bug#20570. mysql-test/t/view_grant.test: Add test case for bug#20570. sql/item_create.cc: Remove create_func_current_user(), as it is not used for automatic function creation. sql/item_create.h: Remove prototype for create_func_current_user(). sql/item_strfunc.cc: Add implementations for Item_func_user::init(), Item_func_user::fix_fields() and Item_func_current_user::fix_fields() methods. The latter uses Security_context from current Name_resolution_context, if one is defined. sql/item_strfunc.h: Move implementation of CURRENT_USER() out of Item_func_user to to new Item_func_current_user class. For both classes calculate user name in fix_fields() method. For Item_func_current_user add context field to store Name_resolution_context in effect. sql/sql_yacc.yy: Pass current Name_resolution_context to Item_func_current_user.
This commit is contained in:
@ -618,3 +618,56 @@ ERROR HY000: There is no 'no-such-user'@'localhost' registered
|
|||||||
DROP VIEW v;
|
DROP VIEW v;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
USE test;
|
USE test;
|
||||||
|
DROP VIEW IF EXISTS v1;
|
||||||
|
DROP VIEW IF EXISTS v2;
|
||||||
|
DROP VIEW IF EXISTS v3;
|
||||||
|
DROP FUNCTION IF EXISTS f1;
|
||||||
|
DROP FUNCTION IF EXISTS f2;
|
||||||
|
DROP PROCEDURE IF EXISTS p1;
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v1 AS SELECT CURRENT_USER() AS cu;
|
||||||
|
CREATE FUNCTION f1() RETURNS VARCHAR(77) SQL SECURITY INVOKER
|
||||||
|
RETURN CURRENT_USER();
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v2 AS SELECT f1() AS cu;
|
||||||
|
CREATE PROCEDURE p1(OUT cu VARCHAR(77)) SQL SECURITY INVOKER
|
||||||
|
SET cu= CURRENT_USER();
|
||||||
|
CREATE FUNCTION f2() RETURNS VARCHAR(77) SQL SECURITY INVOKER
|
||||||
|
BEGIN
|
||||||
|
DECLARE cu VARCHAR(77);
|
||||||
|
CALL p1(cu);
|
||||||
|
RETURN cu;
|
||||||
|
END|
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v3 AS SELECT f2() AS cu;
|
||||||
|
CREATE USER mysqltest_u1@localhost;
|
||||||
|
GRANT ALL ON test.* TO mysqltest_u1@localhost;
|
||||||
|
|
||||||
|
The following tests should all return 1.
|
||||||
|
|
||||||
|
SELECT CURRENT_USER() = 'mysqltest_u1@localhost';
|
||||||
|
CURRENT_USER() = 'mysqltest_u1@localhost'
|
||||||
|
1
|
||||||
|
SELECT f1() = 'mysqltest_u1@localhost';
|
||||||
|
f1() = 'mysqltest_u1@localhost'
|
||||||
|
1
|
||||||
|
CALL p1(@cu);
|
||||||
|
SELECT @cu = 'mysqltest_u1@localhost';
|
||||||
|
@cu = 'mysqltest_u1@localhost'
|
||||||
|
1
|
||||||
|
SELECT f2() = 'mysqltest_u1@localhost';
|
||||||
|
f2() = 'mysqltest_u1@localhost'
|
||||||
|
1
|
||||||
|
SELECT cu = 'root@localhost' FROM v1;
|
||||||
|
cu = 'root@localhost'
|
||||||
|
1
|
||||||
|
SELECT cu = 'root@localhost' FROM v2;
|
||||||
|
cu = 'root@localhost'
|
||||||
|
1
|
||||||
|
SELECT cu = 'root@localhost' FROM v3;
|
||||||
|
cu = 'root@localhost'
|
||||||
|
1
|
||||||
|
DROP VIEW v3;
|
||||||
|
DROP FUNCTION f2;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
DROP FUNCTION f1;
|
||||||
|
DROP VIEW v2;
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP USER mysqltest_u1@localhost;
|
||||||
|
@ -807,3 +807,65 @@ SELECT * FROM v;
|
|||||||
DROP VIEW v;
|
DROP VIEW v;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
USE test;
|
USE test;
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# BUG#20570: CURRENT_USER() in a VIEW with SQL SECURITY DEFINER
|
||||||
|
# returns invoker name
|
||||||
|
#
|
||||||
|
--disable_warnings
|
||||||
|
DROP VIEW IF EXISTS v1;
|
||||||
|
DROP VIEW IF EXISTS v2;
|
||||||
|
DROP VIEW IF EXISTS v3;
|
||||||
|
DROP FUNCTION IF EXISTS f1;
|
||||||
|
DROP FUNCTION IF EXISTS f2;
|
||||||
|
DROP PROCEDURE IF EXISTS p1;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v1 AS SELECT CURRENT_USER() AS cu;
|
||||||
|
|
||||||
|
CREATE FUNCTION f1() RETURNS VARCHAR(77) SQL SECURITY INVOKER
|
||||||
|
RETURN CURRENT_USER();
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v2 AS SELECT f1() AS cu;
|
||||||
|
|
||||||
|
CREATE PROCEDURE p1(OUT cu VARCHAR(77)) SQL SECURITY INVOKER
|
||||||
|
SET cu= CURRENT_USER();
|
||||||
|
delimiter |;
|
||||||
|
CREATE FUNCTION f2() RETURNS VARCHAR(77) SQL SECURITY INVOKER
|
||||||
|
BEGIN
|
||||||
|
DECLARE cu VARCHAR(77);
|
||||||
|
CALL p1(cu);
|
||||||
|
RETURN cu;
|
||||||
|
END|
|
||||||
|
delimiter ;|
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v3 AS SELECT f2() AS cu;
|
||||||
|
|
||||||
|
CREATE USER mysqltest_u1@localhost;
|
||||||
|
GRANT ALL ON test.* TO mysqltest_u1@localhost;
|
||||||
|
|
||||||
|
connect (conn1, localhost, mysqltest_u1,,);
|
||||||
|
|
||||||
|
--echo
|
||||||
|
--echo The following tests should all return 1.
|
||||||
|
--echo
|
||||||
|
SELECT CURRENT_USER() = 'mysqltest_u1@localhost';
|
||||||
|
SELECT f1() = 'mysqltest_u1@localhost';
|
||||||
|
CALL p1(@cu);
|
||||||
|
SELECT @cu = 'mysqltest_u1@localhost';
|
||||||
|
SELECT f2() = 'mysqltest_u1@localhost';
|
||||||
|
SELECT cu = 'root@localhost' FROM v1;
|
||||||
|
SELECT cu = 'root@localhost' FROM v2;
|
||||||
|
SELECT cu = 'root@localhost' FROM v3;
|
||||||
|
|
||||||
|
disconnect conn1;
|
||||||
|
connection default;
|
||||||
|
|
||||||
|
DROP VIEW v3;
|
||||||
|
DROP FUNCTION f2;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
DROP FUNCTION f1;
|
||||||
|
DROP VIEW v2;
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP USER mysqltest_u1@localhost;
|
||||||
|
|
||||||
|
# End of 5.0 tests.
|
||||||
|
@ -296,12 +296,6 @@ Item *create_func_pow(Item* a, Item *b)
|
|||||||
return new Item_func_pow(a,b);
|
return new Item_func_pow(a,b);
|
||||||
}
|
}
|
||||||
|
|
||||||
Item *create_func_current_user()
|
|
||||||
{
|
|
||||||
current_thd->lex->safe_to_cache_query= 0;
|
|
||||||
return new Item_func_user(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
Item *create_func_radians(Item *a)
|
Item *create_func_radians(Item *a)
|
||||||
{
|
{
|
||||||
return new Item_func_units((char*) "radians",a,M_PI/180,0.0);
|
return new Item_func_units((char*) "radians",a,M_PI/180,0.0);
|
||||||
|
@ -73,7 +73,6 @@ Item *create_func_period_add(Item* a, Item *b);
|
|||||||
Item *create_func_period_diff(Item* a, Item *b);
|
Item *create_func_period_diff(Item* a, Item *b);
|
||||||
Item *create_func_pi(void);
|
Item *create_func_pi(void);
|
||||||
Item *create_func_pow(Item* a, Item *b);
|
Item *create_func_pow(Item* a, Item *b);
|
||||||
Item *create_func_current_user(void);
|
|
||||||
Item *create_func_radians(Item *a);
|
Item *create_func_radians(Item *a);
|
||||||
Item *create_func_release_lock(Item* a);
|
Item *create_func_release_lock(Item* a);
|
||||||
Item *create_func_repeat(Item* a, Item *b);
|
Item *create_func_repeat(Item* a, Item *b);
|
||||||
|
@ -1650,42 +1650,51 @@ String *Item_func_database::val_str(String *str)
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make USER() replicate properly (currently it is replicated to "")
|
|
||||||
|
|
||||||
String *Item_func_user::val_str(String *str)
|
/*
|
||||||
|
TODO: make USER() replicate properly (currently it is replicated to "")
|
||||||
|
*/
|
||||||
|
bool Item_func_user::init(const char *user, const char *host)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
THD *thd=current_thd;
|
|
||||||
CHARSET_INFO *cs= system_charset_info;
|
|
||||||
const char *host, *user;
|
|
||||||
uint res_length;
|
|
||||||
|
|
||||||
if (is_current)
|
|
||||||
{
|
|
||||||
user= thd->security_ctx->priv_user;
|
|
||||||
host= thd->security_ctx->priv_host;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
user= thd->main_security_ctx.user;
|
|
||||||
host= thd->main_security_ctx.host_or_ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For system threads (e.g. replication SQL thread) user may be empty
|
// For system threads (e.g. replication SQL thread) user may be empty
|
||||||
if (!user)
|
if (user)
|
||||||
return &my_empty_string;
|
|
||||||
res_length= (strlen(user)+strlen(host)+2) * cs->mbmaxlen;
|
|
||||||
|
|
||||||
if (str->alloc(res_length))
|
|
||||||
{
|
{
|
||||||
null_value=1;
|
CHARSET_INFO *cs= str_value.charset();
|
||||||
return 0;
|
uint res_length= (strlen(user)+strlen(host)+2) * cs->mbmaxlen;
|
||||||
|
|
||||||
|
if (str_value.alloc(res_length))
|
||||||
|
{
|
||||||
|
null_value=1;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
res_length=cs->cset->snprintf(cs, (char*)str_value.ptr(), res_length,
|
||||||
|
"%s@%s", user, host);
|
||||||
|
str_value.length(res_length);
|
||||||
|
str_value.mark_as_const();
|
||||||
}
|
}
|
||||||
res_length=cs->cset->snprintf(cs, (char*)str->ptr(), res_length, "%s@%s",
|
return FALSE;
|
||||||
user, host);
|
}
|
||||||
str->length(res_length);
|
|
||||||
str->set_charset(cs);
|
|
||||||
return str;
|
bool Item_func_user::fix_fields(THD *thd, Item **ref)
|
||||||
|
{
|
||||||
|
return (Item_func_sysconst::fix_fields(thd, ref) ||
|
||||||
|
init(thd->main_security_ctx.user,
|
||||||
|
thd->main_security_ctx.host_or_ip));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Item_func_current_user::fix_fields(THD *thd, Item **ref)
|
||||||
|
{
|
||||||
|
if (Item_func_sysconst::fix_fields(thd, ref))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
Security_context *ctx= (context->security_ctx
|
||||||
|
? context->security_ctx : thd->security_ctx);
|
||||||
|
return init(ctx->priv_user, ctx->priv_host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -385,21 +385,40 @@ public:
|
|||||||
|
|
||||||
class Item_func_user :public Item_func_sysconst
|
class Item_func_user :public Item_func_sysconst
|
||||||
{
|
{
|
||||||
bool is_current;
|
protected:
|
||||||
|
bool init (const char *user, const char *host);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Item_func_user(bool is_current_arg)
|
Item_func_user()
|
||||||
:Item_func_sysconst(), is_current(is_current_arg) {}
|
{
|
||||||
String *val_str(String *);
|
str_value.set("", 0, system_charset_info);
|
||||||
|
}
|
||||||
|
String *val_str(String *)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
return (null_value ? 0 : &str_value);
|
||||||
|
}
|
||||||
|
bool fix_fields(THD *thd, Item **ref);
|
||||||
void fix_length_and_dec()
|
void fix_length_and_dec()
|
||||||
{
|
{
|
||||||
max_length= ((USERNAME_LENGTH + HOSTNAME_LENGTH + 1) *
|
max_length= ((USERNAME_LENGTH + HOSTNAME_LENGTH + 1) *
|
||||||
system_charset_info->mbmaxlen);
|
system_charset_info->mbmaxlen);
|
||||||
}
|
}
|
||||||
const char *func_name() const
|
const char *func_name() const { return "user"; }
|
||||||
{ return is_current ? "current_user" : "user"; }
|
const char *fully_qualified_func_name() const { return "user()"; }
|
||||||
const char *fully_qualified_func_name() const
|
};
|
||||||
{ return is_current ? "current_user()" : "user()"; }
|
|
||||||
|
|
||||||
|
class Item_func_current_user :public Item_func_user
|
||||||
|
{
|
||||||
|
Name_resolution_context *context;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Item_func_current_user(Name_resolution_context *context_arg)
|
||||||
|
: context(context_arg) {}
|
||||||
|
bool fix_fields(THD *thd, Item **ref);
|
||||||
|
const char *func_name() const { return "current_user"; }
|
||||||
|
const char *fully_qualified_func_name() const { return "current_user()"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -4413,7 +4413,10 @@ simple_expr:
|
|||||||
Lex->safe_to_cache_query=0;
|
Lex->safe_to_cache_query=0;
|
||||||
}
|
}
|
||||||
| CURRENT_USER optional_braces
|
| CURRENT_USER optional_braces
|
||||||
{ $$= create_func_current_user(); }
|
{
|
||||||
|
$$= new Item_func_current_user(Lex->current_context());
|
||||||
|
Lex->safe_to_cache_query= 0;
|
||||||
|
}
|
||||||
| DATE_ADD_INTERVAL '(' expr ',' interval_expr interval ')'
|
| DATE_ADD_INTERVAL '(' expr ',' interval_expr interval ')'
|
||||||
{ $$= new Item_date_add_interval($3,$5,$6,0); }
|
{ $$= new Item_date_add_interval($3,$5,$6,0); }
|
||||||
| DATE_SUB_INTERVAL '(' expr ',' interval_expr interval ')'
|
| DATE_SUB_INTERVAL '(' expr ',' interval_expr interval ')'
|
||||||
@ -4764,7 +4767,7 @@ simple_expr:
|
|||||||
| UNIX_TIMESTAMP '(' expr ')'
|
| UNIX_TIMESTAMP '(' expr ')'
|
||||||
{ $$= new Item_func_unix_timestamp($3); }
|
{ $$= new Item_func_unix_timestamp($3); }
|
||||||
| USER '(' ')'
|
| USER '(' ')'
|
||||||
{ $$= new Item_func_user(FALSE); Lex->safe_to_cache_query=0; }
|
{ $$= new Item_func_user(); Lex->safe_to_cache_query=0; }
|
||||||
| UTC_DATE_SYM optional_braces
|
| UTC_DATE_SYM optional_braces
|
||||||
{ $$= new Item_func_curdate_utc(); Lex->safe_to_cache_query=0;}
|
{ $$= new Item_func_curdate_utc(); Lex->safe_to_cache_query=0;}
|
||||||
| UTC_TIME_SYM optional_braces
|
| UTC_TIME_SYM optional_braces
|
||||||
|
Reference in New Issue
Block a user