From b0325bd6d6afa2a904163e683174457fde18c895 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Mon, 13 Dec 2021 16:15:21 +0100 Subject: [PATCH] MDEV-5215 Granted to PUBLIC --- mysql-test/main/public_basic.result | 138 +++++++ mysql-test/main/public_basic.test | 130 +++++++ mysql-test/main/public_privileges.result | 346 ++++++++++++++++++ mysql-test/main/public_privileges.test | 411 +++++++++++++++++++++ mysql-test/suite/roles/none_public.result | 13 +- mysql-test/suite/roles/none_public.test | 21 +- sql/sql_acl.cc | 420 ++++++++++++++-------- sql/sql_acl.h | 4 +- sql/sql_db.cc | 11 +- sql/sql_parse.cc | 14 +- sql/sql_show.cc | 12 +- sql/sql_yacc.yy | 1 + sql/structs.h | 1 + sql/table.h | 9 + 14 files changed, 1326 insertions(+), 205 deletions(-) create mode 100644 mysql-test/main/public_basic.result create mode 100644 mysql-test/main/public_basic.test create mode 100644 mysql-test/main/public_privileges.result create mode 100644 mysql-test/main/public_privileges.test diff --git a/mysql-test/main/public_basic.result b/mysql-test/main/public_basic.result new file mode 100644 index 00000000000..5832180d2cf --- /dev/null +++ b/mysql-test/main/public_basic.result @@ -0,0 +1,138 @@ +SHOW GRANTS FOR PUBLIC; +Grants for PUBLIC +# it is not PUBLIC but an user +# (this should work as it allowed for roles for example) +create user PUBLIC; +create user PUBLIC@localhost; +GRANT SELECT on test.* to PUBLIC@localhost; +drop user PUBLIC@localhost; +drop user PUBLIC; +# preinstalled PUBLIC +GRANT SELECT on test.* to PUBLIC; +GRANT SELECT on mysql.db to PUBLIC; +select * from mysql.global_priv where user="PUBLIC" ; +Host User Priv + PUBLIC {"access":0,"version_id":VERSION,"is_role":true} +SHOW GRANTS FOR PUBLIC; +Grants for PUBLIC +GRANT SELECT ON `test`.* TO `PUBLIC` +GRANT SELECT ON `mysql`.`db` TO `PUBLIC` +GRANT UPDATE on test.* to PUBLIC; +GRANT UPDATE on mysql.db to PUBLIC; +SHOW GRANTS FOR PUBLIC; +Grants for PUBLIC +GRANT SELECT, UPDATE ON `test`.* TO `PUBLIC` +GRANT SELECT, UPDATE ON `mysql`.`db` TO `PUBLIC` +REVOKE SELECT on test.* from PUBLIC; +REVOKE SELECT on mysql.db from PUBLIC; +SHOW GRANTS FOR PUBLIC; +Grants for PUBLIC +GRANT UPDATE ON `test`.* TO `PUBLIC` +GRANT UPDATE ON `mysql`.`db` TO `PUBLIC` +REVOKE UPDATE on test.* from PUBLIC; +REVOKE UPDATE on mysql.db from PUBLIC; +REVOKE UPDATE on test.* from PUBLIC; +ERROR 42000: There is no such grant defined for user 'PUBLIC' on host '' +REVOKE UPDATE on mysql.db from PUBLIC; +ERROR 42000: There is no such grant defined for user 'PUBLIC' on host '' on table 'db' +SHOW GRANTS FOR PUBLIC; +Grants for PUBLIC +# automaticly added PUBLIC +delete from mysql.global_priv where user="PUBLIC"; +flush privileges; +select * from mysql.global_priv where user="PUBLIC" ; +Host User Priv +GRANT SELECT on test.* to PUBLIC; +GRANT SELECT on mysql.db to PUBLIC; +select * from mysql.global_priv where user="PUBLIC" ; +Host User Priv + PUBLIC {"access":0,"version_id":VERSION,"is_role":true} +SHOW GRANTS FOR PUBLIC; +Grants for PUBLIC +GRANT SELECT ON `test`.* TO `PUBLIC` +GRANT SELECT ON `mysql`.`db` TO `PUBLIC` +GRANT UPDATE on test.* to PUBLIC; +GRANT UPDATE on mysql.db to PUBLIC; +SHOW GRANTS FOR PUBLIC; +Grants for PUBLIC +GRANT SELECT, UPDATE ON `test`.* TO `PUBLIC` +GRANT SELECT, UPDATE ON `mysql`.`db` TO `PUBLIC` +REVOKE SELECT on test.* from PUBLIC; +REVOKE SELECT on mysql.db from PUBLIC; +SHOW GRANTS FOR PUBLIC; +Grants for PUBLIC +GRANT UPDATE ON `test`.* TO `PUBLIC` +GRANT UPDATE ON `mysql`.`db` TO `PUBLIC` +REVOKE UPDATE on test.* from PUBLIC; +REVOKE UPDATE on mysql.db from PUBLIC; +SHOW GRANTS FOR PUBLIC; +Grants for PUBLIC +GRANT XXXXXX TO CURRENT_USER; +ERROR OP000: Invalid role specification `XXXXXX` +# following should fail with the same error as above +GRANT PUBLIC TO CURRENT_USER; +ERROR OP000: Invalid role specification `PUBLIC` +REVOKE XXXXXX FROM CURRENT_USER; +ERROR OP000: Invalid role specification `XXXXXX` +# following should fail with the same error as above +REVOKE PUBLIC FROM CURRENT_USER; +ERROR OP000: Invalid role specification `PUBLIC` +drop role XXXXXX; +ERROR HY000: Operation DROP ROLE failed for 'XXXXXX' +# following should fail with the same error as above +drop role PUBLIC; +ERROR HY000: Operation DROP ROLE failed for PUBLIC +SET ROLE XXXXXX; +ERROR OP000: Invalid role specification `XXXXXX` +# following should fail with the same error as above +SET ROLE PUBLIC; +ERROR OP000: Invalid role specification `PUBLIC` +SET DEFAULT ROLE XXXXXX; +ERROR OP000: Invalid role specification `XXXXXX` +# following should fail with the same error as above +SET DEFAULT ROLE PUBLIC; +ERROR OP000: Invalid role specification `PUBLIC` +# +# check prohibition of change security context to PUBLIC +# +# be sure that we have PUBLIC +GRANT SELECT on test.* to PUBLIC; +# try with a view +create table t1( a int); +create definer = PUBLIC view v1 as select * from t1; +Warnings: +Note 1449 The user specified as a definer ('PUBLIC'@'') does not exist +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`PUBLIC` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci +Warnings: +Note 1449 The user specified as a definer ('PUBLIC'@'') does not exist +select * from v1; +ERROR HY000: The user specified as a definer ('PUBLIC'@'') does not exist +drop view v1; +drop table t1; +# try with a view +create definer='PUBLIC' PROCEDURE p1() SELECT 1; +Warnings: +Note 1449 The user specified as a definer ('PUBLIC'@'') does not exist +show create procedure p1; +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +p1 STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`PUBLIC` PROCEDURE `p1`() +SELECT 1 latin1 latin1_swedish_ci latin1_swedish_ci +call p1(); +ERROR HY000: The user specified as a definer ('PUBLIC'@'') does not exist +drop procedure p1; +# this test cleanup +REVOKE SELECT on test.* from PUBLIC; +# +# check autocreation of PUBLIC on GRAND role TO PUBLIC +# +# make sure that the privilege will be added automatically +delete from mysql.global_priv where user="PUBLIC"; +flush privileges; +create role roletest; +GRANT roletest TO PUBLIC; +drop role roletest; +# clean up +delete from mysql.global_priv where user="PUBLIC"; +flush privileges; diff --git a/mysql-test/main/public_basic.test b/mysql-test/main/public_basic.test new file mode 100644 index 00000000000..ddb4e040fce --- /dev/null +++ b/mysql-test/main/public_basic.test @@ -0,0 +1,130 @@ +SHOW GRANTS FOR PUBLIC; + +--echo # it is not PUBLIC but an user +--echo # (this should work as it allowed for roles for example) +create user PUBLIC; +create user PUBLIC@localhost; +GRANT SELECT on test.* to PUBLIC@localhost; +drop user PUBLIC@localhost; +drop user PUBLIC; + +--echo # preinstalled PUBLIC +GRANT SELECT on test.* to PUBLIC; +GRANT SELECT on mysql.db to PUBLIC; +--replace_regex /"version_id"\:[0-9]+/"version_id":VERSION/ +select * from mysql.global_priv where user="PUBLIC" ; + +SHOW GRANTS FOR PUBLIC; + +GRANT UPDATE on test.* to PUBLIC; +GRANT UPDATE on mysql.db to PUBLIC; + +SHOW GRANTS FOR PUBLIC; + +REVOKE SELECT on test.* from PUBLIC; +REVOKE SELECT on mysql.db from PUBLIC; + +SHOW GRANTS FOR PUBLIC; + +REVOKE UPDATE on test.* from PUBLIC; +REVOKE UPDATE on mysql.db from PUBLIC; + +--error ER_NONEXISTING_GRANT +REVOKE UPDATE on test.* from PUBLIC; +--error ER_NONEXISTING_TABLE_GRANT +REVOKE UPDATE on mysql.db from PUBLIC; + +SHOW GRANTS FOR PUBLIC; + +--echo # automaticly added PUBLIC +delete from mysql.global_priv where user="PUBLIC"; +flush privileges; +select * from mysql.global_priv where user="PUBLIC" ; +GRANT SELECT on test.* to PUBLIC; +GRANT SELECT on mysql.db to PUBLIC; +--replace_regex /"version_id"\:[0-9]+/"version_id":VERSION/ +select * from mysql.global_priv where user="PUBLIC" ; + +SHOW GRANTS FOR PUBLIC; + +GRANT UPDATE on test.* to PUBLIC; +GRANT UPDATE on mysql.db to PUBLIC; + +SHOW GRANTS FOR PUBLIC; + +REVOKE SELECT on test.* from PUBLIC; +REVOKE SELECT on mysql.db from PUBLIC; + +SHOW GRANTS FOR PUBLIC; + +REVOKE UPDATE on test.* from PUBLIC; +REVOKE UPDATE on mysql.db from PUBLIC; + +SHOW GRANTS FOR PUBLIC; + +--error ER_INVALID_ROLE +GRANT XXXXXX TO CURRENT_USER; +--echo # following should fail with the same error as above +--error ER_INVALID_ROLE +GRANT PUBLIC TO CURRENT_USER; + +--error ER_INVALID_ROLE +REVOKE XXXXXX FROM CURRENT_USER; +--echo # following should fail with the same error as above +--error ER_INVALID_ROLE +REVOKE PUBLIC FROM CURRENT_USER; +--error ER_CANNOT_USER + +drop role XXXXXX; +--echo # following should fail with the same error as above +--error ER_CANNOT_USER +drop role PUBLIC; + +--error ER_INVALID_ROLE +SET ROLE XXXXXX; +--echo # following should fail with the same error as above +--error ER_INVALID_ROLE +SET ROLE PUBLIC; + +--error ER_INVALID_ROLE +SET DEFAULT ROLE XXXXXX; +--echo # following should fail with the same error as above +--error ER_INVALID_ROLE +SET DEFAULT ROLE PUBLIC; + +--echo # +--echo # check prohibition of change security context to PUBLIC +--echo # +--echo # be sure that we have PUBLIC +GRANT SELECT on test.* to PUBLIC; +--echo # try with a view +create table t1( a int); +create definer = PUBLIC view v1 as select * from t1; +show create view v1; +--error ER_NO_SUCH_USER +select * from v1; +drop view v1; +drop table t1; +--echo # try with a view +create definer='PUBLIC' PROCEDURE p1() SELECT 1; +show create procedure p1; +--error ER_NO_SUCH_USER +call p1(); +drop procedure p1; +--echo # this test cleanup +REVOKE SELECT on test.* from PUBLIC; + +--echo # +--echo # check autocreation of PUBLIC on GRAND role TO PUBLIC +--echo # +--echo # make sure that the privilege will be added automatically +delete from mysql.global_priv where user="PUBLIC"; +flush privileges; +create role roletest; +GRANT roletest TO PUBLIC; +drop role roletest; + + +-- echo # clean up +delete from mysql.global_priv where user="PUBLIC"; +flush privileges; diff --git a/mysql-test/main/public_privileges.result b/mysql-test/main/public_privileges.result new file mode 100644 index 00000000000..ae50ab78553 --- /dev/null +++ b/mysql-test/main/public_privileges.result @@ -0,0 +1,346 @@ +# +# Test DB/TABLE/COLUMN privileges in queries +# +SHOW GRANTS FOR PUBLIC; +Grants for PUBLIC +create user testuser; +create database testdb1; +use testdb1; +create table t1 (a int, b int); +insert into t1 values (1,2); +create database testdb2; +use testdb2; +create table t2 (a int, b int); +insert into t2 values (1,2); +create table t3 (a int, b int); +insert into t3 values (1,2); +connect testuser,localhost,testuser,,; +connection testuser; +select * from testdb1.t1; +ERROR 42000: SELECT command denied to user 'testuser'@'localhost' for table `testdb1`.`t1` +select * from testdb2.t2; +ERROR 42000: SELECT command denied to user 'testuser'@'localhost' for table `testdb2`.`t2` +select b from testdb2.t3; +ERROR 42000: SELECT command denied to user 'testuser'@'localhost' for table `testdb2`.`t3` +select a from testdb2.t3; +ERROR 42000: SELECT command denied to user 'testuser'@'localhost' for table `testdb2`.`t3` +connection default; +GRANT SELECT ON testdb1.* to PUBLIC; +GRANT SELECT ON testdb2.t2 to PUBLIC; +GRANT SELECT (b) ON testdb2.t3 to PUBLIC; +disconnect testuser; +connect testuser,localhost,testuser,,; +connection testuser; +select * from testdb1.t1; +a b +1 2 +select * from testdb2.t2; +a b +1 2 +select b from testdb2.t3; +b +2 +select a from testdb2.t3; +ERROR 42000: SELECT command denied to user 'testuser'@'localhost' for column 'a' in table 't3' +connection default; +disconnect testuser; +# check that the privilegas correctly read by acl_load +flush privileges; +connect testuser,localhost,testuser,,; +connection testuser; +select * from testdb1.t1; +a b +1 2 +select * from testdb2.t2; +a b +1 2 +select b from testdb2.t3; +b +2 +select a from testdb2.t3; +ERROR 42000: SELECT command denied to user 'testuser'@'localhost' for column 'a' in table 't3' +connection default; +use test; +disconnect testuser; +REVOKE SELECT ON testdb1.* from PUBLIC; +REVOKE SELECT ON testdb2.t2 from PUBLIC; +REVOKE SELECT (b) ON testdb2.t3 from PUBLIC; +drop user testuser; +drop database testdb1; +drop database testdb2; +# +# test global process list privilege and EXECUTE db level +# +create user testuser; +create database testdb; +use testdb; +create procedure p1 () select 1; +connect testuser,localhost,testuser,,; +connection testuser; +SHOW PROCESSLIST; +Id User Host db Command Time State Info Progress +# testuser # NULL Query # # SHOW PROCESSLIST 0.000 +call testdb.p1(); +ERROR 42000: execute command denied to user 'testuser'@'%' for routine 'testdb.p1' +connection default; +GRANT PROCESS ON *.* to PUBLIC; +GRANT EXECUTE ON testdb.* to PUBLIC; +disconnect testuser; +connect testuser,localhost,testuser,,; +connection testuser; +SHOW PROCESSLIST; +Id User Host db Command Time State Info Progress +# root # testdb Sleep # # NULL 0.000 +# testuser # NULL Query # # SHOW PROCESSLIST 0.000 +call testdb.p1(); +1 +1 +connection default; +disconnect testuser; +# check that the privilegas correctly read by acl_load +flush privileges; +connect testuser,localhost,testuser,,; +connection testuser; +SHOW PROCESSLIST; +Id User Host db Command Time State Info Progress +# root # testdb Sleep # # NULL 0.000 +# testuser # NULL Query # # SHOW PROCESSLIST 0.000 +call testdb.p1(); +1 +1 +connection default; +SHOW PROCESSLIST; +Id User Host db Command Time State Info Progress +# root # testdb Query # # SHOW PROCESSLIST 0.000 +# testuser # NULL Sleep # # NULL 0.000 +connection default; +use test; +disconnect testuser; +REVOKE PROCESS ON *.* from PUBLIC; +REVOKE EXECUTE ON testdb.* from PUBLIC; +drop user testuser; +drop database testdb; +# +# test DB privilege to allow USE statement +# +create user testuser; +create database testdb; +connect testuser,localhost,testuser,,; +connection testuser; +use testdb; +ERROR 42000: Access denied for user 'testuser'@'%' to database 'testdb' +connection default; +GRANT LOCK TABLES ON testdb.* to PUBLIC; +disconnect testuser; +connect testuser,localhost,testuser,,; +connection testuser; +use testdb; +connection default; +disconnect testuser; +# check that the privilegas correctly read by acl_load +flush privileges; +connect testuser,localhost,testuser,,; +connection testuser; +use testdb; +connection default; +use test; +disconnect testuser; +REVOKE LOCK TABLES ON testdb.* from PUBLIC; +drop user testuser; +drop database testdb; +# +# test DB privilege to allow USE statement (as above) +# test current db privileges +# +create user testuser; +create database testdb; +use testdb; +create table t1 (a int); +insert into t1 values (1); +GRANT LOCK TABLES ON testdb.* to PUBLIC; +connect testuser,localhost,testuser,,; +connection testuser; +use testdb; +update t1 set a=a+1; +ERROR 42000: UPDATE command denied to user 'testuser'@'localhost' for table `testdb`.`t1` +connection default; +GRANT UPDATE,SELECT ON testdb.* to PUBLIC; +disconnect testuser; +connect testuser,localhost,testuser,,; +connection testuser; +use testdb; +update t1 set a=a+1; +connection default; +select * from testdb.t1; +a +2 +use test; +disconnect testuser; +REVOKE LOCK TABLES ON testdb.* from PUBLIC; +REVOKE UPDATE,SELECT ON testdb.* from PUBLIC; +drop user testuser; +drop database testdb; +# +# test DB privilege to allow USE statement (as above) +# test table/column privileges in current DB +# +create user testuser; +create database testdb; +use testdb; +create table t1 (a int); +insert into t1 values (1); +create table t2 (a int, b int); +insert into t2 values (1,2); +GRANT LOCK TABLES ON testdb.* to PUBLIC; +connect testuser,localhost,testuser,,; +connection testuser; +use testdb; +delete from t1; +ERROR 42000: DELETE command denied to user 'testuser'@'localhost' for table `testdb`.`t1` +select b from t2; +ERROR 42000: SELECT command denied to user 'testuser'@'localhost' for table `testdb`.`t2` +select a from t2; +ERROR 42000: SELECT command denied to user 'testuser'@'localhost' for table `testdb`.`t2` +connection default; +GRANT DELETE ON testdb.t1 to PUBLIC; +GRANT SELECT (a) ON testdb.t2 to PUBLIC; +disconnect testuser; +connect testuser,localhost,testuser,,; +connection testuser; +use testdb; +delete from t1; +select a from t2; +a +1 +select b from t2; +ERROR 42000: SELECT command denied to user 'testuser'@'localhost' for column 'b' in table 't2' +connection default; +select * from testdb.t1; +a +insert into t1 values (1); +disconnect testuser; +# check that the privilegas correctly read by acl_load +flush privileges; +connect testuser,localhost,testuser,,; +connection testuser; +use testdb; +delete from t1; +select a from t2; +a +1 +select b from t2; +ERROR 42000: SELECT command denied to user 'testuser'@'localhost' for column 'b' in table 't2' +connection default; +select * from testdb.t1; +a +use test; +disconnect testuser; +REVOKE ALL PRIVILEGES, GRANT OPTION from `PUBLIC`; +SHOW GRANTS FOR PUBLIC; +Grants for PUBLIC +drop user testuser; +drop database testdb; +# +# test function privilege +# +create user testuser; +create database testdb; +use testdb; +create function f1() returns int return 2; +connect testuser,localhost,testuser,,; +connection testuser; +alter function testdb.f1 comment "A stupid function"; +ERROR 42000: alter routine command denied to user 'testuser'@'%' for routine 'testdb.f1' +select testdb.f1(); +ERROR 42000: execute command denied to user 'testuser'@'%' for routine 'testdb.f1' +connection default; +GRANT ALTER ROUTINE ON testdb.* to PUBLIC; +disconnect testuser; +connect testuser,localhost,testuser,,; +connection testuser; +alter function testdb.f1 comment "A stupid function"; +select testdb.f1(); +ERROR 42000: execute command denied to user 'testuser'@'%' for routine 'testdb.f1' +connection default; +disconnect testuser; +# check that the privilegas correctly read by acl_load +flush privileges; +connect testuser,localhost,testuser,,; +connection testuser; +alter function testdb.f1 comment "A stupid function"; +select testdb.f1(); +ERROR 42000: execute command denied to user 'testuser'@'%' for routine 'testdb.f1' +connection default; +use test; +disconnect testuser; +REVOKE ALTER ROUTINE ON testdb.* from PUBLIC; +drop function testdb.f1; +drop user testuser; +drop database testdb; +# +# bug with automatically added PUBLIC role +# +# automaticly added PUBLIC +delete from mysql.global_priv where user="PUBLIC"; +flush privileges; +GRANT SELECT on test.* to PUBLIC; +REVOKE SELECT on test.* from PUBLIC; +create user testuser; +create database testdb1; +use testdb1; +create table t1 (a int, b int); +insert into t1 values (1,2); +connect testuser,localhost,testuser,,; +connection testuser; +select * from testdb1.t1; +ERROR 42000: SELECT command denied to user 'testuser'@'localhost' for table `testdb1`.`t1` +connection default; +disconnect testuser; +drop user testuser; +drop database testdb1; +# +# check assigning privileges via GRAND role TO PUBLIC +# +create user testuser; +create database testdb1; +use testdb1; +create table t1 (a int, b int); +# check that user do not have rights +connect testuser,localhost,testuser,,*NO-ONE*; +connection testuser; +select * from testdb1.t1; +ERROR 42000: SELECT command denied to user 'testuser'@'localhost' for table `testdb1`.`t1` +connection default; +disconnect testuser; +give rights to everyone via assigning the role to public +create role roletest; +GRANT SELECT ON testdb1.* TO roletest; +GRANT roletest TO PUBLIC; +connect testuser,localhost,testuser,,*NO-ONE*; +connection testuser; +select * from testdb1.t1; +a b +connection default; +disconnect testuser; +# check that the privilegas correctly read by acl_load +flush privileges; +connect testuser,localhost,testuser,,*NO-ONE*; +connection testuser; +select * from testdb1.t1; +a b +connection default; +disconnect testuser; +# drop role... +drop role roletest; +# ... and check that user do not have rights again +connect testuser,localhost,testuser,,*NO-ONE*; +connection testuser; +select * from testdb1.t1; +ERROR 42000: SELECT command denied to user 'testuser'@'localhost' for table `testdb1`.`t1` +connection default; +disconnect testuser; +drop user testuser; +drop database testdb1; +# clean up +delete from mysql.global_priv where user="PUBLIC"; +flush privileges; diff --git a/mysql-test/main/public_privileges.test b/mysql-test/main/public_privileges.test new file mode 100644 index 00000000000..2de23b5c81a --- /dev/null +++ b/mysql-test/main/public_privileges.test @@ -0,0 +1,411 @@ +--echo # +--echo # Test DB/TABLE/COLUMN privileges in queries +--echo # + +SHOW GRANTS FOR PUBLIC; + +create user testuser; +create database testdb1; +use testdb1; +create table t1 (a int, b int); +insert into t1 values (1,2); +create database testdb2; +use testdb2; +create table t2 (a int, b int); +insert into t2 values (1,2); +create table t3 (a int, b int); +insert into t3 values (1,2); + +connect (testuser,localhost,testuser,,); +connection testuser; +--error ER_TABLEACCESS_DENIED_ERROR +select * from testdb1.t1; +--error ER_TABLEACCESS_DENIED_ERROR +select * from testdb2.t2; +--error ER_TABLEACCESS_DENIED_ERROR +select b from testdb2.t3; +--error ER_TABLEACCESS_DENIED_ERROR +select a from testdb2.t3; + +connection default; + +GRANT SELECT ON testdb1.* to PUBLIC; +GRANT SELECT ON testdb2.t2 to PUBLIC; +GRANT SELECT (b) ON testdb2.t3 to PUBLIC; + +disconnect testuser; +connect (testuser,localhost,testuser,,); +connection testuser; +select * from testdb1.t1; +select * from testdb2.t2; +select b from testdb2.t3; +--error ER_COLUMNACCESS_DENIED_ERROR +select a from testdb2.t3; + +connection default; +disconnect testuser; + +--echo # check that the privilegas correctly read by acl_load +flush privileges; + +connect (testuser,localhost,testuser,,); +connection testuser; +select * from testdb1.t1; +select * from testdb2.t2; +select b from testdb2.t3; +--error ER_COLUMNACCESS_DENIED_ERROR +select a from testdb2.t3; + +connection default; +use test; +disconnect testuser; +REVOKE SELECT ON testdb1.* from PUBLIC; +REVOKE SELECT ON testdb2.t2 from PUBLIC; +REVOKE SELECT (b) ON testdb2.t3 from PUBLIC; +drop user testuser; +drop database testdb1; +drop database testdb2; + +--echo # +--echo # test global process list privilege and EXECUTE db level +--echo # + +create user testuser; +create database testdb; +use testdb; +create procedure p1 () select 1; + +connect (testuser,localhost,testuser,,); +connection testuser; + +--replace_column 1 # 3 # 6 # 7 # +SHOW PROCESSLIST; +--error ER_PROCACCESS_DENIED_ERROR +call testdb.p1(); + +connection default; + +GRANT PROCESS ON *.* to PUBLIC; +GRANT EXECUTE ON testdb.* to PUBLIC; + +disconnect testuser; +connect (testuser,localhost,testuser,,); +connection testuser; + +--replace_column 1 # 3 # 6 # 7 # +SHOW PROCESSLIST; +call testdb.p1(); + +connection default; +disconnect testuser; + +--echo # check that the privilegas correctly read by acl_load +flush privileges; + +connect (testuser,localhost,testuser,,); +connection testuser; + +--replace_column 1 # 3 # 6 # 7 # +SHOW PROCESSLIST; +call testdb.p1(); + +connection default; + +--replace_column 1 # 3 # 6 # 7 # +SHOW PROCESSLIST; + +connection default; + +use test; +disconnect testuser; +REVOKE PROCESS ON *.* from PUBLIC; +REVOKE EXECUTE ON testdb.* from PUBLIC; +drop user testuser; +drop database testdb; + +--echo # +--echo # test DB privilege to allow USE statement +--echo # + +create user testuser; +create database testdb; + +connect (testuser,localhost,testuser,,); +connection testuser; + +--error ER_DBACCESS_DENIED_ERROR +use testdb; + +connection default; + +GRANT LOCK TABLES ON testdb.* to PUBLIC; + +disconnect testuser; +connect (testuser,localhost,testuser,,); +connection testuser; + +use testdb; + +connection default; +disconnect testuser; + +--echo # check that the privilegas correctly read by acl_load +flush privileges; + +connect (testuser,localhost,testuser,,); +connection testuser; + +use testdb; + +connection default; + +use test; +disconnect testuser; +REVOKE LOCK TABLES ON testdb.* from PUBLIC; +drop user testuser; +drop database testdb; + + +--echo # +--echo # test DB privilege to allow USE statement (as above) +--echo # test current db privileges +--echo # + +create user testuser; +create database testdb; +use testdb; +create table t1 (a int); +insert into t1 values (1); +GRANT LOCK TABLES ON testdb.* to PUBLIC; + +connect (testuser,localhost,testuser,,); +connection testuser; + +use testdb; +--error ER_TABLEACCESS_DENIED_ERROR +update t1 set a=a+1; + +connection default; + +GRANT UPDATE,SELECT ON testdb.* to PUBLIC; + +disconnect testuser; +connect (testuser,localhost,testuser,,); +connection testuser; + +use testdb; +update t1 set a=a+1; + +connection default; +select * from testdb.t1; + +use test; +disconnect testuser; +REVOKE LOCK TABLES ON testdb.* from PUBLIC; +REVOKE UPDATE,SELECT ON testdb.* from PUBLIC; +drop user testuser; +drop database testdb; + + +--echo # +--echo # test DB privilege to allow USE statement (as above) +--echo # test table/column privileges in current DB +--echo # + +create user testuser; +create database testdb; +use testdb; +create table t1 (a int); +insert into t1 values (1); +create table t2 (a int, b int); +insert into t2 values (1,2); +GRANT LOCK TABLES ON testdb.* to PUBLIC; + +connect (testuser,localhost,testuser,,); +connection testuser; + +use testdb; +--error ER_TABLEACCESS_DENIED_ERROR +delete from t1; +--error ER_TABLEACCESS_DENIED_ERROR +select b from t2; +--error ER_TABLEACCESS_DENIED_ERROR +select a from t2; + +connection default; + +GRANT DELETE ON testdb.t1 to PUBLIC; +GRANT SELECT (a) ON testdb.t2 to PUBLIC; + +disconnect testuser; +connect (testuser,localhost,testuser,,); +connection testuser; + +use testdb; +delete from t1; +select a from t2; +--error ER_COLUMNACCESS_DENIED_ERROR +select b from t2; + +connection default; +select * from testdb.t1; +insert into t1 values (1); +disconnect testuser; + +--echo # check that the privilegas correctly read by acl_load +flush privileges; + +connect (testuser,localhost,testuser,,); +connection testuser; + +use testdb; +delete from t1; +select a from t2; +--error ER_COLUMNACCESS_DENIED_ERROR +select b from t2; + +connection default; +select * from testdb.t1; + + +use test; +disconnect testuser; +REVOKE ALL PRIVILEGES, GRANT OPTION from `PUBLIC`; +SHOW GRANTS FOR PUBLIC; + +drop user testuser; +drop database testdb; + +--echo # +--echo # test function privilege +--echo # + +create user testuser; +create database testdb; +use testdb; +create function f1() returns int return 2; + +connect (testuser,localhost,testuser,,); +connection testuser; + +--error ER_PROCACCESS_DENIED_ERROR +alter function testdb.f1 comment "A stupid function"; +--error ER_PROCACCESS_DENIED_ERROR +select testdb.f1(); + +connection default; + +GRANT ALTER ROUTINE ON testdb.* to PUBLIC; + +disconnect testuser; +connect (testuser,localhost,testuser,,); +connection testuser; + +alter function testdb.f1 comment "A stupid function"; +--error ER_PROCACCESS_DENIED_ERROR +select testdb.f1(); + +connection default; +disconnect testuser; + +--echo # check that the privilegas correctly read by acl_load +flush privileges; + +connect (testuser,localhost,testuser,,); +connection testuser; + +alter function testdb.f1 comment "A stupid function"; +--error ER_PROCACCESS_DENIED_ERROR +select testdb.f1(); + +connection default; + +use test; +disconnect testuser; +REVOKE ALTER ROUTINE ON testdb.* from PUBLIC; +drop function testdb.f1; +drop user testuser; +drop database testdb; + +--echo # +--echo # bug with automatically added PUBLIC role +--echo # + +--echo # automaticly added PUBLIC +delete from mysql.global_priv where user="PUBLIC"; +flush privileges; +GRANT SELECT on test.* to PUBLIC; + +REVOKE SELECT on test.* from PUBLIC; + +create user testuser; +create database testdb1; +use testdb1; +create table t1 (a int, b int); +insert into t1 values (1,2); + +connect (testuser,localhost,testuser,,); +connection testuser; +--error ER_TABLEACCESS_DENIED_ERROR +select * from testdb1.t1; + +connection default; + +disconnect testuser; +drop user testuser; +drop database testdb1; + +--echo # +--echo # check assigning privileges via GRAND role TO PUBLIC +--echo # +create user testuser; +create database testdb1; +use testdb1; +create table t1 (a int, b int); + +--echo # check that user do not have rights +connect (testuser,localhost,testuser,,*NO-ONE*); +connection testuser; +--error ER_TABLEACCESS_DENIED_ERROR +select * from testdb1.t1; +connection default; +disconnect testuser; + +--echo give rights to everyone via assigning the role to public +create role roletest; +GRANT SELECT ON testdb1.* TO roletest; +GRANT roletest TO PUBLIC; + +connect (testuser,localhost,testuser,,*NO-ONE*); +connection testuser; +select * from testdb1.t1; +connection default; +disconnect testuser; + +--echo # check that the privilegas correctly read by acl_load +flush privileges; + +connect (testuser,localhost,testuser,,*NO-ONE*); +connection testuser; +select * from testdb1.t1; +connection default; +disconnect testuser; + + +--echo # drop role... +drop role roletest; + +--echo # ... and check that user do not have rights again +connect (testuser,localhost,testuser,,*NO-ONE*); +connection testuser; +--error ER_TABLEACCESS_DENIED_ERROR +select * from testdb1.t1; +connection default; +disconnect testuser; + +drop user testuser; +drop database testdb1; + +-- echo # clean up +delete from mysql.global_priv where user="PUBLIC"; +flush privileges; diff --git a/mysql-test/suite/roles/none_public.result b/mysql-test/suite/roles/none_public.result index c253ae1478b..4acba8bd133 100644 --- a/mysql-test/suite/roles/none_public.result +++ b/mysql-test/suite/roles/none_public.result @@ -14,9 +14,6 @@ ERROR OP000: Invalid role specification `none` grant public to role1; ERROR OP000: Invalid role specification `public` grant role1 to public; -ERROR OP000: Invalid role specification `public` -grant select on *.* to public; -ERROR OP000: Invalid role specification `public` grant role1 to current_role; ERROR OP000: Invalid role specification `NONE` revoke none from role1; @@ -28,21 +25,15 @@ ERROR OP000: Invalid role specification `none` revoke public from role1; ERROR OP000: Invalid role specification `public` revoke role1 from public; -ERROR OP000: Invalid role specification `public` +ERROR HY000: Cannot revoke role 'role1' from: 'public'@'%' revoke select on *.* from public; -ERROR OP000: Invalid role specification `public` show grants for none; ERROR OP000: Invalid role specification `none` -show grants for public; -ERROR OP000: Invalid role specification `public` create definer=none view test.v1 as select 1; ERROR OP000: Invalid role specification `none` -create definer=public view test.v1 as select 1; -ERROR OP000: Invalid role specification `public` drop role role1; -insert mysql.global_priv values ('', 'none', '{"is_role":true}'), ('', 'public', '{"is_role":true}'); +insert mysql.global_priv values ('', 'none', '{"is_role":true}'); flush privileges; Warnings: Error 1959 Invalid role specification `none` -Error 1959 Invalid role specification `public` delete from mysql.global_priv where host=''; diff --git a/mysql-test/suite/roles/none_public.test b/mysql-test/suite/roles/none_public.test index a0ec2315cfc..21e9dacf166 100644 --- a/mysql-test/suite/roles/none_public.test +++ b/mysql-test/suite/roles/none_public.test @@ -17,10 +17,10 @@ grant role1 to none; grant select on *.* to none; --error ER_INVALID_ROLE grant public to role1; ---error ER_INVALID_ROLE grant role1 to public; ---error ER_INVALID_ROLE -grant select on *.* to public; +# PUBLIC is legal role +#--error ER_INVALID_ROLE +#grant select on *.* to public; --error ER_INVALID_ROLE grant role1 to current_role; @@ -33,23 +33,24 @@ revoke role1 from none; revoke select on *.* from none; --error ER_INVALID_ROLE revoke public from role1; ---error ER_INVALID_ROLE +--error ER_CANNOT_REVOKE_ROLE revoke role1 from public; ---error ER_INVALID_ROLE revoke select on *.* from public; --error ER_INVALID_ROLE show grants for none; ---error ER_INVALID_ROLE -show grants for public; +# PUBLIC is legal role +#--error ER_INVALID_ROLE +#show grants for public; --error ER_INVALID_ROLE create definer=none view test.v1 as select 1; ---error ER_INVALID_ROLE -create definer=public view test.v1 as select 1; +# PUBLIC is legal role +#--error ER_INVALID_ROLE +#create definer=public view test.v1 as select 1; drop role role1; -insert mysql.global_priv values ('', 'none', '{"is_role":true}'), ('', 'public', '{"is_role":true}'); +insert mysql.global_priv values ('', 'none', '{"is_role":true}'); flush privileges; delete from mysql.global_priv where host=''; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 20293c613f2..4713787ade8 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -103,7 +103,9 @@ LEX_CSTRING host_not_specified= { STRING_WITH_LEN("%") }; */ LEX_CSTRING current_user= { STRING_WITH_LEN("*current_user") }; LEX_CSTRING current_role= { STRING_WITH_LEN("*current_role") }; -LEX_CSTRING current_user_and_current_role= { STRING_WITH_LEN("*current_user_and_current_role") }; +LEX_CSTRING current_user_and_current_role= + { STRING_WITH_LEN("*current_user_and_current_role") }; +LEX_CSTRING public_name= {STRING_WITH_LEN("PUBLIC") }; static plugin_ref old_password_plugin; @@ -317,6 +319,13 @@ static bool show_table_and_column_privileges(THD *, const char *, const char *, static int show_routine_grants(THD *, const char *, const char *, const Sp_handler *sph, char *, int); +static ACL_ROLE *acl_public= NULL; + +inline privilege_t public_access() +{ + return (acl_public ? acl_public->access : NO_ACL); +} + class Grant_tables; class User_table; class Proxies_priv_table; @@ -685,7 +694,7 @@ static void rebuild_check_host(void); static void rebuild_role_grants(void); static ACL_USER *find_user_exact(const char *host, const char *user); static ACL_USER *find_user_wild(const char *host, const char *user, const char *ip= 0); -static ACL_ROLE *find_acl_role(const char *user); +static ACL_ROLE *find_acl_role(const char *user, bool allow_public); static ROLE_GRANT_PAIR *find_role_grant_pair(const LEX_CSTRING *u, const LEX_CSTRING *h, const LEX_CSTRING *r); static ACL_USER_BASE *find_acl_user_base(const char *user, const char *host); static bool update_user_table_password(THD *, const User_table&, const ACL_USER&); @@ -2196,14 +2205,32 @@ ACL_ROLE::ACL_ROLE(const char * rolename, privilege_t privileges, flags= IS_ROLE; } - -static bool is_invalid_role_name(const char *str) +enum role_name_check_result { - if (*str && strcasecmp(str, "PUBLIC") && strcasecmp(str, "NONE")) - return false; + ROLE_NAME_OK= 0, + ROLE_NAME_PUBLIC, + ROLE_NAME_INVALID +}; +static role_name_check_result check_role_name(const char *str, + bool public_is_ok) +{ + if (*str) + { + if (strcasecmp(str, public_name.str) == 0) + { + if (public_is_ok) + return ROLE_NAME_PUBLIC; + else + goto error; + } + if (strcasecmp(str, "NONE") != 0) + return ROLE_NAME_OK; + } + +error: my_error(ER_INVALID_ROLE, MYF(0), str); - return true; + return ROLE_NAME_INVALID; } @@ -2632,7 +2659,8 @@ static bool acl_load(THD *thd, const Grant_tables& tables) if (is_role) { - if (is_invalid_role_name(username)) + role_name_check_result result= check_role_name(username, true); + if (result == ROLE_NAME_INVALID) { thd->clear_error(); // the warning is still issued continue; @@ -2642,6 +2670,9 @@ static bool acl_load(THD *thd, const Grant_tables& tables) entry->role_grants = user.role_grants; my_init_dynamic_array(key_memory_acl_mem, &entry->parent_grantee, sizeof(ACL_USER_BASE *), 0, 8, MYF(0)); + if (result == ROLE_NAME_PUBLIC) + acl_public= entry; + my_hash_insert(&acl_roles, (uchar *)entry); continue; @@ -2697,7 +2728,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) char *db_name; db.user=safe_str(get_field(&acl_memroot, db_table.user())); const char *hostname= get_field(&acl_memroot, db_table.host()); - if (!hostname && find_acl_role(db.user)) + if (!hostname && find_acl_role(db.user, true)) hostname= ""; update_hostname(&db.host, hostname); db.db= db_name= get_field(&acl_memroot, db_table.db()); @@ -2827,6 +2858,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) void acl_free(bool end) { my_hash_free(&acl_roles); + acl_public= NULL; free_root(&acl_memroot,MYF(0)); delete_dynamic(&acl_hosts); delete_dynamic_with_callback(&acl_users, (FREE_FUNC) free_acl_user); @@ -2871,10 +2903,13 @@ bool acl_reload(THD *thd) DYNAMIC_ARRAY old_acl_hosts, old_acl_users, old_acl_proxy_users; Dynamic_array old_acl_dbs(PSI_INSTRUMENT_MEM, 0, 0); HASH old_acl_roles, old_acl_roles_mappings; + ACL_ROLE *old_acl_public; MEM_ROOT old_mem; int result; DBUG_ENTER("acl_reload"); + acl_public= NULL; + Grant_tables tables; /* To avoid deadlocks we should obtain table locks before @@ -2901,6 +2936,7 @@ bool acl_reload(THD *thd) old_acl_hosts= acl_hosts; old_acl_users= acl_users; old_acl_roles= acl_roles; + old_acl_public= acl_public; old_acl_roles_mappings= acl_roles_mappings; old_acl_proxy_users= acl_proxy_users; old_acl_dbs= acl_dbs; @@ -2925,6 +2961,7 @@ bool acl_reload(THD *thd) acl_hosts= old_acl_hosts; acl_users= old_acl_users; acl_roles= old_acl_roles; + acl_public= old_acl_public; acl_roles_mappings= old_acl_roles_mappings; acl_proxy_users= old_acl_proxy_users; acl_dbs= old_acl_dbs; @@ -3209,7 +3246,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host, } else // Role, not User { - ACL_ROLE *acl_role= find_acl_role(user); + ACL_ROLE *acl_role= find_acl_role(user, false); if (acl_role) { res= 0; @@ -3222,6 +3259,14 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host, } } + if (acl_public) + { + if (ACL_DB *acl_db= acl_db_find(db, public_name.str, "", "", FALSE)) + sctx->db_access|= acl_db->access; + + sctx->master_access|= acl_public->access; + } + mysql_mutex_unlock(&acl_cache->lock); DBUG_RETURN(res); } @@ -3276,7 +3321,7 @@ static int check_user_can_set_role(THD *thd, const char *user, goto end; } - role= find_acl_role(rolename); + role= find_acl_role(rolename, false); /* According to SQL standard, the same error message must be presented */ if (role == NULL) @@ -3381,20 +3426,22 @@ int acl_setrole(THD *thd, const char *rolename, privilege_t access) /* merge the privileges */ Security_context *sctx= thd->security_ctx; sctx->master_access= access; - if (thd->db.str) - sctx->db_access= acl_get(sctx->host, sctx->ip, sctx->user, thd->db.str, FALSE); - if (!strcasecmp(rolename, "NONE")) { thd->security_ctx->priv_role[0]= 0; } else { - if (thd->db.str) - sctx->db_access|= acl_get("", "", rolename, thd->db.str, FALSE); /* mark the current role */ strmake_buf(thd->security_ctx->priv_role, rolename); } + if (thd->db.str) + sctx->db_access= acl_get_all3(sctx, thd->db.str, FALSE); + + // PUBLIC magic + if (acl_public) + sctx->master_access|= acl_public->access; + return 0; } @@ -3408,9 +3455,13 @@ static uchar* check_get_key(ACL_USER *buff, size_t *length, static void acl_update_role(const char *rolename, const privilege_t privileges) { - ACL_ROLE *role= find_acl_role(rolename); + ACL_ROLE *role= find_acl_role(rolename, true); if (role) + { role->initial_role_access= role->access= privileges; + if (strcasecmp(rolename, public_name.str) == 0) + acl_public= role; + } } @@ -3532,6 +3583,8 @@ static int acl_user_update(THD *thd, ACL_USER *acl_user, uint nauth, static void acl_insert_role(const char *rolename, privilege_t privileges) { ACL_ROLE *entry; + DBUG_ENTER("acl_insert_role"); + DBUG_PRINT("enter", ("Role: '%s'", rolename)); mysql_mutex_assert_owner(&acl_cache->lock); entry= new (&acl_memroot) ACL_ROLE(rolename, privileges, &acl_memroot); @@ -3541,6 +3594,10 @@ static void acl_insert_role(const char *rolename, privilege_t privileges) sizeof(ACL_ROLE *), 0, 8, MYF(0)); my_hash_insert(&acl_roles, (uchar *)entry); + if (strcasecmp(rolename, public_name.str) == 0) + acl_public= entry; + + DBUG_VOID_RETURN; } @@ -3659,7 +3716,9 @@ privilege_t acl_get(const char *host, const char *ip, if (acl_db->host.hostname) goto exit; // Fully specified. Take it /* the host table is not used for roles */ - if ((!host || !host[0]) && !acl_db->host.hostname && find_acl_role(user)) + if ((!host || !host[0]) && + !acl_db->host.hostname && + find_acl_role(user, false)) goto exit; } @@ -3699,6 +3758,23 @@ exit: DBUG_RETURN(db_access & host_access); } +/* + Check if there is access for the host/user, role, public on the database +*/ + +privilege_t acl_get_all3(Security_context *sctx, const char *db, + bool db_is_patern) +{ + privilege_t access= acl_get(sctx->host, sctx->ip, + sctx->priv_user, db, db_is_patern); + if (sctx->priv_role[0]) + access|= acl_get("", "", sctx->priv_role, db, db_is_patern); + if (acl_public) + access|= acl_get("", "", public_name.str, db, db_is_patern); + return access; +} + + /* Check if there are any possible matching entries for this host @@ -3820,7 +3896,7 @@ static bool add_role_user_mapping(const char *uname, const char *hname, const char *rname) { ACL_USER_BASE *grantee= find_acl_user_base(uname, hname); - ACL_ROLE *role= find_acl_role(rname); + ACL_ROLE *role= find_acl_role(rname, false); if (grantee == NULL || role == NULL) return 1; @@ -4319,7 +4395,7 @@ bool is_acl_user(const char *host, const char *user) if (*host) // User res= find_user_exact(host, user) != NULL; else // Role - res= find_acl_role(user) != NULL; + res= find_acl_role(user, false) != NULL; mysql_mutex_unlock(&acl_cache->lock); return res; @@ -4369,7 +4445,7 @@ static ACL_USER * find_user_wild(const char *host, const char *user, const char /* Find a role with the specified name */ -static ACL_ROLE *find_acl_role(const char *role) +static ACL_ROLE *find_acl_role(const char *role, bool allow_public) { size_t length= strlen(role); DBUG_ENTER("find_acl_role"); @@ -4378,7 +4454,9 @@ static ACL_ROLE *find_acl_role(const char *role) mysql_mutex_assert_owner(&acl_cache->lock); - if (!length) + if (!length || (!allow_public && + length == public_name.length && + strcasecmp(role, public_name.str) == 0)) DBUG_RETURN(NULL); ACL_ROLE *r= (ACL_ROLE *)my_hash_search(&acl_roles, (uchar *)role, @@ -4392,7 +4470,7 @@ static ACL_USER_BASE *find_acl_user_base(const char *user, const char *host) if (*host) return find_user_exact(host, user); - return find_acl_role(user); + return find_acl_role(user, true); } @@ -4608,10 +4686,7 @@ static bool test_if_create_new_users(THD *thd) NULL, TL_WRITE); create_new_users= 1; - db_access=acl_get(sctx->host, sctx->ip, - sctx->priv_user, tl.db.str, 0); - if (sctx->priv_role[0]) - db_access|= acl_get("", "", sctx->priv_role, tl.db.str, 0); + db_access= acl_get_all3(sctx, tl.db.str, FALSE); if (!(db_access & INSERT_ACL)) { if (check_grant(thd, INSERT_ACL, &tl, FALSE, UINT_MAX, TRUE)) @@ -4903,7 +4978,7 @@ static int replace_db_table(TABLE *table, const char *db, if (!find_user_wild(combo.host.str,combo.user.str)) { /* The user could be a role, check if the user is registered as a role */ - if (!combo.host.length && !find_acl_role(combo.user.str)) + if (!combo.host.length && !find_acl_role(combo.user.str, true)) { my_message(ER_PASSWORD_NO_MATCH, ER_THD(table->in_use, ER_PASSWORD_NO_MATCH), MYF(0)); @@ -5415,7 +5490,7 @@ GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine) const char *hostname= get_field(&grant_memroot, form->field[0]); mysql_mutex_lock(&acl_cache->lock); - if (!hostname && find_acl_role(user)) + if (!hostname && find_acl_role(user, true)) hostname= ""; mysql_mutex_unlock(&acl_cache->lock); update_hostname(&host, hostname); @@ -5874,6 +5949,10 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, privilege_t store_table_rights(NO_ACL), store_col_rights(NO_ACL); uchar user_key[MAX_KEY_LENGTH]; DBUG_ENTER("replace_table_table"); + DBUG_PRINT("enter", ("User: '%s' Host: '%s' Revoke:'%d'", + (combo.user.length ? combo.user.str : ""), + (combo.host.length ? combo.host.str : ""), + (int) revoke_grant)); get_grantor(thd, grantor); /* @@ -5882,7 +5961,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, */ if (!find_user_wild(combo.host.str,combo.user.str)) { - if (!combo.host.length && !find_acl_role(combo.user.str)) + if (!combo.host.length && !find_acl_role(combo.user.str, true)) { my_message(ER_PASSWORD_NO_MATCH, ER_THD(thd, ER_PASSWORD_NO_MATCH), MYF(0)); /* purecov: deadcode */ @@ -7196,8 +7275,9 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, error= copy_and_check_auth(Str, tmp_Str, thd) || replace_user_table(thd, tables.user_table(), Str, NO_ACL, revoke_grant, create_new_users, - MY_TEST(thd->variables.sql_mode & - MODE_NO_AUTO_CREATE_USER)); + MY_TEST(tmp_Str->is_public || + (thd->variables.sql_mode & + MODE_NO_AUTO_CREATE_USER))); if (unlikely(error)) { result= TRUE; // Remember error @@ -7293,7 +7373,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, } } if (Str->is_role()) - propagate_role_grants(find_acl_role(Str->user.str), + propagate_role_grants(find_acl_role(Str->user.str, true), PRIVS_TO_MERGE::TABLE_COLUMN, db_name, table_name); } @@ -7420,7 +7500,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, continue; } if (Str->is_role()) - propagate_role_grants(find_acl_role(Str->user.str), + propagate_role_grants(find_acl_role(Str->user.str, true), sp_privs_to_merge(sph->type()), db_name, table_name); } @@ -7558,7 +7638,7 @@ bool mysql_grant_role(THD *thd, List &list, bool revoke) mysql_rwlock_wrlock(&LOCK_grant); mysql_mutex_lock(&acl_cache->lock); - if (!(role= find_acl_role(rolename.str))) + if (!(role= find_acl_role(rolename.str, false))) { mysql_mutex_unlock(&acl_cache->lock); mysql_rwlock_unlock(&LOCK_grant); @@ -7589,7 +7669,8 @@ bool mysql_grant_role(THD *thd, List &list, bool revoke) result= 1; continue; } - if (!(role_as_user= find_acl_role(thd->security_ctx->priv_role))) + if (!(role_as_user= find_acl_role(thd->security_ctx->priv_role, + true))) { LEX_CSTRING ls= { thd->security_ctx->priv_role, strlen(thd->security_ctx->priv_role) }; @@ -7622,11 +7703,11 @@ bool mysql_grant_role(THD *thd, List &list, bool revoke) if (user->host.str) hostname= user->host; else - if ((role_as_user= find_acl_role(user->user.str))) + if ((role_as_user= find_acl_role(user->user.str, false))) hostname= empty_clex_str; else { - if (is_invalid_role_name(username.str)) + if (check_role_name(username.str, true) == ROLE_NAME_INVALID) { append_user(thd, &wrong_users, &username, &empty_clex_str); result= 1; @@ -7648,19 +7729,31 @@ bool mysql_grant_role(THD *thd, List &list, bool revoke) if (!grantee && !revoke) { LEX_USER user_combo = *user; - user_combo.host = hostname; user_combo.user = username; + user_combo.is_public= (user->host.length == 0 && + // it is also can be that + // hostname.length= 1 && hostname.str[0] == '%' + // if the PUBLIC was absent + username.length == public_name.length && + (strcasecmp(username.str, public_name.str) == 0)); + if (user_combo.is_public) + user_combo.host= hostname= empty_clex_str; + else + user_combo.host = hostname; if (copy_and_check_auth(&user_combo, &user_combo, thd) || replace_user_table(thd, tables.user_table(), &user_combo, NO_ACL, false, create_new_user, - no_auto_create_user)) + (!user_combo.is_public && no_auto_create_user))) { append_user(thd, &wrong_users, &username, &hostname); result= 1; continue; } - grantee= find_user_exact(hostname.str, username.str); + if (!user_combo.is_public) + grantee= find_user_exact(hostname.str, username.str); + else + grantee= role_as_user= acl_public; /* either replace_user_table failed, or we've added the user */ DBUG_ASSERT(grantee); @@ -7826,8 +7919,9 @@ bool mysql_grant(THD *thd, const char *db, List &list, replace_user_table(thd, tables.user_table(), Str, (!db ? rights : NO_ACL), revoke_grant, create_new_users, - MY_TEST(thd->variables.sql_mode & - MODE_NO_AUTO_CREATE_USER))) + MY_TEST(!Str->is_public && + (thd->variables.sql_mode & + MODE_NO_AUTO_CREATE_USER)))) result= true; else if (db) { @@ -7851,7 +7945,7 @@ bool mysql_grant(THD *thd, const char *db, List &list, result= true; } if (Str->is_role()) - propagate_role_grants(find_acl_role(Str->user.str), + propagate_role_grants(find_acl_role(Str->user.str, true), db ? PRIVS_TO_MERGE::DB : PRIVS_TO_MERGE::GLOBAL, db); } @@ -8218,8 +8312,6 @@ bool check_grant(THD *thd, privilege_t want_access, TABLE_LIST *tables, uint i; privilege_t original_want_access(want_access); bool locked= 0; - GRANT_TABLE *grant_table; - GRANT_TABLE *grant_table_role= NULL; DBUG_ENTER("check_grant"); DBUG_ASSERT(number > 0); @@ -8341,18 +8433,11 @@ bool check_grant(THD *thd, privilege_t want_access, TABLE_LIST *tables, mysql_rwlock_rdlock(&LOCK_grant); } - grant_table= table_hash_search(sctx->host, sctx->ip, - t_ref->get_db_name(), - sctx->priv_user, - t_ref->get_table_name(), - FALSE); - if (sctx->priv_role[0]) - grant_table_role= table_hash_search("", NULL, t_ref->get_db_name(), - sctx->priv_role, - t_ref->get_table_name(), - TRUE); + t_ref->grant.read(sctx, t_ref->get_db_name(), t_ref->get_table_name()); - if (!grant_table && !grant_table_role) + if (!t_ref->grant.grant_table_user && + !t_ref->grant.grant_table_role && + !t_ref->grant.grant_public) { want_access&= ~t_ref->grant.privilege; goto err; // No grants @@ -8365,19 +8450,14 @@ bool check_grant(THD *thd, privilege_t want_access, TABLE_LIST *tables, if (any_combination_will_do) continue; - t_ref->grant.grant_table_user= grant_table; // Remember for column test - t_ref->grant.grant_table_role= grant_table_role; - 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; + t_ref->grant.privilege|= t_ref->grant.aggregate_privs(); t_ref->grant.want_privilege= ((want_access & COL_ACLS) & ~t_ref->grant.privilege); if (!(~t_ref->grant.privilege & want_access)) continue; - if ((want_access&= ~((grant_table ? grant_table->cols : NO_ACL) | - (grant_table_role ? grant_table_role->cols : NO_ACL) | - t_ref->grant.privilege))) + if ((want_access&= ~(t_ref->grant.aggregate_cols() | + t_ref->grant.privilege))) { goto err; // impossible } @@ -8420,6 +8500,49 @@ static void check_grant_column_int(GRANT_TABLE *grant_table, const char *name, } } +inline privilege_t GRANT_INFO::aggregate_privs() +{ + return (grant_table_user ? grant_table_user->privs : NO_ACL) | + (grant_table_role ? grant_table_role->privs : NO_ACL) | + (grant_public ? grant_public->privs : NO_ACL); +} + +inline privilege_t GRANT_INFO::aggregate_cols() +{ + return (grant_table_user ? grant_table_user->cols : NO_ACL) | + (grant_table_role ? grant_table_role->cols : NO_ACL) | + (grant_public ? grant_public->cols : NO_ACL); +} + +void GRANT_INFO::refresh(const Security_context *sctx, + const char *db, const char *table) +{ + if (version != grant_version) + read(sctx, db, table); +} + +void GRANT_INFO::read(const Security_context *sctx, + const char *db, const char *table) +{ +#ifdef EMBEDDED_LIBRARY + grant_table_user= grant_table_role= grant_public= NULL; +#else + grant_table_user= + table_hash_search(sctx->host, sctx->ip, db, + sctx->priv_user, + table, FALSE); /* purecov: inspected */ + grant_table_role= + sctx->priv_role[0] ? table_hash_search("", NULL, db, + sctx->priv_role, + table, TRUE) : NULL; + grant_public= + acl_public ? table_hash_search("", NULL, db, + public_name.str, + table, TRUE) : NULL; +#endif + version= grant_version; /* purecov: inspected */ +} + /* Check column rights in given security context @@ -8453,24 +8576,14 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant, mysql_rwlock_rdlock(&LOCK_grant); /* reload table if someone has modified any grants */ - - if (grant->version != grant_version) - { - grant->grant_table_user= - table_hash_search(sctx->host, sctx->ip, db_name, - sctx->priv_user, - table_name, 0); /* purecov: inspected */ - grant->grant_table_role= - sctx->priv_role[0] ? table_hash_search("", NULL, db_name, - sctx->priv_role, - table_name, TRUE) : NULL; - grant->version= grant_version; /* purecov: inspected */ - } + grant->refresh(sctx, db_name, table_name); check_grant_column_int(grant->grant_table_user, name, (uint)length, &want_access); check_grant_column_int(grant->grant_table_role, name, (uint)length, &want_access); + check_grant_column_int(grant->grant_public, name, (uint)length, + &want_access); mysql_rwlock_unlock(&LOCK_grant); if (!want_access) @@ -8586,6 +8699,7 @@ bool check_grant_all_columns(THD *thd, privilege_t want_access_arg, GRANT_INFO *grant; GRANT_TABLE *UNINIT_VAR(grant_table); GRANT_TABLE *UNINIT_VAR(grant_table_role); + GRANT_TABLE *UNINIT_VAR(grant_public); /* Flag that gets set if privilege checking has to be performed on column level. @@ -8611,22 +8725,12 @@ bool check_grant_all_columns(THD *thd, privilege_t want_access_arg, if (want_access) { /* reload table if someone has modified any grants */ - if (grant->version != grant_version) - { - grant->grant_table_user= - table_hash_search(sctx->host, sctx->ip, db_name, - sctx->priv_user, - table_name, 0); /* purecov: inspected */ - grant->grant_table_role= - sctx->priv_role[0] ? table_hash_search("", NULL, db_name, - sctx->priv_role, - table_name, TRUE) : NULL; - grant->version= grant_version; /* purecov: inspected */ - } + grant->refresh(sctx, db_name, table_name); grant_table= grant->grant_table_user; grant_table_role= grant->grant_table_role; - if (!grant_table && !grant_table_role) + grant_public= grant->grant_public; + if (!grant_table && !grant_table_role && !grant_public) goto err; } } @@ -8649,6 +8753,15 @@ bool check_grant_all_columns(THD *thd, privilege_t want_access_arg, if (grant_column) have_access|= grant_column->rights; } + if (grant_public) + { + GRANT_COLUMN *grant_column= + column_hash_search(grant_public, field_name->str, + field_name->length); + if (grant_column) + have_access|= grant_column->rights; + + } if (have_access) using_column_privileges= TRUE; @@ -8828,6 +8941,13 @@ bool check_grant_routine(THD *thd, privilege_t want_access, table->table_name.str, sph, 0))) table->grant.privilege|= grant_proc->privs; } + if (acl_public) + { + if ((grant_proc= routine_hash_search("", NULL, table->db.str, + public_name.str, + table->table_name.str, sph, 0))) + table->grant.privilege|= grant_proc->privs; + } if (want_access & ~table->grant.privilege) { @@ -8907,27 +9027,10 @@ privilege_t get_table_grant(THD *thd, TABLE_LIST *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; 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); - if (sctx->priv_role[0]) - grant_table_role= table_hash_search("", "", db, sctx->priv_role, - table->table_name.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; - if (grant_table_role) - table->grant.privilege|= grant_table_role->privs; + table->grant.read(sctx, db, table->table_name.str); + table->grant.privilege|= table->grant.aggregate_privs(); privilege_t privilege(table->grant.privilege); mysql_rwlock_unlock(&LOCK_grant); return privilege; @@ -8958,29 +9061,19 @@ privilege_t get_column_grant(THD *thd, GRANT_INFO *grant, { GRANT_TABLE *grant_table; GRANT_TABLE *grant_table_role; + GRANT_TABLE *grant_public; GRANT_COLUMN *grant_column; privilege_t priv(NO_ACL); mysql_rwlock_rdlock(&LOCK_grant); /* 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, sctx->priv_user, - table_name, 0); /* purecov: inspected */ - grant->grant_table_role= - sctx->priv_role[0] ? table_hash_search("", "", db_name, - sctx->priv_role, - table_name, TRUE) : NULL; - grant->version= grant_version; /* purecov: inspected */ - } + grant->refresh(thd->security_ctx, db_name, table_name); grant_table= grant->grant_table_user; grant_table_role= grant->grant_table_role; + grant_public= grant->grant_public; - if (!grant_table && !grant_table_role) + if (!grant_table && !grant_table_role && !grant_public) priv= grant->privilege; else { @@ -9004,6 +9097,16 @@ privilege_t get_column_grant(THD *thd, GRANT_INFO *grant, priv|= (grant->privilege | grant_table_role->privs | grant_column->rights); } + if (grant_public) + { + grant_column= column_hash_search(grant_public, field_name, + (uint) strlen(field_name)); + if (!grant_column) + priv|= (grant->privilege | grant_public->privs); + else + priv|= (grant->privilege | grant_public->privs | + grant_column->rights); + } } mysql_rwlock_unlock(&LOCK_grant); return priv; @@ -9479,7 +9582,7 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user) if (rolename) { - acl_role= find_acl_role(rolename); + acl_role= find_acl_role(rolename, true); if (acl_role) { /* get a list of all inherited roles */ @@ -9618,6 +9721,13 @@ static bool show_global_privileges(THD *thd, ACL_USER_BASE *acl_entry, want_access= ((ACL_ROLE *)acl_entry)->initial_role_access; else want_access= acl_entry->access; + + // suppress "GRANT USAGE ON *.* TO `PUBLIC`" + if (!(want_access & ~GRANT_ACL) && + acl_entry->user.length == public_name.length && + strcasecmp(acl_entry->user.str, public_name.str) == 0) + return FALSE; + if (test_all_bits(want_access, (GLOBAL_ACLS & ~ GRANT_ACL))) global.append(STRING_WITH_LEN("ALL PRIVILEGES")); else if (!(want_access & ~GRANT_ACL)) @@ -10354,7 +10464,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, if (struct_no == ROLE_ACL) //no need to scan the structures in this case { - acl_role= find_acl_role(user_from->user.str); + acl_role= find_acl_role(user_from->user.str, true); if (!acl_role) DBUG_RETURN(0); @@ -10712,7 +10822,7 @@ static int handle_grant_data(THD *thd, Grant_tables& tables, bool drop, if (search_only) { /* quickly search in-memory structures first */ - if (handle_as_role && find_acl_role(user_from->user.str)) + if (handle_as_role && find_acl_role(user_from->user.str, true)) DBUG_RETURN(1); // found if (!handle_as_role && find_user_exact(user_from->host.str, user_from->user.str)) @@ -10943,7 +11053,8 @@ bool mysql_create_user(THD *thd, List &list, bool handle_as_role) continue; } - if (handle_as_role && is_invalid_role_name(user_name->user.str)) + if (handle_as_role && + (check_role_name(user_name->user.str, false) == ROLE_NAME_INVALID)) { append_user(thd, &wrong_users, user_name); result= TRUE; @@ -11011,7 +11122,7 @@ bool mysql_create_user(THD *thd, List &list, bool handle_as_role) { ACL_USER_BASE *grantee= find_acl_user_base(thd->lex->definer->user.str, thd->lex->definer->host.str); - ACL_ROLE *role= find_acl_role(user_name->user.str); + ACL_ROLE *role= find_acl_role(user_name->user.str, false); /* just like with routines, views, triggers, and events we allow @@ -11103,10 +11214,15 @@ bool mysql_drop_user(THD *thd, List &list, bool handle_as_role) { int rc; user_name= get_current_user(thd, tmp_user_name, false); - if (!user_name) + if (!user_name || (handle_as_role && + (strcasecmp(user_name->user.str, + public_name.str) == 0))) { thd->clear_error(); - append_str(&wrong_users, STRING_WITH_LEN("CURRENT_ROLE")); + if (!user_name) + append_str(&wrong_users, STRING_WITH_LEN("CURRENT_ROLE")); + else + append_str(&wrong_users, public_name.str, public_name.length); result= TRUE; continue; } @@ -11535,7 +11651,7 @@ bool mysql_revoke_all(THD *thd, List &list) if (lex_user->is_role()) { /* this can not fail due to get_current_user already having searched for it */ - user_or_role= find_acl_role(lex_user->user.str); + user_or_role= find_acl_role(lex_user->user.str, true); } else { @@ -12056,6 +12172,8 @@ static bool set_user_salt_if_needed(ACL_USER *, int, plugin_ref) { return 0; } bool check_grant(THD *, privilege_t, TABLE_LIST *, bool, uint, bool) { return 0; } +inline privilege_t public_access() +{ return NO_ACL; } #endif /*NO_EMBEDDED_ACCESS_CHECKS */ @@ -12314,7 +12432,7 @@ bool check_role_is_granted(const char *username, if (hostname) root= find_user_exact(hostname, username); else - root= find_acl_role(username); + root= find_acl_role(username, false); LEX_CSTRING role_lex; role_lex.str= rolename; @@ -12342,7 +12460,7 @@ int fill_schema_enabled_roles(THD *thd, TABLE_LIST *tables, COND *cond) { mysql_rwlock_rdlock(&LOCK_grant); mysql_mutex_lock(&acl_cache->lock); - ACL_ROLE *acl_role= find_acl_role(thd->security_ctx->priv_role); + ACL_ROLE *acl_role= find_acl_role(thd->security_ctx->priv_role, false); if (acl_role) traverse_role_graph_down(acl_role, table, enabled_roles_insert, NULL); mysql_mutex_unlock(&acl_cache->lock); @@ -12816,11 +12934,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, if (!thd->db.str || strcmp(db, thd->db.str)) { - /* db privileges */ - grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0); - /* db privileges for role */ - if (sctx->priv_role[0]) - grant->privilege|= acl_get("", "", sctx->priv_role, db, 0); + grant->privilege|= acl_get_all3(sctx, db, FALSE); } else { @@ -12829,18 +12943,8 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, /* table privileges */ mysql_rwlock_rdlock(&LOCK_grant); - if (grant->version != grant_version) - { - grant->grant_table_user= - table_hash_search(sctx->host, sctx->ip, db, - sctx->priv_user, - table, 0); /* purecov: inspected */ - grant->grant_table_role= - sctx->priv_role[0] ? table_hash_search("", "", db, - sctx->priv_role, - table, TRUE) : NULL; - grant->version= grant_version; /* purecov: inspected */ - } + grant->refresh(sctx, db, table); + if (grant->grant_table_user != 0) { grant->privilege|= grant->grant_table_user->privs; @@ -12849,6 +12953,10 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, { grant->privilege|= grant->grant_table_role->privs; } + if (grant->grant_public != 0) + { + grant->privilege|= grant->grant_public->privs; + } mysql_rwlock_unlock(&LOCK_grant); DBUG_PRINT("info", ("privilege 0x%llx", (longlong) grant->privilege)); @@ -12904,12 +13012,16 @@ LEX_USER *get_current_user(THD *thd, LEX_USER *user, bool lock) return dup; } - if (is_invalid_role_name(user->user.str)) + role_name_check_result result= check_role_name(user->user.str, + user->host.length == 0); + if (result == ROLE_NAME_INVALID) return 0; + if (result == ROLE_NAME_PUBLIC) + dup->is_public= true; if (lock) mysql_mutex_lock(&acl_cache->lock); - if (find_acl_role(dup->user.str)) + if (find_acl_role(dup->user.str, false) || dup->is_public) dup->host= empty_clex_str; else dup->host= host_not_specified; @@ -14518,7 +14630,7 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) } #endif - sctx->master_access= acl_user->access; + sctx->master_access= (acl_user->access | public_access()); strmake_buf(sctx->priv_user, acl_user->user.str); if (acl_user->host.hostname) diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 570da144b46..d1597ca9f5a 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -76,8 +76,8 @@ bool hostname_requires_resolving(const char *hostname); bool acl_init(bool dont_read_acl_tables); bool acl_reload(THD *thd); void acl_free(bool end=0); -privilege_t acl_get(const char *host, const char *ip, - const char *user, const char *db, my_bool db_is_pattern); +privilege_t acl_get_all3(Security_context *sctx, const char *db, + bool db_is_patern); bool acl_authenticate(THD *thd, uint com_change_user_pkt_len); bool acl_getroot(Security_context *sctx, const char *user, const char *host, const char *ip, const char *db); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 7be4ba00b86..452a01773e5 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -1778,16 +1778,13 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name, #ifndef NO_EMBEDDED_ACCESS_CHECKS if (test_all_bits(sctx->master_access, DB_ACLS)) + { db_access= DB_ACLS; + } else { - db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, - new_db_file_name.str, FALSE) | sctx->master_access; - if (sctx->priv_role[0]) - { - /* include a possible currently set role for access */ - db_access|= acl_get("", "", sctx->priv_role, new_db_file_name.str, FALSE); - } + db_access= acl_get_all3(sctx, new_db_file_name.str, FALSE); + db_access|= sctx->master_access; } if (!force_switch && diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 69803242fc1..7025b7214b3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6760,10 +6760,7 @@ check_access(THD *thd, privilege_t want_access, { if (db && (!thd->db.str || db_is_pattern || strcmp(db, thd->db.str))) { - db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, - db_is_pattern); - if (sctx->priv_role[0]) - db_access|= acl_get("", "", sctx->priv_role, db, db_is_pattern); + db_access= acl_get_all3(sctx, db, db_is_pattern); } else { @@ -6808,14 +6805,7 @@ check_access(THD *thd, privilege_t want_access, } if (db && (!thd->db.str || db_is_pattern || strcmp(db, thd->db.str))) - { - db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, - db_is_pattern); - if (sctx->priv_role[0]) - { - db_access|= acl_get("", "", sctx->priv_role, db, db_is_pattern); - } - } + db_access= acl_get_all3(sctx, db, db_is_pattern); else db_access= sctx->db_access; DBUG_PRINT("info",("db_access: %llx want_access: %llx", diff --git a/sql/sql_show.cc b/sql/sql_show.cc index b47b9f4b89b..87f697c5ae9 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1406,12 +1406,8 @@ bool mysqld_show_create_db(THD *thd, LEX_CSTRING *dbname, if (test_all_bits(sctx->master_access, DB_ACLS)) db_access=DB_ACLS; else - { - db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname->str, 0) | + db_access= acl_get_all3(sctx, dbname->str, FALSE) | sctx->master_access; - if (sctx->priv_role[0]) - db_access|= acl_get("", "", sctx->priv_role, dbname->str, 0); - } if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname->str)) { @@ -5302,7 +5298,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) &thd->col_access, NULL, 0, 1) || (!thd->col_access && check_grant_db(thd, db_name->str))) || sctx->master_access & (DB_ACLS | SHOW_DB_ACL) || - acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0)) + acl_get_all3(sctx, db_name->str, 0)) #endif { Dynamic_array table_names(PSI_INSTRUMENT_MEM); @@ -5502,9 +5498,7 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond) } #ifndef NO_EMBEDDED_ACCESS_CHECKS if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) || - acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, false) || - (sctx->priv_role[0] ? - acl_get("", "", sctx->priv_role, db_name->str, false) : NO_ACL) || + acl_get_all3(sctx, db_name->str, false) || !check_grant_db(thd, db_name->str)) #endif { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 774f92197f9..2c36ee5ab2d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -17156,6 +17156,7 @@ grant_role: $$->user= $1; $$->host= empty_clex_str; $$->auth= NULL; + $$->is_public= false; if (unlikely(check_string_char_length(&$$->user, ER_USERNAME, username_char_length, diff --git a/sql/structs.h b/sql/structs.h index b36f8e6a1a0..edecbf0888b 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -254,6 +254,7 @@ struct AUTHID struct LEX_USER: public AUTHID { USER_AUTH *auth; + bool is_public; bool has_auth() { return auth && (auth->plugin.length || auth->auth_str.length || auth->pwtext.length); diff --git a/sql/table.h b/sql/table.h index 3aabee9a087..97b469e41cb 100644 --- a/sql/table.h +++ b/sql/table.h @@ -301,6 +301,7 @@ typedef struct st_grant_info */ GRANT_TABLE *grant_table_user; GRANT_TABLE *grant_table_role; + GRANT_TABLE *grant_public; /** @brief Used for cache invalidation when caching privilege information. @@ -347,6 +348,14 @@ typedef struct st_grant_info want_privilege(NO_ACL), orig_want_privilege(NO_ACL) { } + + void read(const Security_context *sctx, const char *db, + const char *table); + + inline void refresh(const Security_context *sctx, const char *db, + const char *table); + inline privilege_t aggregate_privs(); + inline privilege_t aggregate_cols(); } GRANT_INFO; enum tmp_table_type