diff options
author | Spencer T Brody <spencer@10gen.com> | 2013-10-25 15:03:59 -0400 |
---|---|---|
committer | Spencer T Brody <spencer@10gen.com> | 2013-10-28 14:57:51 -0400 |
commit | 0e35f9154fe51586d4bbc30267772a664b8df907 (patch) | |
tree | ea957c71863f019d40933c3561e593aac67f24e0 | |
parent | 38b665b22722ab442a9c022b54558e3cd7a9b84f (diff) | |
download | mongo-0e35f9154fe51586d4bbc30267772a664b8df907.tar.gz |
SERVER-8213 Make copyDB and clone work with auth when using new-style users
-rw-r--r-- | jstests/auth/copyauth.js | 9 | ||||
-rw-r--r-- | jstests/clonecollection.js (renamed from jstests/clone/clonecollection.js) | 0 | ||||
-rw-r--r-- | jstests/server7428.js (renamed from jstests/slowNightly/server7428.js) | 0 | ||||
-rw-r--r-- | jstests/sharding/auth_copydb.js | 4 | ||||
-rw-r--r-- | src/mongo/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/auth/action_types.txt | 4 | ||||
-rw-r--r-- | src/mongo/db/auth/role_graph_builtin_roles.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/cloner.cpp | 59 | ||||
-rw-r--r-- | src/mongo/db/commands/copydb.h | 50 | ||||
-rw-r--r-- | src/mongo/db/commands/copydb_common.cpp | 100 | ||||
-rw-r--r-- | src/mongo/db/commands/rename_collection.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/commands/rename_collection.h | 8 | ||||
-rw-r--r-- | src/mongo/db/commands/rename_collection_common.cpp | 59 | ||||
-rw-r--r-- | src/mongo/s/commands_public.cpp | 25 |
14 files changed, 251 insertions, 82 deletions
diff --git a/jstests/auth/copyauth.js b/jstests/auth/copyauth.js index 6a46f42574b..2b344309a39 100644 --- a/jstests/auth/copyauth.js +++ b/jstests/auth/copyauth.js @@ -9,9 +9,12 @@ var baseName = "jstests_clone_copyauth"; var source = startMongod( "--auth", "--port", ports[ 0 ], "--dbpath", "/data/db/" + baseName + "_source", "--nohttpinterface", "--bind_ip", "127.0.0.1", "--smallfiles" ); var target = startMongod( "--port", ports[ 1 ], "--dbpath", "/data/db/" + baseName + "_target", "--nohttpinterface", "--bind_ip", "127.0.0.1", "--smallfiles" ); +source.getDB( "admin" ).addUser( "super", "super" ); +source.getDB( "admin" ).auth( "super", "super" ); source.getDB( baseName )[ baseName ].save( {i:1} ); source.getDB( baseName ).addUser( "foo", "bar" ); -source.getDB( "admin" ).addUser( "super", "super" ); +source.getDB( "admin" ).logout(); + assert.throws( function() { source.getDB( baseName )[ baseName ].findOne(); } ); assert.commandWorked(target.getDB(baseName).copyDatabase(baseName, @@ -61,6 +64,4 @@ assert.eq(1, target.getDB(baseName)[baseName].findOne().i); } -if (0) { // SERVER-8213 - runTest(); -}
\ No newline at end of file +runTest(); diff --git a/jstests/clone/clonecollection.js b/jstests/clonecollection.js index ea5f229085c..ea5f229085c 100644 --- a/jstests/clone/clonecollection.js +++ b/jstests/clonecollection.js diff --git a/jstests/slowNightly/server7428.js b/jstests/server7428.js index 1b28e3fc620..1b28e3fc620 100644 --- a/jstests/slowNightly/server7428.js +++ b/jstests/server7428.js diff --git a/jstests/sharding/auth_copydb.js b/jstests/sharding/auth_copydb.js index 23fea03bdec..bba901967e4 100644 --- a/jstests/sharding/auth_copydb.js +++ b/jstests/sharding/auth_copydb.js @@ -42,6 +42,4 @@ st.stop(); } -if (0) { // SERVER-8213 - runTest(); -}
\ No newline at end of file +runTest(); diff --git a/src/mongo/SConscript b/src/mongo/SConscript index 1503895bac3..fa9a7cb8e9d 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -328,6 +328,7 @@ env.StaticLibrary("coredb", [ "db/commands.cpp", "db/commands/authentication_commands.cpp", "db/commands/connection_status.cpp", + "db/commands/copydb_common.cpp", "db/commands/fail_point_cmd.cpp", "db/commands/find_and_modify_common.cpp", "db/commands/hashcmd.cpp", diff --git a/src/mongo/db/auth/action_types.txt b/src/mongo/db/auth/action_types.txt index 8a2896719cc..f6115dfa060 100644 --- a/src/mongo/db/auth/action_types.txt +++ b/src/mongo/db/auth/action_types.txt @@ -17,9 +17,6 @@ "changeOwnCustomData", "clean", "cleanupOrphaned", -"clone", -"cloneCollectionLocalSource", -"cloneCollectionTarget", "closeAllDatabases", "collMod", "collStats", @@ -27,7 +24,6 @@ "connPoolStats", "connPoolSync", "convertToCapped", -"copyDBTarget", "cpuProfiler", "createCollection", "createDatabase", # Not used for permissions checks, but to id the event in logs. diff --git a/src/mongo/db/auth/role_graph_builtin_roles.cpp b/src/mongo/db/auth/role_graph_builtin_roles.cpp index 1a6e5ba5b5b..b714fa7e9ec 100644 --- a/src/mongo/db/auth/role_graph_builtin_roles.cpp +++ b/src/mongo/db/auth/role_graph_builtin_roles.cpp @@ -93,7 +93,6 @@ namespace { MONGO_INITIALIZER(AuthorizationBuiltinRoles)(InitializerContext* context) { // Read role readRoleActions - << ActionType::cloneCollectionLocalSource << ActionType::collStats << ActionType::dbHash << ActionType::dbStats @@ -103,7 +102,6 @@ namespace { // Read-write role readWriteRoleActions += readRoleActions; readWriteRoleActions - << ActionType::cloneCollectionTarget << ActionType::convertToCapped // db admin gets this also << ActionType::createCollection // db admin gets this also << ActionType::dropCollection @@ -134,7 +132,6 @@ namespace { // DB admin role dbAdminRoleActions << ActionType::clean - << ActionType::cloneCollectionLocalSource << ActionType::collMod << ActionType::collStats // clusterMonitor gets this also << ActionType::compact @@ -226,9 +223,6 @@ namespace { dbOwnerRoleActions += readWriteRoleActions; dbOwnerRoleActions += dbAdminRoleActions; dbOwnerRoleActions += userAdminRoleActions; - dbOwnerRoleActions - << ActionType::clone - << ActionType::copyDBTarget; return Status::OK(); } diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp index 1e0b8c5a257..bd9ac2d66c2 100644 --- a/src/mongo/db/cloner.cpp +++ b/src/mongo/db/cloner.cpp @@ -33,8 +33,12 @@ #include "mongo/base/init.h" #include "mongo/base/status.h" #include "mongo/bson/util/builder.h" +#include "mongo/db/auth/action_set.h" +#include "mongo/db/auth/resource_pattern.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/cloner.h" #include "mongo/db/commands.h" +#include "mongo/db/commands/copydb.h" #include "mongo/db/commands/rename_collection.h" #include "mongo/db/db.h" #include "mongo/db/dbhelpers.h" @@ -318,7 +322,7 @@ namespace mongo { opts.fromDB = fromdb; opts.logForRepl = logForRepl; opts.slaveOk = slaveOk; - opts.useReplAuth = useReplAuth; + opts.useReplAuth = useReplAuth; // TODO(spencer): Remove this. SERVER-11423 opts.snapshot = snapshot; opts.mayYield = mayYield; opts.mayBeInterrupted = mayBeInterrupted; @@ -549,14 +553,17 @@ namespace mongo { help << "clone this database from an instance of the db on another host\n"; help << "{ clone : \"host13\" }"; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { - // Note: privileges required are currently only granted to old-style users for backwards - // compatibility, and to internal connections (used in movePrimary). + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { ActionSet actions; - actions.addAction(ActionType::clone); - out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions)); + actions.addAction(ActionType::insert); + actions.addAction(ActionType::createIndex); + if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + ResourcePattern::forDatabaseName(dbname), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + return Status::OK(); } CmdClone() : Command("clone") { } virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { @@ -605,17 +612,20 @@ namespace mongo { virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const { return parseNsFullyQualified(dbname, cmdObj); } - - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { - // Will fail if source instance has auth on. - NamespaceString ns(parseNs(dbname, cmdObj)); - uassert(16709, "bad 'cloneCollection' value '" + ns.ns() + "'", ns.isValid()); + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + std::string ns = parseNs(dbname, cmdObj); ActionSet actions; - actions.addAction(ActionType::cloneCollectionTarget); - out->push_back(Privilege(ResourcePattern::forExactNamespace(ns), actions)); + actions.addAction(ActionType::insert); + actions.addAction(ActionType::createIndex); // SERVER-11418 + + if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + ResourcePattern::forExactNamespace(NamespaceString(ns)), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + return Status::OK(); } virtual void help( stringstream &help ) const { help << "{ cloneCollection: <collection>, from: <host> [,query: <query_filter>] [,copyIndexes:<bool>] }" @@ -724,17 +734,10 @@ namespace mongo { return false; } virtual LockType locktype() const { return NONE; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { - // Note: privileges required are currently only granted to old-style users for backwards - // compatibility, since we can't properly handle auth checking for the read from the - // source DB. - ActionSet actions; - // TODO: Should this become remove, insert, dropIndex,createIndex, etc., on "todb"? - actions.addAction(ActionType::copyDBTarget); - out->push_back(Privilege(ResourcePattern::forDatabaseName(cmdObj["todb"].str()), - actions)); + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + return copydb::checkAuthForCopydbCommand(client, dbname, cmdObj); } virtual void help( stringstream &help ) const { help << "copy a database from another host to this host\n"; diff --git a/src/mongo/db/commands/copydb.h b/src/mongo/db/commands/copydb.h new file mode 100644 index 00000000000..f7b2adfbe6d --- /dev/null +++ b/src/mongo/db/commands/copydb.h @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2013 10gen Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include <string> +#include <vector> + +#include "mongo/db/auth/privilege.h" +#include "mongo/db/jsobj.h" + +namespace mongo { + + class ClientBasic; + +namespace copydb { + + Status checkAuthForCopydbCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj); + +} // namespace copydb +} // namespace mongo + + diff --git a/src/mongo/db/commands/copydb_common.cpp b/src/mongo/db/commands/copydb_common.cpp new file mode 100644 index 00000000000..5cebb8db021 --- /dev/null +++ b/src/mongo/db/commands/copydb_common.cpp @@ -0,0 +1,100 @@ +/** +* Copyright (C) 2013 10gen Inc. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License, version 3, +* as published by the Free Software Foundation. +* +* 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 Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* As a special exception, the copyright holders give permission to link the +* code of portions of this program with the OpenSSL library under certain +* conditions as described in each individual source file and distribute +* linked combinations including the program with the OpenSSL library. You +* must comply with the GNU Affero General Public License in all respects for +* all of the code used other than as permitted herein. If you modify file(s) +* with this exception, you may extend this exception to your version of the +* file(s), but you are not obligated to do so. If you do not wish to do so, +* delete this exception statement from your version. If you delete this +* exception statement from all source files in the program, then also delete +* it in the license file. +*/ + +#include "mongo/db/commands/copydb.h" + +#include <string> +#include <vector> + +#include "mongo/db/auth/action_set.h" +#include "mongo/db/auth/action_type.h" +#include "mongo/db/auth/authorization_session.h" +#include "mongo/db/auth/privilege.h" +#include "mongo/db/client_basic.h" +#include "mongo/db/jsobj.h" +#include "mongo/db/namespace_string.h" + +namespace mongo { +namespace copydb { + + Status checkAuthForCopydbCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + bool fromSelf = StringData(cmdObj.getStringField("fromhost")).empty(); + StringData fromdb = cmdObj.getStringField("fromdb"); + StringData todb = cmdObj.getStringField("todb"); + + // get system collections + std::vector<std::string> legalClientSystemCollections; + legalClientSystemCollections.push_back("system.js"); + if (fromdb == "admin") { + legalClientSystemCollections.push_back("system.users"); + legalClientSystemCollections.push_back("system.roles"); + legalClientSystemCollections.push_back("system.version"); + } else if (fromdb == "local") { // TODO(spencer): shouldn't be possible. See SERVER-11383 + legalClientSystemCollections.push_back("system.replset"); + } + + // Check authorization on destination db + ActionSet actions; + actions.addAction(ActionType::insert); + actions.addAction(ActionType::createIndex); + if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + ResourcePattern::forDatabaseName(todb), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + + actions.removeAllActions(); + actions.addAction(ActionType::insert); + for (size_t i = 0; i < legalClientSystemCollections.size(); ++i) { + if (!client->getAuthorizationSession()->isAuthorizedForActionsOnNamespace( + NamespaceString(todb, legalClientSystemCollections[i]), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + } + + if (fromSelf) { + // If copying from self, also require privileges on source db + actions.removeAllActions(); + actions.addAction(ActionType::find); + if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + ResourcePattern::forDatabaseName(fromdb), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + for (size_t i = 0; i < legalClientSystemCollections.size(); ++i) { + if (!client->getAuthorizationSession()->isAuthorizedForActionsOnNamespace( + NamespaceString(fromdb, legalClientSystemCollections[i]), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + } + } + return Status::OK(); + } + +} // namespace copydb +} // namespace mongo diff --git a/src/mongo/db/commands/rename_collection.cpp b/src/mongo/db/commands/rename_collection.cpp index a81d02cb148..39fb0d29a1c 100644 --- a/src/mongo/db/commands/rename_collection.cpp +++ b/src/mongo/db/commands/rename_collection.cpp @@ -55,10 +55,10 @@ namespace mongo { virtual bool logTheOp() { return true; // can't log steps when doing fast rename within a db, so always log the op rather than individual steps comprising it. } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { - rename_collection::addPrivilegesRequiredForRenameCollection(cmdObj, out); + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + return rename_collection::checkAuthForRenameCollectionCommand(client, dbname, cmdObj); } virtual void help( stringstream &help ) const { help << " example: { renameCollection: foo.a, to: bar.b }"; diff --git a/src/mongo/db/commands/rename_collection.h b/src/mongo/db/commands/rename_collection.h index f58376fc6c5..f8651bccd4c 100644 --- a/src/mongo/db/commands/rename_collection.h +++ b/src/mongo/db/commands/rename_collection.h @@ -35,10 +35,14 @@ #include "mongo/db/jsobj.h" namespace mongo { + + class ClientBasic; + namespace rename_collection { - void addPrivilegesRequiredForRenameCollection(const BSONObj& cmdObj, - std::vector<Privilege>* out); + Status checkAuthForRenameCollectionCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj); } // namespace rename_collection } // namespace mongo diff --git a/src/mongo/db/commands/rename_collection_common.cpp b/src/mongo/db/commands/rename_collection_common.cpp index 33931b19547..fca7c97ba7f 100644 --- a/src/mongo/db/commands/rename_collection_common.cpp +++ b/src/mongo/db/commands/rename_collection_common.cpp @@ -33,35 +33,60 @@ #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" +#include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/privilege.h" +#include "mongo/db/client_basic.h" #include "mongo/db/jsobj.h" #include "mongo/db/namespace_string.h" namespace mongo { namespace rename_collection { - void addPrivilegesRequiredForRenameCollection(const BSONObj& cmdObj, - std::vector<Privilege>* out) { + Status checkAuthForRenameCollectionCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { NamespaceString sourceNS = NamespaceString(cmdObj.getStringField("renameCollection")); NamespaceString targetNS = NamespaceString(cmdObj.getStringField("to")); - uassert(17140, "Invalid source namespace " + sourceNS.ns(), sourceNS.isValid()); - uassert(17141, "Invalid target namespace " + targetNS.ns(), targetNS.isValid()); - ActionSet sourceActions; - ActionSet targetActions; + bool dropTarget = cmdObj["dropTarget"].trueValue(); - if (sourceNS.db() == targetNS.db()) { - sourceActions.addAction(ActionType::renameCollectionSameDB); - targetActions.addAction(ActionType::renameCollectionSameDB); - } else { - sourceActions.addAction(ActionType::cloneCollectionLocalSource); - sourceActions.addAction(ActionType::dropCollection); - targetActions.addAction(ActionType::createCollection); - targetActions.addAction(ActionType::cloneCollectionTarget); - targetActions.addAction(ActionType::createIndex); + if (sourceNS.db() == targetNS.db() && !sourceNS.isSystem() && !targetNS.isSystem()) { + bool authed1 = client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + ResourcePattern::forDatabaseName(sourceNS.db()), + ActionType::renameCollectionSameDB); + + bool authed2 = true; + if (dropTarget) { + authed2 = client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + ResourcePattern::forExactNamespace(targetNS), ActionType::dropCollection); + } + + if (authed1 && authed2) { + return Status::OK(); + } + } + + // Check privileges on source collection + ActionSet actions; + actions.addAction(ActionType::find); + actions.addAction(ActionType::dropCollection); + if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + ResourcePattern::forExactNamespace(sourceNS), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + + // Check privileges on dest collection + actions.removeAllActions(); + actions.addAction(ActionType::insert); + actions.addAction(ActionType::createIndex); + if (dropTarget) { + actions.addAction(ActionType::dropCollection); + } + if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + ResourcePattern::forExactNamespace(targetNS), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); } - out->push_back(Privilege(ResourcePattern::forExactNamespace(sourceNS), sourceActions)); - out->push_back(Privilege(ResourcePattern::forExactNamespace(targetNS), targetActions)); + return Status::OK(); } } // namespace rename_collection diff --git a/src/mongo/s/commands_public.cpp b/src/mongo/s/commands_public.cpp index ee0473c01e2..81ec9bc4f3f 100644 --- a/src/mongo/s/commands_public.cpp +++ b/src/mongo/s/commands_public.cpp @@ -39,6 +39,7 @@ #include "mongo/db/auth/authorization_manager_global.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/privilege.h" +#include "mongo/db/commands/copydb.h" #include "mongo/db/commands/find_and_modify.h" #include "mongo/db/commands/mr.h" #include "mongo/db/commands/rename_collection.h" @@ -510,10 +511,12 @@ namespace mongo { class RenameCollectionCmd : public PublicGridCommand { public: RenameCollectionCmd() : PublicGridCommand( "renameCollection" ) {} - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { - rename_collection::addPrivilegesRequiredForRenameCollection(cmdObj, out); + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + return rename_collection::checkAuthForRenameCollectionCommand(client, + dbname, + cmdObj); } bool run(const string& dbName, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { string fullnsFrom = cmdObj.firstElement().valuestrsafe(); @@ -543,16 +546,10 @@ namespace mongo { virtual bool adminOnly() const { return true; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { - // Note: privileges required are currently only granted to old-style users for - // backwards compatibility, since we can't properly handle auth checking for the - // read from the source DB. - ActionSet actions; - actions.addAction(ActionType::copyDBTarget); - out->push_back(Privilege(ResourcePattern::forDatabaseName(cmdObj["todb"].str()), - actions)); + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + return copydb::checkAuthForCopydbCommand(client, dbname, cmdObj); } bool run(const string& dbName, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { string todb = cmdObj.getStringField("todb"); |