List:Commits« Previous MessageNext Message »
From:Chuck Bell Date:November 11 2009 9:29pm
Subject:bzr commit into mysql-6.0-backup branch (charles.bell:2889) Bug#44787
View as plain text  
#At file:///Users/cbell/source/bzr/mysql-6.0-bug-44787-elevation/ based on revid:charles.bell@stripped

 2889 Chuck Bell	2009-11-11
      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_errors_debug_3.result
        Corrected result file.
     @ 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_errors_debug_3.test
        Must turn off this test case until we can turn off elevation
        because the debug insertion code is in the prechecking code.
     @ 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 methods to save and restore privileges prior to and
        after elevation.
        
        Added code to call the new check_restore_elevation() method.
        
        Added check to ensure elevation is OFF before doing prechecking.
     @ sql/backup/restore_info.h
        Added attributes for privilege checking.
        Added code to do restore elevation in the check_restore_elevation()
        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.

    modified:
      mysql-test/suite/backup/r/backup_errors_debug_3.result
      mysql-test/suite/backup/r/backup_restore_security.result
      mysql-test/suite/backup/r/backup_security.result
      mysql-test/suite/backup/t/backup_errors_debug_3.test
      mysql-test/suite/backup/t/backup_restore_security.test
      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
=== modified file 'mysql-test/suite/backup/r/backup_errors_debug_3.result'
--- a/mysql-test/suite/backup/r/backup_errors_debug_3.result	2009-11-11 16:51:13 +0000
+++ b/mysql-test/suite/backup/r/backup_errors_debug_3.result	2009-11-11 21:29:15 +0000
@@ -1265,44 +1265,6 @@ backup_id
 # Done.
 #
 #
-# Test case 69 - testing error ER_RESTORE_DB_ERROR
-#
-# Set debug SESSION variable for ER_RESTORE_DB_ERROR
-#
-SET SESSION debug="+d,ER_RESTORE_DB_ERROR";
-#
-# Execute restore
-#
-RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
-ERROR HY000: The database for object 't1' was not found in the catalog.
-#
-# Test case for error ER_RESTORE_DB_ERROR PASSED.
-#
-#
-# Show warning/error from progress and history log
-# if they exist.
-#
-SELECT * FROM mysql.backup_progress WHERE error_num <> 0;
-backup_id	object	error_num	notes
-#		####	The database for object 't1' was not found in the catalog.
-PURGE BACKUP LOGS;
-#
-# Turn off debug SESSION.
-#
-SET SESSION debug="-d";
-#
-# Now demonstrate that the command will work without the
-# debug session tag.
-#
-# Running restore - should not fail.
-#
-RESTORE FROM 'backup_test_orig.bak' OVERWRITE;
-backup_id
-#
-#
-# Done.
-#
-#
 # Test case 70 - testing error ER_BACKUP_UNEXPECTED_DATA
 #
 # Set debug SESSION variable for ER_BACKUP_UNEXPECTED_DATA

=== modified file 'mysql-test/suite/backup/r/backup_restore_security.result'
--- a/mysql-test/suite/backup/r/backup_restore_security.result	2009-11-11 16:51:13 +0000
+++ b/mysql-test/suite/backup/r/backup_restore_security.result	2009-11-11 21:29:15 +0000
@@ -40,6 +40,13 @@ DELETE FROM backup_test.t1 WHERE a = "no
 #
 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';
@@ -56,6 +63,12 @@ GRANT USAGE ON *.* TO 'bup_some_priv'@'l
 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.
 #
@@ -88,6 +101,7 @@ backup_id
 #               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.
@@ -95,7 +109,7 @@ FLUSH PRIVILEGES;
 SHOW GRANTS FOR 'bup_some_priv'@'localhost';
 Grants for bup_some_priv@localhost
 GRANT USAGE ON *.* TO 'bup_some_priv'@'localhost'
-GRANT RESTORE ON `backup_test`.* TO 'bup_some_priv'@'localhost'
+GRANT CREATE, DROP, RESTORE ON `backup_test`.* TO 'bup_some_priv'@'localhost'
 #
 # Connect as user with only some privileges.
 #
@@ -104,10 +118,10 @@ GRANT RESTORE ON `backup_test`.* TO 'bup
 # 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 'backup_test' from this backup image.
+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 'backup_test' from this backup image.
+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.
@@ -124,7 +138,7 @@ FLUSH PRIVILEGES;
 SHOW GRANTS FOR 'bup_some_priv'@'localhost';
 Grants for bup_some_priv@localhost
 GRANT USAGE ON *.* TO 'bup_some_priv'@'localhost'
-GRANT SELECT, RESTORE ON `backup_test`.* 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.
 #
@@ -133,10 +147,10 @@ GRANT SELECT, RESTORE ON `backup_test`.*
 # 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 'backup_test' from this backup image.
+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 'backup_test' from this backup image.
+Error	#	Insufficient privileges. You do not have privileges to restore the object 'p1' from this backup image.
 #
 # Test Case 3 : Show that SUPER is needed to complete restore 
 #               when there are objects with definer clauses.
@@ -224,14 +238,13 @@ REVOKE ALL ON *.* FROM 'bup_some_priv'@'
 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';
-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 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
 #
@@ -255,16 +268,107 @@ 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
 #
 #
-# Connect as root and cleanup.
+# Change privileges for elevated restore test case.
 #
 DROP DATABASE backup_test_trig;
 #
+# Test Case 8 : Show that user can have only RESTORE + SUPER and 
+#               perform an elevated restore.
+#
+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
+#
+#
+# Change privileges for elevated restore test case.
+#
+#
+# Test Case 9 : Show that users who have RESTORE + SUPER for db1 but not
+#               for db2 cannot restore the image.
+#
+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;
@@ -294,4 +398,5 @@ trg
 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-11-11 16:51:13 +0000
+++ b/mysql-test/suite/backup/r/backup_security.result	2009-11-11 21:29:15 +0000
@@ -401,13 +401,13 @@ ERROR HY000: Insufficient privileges. Yo
 #
 #
 # 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

=== modified file 'mysql-test/suite/backup/t/backup_errors_debug_3.test'
--- a/mysql-test/suite/backup/t/backup_errors_debug_3.test	2009-11-11 16:51:13 +0000
+++ b/mysql-test/suite/backup/t/backup_errors_debug_3.test	2009-11-11 21:29:15 +0000
@@ -356,7 +356,7 @@ LET $caseno = 69;
 LET $errno = $ER_RESTORE_DB_ERROR;
 LET $errname = ER_RESTORE_DB_ERROR;
 LET $operation = RESTORE;
---source suite/backup/include/test_for_error.inc
+#--source suite/backup/include/test_for_error.inc
 
 # Test for error ER_BACKUP_UNEXPECTED_DATA.
 --echo #

=== modified file 'mysql-test/suite/backup/t/backup_restore_security.test'
--- a/mysql-test/suite/backup/t/backup_restore_security.test	2009-11-11 16:51:13 +0000
+++ b/mysql-test/suite/backup/t/backup_restore_security.test	2009-11-11 21:29:15 +0000
@@ -11,6 +11,10 @@
 #     all of the required permissions to create and populate all objects.
 #  5. 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
@@ -38,6 +42,15 @@ CREATE USER 'joe'@'user';
 --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';
@@ -56,6 +69,12 @@ SHOW GRANTS FOR 'bup_some_priv'@'localho
 --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 #
@@ -81,6 +100,7 @@ BACKUP DATABASE backup_test to 'backup_t
 --echo #
 
 GRANT RESTORE ON backup_test.* TO 'bup_some_priv'@'localhost';
+GRANT CREATE, DROP ON backup_test.* TO 'bup_some_priv'@'localhost'; 
 
 FLUSH PRIVILEGES;
 
@@ -252,7 +272,6 @@ REVOKE ALL ON *.* FROM 'bup_some_priv'@'
 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';
-GRANT SUPER ON *.* TO 'bup_some_priv'@'localhost';
 
 FLUSH PRIVILEGES;
 
@@ -294,6 +313,33 @@ disconnect conn_root;
 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 #
@@ -301,13 +347,118 @@ RESTORE FROM 'backup_test_trig.bak' OVER
 
 disconnect conn_some_priv;
 --echo #
---echo # Connect as root and cleanup.
+--echo # Change privileges for elevated restore test case.
 --echo #
 connect (conn_root,localhost,root,,);
 
 DROP DATABASE backup_test_trig;
 
 --echo #
+--echo # Test Case 8 : Show that user can have only RESTORE + SUPER and 
+--echo #               perform an elevated restore.
+--echo #
+
+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;
+
+disconnect conn_some_priv;
+--echo #
+--echo # Change privileges for elevated restore test case.
+--echo #
+connect (conn_root,localhost,root,,);
+
+--echo #
+--echo # Test Case 9 : Show that users who have RESTORE + SUPER for db1 but not
+--echo #               for db2 cannot restore the image.
+--echo #
+
+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 #
 
@@ -330,9 +481,12 @@ 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-11-11 16:51:13 +0000
+++ b/mysql-test/suite/backup/t/backup_security.test	2009-11-11 21:29:15 +0000
@@ -19,6 +19,7 @@
 disable_query_log;
 call mtr.add_suppression("Backup: Insufficient privileges");
 call mtr.add_suppression("Restore: Insufficient privileges");
+call mtr.add_suppression("Backup: Unknown database");
 enable_query_log;
 
 connect (conn_root,localhost,root,,);
@@ -198,10 +199,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-11 21:29:15 +0000
@@ -665,7 +665,11 @@ 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))
   {
@@ -673,6 +677,12 @@ backup::Image_info::Db* Backup_info::add
     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))
   {

=== modified file 'sql/backup/kernel.cc'
--- a/sql/backup/kernel.cc	2009-11-11 16:51:13 +0000
+++ b/sql/backup/kernel.cc	2009-11-11 21:29:15 +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;
 
@@ -1986,16 +1996,29 @@ int bcat_add_item(st_bstream_image_heade
                         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).
+    Perform restore elevation or access check for each database. 
+    
+    If user does not have RESTORE_ACL for the database, an error will be 
+    generated. If user has RESTORE_ACL but does not have SUPER_ACL, a check 
+    will be made to ensure user has CREATE_ACL + DROP_ACL for the database.
+    If the user does not have CREATE_ACL + DROP_ACL, an error will be 
+    generated.
+  */
+  if (info->check_restore_elevation(item))
+    return BSTREAM_ERROR;
+
+  /*
+    Perform the prechecking if we are not using elevation.
+
+    Do object-level privilege checking for all objects being restored other
+    than databases. 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))
+  if (!info->elevated_restore() && info->check_restore_privileges(item))
     return BSTREAM_ERROR; 
   
   switch (item->type) {

=== modified file 'sql/backup/restore_info.h'
--- a/sql/backup/restore_info.h	2009-11-11 16:51:13 +0000
+++ b/sql/backup/restore_info.h	2009-11-11 21:29:15 +0000
@@ -46,8 +46,10 @@ public:
   Image_info::Table* add_table(Image_info::Db&, const ::String&,
                                backup::Snapshot_info&, ulong);
                                
+  bool check_restore_elevation(struct st_bstream_item_info *item);
   bool check_restore_privileges(struct st_bstream_item_info *item);
-  
+  bool elevated_restore() { return m_elevated_restore; }
+
 private:
 
   /*
@@ -74,13 +76,20 @@ private:
                                 bstream_blob create_stmt,
                                 bstream_blob other_meta_data);
   friend class Backup_restore_ctx;    // Needs access to the constructor.
+
+  bool m_elevated_restore; // Is restore elevation turned on?
+  bool m_has_super;        // Does user has SUPER_ACL privilege?
+  bool m_check_elevation;  // Are we are in check elevation phase?
 };
 
 
 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_elevated_restore(FALSE), m_check_elevation(FALSE)
+{
+  m_has_super= ((m_thd->security_ctx->master_access & SUPER_ACL) == SUPER_ACL);
+}
 
 
 inline
@@ -114,7 +123,7 @@ 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*
@@ -145,6 +154,98 @@ Restore_info::add_table(Image_info::Db &
   return t;
 }
 
+
+/**
+  Check restore elevation or database access privileges.
+  
+  This method checks to see if it is ok to perform restore elevation. It is
+  only permissible to initiate restore elevation if and only if the user
+  has the RESTORE_ACL privilege on all databases and has the global SUPER_ACL
+  privilege.
+  
+  If the user has RESTORE_ACL but not SUPER_ACL, the code defaults to checking
+  access to the database. Specifically, to see if the user has CREATE_ACL + 
+  DROP_ACL privileges on the database.
+  
+  This method is designed to be called multiple times during the catalog
+  build cycle where the list of databases is read from the stream prior
+  to reading the collections of database objects. Thus, this method is designed
+  to turn on elevation only once all databases have been added to the
+  catalog.
+  
+  When the first database is read, the code turns ON m_check_elevation to
+  signal begin the check elevation phase. It also indicates we are at
+  the state where all databases are being read from the backup image
+  stream. Once a different object type is encountered, the m_check_elevation
+  is turned OFF and a determination is made if it is safe to turn on 
+  elevation. This is determined by whether the user has the SUPER_ACL. This is
+  all that is needed for the check because at this point the code has
+  processed all databases and they have all been checked for RESTORE_ACL. 
+  If any database did not have RESTORE_ACL, an error was generated. Thus, the
+  only way to get to this point is if all databases have RESTORE_ACL.
+
+  @param[in] item     The database 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_elevation(struct st_bstream_item_info *item)
+{
+  /*
+    Only process privilege check for databases.
+  */
+  if (item->type == BSTREAM_IT_DB) 
+  {
+    backup::String item_name(item->name.begin, item->name.end);
+    const char *name_str= item_name.c_ptr_safe();
+
+    // If this is the first database checked, turn on elevation check phase.
+    if (!m_check_elevation)
+      m_check_elevation= TRUE;
+      
+    // If RESTORE_ACL check fails, generate error.
+    if (check_access(m_thd, RESTORE_ACL, name_str, 0, 1, 1, 0))
+    {
+      m_log.report_error(ER_RESTORE_ACCESS_DENIED_ERROR, name_str);
+      return TRUE;
+    }
+    // If user does not have super, check for CREATE + DROP 
+    if (!m_has_super)
+    {
+      if (check_access(m_thd, CREATE_ACL + DROP_ACL, name_str, 0, 1, 1, 0))
+      {
+        m_log.report_error(ER_RESTORE_ACCESS_OBJS_INCOMPLETE, name_str);
+        return TRUE;
+      }
+    }
+  }
+  /*
+    Once a different object is encountered, this indicates all databases have 
+    been read and we can determine if it is safe to elevate privileges.
+    
+    If m_check_elevation is OFF, this indicates no database has been read
+    from the backup image stream and any object prior to the list of
+    databases can be checked in the prechecking method if applicable
+    (e.g., tablespaces).
+  */
+  else if (m_check_elevation)
+  {
+    //  If user has super, elevate privileges.
+    if (m_has_super)
+    {
+      m_elevated_restore= TRUE;
+      m_thd->security_ctx->set_all_global_privileges();
+    }
+    m_check_elevation= FALSE;  // turn off elevation check.
+  }
+
+  return FALSE;    
+}
+
+
 /**
   Perform privilege checking for restore.
  
@@ -159,7 +260,6 @@ Restore_info::add_table(Image_info::Db &
   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)
@@ -191,21 +291,8 @@ Restore_info::check_restore_privileges(s
 
   DBUG_ASSERT(item);
   
-  /*
-    Check privileges for this database. User must have RESTORE
-    privilege in order to execute a restore.
-  */
   DEBUG_SYNC(thd, "before_restore_privileges");
   
-  if (item->type == BSTREAM_IT_DB)
-  {
-    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;
-    }
-  }
-
   /*
     Get the database for objects that have a database element.
   */
@@ -243,11 +330,6 @@ Restore_info::check_restore_privileges(s
       result= !(thd->security_ctx->master_access & 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:
     {

=== 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-11 21:29:15 +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-11 21:29:15 +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= (ulong)~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-11 21:29:15 +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-20091111212915-8ukov2veccafuior.bundle
Thread
bzr commit into mysql-6.0-backup branch (charles.bell:2889) Bug#44787Chuck Bell11 Nov
  • Re: bzr commit into mysql-6.0-backup branch (charles.bell:2889)Bug#44787Rafal Somla12 Nov