Status Pipeline::checkAuthForCommand(ClientBasic* client, const std::string& db, const BSONObj& cmdObj) { NamespaceString inputNs(db, cmdObj.firstElement().str()); auto inputResource = ResourcePattern::forExactNamespace(inputNs); uassert(17138, mongoutils::str::stream() << "Invalid input namespace, " << inputNs.ns(), inputNs.isValid()); std::vector<Privilege> privileges; if (dps::extractElementAtPath(cmdObj, "pipeline.0.$indexStats")) { Privilege::addPrivilegeToPrivilegeVector( &privileges, Privilege(ResourcePattern::forAnyNormalResource(), ActionType::indexStats)); } else if (dps::extractElementAtPath(cmdObj, "pipeline.0.$collStats")) { Privilege::addPrivilegeToPrivilegeVector(&privileges, Privilege(inputResource, ActionType::collStats)); } else { // If no source requiring an alternative permission scheme is specified then default to // requiring find() privileges on the given namespace. Privilege::addPrivilegeToPrivilegeVector(&privileges, Privilege(inputResource, ActionType::find)); } BSONObj pipeline = cmdObj.getObjectField("pipeline"); BSONForEach(stageElem, pipeline) { BSONObj stage = stageElem.embeddedObjectUserCheck(); StringData stageName = stage.firstElementFieldName(); if (stageName == "$out" && stage.firstElementType() == String) { NamespaceString outputNs(db, stage.firstElement().str()); uassert(17139, mongoutils::str::stream() << "Invalid $out target namespace, " << outputNs.ns(), outputNs.isValid()); ActionSet actions; actions.addAction(ActionType::remove); actions.addAction(ActionType::insert); if (shouldBypassDocumentValidationForCommand(cmdObj)) { actions.addAction(ActionType::bypassDocumentValidation); } Privilege::addPrivilegeToPrivilegeVector( &privileges, Privilege(ResourcePattern::forExactNamespace(outputNs), actions)); } else if (stageName == "$lookup" && stage.firstElementType() == Object) { NamespaceString fromNs(db, stage.firstElement()["from"].str()); Privilege::addPrivilegeToPrivilegeVector( &privileges, Privilege(ResourcePattern::forExactNamespace(fromNs), ActionType::find)); } else if (stageName == "$graphLookup" && stage.firstElementType() == Object) { NamespaceString fromNs(db, stage.firstElement()["from"].str()); Privilege::addPrivilegeToPrivilegeVector( &privileges, Privilege(ResourcePattern::forExactNamespace(fromNs), ActionType::find)); } }
bool WriteCmd::run(const string& dbName, BSONObj& cmdObj, int options, string& errMsg, BSONObjBuilder& result, bool fromRepl) { verify(!fromRepl); // Can't be run on secondaries (logTheOp() == false, slaveOk() == false). if (cmdObj.firstElementType() != mongo::String) { errMsg = "expected string type for collection name"; return false; } string ns = parseNs(dbName, cmdObj); if (!NamespaceString(ns).isValid()) { errMsg = mongoutils::str::stream() << "invalid namespace: \"" << ns << "\""; return false; } { // Commands with locktype == NONE need to acquire a Context in order to set // CurOp::_ns. Setting a CurOp's namespace is necessary for higher-level // functionality (e.g. profiling) to operate on the correct database (note that // WriteBatchExecutor doesn't do this for us, since its job is to create child CurOp // objects and operate on them). // // Acquire ReadContext momentarily, for satisfying this purpose. Client::ReadContext ctx(dbName + ".$cmd"); } WriteBatch writeBatch(ns, _writeType); if (!writeBatch.parse(cmdObj, &errMsg)) { return false; } WriteBatchExecutor writeBatchExecutor(&cc(), &globalOpCounters, lastError.get()); return writeBatchExecutor.executeBatch(writeBatch, &errMsg, &result); }