1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Merge with next-mr-runtime.

This commit is contained in:
Konstantin Osipov
2009-10-22 12:46:07 +04:00
29 changed files with 830 additions and 240 deletions

View File

@ -46,7 +46,6 @@
"FUNCTION" : "PROCEDURE")
static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
static bool check_show_create_table_access(THD *thd, TABLE_LIST *table);
const char *any_db="*any*"; // Special symbol for check_access
@ -590,7 +589,7 @@ static bool check_merge_table_access(THD *thd, char *db,
tlist->db= db; /* purecov: inspected */
}
error= check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
table_list, UINT_MAX, FALSE);
table_list, FALSE, UINT_MAX, FALSE);
}
return error;
}
@ -1335,7 +1334,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
0, 0, test(table_list.schema_table)))
break;
if (check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
if (check_grant(thd, SELECT_ACL, &table_list, TRUE, UINT_MAX, FALSE))
break;
/* init structures for VIEW processing */
table_list.select_lex= &(thd->lex->select_lex);
@ -2194,14 +2193,16 @@ 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, UINT_MAX, FALSE)))
if (!(res= check_table_access(thd, SELECT_ACL, all_tables, FALSE,
UINT_MAX, FALSE)))
res= execute_sqlcom_select(thd, all_tables);
break;
case SQLCOM_SHOW_STATUS:
{
system_status_var old_status_var= thd->status_var;
thd->initial_status_var= &old_status_var;
if (!(res= check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE)))
if (!(res= check_table_access(thd, SELECT_ACL, all_tables, FALSE,
UINT_MAX, FALSE)))
res= execute_sqlcom_select(thd, all_tables);
/* Don't log SHOW STATUS commands to slow query log */
thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED |
@ -2231,18 +2232,22 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_STORAGE_ENGINES:
case SQLCOM_SHOW_PROFILE:
case SQLCOM_SELECT:
{
thd->status_var.last_query_cost= 0.0;
/*
lex->exchange != NULL implies SELECT .. INTO OUTFILE and this
requires FILE_ACL access.
*/
ulong privileges_requested= lex->exchange ? SELECT_ACL | FILE_ACL :
SELECT_ACL;
if (all_tables)
{
res= check_table_access(thd,
lex->exchange ? SELECT_ACL | FILE_ACL :
SELECT_ACL,
all_tables, UINT_MAX, FALSE);
}
privileges_requested,
all_tables, FALSE, UINT_MAX, FALSE);
else
res= check_access(thd,
lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
any_db, 0, 0, 0, 0);
res= check_access(thd, privileges_requested, any_db, 0, 0, 0, UINT_MAX);
if (res)
break;
@ -2253,7 +2258,8 @@ mysql_execute_command(THD *thd)
res= execute_sqlcom_select(thd, all_tables);
break;
case SQLCOM_PREPARE:
}
case SQLCOM_PREPARE:
{
mysql_sql_stmt_prepare(thd);
break;
@ -2269,8 +2275,8 @@ mysql_execute_command(THD *thd)
break;
}
case SQLCOM_DO:
if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
open_and_lock_tables(thd, all_tables))
if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)
|| open_and_lock_tables(thd, all_tables))
goto error;
res= mysql_do(thd, *lex->insert_list);
@ -2379,8 +2385,8 @@ mysql_execute_command(THD *thd)
case SQLCOM_BACKUP_TABLE:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
check_global_access(thd, FILE_ACL))
if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)
|| check_global_access(thd, FILE_ACL))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_backup_table(thd, first_table);
@ -2391,8 +2397,8 @@ mysql_execute_command(THD *thd)
case SQLCOM_RESTORE_TABLE:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_table_access(thd, INSERT_ACL, all_tables, UINT_MAX, FALSE) ||
check_global_access(thd, FILE_ACL))
if (check_table_access(thd, INSERT_ACL, all_tables, FALSE, UINT_MAX, FALSE)
|| check_global_access(thd, FILE_ACL))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_restore_table(thd, first_table);
@ -2491,7 +2497,7 @@ mysql_execute_command(THD *thd)
test(first_table->schema_table)))
goto error; /* purecov: inspected */
/* Check that the first table has CREATE privilege */
if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
if (check_grant(thd, CREATE_ACL, all_tables, FALSE, 1, FALSE))
goto error;
pthread_mutex_lock(&LOCK_active_mi);
@ -2861,7 +2867,7 @@ end_with_restore_list:
(TABLE_LIST *)
create_info.merge_list.first))
goto error; /* purecov: inspected */
if (check_grant(thd, priv_needed, all_tables, 0, UINT_MAX, 0))
if (check_grant(thd, priv_needed, all_tables, FALSE, UINT_MAX, FALSE))
goto error;
if (lex->name.str && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
{ // Rename of table
@ -2870,8 +2876,8 @@ end_with_restore_list:
tmp_table.table_name= lex->name.str;
tmp_table.db=select_lex->db;
tmp_table.grant.privilege=priv;
if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
UINT_MAX, 0))
if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, FALSE,
UINT_MAX, FALSE))
goto error;
}
@ -2925,10 +2931,11 @@ end_with_restore_list:
*/
old_list= table[0];
new_list= table->next_local[0];
if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, 0, 1, 0) ||
if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, FALSE, 1, FALSE) ||
(!test_all_bits(table->next_local->grant.privilege,
INSERT_ACL | CREATE_ACL) &&
check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0)))
check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, FALSE, 1,
FALSE)))
goto error;
}
@ -2959,11 +2966,54 @@ end_with_restore_list:
goto error;
#else
{
/* Ignore temporary tables if this is "SHOW CREATE VIEW" */
/*
Access check:
SHOW CREATE TABLE require any privileges on the table level (ie
effecting all columns in the table).
SHOW CREATE VIEW require the SHOW_VIEW and SELECT ACLs on the table
level.
NOTE: SHOW_VIEW ACL is checked when the view is created.
*/
if (lex->only_view)
{
if (check_table_access(thd, SELECT_ACL, first_table, FALSE, 1, FALSE))
{
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
"SHOW", thd->security_ctx->priv_user,
thd->security_ctx->host_or_ip, first_table->alias);
goto error;
}
/* Ignore temporary tables if this is "SHOW CREATE VIEW" */
first_table->skip_temporary= 1;
if (check_show_create_table_access(thd, first_table))
goto error;
}
else
{
ulong save_priv;
if (check_access(thd, SELECT_ACL, first_table->db,
&save_priv, FALSE, FALSE,
test(first_table->schema_table)))
goto error;
/*
save_priv contains any privileges actually granted by check_access.
If there are no global privileges (save_priv == 0) and no table level
privileges, access is denied.
*/
if (!save_priv &&
!has_any_table_level_privileges(thd, TABLE_ACLS,
first_table))
{
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
"SHOW", thd->security_ctx->priv_user,
thd->security_ctx->host_or_ip, first_table->alias);
goto error;
}
}
/*
Access is granted. Execute command.
*/
res= mysqld_show_create(thd, first_table);
break;
}
@ -2971,8 +3021,8 @@ end_with_restore_list:
case SQLCOM_CHECKSUM:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables,
UINT_MAX, FALSE))
if (check_table_access(thd, SELECT_ACL, all_tables,
FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
res = mysql_checksum_table(thd, first_table, &lex->check_opt);
break;
@ -2981,7 +3031,7 @@ end_with_restore_list:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
UINT_MAX, FALSE))
FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res= mysql_repair_table(thd, first_table, &lex->check_opt);
@ -3000,8 +3050,8 @@ end_with_restore_list:
case SQLCOM_CHECK:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables,
UINT_MAX, FALSE))
if (check_table_access(thd, SELECT_ACL, all_tables,
TRUE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_check_table(thd, first_table, &lex->check_opt);
@ -3013,7 +3063,7 @@ end_with_restore_list:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
UINT_MAX, FALSE))
FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res= mysql_analyze_table(thd, first_table, &lex->check_opt);
@ -3034,7 +3084,7 @@ end_with_restore_list:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
UINT_MAX, FALSE))
FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
@ -3407,7 +3457,7 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (!lex->drop_temporary)
{
if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE))
if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
if (end_active_trans(thd))
goto error;
@ -3515,8 +3565,8 @@ end_with_restore_list:
if (lex->autocommit && end_active_trans(thd))
goto error;
if ((check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
open_and_lock_tables(thd, all_tables)))
if ((check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)
|| open_and_lock_tables(thd, all_tables)))
goto error;
if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
{
@ -3570,7 +3620,7 @@ end_with_restore_list:
if (end_active_trans(thd))
goto error;
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
UINT_MAX, FALSE))
FALSE, UINT_MAX, FALSE))
goto error;
if (lex->protect_against_global_read_lock &&
!(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
@ -3966,7 +4016,7 @@ end_with_restore_list:
else
{
if (check_grant(thd,(lex->grant | lex->grant_tot_col | GRANT_ACL),
all_tables, 0, UINT_MAX, 0))
all_tables, FALSE, UINT_MAX, FALSE))
goto error;
/* Conditionally writes to binlog */
res= mysql_table_grant(thd, all_tables, lex->users_list,
@ -4075,7 +4125,7 @@ end_with_restore_list:
#endif
case SQLCOM_HA_OPEN:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE))
if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE))
goto error;
res= mysql_ha_open(thd, first_table, 0);
break;
@ -4361,7 +4411,8 @@ create_sp_error:
This will cache all SP and SF and open and lock all tables
required for execution.
*/
if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
if (check_table_access(thd, SELECT_ACL, all_tables, FALSE,
UINT_MAX, FALSE) ||
open_and_lock_tables(thd, all_tables))
goto error;
@ -4689,8 +4740,8 @@ create_sp_error:
}
case SQLCOM_DROP_VIEW:
{
if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE) ||
end_active_trans(thd))
if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE)
|| end_active_trans(thd))
goto error;
/* Conditionally writes to binlog. */
res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
@ -5139,7 +5190,7 @@ bool check_single_table_access(THD *thd, ulong privilege,
(thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
!(all_tables->view &&
all_tables->effective_algorithm == VIEW_ALGORITHM_TMPTABLE) &&
check_grant(thd, privilege, all_tables, 0, 1, no_errors))
check_grant(thd, privilege, all_tables, FALSE, 1, no_errors))
goto deny;
thd->security_ctx= backup_ctx;
@ -5184,7 +5235,8 @@ bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
subselects_tables= subselects_tables->next_global;
}
if (subselects_tables &&
(check_table_access(thd, SELECT_ACL, subselects_tables, UINT_MAX, FALSE)))
(check_table_access(thd, SELECT_ACL, subselects_tables, FALSE,
UINT_MAX, FALSE)))
return 1;
}
return 0;
@ -5192,46 +5244,54 @@ bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
/**
Get the user (global) and database privileges for all used tables.
@brief Compare requested privileges with the privileges acquired from the
User- and Db-tables.
@param thd Thread handler
@param want_access The requested access privileges.
@param db A pointer to the Db name.
@param[out] save_priv A pointer to the granted privileges will be stored.
@param dont_check_global_grants True if no global grants are checked.
@param no_error True if no errors should be sent to the client.
@param schema_db True if the db specified belongs to the meta data tables.
@param save_priv In this we store global and db level grants for the
table. Note that we don't store db level grants if the
global grants is enough to satisfy the request and the
global grants contains a SELECT grant.
'save_priv' is used to save the User-table (global) and Db-table grants for
the supplied db name. Note that we don't store db level grants if the global
grants is enough to satisfy the request AND the global grants contains a
SELECT grant.
@note
The idea of EXTRA_ACL is that one will be granted access to the table if
one has the asked privilege on any column combination of the table; For
example to be able to check a table one needs to have SELECT privilege on
any column of the table.
A meta data table (from INFORMATION_SCHEMA) can always be accessed with
a SELECT_ACL.
@retval
0 ok
@retval
1 If we can't get the privileges and we don't use table/column
grants.
@see check_grant
@return Status of denial of access by exclusive ACLs.
@retval FALSE Access can't exclusively be denied by Db- and User-table
access unless Column- and Table-grants are checked too.
@retval TRUE Access denied.
*/
bool
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
bool dont_check_global_grants, bool no_errors, bool schema_db)
{
Security_context *sctx= thd->security_ctx;
ulong db_access;
/*
GRANT command:
In case of database level grant the database name may be a pattern,
in case of table|column level grant the database name can not be a pattern.
We use 'dont_check_global_grants' as a flag to determine
if it's database level grant command
if it's database level grant command
(see SQLCOM_GRANT case, mysql_execute_command() function) and
set db_is_pattern according to 'dont_check_global_grants' value.
*/
bool db_is_pattern= (test(want_access & GRANT_ACL) &&
dont_check_global_grants);
bool db_is_pattern= ((want_access & GRANT_ACL) && dont_check_global_grants);
ulong dummy;
DBUG_ENTER("check_access");
DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
db ? db : "", want_access, sctx->master_access));
if (save_priv)
*save_priv=0;
else
@ -5249,8 +5309,12 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if (schema_db)
{
if ((!(sctx->master_access & FILE_ACL) && (want_access & FILE_ACL)) ||
(want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
/*
We don't allow any simple privileges but SELECT_ACL or CREATE_VIEW_ACL
on the information_schema database.
*/
want_access &= ~SELECT_ACL;
if (want_access & DB_ACLS)
{
if (!no_errors)
{
@ -5258,10 +5322,15 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
sctx->priv_user, sctx->priv_host, db_name);
}
/*
Access denied;
[out] *save_privileges= 0
*/
DBUG_RETURN(TRUE);
}
else
{
/* Access granted */
*save_priv= SELECT_ACL;
DBUG_RETURN(FALSE);
}
@ -5269,20 +5338,27 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if ((sctx->master_access & want_access) == want_access)
{
/*
If we don't have a global SELECT privilege, we have to get the database
specific access rights to be able to handle queries of type
UPDATE t1 SET a=1 WHERE b > 0
*/
/* get access for current db */
db_access= sctx->db_access;
/*
1. If we don't have a global SELECT privilege, we have to get the
database specific access rights to be able to handle queries of type
UPDATE t1 SET a=1 WHERE b > 0
2. Change db access if it isn't current db which is being addressed
*/
if (!(sctx->master_access & SELECT_ACL) &&
(db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
db_access=acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
db_is_pattern);
/*
The effective privileges are the union of the global privileges
and the the intersection of db- and host-privileges.
*/
*save_priv=sctx->master_access | db_access;
DBUG_RETURN(FALSE);
}
if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
if (((want_access & ~sctx->master_access) & ~DB_ACLS) ||
(! db && dont_check_global_grants))
{ // We can never grant this
DBUG_PRINT("error",("No possible access"));
@ -5297,33 +5373,66 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
}
if (db == any_db)
DBUG_RETURN(FALSE); // Allow select on anything
{
/*
Access granted; Allow select on *any* db.
[out] *save_privileges= 0
*/
DBUG_RETURN(FALSE);
}
if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
db_is_pattern);
else
db_access= sctx->db_access;
DBUG_PRINT("info",("db_access: %lu", db_access));
/* Remove SHOW attribute and access rights we already have */
want_access &= ~(sctx->master_access | EXTRA_ACL);
DBUG_PRINT("info",("db_access: %lu want_access: %lu",
db_access, want_access));
db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access);
if (db_access == want_access ||
/*
Save the union of User-table and the intersection between Db-table and
Host-table privileges.
*/
db_access= (db_access | sctx->master_access);
*save_priv= db_access;
/*
We need to investigate column- and table access if all requested privileges
belongs to the bit set of .
*/
bool need_table_or_column_check=
(want_access & (TABLE_ACLS | PROC_ACLS | db_access)) == want_access;
/*
Grant access if the requested access is in the intersection of
host- and db-privileges (as retrieved from the acl cache),
also grant access if all the requested privileges are in the union of
TABLES_ACLS and PROC_ACLS; see check_grant.
*/
if ( (db_access & want_access) == want_access ||
(!dont_check_global_grants &&
!(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
DBUG_RETURN(FALSE); /* Ok */
need_table_or_column_check))
{
/*
Ok; but need to check table- and column privileges.
[out] *save_privileges is (User-priv | (Db-priv & Host-priv))
*/
DBUG_RETURN(FALSE);
}
/*
Access is denied;
[out] *save_privileges is (User-priv | (Db-priv & Host-priv))
*/
DBUG_PRINT("error",("Access denied"));
if (!no_errors)
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
sctx->priv_user, sctx->priv_host,
(db ? db : (thd->db ?
thd->db :
"unknown"))); /* purecov: tested */
DBUG_RETURN(TRUE); /* purecov: tested */
"unknown")));
DBUG_RETURN(TRUE);
}
@ -5369,14 +5478,20 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
DBUG_ASSERT(dst_table);
if (check_access(thd, SELECT_ACL | EXTRA_ACL,
dst_table->db,
&dst_table->grant.privilege,
FALSE, FALSE,
if (check_access(thd, SELECT_ACL, dst_table->db,
&dst_table->grant.privilege, FALSE, FALSE,
test(dst_table->schema_table)))
return FALSE;
return TRUE; /* Access denied */
return (check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE));
/*
Check_grant will grant access if there is any column privileges on
all of the tables thanks to the fourth parameter (bool show_table).
*/
if (check_grant(thd, SELECT_ACL, dst_table, TRUE, UINT_MAX, FALSE))
return TRUE; /* Access denied */
/* Access granted */
return FALSE;
}
default:
break;
@ -5386,30 +5501,46 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
}
/**
Check the privilege for all used tables.
@brief Check if the requested privileges exists in either User-, Host- or
Db-tables.
@param thd Thread context
@param want_access Privileges requested
@param tables List of tables to be compared against
@param no_errors Don't report error to the client (using my_error() call).
@param any_combination_of_privileges_will_do TRUE if any privileges on any
column combination is enough.
@param number Only the first 'number' tables in the linked list are
relevant.
@param thd Thread context
@param want_access Privileges requested
@param tables List of tables to be checked
@param number Check at most this number of tables.
@param no_errors FALSE/TRUE - report/don't report error to
the client (using my_error() call).
The suppled table list contains cached privileges. This functions calls the
help functions check_access and check_grant to verify the first three steps
in the privileges check queue:
1. Global privileges
2. OR (db privileges AND host privileges)
3. OR table privileges
4. OR column privileges (not checked by this function!)
5. OR routine privileges (not checked by this function!)
@note
Table privileges are cached in the table list for GRANT checking.
This functions assumes that table list used and
thd->lex->query_tables_own_last value correspond to each other
(the latter should be either 0 or point to next_global member
of one of elements of this table list).
@see check_access
@see check_grant
@retval FALSE OK
@retval TRUE Access denied
@note This functions assumes that table list used and
thd->lex->query_tables_own_last value correspond to each other
(the latter should be either 0 or point to next_global member
of one of elements of this table list).
@return
@retval FALSE OK
@retval TRUE Access denied; But column or routine privileges might need to
be checked also.
*/
bool
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
uint number, bool no_errors)
check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
bool any_combination_of_privileges_will_do,
uint number, bool no_errors)
{
TABLE_LIST *org_tables= tables;
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
@ -5420,22 +5551,31 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
the given table list refers to the list for prelocking (contains tables
of other queries). For simple queries first_not_own_table is 0.
*/
for (; i < number && tables != first_not_own_table;
for (; i < number && tables != first_not_own_table && tables;
tables= tables->next_global, i++)
{
ulong want_access= requirements;
if (tables->security_ctx)
sctx= tables->security_ctx;
else
sctx= backup_ctx;
if (tables->schema_table &&
(want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
/*
Always allow SELECT on schema tables. This is done by removing the
required SELECT_ACL privilege in the want_access parameter.
Disallow any other DDL or DML operation on any schema table.
*/
if (tables->schema_table)
{
if (!no_errors)
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
sctx->priv_user, sctx->priv_host,
INFORMATION_SCHEMA_NAME.str);
return TRUE;
want_access &= ~SELECT_ACL;
if (want_access & DB_ACLS)
{
if (!no_errors)
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
sctx->priv_user, sctx->priv_host,
INFORMATION_SCHEMA_NAME.str);
goto deny;
}
}
/*
Register access for view underlying table.
@ -5447,33 +5587,34 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
{
if (check_show_access(thd, tables))
goto deny;
continue;
}
DBUG_PRINT("info", ("derived: %d view: %d", tables->derived != 0,
tables->view != 0));
if (tables->is_anonymous_derived_table() ||
(tables->table && (int)tables->table->s->tmp_table))
(tables->table && tables->table->s &&
(int)tables->table->s->tmp_table))
continue;
thd->security_ctx= sctx;
if ((sctx->master_access & want_access) ==
(want_access & ~EXTRA_ACL) &&
thd->db)
if ((sctx->master_access & want_access) == want_access &&
thd->db)
tables->grant.privilege= want_access;
else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0)
{
if (check_access(thd, want_access, tables->get_db_name(),
&tables->grant.privilege, 0, no_errors,
&tables->grant.privilege, 0, no_errors,
test(tables->schema_table)))
goto deny; // Access denied
}
else if (check_access(thd, want_access, tables->get_db_name(),
&tables->grant.privilege, 0, no_errors,
test(tables->schema_table)))
&tables->grant.privilege, 0, no_errors, 0))
goto deny;
}
thd->security_ctx= backup_ctx;
return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
test(want_access & EXTRA_ACL), number, no_errors);
return check_grant(thd,requirements,org_tables,
any_combination_of_privileges_will_do,
number, no_errors);
deny:
thd->security_ctx= backup_ctx;
return TRUE;
@ -5561,7 +5702,7 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
if (!check_access(thd, access, table->db,
&table->grant.privilege, 0, 1,
test(table->schema_table)) &&
!check_grant(thd, access, table, 0, 1, 1))
!check_grant(thd, access, table, FALSE, 1, TRUE))
DBUG_RETURN(0);
}
}
@ -7254,11 +7395,11 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
else if ((check_access(thd, UPDATE_ACL, table->db,
&table->grant.privilege, 0, 1,
test(table->schema_table)) ||
check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
check_grant(thd, UPDATE_ACL, table, FALSE, 1, TRUE)) &&
(check_access(thd, SELECT_ACL, table->db,
&table->grant.privilege, 0, 0,
test(table->schema_table)) ||
check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
check_grant(thd, SELECT_ACL, table, FALSE, 1, FALSE)))
DBUG_RETURN(TRUE);
table->table_in_first_from_clause= 1;
@ -7276,7 +7417,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
if (check_access(thd, SELECT_ACL, table->db,
&table->grant.privilege, 0, 0,
test(table->schema_table)) ||
check_grant(thd, SELECT_ACL, table, 0, 1, 0))
check_grant(thd, SELECT_ACL, table, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
}
}
@ -7316,7 +7457,7 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
/* sql_yacc guarantees that tables and aux_tables are not zero */
DBUG_ASSERT(aux_tables != 0);
if (check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE))
DBUG_RETURN(TRUE);
/*
@ -7325,7 +7466,7 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
call check_table_access() safely.
*/
thd->lex->query_tables_own_last= 0;
if (check_table_access(thd, DELETE_ACL, aux_tables, UINT_MAX, FALSE))
if (check_table_access(thd, DELETE_ACL, aux_tables, FALSE, UINT_MAX, FALSE))
{
thd->lex->query_tables_own_last= save_query_tables_own_last;
DBUG_RETURN(TRUE);
@ -7478,25 +7619,6 @@ bool insert_precheck(THD *thd, TABLE_LIST *tables)
}
/**
@brief Check privileges for SHOW CREATE TABLE statement.
@param thd Thread context
@param table Target table
@retval TRUE Failure
@retval FALSE Success
*/
static bool check_show_create_table_access(THD *thd, TABLE_LIST *table)
{
return check_access(thd, SELECT_ACL | EXTRA_ACL, table->db,
&table->grant.privilege, 0, 0,
test(table->schema_table)) ||
check_grant(thd, SELECT_ACL, table, 2, UINT_MAX, 0);
}
/**
CREATE TABLE query pre-check.
@ -7536,7 +7658,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
lex->create_info.merge_list.first))
goto err;
if (want_priv != CREATE_TMP_ACL &&
check_grant(thd, want_priv, create_table, 0, 1, 0))
check_grant(thd, want_priv, create_table, FALSE, 1, FALSE))
goto err;
if (select_lex->item_list.elements)
@ -7564,12 +7686,13 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
}
}
#endif
if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
if (tables && check_table_access(thd, SELECT_ACL, tables, FALSE,
UINT_MAX, FALSE))
goto err;
}
else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
{
if (check_show_create_table_access(thd, tables))
if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE))
goto err;
}
error= FALSE;