summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/deny/show_view.result101
-rw-r--r--mysql-test/suite/deny/show_view.test106
-rw-r--r--sql/item.cc3
-rw-r--r--sql/sql_acl.cc196
-rw-r--r--sql/sql_acl.h18
-rw-r--r--sql/sql_base.cc2
-rw-r--r--sql/sql_show.cc41
-rw-r--r--sql/sql_view.cc2
8 files changed, 399 insertions, 70 deletions
diff --git a/mysql-test/suite/deny/show_view.result b/mysql-test/suite/deny/show_view.result
index 50a65773c56..0b5ac0644a5 100644
--- a/mysql-test/suite/deny/show_view.result
+++ b/mysql-test/suite/deny/show_view.result
@@ -198,3 +198,104 @@ drop view v1, v2;
drop table t1;
drop user foo;
drop database some_db;
+#
+# Test showing / not showing view body with SHOW VIEW and SELECT
+# privilege denies.
+#
+connection default;
+create user foo;
+create database some_db;
+create table some_db.t1 (a int, b int);
+create view some_db.v1 as (select * from some_db.t1);
+grant select, show view on *.* to foo;
+grant select, show view on some_db.* to foo;
+grant select, show view on some_db.v1 to foo;
+connect con1,localhost,foo,,;
+select * from information_schema.views where table_schema = 'some_db';
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE CHARACTER_SET_CLIENT COLLATION_CONNECTION ALGORITHM
+def some_db v1 (select `some_db`.`t1`.`a` AS `a`,`some_db`.`t1`.`b` AS `b` from `some_db`.`t1`) NONE YES root@localhost DEFINER latin1 latin1_swedish_ci UNDEFINED
+disconnect con1;
+#
+# Table level denies.
+#
+connection default;
+deny show view on some_db.v1 to foo;
+connect con1,localhost,foo,,;
+select * from information_schema.views where table_schema = 'some_db';
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE CHARACTER_SET_CLIENT COLLATION_CONNECTION ALGORITHM
+def some_db v1 NONE YES root@localhost DEFINER latin1 latin1_swedish_ci UNDEFINED
+disconnect con1;
+connection default;
+revoke deny show view on some_db.v1 from foo;
+deny select on some_db.v1 to foo;
+connect con1,localhost,foo,,;
+select * from information_schema.views where table_schema = 'some_db';
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE CHARACTER_SET_CLIENT COLLATION_CONNECTION ALGORITHM
+def some_db v1 NONE YES root@localhost DEFINER latin1 latin1_swedish_ci UNDEFINED
+disconnect con1;
+#
+# Database level denies.
+#
+connection default;
+revoke deny select on some_db.v1 from foo;
+deny select on some_db.* to foo;
+connect con1,localhost,foo,,;
+select * from information_schema.views where table_schema = 'some_db';
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE CHARACTER_SET_CLIENT COLLATION_CONNECTION ALGORITHM
+def some_db v1 NONE YES root@localhost DEFINER latin1 latin1_swedish_ci UNDEFINED
+disconnect con1;
+connection default;
+revoke deny select on some_db.* from foo;
+deny show view on some_db.* to foo;
+connect con1,localhost,foo,,;
+select * from information_schema.views where table_schema = 'some_db';
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE CHARACTER_SET_CLIENT COLLATION_CONNECTION ALGORITHM
+def some_db v1 NONE YES root@localhost DEFINER latin1 latin1_swedish_ci UNDEFINED
+disconnect con1;
+#
+# Global level denies.
+#
+connection default;
+revoke deny show view on some_db.* from foo;
+deny show view on *.* to foo;
+connect con1,localhost,foo,,;
+select * from information_schema.views where table_schema = 'some_db';
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE CHARACTER_SET_CLIENT COLLATION_CONNECTION ALGORITHM
+def some_db v1 NONE YES root@localhost DEFINER latin1 latin1_swedish_ci UNDEFINED
+disconnect con1;
+connection default;
+revoke deny show view on *.* from foo;
+deny select on *.* to foo;
+connect con1,localhost,foo,,;
+select * from information_schema.views where table_schema = 'some_db';
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE CHARACTER_SET_CLIENT COLLATION_CONNECTION ALGORITHM
+def some_db v1 NONE YES root@localhost DEFINER latin1 latin1_swedish_ci UNDEFINED
+disconnect con1;
+#
+# Column level denies.
+#
+connection default;
+revoke deny select on *.* from foo;
+#
+# All denies have been revoked from the user, back to regular
+# privilege checking.
+#
+connect con1,localhost,foo,,;
+select * from information_schema.views where table_schema = 'some_db';
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE CHARACTER_SET_CLIENT COLLATION_CONNECTION ALGORITHM
+def some_db v1 (select `some_db`.`t1`.`a` AS `a`,`some_db`.`t1`.`b` AS `b` from `some_db`.`t1`) NONE YES root@localhost DEFINER latin1 latin1_swedish_ci UNDEFINED
+disconnect con1;
+connection default;
+#
+# Here because we have column level denies, a user is not allowed
+# to see the view.
+#
+deny select (a) on some_db.v1 to foo;
+connect con1,localhost,foo,,;
+select * from information_schema.views where table_schema = 'some_db';
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE DEFINER SECURITY_TYPE CHARACTER_SET_CLIENT COLLATION_CONNECTION ALGORITHM
+def some_db v1 NONE YES root@localhost DEFINER latin1 latin1_swedish_ci UNDEFINED
+disconnect con1;
+connection default;
+drop user foo;
+drop database some_db;
diff --git a/mysql-test/suite/deny/show_view.test b/mysql-test/suite/deny/show_view.test
index 9d4bc4a3158..12a86987e80 100644
--- a/mysql-test/suite/deny/show_view.test
+++ b/mysql-test/suite/deny/show_view.test
@@ -175,3 +175,109 @@ drop view v1, v2;
drop table t1;
drop user foo;
drop database some_db;
+
+--echo #
+--echo # Test showing / not showing view body with SHOW VIEW and SELECT
+--echo # privilege denies.
+--echo #
+connection default;
+create user foo;
+create database some_db;
+create table some_db.t1 (a int, b int);
+
+create view some_db.v1 as (select * from some_db.t1);
+
+grant select, show view on *.* to foo;
+grant select, show view on some_db.* to foo;
+grant select, show view on some_db.v1 to foo;
+
+--connect (con1,localhost,foo,,)
+select * from information_schema.views where table_schema = 'some_db';
+disconnect con1;
+
+--echo #
+--echo # Table level denies.
+--echo #
+connection default;
+deny show view on some_db.v1 to foo;
+
+--connect (con1,localhost,foo,,)
+select * from information_schema.views where table_schema = 'some_db';
+disconnect con1;
+
+connection default;
+revoke deny show view on some_db.v1 from foo;
+deny select on some_db.v1 to foo;
+
+--connect (con1,localhost,foo,,)
+select * from information_schema.views where table_schema = 'some_db';
+disconnect con1;
+
+--echo #
+--echo # Database level denies.
+--echo #
+connection default;
+revoke deny select on some_db.v1 from foo;
+deny select on some_db.* to foo;
+
+--connect (con1,localhost,foo,,)
+select * from information_schema.views where table_schema = 'some_db';
+disconnect con1;
+
+connection default;
+revoke deny select on some_db.* from foo;
+deny show view on some_db.* to foo;
+
+--connect (con1,localhost,foo,,)
+select * from information_schema.views where table_schema = 'some_db';
+disconnect con1;
+
+--echo #
+--echo # Global level denies.
+--echo #
+connection default;
+revoke deny show view on some_db.* from foo;
+deny show view on *.* to foo;
+
+--connect (con1,localhost,foo,,)
+select * from information_schema.views where table_schema = 'some_db';
+disconnect con1;
+
+connection default;
+revoke deny show view on *.* from foo;
+deny select on *.* to foo;
+
+--connect (con1,localhost,foo,,)
+select * from information_schema.views where table_schema = 'some_db';
+disconnect con1;
+
+--echo #
+--echo # Column level denies.
+--echo #
+
+connection default;
+revoke deny select on *.* from foo;
+
+--echo #
+--echo # All denies have been revoked from the user, back to regular
+--echo # privilege checking.
+--echo #
+
+--connect (con1,localhost,foo,,)
+select * from information_schema.views where table_schema = 'some_db';
+disconnect con1;
+
+connection default;
+--echo #
+--echo # Here because we have column level denies, a user is not allowed
+--echo # to see the view.
+--echo #
+deny select (a) on some_db.v1 to foo;
+
+--connect (con1,localhost,foo,,)
+select * from information_schema.views where table_schema = 'some_db';
+disconnect con1;
+
+connection default;
+drop user foo;
+drop database some_db;
diff --git a/sql/item.cc b/sql/item.cc
index 4eb8e50be84..90d63a91691 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -6181,7 +6181,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (any_privileges)
{
- if (!(have_privileges= (get_column_grant(thd, &field->table->grant,
+ if (!(have_privileges= (get_column_grant(thd->security_context(),
+ &field->table->grant,
field->table->s->db,
field->table->s->table_name,
field_name) &
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index df9409800ba..919417b5fa1 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -198,6 +198,11 @@ public:
};
+enum object_type {
+ TABLE_TYPE, PROCEDURE_TYPE, FUNCTION_TYPE, PACKAGE_SPEC_TYPE,
+ PACKAGE_BODY_TYPE
+};
+
class Deny_spec
{
typedef std::pair<LEX_CSTRING, privilege_t> deny_entry;
@@ -4238,6 +4243,13 @@ check_routine_access(THD *thd, privilege_t want_access, const LEX_CSTRING *db,
return check_grant_routine(thd, want_access, tables, sph, no_errors);
}
+static privilege_t acl_get_effective_deny_mask_impl(
+ const Deny_spec &denies,
+ const Deny_spec *role_denies,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &object_name,
+ const LEX_CSTRING &column_name,
+ enum object_type type);
/**
Check if the routine has any of the routine privileges.
@@ -4275,6 +4287,52 @@ bool check_some_routine_access(THD *thd,
}
+bool check_if_any_column_is_denied(Security_context *sctx,
+ privilege_t privilege_needed,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &table,
+ Field **fields)
+{
+ const Deny_spec *denies;
+ const Deny_spec *role_denies= nullptr;
+
+ mysql_mutex_lock(&acl_cache->lock);
+ /*
+ TODO(cvicentiu) this snippet really repeats in too many places. Factor
+ it out into a function.
+ */
+ ACL_USER *acl_user= find_user_exact(sctx->priv_host, sctx->priv_user);
+ if (!acl_user)
+ {
+ mysql_mutex_unlock(&acl_cache->lock);
+ return true;
+ }
+ denies= acl_user->denies;
+ /* This function should only be called when denies are active. */
+ DBUG_ASSERT(denies);
+
+ ACL_ROLE *role= find_acl_role(sctx->priv_role);
+ if (role)
+ role_denies= role->denies;
+
+ while (*fields)
+ {
+ privilege_t deny_mask= acl_get_effective_deny_mask_impl(
+ *denies, role_denies, db, table, (*fields)->field_name, TABLE_TYPE);
+
+ if (privilege_needed & deny_mask)
+ {
+ mysql_mutex_unlock(&acl_cache->lock);
+ return true;
+ }
+ fields++;
+ }
+
+ mysql_mutex_unlock(&acl_cache->lock);
+ return false;
+}
+
+
/*
Check if the given table has any of the asked privileges
@@ -5218,11 +5276,6 @@ static bool compute_acl_cache_key(const char *ip,
}
-enum object_type {
- TABLE_TYPE, PROCEDURE_TYPE, FUNCTION_TYPE, PACKAGE_SPEC_TYPE,
- PACKAGE_BODY_TYPE
-};
-
static enum object_type get_corresponding_object_type(const Sp_handler &sph)
{
switch (sph.type())
@@ -5283,7 +5336,7 @@ static enum PRIV_TYPE get_corresponding_priv_spec_type(const Sp_handler &sph)
return NO_PRIV;
}
-static privilege_t acl_get_effective_deny_mask_impl(
+static privilege_t get_deny_mask(
const Deny_spec &denies,
const LEX_CSTRING &db,
const LEX_CSTRING &object_name,
@@ -5318,6 +5371,21 @@ static privilege_t acl_get_effective_deny_mask_impl(
return result;
}
+static privilege_t acl_get_effective_deny_mask_impl(
+ const Deny_spec &denies,
+ const Deny_spec *role_denies,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &object_name,
+ const LEX_CSTRING &column_name,
+ enum object_type type)
+{
+ privilege_t result= get_deny_mask(denies, db, object_name, column_name, type);
+ if (role_denies)
+ result|= get_deny_mask(*role_denies, db, object_name, column_name, type);
+ return result;
+}
+
+
privilege_t acl_get_effective_deny_mask_impl(const Security_context *ctx,
const LEX_CSTRING &db,
const LEX_CSTRING &object_name,
@@ -5371,13 +5439,11 @@ privilege_t acl_get_effective_deny_mask_impl(const Security_context *ctx,
return ALL_KNOWN_ACL;
}
- result= acl_get_effective_deny_mask_impl(*acl_user->denies,
- db, object_name, column_name, type);
+ result= get_deny_mask(*acl_user->denies, db, object_name, column_name, type);
ACL_ROLE *role= find_acl_role(ctx->priv_role);
if (role)
- result|= acl_get_effective_deny_mask_impl(*role->denies, db,
- object_name, column_name, type);
+ result|= get_deny_mask(*role->denies, db, object_name, column_name, type);
mysql_mutex_unlock(&acl_cache->lock);
return result;
@@ -9947,9 +10013,9 @@ bool grant_reload(THD *thd)
}
-/* TODO(cvicentiu) extend this to pass in both user and role denies. */
static
bool check_some_grants_remain(const Deny_spec &denies,
+ const Deny_spec *role_denies,
privilege_t table_deny_mask, GRANT_TABLE *table)
{
if (!table)
@@ -9968,6 +10034,9 @@ bool check_some_grants_remain(const Deny_spec &denies,
privilege_t col_deny_mask=
table_deny_mask | denies.get_column_deny(db, table_name, column_name);
+ if (role_denies)
+ col_deny_mask|= role_denies->get_column_deny(db, table_name, column_name);
+
if (grant_column->rights & ~col_deny_mask)
return true;
}
@@ -9994,13 +10063,26 @@ bool check_some_grants_remain(Security_context *sctx,
}
DBUG_ASSERT(sctx->denies_active && acl_user->denies);
- const Deny_spec& denies= *acl_user->denies;
+ const Deny_spec &denies= *acl_user->denies;
+ const Deny_spec *role_denies= nullptr;
+
privilege_t deny_mask= denies.get_global() |
denies.get_db_deny(db) |
denies.get_table_deny(db, table);
- result= check_some_grants_remain(denies, deny_mask, grant_table) ||
- check_some_grants_remain(denies, deny_mask, grant_table_role);
+ ACL_ROLE *role= find_acl_role(sctx->priv_role);
+ if (role && role->denies)
+ {
+ role_denies= role->denies;
+ deny_mask|= role_denies->get_global() |
+ role_denies->get_db_deny(db) |
+ role_denies->get_table_deny(db, table);
+ }
+
+ result= check_some_grants_remain(denies, role_denies,
+ deny_mask, grant_table) ||
+ check_some_grants_remain(denies, role_denies,
+ deny_mask, grant_table_role);
mysql_mutex_unlock(&acl_cache->lock);
return result;
@@ -10294,7 +10376,6 @@ bool check_grant(THD *thd, privilege_t want_access, TABLE_LIST *tables,
t_ref->grant.version= grant_version;
t_ref->grant.privilege|= grant_table ? grant_table->privs : NO_ACL;
t_ref->grant.privilege|= grant_table_role ? grant_table_role->privs : NO_ACL;
- // TODO(cvicentiu) here the deny mask for the role must be created too.
t_ref->grant.privilege&= ~deny_mask;
/*
@@ -10494,7 +10575,10 @@ bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
if (table_ref->belong_to_view &&
thd->lex->sql_command == SQLCOM_SHOW_FIELDS)
{
- view_privs= get_column_grant(thd, grant,
+ /* !!! TODO(cvicentiu) This changes from always thd->security_context
+ * to also point to table_ref->security_ctx, CHECK! Perhaps
+ * this is not the intent *here* !*/
+ view_privs= get_column_grant(sctx, grant,
*db_name, *table_name, {name, length});
if (view_privs & VIEW_ANY_ACL)
{
@@ -10548,6 +10632,7 @@ bool check_grant_all_columns(THD *thd, privilege_t want_access_arg,
GRANT_TABLE *UNINIT_VAR(grant_table);
GRANT_TABLE *UNINIT_VAR(grant_table_role);
const Deny_spec *denies= nullptr;
+ const Deny_spec *role_denies= nullptr;
const bool denies_could_interfere=
sctx->denies_active & (GLOBAL_PRIV | DATABASE_PRIV | TABLE_PRIV |
COLUMN_PRIV);
@@ -10568,6 +10653,7 @@ bool check_grant_all_columns(THD *thd, privilege_t want_access_arg,
mysql_mutex_lock(&acl_cache->lock);
/* TODO(cvicentiu) modify this for role denies too! */
ACL_USER *acl_user= find_user_exact(sctx->priv_host, sctx->priv_user);
+ ACL_ROLE *acl_role= find_acl_role(sctx->priv_role);
if (!acl_user)
goto err; /* See acl_get_effective_deny_mask_impl, same shortcut. */
/*
@@ -10575,6 +10661,8 @@ bool check_grant_all_columns(THD *thd, privilege_t want_access_arg,
it again.
*/
denies= acl_user->denies;
+ if (acl_role)
+ role_denies= acl_role->denies;
}
for (; !fields->end_of_fields(); fields->next())
@@ -10594,10 +10682,10 @@ bool check_grant_all_columns(THD *thd, privilege_t want_access_arg,
if (sctx->denies_active & (GLOBAL_PRIV | DATABASE_PRIV | TABLE_PRIV |
COLUMN_PRIV))
{
- /* TODO(cvicentiu) -> Role denies too... */
field_deny_mask=
acl_get_effective_deny_mask_impl(
*denies,
+ role_denies,
{fields->get_db_name(), strlen(fields->get_db_name())},
{fields->get_table_name(), strlen(fields->get_table_name())},
*field_name,
@@ -10709,33 +10797,32 @@ static bool check_grant_db_routine(Security_context *sctx,
HASH *hash= get_corresponding_routine_hash(routine_type);
for (uint idx= 0; idx < hash->records; ++idx)
{
+ privilege_t usable_mask= db_deny_mask;
GRANT_NAME *item= (GRANT_NAME*) my_hash_element(hash, idx);
+ /*
+ Only re-compute the deny mask if there are specific denies active
+ that might impact it.
+ */
+ if (sctx->denies_active & get_corresponding_priv_spec_type(routine_type))
+ {
+ LEX_CSTRING routine_name= {item->tname, strlen(item->tname)};
+ usable_mask= acl_get_effective_deny_mask_impl(sctx, db, routine_name,
+ {nullptr, 0},
+ routine_type);
+ }
if (strcmp(item->user, sctx->priv_user) == 0 &&
strcmp(item->db, db.str) == 0 &&
compare_hostname(&item->host, sctx->host, sctx->ip))
{
- privilege_t usable_mask= db_deny_mask;
- /*
- Only re-compute the deny mask if there are specific denies active
- that might impact it.
- */
- if (sctx->denies_active & get_corresponding_priv_spec_type(routine_type))
- {
- LEX_CSTRING routine_name= {item->tname, strlen(item->tname)};
- usable_mask= acl_get_effective_deny_mask_impl(sctx, db, routine_name,
- {nullptr, 0},
- routine_type);
- }
if (item->privs & ~usable_mask)
return FALSE;
}
- /* TODO(cvicentiu) make this work for role denies too. */
if (sctx->priv_role[0] && strcmp(item->user, sctx->priv_role) == 0 &&
strcmp(item->db, db.str) == 0 &&
(!item->host.hostname || !item->host.hostname[0]))
{
- if (item->privs & ~db_deny_mask)
+ if (item->privs & ~usable_mask)
return FALSE; /* Found current role match */
}
}
@@ -10761,6 +10848,7 @@ bool check_grant_db(Security_context *sctx,
bool denies_at_table_or_column_level=
sctx->denies_active & (TABLE_PRIV | COLUMN_PRIV);
const Deny_spec *denies= nullptr;
+ const Deny_spec *role_denies= nullptr;
LEX_CSTRING lower_case_db= db;
@@ -10802,11 +10890,15 @@ bool check_grant_db(Security_context *sctx,
ACL_USER *acl_user= find_user_exact(sctx->priv_host, sctx->priv_user);
if (!acl_user)
goto error; /* See acl_get_effective_deny_mask_impl, same shortcut. */
+
+ ACL_ROLE *role= find_acl_role(sctx->priv_role);
/*
Caching denies here, vs for every hash entry means we don't need to find
it again.
*/
denies= acl_user->denies;
+ if (role)
+ role_denies= role->denies;
}
for (size_t idx=0 ; idx < column_priv_hash.records ; idx++)
@@ -10823,6 +10915,8 @@ bool check_grant_db(Security_context *sctx,
{
table_name= {grant_table->tname, strlen(grant_table->tname)};
deny_mask|= denies->get_table_deny(db, table_name);
+ if (role_denies)
+ deny_mask|= role_denies->get_table_deny(db, table_name);
}
if (grant_table->privs & ~deny_mask)
@@ -10852,7 +10946,7 @@ bool check_grant_db(Security_context *sctx,
to check if there is an explicit deny on each of those columns
and compute the effective privileges.
*/
- if (check_some_grants_remain(*denies, deny_mask, grant_table))
+ if (check_some_grants_remain(*denies, role_denies, deny_mask, grant_table))
{
error= false;
goto error;
@@ -10864,7 +10958,6 @@ bool check_grant_db(Security_context *sctx,
!memcmp(grant_table->hash_key, helping2, len2) &&
(!grant_table->host.hostname || !grant_table->host.hostname[0]))
{
- //TODO(cvicentiu) implement for roles...
if (grant_table->privs & ~deny_mask || grant_table->cols & ~deny_mask)
{
error= FALSE; /* Found role match. */
@@ -11027,39 +11120,36 @@ bool check_routine_level_acl(THD *thd,
Functions to retrieve the grant for a table/column (for SHOW functions)
*****************************************************************************/
-privilege_t get_table_grant(THD *thd, TABLE_LIST *table)
+privilege_t get_table_grant(Security_context *sctx,
+ privilege_t db_access,
+ const LEX_CSTRING &db, const LEX_CSTRING &table)
{
- Security_context *sctx= thd->security_ctx;
- const char *db = table->db.str ? table->db.str : thd->db.str;
GRANT_TABLE *grant_table;
GRANT_TABLE *grant_table_role= NULL;
+ privilege_t result= db_access;
+
//TODO(cvicentiu) table level and column level deny mask recompute per table.
- privilege_t deny_mask= acl_get_effective_deny_mask(sctx, {db, strlen(db)});
+ privilege_t deny_mask= acl_get_effective_deny_mask(sctx, db, table);
mysql_rwlock_rdlock(&LOCK_grant);
#ifdef EMBEDDED_LIBRARY
grant_table= NULL;
grant_table_role= NULL;
#else
- grant_table= table_hash_search(sctx->host, sctx->ip, db, sctx->priv_user,
- table->table_name.str, 0);
+ grant_table= table_hash_search(sctx->host, sctx->ip, db.str, sctx->priv_user,
+ table.str, 0);
if (sctx->priv_role[0])
- grant_table_role= table_hash_search("", "", db, sctx->priv_role,
- table->table_name.str, 0);
+ grant_table_role= table_hash_search("", "", db.str, sctx->priv_role,
+ table.str, 0);
#endif
- table->grant.grant_table_user= grant_table; // Remember for column test
- table->grant.grant_table_role= grant_table_role;
- table->grant.version=grant_version;
if (grant_table)
- table->grant.privilege|= grant_table->privs;
+ result|= grant_table->privs;
if (grant_table_role)
- table->grant.privilege|= grant_table_role->privs;
+ result|= grant_table_role->privs;
- table->grant.privilege &= ~deny_mask;
-
- privilege_t privilege(table->grant.privilege);
+ result&= ~deny_mask;
mysql_rwlock_unlock(&LOCK_grant);
- return privilege;
+ return result;
}
@@ -11081,7 +11171,7 @@ privilege_t get_table_grant(THD *thd, TABLE_LIST *table)
The access priviliges for the field db_name.table_name.field_name
*/
-privilege_t get_column_grant(THD *thd, GRANT_INFO *grant,
+privilege_t get_column_grant(Security_context *sctx, GRANT_INFO *grant,
const LEX_CSTRING &db_name,
const LEX_CSTRING &table_name,
const LEX_CSTRING &field_name)
@@ -11094,14 +11184,12 @@ privilege_t get_column_grant(THD *thd, GRANT_INFO *grant,
mysql_rwlock_rdlock(&LOCK_grant);
- deny_mask= acl_get_effective_deny_mask(thd->security_ctx,
+ deny_mask= acl_get_effective_deny_mask(sctx,
db_name, table_name, field_name);
/* reload table if someone has modified any grants */
if (grant->version != grant_version)
{
- Security_context *sctx= thd->security_ctx;
-
grant->grant_table_user=
table_hash_search(sctx->host, sctx->ip,
db_name.str, sctx->priv_user,
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index dcf9ee2a09a..0fff913c2f0 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -130,6 +130,12 @@ bool check_table_access(THD *thd, privilege_t requirements,TABLE_LIST *tables,
bool any_combination_of_privileges_will_do,
uint number,
bool no_errors);
+
+bool check_if_any_column_is_denied(Security_context *ctx,
+ privilege_t privilege_needed,
+ const LEX_CSTRING &db, const LEX_CSTRING &table,
+ Field **fields);
+
#else
inline bool check_access(THD *thd, privilege_t want_access,
const char *db, privilege_t *save_priv,
@@ -168,10 +174,18 @@ check_table_access(THD *thd, privilege_t requirements,TABLE_LIST *tables,
uint number,
bool no_errors)
{ return false; }
+inline bool
+check_if_any_column_is_denied(Security_context *sctx,
+ privilege_t privilege_needed,
+ const LEX_CSTRING &db, const LEX_CSTRING &table,
+ Field **fields);
+
#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
-privilege_t get_table_grant(THD *thd, TABLE_LIST *table);
-privilege_t get_column_grant(THD *thd, GRANT_INFO *grant,
+privilege_t get_table_grant(Security_context *sctx,
+ privilege_t db_access,
+ const LEX_CSTRING &db, const LEX_CSTRING &table);
+privilege_t get_column_grant(Security_context *sctx, GRANT_INFO *grant,
const LEX_CSTRING &db_name,
const LEX_CSTRING &table_name,
const LEX_CSTRING &field_name);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 1d92a1a2a03..e4defdff2c7 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -8491,7 +8491,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
if (!tables->schema_table &&
!(fld->have_privileges=
- (get_column_grant(thd, field_iterator.grant(),
+ (get_column_grant(thd->security_context(), field_iterator.grant(),
field_db_name, field_table_name,
fld->field_name) &
VIEW_ANY_ACL)))
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 01fb7813d7a..cb6fc67cdb6 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -6123,7 +6123,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
ulonglong col_access;
check_access(thd,SELECT_ACL, db_name->str,
&tables->grant.privilege, 0, 0, MY_TEST(tables->schema_table));
- col_access= get_column_grant(thd, &tables->grant,
+ col_access= get_column_grant(thd->security_context(), &tables->grant,
*db_name, *table_name,
field->field_name) & COL_ACLS;
if (!tables->schema_table && !col_access)
@@ -6917,19 +6917,38 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
else
{
if ((thd->col_access & (SHOW_VIEW_ACL|SELECT_ACL)) ==
- (SHOW_VIEW_ACL|SELECT_ACL))
+ (SHOW_VIEW_ACL|SELECT_ACL) &&
+ !(thd->security_ctx->denies_active & (TABLE_PRIV | COLUMN_PRIV)))
+ {
tables->allowed_show= TRUE;
+ }
else
{
- TABLE_LIST table_list;
- table_list.reset();
- table_list.db= tables->db;
- table_list.table_name= tables->table_name;
- table_list.grant.privilege= thd->col_access;
- privilege_t view_access(get_table_grant(thd, &table_list));
- if ((view_access & (SHOW_VIEW_ACL|SELECT_ACL)) ==
- (SHOW_VIEW_ACL|SELECT_ACL))
- tables->allowed_show= TRUE;
+ privilege_t view_access(get_table_grant(thd->security_context(),
+ thd->col_access, tables->db,
+ tables->table_name));
+ if ((view_access & (SHOW_VIEW_ACL|SELECT_ACL)) ==
+ (SHOW_VIEW_ACL|SELECT_ACL))
+ {
+ if (thd->security_context()->denies_active & COLUMN_PRIV)
+ {
+ /*
+ Only allow show of the view's definition *if* we have
+ TABLE or higher SELECT & SHOW VIEW privilege *and*
+ we do not have any columns in the view with a denied
+ SELECT.
+ */
+ if (!check_if_any_column_is_denied(thd->security_context(),
+ SELECT_ACL,
+ tables->db, tables->table_name,
+ tables->table->field))
+ tables->allowed_show= TRUE;
+ }
+ else
+ {
+ tables->allowed_show= TRUE;
+ }
+ }
}
}
#endif
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 90c4e4fe0dc..ba1b4d7688e 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -624,7 +624,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
while ((item= it++))
{
Item_field *fld= item->field_for_view_update();
- privilege_t priv(get_column_grant(thd, &view->grant,
+ privilege_t priv(get_column_grant(thd->security_context(), &view->grant,
view->db,
view->table_name,
item->name) &