bool CmdLogout::run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthenticationInfo *ai = ClientInfo::get()->getAuthenticationInfo(); AuthorizationManager* authManager = ClientInfo::get()->getAuthorizationManager(); ai->logout(dbname); authManager->logoutDatabase(dbname); return true; }
bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthorizationManager* authzManager = getGlobalAuthorizationManager(); AuthzDocumentsUpdateGuard updateGuard(authzManager); if (!updateGuard.tryLock("Create role")) { addStatus(Status(ErrorCodes::LockBusy, "Could not lock auth data update lock."), result); return false; } BSONObj roleObj; BSONObj writeConcern; Status status = auth::parseAndValidateCreateRoleCommand(cmdObj, dbname, authzManager, &roleObj, &writeConcern); if (!status.isOK()) { addStatus(status, result); return false; } status = authzManager->insertRoleDocument(roleObj, writeConcern); if (!status.isOK()) { addStatus(status, result); return false; } return true; }
bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthorizationManager* authzManager = getGlobalAuthorizationManager(); AuthzDocumentsUpdateGuard updateGuard(authzManager); if (!updateGuard.tryLock("Grant role delegation to user")) { addStatus(Status(ErrorCodes::LockBusy, "Could not lock auth data update lock."), result); return false; } UserName userName; std::vector<RoleName> roles; BSONObj writeConcern; Status status = auth::parseUserRoleManipulationCommand(cmdObj, "grantDelegateRolesToUser", dbname, authzManager, &userName, &roles, &writeConcern); if (!status.isOK()) { addStatus(status, result); return false; } User::RoleDataMap userRoles; status = getCurrentUserRoles(authzManager, userName, &userRoles); if (!status.isOK()) { addStatus(status, result); return false; } for (vector<RoleName>::iterator it = roles.begin(); it != roles.end(); ++it) { RoleName& roleName = *it; User::RoleData& role = userRoles[roleName]; if (role.name.empty()) { role.name = roleName; } role.canDelegate = true; } BSONArray newRolesBSONArray = rolesToBSONArray(userRoles); status = authzManager->updatePrivilegeDocument( userName, BSON("$set" << BSON("roles" << newRolesBSONArray)), writeConcern); // Must invalidate even on bad status - what if the write succeeded but the GLE failed? authzManager->invalidateUserByName(userName); if (!status.isOK()) { addStatus(status, result); return false; } return true; }
void SASLServerMechanismRegistry::advertiseMechanismNamesForUser(OperationContext* opCtx, const BSONObj& isMasterCmd, BSONObjBuilder* builder) { BSONElement saslSupportedMechs = isMasterCmd["saslSupportedMechs"]; if (saslSupportedMechs.type() == BSONType::String) { UserName userName = uassertStatusOK(UserName::parse(saslSupportedMechs.String())); // Authenticating the __system@local user to the admin database on mongos is required // by the auth passthrough test suite. if (getTestCommandsEnabled() && userName.getUser() == internalSecurity.user->getName().getUser() && userName.getDB() == "admin") { userName = internalSecurity.user->getName(); } AuthorizationManager* authManager = AuthorizationManager::get(opCtx->getServiceContext()); UserHandle user; const auto swUser = authManager->acquireUser(opCtx, userName); if (!swUser.isOK()) { auto& status = swUser.getStatus(); if (status.code() == ErrorCodes::UserNotFound) { log() << "Supported SASL mechanisms requested for unknown user '" << userName << "'"; return; } uassertStatusOK(status); } user = std::move(swUser.getValue()); BSONArrayBuilder mechanismsBuilder; const auto& mechList = _getMapRef(userName.getDB()); for (const auto& factoryIt : mechList) { SecurityPropertySet properties = factoryIt->properties(); if (!properties.hasAllProperties(SecurityPropertySet{SecurityProperty::kNoPlainText, SecurityProperty::kMutualAuth}) && userName.getDB() != "$external") { continue; } auto mechanismEnabled = _mechanismSupportedByConfig(factoryIt->mechanismName()); if (!mechanismEnabled && userName == internalSecurity.user->getName()) { mechanismEnabled = factoryIt->isInternalAuthMech(); } if (mechanismEnabled && factoryIt->canMakeMechanismForUser(user.get())) { mechanismsBuilder << factoryIt->mechanismName(); } } builder->appendArray("saslSupportedMechs", mechanismsBuilder.arr()); } }
bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result) { AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); authzManager->invalidateUserCache(); return true; }
void _authorizePrincipal(const std::string& principalName, bool readOnly) { Principal* principal = new Principal(PrincipalName(principalName, "local")); ActionSet actions = AuthorizationManager::getActionsForOldStyleUser( "admin", readOnly); AuthorizationManager* authorizationManager = cc().getAuthorizationManager(); authorizationManager->addAuthorizedPrincipal(principal); Status status = authorizationManager->acquirePrivilege( Privilege(PrivilegeSet::WILDCARD_RESOURCE, actions), principal->getName()); verify (status == Status::OK()); }
Status authenticateAndAuthorizePrincipal(const std::string& principalName, const std::string& dbname, const BSONObj& userObj) { AuthorizationManager* authorizationManager = ClientBasic::getCurrent()->getAuthorizationManager(); Principal* principal = new Principal(principalName, dbname); authorizationManager->addAuthorizedPrincipal(principal); return authorizationManager->acquirePrivilegesFromPrivilegeDocument(dbname, principal, userObj); }
void ClientInfo::_setupAuth() { std::string adminNs = "admin"; DBConfigPtr config = grid.getDBConfig(adminNs); Shard shard = config->getShard(adminNs); ShardConnection conn(shard, adminNs); AuthorizationManager* authManager = new AuthorizationManager(new AuthExternalStateImpl()); Status status = authManager->initialize(conn.get()); massert(16479, mongoutils::str::stream() << "Error initializing AuthorizationManager: " << status.reason(), status == Status::OK()); setAuthorizationManager(authManager); }
bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthorizationManager* authzManager = getGlobalAuthorizationManager(); AuthzDocumentsUpdateGuard updateGuard(authzManager); if (!updateGuard.tryLock("Remove user")) { addStatus(Status(ErrorCodes::LockBusy, "Could not lock auth data update lock."), result); return false; } UserName userName; BSONObj writeConcern; Status status = auth::parseAndValidateRemoveUserCommand(cmdObj, dbname, &userName, &writeConcern); if (!status.isOK()) { addStatus(status, result); return false; } int numUpdated; status = authzManager->removePrivilegeDocuments( BSON(AuthorizationManager::USER_NAME_FIELD_NAME << userName.getUser() << AuthorizationManager::USER_SOURCE_FIELD_NAME << userName.getDB()), writeConcern, &numUpdated); // Must invalidate even on bad status - what if the write succeeded but the GLE failed? authzManager->invalidateUserByName(userName); if (!status.isOK()) { addStatus(status, result); return false; } if (numUpdated == 0) { addStatus(Status(ErrorCodes::UserNotFound, mongoutils::str::stream() << "User '" << userName.getFullName() << "' not found"), result); return false; } return true; }
bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result) { const bool ok = grid.catalogManager(txn)->runUserManagementWriteCommand( txn, this->name, dbname, cmdObj, &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); authzManager->invalidateUserCache(); return ok; }
bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result) { auth::CreateOrUpdateUserArgs args; Status status = auth::parseCreateOrUpdateUserCommands(cmdObj, this->name, dbname, &args); if (!status.isOK()) { return appendCommandStatus(result, status); } const bool ok = grid.catalogManager(txn)->runUserManagementWriteCommand( txn, this->name, dbname, cmdObj, &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); authzManager->invalidateUserByName(args.userName); return ok; }
void ClientInfo::_setupAuth() { std::string adminNs = "admin"; DBConfigPtr config = grid.getDBConfig(adminNs); Shard shard = config->getShard(adminNs); scoped_ptr<ScopedDbConnection> connPtr( ScopedDbConnection::getInternalScopedDbConnection(shard.getConnString(), 30.0)); ScopedDbConnection& conn = *connPtr; // // Note: The connection mechanism here is *not* ideal, and should not be used elsewhere. // It is safe in this particular case because the admin database is always on the config // server and does not move. // AuthorizationManager* authManager = new AuthorizationManager(new AuthExternalStateImpl()); Status status = authManager->initialize(conn.get()); massert(16479, mongoutils::str::stream() << "Error initializing AuthorizationManager: " << status.reason(), status == Status::OK()); setAuthorizationManager(authManager); }
bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result) { UserName userName; BSONObj unusedWriteConcern; Status status = auth::parseAndValidateDropUserCommand(cmdObj, dbname, &userName, &unusedWriteConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } const bool ok = grid.catalogManager(txn)->runUserManagementWriteCommand( txn, this->name, dbname, cmdObj, &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); authzManager->invalidateUserByName(userName); return ok; }
bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { bool anyDB = false; BSONElement usersFilter; Status status = auth::parseAndValidateInfoCommands(cmdObj, "usersInfo", dbname, &anyDB, &usersFilter); if (!status.isOK()) { addStatus(status, result); return false; } BSONObjBuilder queryBuilder; queryBuilder.appendAs(usersFilter, "name"); if (!anyDB) { queryBuilder.append("source", dbname); } BSONArrayBuilder usersArrayBuilder; BSONArrayBuilder& (BSONArrayBuilder::* appendBSONObj) (const BSONObj&) = &BSONArrayBuilder::append<BSONObj>; const boost::function<void(const BSONObj&)> function = boost::bind(appendBSONObj, &usersArrayBuilder, _1); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); authzManager->queryAuthzDocument(NamespaceString("admin.system.users"), queryBuilder.done(), function); result.append("users", usersArrayBuilder.arr()); return true; }
bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthorizationManager* authzManager = getGlobalAuthorizationManager(); AuthzDocumentsUpdateGuard updateGuard(authzManager); if (!updateGuard.tryLock("Remove all users from database")) { addStatus(Status(ErrorCodes::LockBusy, "Could not lock auth data update lock."), result); return false; } BSONObj writeConcern; Status status = auth::parseAndValidateRemoveUsersFromDatabaseCommand(cmdObj, dbname, &writeConcern); if (!status.isOK()) { addStatus(status, result); return false; } int numRemoved; status = authzManager->removePrivilegeDocuments( BSON(AuthorizationManager::USER_SOURCE_FIELD_NAME << dbname), writeConcern, &numRemoved); // Must invalidate even on bad status - what if the write succeeded but the GLE failed? authzManager->invalidateUsersFromDB(dbname); if (!status.isOK()) { addStatus(status, result); return false; } result.append("n", numRemoved); return true; }
bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthorizationManager* authzManager = getGlobalAuthorizationManager(); AuthzDocumentsUpdateGuard updateGuard(authzManager); if (!updateGuard.tryLock("Update user")) { addStatus(Status(ErrorCodes::LockBusy, "Could not lock auth data update lock."), result); return false; } BSONObj updateObj; UserName userName; BSONObj writeConcern; Status status = auth::parseAndValidateUpdateUserCommand(cmdObj, dbname, authzManager, &updateObj, &userName, &writeConcern); if (!status.isOK()) { addStatus(status, result); return false; } status = authzManager->updatePrivilegeDocument(userName, updateObj, writeConcern); // Must invalidate even on bad status - what if the write succeeded but the GLE failed? authzManager->invalidateUserByName(userName); if (!status.isOK()) { addStatus(status, result); return false; } return true; }
bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result) { string userNameString; vector<RoleName> unusedRoles; BSONObj unusedWriteConcern; Status status = auth::parseRolePossessionManipulationCommands( cmdObj, this->name, dbname, &userNameString, &unusedRoles, &unusedWriteConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } const bool ok = grid.catalogManager(txn)->runUserManagementWriteCommand( txn, this->name, dbname, cmdObj, &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); authzManager->invalidateUserByName(UserName(userNameString, dbname)); return ok; }
StatusWith<std::tuple<bool, std::string>> SASLPlainServerMechanism::stepImpl( OperationContext* opCtx, StringData inputData) { if (_authenticationDatabase == "$external") { return Status(ErrorCodes::AuthenticationFailed, "PLAIN mechanism must be used with internal users"); } AuthorizationManager* authManager = AuthorizationManager::get(opCtx->getServiceContext()); // Expecting user input on the form: [authz-id]\0authn-id\0pwd std::string input = inputData.toString(); SecureAllocatorAuthDomain::SecureString pwd = ""; try { size_t firstNull = inputData.find('\0'); if (firstNull == std::string::npos) { return Status( ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, missing first NULL delimiter"); } size_t secondNull = inputData.find('\0', firstNull + 1); if (secondNull == std::string::npos) { return Status( ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, missing second NULL delimiter"); } std::string authorizationIdentity = input.substr(0, firstNull); ServerMechanismBase::_principalName = input.substr(firstNull + 1, (secondNull - firstNull) - 1); if (ServerMechanismBase::_principalName.empty()) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, empty username"); } else if (!authorizationIdentity.empty() && authorizationIdentity != ServerMechanismBase::_principalName) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "SASL authorization identity must match authentication identity"); } pwd = SecureAllocatorAuthDomain::SecureString(input.substr(secondNull + 1).c_str()); if (pwd->empty()) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, empty password"); } } catch (std::out_of_range&) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message"); } // The authentication database is also the source database for the user. auto swUser = authManager->acquireUser( opCtx, UserName(ServerMechanismBase::_principalName, _authenticationDatabase)); if (!swUser.isOK()) { return swUser.getStatus(); } auto userObj = std::move(swUser.getValue()); const auto creds = userObj->getCredentials(); const auto sha256Status = trySCRAM<SHA256Block>(creds, pwd->c_str()); if (!sha256Status.isOK()) { return sha256Status.getStatus(); } if (sha256Status.getValue()) { return std::make_tuple(true, std::string()); } const auto authDigest = createPasswordDigest(ServerMechanismBase::_principalName, pwd->c_str()); const auto sha1Status = trySCRAM<SHA1Block>(creds, authDigest); if (!sha1Status.isOK()) { return sha1Status.getStatus(); } if (sha1Status.getValue()) { return std::make_tuple(true, std::string()); } return Status(ErrorCodes::AuthenticationFailed, str::stream() << "No credentials available."); return std::make_tuple(true, std::string()); }
ExitCode _initAndListen(int listenPort) { Client::initThread("initandlisten"); _initWireSpec(); auto globalServiceContext = getGlobalServiceContext(); globalServiceContext->setFastClockSource(FastClockSourceFactory::create(Milliseconds(10))); globalServiceContext->setOpObserver(stdx::make_unique<OpObserver>()); DBDirectClientFactory::get(globalServiceContext) .registerImplementation([](OperationContext* txn) { return std::unique_ptr<DBClientBase>(new DBDirectClient(txn)); }); const repl::ReplSettings& replSettings = repl::getGlobalReplicationCoordinator()->getSettings(); { ProcessId pid = ProcessId::getCurrent(); LogstreamBuilder l = log(LogComponent::kControl); l << "MongoDB starting : pid=" << pid << " port=" << serverGlobalParams.port << " dbpath=" << storageGlobalParams.dbpath; if (replSettings.isMaster()) l << " master=" << replSettings.isMaster(); if (replSettings.isSlave()) l << " slave=" << (int)replSettings.isSlave(); const bool is32bit = sizeof(int*) == 4; l << (is32bit ? " 32" : " 64") << "-bit host=" << getHostNameCached() << endl; } DEV log(LogComponent::kControl) << "DEBUG build (which is slower)" << endl; #if defined(_WIN32) VersionInfoInterface::instance().logTargetMinOS(); #endif logProcessDetails(); checked_cast<ServiceContextMongoD*>(getGlobalServiceContext())->createLockFile(); transport::TransportLayerLegacy::Options options; options.port = listenPort; options.ipList = serverGlobalParams.bind_ip; auto sep = stdx::make_unique<ServiceEntryPointMongod>(getGlobalServiceContext()->getTransportLayer()); auto sepPtr = sep.get(); getGlobalServiceContext()->setServiceEntryPoint(std::move(sep)); // Create, start, and attach the TL auto transportLayer = stdx::make_unique<transport::TransportLayerLegacy>(options, sepPtr); auto res = transportLayer->setup(); if (!res.isOK()) { error() << "Failed to set up listener: " << res; return EXIT_NET_ERROR; } std::shared_ptr<DbWebServer> dbWebServer; if (serverGlobalParams.isHttpInterfaceEnabled) { dbWebServer.reset(new DbWebServer(serverGlobalParams.bind_ip, serverGlobalParams.port + 1000, getGlobalServiceContext(), new RestAdminAccess())); if (!dbWebServer->setupSockets()) { error() << "Failed to set up sockets for HTTP interface during startup."; return EXIT_NET_ERROR; } } getGlobalServiceContext()->initializeGlobalStorageEngine(); #ifdef MONGO_CONFIG_WIREDTIGER_ENABLED if (WiredTigerCustomizationHooks::get(getGlobalServiceContext())->restartRequired()) { exitCleanly(EXIT_CLEAN); } #endif // Warn if we detect configurations for multiple registered storage engines in // the same configuration file/environment. if (serverGlobalParams.parsedOpts.hasField("storage")) { BSONElement storageElement = serverGlobalParams.parsedOpts.getField("storage"); invariant(storageElement.isABSONObj()); BSONObj storageParamsObj = storageElement.Obj(); BSONObjIterator i = storageParamsObj.begin(); while (i.more()) { BSONElement e = i.next(); // Ignore if field name under "storage" matches current storage engine. if (storageGlobalParams.engine == e.fieldName()) { continue; } // Warn if field name matches non-active registered storage engine. if (getGlobalServiceContext()->isRegisteredStorageEngine(e.fieldName())) { warning() << "Detected configuration for non-active storage engine " << e.fieldName() << " when current storage engine is " << storageGlobalParams.engine; } } } if (!getGlobalServiceContext()->getGlobalStorageEngine()->getSnapshotManager()) { if (moe::startupOptionsParsed.count("replication.enableMajorityReadConcern") && moe::startupOptionsParsed["replication.enableMajorityReadConcern"].as<bool>()) { // Note: we are intentionally only erroring if the user explicitly requested that we // enable majority read concern. We do not error if the they are implicitly enabled for // CSRS because a required step in the upgrade procedure can involve an mmapv1 node in // the CSRS in the REMOVED state. This is handled by the TopologyCoordinator. invariant(replSettings.isMajorityReadConcernEnabled()); severe() << "Majority read concern requires a storage engine that supports" << " snapshots, such as wiredTiger. " << storageGlobalParams.engine << " does not support snapshots."; exitCleanly(EXIT_BADOPTIONS); } } logMongodStartupWarnings(storageGlobalParams, serverGlobalParams); { stringstream ss; ss << endl; ss << "*********************************************************************" << endl; ss << " ERROR: dbpath (" << storageGlobalParams.dbpath << ") does not exist." << endl; ss << " Create this directory or give existing directory in --dbpath." << endl; ss << " See http://dochub.mongodb.org/core/startingandstoppingmongo" << endl; ss << "*********************************************************************" << endl; uassert(10296, ss.str().c_str(), boost::filesystem::exists(storageGlobalParams.dbpath)); } { stringstream ss; ss << "repairpath (" << storageGlobalParams.repairpath << ") does not exist"; uassert(12590, ss.str().c_str(), boost::filesystem::exists(storageGlobalParams.repairpath)); } // TODO: This should go into a MONGO_INITIALIZER once we have figured out the correct // dependencies. if (snmpInit) { snmpInit(); } if (!storageGlobalParams.readOnly) { boost::filesystem::remove_all(storageGlobalParams.dbpath + "/_tmp/"); } if (mmapv1GlobalOptions.journalOptions & MMAPV1Options::JournalRecoverOnly) return EXIT_NET_ERROR; if (mongodGlobalParams.scriptingEnabled) { ScriptEngine::setup(); } auto startupOpCtx = getGlobalServiceContext()->makeOperationContext(&cc()); repairDatabasesAndCheckVersion(startupOpCtx.get()); if (storageGlobalParams.upgrade) { log() << "finished checking dbs"; exitCleanly(EXIT_CLEAN); } uassertStatusOK(getGlobalAuthorizationManager()->initialize(startupOpCtx.get())); /* this is for security on certain platforms (nonce generation) */ srand((unsigned)(curTimeMicros64() ^ startupSrandTimer.micros())); // The snapshot thread provides historical collection level and lock statistics for use // by the web interface. Only needed when HTTP is enabled. if (serverGlobalParams.isHttpInterfaceEnabled) { statsSnapshotThread.go(); invariant(dbWebServer); stdx::thread web(stdx::bind(&webServerListenThread, dbWebServer)); web.detach(); } #ifndef _WIN32 mongo::signalForkSuccess(); #endif AuthorizationManager* globalAuthzManager = getGlobalAuthorizationManager(); if (globalAuthzManager->shouldValidateAuthSchemaOnStartup()) { Status status = authindex::verifySystemIndexes(startupOpCtx.get()); if (!status.isOK()) { log() << redact(status); exitCleanly(EXIT_NEED_UPGRADE); } // SERVER-14090: Verify that auth schema version is schemaVersion26Final. int foundSchemaVersion; status = globalAuthzManager->getAuthorizationVersion(startupOpCtx.get(), &foundSchemaVersion); if (!status.isOK()) { log() << "Auth schema version is incompatible: " << "User and role management commands require auth data to have " << "at least schema version " << AuthorizationManager::schemaVersion26Final << " but startup could not verify schema version: " << status; exitCleanly(EXIT_NEED_UPGRADE); } if (foundSchemaVersion < AuthorizationManager::schemaVersion26Final) { log() << "Auth schema version is incompatible: " << "User and role management commands require auth data to have " << "at least schema version " << AuthorizationManager::schemaVersion26Final << " but found " << foundSchemaVersion << ". In order to upgrade " << "the auth schema, first downgrade MongoDB binaries to version " << "2.6 and then run the authSchemaUpgrade command."; exitCleanly(EXIT_NEED_UPGRADE); } } else if (globalAuthzManager->isAuthEnabled()) { error() << "Auth must be disabled when starting without auth schema validation"; exitCleanly(EXIT_BADOPTIONS); } else { // If authSchemaValidation is disabled and server is running without auth, // warn the user and continue startup without authSchema metadata checks. log() << startupWarningsLog; log() << "** WARNING: Startup auth schema validation checks are disabled for the " "database." << startupWarningsLog; log() << "** This mode should only be used to manually repair corrupted auth " "data." << startupWarningsLog; } auto shardingInitialized = uassertStatusOK(ShardingState::get(startupOpCtx.get()) ->initializeShardingAwarenessIfNeeded(startupOpCtx.get())); if (shardingInitialized) { reloadShardRegistryUntilSuccess(startupOpCtx.get()); } if (!storageGlobalParams.readOnly) { logStartup(startupOpCtx.get()); startFTDC(); getDeleter()->startWorkers(); restartInProgressIndexesFromLastShutdown(startupOpCtx.get()); if (serverGlobalParams.clusterRole == ClusterRole::ShardServer) { // Note: For replica sets, ShardingStateRecovery happens on transition to primary. if (!repl::getGlobalReplicationCoordinator()->isReplEnabled()) { uassertStatusOK(ShardingStateRecovery::recover(startupOpCtx.get())); } } else if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer) { uassertStatusOK( initializeGlobalShardingStateForMongod(startupOpCtx.get(), ConnectionString::forLocal(), kDistLockProcessIdForConfigServer)); Balancer::create(startupOpCtx->getServiceContext()); } repl::getGlobalReplicationCoordinator()->startup(startupOpCtx.get()); const unsigned long long missingRepl = checkIfReplMissingFromCommandLine(startupOpCtx.get()); if (missingRepl) { log() << startupWarningsLog; log() << "** WARNING: mongod started without --replSet yet " << missingRepl << " documents are present in local.system.replset" << startupWarningsLog; log() << "** Restart with --replSet unless you are doing maintenance and " << " no other clients are connected." << startupWarningsLog; log() << "** The TTL collection monitor will not start because of this." << startupWarningsLog; log() << "** "; log() << " For more info see http://dochub.mongodb.org/core/ttlcollections"; log() << startupWarningsLog; } else { startTTLBackgroundJob(); } if (!replSettings.usingReplSets() && !replSettings.isSlave() && storageGlobalParams.engine != "devnull") { ScopedTransaction transaction(startupOpCtx.get(), MODE_X); Lock::GlobalWrite lk(startupOpCtx.get()->lockState()); FeatureCompatibilityVersion::setIfCleanStartup( startupOpCtx.get(), repl::StorageInterface::get(getGlobalServiceContext())); } } startClientCursorMonitor(); PeriodicTask::startRunningPeriodicTasks(); // MessageServer::run will return when exit code closes its socket and we don't need the // operation context anymore startupOpCtx.reset(); auto start = getGlobalServiceContext()->addAndStartTransportLayer(std::move(transportLayer)); if (!start.isOK()) { error() << "Failed to start the listener: " << start.toString(); return EXIT_NET_ERROR; } return waitForShutdown(); }
bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthorizationManager* authzManager = getGlobalAuthorizationManager(); AuthzDocumentsUpdateGuard updateGuard(authzManager); if (!updateGuard.tryLock("Revoke role delegation from user")) { addStatus(Status(ErrorCodes::LockBusy, "Could not lock auth data update lock."), result); return false; } UserName userName; std::vector<RoleName> roles; BSONObj writeConcern; Status status = auth::parseUserRoleManipulationCommand(cmdObj, "revokeDelegateRolesFromUser", dbname, authzManager, &userName, &roles, &writeConcern); if (!status.isOK()) { addStatus(status, result); return false; } User::RoleDataMap userRoles; status = getCurrentUserRoles(authzManager, userName, &userRoles); if (!status.isOK()) { addStatus(status, result); return false; } for (vector<RoleName>::iterator it = roles.begin(); it != roles.end(); ++it) { RoleName& roleName = *it; User::RoleDataMap::iterator roleDataIt = userRoles.find(roleName); if (roleDataIt == userRoles.end()) { continue; // User already doesn't have the role, nothing to do } User::RoleData& role = roleDataIt->second; if (role.hasRole) { // If the user still has the role, need to leave it in the roles array role.canDelegate = false; } else { // If the user doesn't have the role, and now can't delegate it either, remove // the role from that user's roles array entirely userRoles.erase(roleDataIt); } } BSONArray newRolesBSONArray = rolesToBSONArray(userRoles); status = authzManager->updatePrivilegeDocument( userName, BSON("$set" << BSON("roles" << newRolesBSONArray)), writeConcern); // Must invalidate even on bad status - what if the write succeeded but the GLE failed? authzManager->invalidateUserByName(userName); if (!status.isOK()) { addStatus(status, result); return false; } return true; }
void CursorCache::gotKillCursors(Message& m ) { int *x = (int *) m.singleData()->_data; x++; // reserved int n = *x++; if ( n > 2000 ) { LOG( n < 30000 ? LL_WARNING : LL_ERROR ) << "receivedKillCursors, n=" << n << endl; } uassert( 13286 , "sent 0 cursors to kill" , n >= 1 ); uassert( 13287 , "too many cursors to kill" , n < 30000 ); long long * cursors = (long long *)x; AuthorizationManager* authManager = ClientBasic::getCurrent()->getAuthorizationManager(); for ( int i=0; i<n; i++ ) { long long id = cursors[i]; LOG(_myLogLevel) << "CursorCache::gotKillCursors id: " << id << endl; if ( ! id ) { LOG( LL_WARNING ) << " got cursor id of 0 to kill" << endl; continue; } string server; { scoped_lock lk( _mutex ); MapSharded::iterator i = _cursors.find( id ); if ( i != _cursors.end() ) { if (authManager->checkAuthorization(i->second->getNS(), ActionType::killCursors)) { _cursors.erase( i ); } continue; } MapNormal::iterator refsIt = _refs.find(id); MapNormal::iterator refsNSIt = _refsNS.find(id); if (refsIt == _refs.end()) { LOG( LL_WARNING ) << "can't find cursor: " << id << endl; continue; } verify(refsNSIt != _refsNS.end()); if (!authManager->checkAuthorization(refsNSIt->second, ActionType::killCursors)) { continue; } server = refsIt->second; _refs.erase(refsIt); _refsNS.erase(refsNSIt); } LOG(_myLogLevel) << "CursorCache::found gotKillCursors id: " << id << " server: " << server << endl; verify( server.size() ); scoped_ptr<ScopedDbConnection> conn( ScopedDbConnection::getScopedDbConnection( server ) ); conn->get()->killCursor( id ); conn->done(); } }
bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthorizationManager* authzManager = getGlobalAuthorizationManager(); AuthzDocumentsUpdateGuard updateGuard(authzManager); if (!updateGuard.tryLock("Grant privileges to role")) { addStatus(Status(ErrorCodes::LockBusy, "Could not lock auth data update lock."), result); return false; } RoleName roleName; PrivilegeVector privilegesToAdd; BSONObj writeConcern; Status status = auth::parseAndValidateRolePrivilegeManipulationCommands( cmdObj, "grantPrivilegesToRole", dbname, &roleName, &privilegesToAdd, &writeConcern); if (!status.isOK()) { addStatus(status, result); return false; } if (!authzManager->roleExists(roleName)) { addStatus(Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << roleName.getFullName() << " does not name an existing role"), result); return false; } if (authzManager->isBuiltinRole(roleName)) { addStatus(Status(ErrorCodes::InvalidRoleModification, mongoutils::str::stream() << roleName.getFullName() << " is a built-in role and cannot be modified."), result); return false; } PrivilegeVector privileges = authzManager->getDirectPrivilegesForRole(roleName); for (PrivilegeVector::iterator it = privilegesToAdd.begin(); it != privilegesToAdd.end(); ++it) { Privilege::addPrivilegeToPrivilegeVector(&privileges, *it); } // Build up update modifier object to $set privileges. mutablebson::Document updateObj; mutablebson::Element setElement = updateObj.makeElementObject("$set"); status = updateObj.root().pushBack(setElement); if (!status.isOK()) { addStatus(status, result); return false; } mutablebson::Element privilegesElement = updateObj.makeElementArray("privileges"); status = setElement.pushBack(privilegesElement); if (!status.isOK()) { addStatus(status, result); return false; } status = authzManager->getBSONForPrivileges(privileges, privilegesElement); if (!status.isOK()) { addStatus(status, result); return false; } BSONObjBuilder updateBSONBuilder; updateObj.writeTo(&updateBSONBuilder); status = authzManager->updateRoleDocument( roleName, updateBSONBuilder.done(), writeConcern); if (!status.isOK()) { addStatus(status, result); return false; } return true; }
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { _runCalled = true; long long start = Listener::getElapsedTimeMillis(); BSONObjBuilder timeBuilder(256); const ClientBasic* myClientBasic = ClientBasic::getCurrent(); AuthorizationManager* authManager = myClientBasic->getAuthorizationManager(); // --- basic fields that are global result.append("host", prettyHostName() ); result.append("version", versionString); result.append("process",cmdLine.binaryName); result.append("pid", (int)getpid()); result.append("uptime",(double) (time(0)-cmdLine.started)); result.append("uptimeMillis", (long long)(curTimeMillis64()-_started)); result.append("uptimeEstimate",(double) (start/1000)); result.appendDate( "localTime" , jsTime() ); timeBuilder.appendNumber( "after basic" , Listener::getElapsedTimeMillis() - start ); // --- all sections for ( SectionMap::const_iterator i = _sections->begin(); i != _sections->end(); ++i ) { ServerStatusSection* section = i->second; std::vector<Privilege> requiredPrivileges; section->addRequiredPrivileges(&requiredPrivileges); if (!authManager->checkAuthForPrivileges(requiredPrivileges).isOK()) continue; bool include = section->includeByDefault(); BSONElement e = cmdObj[section->getSectionName()]; if ( e.type() ) { include = e.trueValue(); } if ( ! include ) continue; BSONObj data = section->generateSection(e); if ( data.isEmpty() ) continue; result.append( section->getSectionName(), data ); timeBuilder.appendNumber( static_cast<string>(str::stream() << "after " << section->getSectionName()), Listener::getElapsedTimeMillis() - start ); } // --- counters if ( MetricTree::theMetricTree ) { MetricTree::theMetricTree->appendTo( result ); } // --- some hard coded global things hard to pull out { RamLog* rl = RamLog::get( "warnings" ); massert(15880, "no ram log for warnings?" , rl); if (rl->lastWrite() >= time(0)-(10*60)){ // only show warnings from last 10 minutes vector<const char*> lines; rl->get( lines ); BSONArrayBuilder arr( result.subarrayStart( "warnings" ) ); for ( unsigned i=std::max(0,(int)lines.size()-10); i<lines.size(); i++ ) arr.append( lines[i] ); arr.done(); } } timeBuilder.appendNumber( "at end" , Listener::getElapsedTimeMillis() - start ); if ( Listener::getElapsedTimeMillis() - start > 1000 ) { BSONObj t = timeBuilder.obj(); log() << "serverStatus was very slow: " << t << endl; result.append( "timing" , t ); } return true; }
bool handleSpecialNamespaces( Request& r , QueryMessage& q ) { const char * ns = r.getns(); ns = strstr( r.getns() , ".$cmd.sys." ); if ( ! ns ) return false; ns += 10; BSONObjBuilder b; vector<Shard> shards; AuthorizationManager* authManager = ClientBasic::getCurrent()->getAuthorizationManager(); if ( strcmp( ns , "inprog" ) == 0 ) { uassert(16545, "not authorized to run inprog", authManager->checkAuthorization(AuthorizationManager::SERVER_RESOURCE_NAME, ActionType::inprog)); Shard::getAllShards( shards ); BSONArrayBuilder arr( b.subarrayStart( "inprog" ) ); for ( unsigned i=0; i<shards.size(); i++ ) { Shard shard = shards[i]; scoped_ptr<ScopedDbConnection> conn( ScopedDbConnection::getScopedDbConnection( shard.getConnString() ) ); BSONObj temp = conn->get()->findOne( r.getns() , q.query ); if ( temp["inprog"].isABSONObj() ) { BSONObjIterator i( temp["inprog"].Obj() ); while ( i.more() ) { BSONObjBuilder x; BSONObjIterator j( i.next().Obj() ); while( j.more() ) { BSONElement e = j.next(); if ( str::equals( e.fieldName() , "opid" ) ) { stringstream ss; ss << shard.getName() << ':' << e.numberInt(); x.append( "opid" , ss.str() ); } else if ( str::equals( e.fieldName() , "client" ) ) { x.appendAs( e , "client_s" ); } else { x.append( e ); } } arr.append( x.obj() ); } } conn->done(); } arr.done(); } else if ( strcmp( ns , "killop" ) == 0 ) { uassert(16546, "not authorized to run killop", authManager->checkAuthorization(AuthorizationManager::SERVER_RESOURCE_NAME, ActionType::killop)); BSONElement e = q.query["op"]; if ( e.type() != String ) { b.append( "err" , "bad op" ); b.append( e ); } else { b.append( e ); string s = e.String(); string::size_type i = s.find( ':' ); if ( i == string::npos ) { b.append( "err" , "bad opid" ); } else { string shard = s.substr( 0 , i ); int opid = atoi( s.substr( i + 1 ).c_str() ); b.append( "shard" , shard ); b.append( "shardid" , opid ); log() << "want to kill op: " << e << endl; Shard s(shard); scoped_ptr<ScopedDbConnection> conn( ScopedDbConnection::getScopedDbConnection( s.getConnString() ) ); conn->get()->findOne( r.getns() , BSON( "op" << opid ) ); conn->done(); } } } else if ( strcmp( ns , "unlock" ) == 0 ) { b.append( "err" , "can't do unlock through mongos" ); } else { LOG( LL_WARNING ) << "unknown sys command [" << ns << "]" << endl; return false; } BSONObj x = b.done(); replyToQuery(0, r.p(), r.m(), x); return true; }
void Command::execCommandClientBasic(Command * c , ClientBasic& client, int queryOptions, const char *ns, BSONObj& cmdObj, BSONObjBuilder& result, bool fromRepl ) { verify(c); std::string dbname = nsToDatabase(ns); // Access control checks if (!noauth) { std::vector<Privilege> privileges; c->addRequiredPrivileges(dbname, cmdObj, &privileges); AuthorizationManager* authManager = client.getAuthorizationManager(); if (!authManager->checkAuthForPrivileges(privileges).isOK()) { result.append("note", str::stream() << "not authorized for command: " << c->name << " on database " << dbname); appendCommandStatus(result, false, "unauthorized"); return; } } if (c->adminOnly() && c->localHostOnlyIfNoAuth(cmdObj) && noauth && !client.getIsLocalHostConnection()) { log() << "command denied: " << cmdObj.toString() << endl; appendCommandStatus(result, false, "unauthorized: this command must run from localhost when running db " "without auth"); return; } if (c->adminOnly() && !startsWith(ns, "admin.")) { log() << "command denied: " << cmdObj.toString() << endl; appendCommandStatus(result, false, "access denied - use admin db"); return; } // End of access control checks if (cmdObj.getBoolField("help")) { stringstream help; help << "help for: " << c->name << " "; c->help( help ); result.append( "help" , help.str() ); result.append( "lockType" , c->locktype() ); appendCommandStatus(result, true, ""); return; } std::string errmsg; bool ok; try { ok = c->run( dbname , cmdObj, queryOptions, errmsg, result, false ); } catch (DBException& e) { ok = false; int code = e.getCode(); if (code == RecvStaleConfigCode) { // code for StaleConfigException throw; } stringstream ss; ss << "exception: " << e.what(); errmsg = ss.str(); result.append( "code" , code ); } appendCommandStatus(result, ok, errmsg); }