From 547dfc0e01bb5acbe070728706afb8a116b100e2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 19 Oct 2023 17:02:37 +0200 Subject: [PATCH] MDEV-32500 Information schema leaks table names and structure to unauthorized users standard table KEY_COLUMN_USAGE should only show keys where a user has some privileges on every column of the key standard table TABLE_CONSTRAINTS should show tables where a user has any non-SELECT privilege on the table or on any column of the table standard table REFERENTIAL_CONSTRAINTS is defined in terms of TABLE_CONSTRAINTS, so the same rule applies. If the user has no rights to see the REFERENCED_TABLE_NAME value, it should be NULL SHOW INDEX (and STATISTICS table) is non-standard, but it seems reasonable to use the same logic as for KEY_COLUMN_USAGE. --- mysql-test/main/grant4.result | 1 - mysql-test/main/information_schema_db.result | 48 +++++- mysql-test/main/information_schema_db.test | 39 ++++- .../suite/funcs_1/r/is_columns_is.result | 2 +- .../funcs_1/r/is_columns_is_embedded.result | 2 +- .../suite/funcs_1/r/is_statistics.result | 4 - .../funcs_1/r/is_table_constraints.result | 11 +- .../suite/funcs_1/t/is_table_constraints.test | 2 +- sql/sql_parse.cc | 1 + sql/sql_show.cc | 144 +++++++++++++++++- 10 files changed, 229 insertions(+), 25 deletions(-) diff --git a/mysql-test/main/grant4.result b/mysql-test/main/grant4.result index a5873a4f8ac..1760f2a5d1f 100644 --- a/mysql-test/main/grant4.result +++ b/mysql-test/main/grant4.result @@ -101,7 +101,6 @@ ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for table ** SHOW INDEX FROM t6 will succeed because there exist a privilege on a column combination on t6. SHOW INDEX FROM t6; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment -t6 1 i 1 s1 A NULL NULL NULL YES BTREE ** CHECK TABLE requires any privilege on any column combination and should succeed for t6: CHECK TABLE t6; Table Op Msg_type Msg_text diff --git a/mysql-test/main/information_schema_db.result b/mysql-test/main/information_schema_db.result index 2724272efb3..6fac8ea6fa4 100644 --- a/mysql-test/main/information_schema_db.result +++ b/mysql-test/main/information_schema_db.result @@ -262,8 +262,8 @@ set global sql_mode=default; create user foo@localhost; grant select on test.* to foo@localhost; create procedure rootonly() select 1; -create sql security definer view v1d as select current_user(),user from information_schema.processlist; -create sql security invoker view v1i as select current_user(),user from information_schema.processlist; +create sql security definer view v1d as select current_user(),user from information_schema.processlist where command!='daemon'; +create sql security invoker view v1i as select current_user(),user from information_schema.processlist where command!='daemon'; create sql security definer view v2d as select table_name from information_schema.tables where table_schema='mysql' and table_name like '%user%'; create sql security invoker view v2i as select table_name from information_schema.tables where table_schema='mysql' and table_name like '%user%'; create sql security definer view v3d as select schema_name from information_schema.schemata where schema_name like '%mysql%'; @@ -341,3 +341,47 @@ drop procedure rootonly; # # End of 10.2 tests # +# +# MDEV-32500 Information schema leaks table names and structure to unauthorized users +# +create database db; +create table db.t1 (x int, key(x)) engine=InnoDB; +create table db.t2 (a int, b int, c int, unique(b), check(c>b), foreign key(c) references db.t1(x)) engine=InnoDB; +create table db.t3 (d int, e int, f int, unique(e), check(f>e), foreign key(f) references db.t1(x), +foreign key(e) references db.t2(b), +foreign key(d) references db.t3(f) +) engine=InnoDB; +create user u@localhost; +grant select (a) on db.t2 to u@localhost; +grant update (d) on db.t3 to u@localhost; +connect con1,localhost,u,,db; +select table_name, column_name from information_schema.columns where table_name like 't_'; +table_name column_name +t2 a +t3 d +select table_name, column_name from information_schema.key_column_usage where table_name like 't_'; +table_name column_name +select table_name, unique_constraint_name, referenced_table_name from information_schema.referential_constraints where table_name like 't_'; +table_name unique_constraint_name referenced_table_name +t3 x NULL +t3 b NULL +t3 f t3 +select table_name, constraint_name, constraint_type from information_schema.table_constraints where table_name like 't_'; +table_name constraint_name constraint_type +t3 e UNIQUE +t3 CONSTRAINT_1 CHECK +t3 t3_ibfk_1 FOREIGN KEY +t3 t3_ibfk_2 FOREIGN KEY +t3 t3_ibfk_3 FOREIGN KEY +show index in t2; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +show index in t3; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t3 1 d 1 d A 0 NULL NULL YES BTREE +disconnect con1; +connection default; +drop user u@localhost; +drop database db; +# +# End of 10.4 tests +# diff --git a/mysql-test/main/information_schema_db.test b/mysql-test/main/information_schema_db.test index 229ab0bfac0..4d5b9373af6 100644 --- a/mysql-test/main/information_schema_db.test +++ b/mysql-test/main/information_schema_db.test @@ -1,7 +1,7 @@ # this test mostly test privilege control (what doesn't work # in the embedded server by default). So skip the test in embedded-server mode. -- source include/not_embedded.inc - +-- source include/have_innodb.inc -- source include/testdb_only.inc set local sql_mode=""; @@ -256,8 +256,8 @@ set global sql_mode=default; create user foo@localhost; grant select on test.* to foo@localhost; create procedure rootonly() select 1; -create sql security definer view v1d as select current_user(),user from information_schema.processlist; -create sql security invoker view v1i as select current_user(),user from information_schema.processlist; +create sql security definer view v1d as select current_user(),user from information_schema.processlist where command!='daemon'; +create sql security invoker view v1i as select current_user(),user from information_schema.processlist where command!='daemon'; create sql security definer view v2d as select table_name from information_schema.tables where table_schema='mysql' and table_name like '%user%'; create sql security invoker view v2i as select table_name from information_schema.tables where table_schema='mysql' and table_name like '%user%'; create sql security definer view v3d as select schema_name from information_schema.schemata where schema_name like '%mysql%'; @@ -297,3 +297,36 @@ drop procedure rootonly; --echo # --echo # End of 10.2 tests --echo # + +--echo # +--echo # MDEV-32500 Information schema leaks table names and structure to unauthorized users +--echo # +create database db; +create table db.t1 (x int, key(x)) engine=InnoDB; +create table db.t2 (a int, b int, c int, unique(b), check(c>b), foreign key(c) references db.t1(x)) engine=InnoDB; +create table db.t3 (d int, e int, f int, unique(e), check(f>e), foreign key(f) references db.t1(x), + foreign key(e) references db.t2(b), + foreign key(d) references db.t3(f) + ) engine=InnoDB; + +create user u@localhost; +grant select (a) on db.t2 to u@localhost; +grant update (d) on db.t3 to u@localhost; + +--connect con1,localhost,u,,db +--sorted_result +select table_name, column_name from information_schema.columns where table_name like 't_'; +select table_name, column_name from information_schema.key_column_usage where table_name like 't_'; +select table_name, unique_constraint_name, referenced_table_name from information_schema.referential_constraints where table_name like 't_'; +select table_name, constraint_name, constraint_type from information_schema.table_constraints where table_name like 't_'; +show index in t2; +show index in t3; + +--disconnect con1 +--connection default +drop user u@localhost; +drop database db; + +--echo # +--echo # End of 10.4 tests +--echo # diff --git a/mysql-test/suite/funcs_1/r/is_columns_is.result b/mysql-test/suite/funcs_1/r/is_columns_is.result index 910a86b31f0..50c16b54976 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_is.result +++ b/mysql-test/suite/funcs_1/r/is_columns_is.result @@ -287,7 +287,7 @@ def information_schema REFERENTIAL_CONSTRAINTS CONSTRAINT_NAME 3 NULL NO varchar def information_schema REFERENTIAL_CONSTRAINTS CONSTRAINT_SCHEMA 2 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL def information_schema REFERENTIAL_CONSTRAINTS DELETE_RULE 9 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL def information_schema REFERENTIAL_CONSTRAINTS MATCH_OPTION 7 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL -def information_schema REFERENTIAL_CONSTRAINTS REFERENCED_TABLE_NAME 11 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL +def information_schema REFERENTIAL_CONSTRAINTS REFERENCED_TABLE_NAME 11 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL def information_schema REFERENTIAL_CONSTRAINTS TABLE_NAME 10 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL def information_schema REFERENTIAL_CONSTRAINTS UNIQUE_CONSTRAINT_CATALOG 4 NULL NO varchar 512 1536 NULL NULL NULL utf8 utf8_general_ci varchar(512) select NEVER NULL def information_schema REFERENTIAL_CONSTRAINTS UNIQUE_CONSTRAINT_NAME 6 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL diff --git a/mysql-test/suite/funcs_1/r/is_columns_is_embedded.result b/mysql-test/suite/funcs_1/r/is_columns_is_embedded.result index 80865e6347d..7b6da4e23c0 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_is_embedded.result +++ b/mysql-test/suite/funcs_1/r/is_columns_is_embedded.result @@ -287,7 +287,7 @@ def information_schema REFERENTIAL_CONSTRAINTS CONSTRAINT_NAME 3 NULL NO varchar def information_schema REFERENTIAL_CONSTRAINTS CONSTRAINT_SCHEMA 2 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL def information_schema REFERENTIAL_CONSTRAINTS DELETE_RULE 9 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL def information_schema REFERENTIAL_CONSTRAINTS MATCH_OPTION 7 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL -def information_schema REFERENTIAL_CONSTRAINTS REFERENCED_TABLE_NAME 11 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL +def information_schema REFERENTIAL_CONSTRAINTS REFERENCED_TABLE_NAME 11 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL def information_schema REFERENTIAL_CONSTRAINTS TABLE_NAME 10 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL def information_schema REFERENTIAL_CONSTRAINTS UNIQUE_CONSTRAINT_CATALOG 4 NULL NO varchar 512 1536 NULL NULL NULL utf8 utf8_general_ci varchar(512) NEVER NULL def information_schema REFERENTIAL_CONSTRAINTS UNIQUE_CONSTRAINT_NAME 6 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL diff --git a/mysql-test/suite/funcs_1/r/is_statistics.result b/mysql-test/suite/funcs_1/r/is_statistics.result index 715304ef0ec..aeee7595ffb 100644 --- a/mysql-test/suite/funcs_1/r/is_statistics.result +++ b/mysql-test/suite/funcs_1/r/is_statistics.result @@ -250,8 +250,6 @@ ORDER BY table_schema,table_name,index_name,seq_in_index,column_name; TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT INDEX_COMMENT def db_datadict t1 1 db_datadict f2_ind 1 f2 NULL 0 NULL NULL YES HASH def db_datadict t1 0 db_datadict PRIMARY 1 f1 NULL 0 NULL NULL HASH -def db_datadict_2 t3 1 db_datadict_2 f2f1_ind 1 f2 NULL NULL NULL NULL YES HASH -def db_datadict_2 t3 1 db_datadict_2 f2f1_ind 2 f1 NULL 0 NULL NULL HASH def db_datadict_2 t3 0 db_datadict_2 f5 1 f5 NULL 0 NULL NULL YES HASH def db_datadict_2 t3 0 db_datadict_2 PRIMARY 1 f1 NULL 0 NULL NULL HASH SHOW GRANTS FOR 'testuser1'@'localhost'; @@ -282,8 +280,6 @@ SELECT * FROM information_schema.statistics WHERE table_schema LIKE 'db_datadict%' ORDER BY table_schema,table_name,index_name,seq_in_index,column_name; TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT INDEX_COMMENT -def db_datadict_2 t3 1 db_datadict_2 f2f1_ind 1 f2 NULL NULL NULL NULL YES HASH -def db_datadict_2 t3 1 db_datadict_2 f2f1_ind 2 f1 NULL 0 NULL NULL HASH def db_datadict_2 t3 0 db_datadict_2 f5 1 f5 NULL 0 NULL NULL YES HASH def db_datadict_2 t3 0 db_datadict_2 PRIMARY 1 f1 NULL 0 NULL NULL HASH SHOW GRANTS FOR 'testuser1'@'localhost'; diff --git a/mysql-test/suite/funcs_1/r/is_table_constraints.result b/mysql-test/suite/funcs_1/r/is_table_constraints.result index d306a83d15a..9d205dcdee3 100644 --- a/mysql-test/suite/funcs_1/r/is_table_constraints.result +++ b/mysql-test/suite/funcs_1/r/is_table_constraints.result @@ -104,11 +104,11 @@ CREATE TABLE db_datadict.t2 (f1 BIGINT, f2 BIGINT, f3 BIGINT, f4 BIGINT, f5 BIGINT, f6 BIGINT, PRIMARY KEY (f1,f2)) ENGINE = ; CREATE USER 'testuser1'@'localhost'; -GRANT SELECT(f5) ON db_datadict.t1 TO 'testuser1'@'localhost'; +GRANT SELECT(f5), UPDATE(f6) ON db_datadict.t1 TO 'testuser1'@'localhost'; SHOW GRANTS FOR 'testuser1'@'localhost'; Grants for testuser1@localhost GRANT USAGE ON *.* TO `testuser1`@`localhost` -GRANT SELECT (`f5`) ON `db_datadict`.`t1` TO `testuser1`@`localhost` +GRANT SELECT (`f5`), UPDATE (`f6`) ON `db_datadict`.`t1` TO `testuser1`@`localhost` SELECT * FROM information_schema.table_constraints WHERE table_schema = 'db_datadict' ORDER BY table_schema,table_name, constraint_name; @@ -132,7 +132,7 @@ connect testuser1, localhost, testuser1, , db_datadict; SHOW GRANTS FOR 'testuser1'@'localhost'; Grants for testuser1@localhost GRANT USAGE ON *.* TO `testuser1`@`localhost` -GRANT SELECT (`f5`) ON `db_datadict`.`t1` TO `testuser1`@`localhost` +GRANT SELECT (`f5`), UPDATE (`f6`) ON `db_datadict`.`t1` TO `testuser1`@`localhost` SELECT * FROM information_schema.table_constraints WHERE table_schema = 'db_datadict' ORDER BY table_schema,table_name, constraint_name; @@ -142,11 +142,6 @@ def db_datadict my_idx2 db_datadict t1 UNIQUE def db_datadict PRIMARY db_datadict t1 PRIMARY KEY SHOW INDEXES FROM db_datadict.t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment -t1 0 PRIMARY 1 f1 ### ### ### ### ### ### ### -t1 0 PRIMARY 2 f2 ### ### ### ### ### ### ### -t1 0 my_idx1 1 f6 ### ### ### ### ### ### ### -t1 0 my_idx1 2 f1 ### ### ### ### ### ### ### -t1 0 my_idx2 1 f3 ### ### ### ### ### ### ### SHOW INDEXES FROM db_datadict.t2; ERROR 42000: SELECT command denied to user 'testuser1'@'localhost' for table `db_datadict`.`t2` connection default; diff --git a/mysql-test/suite/funcs_1/t/is_table_constraints.test b/mysql-test/suite/funcs_1/t/is_table_constraints.test index d841ae17789..b4d550fc3b2 100644 --- a/mysql-test/suite/funcs_1/t/is_table_constraints.test +++ b/mysql-test/suite/funcs_1/t/is_table_constraints.test @@ -99,7 +99,7 @@ CREATE TABLE db_datadict.t2 (f1 BIGINT, f2 BIGINT, f3 BIGINT, f4 BIGINT, ENGINE = $engine_type; CREATE USER 'testuser1'@'localhost'; -GRANT SELECT(f5) ON db_datadict.t1 TO 'testuser1'@'localhost'; +GRANT SELECT(f5), UPDATE(f6) ON db_datadict.t1 TO 'testuser1'@'localhost'; SHOW GRANTS FOR 'testuser1'@'localhost'; let $my_select = SELECT * FROM information_schema.table_constraints diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c13637a3cfd..ffba37b84a7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7011,6 +7011,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table) FALSE, FALSE)) return TRUE; /* Access denied */ + thd->col_access= dst_table->grant.privilege; // for sql_show.cc /* Check_grant will grant access if there is any column privileges on all of the tables thanks to the fourth parameter (bool show_table). diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a178057a312..7d549c653f2 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -6782,6 +6782,21 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables, HA_STATUS_CONST | HA_STATUS_TIME); set_statistics_for_table(thd, show_table); } + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + bool need_column_checks= false; + /* we know that the table or at least some of the columns have + necessary privileges, but the caller didn't pass down the GRANT_INFO + object, so we have to rediscover everything again :( */ + if (!(thd->col_access & TABLE_ACLS)) + { + check_grant(thd, SELECT_ACL, tables, 0, 1, 1); + + if (!(tables->grant.privilege & TABLE_ACLS)) + need_column_checks= true; + } +#endif + for (uint i=0 ; i < show_table->s->keys ; i++,key_info++) { if ((key_info->flags & HA_INVISIBLE_KEY) && @@ -6790,6 +6805,26 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables, KEY_PART_INFO *key_part= key_info->key_part; LEX_CSTRING *str; LEX_CSTRING unknown= {STRING_WITH_LEN("?unknown field?") }; + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (need_column_checks) + { + uint j; + for (j=0 ; j < key_info->user_defined_key_parts ; j++,key_part++) + { + uint access= get_column_grant(thd, &tables->grant, db_name->str, + table_name->str, + key_part->field->field_name.str); + + if (!access) + break; + } + if (j != key_info->user_defined_key_parts) + continue; + key_part= key_info->key_part; + } +#endif + for (uint j=0 ; j < key_info->user_defined_key_parts ; j++,key_part++) { if (key_part->field->invisible >= INVISIBLE_SYSTEM && @@ -7102,6 +7137,21 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, } else if (!tables->view) { +#ifndef NO_EMBEDDED_ACCESS_CHECKS + /* need any non-SELECT privilege on the table or any of its columns */ + const ulong need= TABLE_ACLS & ~SELECT_ACL; + if (!(thd->col_access & need)) + { + /* we know that the table or at least some of the columns have + necessary privileges, but the caller didn't pass down the GRANT_INFO + object, so we have to rediscover everything again :( */ + check_grant(thd, SELECT_ACL, tables, 0, 1, 1); + + if (!(tables->grant.all_privilege() & need)) + DBUG_RETURN(0); + } +#endif + List f_key_list; TABLE *show_table= tables->table; KEY *key_info=show_table->s->key_info; @@ -7299,12 +7349,46 @@ static int get_schema_key_column_usage_record(THD *thd, TABLE_LIST *tables, uint primary_key= show_table->s->primary_key; show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + bool need_column_checks= false; + /* we know that the table or at least some of the columns have + necessary privileges, but the caller didn't pass down the GRANT_INFO + object, so we have to rediscover everything again :( */ + if (!(thd->col_access & TABLE_ACLS)) + { + check_grant(thd, SELECT_ACL, tables, 0, 1, 1); + + if (!(tables->grant.privilege & TABLE_ACLS)) + need_column_checks= true; + } +#endif + for (uint i=0 ; i < show_table->s->keys ; i++, key_info++) { if (i != primary_key && !(key_info->flags & HA_NOSAME)) continue; uint f_idx= 0; KEY_PART_INFO *key_part= key_info->key_part; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (need_column_checks) + { + uint j; + for (j=0 ; j < key_info->user_defined_key_parts ; j++,key_part++) + { + uint access= get_column_grant(thd, &tables->grant, db_name->str, + table_name->str, + key_part->field->field_name.str); + + if (!access) + break; + } + if (j != key_info->user_defined_key_parts) + continue; + key_part= key_info->key_part; + } +#endif + for (uint j=0 ; j < key_info->user_defined_key_parts ; j++,key_part++) { f_idx++; @@ -7329,6 +7413,23 @@ static int get_schema_key_column_usage_record(THD *thd, TABLE_LIST *tables, List_iterator_fast it(f_key_info->foreign_fields), it1(f_key_info->referenced_fields); uint f_idx= 0; + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (need_column_checks) + { + while ((r_info= it1++)) + { + uint access= get_column_grant(thd, &tables->grant, db_name->str, + table_name->str, r_info->str); + + if (!access) + break; + } + if (!it1.at_end()) + continue; + it1.rewind(); + } +#endif while ((f_info= it++)) { r_info= it1++; @@ -8179,6 +8280,21 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables, show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); +#ifndef NO_EMBEDDED_ACCESS_CHECKS + /* need any non-SELECT privilege on the table or any of its columns */ + const ulong need= TABLE_ACLS & ~SELECT_ACL; + if (!(thd->col_access & need)) + { + /* we know that the table or at least some of the columns have + necessary privileges, but the caller didn't pass down the GRANT_INFO + object, so we have to rediscover everything again :( */ + check_grant(thd, SELECT_ACL, tables, 0, 1, 1); + + if (!(tables->grant.all_privilege() & need)) + DBUG_RETURN(0); + } +#endif + show_table->file->get_foreign_key_list(thd, &f_key_list); FOREIGN_KEY_INFO *f_key_info; List_iterator_fast it(f_key_list); @@ -8193,8 +8309,28 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables, table->field[3]->store(STRING_WITH_LEN("def"), cs); table->field[4]->store(f_key_info->referenced_db->str, f_key_info->referenced_db->length, cs); - table->field[10]->store(f_key_info->referenced_table->str, - f_key_info->referenced_table->length, cs); + bool show_ref_table= true; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + /* need any non-SELECT privilege on the table or any of its columns */ + if (!(thd->col_access & need)) + { + TABLE_LIST table_acl_check; + bzero((char*) &table_acl_check, sizeof(table_acl_check)); + table_acl_check.db= *f_key_info->referenced_db; + table_acl_check.table_name= *f_key_info->referenced_table; + table_acl_check.grant.privilege= thd->col_access; + check_grant(thd, SELECT_ACL, &table_acl_check, 0, 1, 1); + + if (!(table_acl_check.grant.all_privilege() & need)) + show_ref_table= false; + } +#endif + if (show_ref_table) + { + table->field[10]->set_notnull(); + table->field[10]->store(f_key_info->referenced_table->str, + f_key_info->referenced_table->length, cs); + } if (f_key_info->referenced_key_name) { table->field[5]->store(f_key_info->referenced_key_name->str, @@ -9898,8 +10034,8 @@ ST_FIELD_INFO referential_constraints_fields_info[]= {"UPDATE_RULE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"DELETE_RULE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {"REFERENCED_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, - OPEN_FULL_TABLE}, + {"REFERENCED_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, + MY_I_S_MAYBE_NULL, 0, OPEN_FULL_TABLE}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} };