summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/view_grant.result53
-rw-r--r--mysql-test/t/view_grant.test62
-rw-r--r--sql/item_create.cc6
-rw-r--r--sql/item_create.h1
-rw-r--r--sql/item_strfunc.cc65
-rw-r--r--sql/item_strfunc.h35
-rw-r--r--sql/sql_yacc.yy7
7 files changed, 184 insertions, 45 deletions
diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result
index 0431957f602..7f63d790fb8 100644
--- a/mysql-test/r/view_grant.result
+++ b/mysql-test/r/view_grant.result
@@ -659,3 +659,56 @@ DROP VIEW test2.t3;
DROP TABLE test2.t1, test1.t0;
DROP DATABASE test2;
DROP DATABASE test1;
+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;
diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test
index 429a2af6bac..c75e5422de7 100644
--- a/mysql-test/t/view_grant.test
+++ b/mysql-test/t/view_grant.test
@@ -866,3 +866,65 @@ DROP VIEW test2.t3;
DROP TABLE test2.t1, test1.t0;
DROP DATABASE test2;
DROP DATABASE test1;
+
+
+#
+# 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.
diff --git a/sql/item_create.cc b/sql/item_create.cc
index bfcb2101d60..7d57757432e 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -296,12 +296,6 @@ Item *create_func_pow(Item* a, Item *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)
{
return new Item_func_units((char*) "radians",a,M_PI/180,0.0);
diff --git a/sql/item_create.h b/sql/item_create.h
index 35db9be3c89..cf61f90f91d 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -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_pi(void);
Item *create_func_pow(Item* a, Item *b);
-Item *create_func_current_user(void);
Item *create_func_radians(Item *a);
Item *create_func_release_lock(Item* a);
Item *create_func_repeat(Item* a, Item *b);
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 9e3a9b64288..8bc1bfaf7dd 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1670,42 +1670,51 @@ String *Item_func_database::val_str(String *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);
- 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
+ // For system threads (e.g. replication SQL thread) user may be empty
+ if (user)
{
- user= thd->main_security_ctx.user;
- host= thd->main_security_ctx.host_or_ip;
- }
+ CHARSET_INFO *cs= str_value.charset();
+ uint res_length= (strlen(user)+strlen(host)+2) * cs->mbmaxlen;
- // For system threads (e.g. replication SQL thread) user may be empty
- if (!user)
- return &my_empty_string;
- res_length= (strlen(user)+strlen(host)+2) * cs->mbmaxlen;
+ if (str_value.alloc(res_length))
+ {
+ null_value=1;
+ return TRUE;
+ }
- if (str->alloc(res_length))
- {
- null_value=1;
- return 0;
+ 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",
- user, host);
- str->length(res_length);
- str->set_charset(cs);
- return str;
+ return FALSE;
+}
+
+
+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);
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index af59b8d740b..a2204f22822 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -385,21 +385,40 @@ public:
class Item_func_user :public Item_func_sysconst
{
- bool is_current;
+protected:
+ bool init (const char *user, const char *host);
public:
- Item_func_user(bool is_current_arg)
- :Item_func_sysconst(), is_current(is_current_arg) {}
- String *val_str(String *);
+ Item_func_user()
+ {
+ 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()
{
max_length= ((USERNAME_LENGTH + HOSTNAME_LENGTH + 1) *
system_charset_info->mbmaxlen);
}
- const char *func_name() const
- { return is_current ? "current_user" : "user"; }
- const char *fully_qualified_func_name() const
- { return is_current ? "current_user()" : "user()"; }
+ const char *func_name() const { return "user"; }
+ const char *fully_qualified_func_name() const { return "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()"; }
};
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 952a8eb44ea..e83e262c076 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4453,7 +4453,10 @@ simple_expr:
Lex->safe_to_cache_query=0;
}
| 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 ')'
{ $$= new Item_date_add_interval($3,$5,$6,0); }
| DATE_SUB_INTERVAL '(' expr ',' interval_expr interval ')'
@@ -4810,7 +4813,7 @@ simple_expr:
| UNIX_TIMESTAMP '(' expr ')'
{ $$= new Item_func_unix_timestamp($3); }
| 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
{ $$= new Item_func_curdate_utc(); Lex->safe_to_cache_query=0;}
| UTC_TIME_SYM optional_braces