diff options
-rw-r--r-- | mysql-test/r/view_grant.result | 53 | ||||
-rw-r--r-- | mysql-test/t/view_grant.test | 62 | ||||
-rw-r--r-- | sql/item_create.cc | 6 | ||||
-rw-r--r-- | sql/item_create.h | 1 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 65 | ||||
-rw-r--r-- | sql/item_strfunc.h | 35 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 7 |
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 |