diff --git a/mysql-test/main/sp-security.result b/mysql-test/main/sp-security.result index 7d2098f62be..2c48883a509 100644 --- a/mysql-test/main/sp-security.result +++ b/mysql-test/main/sp-security.result @@ -802,3 +802,21 @@ connection default; DROP DATABASE u1; DROP USER u1@localhost; set @@global.character_set_server=@save_character_set_server; +# +# Start of 10.5 tests +# +# +# MDEV-20366 Server crashes in get_current_user upon SET PASSWORD via SP +# +CREATE PROCEDURE p1() SET PASSWORD FOR foo@localhost=PASSWORD('x'); +CALL p1(); +ERROR 28000: Can't find any matching row in the user table +DROP PROCEDURE p1; +CREATE USER foo@localhost; +CREATE PROCEDURE p1() SET PASSWORD FOR foo@localhost=PASSWORD('x'); +CALL p1(); +DROP PROCEDURE p1; +DROP USER foo@localhost; +# +# End of 10.5 tests +# diff --git a/mysql-test/main/sp-security.test b/mysql-test/main/sp-security.test index c375815b29a..e7790bf703a 100644 --- a/mysql-test/main/sp-security.test +++ b/mysql-test/main/sp-security.test @@ -1078,3 +1078,30 @@ DROP DATABASE u1; DROP USER u1@localhost; set @@global.character_set_server=@save_character_set_server; + + +--echo # +--echo # Start of 10.5 tests +--echo # + +--echo # +--echo # MDEV-20366 Server crashes in get_current_user upon SET PASSWORD via SP +--echo # + +# Testing without the user +CREATE PROCEDURE p1() SET PASSWORD FOR foo@localhost=PASSWORD('x'); +--error ER_PASSWORD_NO_MATCH +CALL p1(); +DROP PROCEDURE p1; + +# Testing with the user +CREATE USER foo@localhost; +CREATE PROCEDURE p1() SET PASSWORD FOR foo@localhost=PASSWORD('x'); +CALL p1(); +DROP PROCEDURE p1; +DROP USER foo@localhost; + + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 477401c793f..671948f8e8d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -11393,3 +11393,36 @@ bool LEX::stmt_revoke_proxy(THD *thd, LEX_USER *user) return !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_proxy(sql_command, NO_ACL)); } + + +LEX_USER *LEX::current_user_for_set_password(THD *thd) +{ + LEX_CSTRING pw= { STRING_WITH_LEN("password") }; + if (unlikely(spcont && spcont->find_variable(&pw, false))) + { + my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str); + return NULL; + } + LEX_USER *res; + if (unlikely(!(res= (LEX_USER*) thd->calloc(sizeof(LEX_USER))))) + return NULL; + res->user= current_user; + return res; +} + + +bool LEX::sp_create_set_password_instr(THD *thd, + LEX_USER *user, + USER_AUTH *auth, + bool no_lookahead) +{ + user->auth= auth; + set_var_password *var= new (thd->mem_root) set_var_password(user); + if (unlikely(var == NULL) || + unlikely(var_list.push_back(var, thd->mem_root))) + return true; + autocommit= true; + if (sphead) + sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; + return sp_create_assignment_instr(thd, no_lookahead); +} diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 0a802b9652c..49edce508ca 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3864,6 +3864,21 @@ public: const Column_definition &ref, Row_definition_list *fields, Item *def); + + LEX_USER *current_user_for_set_password(THD *thd); + bool sp_create_set_password_instr(THD *thd, + LEX_USER *user, + USER_AUTH *auth, + bool no_lookahead); + bool sp_create_set_password_instr(THD *thd, + USER_AUTH *auth, + bool no_lookahead) + { + LEX_USER *user; + return !(user= current_user_for_set_password(thd)) || + sp_create_set_password_instr(thd, user, auth, no_lookahead); + } + bool sp_handler_declaration_init(THD *thd, int type); bool sp_handler_declaration_finalize(THD *thd, int type); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6fe7d871f40..da752c0a3cb 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1543,6 +1543,7 @@ End SQL_MODE_ORACLE_SPECIFIC */ admin_option_for_role user_maybe_role %type opt_auth_str auth_expression auth_token + text_or_password %type opt_collate @@ -16433,25 +16434,30 @@ option_value_no_option_type: unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) MYSQL_YYABORT; } - | PASSWORD_SYM opt_for_user text_or_password + | PASSWORD_SYM equal { if (sp_create_assignment_lex(thd, $1.pos())) MYSQL_YYABORT; - LEX *lex = Lex; - set_var_password *var= (new (thd->mem_root) - set_var_password(lex->definer)); - if (unlikely(var == NULL) || - unlikely(lex->var_list.push_back(var, thd->mem_root))) + } + text_or_password + { + if (unlikely(Lex->sp_create_set_password_instr(thd, $4, + yychar == YYEMPTY))) MYSQL_YYABORT; - lex->autocommit= TRUE; - if (lex->sphead) - lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; - if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + } + | PASSWORD_SYM FOR_SYM + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + user equal text_or_password + { + if (unlikely(Lex->sp_create_set_password_instr(thd, $4, $6, + yychar == YYEMPTY))) MYSQL_YYABORT; } ; - transaction_characteristics: transaction_access_mode | isolation_level @@ -16508,42 +16514,25 @@ isolation_types: | SERIALIZABLE_SYM { $$= ISO_SERIALIZABLE; } ; -opt_for_user: - equal - { - LEX *lex= thd->lex; - sp_pcontext *spc= lex->spcont; - LEX_CSTRING pw= { STRING_WITH_LEN("password") }; - - if (unlikely(spc && spc->find_variable(&pw, false))) - my_yyabort_error((ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str)); - if (unlikely(!(lex->definer= (LEX_USER*) - thd->calloc(sizeof(LEX_USER))))) - MYSQL_YYABORT; - lex->definer->user= current_user; - lex->definer->auth= new (thd->mem_root) USER_AUTH(); - } - | FOR_SYM user equal { Lex->definer= $2; } - ; text_or_password: TEXT_STRING { - Lex->definer->auth= new (thd->mem_root) USER_AUTH(); - Lex->definer->auth->auth_str= $1; + $$= new (thd->mem_root) USER_AUTH(); + $$->auth_str= $1; } | PASSWORD_SYM '(' TEXT_STRING ')' { - Lex->definer->auth= new (thd->mem_root) USER_AUTH(); - Lex->definer->auth->pwtext= $3; + $$= new (thd->mem_root) USER_AUTH(); + $$->pwtext= $3; } | OLD_PASSWORD_SYM '(' TEXT_STRING ')' { - Lex->definer->auth= new (thd->mem_root) USER_AUTH(); - Lex->definer->auth->pwtext= $3; - Lex->definer->auth->auth_str.str= Item_func_password::alloc(thd, + $$= new (thd->mem_root) USER_AUTH(); + $$->pwtext= $3; + $$->auth_str.str= Item_func_password::alloc(thd, $3.str, $3.length, Item_func_password::OLD); - Lex->definer->auth->auth_str.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; + $$->auth_str.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; } ;