#At file:///Users/cbell/source/bzr/mysql-6.0-bug-44787-elevation/ based on revid:charles.bell@stripped
2888 Chuck Bell 2009-11-04 [merge]
BUG#44787 : Backup: Check privileges before executing BACKUP/RESTORE
The backup system must be changed to meet a decision to allow
elevation of privileges for backup if the user has only the
BACKUP_ACL privilege and elevation of privileges for restore
if the user has the RESTORE_ACL and SUPER_ACL privileges.
This patch implements the privilege elevation change for backup
as well as privilege elevation for restore iff the user has both
RESTORE and SUPER on all databases in the image. The restore
will fall back to object-level privilege checking if this condition
is not met.
Note: This is patch 2 of 3. Patch 1 implements privilege checking,
patch 3 implements the options to skip precheck and turn
elevation off.
@ mysql-test/suite/backup/r/backup_restore_security.result
Corrected result file.
@ mysql-test/suite/backup/r/backup_security.result
Corrected result file.
@ mysql-test/suite/backup/t/backup_restore_security.test
Added new test cases.
@ mysql-test/suite/backup/t/backup_security.test
Corrected error return codes.
@ sql/backup/backup_info.cc
Added privilege elevation for backup using security context
method (similar to replication).
@ sql/backup/kernel.cc
Added privilege elevation code for elevating iff the user
has RESTORE + SUPER.
@ sql/backup/restore_info.h
Added attributes for privilege checking.
Moved privilege checking to new method.
@ sql/si_objects.cc
Removed privilege elevation from si_objects code
@ sql/sql_class.cc
Added methods to set, save, restore the access levels for turning off
elevation and preserving user context.
@ sql/sql_class.h
Added methods to set, save, and restore privilege access.
added:
mysql-test/suite/backup/r/backup_restore_security.result
mysql-test/suite/backup/t/backup_restore_security.test
modified:
mysql-test/suite/backup/r/backup_security.result
mysql-test/suite/backup/t/backup_security.test
sql/backup/backup_info.cc
sql/backup/kernel.cc
sql/backup/restore_info.h
sql/si_objects.cc
sql/sql_class.cc
sql/sql_class.h
=== added file 'mysql-test/suite/backup/r/backup_restore_security.result'
--- a/mysql-test/suite/backup/r/backup_restore_security.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/backup/r/backup_restore_security.result 2009-11-04 20:56:16 +0000
@@ -0,0 +1,402 @@
+DROP DATABASE IF EXISTS backup_test;
+DROP DATABASE IF EXISTS backup_test_alt;
+#
+# Create users.
+#
+CREATE USER 'bup_some_priv'@'localhost';
+CREATE USER 'joe'@'user';
+#
+# Use the basic data setup in backup_test database.
+#
+#
+# Create database and data to test.
+#
+CREATE DATABASE backup_test;
+CREATE TABLE backup_test.t1 (a char(30)) ENGINE=MEMORY;
+INSERT INTO backup_test.t1 VALUES ("01 Test Basic database example");
+INSERT INTO backup_test.t1 VALUES ("02 Test Basic database example");
+INSERT INTO backup_test.t1 VALUES ("03 Test Basic database example");
+INSERT INTO backup_test.t1 VALUES ("04 Test Basic database example");
+INSERT INTO backup_test.t1 VALUES ("05 Test Basic database example");
+INSERT INTO backup_test.t1 VALUES ("06 Test Basic database example");
+INSERT INTO backup_test.t1 VALUES ("07 Test Basic database example");
+CREATE TABLE backup_test.t2 (a char(30)) ENGINE=MYISAM;
+INSERT INTO backup_test.t2 VALUES ("11 Test Basic database example");
+INSERT INTO backup_test.t2 VALUES ("12 Test Basic database example");
+INSERT INTO backup_test.t2 VALUES ("13 Test Basic database example");
+#
+# Now create more database objects for test.
+#
+CREATE PROCEDURE backup_test.p1(p1 CHAR(20))
+INSERT INTO backup_test.t1 VALUES ("50");
+CREATE TRIGGER backup_test.trg AFTER INSERT ON backup_test.t1 FOR EACH ROW
+INSERT INTO backup_test.t1 VALUES('Test objects count');
+CREATE FUNCTION backup_test.f1() RETURNS INT RETURN (SELECT 1);
+CREATE VIEW backup_test.v1 as SELECT * FROM backup_test.t1;
+CREATE EVENT backup_test.e1 ON SCHEDULE EVERY 1 YEAR DO
+DELETE FROM backup_test.t1 WHERE a = "not there";
+#
+# Now we need some privileges
+#
+GRANT ALL ON backup_test.* TO 'joe'@'user';
+#
+# Create a second database for testing multiple database privilege
+# checking.
+#
+CREATE DATABASE backup_test_alt;
+CREATE TABLE backup_test_alt.t1 (a int);
+INSERT INTO backup_test_alt.t1 VALUES (10), (11), (12);
+#
+# Revoke grants for bup_some_priv
+#
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+#
+# Show grants for user.
+#
+SHOW GRANTS FOR 'bup_some_priv'@'localhost';
+Grants for bup_some_priv@localhost
+GRANT USAGE ON *.* TO 'bup_some_priv'@'localhost'
+#
+# conn_root_user: Do backup of database with root user for later tests.
+#
+BACKUP DATABASE backup_test to 'backup_test_orig.bak';
+backup_id
+#
+BACKUP DATABASE backup_test, backup_test_alt to 'backup_test_orig_alt1.bak';
+backup_id
+#
+BACKUP DATABASE backup_test_alt, backup_test to 'backup_test_orig_alt2.bak';
+backup_id
+#
+#
+# Show list of all objects in the database.
+#
+SHOW FULL TABLES FROM backup_test;
+Tables_in_backup_test Table_type
+t1 BASE TABLE
+t2 BASE TABLE
+v1 VIEW
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS WHERE event_schema = 'backup_test';
+event_name
+e1
+SELECT routine_name FROM INFORMATION_SCHEMA.ROUTINES WHERE routine_schema = 'backup_test';
+routine_name
+f1
+p1
+SELECT trigger_name FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_schema = 'backup_test';
+trigger_name
+trg
+#
+# conn_root_user: Do backup of database with root user without
+# stored procedures for later tests.
+#
+DROP PROCEDURE backup_test.p1;
+DROP FUNCTION backup_test.f1;
+BACKUP DATABASE backup_test to 'backup_test_no_proc.bak';
+backup_id
+#
+#
+# Test Case 1 : Ensure a user with only RESTORE on db1.* cannot restore
+# the database.
+#
+GRANT RESTORE ON backup_test.* TO 'bup_some_priv'@'localhost';
+GRANT CREATE, DROP ON backup_test.* TO 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+#
+# Show grants for user.
+#
+SHOW GRANTS FOR 'bup_some_priv'@'localhost';
+Grants for bup_some_priv@localhost
+GRANT USAGE ON *.* TO 'bup_some_priv'@'localhost'
+GRANT CREATE, DROP, RESTORE ON `backup_test`.* TO 'bup_some_priv'@'localhost'
+#
+# Connect as user with only some privileges.
+#
+#
+# conn_some_priv: Attempting restore. Should fail with
+# error ER_RESTORE_ACCESS_OBJS_INCOMPLETE
+#
+RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
+ERROR HY000: Insufficient privileges. You do not have privileges to restore the object 'p1' from this backup image.
+SHOW ERRORS;
+Level Code Message
+Error # Insufficient privileges. You do not have privileges to restore the object 'p1' from this backup image.
+#
+# Test Case 2 : Ensure a user with only SELECT on db1.* cannot restore
+# the database.
+#
+#
+# Connect as root and add privileges.
+#
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+GRANT SELECT ON backup_test.* TO 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+#
+# Show grants for user.
+#
+SHOW GRANTS FOR 'bup_some_priv'@'localhost';
+Grants for bup_some_priv@localhost
+GRANT USAGE ON *.* TO 'bup_some_priv'@'localhost'
+GRANT SELECT, CREATE, DROP, RESTORE ON `backup_test`.* TO 'bup_some_priv'@'localhost'
+#
+# Connect as user with only some privileges.
+#
+#
+# conn_some_priv: Attempting restore. Should fail with
+# error ER_RESTORE_ACCESS_OBJS_INCOMPLETE
+#
+RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
+ERROR HY000: Insufficient privileges. You do not have privileges to restore the object 'p1' from this backup image.
+SHOW ERRORS;
+Level Code Message
+Error # Insufficient privileges. You do not have privileges to restore the object 'p1' from this backup image.
+#
+# Test Case 5 : Show that SUPER is needed to complete restore
+# when there are objects with definer clauses.
+#
+#
+# Connect as root and add privileges.
+#
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+GRANT ALL ON backup_test.* TO 'bup_some_priv'@'localhost' WITH GRANT OPTION;
+GRANT ALL ON mysql.* TO 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+#
+# Show grants for user.
+#
+SHOW GRANTS FOR 'bup_some_priv'@'localhost';
+Grants for bup_some_priv@localhost
+GRANT USAGE ON *.* TO 'bup_some_priv'@'localhost'
+GRANT ALL PRIVILEGES ON `mysql`.* TO 'bup_some_priv'@'localhost'
+GRANT ALL PRIVILEGES ON `backup_test`.* TO 'bup_some_priv'@'localhost' WITH GRANT OPTION
+#
+# Connect as user with only some privileges.
+#
+#
+# conn_some_priv: Attempting restore. Should fail with
+# ER_RESTORE_ACCESS_DEFINER
+#
+RESTORE FROM 'backup_test_no_proc.bak' OVERWRITE;
+ERROR HY000: Insufficient privileges. You must have the SUPER privilege to restore the object 'backup_test'.'v1'.
+SHOW ERRORS;
+Level Code Message
+Error # Insufficient privileges. You must have the SUPER privilege to restore the object 'backup_test'.'v1'.
+#
+# Test Case 6 : Ensure a user can only restore the database if and only
+# if she has all of the required permissions to create and
+# populate all objects.
+#
+#
+# Connect as root and add privileges.
+#
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+GRANT ALL ON backup_test.* TO 'bup_some_priv'@'localhost' WITH GRANT OPTION;
+GRANT SELECT ON mysql.* TO 'bup_some_priv'@'localhost';
+GRANT SUPER ON *.* TO 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+#
+# Show grants for user.
+#
+SHOW GRANTS FOR 'bup_some_priv'@'localhost';
+Grants for bup_some_priv@localhost
+GRANT SUPER ON *.* TO 'bup_some_priv'@'localhost'
+GRANT ALL PRIVILEGES ON `mysql`.* TO 'bup_some_priv'@'localhost'
+GRANT ALL PRIVILEGES ON `backup_test`.* TO 'bup_some_priv'@'localhost' WITH GRANT OPTION
+#
+# Connect as user with only some privileges.
+#
+#
+# conn_some_priv: Attempting restore. Should succeed.
+#
+RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
+backup_id
+#
+#
+# Connect as root and cleanup.
+#
+#
+# Test Case 7 : Show that the privilege check on TRIGGER is required to
+# restore a table with a trigger.
+#
+# Perform a backup with only a table and a trigger.
+# No grants either.
+#
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+REVOKE ALL ON backup_test.* FROM 'bup_some_priv'@'localhost';
+DROP USER 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+CREATE DATABASE backup_test_trig;
+CREATE TABLE backup_test_trig.t1 (a char(30)) ENGINE=MEMORY;
+CREATE TRIGGER backup_test_trig.trg AFTER INSERT ON backup_test_trig.t1 FOR EACH ROW
+INSERT INTO backup_test_trig.t1 VALUES('Test objects count');
+BACKUP DATABASE backup_test_trig TO 'backup_test_trig.bak';
+backup_id
+#
+CREATE USER 'bup_some_priv'@'localhost';
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+GRANT INSERT, UPDATE, DELETE, BACKUP, RESTORE, SELECT, CREATE, DROP
+ON backup_test_trig.* TO 'bup_some_priv'@'localhost' WITH GRANT OPTION;
+GRANT SELECT ON mysql.* TO 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+#
+# Show grants for user.
+#
+SHOW GRANTS FOR 'bup_some_priv'@'localhost';
+Grants for bup_some_priv@localhost
+GRANT USAGE ON *.* TO 'bup_some_priv'@'localhost'
+GRANT SELECT ON `mysql`.* TO 'bup_some_priv'@'localhost'
+GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, BACKUP, RESTORE ON `backup_test_trig`.* TO 'bup_some_priv'@'localhost' WITH GRANT OPTION
+#
+# Connect as user with only some privileges.
+#
+#
+# conn_some_priv: Attempting restore. Should fail with
+# error ER_RESTORE_ACCESS_OBJS_INCOMPLETE
+#
+RESTORE FROM 'backup_test_trig.bak' OVERWRITE;
+ERROR HY000: Insufficient privileges. You do not have privileges to restore the object 'trg' from this backup image.
+SHOW ERRORS;
+Level Code Message
+Error # Insufficient privileges. You do not have privileges to restore the object 'trg' from this backup image.
+#
+# Connect as root and add privilege for trigger.
+#
+GRANT TRIGGER ON backup_test_trig.t1 TO 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+#
+# Connect as user with only some privileges.
+#
+#
+# conn_some_priv: Attempting restore. Should fail with
+# ER_RESTORE_ACCESS_DEFINER
+#
+RESTORE FROM 'backup_test_trig.bak' OVERWRITE;
+ERROR HY000: Insufficient privileges. You must have the SUPER privilege to restore the object 'backup_test_trig'.'trg'.
+SHOW ERRORS;
+Level Code Message
+Error 1799 Insufficient privileges. You must have the SUPER privilege to restore the object 'backup_test_trig'.'trg'.
+#
+# Connect as root and add privilege for trigger.
+# In this case, we must add SUPER to overcome limitation with
+# the definer clause.
+#
+GRANT SUPER ON *.* TO 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+#
+# Connect as user with only some privileges.
+#
+#
+# conn_some_priv: Attempting restore. Should succeed.
+#
+RESTORE FROM 'backup_test_trig.bak' OVERWRITE;
+backup_id
+#
+#
+# Test Case 8 : Show that user can have only RESTORE_ACL +
+# SUPER_ACL to perform an elevated restore.
+#
+#
+# Change privileges for elevated restore test case.
+#
+DROP DATABASE backup_test_trig;
+DROP USER 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+CREATE USER 'bup_some_priv'@'localhost';
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+GRANT RESTORE ON backup_test.* TO 'bup_some_priv'@'localhost';
+GRANT SUPER ON *.* TO 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+#
+# Connect as user with only some privileges.
+#
+#
+# conn_some_priv: Attempting restore. Should succeed.
+#
+RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
+backup_id
+#
+#
+# Test Case 9 : Show that users who have RESTORE + SUPER for db1 but not
+# for db2 cannot restore the image.
+#
+#
+# Change privileges for elevated restore test case.
+#
+DROP USER 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+CREATE USER 'bup_some_priv'@'localhost';
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+GRANT RESTORE ON backup_test.* TO 'bup_some_priv'@'localhost';
+GRANT SUPER ON *.* TO 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+#
+# Connect as user with only some privileges.
+#
+#
+# conn_some_priv: Attempting restore. Should fail with
+# error ER_RESTORE_ACCESS_DENIED_ERROR
+#
+RESTORE FROM 'backup_test_orig_alt1.bak' OVERWRITE;
+ERROR HY000: Insufficient privileges. You must have the RESTORE privilege to restore database 'backup_test_alt'.
+SHOW ERRORS;
+Level Code Message
+Error 1794 Insufficient privileges. You must have the RESTORE privilege to restore database 'backup_test_alt'.
+#
+# conn_some_priv: Attempting restore. Should fail with
+# error ER_RESTORE_ACCESS_DENIED_ERROR
+#
+RESTORE FROM 'backup_test_orig_alt2.bak' OVERWRITE;
+ERROR HY000: Insufficient privileges. You must have the RESTORE privilege to restore database 'backup_test_alt'.
+SHOW ERRORS;
+Level Code Message
+Error 1794 Insufficient privileges. You must have the RESTORE privilege to restore database 'backup_test_alt'.
+#
+# Change privileges for elevated restore test case.
+#
+GRANT RESTORE ON backup_test_alt.* TO 'bup_some_priv'@'localhost';
+FLUSH PRIVILEGES;
+#
+# Connect as user with only some privileges.
+#
+#
+# conn_some_priv: Attempting restore. Should succeed.
+#
+RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
+backup_id
+#
+#
+# Connect as root and cleanup.
+#
+#
+# Compare to original backup image file.
+#
+RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
+backup_id
+#
+#
+# Show list of all objects in the database.
+#
+SHOW FULL TABLES FROM backup_test;
+Tables_in_backup_test Table_type
+t1 BASE TABLE
+t2 BASE TABLE
+v1 VIEW
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS WHERE event_schema = 'backup_test';
+event_name
+e1
+SELECT routine_name FROM INFORMATION_SCHEMA.ROUTINES WHERE routine_schema = 'backup_test';
+routine_name
+f1
+p1
+SELECT trigger_name FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_schema = 'backup_test';
+trigger_name
+trg
+#
+# Cleanup
+#
+DROP USER 'bup_some_priv'@'localhost';
+DROP USER 'joe'@'user';
+DROP DATABASE backup_test;
+DROP DATABASE backup_test_alt;
+FLUSH PRIVILEGES;
=== modified file 'mysql-test/suite/backup/r/backup_security.result'
--- a/mysql-test/suite/backup/r/backup_security.result 2009-10-23 21:26:11 +0000
+++ b/mysql-test/suite/backup/r/backup_security.result 2009-11-04 20:56:16 +0000
@@ -390,24 +390,24 @@ Tables_in_backup_test
# the user to backup the database but not restore it.
#
#
-# conn_user1: Attempting restore. Should fail with one of the restore
-# catalog errors.
+# conn_user1: Attempting restore. Should fail with
+# error ER_RESTORE_ACCESS_OBJS_INCOMPLETE.
#
RESTORE FROM 'bup_user1.bak' OVERWRITE;
-Got one of the listed errors
+ERROR HY000: Insufficient privileges. You do not have privileges to restore the object 'backup_test' from this backup image.
#
# Test 4 - Show that if a user has BACKUP on one database but not
# another, the user cannot perform a backup of both databases.
#
#
# conn_user1: Attempting backup. Should fail with
-# error ER_BACKUP_ACCESS_DENIED_ERROR
+# error ER_BAD_DB_ERROR
#
BACKUP DATABASE backup_test_alt to 'bup_no_priv.bak';
-ERROR HY000: Insufficient privileges. You must have the BACKUP privilege to backup database 'backup_test_alt'.
+ERROR 42000: Unknown database 'backup_test_alt'
SHOW ERRORS;
Level Code Message
-Error # Insufficient privileges. You must have the BACKUP privilege to backup database 'backup_test_alt'.
+Error # Unknown database 'backup_test_alt'
#
# conn_user1: Attempting backup. Should fail with
# error ER_BACKUP_ACCESS_DENIED_ERROR
=== added file 'mysql-test/suite/backup/t/backup_restore_security.test'
--- a/mysql-test/suite/backup/t/backup_restore_security.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/backup/t/backup_restore_security.test 2009-11-04 20:56:16 +0000
@@ -0,0 +1,494 @@
+#
+# This test includes test cases for testing privilege checking on restore.
+#
+# Test Cases
+# ----------
+# 1. Ensure a user with only RESTORE on db1.* cannot restore the database.
+# 2. Ensure a user with only SELECT on db1.* cannot restore the database.
+# 3. Demonstrate that the user must have all privileges to run restore.
+# 4. Show that SUPER is needed to complete restore with binlog on.
+# 5. Show that SUPER is needed when there are object that use a definer
+# clause are in the backup image.
+# 6. Ensure a user can only restore the database if and only if she has
+# all of the required permissions to create and populate all objects.
+# 7. Show that having TRIGGER on a specific table is required to restore
+# a table with a trigger.
+# 8. Show that user can have only RESTORE + SUPER and perform an
+# elevated restore.
+# 9. Show that users who have RESTORE + SUPER for db1 but not for db2
+# cannot restore the image.
+#
+
+--source include/not_embedded.inc
+
+disable_query_log;
+call mtr.add_suppression("Restore: Insufficient privileges");
+enable_query_log;
+
+connect (conn_root,localhost,root,,);
+
+--disable_warnings
+DROP DATABASE IF EXISTS backup_test;
+DROP DATABASE IF EXISTS backup_test_alt;
+--enable_warnings
+
+--echo #
+--echo # Create users.
+--echo #
+CREATE USER 'bup_some_priv'@'localhost';
+CREATE USER 'joe'@'user';
+
+--echo #
+--echo # Use the basic data setup in backup_test database.
+--echo #
+--source suite/backup/include/basic_data.inc
+
+--echo #
+--echo # Create a second database for testing multiple database privilege
+--echo # checking.
+--echo #
+
+CREATE DATABASE backup_test_alt;
+CREATE TABLE backup_test_alt.t1 (a int);
+INSERT INTO backup_test_alt.t1 VALUES (10), (11), (12);
+
+--echo #
+--echo # Revoke grants for bup_some_priv
+--echo #
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+--echo #
+--echo # Show grants for user.
+--echo #
+SHOW GRANTS FOR 'bup_some_priv'@'localhost';
+
+--echo #
+--echo # conn_root_user: Do backup of database with root user for later tests.
+--echo #
+
+--replace_column 1 #
+BACKUP DATABASE backup_test to 'backup_test_orig.bak';
+
+--replace_column 1 #
+BACKUP DATABASE backup_test, backup_test_alt to 'backup_test_orig_alt1.bak';
+
+--replace_column 1 #
+BACKUP DATABASE backup_test_alt, backup_test to 'backup_test_orig_alt2.bak';
+
+--echo #
+--echo # Show list of all objects in the database.
+--echo #
+SHOW FULL TABLES FROM backup_test;
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS WHERE event_schema = 'backup_test';
+SELECT routine_name FROM INFORMATION_SCHEMA.ROUTINES WHERE routine_schema = 'backup_test';
+SELECT trigger_name FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_schema = 'backup_test';
+
+--echo #
+--echo # conn_root_user: Do backup of database with root user without
+--echo # stored procedures for later tests.
+--echo #
+
+DROP PROCEDURE backup_test.p1;
+DROP FUNCTION backup_test.f1;
+
+--replace_column 1 #
+BACKUP DATABASE backup_test to 'backup_test_no_proc.bak';
+
+--echo #
+--echo # Test Case 1 : Ensure a user with only RESTORE on db1.* cannot restore
+--echo # the database.
+--echo #
+
+GRANT RESTORE ON backup_test.* TO 'bup_some_priv'@'localhost';
+GRANT CREATE, DROP ON backup_test.* TO 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+--echo #
+--echo # Show grants for user.
+--echo #
+SHOW GRANTS FOR 'bup_some_priv'@'localhost';
+
+disconnect conn_root;
+--echo #
+--echo # Connect as user with only some privileges.
+--echo #
+connect (conn_some_priv,localhost,bup_some_priv,,);
+
+--echo #
+--echo # conn_some_priv: Attempting restore. Should fail with
+--echo # error ER_RESTORE_ACCESS_OBJS_INCOMPLETE
+--echo #
+--replace_column 1 #
+--error ER_RESTORE_ACCESS_OBJS_INCOMPLETE
+RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
+--replace_column 2 #
+SHOW ERRORS;
+
+--echo #
+--echo # Test Case 2 : Ensure a user with only SELECT on db1.* cannot restore
+--echo # the database.
+--echo #
+
+disconnect conn_some_priv;
+--echo #
+--echo # Connect as root and add privileges.
+--echo #
+connect (conn_root,localhost,root,,);
+
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+GRANT SELECT ON backup_test.* TO 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+--echo #
+--echo # Show grants for user.
+--echo #
+SHOW GRANTS FOR 'bup_some_priv'@'localhost';
+
+disconnect conn_root;
+--echo #
+--echo # Connect as user with only some privileges.
+--echo #
+connect (conn_some_priv,localhost,bup_some_priv,,);
+
+--echo #
+--echo # conn_some_priv: Attempting restore. Should fail with
+--echo # error ER_RESTORE_ACCESS_OBJS_INCOMPLETE
+--echo #
+--replace_column 1 #
+--error ER_RESTORE_ACCESS_OBJS_INCOMPLETE
+RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
+--replace_column 2 #
+SHOW ERRORS;
+
+--echo #
+--echo # Test Case 5 : Show that SUPER is needed to complete restore
+--echo # when there are objects with definer clauses.
+--echo #
+
+disconnect conn_some_priv;
+--echo #
+--echo # Connect as root and add privileges.
+--echo #
+connect (conn_root,localhost,root,,);
+
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+GRANT ALL ON backup_test.* TO 'bup_some_priv'@'localhost' WITH GRANT OPTION;
+GRANT ALL ON mysql.* TO 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+--echo #
+--echo # Show grants for user.
+--echo #
+SHOW GRANTS FOR 'bup_some_priv'@'localhost';
+
+disconnect conn_root;
+--echo #
+--echo # Connect as user with only some privileges.
+--echo #
+connect (conn_some_priv,localhost,bup_some_priv,,);
+
+--echo #
+--echo # conn_some_priv: Attempting restore. Should fail with
+--echo # ER_RESTORE_ACCESS_DEFINER
+--echo #
+--replace_column 1 #
+--error ER_RESTORE_ACCESS_DEFINER
+RESTORE FROM 'backup_test_no_proc.bak' OVERWRITE;
+--replace_column 2 #
+SHOW ERRORS;
+
+--echo #
+--echo # Test Case 6 : Ensure a user can only restore the database if and only
+--echo # if she has all of the required permissions to create and
+--echo # populate all objects.
+--echo #
+
+disconnect conn_some_priv;
+--echo #
+--echo # Connect as root and add privileges.
+--echo #
+connect (conn_root,localhost,root,,);
+
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+GRANT ALL ON backup_test.* TO 'bup_some_priv'@'localhost' WITH GRANT OPTION;
+GRANT SELECT ON mysql.* TO 'bup_some_priv'@'localhost';
+GRANT SUPER ON *.* TO 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+--echo #
+--echo # Show grants for user.
+--echo #
+SHOW GRANTS FOR 'bup_some_priv'@'localhost';
+
+disconnect conn_root;
+--echo #
+--echo # Connect as user with only some privileges.
+--echo #
+connect (conn_some_priv,localhost,bup_some_priv,,);
+
+--echo #
+--echo # conn_some_priv: Attempting restore. Should succeed.
+--echo #
+--replace_column 1 #
+RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
+
+disconnect conn_some_priv;
+--echo #
+--echo # Connect as root and cleanup.
+--echo #
+connect (conn_root,localhost,root,,);
+
+--echo #
+--echo # Test Case 7 : Show that the privilege check on TRIGGER is required to
+--echo # restore a table with a trigger.
+
+--echo #
+--echo # Perform a backup with only a table and a trigger.
+--echo # No grants either.
+--echo #
+
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+REVOKE ALL ON backup_test.* FROM 'bup_some_priv'@'localhost';
+DROP USER 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+CREATE DATABASE backup_test_trig;
+CREATE TABLE backup_test_trig.t1 (a char(30)) ENGINE=MEMORY;
+CREATE TRIGGER backup_test_trig.trg AFTER INSERT ON backup_test_trig.t1 FOR EACH ROW
+ INSERT INTO backup_test_trig.t1 VALUES('Test objects count');
+
+--replace_column 1 #
+BACKUP DATABASE backup_test_trig TO 'backup_test_trig.bak';
+
+CREATE USER 'bup_some_priv'@'localhost';
+
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+
+GRANT INSERT, UPDATE, DELETE, BACKUP, RESTORE, SELECT, CREATE, DROP
+ ON backup_test_trig.* TO 'bup_some_priv'@'localhost' WITH GRANT OPTION;
+GRANT SELECT ON mysql.* TO 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+--echo #
+--echo # Show grants for user.
+--echo #
+SHOW GRANTS FOR 'bup_some_priv'@'localhost';
+
+disconnect conn_root;
+--echo #
+--echo # Connect as user with only some privileges.
+--echo #
+connect (conn_some_priv,localhost,bup_some_priv,,);
+
+--echo #
+--echo # conn_some_priv: Attempting restore. Should fail with
+--echo # error ER_RESTORE_ACCESS_OBJS_INCOMPLETE
+--echo #
+--replace_column 1 #
+--error ER_RESTORE_ACCESS_OBJS_INCOMPLETE
+RESTORE FROM 'backup_test_trig.bak' OVERWRITE;
+--replace_column 2 #
+SHOW ERRORS;
+
+disconnect conn_some_priv;
+--echo #
+--echo # Connect as root and add privilege for trigger.
+--echo #
+connect (conn_root,localhost,root,,);
+
+GRANT TRIGGER ON backup_test_trig.t1 TO 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+disconnect conn_root;
+--echo #
+--echo # Connect as user with only some privileges.
+--echo #
+connect (conn_some_priv,localhost,bup_some_priv,,);
+
+--echo #
+--echo # conn_some_priv: Attempting restore. Should fail with
+--echo # ER_RESTORE_ACCESS_DEFINER
+--echo #
+--replace_column 1 #
+--error ER_RESTORE_ACCESS_DEFINER
+RESTORE FROM 'backup_test_trig.bak' OVERWRITE;
+SHOW ERRORS;
+
+disconnect conn_some_priv;
+--echo #
+--echo # Connect as root and add privilege for trigger.
+--echo # In this case, we must add SUPER to overcome limitation with
+--echo # the definer clause.
+--echo #
+connect (conn_root,localhost,root,,);
+
+GRANT SUPER ON *.* TO 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+disconnect conn_root;
+--echo #
+--echo # Connect as user with only some privileges.
+--echo #
+connect (conn_some_priv,localhost,bup_some_priv,,);
+
+--echo #
+--echo # conn_some_priv: Attempting restore. Should succeed.
+--echo #
+--replace_column 1 #
+RESTORE FROM 'backup_test_trig.bak' OVERWRITE;
+
+--echo #
+--echo # Test Case 8 : Show that user can have only RESTORE_ACL +
+--echo # SUPER_ACL to perform an elevated restore.
+--echo #
+
+disconnect conn_some_priv;
+--echo #
+--echo # Change privileges for elevated restore test case.
+--echo #
+connect (conn_root,localhost,root,,);
+
+DROP DATABASE backup_test_trig;
+
+DROP USER 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+CREATE USER 'bup_some_priv'@'localhost';
+
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+GRANT RESTORE ON backup_test.* TO 'bup_some_priv'@'localhost';
+GRANT SUPER ON *.* TO 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+disconnect conn_root;
+--echo #
+--echo # Connect as user with only some privileges.
+--echo #
+connect (conn_some_priv,localhost,bup_some_priv,,);
+
+--echo #
+--echo # conn_some_priv: Attempting restore. Should succeed.
+--echo #
+--replace_column 1 #
+RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
+
+--echo #
+--echo # Test Case 9 : Show that users who have RESTORE + SUPER for db1 but not
+--echo # for db2 cannot restore the image.
+--echo #
+
+disconnect conn_some_priv;
+--echo #
+--echo # Change privileges for elevated restore test case.
+--echo #
+connect (conn_root,localhost,root,,);
+
+DROP USER 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+CREATE USER 'bup_some_priv'@'localhost';
+
+REVOKE ALL ON *.* FROM 'bup_some_priv'@'localhost';
+GRANT RESTORE ON backup_test.* TO 'bup_some_priv'@'localhost';
+GRANT SUPER ON *.* TO 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+disconnect conn_root;
+--echo #
+--echo # Connect as user with only some privileges.
+--echo #
+connect (conn_some_priv,localhost,bup_some_priv,,);
+
+--echo #
+--echo # conn_some_priv: Attempting restore. Should fail with
+--echo # error ER_RESTORE_ACCESS_DENIED_ERROR
+--echo #
+--replace_column 1 #
+--error ER_RESTORE_ACCESS_DENIED_ERROR
+RESTORE FROM 'backup_test_orig_alt1.bak' OVERWRITE;
+SHOW ERRORS;
+
+--echo #
+--echo # conn_some_priv: Attempting restore. Should fail with
+--echo # error ER_RESTORE_ACCESS_DENIED_ERROR
+--echo #
+--replace_column 1 #
+--error ER_RESTORE_ACCESS_DENIED_ERROR
+RESTORE FROM 'backup_test_orig_alt2.bak' OVERWRITE;
+SHOW ERRORS;
+
+disconnect conn_some_priv;
+--echo #
+--echo # Change privileges for elevated restore test case.
+--echo #
+connect (conn_root,localhost,root,,);
+
+GRANT RESTORE ON backup_test_alt.* TO 'bup_some_priv'@'localhost';
+
+FLUSH PRIVILEGES;
+
+disconnect conn_root;
+--echo #
+--echo # Connect as user with only some privileges.
+--echo #
+connect (conn_some_priv,localhost,bup_some_priv,,);
+
+--echo #
+--echo # conn_some_priv: Attempting restore. Should succeed.
+--echo #
+--replace_column 1 #
+RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
+
+
+disconnect conn_some_priv;
+--echo #
+--echo # Connect as root and cleanup.
+--echo #
+connect (conn_root,localhost,root,,);
+
+--echo #
+--echo # Compare to original backup image file.
+--echo #
+
+--replace_column 1 #
+RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
+
+--echo #
+--echo # Show list of all objects in the database.
+--echo #
+SHOW FULL TABLES FROM backup_test;
+SELECT event_name FROM INFORMATION_SCHEMA.EVENTS WHERE event_schema = 'backup_test';
+SELECT routine_name FROM INFORMATION_SCHEMA.ROUTINES WHERE routine_schema = 'backup_test';
+SELECT trigger_name FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_schema = 'backup_test';
+
+--echo #
+--echo # Cleanup
+--echo #
+
+DROP USER 'bup_some_priv'@'localhost';
+DROP USER 'joe'@'user';
+
+DROP DATABASE backup_test;
+DROP DATABASE backup_test_alt;
+FLUSH PRIVILEGES;
+
+let $MYSQLD_BACKUPDIR= `select @@backupdir`;
+remove_file $MYSQLD_BACKUPDIR/backup_test_orig.bak;
+remove_file $MYSQLD_BACKUPDIR/backup_test_orig_alt1.bak;
+remove_file $MYSQLD_BACKUPDIR/backup_test_orig_alt2.bak;
+remove_file $MYSQLD_BACKUPDIR/backup_test_trig.bak;
+remove_file $MYSQLD_BACKUPDIR/backup_test_no_proc.bak;
=== modified file 'mysql-test/suite/backup/t/backup_security.test'
--- a/mysql-test/suite/backup/t/backup_security.test 2009-10-23 21:26:11 +0000
+++ b/mysql-test/suite/backup/t/backup_security.test 2009-11-04 20:56:16 +0000
@@ -184,11 +184,11 @@ SHOW TABLES FROM backup_test;
--echo #
--echo #
---echo # conn_user1: Attempting restore. Should fail with one of the restore
---echo # catalog errors.
+--echo # conn_user1: Attempting restore. Should fail with
+--echo # error ER_RESTORE_ACCESS_OBJS_INCOMPLETE.
--echo #
--replace_column 1 #
---error ER_BACKUP_CANT_RESTORE_DB, ER_BACKUP_CANT_RESTORE_TABLE, ER_BACKUP_CANT_RESTORE_VIEW, ER_BACKUP_CANT_RESTORE_SROUT, ER_BACKUP_CANT_RESTORE_EVENT, ER_BACKUP_CANT_RESTORE_TRIGGER
+--error ER_RESTORE_ACCESS_OBJS_INCOMPLETE
eval RESTORE FROM 'bup_user1.bak' OVERWRITE;
--echo #
@@ -198,10 +198,10 @@ eval RESTORE FROM 'bup_user1.bak' OVERWR
--echo #
--echo # conn_user1: Attempting backup. Should fail with
---echo # error ER_BACKUP_ACCESS_DENIED_ERROR
+--echo # error ER_BAD_DB_ERROR
--echo #
--replace_column 1 #
---error ER_BACKUP_ACCESS_DENIED_ERROR
+--error ER_BAD_DB_ERROR
BACKUP DATABASE backup_test_alt to 'bup_no_priv.bak';
--replace_column 2 #
SHOW ERRORS;
=== modified file 'sql/backup/backup_info.cc'
--- a/sql/backup/backup_info.cc 2009-10-23 15:41:56 +0000
+++ b/sql/backup/backup_info.cc 2009-11-04 20:56:16 +0000
@@ -665,21 +665,31 @@ backup::Image_info::Db* Backup_info::add
/*
Check privileges for this database. User must have BACKUP
privilege in order to execute a backup.
+
+ We must turn privilege checking back on first.
*/
+ m_thd->security_ctx->restore_global_privileges();
+
DEBUG_SYNC(m_thd, "before_backup_privileges");
if (check_access(m_thd, BACKUP_ACL, name->ptr(), 0, 1, 1, 0))
{
m_log.report_error(ER_BACKUP_ACCESS_DENIED_ERROR, name->ptr());
return NULL;
- }
+ }
+ /*
+ The base check for BACKUP_ACL for this database is satisfied,
+ ok to elevate by turning off privilege checking.
+ */
+ m_thd->security_ctx->set_all_global_privileges();
+
// Check to see if the user can see all of the objects in the database.
if (obs::check_user_access(m_thd, name))
{
m_log.report_error(ER_BACKUP_ACCESS_OBJS_INCOMPLETE, name->ptr());
return NULL;
}
-
+
Db *db= Image_info::add_db(*name, pos);
if (!db)
@@ -766,7 +776,7 @@ int Backup_info::add_dbs(THD *thd, List<
delete obj;
goto error;
}
-
+
if (add_db_items(*db)) // Reports errors.
goto error;
}
=== modified file 'sql/backup/kernel.cc'
--- a/sql/backup/kernel.cc 2009-10-23 15:41:56 +0000
+++ b/sql/backup/kernel.cc 2009-11-04 20:56:16 +0000
@@ -639,6 +639,11 @@ int Backup_restore_ctx::prepare_path(::S
int Backup_restore_ctx::prepare(::String *backupdir, LEX_STRING location)
{
+ /*
+ Save privilege information for restoring later.
+ */
+ m_thd->security_ctx->save_global_privileges();
+
if (m_error)
return m_error;
@@ -1180,6 +1185,11 @@ int Backup_restore_ctx::close()
{
int res= 0;
+ /*
+ Restore privilege information.
+ */
+ m_thd->security_ctx->restore_global_privileges();
+
if (m_state == CLOSED)
return 0;
@@ -1984,7 +1994,20 @@ int bcat_add_item(st_bstream_image_heade
item->name.begin,
item->type,
item->pos));
+
+ /*
+ Do object-level privilege checking for all objects being restored.
+ The user must have, at a minimum, the ability to create each object
+ plus any specific privileges for the object type (e.g. functions,
+ triggers).
+
+ An error is returned if the user does not have the correct privileges
+ to create the object.
+ */
+ if (info->check_restore_privileges(item))
+ return BSTREAM_ERROR;
+
switch (item->type) {
case BSTREAM_IT_TABLESPACE:
=== modified file 'sql/backup/restore_info.h'
--- a/sql/backup/restore_info.h 2009-10-21 13:32:24 +0000
+++ b/sql/backup/restore_info.h 2009-11-04 20:56:16 +0000
@@ -45,6 +45,12 @@ public:
Image_info::Db* add_db(const ::String&, uint);
Image_info::Table* add_table(Image_info::Db&, const ::String&,
backup::Snapshot_info&, ulong);
+
+ bool check_restore_privileges(struct st_bstream_item_info *item);
+
+ bool m_skip_precheck; // skip prechecking if privilege check ok
+ bool m_first_priv_check; // determines if this is the first db to be checked
+
private:
/*
@@ -76,7 +82,8 @@ private:
inline
Restore_info::Restore_info(backup::Logger &log, THD *thd)
- :m_log(log), m_thd(thd), m_data_changed(FALSE)
+ :m_log(log), m_thd(thd), m_data_changed(FALSE),
+ m_skip_precheck(FALSE), m_first_priv_check(TRUE)
{}
@@ -111,23 +118,12 @@ Restore_info::add_ts(const ::String &nam
}
-/// Wrapper around Image_info method which reports errors and checks privileges.
+/// Wrapper around Image_info method which reports errors.
inline
backup::Image_info::Db*
Restore_info::add_db(const ::String &name, uint pos)
{
- /*
- Check privileges for this database. User must have RESTORE
- privilege in order to execute a restore.
- */
- DEBUG_SYNC(m_thd, "before_restore_privileges");
- if (check_access(m_thd, RESTORE_ACL, name.ptr(), 0, 1, 1, 0))
- {
- m_log.report_error(ER_RESTORE_ACCESS_DENIED_ERROR, name.ptr());
- return NULL;
- }
-
Db *db= Image_info::add_db(name, pos);
if (!db)
@@ -153,4 +149,247 @@ Restore_info::add_table(Image_info::Db &
return t;
}
+/**
+ Perform privilege checking for restore.
+
+ This method checks the known minimal privileges needed to restore each
+ object in the backup image. This method is called once for every object in
+ the catalog. It ensures there are no privilege-based restrictions that would
+ prohibit a successful restore.
+
+ It begins by checking that the user has RESTORE for the database. If the user
+ does not have RESTORE on any database in the backup image, an error is
+ generated. Next, specific object-level privilege checking is performed for
+ all of the objects in the database. The object-level privileges checked
+ include the following.
+
+ RESTORE,CREATE,DROP on db
+ CREATE on db.x (if table or view x)
+ CREATE_TABLESPACE on *.* (if tablespace)
+ SUPER on *.* (if view, stored routine, event or trigger)
+ CREATE_PROC on db.* (if stored routine)
+ EVENT on db.* (if event)
+ GRANT on db.* (if privilege)
+ TRIGGER on db.* (if trigger but table not found)
+ TRIGGER on db.t (if trigger on t)
+
+ @param[in] item The item to check.
+
+ @returns
+ @retval FALSE User has privileges for the object.
+ @retval TRUE User does not have privileges for object.
+*/
+inline
+bool
+Restore_info::check_restore_privileges(struct st_bstream_item_info *item)
+{
+ using namespace backup;
+ int result= 0;
+ THD *thd= ::current_thd;
+ Image_info::Db *db= NULL; // Database object
+ st_bstream_table_info *tbl_info; // Table information
+ st_bstream_dbitem_info *db_item; // Database item information
+ TABLE_LIST tbl_list;
+
+ backup::String item_name(item->name.begin, item->name.end);
+ const char *name_str= item_name.c_ptr_safe();
+
+ /*
+ Check privileges for this database. User must have RESTORE
+ privilege in order to execute a restore.
+ Check privileges for this database.
+
+ If user has RESTORE + SUPER, do not do object-level privilege checking.
+
+ If the user does not have RESTORE, fail with an error.
+
+ @note Databases are listed after tablesspaces and charsets in the
+ catalog. Thus, the list of databases are read before the database
+ objects.
+ */
+ DEBUG_SYNC(thd, "before_restore_privileges");
+
+ if (item->type == BSTREAM_IT_DB)
+ {
+ // We must turn privilege checking back on first.
+ m_thd->security_ctx->restore_global_privileges();
+
+ /*
+ If this is the first check, set m_skip_precheck.
+ */
+ if (m_first_priv_check)
+ {
+ m_skip_precheck= TRUE;
+ m_first_priv_check= FALSE;
+ }
+ if (!check_access(m_thd, RESTORE_ACL, name_str, 0, 1, 1, 0) &&
+ (m_thd->security_ctx->master_access & SUPER_ACL) &&
+ m_skip_precheck)
+ {
+ /*
+ The base check for RESTORE_ACL + SUPER_ACL for this database is
+ satisfied. It is ok to elevate by turning off privilege checking.
+ */
+ m_thd->security_ctx->set_all_global_privileges();
+ m_skip_precheck= TRUE;
+ }
+ else
+ {
+ m_skip_precheck= FALSE;
+ }
+ if (check_access(thd, RESTORE_ACL, name_str, 0, 1, 1, 0))
+ {
+ m_log.report_error(ER_RESTORE_ACCESS_DENIED_ERROR, name_str);
+ return TRUE;
+ }
+ }
+
+ /*
+ If the user does not have RESTORE + SUPER, as indicated by m_skip_precheck
+ == FALSE, we must perform object-level privilege checking for all objects
+ being restored. The user must have, at a minimum, the ability to create
+ each object plus any specific privileges for the object type (e.g.
+ functions, triggers, events, etc.).
+
+ An error is returned if the user does not have the correct privileges
+ to create the object.
+ */
+ if (!m_skip_precheck)
+ {
+ /*
+ Check privileges for each object based on type of object.
+ */
+ switch (item->type)
+ {
+ case BSTREAM_IT_TABLESPACE:
+ {
+ result= check_global_access(thd, CREATE_TABLESPACE_ACL);
+ break;
+ }
+ case BSTREAM_IT_DB:
+ {
+ result= check_access(thd, CREATE_ACL + DROP_ACL,
+ name_str, 0, 1, 1, 0);
+ break;
+ }
+ case BSTREAM_IT_TABLE:
+ case BSTREAM_IT_VIEW:
+ {
+ tbl_info= (st_bstream_table_info*) item;
+ DBUG_ASSERT (tbl_info);
+
+ db= get_db(tbl_info->base.db->base.pos); // reports errors
+ DBUG_ASSERT(db);
+
+ tbl_list.init_one_table(db->name().ptr(), db->name().length(),
+ name_str, strlen(name_str),
+ name_str, TL_READ);
+
+ result= check_table_access(thd, CREATE_ACL, &tbl_list, TRUE, TRUE, 1);
+
+ break;
+ }
+ case BSTREAM_IT_SPROC:
+ case BSTREAM_IT_SFUNC:
+ {
+ st_bstream_dbitem_info *db_item= (st_bstream_dbitem_info*) item;
+ DBUG_ASSERT(db_item);
+
+ db= (Image_info::Db*) get_db(db_item->db->base.pos);
+ DBUG_ASSERT(db);
+
+ result= check_access(thd, CREATE_PROC_ACL, db->name().ptr(), 0, 1, 1, 0);
+ break;
+ }
+ case BSTREAM_IT_EVENT:
+ {
+ st_bstream_dbitem_info *db_item= (st_bstream_dbitem_info*) item;
+ DBUG_ASSERT(db_item);
+
+ db= (Image_info::Db*) get_db(db_item->db->base.pos);
+ DBUG_ASSERT(db);
+
+ result= check_access(thd, EVENT_ACL, db->name().ptr(), 0, 1, 1, 0);
+ break;
+ }
+ case BSTREAM_IT_TRIGGER:
+ {
+ st_bstream_dbitem_info *db_item= (st_bstream_dbitem_info*) item;
+ DBUG_ASSERT(db_item);
+
+ db= (Image_info::Db*) get_db(db_item->db->base.pos);
+ DBUG_ASSERT(db);
+
+ /*
+ Get the table reference for this trigger and check access.
+ */
+ Image_info::Table *tbl= get_table(db_item->snap_num, db_item->pos);
+
+ /*
+ If the table is not found, revert to checking at the database
+ level.
+ */
+ if (!tbl)
+ {
+ result= check_access(thd, TRIGGER_ACL, db->name().ptr(), 0, 1, 1, 0);
+ }
+ else
+ {
+ tbl_list.init_one_table(db->name().ptr(), db->name().length(),
+ tbl->name().ptr(), tbl->name().length(),
+ tbl->name().ptr(), TL_READ);
+ result= check_table_access(thd, TRIGGER_ACL, &tbl_list, TRUE, TRUE, 1);
+ }
+ break;
+ }
+ case BSTREAM_IT_PRIVILEGE:
+ {
+ st_bstream_dbitem_info *db_item= (st_bstream_dbitem_info*) item;
+ DBUG_ASSERT(db_item);
+
+ db= (Image_info::Db*) get_db(db_item->db->base.pos);
+ DBUG_ASSERT(db);
+
+ result= check_access(thd, GRANT_ACL, db->name().ptr(), 0, 1, 1, 0);
+ break;
+ }
+ default:
+ break;
+ } // switch (item->type)
+
+ // Return error if privilege check fails.
+ if (result)
+ {
+ m_log.report_error(ER_RESTORE_ACCESS_OBJS_INCOMPLETE, name_str);
+ return TRUE;
+ }
+
+ /*
+ Check for SUPER_ACL if any objects exist that have a definer clause.
+ */
+ switch (item->type)
+ {
+ case BSTREAM_IT_VIEW:
+ case BSTREAM_IT_SPROC:
+ case BSTREAM_IT_SFUNC:
+ case BSTREAM_IT_EVENT:
+ case BSTREAM_IT_TRIGGER:
+ {
+ result= !(thd->security_ctx->master_access & SUPER_ACL);
+ break;
+ }
+ default:
+ break;
+ } // switch (item->type)
+
+ // Return error if privilege check fails.
+ if (result)
+ {
+ m_log.report_error(ER_RESTORE_ACCESS_DEFINER, db->name().ptr(), name_str);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
#endif /*RESTORE_INFO_H_*/
=== modified file 'sql/si_objects.cc'
--- a/sql/si_objects.cc 2009-11-04 14:18:21 +0000
+++ b/sql/si_objects.cc 2009-11-04 20:56:16 +0000
@@ -202,10 +202,7 @@ bool
run_service_interface_sql(THD *thd, Ed_connection *ed_connection,
const LEX_STRING *query, bool get_warnings)
{
- Si_session_context session_context;
- ulong saved_master_access; // Saved master access ACLs
- ulong saved_db_access; // Saved db access ACLs
-
+ Si_session_context session_context;
DBUG_ENTER("run_service_interface_sql");
DBUG_PRINT("run_service_interface_sql",
@@ -215,25 +212,6 @@ run_service_interface_sql(THD *thd, Ed_c
session_context.save_si_ctx(thd);
session_context.reset_si_ctx(thd);
- /*
- We only elevate for SELECT or SHOW CREATE queries.
- */
- my_bool elevate= strncmp(query->str, "SELECT", 6) == 0 ||
- strncmp(query->str, "(SELECT", 7) == 0 ||
- strncmp(query->str, "SHOW CREATE", 11) == 0 ? TRUE : FALSE;
-
- /*
- Temporarily give user SELECT privilege so operations on
- mysql and information_schema can succeed.
- */
- if (elevate)
- {
- saved_master_access= thd->security_ctx->master_access;
- saved_db_access= thd->security_ctx->db_access;
- thd->security_ctx->master_access |= (SELECT_ACL | SHOW_VIEW_ACL |
- TRIGGER_ACL | PROC_ACLS | EVENT_ACL);
- }
-
bool rc= ed_connection->execute_direct(*query);
if (get_warnings)
@@ -242,15 +220,6 @@ run_service_interface_sql(THD *thd, Ed_c
thd->warning_info->append_warnings(thd, ed_connection->get_warn_list());
}
- /*
- Remove elevated privilege.
- */
- if (elevate)
- {
- thd->security_ctx->master_access= saved_master_access;
- thd->security_ctx->db_access= saved_db_access;
- }
-
session_context.restore_si_ctx(thd);
DBUG_RETURN(rc);
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2009-10-26 14:02:26 +0000
+++ b/sql/sql_class.cc 2009-11-04 20:56:16 +0000
@@ -2991,6 +2991,24 @@ void Security_context::skip_grants()
*priv_host= '\0';
}
+// Turns off grants but keeps user context.
+void Security_context::set_all_global_privileges()
+{
+ master_access= ~NO_ACCESS;
+}
+
+// Saves current privilege settings.
+void Security_context::save_global_privileges()
+{
+ /* save the values for restoring later with reset_grant_info() */
+ m_saved_master_access= master_access;
+}
+
+// Turns grants back on.
+void Security_context::restore_global_privileges()
+{
+ master_access= m_saved_master_access;
+}
bool Security_context::set_user(char *user_arg)
{
=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h 2009-10-28 15:45:46 +0000
+++ b/sql/sql_class.h 2009-11-04 20:56:16 +0000
@@ -852,6 +852,9 @@ public:
void init();
void destroy();
void skip_grants();
+ void set_all_global_privileges();
+ void save_global_privileges();
+ void restore_global_privileges();
inline char *priv_host_name()
{
return (*priv_host ? priv_host : (char *)"%");
@@ -871,6 +874,8 @@ public:
restore_security_context(THD *thd, Security_context *backup);
#endif
bool user_matches(Security_context *);
+private:
+ ulong m_saved_master_access;
};
Attachment: [text/bzr-bundle] bzr/charles.bell@sun.com-20091104205616-61dj70bst5fzuima.bundle
| Thread |
|---|
| • bzr commit into mysql-6.0-backup branch (charles.bell:2888) Bug#44787 | Chuck Bell | 4 Nov |