1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-27 18:02:13 +03:00

Bug#27145 EXTRA_ACL troubles

The flag EXTRA_ACL is used in conjugation with our access checks, yet it is
not clear what impact this flag has.
This is a code clean up which replaces use of EXTRA_ACL with an explicit
function parameter.
The patch also fixes privilege checks for:
- SHOW CREATE TABLE: The new privilege requirement is any privilege on
  the table-level.
- CHECKSUM TABLE: Requires SELECT on the table level.
- SHOW CREATE VIEW: Requires SHOW_VIEW and SELECT on the table level
  (just as the manual claims)
- SHOW INDEX: Requires any privilege on any column combination.
This commit is contained in:
Kristofer Pettersson
2009-10-19 14:58:13 +02:00
parent 4863e5ceb8
commit b5559f5305
23 changed files with 751 additions and 235 deletions

View File

@ -1879,7 +1879,7 @@ static bool test_if_create_new_users(THD *thd)
sctx->priv_user, tl.db, 0);
if (!(db_access & INSERT_ACL))
{
if (check_grant(thd, INSERT_ACL, &tl, 0, UINT_MAX, 1))
if (check_grant(thd, INSERT_ACL, &tl, FALSE, UINT_MAX, TRUE))
create_new_users=0;
}
}
@ -3835,40 +3835,52 @@ end:
DBUG_RETURN(return_val);
}
/****************************************************************************
Check table level grants
SYNOPSIS
bool check_grant()
thd Thread handler
want_access Bits of privileges user needs to have
tables List of tables to check. The user should have 'want_access'
to all tables in list.
show_table <> 0 if we are in show table. In this case it's enough to have
any privilege for the table
number Check at most this number of tables.
no_errors If 0 then we write an error. The error is sent directly to
the client
/**
@brief Check table level grants
RETURN
0 ok
1 Error: User did not have the requested privileges
@param thd Thread handler
@param want_access Bits of privileges user needs to have.
@param tables List of tables to check. The user should have
'want_access' to all tables in list.
@param any_combination_will_do TRUE if it's enough to have any privilege for
any combination of the table columns.
@param number Check at most this number of tables.
@param no_errors TRUE if no error should be sent directly to the client.
NOTE
This functions assumes that either number of tables to be inspected
If table->grant.want_privilege != 0 then the requested privileges where
in the set of COL_ACLS but access was not granted on the table level. As
a consequence an extra check of column privileges is required.
Specifically if this function returns FALSE the user has some kind of
privilege on a combination of columns in each table.
This function is usually preceeded by check_access which establish the
User-, Db- and Host access rights.
@see check_access
@see check_table_access
@note This functions assumes that either number of tables to be inspected
by it is limited explicitly (i.e. is is not UINT_MAX) or 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 Access status
@retval FALSE Access granted; But column privileges might need to be
checked.
@retval TRUE The user did not have the requested privileges on any of the
tables.
*/
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
uint show_table, uint number, bool no_errors)
bool any_combination_will_do, uint number, bool no_errors)
{
TABLE_LIST *table, *first_not_own_table= thd->lex->first_not_own_table();
Security_context *sctx= thd->security_ctx;
uint i;
ulong orig_want_access= want_access;
DBUG_ENTER("check_grant");
DBUG_ASSERT(number > 0);
@ -3886,7 +3898,10 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
i < number && table != first_not_own_table;
table= table->next_global, i++)
{
/* Remove SHOW_VIEW_ACL, because it will be checked during making view */
/*
Save a copy of the privileges without the SHOW_VIEW_ACL attribute.
It will be checked during making view.
*/
table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
}
@ -3899,7 +3914,6 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
sctx = test(table->security_ctx) ?
table->security_ctx : thd->security_ctx;
want_access= orig_want_access;
want_access&= ~sctx->master_access;
if (!want_access)
continue; // ok
@ -3929,8 +3943,13 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
want_access &= ~table->grant.privilege;
goto err; // No grants
}
if (show_table)
continue; // We have some priv on this
/*
For SHOW COLUMNS, SHOW INDEX it is enough to have some
privileges on any column combination on the table.
*/
if (any_combination_will_do)
continue;
table->grant.grant_table=grant_table; // Remember for column test
table->grant.version=grant_version;
@ -3948,7 +3967,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
}
}
rw_unlock(&LOCK_grant);
DBUG_RETURN(0);
DBUG_RETURN(FALSE);
err:
rw_unlock(&LOCK_grant);
@ -3962,7 +3981,97 @@ err:
sctx->host_or_ip,
table ? table->get_table_name() : "unknown");
}
DBUG_RETURN(1);
DBUG_RETURN(TRUE);
}
/**
Check if all tables in the table list has any of the requested table level
privileges matching the current user.
@param thd A pointer to the thread context.
@param required_access Set of privileges to compare against.
@param tables[in,out] A list of tables to be checked.
@note If the table grant hash contains any grant table, this table will be
attached to the corresponding TABLE_LIST object in 'tables'.
@return
@retval TRUE There is a privilege on the table level granted to the
current user.
@retval FALSE There are no privileges on the table level granted to the
current user.
*/
bool has_any_table_level_privileges(THD *thd, ulong required_access,
TABLE_LIST *tables)
{
Security_context *sctx;
GRANT_TABLE *grant_table;
TABLE_LIST *table;
/* For each table in tables */
for (table= tables; table; table= table->next_global)
{
/*
If this table is a VIEW, then it will supply its own security context.
This is because VIEWs can have a DEFINER or an INVOKER security role.
*/
sctx= table->security_ctx ? table->security_ctx : thd->security_ctx;
/*
Get privileges from table_priv and column_priv tables by searching
the cache.
*/
rw_rdlock(&LOCK_grant);
grant_table= table_hash_search(sctx->host, sctx->ip,
table->db, sctx->priv_user,
table->table_name,0);
rw_unlock(&LOCK_grant);
/* Stop if there are no grants for the current user */
if (!grant_table)
return FALSE;
/*
Save a pointer to the found grant_table in the table object.
This pointer can later be used to verify other access requirements
without having to look up the grant table in the hash.
*/
table->grant.grant_table= grant_table;
table->grant.version= grant_version;
table->grant.privilege|= grant_table->privs;
/*
Save all privileges which might be subject to column privileges
but not which aren't yet granted by table level ACLs.
This is can later be used for column privilege checks.
*/
table->grant.want_privilege= ((required_access & COL_ACLS)
& ~table->grant.privilege);
/*
If the requested privileges share any intersection with the current
table privileges we have found at least one common privilege on the
table level.
*/
if (grant_table->privs & required_access)
continue; /* Check next table */
/*
There are no table level privileges which satisfies any of the
requested privileges. There might still be column privileges which
does though.
*/
return FALSE;
}
/*
All tables in TABLE_LIST satisfy the requirement of having any
privilege on the table level.
*/
return TRUE;
}