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:
165
sql/sql_acl.cc
165
sql/sql_acl.cc
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user