diff options
author | anozdrin@mysql.com <> | 2006-03-01 14:13:07 +0300 |
---|---|---|
committer | anozdrin@mysql.com <> | 2006-03-01 14:13:07 +0300 |
commit | e03e5222013a0bbfc17adb37f5201b9f0dbc5327 (patch) | |
tree | baf54f335b2a6ccc3c2d1da9406e0832ddb6c26b /sql | |
parent | db1ecaa1a29e958815befb2c6dbfd9a78229e6d1 (diff) | |
download | mariadb-git-e03e5222013a0bbfc17adb37f5201b9f0dbc5327.tar.gz |
Fix for BUG#16266: Definer is not fully qualified error during replication.
The idea of the fix is to extend support of non-SUID triggers for backward
compatibility. Formerly non-SUID triggers were appeared when "new" server
is being started against "old" database. Now, they are also created when
"new" slave receives updates from "old" master.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/mysql_priv.h | 1 | ||||
-rw-r--r-- | sql/sql_parse.cc | 30 | ||||
-rw-r--r-- | sql/sql_trigger.cc | 108 | ||||
-rw-r--r-- | sql/sql_view.cc | 20 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 42 |
5 files changed, 149 insertions, 52 deletions
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2c817ae54c2..9559b0be76a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -531,6 +531,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *create_table); bool get_default_definer(THD *thd, LEX_USER *definer); +LEX_USER *create_default_definer(THD *thd); LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name); enum enum_mysql_completiontype { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b2066953cf5..0494ccf985f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7207,6 +7207,34 @@ bool get_default_definer(THD *thd, LEX_USER *definer) /* + Create default definer for the specified THD. Also check that the current + user is conformed to the definers requirements. + + SYNOPSIS + create_default_definer() + thd [in] thread handler + + RETURN + On success, return a valid pointer to the created and initialized + LEX_USER, which contains definer information. + On error, return 0. +*/ + +LEX_USER *create_default_definer(THD *thd) +{ + LEX_USER *definer; + + if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER)))) + return 0; + + if (get_default_definer(thd, definer)) + return 0; + + return definer; +} + + +/* Create definer with the given user and host names. Also check that the user and host names satisfy definers requirements. @@ -7218,7 +7246,7 @@ bool get_default_definer(THD *thd, LEX_USER *definer) RETURN On success, return a valid pointer to the created and initialized - LEX_STRING, which contains definer information. + LEX_USER, which contains definer information. On error, return 0. */ diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 4c3ae5c032d..9ccc70d8ccd 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -264,7 +264,17 @@ end: log_query.set((char *) 0, 0, system_charset_info); /* reset log_query */ log_query.append(STRING_WITH_LEN("CREATE ")); - append_definer(thd, &log_query, &definer_user, &definer_host); + + if (definer_user.str && definer_host.str) + { + /* + Append definer-clause if the trigger is SUID (a usual trigger in + new MySQL versions). + */ + + append_definer(thd, &log_query, &definer_user, &definer_host); + } + log_query.append(thd->lex->trigger_definition_begin); } @@ -289,17 +299,30 @@ end: LEX) tables - table list containing one open table for which the trigger is created. - definer_user - [out] after a call it points to 0-terminated string, - which contains user name part of the actual trigger - definer. The caller is responsible to provide memory for + definer_user - [out] after a call it points to 0-terminated string or + contains the NULL-string: + - 0-terminated is returned if the trigger is SUID. The + string contains user name part of the actual trigger + definer. + - NULL-string is returned if the trigger is non-SUID. + Anyway, the caller is responsible to provide memory for storing LEX_STRING object. - definer_host - [out] after a call it points to 0-terminated string, - which contains host name part of the actual trigger - definer. The caller is responsible to provide memory for + definer_host - [out] after a call it points to 0-terminated string or + contains the NULL-string: + - 0-terminated string is returned if the trigger is + SUID. The string contains host name part of the + actual trigger definer. + - NULL-string is returned if the trigger is non-SUID. + Anyway, the caller is responsible to provide memory for storing LEX_STRING object. NOTE - Assumes that trigger name is fully qualified. + - Assumes that trigger name is fully qualified. + - NULL-string means the following LEX_STRING instance: + { str = 0; length = 0 }. + - In other words, definer_user and definer_host should contain + simultaneously NULL-strings (non-SUID/old trigger) or valid strings + (SUID/new trigger). RETURN VALUE False - success @@ -336,12 +359,30 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, return 1; } - /* - Definer attribute of the Lex instance is always set in sql_yacc.yy when - trigger is created. - */ + if (!lex->definer) + { + /* + DEFINER-clause is missing. - DBUG_ASSERT(lex->definer); + If we are in slave thread, this means that we received CREATE TRIGGER + from the master, that does not support definer in triggers. So, we + should mark this trigger as non-SUID. Note that this does not happen + when we parse triggers' definitions during opening .TRG file. + LEX::definer is ignored in that case. + + Otherwise, we should use CURRENT_USER() as definer. + + NOTE: when CREATE TRIGGER statement is allowed to be executed in PS/SP, + it will be required to create the definer below in persistent MEM_ROOT + of PS/SP. + */ + + if (!thd->slave_thread) + { + if (!(lex->definer= create_default_definer(thd))) + return 1; + } + } /* If the specified definer differs from the current user, we should check @@ -349,10 +390,11 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, under another user one must have SUPER privilege). */ - if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) || - my_strcasecmp(system_charset_info, - lex->definer->host.str, - thd->security_ctx->priv_host)) + if (lex->definer && + (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) || + my_strcasecmp(system_charset_info, + lex->definer->host.str, + thd->security_ctx->priv_host))) { if (check_global_access(thd, SUPER_ACL)) { @@ -446,8 +488,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, *trg_sql_mode= thd->variables.sql_mode; #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!is_acl_user(lex->definer->host.str, - lex->definer->user.str)) + if (lex->definer && !is_acl_user(lex->definer->host.str, + lex->definer->user.str)) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, @@ -458,12 +500,30 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, } #endif /* NO_EMBEDDED_ACCESS_CHECKS */ - *definer_user= lex->definer->user; - *definer_host= lex->definer->host; + if (lex->definer) + { + /* SUID trigger. */ + + *definer_user= lex->definer->user; + *definer_host= lex->definer->host; - trg_definer->str= trg_definer_holder; - trg_definer->length= strxmov(trg_definer->str, definer_user->str, "@", - definer_host->str, NullS) - trg_definer->str; + trg_definer->str= trg_definer_holder; + trg_definer->length= strxmov(trg_definer->str, definer_user->str, "@", + definer_host->str, NullS) - trg_definer->str; + } + else + { + /* non-SUID trigger. */ + + definer_user->str= 0; + definer_user->length= 0; + + definer_host->str= 0; + definer_host->length= 0; + + trg_definer->str= (char*) ""; + trg_definer->length= 0; + } if (!sql_create_definition_file(&dir, &file, &triggers_file_type, (gptr)this, triggers_file_parameters, 0)) diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 4f62a80cfd4..2178b5d00a8 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -208,6 +208,26 @@ bool mysql_create_view(THD *thd, if (mode != VIEW_CREATE_NEW) sp_cache_invalidate(); + if (!lex->definer) + { + /* + DEFINER-clause is missing; we have to create default definer in + persistent arena to be PS/SP friendly. + */ + + Query_arena original_arena; + Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena); + + if (!(lex->definer= create_default_definer(thd))) + res= TRUE; + + if (ps_arena) + thd->restore_active_arena(ps_arena, &original_arena); + + if (res) + goto err; + } + #ifndef NO_EMBEDDED_ACCESS_CHECKS /* check definer of view: diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index d6d2939bed3..7e93b9c8e73 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -778,7 +778,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <symbol> FUNC_ARG0 FUNC_ARG1 FUNC_ARG2 FUNC_ARG3 keyword keyword_sp -%type <lex_user> user grant_user get_definer +%type <lex_user> user grant_user %type <charset> opt_collate @@ -8960,41 +8960,29 @@ subselect_end: }; definer: - get_definer + /* empty */ { - THD *thd= YYTHD; - - if (! (thd->lex->definer= create_definer(thd, &$1->user, &$1->host))) - YYABORT; + /* + We have to distinguish missing DEFINER-clause from case when + CURRENT_USER specified as definer explicitly in order to properly + handle CREATE TRIGGER statements which come to replication thread + from older master servers (i.e. to create non-suid trigger in this + case). + */ + YYTHD->lex->definer= 0; } - ; - -get_definer: - opt_current_definer + | DEFINER_SYM EQ CURRENT_USER optional_braces { - THD *thd= YYTHD; - - if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) - YYABORT; - - if (get_default_definer(thd, $$)) - YYABORT; + if (! (YYTHD->lex->definer= create_default_definer(YYTHD))) + YYABORT; } | DEFINER_SYM EQ ident_or_text '@' ident_or_text { - if (!($$=(LEX_USER*) YYTHD->alloc(sizeof(st_lex_user)))) - YYABORT; - - $$->user= $3; - $$->host= $5; + if (!(YYTHD->lex->definer= create_definer(YYTHD, &$3, &$5))) + YYABORT; } ; -opt_current_definer: - /* empty */ - | DEFINER_SYM EQ CURRENT_USER optional_braces - ; - /************************************************************************** CREATE VIEW statement options. |