static int DeleteRefAttributesValue( VDIR_OPERATION * pOperation, VDIR_BERVALUE * dn ) { int retVal = LDAP_SUCCESS; VDIR_FILTER * f = NULL; VDIR_CANDIDATES * cl = NULL; VDIR_ENTRY groupEntry = {0}; VDIR_ENTRY * pGroupEntry = NULL; int i = 0; VDIR_MODIFICATION mod = {0}; ModifyReq mr; VDIR_BERVALUE delVals[2]; PSTR pszLocalErrorMsg = NULL; assert( pOperation != NULL && pOperation->pBEIF != NULL && dn != NULL); retVal = VmDirNormalizeDN( dn, pOperation->pSchemaCtx ); BAIL_ON_VMDIR_ERROR( retVal ); // Set filter retVal = VmDirAllocateMemory( sizeof( VDIR_FILTER ), (PVOID *)&f); BAIL_ON_VMDIR_ERROR( retVal ); f->choice = LDAP_FILTER_EQUALITY; f->filtComp.ava.type.lberbv.bv_val = ATTR_MEMBER; f->filtComp.ava.type.lberbv.bv_len = ATTR_MEMBER_LEN; f->filtComp.ava.value = *dn; if ((f->filtComp.ava.pATDesc = VmDirSchemaAttrNameToDesc( pOperation->pSchemaCtx, ATTR_MEMBER)) == NULL) { retVal = VMDIR_ERROR_NO_SUCH_ATTRIBUTE; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "undefined attribute (%s)", VDIR_SAFE_STRING(ATTR_MEMBER)); } // Set ModifyReq structure memset(&mr, 0, sizeof(ModifyReq)); mod.operation = MOD_OP_DELETE; mod.attr.type.lberbv.bv_val = ATTR_MEMBER; mod.attr.type.lberbv.bv_len = ATTR_MEMBER_LEN; mod.attr.pATDesc = f->filtComp.ava.pATDesc; mod.attr.next = NULL; delVals[0] = *dn; memset(&(delVals[1]), 0, sizeof(VDIR_BERVALUE)); mod.attr.vals = delVals; mod.attr.numVals = 1; mod.next = NULL; mr.mods = &mod; mr.numMods = 1; retVal = pOperation->pBEIF->pfnBEGetCandidates( pOperation->pBECtx, f); if ( retVal != 0 ) { if (retVal == VMDIR_ERROR_BACKEND_ENTRY_NOTFOUND) { retVal = LDAP_SUCCESS; // no member refer to this DN. return ok/0 } else { retVal = VMDIR_ERROR_GENERIC; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "DeleteRefAttributesValue: Building group list (BdbGetCandidates()) failed."); } } else { cl = f->candidates; for (i = 0; i < cl->size; i++) { pGroupEntry = &groupEntry; if ((retVal = VmDirModifyEntryCoreLogic( pOperation, &mr, cl->eIds[i], pGroupEntry)) != 0) { switch (retVal) { case VMDIR_ERROR_BACKEND_PARENT_NOTFOUND: case VMDIR_ERROR_BACKEND_ENTRY_NOTFOUND: case VMDIR_ERROR_ENTRY_NOT_FOUND: continue; default: // Including LDAP_LOCK_DEADLOCK, which is handled by the caller BAIL_ON_VMDIR_ERROR( retVal ); } } VmDirFreeBervalContent( &(mr.dn) ); // VmDirModifyEntryCoreLogic fill in DN if not exists VmDirFreeEntryContent( pGroupEntry ); pGroupEntry = NULL; // Reset to NULL so that DeleteEntry is no-op. } } cleanup: memset(&(f->filtComp.ava.value), 0, sizeof(VDIR_BERVALUE)); // Since ava.value is NOT owned by filter. DeleteFilter( f ); VmDirFreeEntryContent( pGroupEntry ); VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return retVal; error: VMDIR_APPEND_ERROR_MSG(pOperation->ldapResult.pszErrMsg, pszLocalErrorMsg); goto cleanup; }
/* VmDirInternalModifyEntry: Interface that can be used "internally" by the server code, e.g. to modify schema, indices, * config etc. entries in the BDB store. One of the main differences between this function and MLModify is that * this function does not send back an LDAP result to the client. * * Return: VmDir level error code. Also, pOperation->ldapResult content is set. */ int VmDirInternalModifyEntry( PVDIR_OPERATION pOperation ) { int retVal = LDAP_SUCCESS; VDIR_ENTRY entry = {0}; PVDIR_ENTRY pEntry = NULL; ModifyReq* modReq = NULL; ENTRYID entryId = 0; BOOLEAN bHasTxn = FALSE; PSTR pszLocalErrMsg = NULL; PVDIR_OPERATION_ML_METRIC pMLMetrics = NULL; assert(pOperation && pOperation->pBEIF); pMLMetrics = &pOperation->MLMetrics; VMDIR_COLLECT_TIME(pMLMetrics->iMLStartTime); if (VmDirdState() == VMDIRD_STATE_READ_ONLY) { retVal = VMDIR_ERROR_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Server in read-only mode"); } modReq = &(pOperation->request.modifyReq); // make sure we have minimum DN length if (modReq->dn.lberbv_len < 3) { retVal = VMDIR_ERROR_INVALID_REQUEST; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Invalid DN length - (%u)", modReq->dn.lberbv_len); } // Normalize DN retVal = VmDirNormalizeDN(&(modReq->dn), pOperation->pSchemaCtx); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "DN normalization failed - (%u)(%s)", retVal, VDIR_SAFE_STRING(VmDirSchemaCtxGetErrorMsg(pOperation->pSchemaCtx))); // Acquire schema modification mutex retVal = VmDirSchemaModMutexAcquire(pOperation); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Failed to lock schema mod mutex", retVal); if (pOperation->opType != VDIR_OPERATION_TYPE_REPL) { // Generate mods based on MODN request retVal = VmDirGenerateRenameAttrsMods(pOperation); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "GenerateDeleteAttrsMods failed - (%u)", retVal); } VMDIR_COLLECT_TIME(pMLMetrics->iBETxnBeginStartTime); retVal = pOperation->pBEIF->pfnBETxnBegin(pOperation->pBECtx, VDIR_BACKEND_TXN_WRITE, &bHasTxn); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn begin (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); VMDIR_COLLECT_TIME(pMLMetrics->iBETxnBeginEndTime); if (bHasTxn) { retVal = VmDirValidateOp(pOperation, __func__); BAIL_ON_VMDIR_ERROR(retVal); } // Execute pre modify plugin logic VMDIR_COLLECT_TIME(pMLMetrics->iPrePluginsStartTime); retVal = VmDirExecutePreModApplyModifyPlugins(pOperation, NULL, retVal); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "PreModApplyModify plugin failed - (%u)", retVal); VMDIR_COLLECT_TIME(pMLMetrics->iPrePlugunsEndTim); // Normalize attribute values in mods retVal = VmDirNormalizeMods(pOperation->pSchemaCtx, modReq->mods, &pszLocalErrMsg); BAIL_ON_VMDIR_ERROR(retVal); // Read current entry from DB retVal = pOperation->pBEIF->pfnBEDNToEntryId(pOperation->pBECtx, &(modReq->dn), &entryId); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "BEEntryModify (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); pEntry = &entry; retVal = VmDirModifyEntryCoreLogic( pOperation, &pOperation->request.modifyReq, entryId, pOperation->bNoRaftLog, pEntry); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "CoreLogicModifyEntry failed. (%u)", retVal); if (bHasTxn) { VMDIR_COLLECT_TIME(pMLMetrics->iBETxnCommitStartTime); retVal = pOperation->pBEIF->pfnBETxnCommit(pOperation->pBECtx); bHasTxn = FALSE; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn commit logIndex %llu (%u)(%s)", pOperation->logIndex, retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); VMDIR_COLLECT_TIME(pMLMetrics->iBETxnCommitEndTime); } if (!pOperation->bSuppressLogInfo) { VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Modify Entry (%s) blob size %d logIndex %llu", VDIR_SAFE_STRING(pEntry->dn.lberbv_val), pEntry->encodedSize, pOperation->logIndex); } cleanup: if (retVal == 0) { int iPostCommitPluginRtn = 0; VMDIR_COLLECT_TIME(pMLMetrics->iPostPluginsStartTime); // Execute post modify plugin logic iPostCommitPluginRtn = VmDirExecutePostModifyCommitPlugins(pOperation, &entry, retVal); if (iPostCommitPluginRtn != LDAP_SUCCESS && iPostCommitPluginRtn != pOperation->ldapResult.errCode) // pass through { VMDIR_LOG_ERROR( LDAP_DEBUG_ANY, "InternalModifyEntry: VdirExecutePostModifyCommitPlugins - code(%d)", iPostCommitPluginRtn); } VMDIR_COLLECT_TIME(pMLMetrics->iPostPlugunsEndTime); } // Release schema modification mutex (VOID)VmDirSchemaModMutexRelease(pOperation); // collect metrics VMDIR_COLLECT_TIME(pMLMetrics->iMLEndTime); VmDirInternalMetricsUpdate(pOperation); VmDirInternalMetricsLogInefficientOp(pOperation); VmDirFreeEntryContent(&entry); VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return retVal; error: if (bHasTxn) { pOperation->pBEIF->pfnBETxnAbort(pOperation->pBECtx); } VMDIR_SET_LDAP_RESULT_ERROR(&pOperation->ldapResult, retVal, pszLocalErrMsg); goto cleanup; }