mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
merge of 2876.430.11 & 2876.430.1
CF_PREOPEN_TMP_TABLES & CF_HA_CLOSE & Patch for Bug#11746602 (27480: Extend CREATE TEMPORARY TABLES privilege to allow temp table operations).
This commit is contained in:
122
sql/sql_parse.cc
122
sql/sql_parse.cc
@ -24,7 +24,7 @@
|
||||
// set_handler_table_locks,
|
||||
// lock_global_read_lock,
|
||||
// make_global_read_lock_block_commit
|
||||
#include "sql_base.h" // find_temporary_tablesx
|
||||
#include "sql_base.h" // find_temporary_table
|
||||
#include "sql_cache.h" // QUERY_CACHE_FLAGS_SIZE, query_cache_*
|
||||
#include "sql_show.h" // mysqld_list_*, mysqld_show_*,
|
||||
// calc_sum_of_all_status
|
||||
@ -44,7 +44,6 @@
|
||||
#include "sql_table.h" // mysql_create_like_table,
|
||||
// mysql_create_table,
|
||||
// mysql_alter_table,
|
||||
// mysql_recreate_table,
|
||||
// mysql_backup_table,
|
||||
// mysql_restore_table
|
||||
#include "sql_reload.h" // reload_acl_and_cache
|
||||
@ -124,6 +123,7 @@ static void sql_kill(THD *thd, ulong id, killed_state state);
|
||||
static void sql_kill_user(THD *thd, LEX_USER *user, killed_state state);
|
||||
static bool execute_show_status(THD *, TABLE_LIST *);
|
||||
static bool execute_rename_table(THD *, TABLE_LIST *, TABLE_LIST *);
|
||||
static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables);
|
||||
|
||||
const char *any_db="*any*"; // Special symbol for check_access
|
||||
|
||||
@ -499,6 +499,7 @@ void init_update_queries(void)
|
||||
sql_command_flags[SQLCOM_SELECT]|= CF_PREOPEN_TMP_TABLES;
|
||||
sql_command_flags[SQLCOM_SET_OPTION]|= CF_PREOPEN_TMP_TABLES;
|
||||
sql_command_flags[SQLCOM_DO]|= CF_PREOPEN_TMP_TABLES;
|
||||
sql_command_flags[SQLCOM_HA_OPEN]|= CF_PREOPEN_TMP_TABLES;
|
||||
sql_command_flags[SQLCOM_CALL]|= CF_PREOPEN_TMP_TABLES;
|
||||
sql_command_flags[SQLCOM_CHECKSUM]|= CF_PREOPEN_TMP_TABLES;
|
||||
sql_command_flags[SQLCOM_ANALYZE]|= CF_PREOPEN_TMP_TABLES;
|
||||
@ -2413,6 +2414,7 @@ mysql_execute_command(THD *thd)
|
||||
if (open_temporary_tables(thd, all_tables))
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch (lex->sql_command) {
|
||||
|
||||
case SQLCOM_SHOW_EVENTS:
|
||||
@ -2422,8 +2424,7 @@ mysql_execute_command(THD *thd)
|
||||
#endif
|
||||
case SQLCOM_SHOW_STATUS_PROC:
|
||||
case SQLCOM_SHOW_STATUS_FUNC:
|
||||
if ((res= check_table_access(thd, SELECT_ACL, all_tables, FALSE,
|
||||
UINT_MAX, FALSE)))
|
||||
if (lock_tables_precheck(thd, all_tables))
|
||||
goto error;
|
||||
res= execute_sqlcom_select(thd, all_tables);
|
||||
break;
|
||||
@ -2798,12 +2799,6 @@ case SQLCOM_PREPARE:
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Close any open handlers for the table. We need to this extra call here
|
||||
as there may have been new handlers created since the previous call.
|
||||
*/
|
||||
mysql_ha_rm_tables(thd, create_table);
|
||||
|
||||
if (select_lex->item_list.elements) // With select
|
||||
{
|
||||
select_result *result;
|
||||
@ -4173,6 +4168,9 @@ end_with_restore_list:
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE))
|
||||
goto error;
|
||||
/* Close temporary tables which were pre-opened for privilege checking. */
|
||||
close_thread_tables(thd);
|
||||
all_tables->table= NULL;
|
||||
res= mysql_ha_open(thd, first_table, 0);
|
||||
break;
|
||||
case SQLCOM_HA_CLOSE:
|
||||
@ -5519,6 +5517,9 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
|
||||
if (check_grant(thd, SELECT_ACL, dst_table, TRUE, UINT_MAX, FALSE))
|
||||
return TRUE; /* Access denied */
|
||||
|
||||
close_thread_tables(thd);
|
||||
dst_table->table= NULL;
|
||||
|
||||
/* Access granted */
|
||||
return FALSE;
|
||||
}
|
||||
@ -5604,10 +5605,10 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
|
||||
|
||||
DBUG_PRINT("info", ("derived: %d view: %d", tables->derived != 0,
|
||||
tables->view != 0));
|
||||
if (tables->is_anonymous_derived_table() ||
|
||||
(tables->table && tables->table->s &&
|
||||
(int)tables->table->s->tmp_table))
|
||||
|
||||
if (tables->is_anonymous_derived_table())
|
||||
continue;
|
||||
|
||||
thd->security_ctx= sctx;
|
||||
|
||||
if (check_access(thd, want_access, tables->get_db_name(),
|
||||
@ -7465,6 +7466,19 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
|
||||
TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
|
||||
DBUG_ENTER("multi_delete_precheck");
|
||||
|
||||
/*
|
||||
Temporary tables are pre-opened in 'tables' list only. Here we need to
|
||||
initialize TABLE instances in 'aux_tables' list.
|
||||
*/
|
||||
for (TABLE_LIST *tl= aux_tables; tl; tl= tl->next_global)
|
||||
{
|
||||
if (tl->table)
|
||||
continue;
|
||||
|
||||
if (tl->correspondent_table)
|
||||
tl->table= tl->correspondent_table->table;
|
||||
}
|
||||
|
||||
/* sql_yacc guarantees that tables and aux_tables are not zero */
|
||||
DBUG_ASSERT(aux_tables != 0);
|
||||
if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE))
|
||||
@ -7733,9 +7747,9 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
|
||||
CREATE TABLE ... SELECT, also require INSERT.
|
||||
*/
|
||||
|
||||
want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
|
||||
CREATE_TMP_ACL : CREATE_ACL) |
|
||||
(select_lex->item_list.elements ? INSERT_ACL : 0);
|
||||
want_priv= (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
|
||||
CREATE_TMP_ACL :
|
||||
(CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : 0));
|
||||
|
||||
if (check_access(thd, want_priv, create_table->db,
|
||||
&create_table->grant.privilege,
|
||||
@ -7744,11 +7758,48 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
|
||||
goto err;
|
||||
|
||||
/* If it is a merge table, check privileges for merge children. */
|
||||
if (lex->create_info.merge_list.first &&
|
||||
check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
|
||||
lex->create_info.merge_list.first,
|
||||
FALSE, UINT_MAX, FALSE))
|
||||
goto err;
|
||||
if (lex->create_info.merge_list.first)
|
||||
{
|
||||
/*
|
||||
The user must have (SELECT_ACL | UPDATE_ACL | DELETE_ACL) on the
|
||||
underlying base tables, even if there are temporary tables with the same
|
||||
names.
|
||||
|
||||
From user's point of view, it might look as if the user must have these
|
||||
privileges on temporary tables to create a merge table over them. This is
|
||||
one of two cases when a set of privileges is required for operations on
|
||||
temporary tables (see also CREATE TABLE).
|
||||
|
||||
The reason for this behavior stems from the following facts:
|
||||
|
||||
- For merge tables, the underlying table privileges are checked only
|
||||
at CREATE TABLE / ALTER TABLE time.
|
||||
|
||||
In other words, once a merge table is created, the privileges of
|
||||
the underlying tables can be revoked, but the user will still have
|
||||
access to the merge table (provided that the user has privileges on
|
||||
the merge table itself).
|
||||
|
||||
- Temporary tables shadow base tables.
|
||||
|
||||
I.e. there might be temporary and base tables with the same name, and
|
||||
the temporary table takes the precedence in all operations.
|
||||
|
||||
- For temporary MERGE tables we do not track if their child tables are
|
||||
base or temporary. As result we can't guarantee that privilege check
|
||||
which was done in presence of temporary child will stay relevant later
|
||||
as this temporary table might be removed.
|
||||
|
||||
If SELECT_ACL | UPDATE_ACL | DELETE_ACL privileges were not checked for
|
||||
the underlying *base* tables, it would create a security breach as in
|
||||
Bug#12771903.
|
||||
*/
|
||||
|
||||
if (check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
|
||||
lex->create_info.merge_list.first,
|
||||
FALSE, UINT_MAX, FALSE))
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (want_priv != CREATE_TMP_ACL &&
|
||||
check_grant(thd, want_priv, create_table, FALSE, 1, FALSE))
|
||||
@ -7773,6 +7824,35 @@ err:
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check privileges for LOCK TABLES statement.
|
||||
|
||||
@param thd Thread context.
|
||||
@param tables List of tables to be locked.
|
||||
|
||||
@retval FALSE - Success.
|
||||
@retval TRUE - Failure.
|
||||
*/
|
||||
|
||||
static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables)
|
||||
{
|
||||
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
|
||||
|
||||
for (TABLE_LIST *table= tables; table != first_not_own_table && table;
|
||||
table= table->next_global)
|
||||
{
|
||||
if (is_temporary_table(table))
|
||||
continue;
|
||||
|
||||
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, table,
|
||||
FALSE, 1, FALSE))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
negate given expression.
|
||||
|
||||
|
Reference in New Issue
Block a user