1
0
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:
unknown
2013-06-27 17:42:18 +03:00
parent 94d722b6a4
commit 70092601bc
13 changed files with 168 additions and 81 deletions

View File

@ -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.