#At file:///home/cbell/source/bzr/backport-MS04/ based on revid:charles.bell@stripped
3022 Chuck Bell 2009-12-21
BUG#44787 : Backup: Check privileges before executing BACKUP/RESTORE
WL#5172 : MySQL Backup elevation options
There are three problems that have been identified for this bug.
1) Restore can fail in the middle if the user does not have
sufficient privileges to create and populate all of the
objects. This patch implements a privilege precheck step to check
all objects for proper access. If any object fails the
privilege check, restore halts with an error. 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)
2) The backup system must be changed to permit the
elevation of privileges for backup if the user has the
BACKUP_ACL privilege and elevation of privileges for restore
if the user has the RESTORE_ACL on all databases and the
global SUPER_ACL privilege. This patch implements the privilege
elevation change for backup as well as privilege elevation for
restore. The restore will fall back to object-level privilege
checking if the conditions for restore are not met.
3) The backup system must be changed to allow users to adjust the
privilege behavior of MySQL Backup by allowing them
to turn off backup elevation, restore elevation, and restore
prechecking using startup options. It shall also permit the user
to turn restore prechecking on or off via a variable. This patch
implements the following:
backup_elevation - startup option, global read only variable
ON = turn on backup elevation
OFF = turn off backup elevation
Note: Default is ON
restore_elevation - startup option, global read only variable
ON = turn on restore elevation
OFF = turn off restore elevation
Note: Default is ON
restore_precheck - startup option, global and session variable
ON = turn on restore precheck
OFF = turn off restore precheck
Note: Default is ON
original changeset: 2899 (from mysql-6.0-backup)
@ sql/backup/restore_info.cc
New code file.
Implements prechecking method.
added:
sql/backup/restore_info.cc
=== added file 'sql/backup/restore_info.cc'
--- a/sql/backup/restore_info.cc 1970-01-01 00:00:00 +0000
+++ b/sql/backup/restore_info.cc 2009-12-21 19:30:16 +0000
@@ -0,0 +1,226 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/**
+ @file
+
+ Implementation of @c Restore_info class methods.
+
+ Method @c check_restore_privileges performs privilege checking for restore.
+*/
+
+#include <backup/restore_info.h>
+
+
+/**
+ 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 each database listed in
+ the backup image. If the user does not have RESTORE for any database in the
+ list, 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)
+
+ @note Object-level prechecking is skipped if restore_prechecking is
+ turned off or it has been determined it is safe to elevate restore. The
+ actual elevation of restore occurs before metadata creation.
+
+ @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.
+*/
+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_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();
+
+ 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;
+ }
+ }
+
+ /*
+ Since restore_elevation is a global read-only variable, we must turn
+ result of elevation check off via debug to allow debug error insertion
+ to work below.
+ */
+ DBUG_EXECUTE_IF("ER_RESTORE_DB_ERROR", m_restore_elevation= FALSE;);
+
+ /*
+ If prechecking is turned off or restore elevation is turned on,
+ skip prechecking.
+ */
+ if (!m_thd->variables.restore_precheck || m_restore_elevation)
+ return FALSE;
+
+ /*
+ Get the database for objects that have a database element.
+ */
+ switch (item->type)
+ {
+ case BSTREAM_IT_TABLE:
+ case BSTREAM_IT_VIEW:
+ case BSTREAM_IT_SPROC:
+ case BSTREAM_IT_SFUNC:
+ case BSTREAM_IT_EVENT:
+ case BSTREAM_IT_TRIGGER:
+ case BSTREAM_IT_PRIVILEGE:
+ {
+ db_item= (st_bstream_dbitem_info*) item;
+
+ db= get_db(db_item->db->base.pos);
+ DBUG_EXECUTE_IF("ER_RESTORE_DB_ERROR", db= NULL;);
+ if (!db)
+ {
+ m_log.report_error(ER_RESTORE_DB_ERROR, name_str);
+ return TRUE;
+ }
+ break;
+ }
+ default:
+ break;
+ } // switch (item->type)
+
+ /*
+ Check privileges for each object based on type of object.
+ */
+ switch (item->type)
+ {
+ case BSTREAM_IT_TABLESPACE:
+ {
+ 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_SPROC:
+ case BSTREAM_IT_SFUNC:
+ {
+ result= check_access(thd, CREATE_PROC_ACL, db->name().ptr(), 0, 1, 1, 0);
+ break;
+ }
+ case BSTREAM_IT_EVENT:
+ {
+ result= check_access(thd, EVENT_ACL, db->name().ptr(), 0, 1, 1, 0);
+ break;
+ }
+ case BSTREAM_IT_TRIGGER:
+ {
+ /*
+ 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:
+ {
+ 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;
+}
+
Attachment: [text/bzr-bundle] bzr/charles.bell@sun.com-20091221193016-wujzz7a26av7isdj.bundle
Thread |
---|
• bzr commit into mysql-5.6-next-mr branch (charles.bell:3022) Bug#44787WL#5172 | Chuck Bell | 21 Dec |