TEST_F(WiredTigerUtilMetadataTest, GetApplicationMetadataTypes) {
        const char* config = "app_metadata=(stringkey=\"abc\",boolkey1=true,boolkey2=false,"
                             "idkey=def,numkey=123,"
                             "structkey=(k1=v2,k2=v2))";
        createSession(config);
        StatusWith<BSONObj> result =
            WiredTigerUtil::getApplicationMetadata(getOperationContext(), getURI());
        ASSERT_OK(result.getStatus());
        const BSONObj& obj = result.getValue();

        BSONElement stringElement = obj.getField("stringkey");
        ASSERT_EQUALS(mongo::String, stringElement.type());
        ASSERT_EQUALS("abc", stringElement.String());

        BSONElement boolElement1 = obj.getField("boolkey1");
        ASSERT_TRUE(boolElement1.isBoolean());
        ASSERT_TRUE(boolElement1.boolean());

        BSONElement boolElement2 = obj.getField("boolkey2");
        ASSERT_TRUE(boolElement2.isBoolean());
        ASSERT_FALSE(boolElement2.boolean());

        BSONElement identifierElement = obj.getField("idkey");
        ASSERT_EQUALS(mongo::String, identifierElement.type());
        ASSERT_EQUALS("def", identifierElement.String());

        BSONElement numberElement = obj.getField("numkey");
        ASSERT_TRUE(numberElement.isNumber());
        ASSERT_EQUALS(123, numberElement.numberInt());

        BSONElement structElement = obj.getField("structkey");
        ASSERT_EQUALS(mongo::String, structElement.type());
        ASSERT_EQUALS("(k1=v2,k2=v2)", structElement.String());
    }
Beispiel #2
0
        Config::OutputOptions Config::parseOutputOptions(const std::string& dbname,
                                                         const BSONObj& cmdObj) {
            Config::OutputOptions outputOptions;

            outputOptions.outNonAtomic = false;
            if (cmdObj["out"].type() == String) {
                outputOptions.collectionName = cmdObj["out"].String();
                outputOptions.outType = REPLACE;
            }
            else if (cmdObj["out"].type() == Object) {
                BSONObj o = cmdObj["out"].embeddedObject();

                BSONElement e = o.firstElement();
                string t = e.fieldName();

                if (t == "normal" || t == "replace") {
                    outputOptions.outType = REPLACE;
                    outputOptions.collectionName = e.String();
                }
                else if (t == "merge") {
                    outputOptions.outType = MERGE;
                    outputOptions.collectionName = e.String();
                }
                else if (t == "reduce") {
                    outputOptions.outType = REDUCE;
                    outputOptions.collectionName = e.String();
                }
                else if (t == "inline") {
                    outputOptions.outType = INMEMORY;
                }
                else {
                    uasserted(13522,
                              mongoutils::str::stream() << "unknown out specifier [" << t << "]");
                }

                if (o.hasElement("db")) {
                    outputOptions.outDB = o["db"].String();
                }

                if (o.hasElement("nonAtomic")) {
                    outputOptions.outNonAtomic = o["nonAtomic"].Bool();
                    if (outputOptions.outNonAtomic)
                        uassert(15895,
                                "nonAtomic option cannot be used with this output type",
                                (outputOptions.outType == REDUCE ||
                                         outputOptions.outType == MERGE));
                }
            }
            else {
                uasserted(13606 , "'out' has to be a string or an object");
            }

            if (outputOptions.outType != INMEMORY) {
                outputOptions.finalNamespace = mongoutils::str::stream()
                    << (outputOptions.outDB.empty() ? dbname : outputOptions.outDB)
                    << "." << outputOptions.collectionName;
            }

            return outputOptions;
        }
Beispiel #3
0
        /*
         * Recurses over all fields in the obj to match against phrase
         * @param phrase, string to be matched
         * @param obj, object to matched against
         */
        bool FTSMatcher::_phraseRecurse( const string& phrase, const BSONObj& obj ) const {
            BSONObjIterator j( obj );
            while ( j.more() ) {
                BSONElement x = j.next();

                if ( _spec.languageOverrideField() == x.fieldName() )
                    continue;

                if ( x.type() == String ) {
                    if ( _phraseMatches( phrase, x.String() ) )
                        return true;
                } 
                else if ( x.isABSONObj() ) {
                    BSONObjIterator k( x.Obj() );

                    while ( k.more() ) {

                        BSONElement y = k.next();

                        if ( y.type() == mongo::String ) {
                            if ( _phraseMatches( phrase, y.String() ) )
                                return true;
                        }
                        else if ( y.isABSONObj() ) {
                            if ( _phraseRecurse( phrase, y.Obj() ) )
                                return true;
                        }
                    }

                }
            }

            return false;
        }
Beispiel #4
0
        /**
         * Checks if phrase is exactly matched in obj, returns true if so, false otherwise
         * @param phrase, the string to be matched
         * @param obj, document in the collection to match against
         */
        bool FTSMatcher::phraseMatch( const string& phrase, const BSONObj& obj ) const {

            if ( _spec.wildcard() ) {
                // case where everything is indexed (all fields)
                return _phraseRecurse( phrase, obj );
            }

            for ( Weights::const_iterator i = _spec.weights().begin();
                  i != _spec.weights().end();
                  ++i ) {

                //  figure out what the indexed field is.. ie. is it "field" or "field.subfield" etc.
                const char * leftOverName = i->first.c_str();
                BSONElement e = obj.getFieldDottedOrArray(leftOverName);

                if ( e.type() == Array ) {
                    BSONObjIterator j( e.Obj() );
                    while ( j.more() ) {
                        BSONElement x = j.next();

                        if ( leftOverName[0] && x.isABSONObj() )
                            x = x.Obj().getFieldDotted( leftOverName );

                        if ( x.type() == String )
                            if ( _phraseMatches( phrase, x.String() ) )
                                return true;
                    }
                }
                else if ( e.type() == String ) {
                    if ( _phraseMatches( phrase, e.String() ) )
                        return true;
                }
            }
            return false;
        }
Beispiel #5
0
        bool FTSMatcher::_hasNegativeTerm_recurse(const BSONObj& obj ) const {
            BSONObjIterator j( obj );
            while ( j.more() ) {
                BSONElement x = j.next();

                if ( _spec.languageOverrideField() == x.fieldName())
                    continue;

                if (x.type() == String) {
                    if ( _hasNegativeTerm_string( x.String() ) )
                        return true;
                }
                else if ( x.isABSONObj() ) {
                    BSONObjIterator k( x.Obj() );
                    while ( k.more() ) {
                        // check if k.next() is a obj/array or not
                        BSONElement y = k.next();
                        if ( y.type() == String ) {
                            if ( _hasNegativeTerm_string( y.String() ) )
                                return true;
                        }
                        else if ( y.isABSONObj() ) {
                            if ( _hasNegativeTerm_recurse( y.Obj() ) )
                                return true;
                        }
                    }
                }
            }
            return false;
        }
    Status V2PrivilegeDocumentParser::initializeUserRolesFromPrivilegeDocument(
            User* user, const BSONObj& privDoc, const StringData&) const {

        BSONElement rolesElement = privDoc[ROLES_FIELD_NAME];

        if (rolesElement.type() != Array) {
            return Status(ErrorCodes::UnsupportedFormat,
                          "User document needs 'roles' field to be an array");
        }

        for (BSONObjIterator it(rolesElement.Obj()); it.more(); it.next()) {
            if ((*it).type() != Object) {
                return Status(ErrorCodes::UnsupportedFormat,
                              "User document needs values in 'roles' array to be a sub-documents");
            }
            BSONObj roleObject = (*it).Obj();

            BSONElement roleNameElement = roleObject[ROLE_NAME_FIELD_NAME];
            BSONElement roleSourceElement = roleObject[ROLE_SOURCE_FIELD_NAME];

            if (roleNameElement.type() != String ||
                    makeStringDataFromBSONElement(roleNameElement).empty()) {
                return Status(ErrorCodes::UnsupportedFormat,
                              "Role names must be non-empty strings");
            }
            if (roleSourceElement.type() != String ||
                    makeStringDataFromBSONElement(roleSourceElement).empty()) {
                return Status(ErrorCodes::UnsupportedFormat,
                              "Role source must be non-empty strings");
            }

            user->addRole(RoleName(roleNameElement.String(), roleSourceElement.String()));
        }
        return Status::OK();
    }
    /**
     * Validates that the roles array described by rolesElement is valid.
     * Also returns a new roles array (via the modifiedRolesArray output param) where any roles
     * from the input array that were listed as strings have been expanded to a full role document.
     */
    Status _validateAndModifyRolesArray(const BSONElement& rolesElement,
                                        const std::string& dbname,
                                        AuthorizationManager* authzManager,
                                        BSONArray* modifiedRolesArray) {
        BSONArrayBuilder rolesBuilder;

        for (BSONObjIterator it(rolesElement.Obj()); it.more(); it.next()) {
            BSONElement element = *it;
            if (element.type() == String) {
                RoleName roleName(element.String(), dbname);
                if (!authzManager->roleExists(roleName)) {
                    return Status(ErrorCodes::RoleNotFound,
                                  mongoutils::str::stream() << roleName.toString() <<
                                  " does not name an existing role");
                }

                rolesBuilder.append(BSON("name" << element.String() <<
                                         "source" << dbname <<
                                         "hasRole" << true <<
                                         "canDelegate" << false));
            } else if (element.type() == Object) {
                // Check that the role object is valid
                V2PrivilegeDocumentParser parser;
                BSONObj roleObj = element.Obj();
                Status status = parser.checkValidRoleObject(roleObj);
                if (!status.isOK()) {
                    return status;
                }

                // Check that the role actually exists
                std::string roleNameString;
                std::string roleSource;
                status = bsonExtractStringField(roleObj, "name", &roleNameString);
                if (!status.isOK()) {
                    return status;
                }
                status = bsonExtractStringField(roleObj, "source", &roleSource);
                if (!status.isOK()) {
                    return status;
                }

                RoleName roleName(roleNameString, roleSource);
                if (!authzManager->roleExists(roleName)) {
                    return Status(ErrorCodes::RoleNotFound,
                                  mongoutils::str::stream() << roleName.toString() <<
                                  " does not name an existing role");
                }

                rolesBuilder.append(element);
            } else {
                return Status(ErrorCodes::UnsupportedFormat,
                              "Values in 'roles' array must be sub-documents or strings");
            }
        }

        *modifiedRolesArray = rolesBuilder.arr();
        return Status::OK();
    }
Beispiel #8
0
/**********************************************************
 *reads from db and converts bson to FileRec object
 * 
***********************************************************/
void FileRec::readFromDB(mongo::DBClientConnection& conn, string filename) {

    boost::filesystem::path p(filename); //get filename from path
    string file(p.filename().c_str());
    auto_ptr<mongo::DBClientCursor> cursor = conn.query("fileRecords.Filerec", MONGO_QUERY("filename" << file));

    if (cursor->more()) {

        BSONObj record = cursor->next();
        //get data from db and store in the FileRec
        this->filename = record.getStringField("filename");
        this->tempname = record.getStringField("Tempname");
        this->recentHash = record.getStringField("curhash");
        this->origHash = record.getStringField("ovhash");
        this->length = record.getIntField("length");
        this->versionCount = record.getIntField("nversions");
        this->modifytime.tv_nsec = record.getField("Mtnsec").numberLong();
        this->modifytime.tv_sec = record.getField("mtsec").numberLong();
        this->refNum = record.getIntField("currentversion");

        vector<BSONElement> hashes(record.getField("FileBlkHashes").Array());
        for (vector<BSONElement>::iterator it = hashes.begin(); it != hashes.end(); ++it) {
            appendBlock((*it).String());
        }

        //comments is an array of objects so it takes a bit of nesting to convert
        vector<BSONElement> array = record["comments"].Array(); //convert to array
        for (vector<BSONElement>::iterator ar = array.begin(); ar != array.end(); ++ar) {
            BSONObj commentdata = ar->Obj(); //store object at array[x] into BSONObj
            BSONElement version = commentdata.getField("version"); //convert
            BSONElement commentdb = commentdata.getField("comment");

            comment data;
            data.comment = commentdb.String();
            data.version = version.Int();
            appendComment(data);
        }


        if (record.hasElement("versionrec")) { //again an array of objects
            vector<BSONElement> array = record["versionrec"].Array();
            for (vector<BSONElement>::iterator it = array.begin(); it != array.end(); ++it) {

                BSONObj versionRecord = it->Obj();
                BSONElement id = versionRecord.getField("id");
                appendVersion(id.String());
            }
        } 
    }
}
Beispiel #9
0
    bool GeoParser::isGeoJSONPolygon(const BSONObj& obj) {
        BSONElement type = obj.getFieldDotted(GEOJSON_TYPE);
        if (type.eoo() || (String != type.type())) { return false; }
        if (GEOJSON_TYPE_POLYGON != type.String()) { return false; }

        if (!crsIsOK(obj)) {
            warning() << "Invalid CRS: " << obj.toString() << endl;
            return false;
        }

        BSONElement coordElt = obj.getFieldDotted(GEOJSON_COORDINATES);
        if (coordElt.eoo() || (Array != coordElt.type())) { return false; }

        const vector<BSONElement>& coordinates = coordElt.Array();
        // Must be at least one element, the outer shell
        if (coordinates.empty()) { return false; }
        // Verify that the shell is a bunch'a coordinates.
        for (size_t i = 0; i < coordinates.size(); ++i) {
            if (Array != coordinates[i].type()) { return false; }
            const vector<BSONElement>& thisLoop = coordinates[i].Array();
            // A triangle is the simplest 2d shape, and we repeat a vertex, so, 4.
            if (thisLoop.size() < 4) { return false; }
            if (!isArrayOfCoordinates(thisLoop)) { return false; }
            if (!isLoopClosed(thisLoop)) { return false; }
        }
        return true;
    }
EncryptSchemaKeyId EncryptSchemaKeyId::parseFromBSON(const BSONElement& element) {
    if (element.type() == BSONType::String) {
        return EncryptSchemaKeyId(element.String());
    } else if (element.type() == BSONType::Array) {
        std::vector<UUID> keys;

        for (auto&& arrayElement : element.embeddedObject()) {
            if (arrayElement.type() != BSONType::BinData) {
                uasserted(51088,
                          str::stream() << "Array elements must have type BinData, found "
                                        << arrayElement.type());
            }
            if (arrayElement.binDataType() == BinDataType::newUUID) {
                const auto uuid = uassertStatusOK(UUID::parse(arrayElement));

                keys.emplace_back(uuid);
            } else {
                uasserted(51084,
                          str::stream() << "Array elements must have bindata type UUID, found "
                                        << arrayElement.binDataType());
            }
        }
        return EncryptSchemaKeyId(keys);
    } else {
        uasserted(51085,
                  str::stream()
                      << "Expected either string or array of UUID for EncryptSchemaKeyId, found "
                      << element.type());
    }
    MONGO_UNREACHABLE;
}
Beispiel #11
0
    S2AccessMethod::S2AccessMethod(IndexCatalogEntry* btreeState, RecordStore* rs)
        : BtreeBasedAccessMethod(btreeState, rs) {

        const IndexDescriptor* descriptor = btreeState->descriptor();

        ExpressionParams::parse2dsphereParams(descriptor->infoObj(),
                                              &_params);

        int geoFields = 0;

        // Categorize the fields we're indexing and make sure we have a geo field.
        BSONObjIterator i(descriptor->keyPattern());
        while (i.more()) {
            BSONElement e = i.next();
            if (e.type() == String && IndexNames::GEO_2DSPHERE == e.String() ) {
                ++geoFields;
            }
            else {
                // We check for numeric in 2d, so that's the check here
                uassert( 16823, (string)"Cannot use " + IndexNames::GEO_2DSPHERE +
                                    " index with other special index types: " + e.toString(),
                         e.isNumber() );
            }
        }

        uassert(16750, "Expect at least one geo field, spec=" + descriptor->keyPattern().toString(),
                geoFields >= 1);

        if (descriptor->isSparse()) {
            warning() << "Sparse option ignored for index spec "
                      << descriptor->keyPattern().toString() << "\n";
        }
    }
    StatusWithMatchExpression expressionParserTextCallbackReal( const BSONObj& queryObj ) {
        // Validate queryObj, but defer construction of FTSQuery (which requires access to the
        // target namespace) until stage building time.

        if ( mongo::String != queryObj["$search"].type() ) {
            return StatusWithMatchExpression( ErrorCodes::BadValue, "$search needs a String" );
        }

        string language = "";
        BSONElement languageElt = queryObj["$language"];
        if ( !languageElt.eoo() ) {
            if ( mongo::String != languageElt.type() ) {
                return StatusWithMatchExpression( ErrorCodes::BadValue,
                                                  "$language needs a String" );
            }
            language = languageElt.String();
            if ( !fts::FTSLanguage::makeFTSLanguage( language ).getStatus().isOK() ) {
                return StatusWithMatchExpression( ErrorCodes::BadValue,
                                                  "$language specifies unsupported language" );
            }
        }
        string query = queryObj["$search"].String();

        if ( queryObj.nFields() != ( languageElt.eoo() ? 1 : 2 ) ) {
            return StatusWithMatchExpression( ErrorCodes::BadValue, "extra fields in $text" );
        }

        auto_ptr<TextMatchExpression> e( new TextMatchExpression() );
        Status s = e->init( query, language );
        if ( !s.isOK() ) {
            return StatusWithMatchExpression( s );
        }
        return StatusWithMatchExpression( e.release() );
    }
Beispiel #13
0
/**********************************************************
 *see readFromDB in FileRec, similar structure
 * 
***********************************************************/
void VersionRec::readFromDB(mongo::DBClientConnection& conn, string versionID) {

    auto_ptr<mongo::DBClientCursor> cursor =
            conn.query("fileRecords.FileVersion", MONGO_QUERY("_id" << mongo::OID(versionID)));

    if (cursor->more()) {
        //convert to VersionRec
        BSONObj record = cursor->next();
        this->versionid = versionID;
        this->tmpname = record.getStringField("Tempname");
        this->filehash = record.getStringField("filehash");
        this->length = record.getIntField("length");
        this->modifytime.tv_nsec = record.getField("Mtnsec").numberLong();
        this->modifytime.tv_sec = record.getField("mtsec").numberLong();
        this->versionnumber = record.getIntField("Version");

        //similar to the comments collection in readfromDB in FileRec
        vector<BSONElement> hashes(record.getField("Blktable").Array());
        for (vector<BSONElement>::iterator it = hashes.begin(); it != hashes.end(); ++it) {

            BSONObj blockdata = it->Obj();
            BSONElement blocknum = blockdata.getField("Blknum");
            BSONElement blockhash = blockdata.getField("hash");

            VersionDiffBlock tmp;
            tmp.blockNo = blocknum.Int();
            tmp.blockHash = blockhash.String();
            changesAppend(tmp);
        }
    }
    else{
        cout << "could not find version " << versionID << endl;
    }
}
    CollectionOptions MMAPV1DatabaseCatalogEntry::getCollectionOptions( OperationContext* txn,
                                                                        const StringData& ns ) const {
        if ( nsToCollectionSubstring( ns ) == "system.namespaces" ) {
            return CollectionOptions();
        }

        RecordStoreV1Base* rs = _getNamespaceRecordStore();
        invariant( rs );

        scoped_ptr<RecordIterator> it( rs->getIterator(txn) );
        while ( !it->isEOF() ) {
            DiskLoc loc = it->getNext();
            BSONObj entry = it->dataFor( loc ).toBson();
            BSONElement name = entry["name"];
            if ( name.type() == String && name.String() == ns ) {
                CollectionOptions options;
                if ( entry["options"].isABSONObj() ) {
                    Status status = options.parse( entry["options"].Obj() );
                    fassert( 18523, status );
                }
                return options;
            }
        }

        return CollectionOptions();
    }
    void NamespaceDetailsRSV1MetaData::_syncUserFlags( OperationContext* txn ) {
        if ( !_namespaceRecordStore )
            return;

        scoped_ptr<RecordIterator> iterator( _namespaceRecordStore->getIterator(txn) );
        while ( !iterator->isEOF() ) {
            RecordId loc = iterator->getNext();

            BSONObj oldEntry = iterator->dataFor( loc ).toBson();
            BSONElement e = oldEntry["name"];
            if ( e.type() != String )
                continue;

            if ( e.String() != _ns )
                continue;

            BSONObj newEntry = applyUpdateOperators( oldEntry,
                                                     BSON( "$set" << BSON( "options.flags" << userFlags() ) ) );

            StatusWith<RecordId> result = _namespaceRecordStore->updateRecord(txn,
                                                                              loc,
                                                                              newEntry.objdata(),
                                                                              newEntry.objsize(),
                                                                              false,
                                                                              NULL);
            fassert( 17486, result.isOK() );
            return;
        }

        fassertFailed( 17488 );
    }
Status _parseNameFromBSONElement(const BSONElement& element,
                                 StringData dbname,
                                 StringData nameFieldName,
                                 StringData sourceFieldName,
                                 Name* parsedName) {
    if (element.type() == String) {
        *parsedName = Name(element.String(), dbname);
    } else if (element.type() == Object) {
        BSONObj obj = element.Obj();

        std::string name;
        std::string source;
        Status status = bsonExtractStringField(obj, nameFieldName, &name);
        if (!status.isOK()) {
            return status;
        }
        status = bsonExtractStringField(obj, sourceFieldName, &source);
        if (!status.isOK()) {
            return status;
        }

        *parsedName = Name(name, source);
    } else {
        return Status(ErrorCodes::BadValue,
                      "User and role names must be either strings or objects");
    }
    return Status::OK();
}
Beispiel #17
0
        static void printData( const BSONObj& o , const BSONObj& headers ) {

            BSONObjIterator i(headers);
            while ( i.more() ) {
                BSONElement e = i.next();
                BSONObj h = e.Obj();
                int w = h["width"].numberInt();

                BSONElement data;
                {
                    BSONElement temp = o[e.fieldName()];
                    if ( temp.isABSONObj() )
                        data = temp.Obj()["data"];
                }

                if ( data.type() == String )
                    cout << setw(w) << data.String();
                else if ( data.type() == NumberDouble )
                    cout << setw(w) << setprecision(3) << data.number();
                else if ( data.type() == NumberInt )
                    cout << setw(w) << data.numberInt();
                else if ( data.eoo() )
                    cout << setw(w) << "";
                else
                    cout << setw(w) << "???";

                cout << ' ';
            }
            cout << endl;
        }
Beispiel #18
0
std::vector<std::string> KVCatalog::getAllIdents(OperationContext* opCtx) const {
    std::vector<std::string> v;

    auto cursor = _rs->getCursor(opCtx);
    while (auto record = cursor->next()) {
        BSONObj obj = record->data.releaseToBson();
        if (FeatureTracker::isFeatureDocument(obj)) {
            // Skip over the version document because it doesn't correspond to a namespace entry and
            // therefore doesn't refer to any idents.
            continue;
        }
        v.push_back(obj["ident"].String());

        BSONElement e = obj["idxIdent"];
        if (!e.isABSONObj())
            continue;
        BSONObj idxIdent = e.Obj();

        BSONObjIterator sub(idxIdent);
        while (sub.more()) {
            BSONElement e = sub.next();
            v.push_back(e.String());
        }
    }

    return v;
}
Status getStatusFromCommandResult(const BSONObj& result) {
    BSONElement okElement = result["ok"];
    BSONElement codeElement = result["code"];
    BSONElement errmsgElement = result["errmsg"];

    // StaleConfigException doesn't pass "ok" in legacy servers
    BSONElement dollarErrElement = result["$err"];

    if (okElement.eoo() && dollarErrElement.eoo()) {
        return Status(ErrorCodes::CommandResultSchemaViolation,
                      mongoutils::str::stream() << "No \"ok\" field in command result " << result);
    }
    if (okElement.trueValue()) {
        return Status::OK();
    }
    int code = codeElement.numberInt();
    if (0 == code) {
        code = ErrorCodes::UnknownError;
    }
    std::string errmsg;
    if (errmsgElement.type() == String) {
        errmsg = errmsgElement.String();
    } else if (!errmsgElement.eoo()) {
        errmsg = errmsgElement.toString();
    }

    // we can't use startsWith(errmsg, "no such")
    // as we have errors such as "no such collection"
    if (code == ErrorCodes::UnknownError &&
        (str::startsWith(errmsg, "no such cmd") || str::startsWith(errmsg, "no such command"))) {
        code = ErrorCodes::CommandNotFound;
    }

    return Status(ErrorCodes::Error(code), errmsg, result);
}
    Status parseRoleNamesFromBSONArray(const BSONArray& rolesArray,
                                       const StringData& dbname,
                                       const StringData& rolesFieldName,
                                       std::vector<RoleName>* parsedRoleNames) {
        for (BSONObjIterator it(rolesArray); it.more(); it.next()) {
            BSONElement element = *it;
            if (element.type() == String) {
                parsedRoleNames->push_back(RoleName(element.String(), dbname));
            }
            else if (element.type() == Object) {
                BSONObj roleObj = element.Obj();

                std::string roleNameString;
                std::string roleSource;
                Status status = bsonExtractStringField(roleObj, "name", &roleNameString);
                if (!status.isOK()) {
                    return status;
                }
                status = bsonExtractStringField(roleObj, "source", &roleSource);
                if (!status.isOK()) {
                    return status;
                }

                parsedRoleNames->push_back(RoleName(roleNameString, roleSource));
            }
            else {
                return Status(ErrorCodes::BadValue,
                              mongoutils::str::stream() << "Values in \"" << rolesFieldName <<
                                      "\" array must be sub-documents or strings");
            }
        }
        return Status::OK();
    }
Beispiel #21
0
    /**
     * Returns true if 'e' contains a valid operation.
     */
    bool _checkOperation(const BSONElement& e, string& errmsg) {
        if (e.type() != Object) {
            errmsg = str::stream() << "op not an object: " << e.fieldName();
            return false;
        }
        BSONObj obj = e.Obj();
        // op - operation type
        BSONElement opElement = obj.getField("op");
        if (opElement.eoo()) {
            errmsg = str::stream()
                << "op does not contain required \"op\" field: " << e.fieldName();
            return false;
        }
        if (opElement.type() != mongol::String) {
            errmsg = str::stream() << "\"op\" field is not a string: " << e.fieldName();
            return false;
        }
        // operation type -- see logOp() comments for types
        const char* opType = opElement.valuestrsafe();
        if (*opType == '\0') {
            errmsg = str::stream() << "\"op\" field value cannot be empty: " << e.fieldName();
            return false;
        }

        // ns - namespace
        // Only operations of type 'n' are allowed to have an empty namespace.
        BSONElement nsElement = obj.getField("ns");
        if (nsElement.eoo()) {
            errmsg = str::stream()
                << "op does not contain required \"ns\" field: " << e.fieldName();
            return false;
        }
        if (nsElement.type() != mongol::String) {
            errmsg = str::stream() << "\"ns\" field is not a string: " << e.fieldName();
            return false;
        }
        if (nsElement.String().find('\0') != std::string::npos) {
            errmsg = str::stream() << "namespaces cannot have embedded null characters";
            return false;
        }
        if (*opType != 'n' && nsElement.String().empty()) {
            errmsg = str::stream()
                << "\"ns\" field value cannot be empty when op type is not 'n': " << e.fieldName();
            return false;
        }
        return true;
    }
Beispiel #22
0
        bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result,
                 bool fromRepl) {
            BSONElement argElt = cmdObj["stageDebug"];
            if (argElt.eoo() || !argElt.isABSONObj()) { return false; }
            BSONObj argObj = argElt.Obj();

            // Pull out the collection name.
            BSONElement collElt = argObj["collection"];
            if (collElt.eoo() || (String != collElt.type())) {
                return false;
            }
            string collName = collElt.String();

            // Need a context to get the actual Collection*
            // TODO A write lock is currently taken here to accommodate stages that perform writes
            //      (e.g. DeleteStage).  This should be changed to use a read lock for read-only
            //      execution trees.
            ScopedTransaction transaction(txn, MODE_IX);
            Lock::DBLock lk(txn->lockState(), dbname, MODE_X);
            Client::Context ctx(txn, dbname);

            // Make sure the collection is valid.
            Database* db = ctx.db();
            Collection* collection = db->getCollection(db->name() + '.' + collName);
            uassert(17446, "Couldn't find the collection " + collName, NULL != collection);

            // Pull out the plan
            BSONElement planElt = argObj["plan"];
            if (planElt.eoo() || !planElt.isABSONObj()) {
                return false;
            }
            BSONObj planObj = planElt.Obj();

            // Parse the plan into these.
            OwnedPointerVector<MatchExpression> exprs;
            auto_ptr<WorkingSet> ws(new WorkingSet());

            PlanStage* userRoot = parseQuery(txn, collection, planObj, ws.get(), &exprs);
            uassert(16911, "Couldn't parse plan from " + cmdObj.toString(), NULL != userRoot);

            // Add a fetch at the top for the user so we can get obj back for sure.
            // TODO: Do we want to do this for the user?  I think so.
            PlanStage* rootFetch = new FetchStage(txn, ws.get(), userRoot, NULL, collection);

            PlanExecutor* rawExec;
            Status execStatus = PlanExecutor::make(txn, ws.release(), rootFetch, collection,
                                                   PlanExecutor::YIELD_MANUAL, &rawExec);
            fassert(28536, execStatus);
            boost::scoped_ptr<PlanExecutor> exec(rawExec);

            BSONArrayBuilder resultBuilder(result.subarrayStart("results"));

            for (BSONObj obj; PlanExecutor::ADVANCED == exec->getNext(&obj, NULL); ) {
                resultBuilder.append(obj);
            }

            resultBuilder.done();
            return true;
        }
Beispiel #23
0
StatusWith<CursorResponse> CursorResponse::parseFromBSON(const BSONObj& cmdResponse) {
    Status cmdStatus = getStatusFromCommandResult(cmdResponse);
    if (!cmdStatus.isOK()) {
        return cmdStatus;
    }

    std::string fullns;
    BSONObj batchObj;
    CursorId cursorId;

    BSONElement cursorElt = cmdResponse[kCursorField];
    if (cursorElt.type() != BSONType::Object) {
        return {ErrorCodes::TypeMismatch,
                str::stream() << "Field '" << kCursorField
                              << "' must be a nested object in: " << cmdResponse};
    }
    BSONObj cursorObj = cursorElt.Obj();

    BSONElement idElt = cursorObj[kIdField];
    if (idElt.type() != BSONType::NumberLong) {
        return {ErrorCodes::TypeMismatch,
                str::stream() << "Field '" << kIdField
                              << "' must be of type long in: " << cmdResponse};
    }
    cursorId = idElt.Long();

    BSONElement nsElt = cursorObj[kNsField];
    if (nsElt.type() != BSONType::String) {
        return {ErrorCodes::TypeMismatch,
                str::stream() << "Field '" << kNsField
                              << "' must be of type string in: " << cmdResponse};
    }
    fullns = nsElt.String();

    BSONElement batchElt = cursorObj[kBatchField];
    if (batchElt.eoo()) {
        batchElt = cursorObj[kBatchFieldInitial];
    }

    if (batchElt.type() != BSONType::Array) {
        return {ErrorCodes::TypeMismatch,
                str::stream() << "Must have array field '" << kBatchFieldInitial << "' or '"
                              << kBatchField << "' in: " << cmdResponse};
    }
    batchObj = batchElt.Obj();

    std::vector<BSONObj> batch;
    for (BSONElement elt : batchObj) {
        if (elt.type() != BSONType::Object) {
            return {
                ErrorCodes::BadValue,
                str::stream() << "getMore response batch contains a non-object element: " << elt};
        }

        batch.push_back(elt.Obj().getOwned());
    }

    return {{NamespaceString(fullns), cursorId, batch}};
}
Beispiel #24
0
    StatusWith<ShardType> ShardType::fromBSON(const BSONObj& source) {
        ShardType shard;

        {
            std::string shardName;
            Status status = bsonExtractStringField(source, name.name(), &shardName);
            if (!status.isOK()) return status;
            shard._name = shardName;
        }

        {
            std::string shardHost;
            Status status = bsonExtractStringField(source, host.name(), &shardHost);
            if (!status.isOK()) return status;
            shard._host = shardHost;
        }

        {
            bool isShardDraining;
            Status status = bsonExtractBooleanFieldWithDefault(source,
                                                               draining.name(),
                                                               false,
                                                               &isShardDraining);
            if (!status.isOK()) return status;
            shard._draining = isShardDraining;
        }

        {
            long long shardMaxSize;
            // maxSize == 0 means there's no limitation to space usage.
            Status status = bsonExtractIntegerFieldWithDefault(source,
                                                               maxSize.name(),
                                                               0,
                                                               &shardMaxSize);
            if (!status.isOK()) return status;
            shard._maxSize = shardMaxSize;
        }

        shard._tags = std::vector<std::string>();
        if (source.hasField(tags.name())) {
            BSONElement tagsElement;
            Status status = bsonExtractTypedField(source, tags.name(), Array, &tagsElement);
            if (!status.isOK()) return status;

            BSONObjIterator it(tagsElement.Obj());
            while (it.more()) {
                BSONElement tagElement = it.next();
                if (tagElement.type() != String) {
                    return Status(ErrorCodes::TypeMismatch,
                                  str::stream() << "Elements in \"" << tags.name()
                                                << "\" array must be strings but found "
                                                <<  typeName(tagElement.type()));
                }
                shard._tags->push_back(tagElement.String());
            }
        }

        return shard;
    }
Beispiel #25
0
Status ModifierRename::init(const BSONElement& modExpr, const Options& opts, bool* positional) {
    if (modExpr.type() != String) {
        return Status(ErrorCodes::BadValue,
                      str::stream() << "The 'to' field for $rename must be a string: " << modExpr);
    }

    if (modExpr.valueStringData().find('\0') != std::string::npos) {
        return Status(ErrorCodes::BadValue,
                      "The 'to' field for $rename cannot contain an embedded null byte");
    }

    // Extract the field names from the mod expression

    _fromFieldRef.parse(modExpr.fieldName());
    Status status = fieldchecker::isUpdatable(_fromFieldRef);
    if (!status.isOK())
        return status;

    _toFieldRef.parse(modExpr.String());
    status = fieldchecker::isUpdatable(_toFieldRef);
    if (!status.isOK())
        return status;

    // TODO: Remove this restriction and make a noOp to lift restriction
    // Old restriction is that if the fields are the same then it is not allowed.
    if (_fromFieldRef == _toFieldRef)
        return Status(ErrorCodes::BadValue,
                      str::stream() << "The source and target field for $rename must differ: "
                                    << modExpr);

    // TODO: Remove this restriction by allowing moving deeping from the 'from' path
    // Old restriction is that if the to/from is on the same path it fails
    if (_fromFieldRef.isPrefixOf(_toFieldRef) || _toFieldRef.isPrefixOf(_fromFieldRef)) {
        return Status(ErrorCodes::BadValue,
                      str::stream() << "The source and target field for $rename must "
                                       "not be on the same path: "
                                    << modExpr);
    }
    // TODO: We can remove this restriction as long as there is only one,
    //       or it is the same array -- should think on this a bit.
    //
    // If a $-positional operator was used it is an error
    size_t dummyPos;
    if (fieldchecker::isPositional(_fromFieldRef, &dummyPos))
        return Status(ErrorCodes::BadValue,
                      str::stream() << "The source field for $rename may not be dynamic: "
                                    << _fromFieldRef.dottedField());
    else if (fieldchecker::isPositional(_toFieldRef, &dummyPos))
        return Status(ErrorCodes::BadValue,
                      str::stream() << "The destination field for $rename may not be dynamic: "
                                    << _toFieldRef.dottedField());

    if (positional)
        *positional = false;

    return Status::OK();
}
Beispiel #26
0
    /* Do we have the newest data of them all?
       @param allUp - set to true if all members are up.  Only set if true returned.
       @return true if we are freshest.  Note we may tie.
    */
    bool Consensus::_weAreFreshest(bool& allUp, int& nTies) {
        const OpTime ord = theReplSet->lastOpTimeWritten;
        nTies = 0;
        verify( !ord.isNull() );
        BSONObj cmd = BSON(
                          "replSetFresh" << 1 <<
                          "set" << rs.name() <<
                          "opTime" << Date_t(ord.asDate()) <<
                          "who" << rs._self->fullName() <<
                          "cfgver" << rs._cfg->version <<
                          "id" << rs._self->id());
        list<Target> L;
        int ver;
        /* the following queries arbiters, even though they are never fresh.  wonder if that makes sense.
           it doesn't, but it could, if they "know" what freshness it one day.  so consider removing
           arbiters from getTargets() here.  although getTargets is used elsewhere for elections; there
           arbiters are certainly targets - so a "includeArbs" bool would be necessary if we want to make
           not fetching them herein happen.
           */
        rs.getTargets(L, ver);
        _multiCommand(cmd, L);
        int nok = 0;
        allUp = true;
        for( list<Target>::iterator i = L.begin(); i != L.end(); i++ ) {
            if( i->ok ) {
                nok++;
                if( i->result["fresher"].trueValue() ) {
                    log() << "not electing self, we are not freshest" << rsLog;
                    return false;
                }
                OpTime remoteOrd( i->result["opTime"].Date() );
                if( remoteOrd == ord )
                    nTies++;
                verify( remoteOrd <= ord );

                if( i->result["veto"].trueValue() ) {
                    BSONElement msg = i->result["errmsg"];
                    if (!msg.eoo()) {
                        log() << "not electing self, " << i->toHost << " would veto with '" <<
                            msg.String() << "'" << rsLog;
                    }
                    else {
                        log() << "not electing self, " << i->toHost << " would veto" << rsLog;
                    }
                    return false;
                }
            }
            else {
                DEV log() << "replSet freshest returns " << i->result.toString() << rsLog;
                allUp = false;
            }
        }
        LOG(1) << "replSet dev we are freshest of up nodes, nok:" << nok << " nTies:" << nTies << rsLog;
        verify( ord <= theReplSet->lastOpTimeWritten ); // <= as this may change while we are working...
        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());
    }
}
Status WiredTigerEngineRuntimeConfigParameter::set(const BSONElement& newValueElement) {
    try {
        return setFromString(newValueElement.String());
    }
    catch (MsgAssertionException msg) {
        return Status(ErrorCodes::BadValue, mongoutils::str::stream() <<
                "Invalid value for wiredTigerEngineRuntimeConfig via setParameter command: "
                << newValueElement);
    }
}
Beispiel #29
0
 string Command::parseNsFullyQualified(const string& dbname, const BSONObj& cmdObj) const {
     BSONElement first = cmdObj.firstElement();
     uassert(17005,
             mongoutils::str::stream() << "Main argument to " << first.fieldNameStringData() <<
                     " must be a fully qualified namespace string.  Found: " <<
                     first.toString(false),
             first.type() == mongo::String &&
             NamespaceString::validCollectionComponent(first.valuestr()));
     return first.String();
 }
Beispiel #30
0
    StatusWithMatchExpression MatchExpressionParser::_parseRegexDocument( const char* name,
                                                                const BSONObj& doc ) {
        string regex;
        string regexOptions;

        BSONObjIterator i( doc );
        while ( i.more() ) {
            BSONElement e = i.next();
            switch ( e.getGtLtOp() ) {
            case BSONObj::opREGEX:
                if ( e.type() == String ) {
                    regex = e.String();
                }
                else if ( e.type() == RegEx ) {
                    regex = e.regex();
                    regexOptions = e.regexFlags();
                }
                else {
                    return StatusWithMatchExpression( ErrorCodes::BadValue,
                                                      "$regex has to be a string" );
                }

                break;
            case BSONObj::opOPTIONS:
                if ( e.type() != String )
                    return StatusWithMatchExpression( ErrorCodes::BadValue,
                                                      "$options has to be a string" );
                regexOptions = e.String();
                break;
            default:
                break;
            }

        }

        std::auto_ptr<RegexMatchExpression> temp( new RegexMatchExpression() );
        Status s = temp->init( name, regex, regexOptions );
        if ( !s.isOK() )
            return StatusWithMatchExpression( s );
        return StatusWithMatchExpression( temp.release() );

    }