/* * After copying DB from partner, we need to derive UTDVector for new node from partner. * i.e. <whatever partner node current UTDVector> + <partner invoactionid:partner max commited USN> */ static DWORD _VmDirComposeUtdVector( PVMDIR_SWAP_DB_INFO pSwapDBInfo ) { DWORD dwError = 0; PVDIR_ENTRY pServerEntry = NULL; PVDIR_ATTRIBUTE pAttrUTDVector = NULL; PVDIR_ATTRIBUTE pAttrInvocationId = NULL; VDIR_OPERATION searchOp = {0}; dwError = VmDirInitStackOperation(&searchOp, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_SEARCH, NULL); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirInternalSearchSeverObj(pSwapDBInfo->pszOrgDBServerName, &searchOp); BAIL_ON_VMDIR_ERROR(dwError); pServerEntry = searchOp.internalSearchEntryArray.pEntry; pAttrUTDVector = VmDirEntryFindAttribute(ATTR_UP_TO_DATE_VECTOR, pServerEntry); pAttrInvocationId = VmDirEntryFindAttribute(ATTR_INVOCATION_ID, pServerEntry); dwError = _VmGetHighestCommittedUSN(&pSwapDBInfo->pszOrgDBMaxUSN); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "DB maxCommittedUSN %s", pSwapDBInfo->pszOrgDBMaxUSN); dwError = VmDirUTDVectorCacheInit(&pSwapDBInfo->pMyUTDVector); BAIL_ON_VMDIR_ERROR(dwError); if (pAttrUTDVector) { dwError = VmDirUTDVectorCacheReplace(pSwapDBInfo->pMyUTDVector, pAttrUTDVector->vals[0].lberbv.bv_val); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "DB UTDVector %s", pSwapDBInfo->pMyUTDVector->pszUtdVector); } dwError = VmDirUTDVectorCacheAdd( pSwapDBInfo->pMyUTDVector, pAttrInvocationId->vals[0].lberbv.bv_val, pSwapDBInfo->pszOrgDBMaxUSN); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "My UTDVector %s", pSwapDBInfo->pMyUTDVector->pszUtdVector); cleanup: VmDirFreeOperationContent(&searchOp); return dwError; error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "error (%u)", dwError); goto cleanup; }
static int GenerateDeleteAttrsMods( PVDIR_OPERATION pOperation, VDIR_ENTRY * pEntry ) { int retVal = 0; VDIR_MODIFICATION * delMod = NULL; VDIR_ATTRIBUTE * attr = NULL; PVDIR_ATTRIBUTE objectGuidAttr = NULL; VDIR_BERVALUE deletedObjDN = VDIR_BERVALUE_INIT; ModifyReq * modReq = &(pOperation->request.modifyReq); for ( attr = pEntry->attrs; attr != NULL; attr = attr->next ) { // Retain the following kind of attributes if (attr->pATDesc->usage != VDIR_ATTRIBUTETYPE_USER_APPLICATIONS || VmDirStringCompareA( attr->type.lberbv.bv_val, ATTR_OBJECT_CLASS, FALSE ) == 0) { continue; } retVal = VmDirAllocateMemory( sizeof( VDIR_MODIFICATION ), (PVOID *)&(delMod) ); BAIL_ON_VMDIR_ERROR( retVal ); delMod->operation = MOD_OP_DELETE; delMod->attr.next = NULL; delMod->attr.type = attr->type; delMod->attr.pATDesc = attr->pATDesc; delMod->attr.vals = NULL; delMod->attr.numVals = 0; delMod->next = modReq->mods; modReq->mods = delMod; modReq->numMods++; } // Add mod to set new DN. objectGuidAttr = VmDirEntryFindAttribute(ATTR_OBJECT_GUID, pEntry); assert( objectGuidAttr ); retVal = constructDeletedObjDN( &pOperation->request.deleteReq.dn, objectGuidAttr->vals[0].lberbv.bv_val, &deletedObjDN ); BAIL_ON_VMDIR_ERROR( retVal ); retVal = VmDirAppendAMod( pOperation, MOD_OP_REPLACE, ATTR_DN, ATTR_DN_LEN, deletedObjDN.lberbv.bv_val, deletedObjDN.lberbv.bv_len ); BAIL_ON_VMDIR_ERROR( retVal ); cleanup: VmDirFreeMemory( deletedObjDN.lberbv.bv_val ); return retVal; error: goto cleanup; }
static DWORD _VmDirComposeHighWaterMark( PVMDIR_SWAP_DB_INFO pSwapDBInfo ) { DWORD dwError = 0; PVDIR_ENTRY pServerEntry = NULL; PVDIR_ATTRIBUTE pAttrInvocationId = NULL; VDIR_OPERATION searchOp = {0}; USN hwmUSN = 0; dwError = VmDirInitStackOperation(&searchOp, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_SEARCH, NULL); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirInternalSearchSeverObj(pSwapDBInfo->pszPartnerServerName, &searchOp); BAIL_ON_VMDIR_ERROR(dwError); pServerEntry = searchOp.internalSearchEntryArray.pEntry; pAttrInvocationId = VmDirEntryFindAttribute(ATTR_INVOCATION_ID, pServerEntry); // use this node max originating usn as high water mark dwError = VmDirUTDVectorCacheLookup( pSwapDBInfo->pMyUTDVector, pAttrInvocationId->vals[0].lberbv_val, &hwmUSN); if (dwError == LW_STATUS_NOT_FOUND) { VMDIR_LOG_WARNING(VMDIR_LOG_MASK_ALL, "Partner (%s,%s) not found in ORG DB UTDVector (%s). Join scenario NOT supported.", pSwapDBInfo->pszPartnerServerName, pAttrInvocationId->vals[0].lberbv_val, pSwapDBInfo->pMyUTDVector->pszUtdVector); } BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringPrintf(&pSwapDBInfo->pszMyHighWaterMark, "%" PRId64, hwmUSN); BAIL_ON_VMDIR_ERROR(dwError); cleanup: VmDirFreeOperationContent(&searchOp); return dwError; error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "error (%u)", dwError); goto cleanup; }
int VmDirSendSearchEntry( PVDIR_OPERATION pOperation, PVDIR_ENTRY pSrEntry ) { int retVal = LDAP_SUCCESS; BerElementBuffer berbuf; BerElement * ber = (BerElement *) &berbuf; BOOLEAN bFreeBer = FALSE; ber_len_t iBlobSize = 0; BerValue lberBervEntryBlob = {0}; int nAttrs = 0; int nVals = 0; BOOLEAN attrMetaDataReqd = FALSE; SearchReq * sr = &(pOperation->request.searchReq); int i = 0; BOOLEAN nonTrivialAttrsInReplScope = FALSE; uint32_t iSearchReqSpecialChars = 0; PATTRIBUTE_META_DATA_NODE pAttrMetaData = NULL; int numAttrMetaData = 0; PVDIR_ATTRIBUTE pAttr = NULL; USN usnChanged = 0; PSTR pszLocalErrorMsg = NULL; if ( !pOperation || !pSrEntry ) { retVal = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(retVal); } pSrEntry->bSearchEntrySent = FALSE; // see if client request has "*" and/or "+" ("-" for userpassword internal to vmdir) // WEI TODO: when we have attribute level ACL check, this information will be useful // return result will depend on ACL each on each attribute client is asking before // generating a final result to send back SetSpecialReturnChar(&pOperation->request.searchReq, &iSearchReqSpecialChars); if ( pSrEntry->eId == DSE_ROOT_ENTRY_ID && pOperation->request.searchReq.attrs == NULL ) { // For ADSI, if no specific attributes requested of DSE ROOT search, // return ALL (include operational) attributes. iSearchReqSpecialChars |= LDAP_SEARCH_REQUEST_CHAR_OP; } // ACL check before processing/sending the current srEntry back retVal = VmDirSrvAccessCheck( pOperation, &pOperation->conn->AccessInfo, pSrEntry, VMDIR_RIGHT_DS_READ_PROP ); BAIL_ON_VMDIR_ERROR( retVal ); if ( pOperation->opType == VDIR_OPERATION_TYPE_INTERNAL ) { ; // no op in INTERNAL case } else { // If not replication, and showDeletedObjectsCtrl not present, => don't send back Deleted objects (tombstones). if (pOperation->syncReqCtrl == NULL && pOperation->showDeletedObjectsCtrl == NULL) { pAttr = VmDirEntryFindAttribute(ATTR_IS_DELETED, pSrEntry); if (pAttr) { if (VmDirStringCompareA((PSTR)pAttr->vals[0].lberbv.bv_val, VMDIR_IS_DELETED_TRUE_STR, FALSE) == 0) { goto cleanup; // Don't send this entry } } } // In case of replication request, skip certain updates if (pOperation->syncReqCtrl != NULL) { PVDIR_ATTRIBUTE pAttrUsnCreated = NULL; USN usnCreated = 0; USN limitUsn = 0; VMDIR_REPLICATION_AGREEMENT * replAgr = NULL; pAttr = VmDirEntryFindAttribute(ATTR_USN_CHANGED, pSrEntry); assert( pAttr != NULL ); usnChanged = VmDirStringToLA( pAttr->vals[0].lberbv.bv_val, NULL, 10); // Check if usnChanged is beyond successful replication update state limitUsn = VmDirdGetLimitLocalUsnToBeSupplied(); if (limitUsn != 0 && usnChanged >= limitUsn) { VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "SendSearchEntry: bug# 863244 RACE CONDITION encountered., " "usnChanged = %ld, limitLocalUsnToBeSupplied = %ld, skipping entry: %s", usnChanged, limitUsn, pSrEntry->dn.lberbv.bv_val ); goto cleanup; // Don't send this entry } // Check if usnChanged is beyond lowestPendingUncommittedUsn recorded at the beginning of replication search if (pOperation->lowestPendingUncommittedUsn != 0 && usnChanged >= pOperation->lowestPendingUncommittedUsn) { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: usnChanged = %ld, lowestPendingUncommittedUsn = %ld, " "skipping entry: %s", usnChanged, pOperation->lowestPendingUncommittedUsn, pSrEntry->dn.lberbv.bv_val ); goto cleanup; // Don't send this entry } // Don't send (skip) modifications to my server object, and my RAs pAttrUsnCreated = VmDirEntryFindAttribute(ATTR_USN_CREATED, pSrEntry); assert( pAttrUsnCreated != NULL ); usnCreated = VmDirStringToLA( pAttrUsnCreated->vals[0].lberbv.bv_val, NULL, 10); // Only send back creation of certain objects, and not their modifications. // Check if consumer has already seen the creation. If yes, we are dealing with mods, which should be skipped // for my server object, and my RAs // Note: Skipping mods for RAs and Server Objects will cause inconsistencies with replicas. But these // two types only have local scope regarding functional effects. But if we are looking up / processing // information for these two types of objects on a replica, we need to watch out for potential // inconsistencies against the original source. if (pOperation->syncReqCtrl->value.syncReqCtrlVal.intLastLocalUsnProcessed > usnCreated) { if (strcmp(pSrEntry->dn.bvnorm_val, gVmdirServerGlobals.serverObjDN.bvnorm_val) == 0) { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: Not sending modifications to my server object, DN: %s", gVmdirServerGlobals.serverObjDN.lberbv.bv_val ); goto cleanup; // Don't send this entry } for (replAgr = gVmdirReplAgrs; replAgr != NULL; replAgr = replAgr->next ) { if (strcmp(pSrEntry->dn.bvnorm_val, replAgr->dn.bvnorm_val) == 0) { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: Not sending modifications to my RA object, DN: %s", replAgr->dn.bvnorm_val ); goto cleanup; // Don't send this entry } } } // do not replicate DSE Root entry, because it is a "local" entry. if (pSrEntry->eId == DSE_ROOT_ENTRY_ID) { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: Not sending modifications to DSE Root entry, DN: %s", pSrEntry->dn.bvnorm_val ); goto cleanup; // Don't send this entry } } // Approximate calculation for the required ber size, because apart from lengths and strings, ber also includes // tags. if ( VmDirComputeEncodedEntrySize(pSrEntry, &nAttrs, &nVals, &iBlobSize) != 0 || VmDirAllocateMemory(iBlobSize, (PVOID*)&lberBervEntryBlob.bv_val) != 0 ) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "no memory"); } lberBervEntryBlob.bv_len = iBlobSize; ber_init2( ber, &lberBervEntryBlob, LBER_USE_DER ); // ber takes over lberBervEntryBlob.lberbv.bv_val ownership bFreeBer = TRUE; if ( ber_printf( ber, "{it{O{", pOperation->msgId, LDAP_RES_SEARCH_ENTRY, &pSrEntry->dn ) == -1) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendSearchEntry: ber_printf (to print msgId ...) failed" ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding msgId, RES_SEARCH_ENTRY, DN failed"); } // Determine if we need to send back the attribute metaData if ( pOperation->syncReqCtrl != NULL ) // Replication { attrMetaDataReqd = TRUE; } else // check if attrMetaData attribute has been requested explicitly. { if (sr->attrs != NULL) { for (i = 0; sr->attrs[i].lberbv.bv_val != NULL; i++) { if (VmDirStringCompareA( sr->attrs[i].lberbv.bv_val, ATTR_ATTR_META_DATA, FALSE) == 0) { attrMetaDataReqd = TRUE; break; } } } } if (attrMetaDataReqd) { if ((pOperation->pBEIF->pfnBEGetAllAttrsMetaData( pOperation->pBECtx, pSrEntry->eId, &pAttrMetaData, &numAttrMetaData )) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendSearchEntry: pfnBEGetAllAttrsMetaData failed for entryId: %ld", pSrEntry->eId); retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "pfnBEGetAllAttrsMetaData failed."); } // SJ-TBD: Following double for loop to be optimized // Copy attrMetaData to corresponding attributes for (i=0; i<numAttrMetaData; i++) { for ( pAttr = pSrEntry->attrs; pAttr != NULL; pAttr = pAttr->next) { if (pAttr->pATDesc->usAttrID == pAttrMetaData[i].attrID) { VmDirStringCpyA( pAttr->metaData, VMDIR_MAX_ATTR_META_DATA_LEN, pAttrMetaData[i].metaData ); pAttrMetaData[i].metaData[0] = '\0'; } } } } retVal = WriteAttributes( pOperation, pSrEntry, iSearchReqSpecialChars , ber, &pszLocalErrorMsg ); BAIL_ON_VMDIR_ERROR( retVal ); if (attrMetaDataReqd) { retVal = WriteMetaDataAttribute( pOperation, pSrEntry->attrs, numAttrMetaData, pAttrMetaData, ber, &nonTrivialAttrsInReplScope, &pszLocalErrorMsg ); BAIL_ON_VMDIR_ERROR( retVal ); } if (ber_printf( ber, "N}N}" ) == -1) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ber_printf (to terminate the entry and the complete search result entry message ...) failed" ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding terminating the entry failed."); } if ( pOperation->syncReqCtrl != NULL ) // Replication, => write Sync State Control { retVal = WriteSyncStateControl( pOperation, pSrEntry->attrs, ber, &pszLocalErrorMsg ); BAIL_ON_VMDIR_ERROR( retVal ); } if (ber_printf( ber, "N}" ) == -1) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ber_printf (to terminate the entry and the complete search result entry message ...) failed" );; retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding terminating the entry failed."); } if ((pOperation->syncReqCtrl == NULL) || (pOperation->syncReqCtrl != NULL && nonTrivialAttrsInReplScope )) { if (WriteBerOnSocket( pOperation->conn, ber ) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendSearchEntry: WriteBerOnSocket failed." ); retVal = LDAP_UNAVAILABLE; BAIL_ON_VMDIR_ERROR( retVal ); } pSrEntry->bSearchEntrySent = TRUE; sr->iNumEntrySent++; VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: Send entry: %s", pSrEntry->dn.lberbv.bv_val); } else { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: NOT Sending entry: %s %p %d", pSrEntry->dn.lberbv.bv_val, pOperation->syncReqCtrl, nonTrivialAttrsInReplScope); } // record max local usnChanged in syncControlDone if (pOperation->syncReqCtrl != NULL) { if (usnChanged > pOperation->syncDoneCtrl->value.syncDoneCtrlVal.intLastLocalUsnProcessed) { pOperation->syncDoneCtrl->value.syncDoneCtrlVal.intLastLocalUsnProcessed = usnChanged; } } retVal = LDAP_SUCCESS; } cleanup: if (bFreeBer) { ber_free_buf( ber ); } VMDIR_SAFE_FREE_MEMORY( pAttrMetaData ); VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return( retVal ); error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendSearchEntry failed DN=(%s), (%u)(%s)", (pSrEntry && pSrEntry->dn.lberbv.bv_val) ? pSrEntry->dn.lberbv.bv_val : "", retVal, VDIR_SAFE_STRING( pszLocalErrorMsg)); if ( !pOperation->ldapResult.pszErrMsg && pszLocalErrorMsg ) { pOperation->ldapResult.pszErrMsg = pszLocalErrorMsg; pszLocalErrorMsg = NULL; } goto cleanup; }
/* * Convert attrIndexDesc attribute into a VDIR_ATTR_INDEX_INSTANCE * and enable gVdirAttrIndexCache with version 0. */ DWORD VdirAttrIndexInitViaEntry( PVDIR_ENTRY pEntry ) { DWORD dwError = 0; DWORD dwCnt = 0; BOOLEAN bInLock = FALSE; PVDIR_ATTRIBUTE pAttr = NULL; PVDIR_ATTR_INDEX_INSTANCE pAttrIdxCache = NULL; USHORT usLive = gVdirAttrIndexGlobals.usLive; PVDIR_SCHEMA_CTX pSchemaCtx = NULL; assert(pEntry); dwError = VmDirSchemaCtxAcquire(&pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); assert(pSchemaCtx); pAttr = VmDirEntryFindAttribute( ATTR_INDEX_DESC, pEntry); assert(pAttr); dwError = VdirAttrIndexCacheAllocate( &pAttrIdxCache, pAttr->numVals); BAIL_ON_VMDIR_ERROR(dwError); for (dwCnt = 0; dwCnt < pAttr->numVals; dwCnt++) { VDIR_CFG_ATTR_INDEX_DESC indexDesc = {0}; dwError = VdirstrToAttrIndexDesc( pAttr->vals[dwCnt].lberbv.bv_val, &indexDesc); BAIL_ON_VMDIR_ERROR(dwError); // cache takes over indexDesc.pszAttrName pAttrIdxCache->pSortName[dwCnt].pszAttrName = indexDesc.pszAttrName; indexDesc.pszAttrName = NULL; pAttrIdxCache->pSortName[dwCnt].bIsUnique = indexDesc.bIsUnique; pAttrIdxCache->pSortName[dwCnt].iTypes = indexDesc.iTypes; pAttrIdxCache->pSortName[dwCnt].status = indexDesc.status; pAttrIdxCache->pSortName[dwCnt].bIsNumeric = VmDirSchemaAttrHasIntegerMatchingRule( pSchemaCtx, pAttrIdxCache->pSortName[dwCnt].pszAttrName); pAttrIdxCache->pSortName[dwCnt].iId = dwCnt; } qsort(pAttrIdxCache->pSortName, pAttrIdxCache->usNumIndex, sizeof(VDIR_CFG_ATTR_INDEX_DESC), VdirAttrIndexNameCmp); VMDIR_LOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex); // Set up a cache instance // In case there is no need to do bootstrape during server start up, usLive == 0 // is not assigned (i.e.: schema entry is found) if ((usLive == 0 && gVdirAttrIndexGlobals.pCaches[usLive] != NULL) || usLive > 0) { usLive++; } gVdirAttrIndexGlobals.pCaches[usLive] = pAttrIdxCache; gVdirAttrIndexGlobals.usLive = usLive; cleanup: VMDIR_UNLOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex); if (pSchemaCtx) { VmDirSchemaCtxRelease(pSchemaCtx); } return dwError; error: if (pAttrIdxCache) { VdirAttrIdxCacheFree(pAttrIdxCache); } goto cleanup; }
static int _VmDirSwapDB( PCSTR dbHomeDir, BOOLEAN bHasXlog) { int retVal = LDAP_SUCCESS; char dbExistingName[VMDIR_MAX_FILE_NAME_LEN] = {0}; char dbNewName[VMDIR_MAX_FILE_NAME_LEN] = {0}; PSTR pszLocalErrorMsg = NULL; int errorCode = 0; BOOLEAN bLegacyDataLoaded = FALSE; PVDIR_BACKEND_INTERFACE pBE = NULL; #ifndef _WIN32 const char fileSeperator = '/'; #else const char fileSeperator = '\\'; #endif // Shutdown backend pBE = VmDirBackendSelect(NULL); assert(pBE); VmDirdStateSet(VMDIRD_STATE_SHUTDOWN); VmDirIndexLibShutdown(); VmDirSchemaLibShutdown(); pBE->pfnBEShutdown(); VmDirBackendContentFree(pBE); // move .mdb files retVal = VmDirStringPrintFA( dbExistingName, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s%c%s", dbHomeDir, fileSeperator, LOCAL_PARTNER_DIR, fileSeperator, VMDIR_MDB_DATA_FILE_NAME); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "_VmDirSwapDB: VmDirStringPrintFA() call failed with error: %d", retVal ); retVal = VmDirStringPrintFA( dbNewName, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s", dbHomeDir, fileSeperator, VMDIR_MDB_DATA_FILE_NAME ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "_VmDirSwapDB: VmDirStringPrintFA() call failed with error: %d", retVal ); #ifdef WIN32 if (MoveFileEx(dbExistingName, dbNewName, MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING) == 0) { retVal = LDAP_OPERATIONS_ERROR; errorCode = GetLastError(); #else if (rename(dbExistingName, dbNewName) != 0) { retVal = LDAP_OPERATIONS_ERROR; errorCode = errno; #endif BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "_VmDirSwapDB: rename file from %s to %s failed, errno %d", dbExistingName, dbNewName, errorCode ); } retVal = VmDirStringPrintFA(dbNewName, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s%c%s", dbHomeDir, fileSeperator, VMDIR_MDB_XLOGS_DIR_NAME); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "_VmDirSwapDB: VmDirStringPrintFA() call failed with error: %d", retVal ); if (bHasXlog) { //move xlog directory retVal = VmDirStringPrintFA(dbExistingName, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s%c%s", dbHomeDir, fileSeperator, LOCAL_PARTNER_DIR, fileSeperator, VMDIR_MDB_XLOGS_DIR_NAME); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "_VmDirSwapDB: VmDirStringPrintFA() call failed with error: %d", retVal ); #ifdef WIN32 if (MoveFileEx(dbExistingName, dbNewName, MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING) == 0) { retVal = LDAP_OPERATIONS_ERROR; errorCode = GetLastError(); #else if (rmdir(dbNewName) != 0) { retVal = LDAP_OPERATIONS_ERROR; errorCode = errno; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "_VmDirSwapDB cannot remove directory %s, errno %d", dbNewName, errorCode); } if (rename(dbExistingName, dbNewName) != 0) { retVal = LDAP_OPERATIONS_ERROR; errorCode = errno; #endif BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "_VmDirSwapDB cannot move directory from %s to %s, errno %d", dbNewName, dbExistingName, errorCode); } } retVal = VmDirStringPrintFA(dbExistingName, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s", dbHomeDir, fileSeperator, LOCAL_PARTNER_DIR); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "_VmDirSwapDB: VmDirStringPrintFA() call failed with error: %d", retVal ); #ifdef WIN32 if (RemoveDirectory(dbExistingName)==0) { errorCode = GetLastError(); #else if (rmdir(dbExistingName)) { errorCode = errno; #endif VMDIR_LOG_WARNING(VMDIR_LOG_MASK_ALL, "cannot remove directory %s errno %d", dbExistingName, errorCode); } VmDirdStateSet(VMDIRD_STATE_STARTUP); retVal = VmDirInitBackend(&bLegacyDataLoaded); BAIL_ON_VMDIR_ERROR(retVal); if (bLegacyDataLoaded) { retVal = VmDirPatchLocalSubSchemaSubEntry(); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrorMsg, "_VmDirSwapDB: failed to patch subschema subentry: %d", retVal ); retVal = VmDirWriteSchemaObjects(); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrorMsg, "_VmDirSwapDB: failed to create schema tree: %d", retVal ); } VmDirdStateSet(VMDIRD_STATE_NORMAL); cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return retVal; error: retVal = LDAP_OPERATIONS_ERROR; VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s", VDIR_SAFE_STRING(pszLocalErrorMsg) ); goto cleanup; } static int _VmDirWrapUpFirstReplicationCycle( PCSTR pszHostname, VMDIR_REPLICATION_AGREEMENT * pReplAgr) { int retVal = LDAP_SUCCESS; PVDIR_ENTRY pPartnerServerEntry = NULL; PVDIR_ATTRIBUTE pAttrUpToDateVector = NULL; PVDIR_ATTRIBUTE pAttrInvocationId = NULL; USN localUsn = 0; USN partnerLocalUsn = 0; char partnerlocalUsnStr[VMDIR_MAX_USN_STR_LEN]; VDIR_BACKEND_CTX beCtx = {0}; struct berval syncDoneCtrlVal = {0}; PVDIR_SCHEMA_CTX pSchemaCtx = NULL; VDIR_OPERATION searchOp = {0}; PVDIR_FILTER pSearchFilter = NULL; PSTR pszSeparator = NULL; retVal = VmDirSchemaCtxAcquire(&pSchemaCtx); BAIL_ON_VMDIR_ERROR( retVal ); retVal = VmDirInitStackOperation( &searchOp, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_SEARCH, pSchemaCtx ); BAIL_ON_VMDIR_ERROR(retVal); searchOp.pBEIF = VmDirBackendSelect(NULL); assert(searchOp.pBEIF); searchOp.reqDn.lberbv.bv_val = ""; searchOp.reqDn.lberbv.bv_len = 0; searchOp.request.searchReq.scope = LDAP_SCOPE_SUBTREE; retVal = VmDirConcatTwoFilters(searchOp.pSchemaCtx, ATTR_CN, (PSTR) pszHostname, ATTR_OBJECT_CLASS, OC_DIR_SERVER, &pSearchFilter); BAIL_ON_VMDIR_ERROR(retVal); searchOp.request.searchReq.filter = pSearchFilter; retVal = VmDirInternalSearch(&searchOp); BAIL_ON_VMDIR_ERROR(retVal); if (searchOp.internalSearchEntryArray.iSize != 1) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "_VmDirWrapUpFirstReplicationCycle: Unexpected (not 1) number of partner server entries found (%d)", searchOp.internalSearchEntryArray.iSize ); retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR(retVal); } pPartnerServerEntry = searchOp.internalSearchEntryArray.pEntry; pAttrUpToDateVector = VmDirEntryFindAttribute( ATTR_UP_TO_DATE_VECTOR, pPartnerServerEntry ); pAttrInvocationId = VmDirEntryFindAttribute( ATTR_INVOCATION_ID, pPartnerServerEntry ); assert( pAttrInvocationId != NULL ); beCtx.pBE = VmDirBackendSelect(NULL); assert(beCtx.pBE); if ((retVal = beCtx.pBE->pfnBEGetNextUSN( &beCtx, &localUsn )) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "_VmDirWrapUpFirstReplicationCycle: pfnBEGetNextUSN failed with error code: %d, " "error message: %s", retVal, VDIR_SAFE_STRING(beCtx.pszBEErrorMsg) ); BAIL_ON_VMDIR_ERROR( retVal ); } retVal = _VmGetHighestCommittedUSN(localUsn, &partnerLocalUsn); BAIL_ON_VMDIR_ERROR( retVal ); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "_VmDirWrapUpFirstReplicationCycle: partnerLocalUsn %llu locaUsn %llu", partnerLocalUsn, localUsn); if ((retVal = VmDirStringNPrintFA( partnerlocalUsnStr, sizeof(partnerlocalUsnStr), sizeof(partnerlocalUsnStr) - 1, "%" PRId64, partnerLocalUsn)) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "_VmDirWrapUpFirstReplicationCycle: VmDirStringNPrintFA failed with error code: %d", retVal ); BAIL_ON_VMDIR_ERROR( retVal ); } if (pAttrUpToDateVector) { if (VmDirStringEndsWith( pAttrUpToDateVector->vals[0].lberbv.bv_val, ",", FALSE)) { pszSeparator = ""; } else { pszSeparator = ","; } // <partnerLocalUSN>,<partner up-to-date vector>,<partner server GUID>:<partnerLocalUSN>, retVal = VmDirAllocateStringPrintf( &(syncDoneCtrlVal.bv_val), "%s,%s%s%s:%s,", partnerlocalUsnStr, pAttrUpToDateVector->vals[0].lberbv.bv_val, pszSeparator, pAttrInvocationId->vals[0].lberbv.bv_val, partnerlocalUsnStr); BAIL_ON_VMDIR_ERROR(retVal); } else { // <partnerLocalUSN>,<partner server GUID>:<partnerLocalUSN>, retVal = VmDirAllocateStringPrintf( &(syncDoneCtrlVal.bv_val), "%s,%s:%s,", partnerlocalUsnStr, pAttrInvocationId->vals[0].lberbv.bv_val, partnerlocalUsnStr); BAIL_ON_VMDIR_ERROR(retVal); } VmDirSetACLMode(); syncDoneCtrlVal.bv_len = VmDirStringLenA(syncDoneCtrlVal.bv_val); if ((retVal = VmDirReplUpdateCookies( pSchemaCtx, &(syncDoneCtrlVal), pReplAgr )) != LDAP_SUCCESS) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "vdirReplicationThrFun: UpdateCookies failed. Error: %d", retVal ); BAIL_ON_VMDIR_ERROR( retVal ); } if ((retVal = _VmDirPatchDSERoot(pSchemaCtx)) != LDAP_SUCCESS) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "vdirReplicationThrFun: _VmDirPatchDSERoot failed. Error: %d", retVal ); BAIL_ON_VMDIR_ERROR( retVal ); } cleanup: VmDirFreeOperationContent(&searchOp); VmDirBackendCtxContentFree(&beCtx); VMDIR_SAFE_FREE_MEMORY(syncDoneCtrlVal.bv_val); VmDirSchemaCtxRelease(pSchemaCtx); return retVal; error: retVal = LDAP_OPERATIONS_ERROR; goto cleanup; } #ifndef VDIR_PSC_VERSION #define VDIR_PSC_VERSION "6.7.0" #endif static int _VmDirPatchDSERoot( PVDIR_SCHEMA_CTX pSchemaCtx) { int retVal = LDAP_SUCCESS; VDIR_OPERATION op = {0}; VDIR_BERVALUE bvDSERootDN = VDIR_BERVALUE_INIT; VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "_VmDirPatchDSERoot: Begin" ); bvDSERootDN.lberbv.bv_val = PERSISTED_DSE_ROOT_DN; bvDSERootDN.lberbv.bv_len = VmDirStringLenA( bvDSERootDN.lberbv.bv_val ); retVal = VmDirInitStackOperation( &op, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_MODIFY, pSchemaCtx ); BAIL_ON_VMDIR_ERROR(retVal); retVal = VmDirNormalizeDN( &bvDSERootDN, pSchemaCtx); BAIL_ON_VMDIR_ERROR(retVal); retVal = VmDirBervalContentDup( &bvDSERootDN, &op.reqDn ); BAIL_ON_VMDIR_ERROR(retVal); op.pBEIF = VmDirBackendSelect(op.reqDn.lberbv.bv_val); assert(op.pBEIF); if (VmDirBervalContentDup( &op.reqDn, &op.request.modifyReq.dn ) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "_VmDirPatchDSERoot: BervalContentDup failed." ); BAIL_ON_VMDIR_ERROR( retVal ); } retVal = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_DC_ACCOUNT_UPN, ATTR_DC_ACCOUNT_UPN_LEN, gVmdirServerGlobals.dcAccountUPN.lberbv.bv_val, gVmdirServerGlobals.dcAccountUPN.lberbv.bv_len ); BAIL_ON_VMDIR_ERROR( retVal ); retVal = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_DC_ACCOUNT_DN, ATTR_DC_ACCOUNT_DN_LEN, gVmdirServerGlobals.dcAccountDN.lberbv.bv_val, gVmdirServerGlobals.dcAccountDN.lberbv.bv_len ); BAIL_ON_VMDIR_ERROR( retVal ); retVal = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_SERVER_NAME, ATTR_SERVER_NAME_LEN, gVmdirServerGlobals.serverObjDN.lberbv.bv_val, gVmdirServerGlobals.serverObjDN.lberbv.bv_len ); BAIL_ON_VMDIR_ERROR( retVal ); retVal = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_SITE_NAME, ATTR_SITE_NAME_LEN, gVmdirServerGlobals.pszSiteName, VmDirStringLenA(gVmdirServerGlobals.pszSiteName) ); BAIL_ON_VMDIR_ERROR( retVal ); retVal = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_PSC_VERSION, ATTR_PSC_VERSION_LEN, VDIR_PSC_VERSION, VmDirStringLenA(VDIR_PSC_VERSION) ); BAIL_ON_VMDIR_ERROR( retVal ); retVal = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_MAX_DOMAIN_FUNCTIONAL_LEVEL, ATTR_MAX_DOMAIN_FUNCTIONAL_LEVEL_LEN, VMDIR_MAX_DFL_STRING, VmDirStringLenA(VMDIR_MAX_DFL_STRING) ); BAIL_ON_VMDIR_ERROR( retVal ); if ((retVal = VmDirInternalModifyEntry( &op )) != 0) { // If VmDirInternall call failed, reset retVal to LDAP level error space (for B/C) retVal = op.ldapResult.errCode; VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "_VmDirPatchDSERoot: InternalModifyEntry failed. " "Error code: %d, Error string: %s", retVal, VDIR_SAFE_STRING( op.ldapResult.pszErrMsg ) ); BAIL_ON_VMDIR_ERROR( retVal ); } cleanup: VmDirFreeOperationContent(&op); VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "_VmDirPatchDSERoot: End" ); return retVal; error: retVal = LDAP_OPERATIONS_ERROR; goto cleanup; }
/* * merge current and patch schema * 1. if new schema defined in patch, copy them over to current schema * 2. if both current and patch schema have schema definition, use value from patch schema * * The output is merged into pCurrentEntry. */ static DWORD VmDirSchemaPatchMerge( PVDIR_ENTRY pCurrentEntry, PVDIR_ENTRY pPatchEntry ) { DWORD dwError = 0; PVDIR_SCHEMA_INSTANCE pPatchSchema = NULL; PVDIR_ATTRIBUTE pAttr = NULL; USHORT usCnt = 0; dwError = _VmDirSchemaEntryToInstance( pPatchEntry, &pPatchSchema); BAIL_ON_VMDIR_ERROR(dwError); pAttr = VmDirEntryFindAttribute( VDIR_ATTRIBUTE_ATTRIBUTE_TYPES, pCurrentEntry ); assert( pAttr ); _VmDirSchemaNormalizeAttrValue( pAttr ); for (usCnt = 0; usCnt < pPatchSchema->ats.usNumATs; usCnt++) { PVDIR_SCHEMA_AT_DESC pATDesc = NULL; dwError = VmDirSchemaAttrNameToDescriptor( pCurrentEntry->pSchemaCtx, pPatchSchema->ats.pATSortName[ usCnt ].pszName, &pATDesc); if ( dwError == ERROR_NO_SUCH_ATTRIBUTE ) { dwError = VmDirEntryAddSingleValueStrAttribute( pCurrentEntry, VDIR_ATTRIBUTE_ATTRIBUTE_TYPES, pPatchSchema->ats.pATSortName[ usCnt ].pszDefinition); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Merge schema, add - %s", VDIR_SAFE_STRING(pPatchSchema->ats.pATSortName[ usCnt ].pszDefinition)); } else { dwError = _VmDirSchemaAttrReplaceValue( pAttr, pPatchSchema->ats.pATSortName[ usCnt ].pszName, pPatchSchema->ats.pATSortName[ usCnt ].pszDefinition); BAIL_ON_VMDIR_ERROR(dwError); } } pAttr = VmDirEntryFindAttribute( VDIR_ATTRIBUTE_OBJECT_CLASSES, pCurrentEntry ); assert( pAttr ); _VmDirSchemaNormalizeAttrValue( pAttr ); for (usCnt = 0; usCnt < pPatchSchema->ocs.usNumOCs; usCnt++) { PVDIR_SCHEMA_OC_DESC pOCDesc = NULL; dwError = VmDirSchemaOCNameToDescriptor( pCurrentEntry->pSchemaCtx, pPatchSchema->ocs.pOCSortName[ usCnt ].pszName, &pOCDesc); if ( dwError == ERROR_NO_SUCH_OBJECTCLASS ) { dwError = VmDirEntryAddSingleValueStrAttribute( pCurrentEntry, VDIR_ATTRIBUTE_OBJECT_CLASSES, pPatchSchema->ocs.pOCSortName[ usCnt ].pszDefinition); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Merge schema, add - %s", VDIR_SAFE_STRING(pPatchSchema->ocs.pOCSortName[ usCnt ].pszDefinition)); } else { dwError = _VmDirSchemaAttrReplaceValue( pAttr, pPatchSchema->ocs.pOCSortName[ usCnt ].pszName, pPatchSchema->ocs.pOCSortName[ usCnt ].pszDefinition); BAIL_ON_VMDIR_ERROR(dwError); } } pAttr = VmDirEntryFindAttribute( VDIR_ATTRIBUTE_DIT_CONTENTRULES, pCurrentEntry ); assert ( pAttr ); _VmDirSchemaNormalizeAttrValue( pAttr ); for (usCnt = 0; pAttr && usCnt < pPatchSchema->contentRules.usNumContents; usCnt++) { PVDIR_SCHEMA_CR_DESC pCRDesc = NULL; dwError = VmDirSchemaCRNameToDescriptor( pCurrentEntry->pSchemaCtx, pPatchSchema->contentRules.pContentSortName[ usCnt ].pszName, &pCRDesc); if ( dwError == ERROR_NO_SUCH_DITCONTENTRULES ) { dwError = VmDirEntryAddSingleValueStrAttribute( pCurrentEntry, VDIR_ATTRIBUTE_DIT_CONTENTRULES, pPatchSchema->contentRules.pContentSortName[ usCnt ].pszDefinition); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Merge schema, add - %s", VDIR_SAFE_STRING(pPatchSchema->contentRules.pContentSortName[ usCnt ].pszDefinition)); } else { dwError = _VmDirSchemaAttrReplaceValue( pAttr, pPatchSchema->contentRules.pContentSortName[ usCnt ].pszName, pPatchSchema->contentRules.pContentSortName[ usCnt ].pszDefinition); BAIL_ON_VMDIR_ERROR(dwError); } } cleanup: if ( pPatchSchema ) { VdirSchemaInstanceFree(pPatchSchema); } return dwError; error: goto cleanup; }