diff options
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 124 |
1 files changed, 117 insertions, 7 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b389e591bc0..87810a65b0f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1297,6 +1297,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->enable_slow_log= TRUE; thd->query_plan_flags= QPLAN_INIT; thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ + thd->reset_kill_query(); DEBUG_SYNC(thd,"dispatch_command_before_set_time"); @@ -5560,11 +5561,7 @@ finish: if (! thd->get_stmt_da()->is_set()) thd->send_kill_message(); } - if (thd->killed < KILL_CONNECTION) - { - thd->reset_killed(); - thd->mysys_var->abort= 0; - } + thd->reset_kill_query(); } if (thd->is_error() || (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR)) trans_rollback_stmt(thd); @@ -6456,6 +6453,115 @@ bool check_global_access(THD *thd, ulong want_access, bool no_errors) #endif } + +/** + Checks foreign key's parent table access. + + @param thd [in] Thread handler + @param create_info [in] Create information (like MAX_ROWS, ENGINE or + temporary table flag) + @param alter_info [in] Initial list of columns and indexes for the + table to be created + + @retval + false ok. + @retval + true error or access denied. Error is sent to client in this case. +*/ +bool check_fk_parent_table_access(THD *thd, + HA_CREATE_INFO *create_info, + Alter_info *alter_info) +{ + Key *key; + List_iterator<Key> key_iterator(alter_info->key_list); + + while ((key= key_iterator++)) + { + if (key->type == Key::FOREIGN_KEY) + { + TABLE_LIST parent_table; + bool is_qualified_table_name; + Foreign_key *fk_key= (Foreign_key *)key; + LEX_STRING db_name; + LEX_STRING table_name= { fk_key->ref_table.str, + fk_key->ref_table.length }; + const ulong privileges= (SELECT_ACL | INSERT_ACL | UPDATE_ACL | + DELETE_ACL | REFERENCES_ACL); + + // Check if tablename is valid or not. + DBUG_ASSERT(table_name.str != NULL); + if (check_table_name(table_name.str, table_name.length, false)) + { + my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str); + return true; + } + + if (fk_key->ref_db.str) + { + is_qualified_table_name= true; + db_name.str= (char *) thd->memdup(fk_key->ref_db.str, + fk_key->ref_db.length+1); + db_name.length= fk_key->ref_db.length; + + // Check if database name is valid or not. + if (fk_key->ref_db.str && check_db_name(&db_name)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); + return true; + } + } + else if (thd->lex->copy_db_to(&db_name.str, &db_name.length)) + return true; + else + is_qualified_table_name= false; + + // if lower_case_table_names is set then convert tablename to lower case. + if (lower_case_table_names) + { + table_name.str= (char *) thd->memdup(fk_key->ref_table.str, + fk_key->ref_table.length+1); + table_name.length= my_casedn_str(files_charset_info, table_name.str); + } + + parent_table.init_one_table(db_name.str, db_name.length, + table_name.str, table_name.length, + table_name.str, TL_IGNORE); + + /* + Check if user has any of the "privileges" at table level on + "parent_table". + Having privilege on any of the parent_table column is not + enough so checking whether user has any of the "privileges" + at table level only here. + */ + if (check_some_access(thd, privileges, &parent_table) || + parent_table.grant.want_privilege) + { + if (is_qualified_table_name) + { + const size_t qualified_table_name_len= NAME_LEN + 1 + NAME_LEN + 1; + char *qualified_table_name= (char *) thd->alloc(qualified_table_name_len); + + my_snprintf(qualified_table_name, qualified_table_name_len, "%s.%s", + db_name.str, table_name.str); + table_name.str= qualified_table_name; + } + + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), + "REFERENCES", + thd->security_ctx->priv_user, + thd->security_ctx->host_or_ip, + table_name.str); + + return true; + } + } + } + + return false; +} + + /**************************************************************************** Check stack size; Send error if there isn't enough stack to continue ****************************************************************************/ @@ -7995,7 +8101,7 @@ static uint kill_threads_for_user(THD *thd, LEX_USER *user, host.str[0] == '%' means that host name was not given. See sql_yacc.yy */ if (((user->host.str[0] == '%' && !user->host.str[1]) || - !strcmp(tmp->security_ctx->host, user->host.str)) && + !strcmp(tmp->security_ctx->host_or_ip, user->host.str)) && !strcmp(tmp->security_ctx->user, user->user.str)) { if (!(thd->security_ctx->master_access & SUPER_ACL) && @@ -8651,7 +8757,9 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)) goto err; } - error= FALSE; + + if (check_fk_parent_table_access(thd, &lex->create_info, &lex->alter_info)) + goto err; /* For CREATE TABLE we should not open the table even if it exists. @@ -8659,6 +8767,8 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, */ lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB; + error= FALSE; + err: DBUG_RETURN(error); } |