예제 #1
0
/*
 * Convenient function to add a single attribute to pEntry.
 */
DWORD
VmDirEntryAddSingleValueAttribute(
    PVDIR_ENTRY pEntry,
    PCSTR pszAttrName,
    PCSTR pszAttrValue,
    size_t   iAttrValueLen
    )
{
    DWORD dwError = 0;
    PVDIR_ATTRIBUTE pAttr = NULL;

    if (!pEntry || !pEntry->pSchemaCtx || !pszAttrName || !pszAttrValue || iAttrValueLen < 1)
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    dwError = VmDirAttributeAllocate(
                pszAttrName,
                1,
                pEntry->pSchemaCtx,
                &pAttr);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirAllocateMemory(
            iAttrValueLen + 1,                  // want string null terminated.
            (PVOID*)&pAttr->vals[0].lberbv.bv_val );
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirCopyMemory(
        pAttr->vals[0].lberbv.bv_val,
        (iAttrValueLen + 1),
        (PCVOID)pszAttrValue,
        iAttrValueLen
    );
    BAIL_ON_VMDIR_ERROR(dwError);

    pAttr->vals[0].bOwnBvVal = TRUE;
    pAttr->vals[0].lberbv.bv_len = iAttrValueLen;

    dwError = VmDirEntryAddAttribute(
                pEntry,
                pAttr);
    BAIL_ON_VMDIR_ERROR(dwError);
    pAttr = NULL;

cleanup:

    return dwError;

error:

    if (pAttr)
    {
        VmDirFreeAttribute(pAttr);
    }

    goto cleanup;
}
예제 #2
0
/*
 * Create an Attribute on the heap and establish its pATDesc
 * two memory allocate
 * 1. pAttribute
 * 2. pAttribute->vals (BerValue array is one more then requested)
 */
DWORD
VmDirAttributeAllocate(
    PCSTR   pszName,
    USHORT  usBerSize,
    PVDIR_SCHEMA_CTX pCtx,
    PVDIR_ATTRIBUTE* ppOutAttr)
{
    DWORD    dwError = 0;
    PVDIR_ATTRIBUTE    pAttr = NULL;

    if (!ppOutAttr)
    {
        return 0;
    }

    dwError = VmDirAllocateMemory(
            sizeof(VDIR_ATTRIBUTE),
            (PVOID*)&pAttr);
    BAIL_ON_VMDIR_ERROR(dwError);

    // add one more BerValue as Encode/Decode entry in data store layer needs it.
    dwError = VmDirAllocateMemory(
            sizeof(VDIR_BERVALUE) * (usBerSize + 1),
            (PVOID*)&pAttr->vals);
    BAIL_ON_VMDIR_ERROR(dwError);

    pAttr->numVals = usBerSize;

    pAttr->pATDesc = VmDirSchemaAttrNameToDesc(
                    pCtx,
                    pszName);
    if (!pAttr->pATDesc)
    {
        dwError = VMDIR_ERROR_NO_SUCH_ATTRIBUTE;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    // pAttr->type.lberbv.bv_val always store in-place
    pAttr->type.lberbv.bv_val = pAttr->pATDesc->pszName;
    pAttr->type.lberbv.bv_len = VmDirStringLenA(pAttr->type.lberbv.bv_val);

    *ppOutAttr = pAttr;

cleanup:

    return dwError;

error:

    if (pAttr)
    {
        VmDirFreeAttribute(pAttr);
    }

    VmDirLog( LDAP_DEBUG_ANY, "AllocateAttribute failed (%d)(%s)",
              dwError, VDIR_SAFE_STRING(pszName));

    goto cleanup;
}
예제 #3
0
파일: init.c 프로젝트: divyamehta/lightwave
static
DWORD
schemaInitFillAttrFromCache(
    PVDIR_SCHEMA_CTX    pCtx,
    PSTR*    ppszValues,
    USHORT   dwValueSize,
    PSTR     pszAttrName,
    PVDIR_ENTRY   pEntry
    )
{
    DWORD dwError = 0;
    DWORD dwCnt = 0;
    VDIR_ATTRIBUTE* pAttr = NULL;

    dwError = VmDirAttributeAllocate(
            pszAttrName,
            dwValueSize,
            pCtx,
            &pAttr);
    BAIL_ON_VMDIR_ERROR(dwError);

    for (dwCnt = 0; dwCnt < dwValueSize; dwCnt++)
    {
        char* pszStr = &ppszValues[dwCnt][0];

        //ignore leading spaces
        while (*pszStr == ' ') pszStr++;

        dwError = VmDirAllocateStringA(
                ppszValues[dwCnt],
                &pAttr->vals[dwCnt].lberbv.bv_val);
        BAIL_ON_VMDIR_ERROR(dwError);

        pAttr->vals[dwCnt].bOwnBvVal = TRUE;
        pAttr->vals[dwCnt].lberbv.bv_len = VmDirStringLenA(pAttr->vals[dwCnt].lberbv.bv_val);
    }

    dwError = VmDirEntryAddAttribute(
            pEntry,
            pAttr);
    BAIL_ON_VMDIR_ERROR(dwError);
    pAttr = NULL;

cleanup:

    return dwError;

error:

    if (pAttr)
    {
        VmDirFreeAttribute(pAttr);
    }

    goto cleanup;
}
예제 #4
0
/*
 * FROM and TO Attributes use same schema context
 */
DWORD
VmDirAttributeDup(
    PVDIR_ATTRIBUTE  pAttr,
    PVDIR_ATTRIBUTE* ppDupAttr
    )
{
    DWORD   dwError = 0;
    DWORD   dwCnt = 0;
    PVDIR_ATTRIBUTE    pAttribute = NULL;

    assert(pAttr && ppDupAttr);

    dwError = VmDirAllocateMemory(
            sizeof(VDIR_ATTRIBUTE),
            (PVOID*)&pAttribute);
    BAIL_ON_VMDIR_ERROR(dwError);

    // add one more BerValue as Encode/Decode entry in data store layer needs it.
    dwError = VmDirAllocateMemory(
            sizeof(VDIR_BERVALUE) * (pAttr->numVals + 1),
            (PVOID*)&pAttribute->vals);
    BAIL_ON_VMDIR_ERROR(dwError);

    for (dwCnt = 0 ; dwCnt < pAttr->numVals; dwCnt++)
    {
        dwError = VmDirBervalContentDup(
                &pAttr->vals[dwCnt],
                &pAttribute->vals[dwCnt]);
        BAIL_ON_VMDIR_ERROR(dwError);

        pAttribute->numVals = dwCnt + 1;
    }

    // use the same pATDesc and type from pAttr
    pAttribute->pATDesc = pAttr->pATDesc;
    // type.lberbv.bv_val always store in-place
    pAttribute->type.lberbv.bv_val = pAttr->pATDesc->pszName;
    pAttribute->type.lberbv.bv_len = VmDirStringLenA(pAttr->type.lberbv.bv_val);

    *ppDupAttr = pAttribute;

cleanup:

    return dwError;

error:

    if (pAttribute)
    {
        VmDirFreeAttribute(pAttribute);
    }

    goto cleanup;
}
예제 #5
0
파일: check.c 프로젝트: Dan-McGee/lightwave
static
DWORD
_VmDirSchemaComputeAllowedChildClassesEffective(
    PVDIR_ENTRY         pEntry,
    PVDIR_ATTRIBUTE*    ppOutAttr
    )
{
    DWORD                   dwError = 0;
    PVDIR_SCHEMA_OC_DESC    pStructureOCDesc = NULL;
    PVDIR_ATTRIBUTE         pLocalAttr = NULL;
    int                     iCnt = 0;

    dwError = VmDirSchemaGetEntryStructureOCDesc( pEntry,
                                                   &pStructureOCDesc );
    BAIL_ON_VMDIR_ERROR(dwError);
    if ( !pStructureOCDesc )
    {
        dwError = ERROR_INVALID_ENTRY;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    for (iCnt = 0; pStructureOCDesc->ppszAllowedChildOCs && pStructureOCDesc->ppszAllowedChildOCs[iCnt]; iCnt++) {}

    if (iCnt > 0)
    {
        dwError = VmDirAttributeAllocate( ATTR_ALLOWD_CHILD_CLASSES_EFFECTIVE,
                                          iCnt,
                                          pEntry->pSchemaCtx,
                                          &pLocalAttr);
        BAIL_ON_VMDIR_ERROR(dwError);

        for (iCnt = 0; pStructureOCDesc->ppszAllowedChildOCs[iCnt]; iCnt++)
        {
            dwError = VmDirAllocateStringA( pStructureOCDesc->ppszAllowedChildOCs[iCnt],
                                            &(pLocalAttr->vals[iCnt].lberbv_val));
            BAIL_ON_VMDIR_ERROR(dwError);

            pLocalAttr->vals[iCnt].lberbv_len = VmDirStringLenA(pLocalAttr->vals[iCnt].lberbv_val);
            pLocalAttr->vals[iCnt].bOwnBvVal = TRUE;
        }
    }

    *ppOutAttr = pLocalAttr;

cleanup:

    return dwError;

error:

    VmDirFreeAttribute( pLocalAttr );

    goto cleanup;
}
예제 #6
0
/*
 * Remove an attribute of an entry.
 * Only handle ENTRY_STORAGE_FORMAT_NORMAL.
 */
DWORD
VmDirEntryRemoveAttribute(
    PVDIR_ENTRY     pEntry,
    PCSTR           pszName
    )
{
    DWORD               dwError = 0;
    PVDIR_ATTRIBUTE     pAttr = NULL;
    PVDIR_ATTRIBUTE     pPrevAttr = NULL;

    if (!pEntry || !pszName || pEntry->allocType != ENTRY_STORAGE_FORMAT_NORMAL)
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    for (pAttr = pEntry->attrs; pAttr; pAttr = pAttr->next)
    {
        if (VmDirStringCompareA(pAttr->pATDesc->pszName, pszName, FALSE) == 0)
        {
            break;
        }

        pPrevAttr = pAttr;
    }

    if (pAttr)
    {
        if (pPrevAttr)
        {
            pPrevAttr->next = pAttr->next;
        }
        else
        {
            assert(pAttr == pEntry->attrs);
            pEntry->attrs = pAttr->next;
        }

        VmDirFreeAttribute(pAttr);
    }

cleanup:

    return dwError;

error:

    goto cleanup;
}
예제 #7
0
/*
 * FROM and TO Attributes use same schema context
 */
DWORD
VmDirAttributeDup(
    PVDIR_ATTRIBUTE     pAttr,
    PVDIR_ATTRIBUTE*    ppDupAttr
    )
{
    DWORD              dwError = 0;
    DWORD              dwCnt = 0;
    PVDIR_ATTRIBUTE    pAttribute = NULL;

    if (!pAttr || !ppDupAttr)
    {
        BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER);
    }

    dwError = VmDirAllocateMemory(sizeof(VDIR_ATTRIBUTE), (PVOID*)&pAttribute);
    BAIL_ON_VMDIR_ERROR(dwError);

    // add one more BerValue as Encode/Decode entry in data store layer needs it.
    dwError = VmDirAllocateMemory(
            sizeof(VDIR_BERVALUE) * (pAttr->numVals + 1),
            (PVOID*)&pAttribute->vals);
    BAIL_ON_VMDIR_ERROR(dwError);

    for (dwCnt = 0 ; dwCnt < pAttr->numVals; dwCnt++)
    {
        dwError = VmDirBervalContentDup(&pAttr->vals[dwCnt], &pAttribute->vals[dwCnt]);
        BAIL_ON_VMDIR_ERROR(dwError);

        pAttribute->numVals = dwCnt + 1;
    }

    // use the same pATDesc and type from pAttr
    pAttribute->pATDesc = pAttr->pATDesc;

    dwError = VmDirBervalContentDup(&pAttr->type, &pAttribute->type);
    BAIL_ON_VMDIR_ERROR(dwError);

    *ppDupAttr = pAttribute;

cleanup:
    return dwError;

error:
    VmDirFreeAttribute(pAttribute);
    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "failed, error (%d)", dwError);
    goto cleanup;
}
예제 #8
0
/*
 * Add an array of bervalue attribute values into an entry.
 */
DWORD
VmDirEntryAddBervArrayAttribute(
    PVDIR_ENTRY     pEntry,
    PCSTR           pszAttrName,
    VDIR_BERVARRAY  attrVals,
    USHORT          usNumVals
    )
{
    DWORD           dwError = 0;
    PVDIR_ATTRIBUTE pAttr = NULL;
    USHORT          usCnt = 0;

    if (!pEntry || !pEntry->pSchemaCtx || !pszAttrName || !attrVals)
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    if (usNumVals)
    {
        dwError = VmDirAttributeAllocate(
                pszAttrName,
                usNumVals,
                pEntry->pSchemaCtx,
                &pAttr);
        BAIL_ON_VMDIR_ERROR(dwError);

        for (usCnt=0; usCnt < usNumVals; usCnt++)
        {
            dwError = VmDirBervalContentDup(
                    &attrVals[usCnt], &pAttr->vals[usCnt]);
            BAIL_ON_VMDIR_ERROR(dwError);
        }

        dwError = VmDirEntryAddAttribute(pEntry, pAttr);
        BAIL_ON_VMDIR_ERROR(dwError);
    }

cleanup:
    return dwError;

error:
    VmDirFreeAttribute(pAttr);
    goto cleanup;
}
예제 #9
0
/*
 * replace attribute in pEntry if such attribute exists.
 * pEntry takes over ownership of pNewAttr if success.
 */
DWORD
VmDirEntryReplaceAttribute(
    PVDIR_ENTRY     pEntry,
    PVDIR_ATTRIBUTE pNewAttr)
{
    DWORD   dwError = 0;
    BOOLEAN bFound = FALSE;
    PVDIR_ATTRIBUTE  pAttr = NULL;
    PVDIR_ATTRIBUTE  pPriorAttr = NULL;

    assert ( pEntry && pEntry->allocType == ENTRY_STORAGE_FORMAT_NORMAL && pNewAttr);

    for ( pAttr = pEntry->attrs;
          pAttr;
          pPriorAttr = pAttr, pAttr = pAttr->next
        )
    {
        if (0 == VmDirStringCompareA(pAttr->type.lberbv.bv_val, pNewAttr->type.lberbv.bv_val, FALSE))
        {
            if ( pEntry->attrs == pAttr )
            {
                pEntry->attrs = pNewAttr;
            }
            else
            {
                pPriorAttr->next = pNewAttr;
            }
            pNewAttr->next = pAttr->next;

            VmDirFreeAttribute(pAttr);
            bFound = TRUE;
            break;
        }
    }

    if ( bFound == FALSE )
    {
        dwError = VMDIR_ERROR_NO_SUCH_ATTRIBUTE;
    }

    return dwError;
}
예제 #10
0
void
VmDirFreeEntryContent(
   VDIR_ENTRY * e
   )
{
   VmDirLog( LDAP_DEBUG_TRACE, "DeleteEntry: Begin" );

   if ( e )
   {
      VmDirLog( LDAP_DEBUG_TRACE, "DeleteEntry: DN = %s",
              e ? (e->dn.lberbv.bv_val ? e->dn.lberbv.bv_val : "") : "" );

      if (e->pParentEntry)
      {
          VmDirFreeEntryContent(e->pParentEntry);
          VMDIR_SAFE_FREE_MEMORY(e->pParentEntry);
      }

      VmDirFreeLDAPDNContent( &(e->ldapDN) );
      VmDirFreeBervalContent( &(e->dn) );
      VmDirFreeBervalContent( &(e->pdn) );
      VmDirFreeBervalContent( &(e->newpdn) );

      if (e->allocType == ENTRY_STORAGE_FORMAT_PACK)
      {
         PVDIR_ATTRIBUTE    pCurrAttr = NULL;
         PVDIR_ATTRIBUTE    pTempAttr = NULL;

         pCurrAttr = e->attrs;
         while(pCurrAttr != NULL)
         {
             pTempAttr = pCurrAttr->next;
             VmDirFreeMetaData(pCurrAttr->pMetaData);
             pCurrAttr = pTempAttr;
         }
         VMDIR_SAFE_FREE_MEMORY( e->encodedEntry );
         VmDirFreeBervalArrayContent(e->bvs, e->usNumBVs);
         VMDIR_SAFE_FREE_MEMORY( e->bvs );
         VMDIR_SAFE_FREE_MEMORY( e->savedAttrsPtr );
      }
      else if (e->allocType == ENTRY_STORAGE_FORMAT_NORMAL)
      {
         VDIR_ATTRIBUTE * currAttr = NULL;
         VDIR_ATTRIBUTE * tmpAttr = NULL;

         VMDIR_SAFE_FREE_MEMORY( e->encodedEntry );

         for (currAttr = e->attrs; currAttr != NULL; )
         {
            tmpAttr = currAttr->next;
            VmDirFreeAttribute(currAttr);
            currAttr = tmpAttr;
         }
      }

      if (e->pComputedAttrs)
      {
          VDIR_ATTRIBUTE * currAttr = NULL;
          VDIR_ATTRIBUTE * tmpAttr = NULL;

          for (currAttr = e->pComputedAttrs; currAttr != NULL; )
          {
             tmpAttr = currAttr->next;
             VmDirFreeAttribute(currAttr);
             currAttr = tmpAttr;
          }
      }

      VmDirSchemaCtxRelease(e->pSchemaCtx);
      VmDirAclCtxContentFree(e->pAclCtx);
      VMDIR_SAFE_FREE_MEMORY(e->pAclCtx);
      VMDIR_SAFE_FREE_MEMORY(e->pszGuid);

      memset(e, 0, sizeof(*e));
   }

   VmDirLog( LDAP_DEBUG_TRACE, "DeleteEntry: End" );
}
예제 #11
0
파일: modify.c 프로젝트: vmware/lightwave
int
VmDirModifyEntryCoreLogic(
    VDIR_OPERATION *    pOperation, /* IN */
    ModifyReq *         modReq, /* IN */
    ENTRYID             entryId, /* IN */
    BOOLEAN             bNoRaftLog, /* IN */
    VDIR_ENTRY *        pEntry  /* OUT */
    )
{
    int       retVal = LDAP_SUCCESS;
    PSTR      pszLocalErrMsg = NULL;
    BOOLEAN   bDnModified = FALSE;
    BOOLEAN   bLeafNode = FALSE;
    PVDIR_ATTRIBUTE pAttrMemberOf = NULL;
    extern DWORD VmDirModifyRaftPreCommit(PVDIR_SCHEMA_CTX, ENTRYID, char *, PVDIR_MODIFICATION, PVDIR_OPERATION);

    retVal = pOperation->pBEIF->pfnBEIdToEntry(
            pOperation->pBECtx,
            pOperation->pSchemaCtx,
            entryId,
            pEntry,
            VDIR_BACKEND_ENTRY_LOCK_WRITE);
    BAIL_ON_VMDIR_ERROR(retVal);

    if (pOperation->pCondWriteCtrl)
    {
        retVal = VmDirMatchEntryWithFilter(
                pOperation,
                pEntry,
                pOperation->pCondWriteCtrl->value.condWriteCtrlVal.pszFilter);
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "Conditional Write pre-conditions (%s) failed - (%d)",
                VDIR_SAFE_STRING(pOperation->pCondWriteCtrl->value.condWriteCtrlVal.pszFilter),
                retVal);
    }

    if (modReq->dn.lberbv.bv_val == NULL) // If not already set by the caller
    {   // e.g. delete membership case via index lookup to get EID.
        retVal = VmDirBervalContentDup(&pEntry->dn, &modReq->dn);
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "VmDirBervalContentDup failed - (%d)",
                retVal);
    }

    retVal = VmDirSrvAccessCheck(
            pOperation,
            &pOperation->conn->AccessInfo,
            pEntry,
            VMDIR_RIGHT_DS_WRITE_PROP);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "VmDirSrvAccessCheck failed - (%u)",
            retVal);

    // Apply modify operations to the current entry (in pack format)
    retVal = VmDirApplyModsToEntryStruct(
            pOperation->pSchemaCtx, modReq, pEntry, &bDnModified, &pszLocalErrMsg);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "ApplyModsToEntryStruct failed - (%d)(%s)",
            retVal,
            pszLocalErrMsg);

    if (bDnModified)
    {
        retVal = pOperation->pBEIF->pfnBEChkIsLeafEntry(
                pOperation->pBECtx, entryId, &bLeafNode);
        BAIL_ON_VMDIR_ERROR(retVal);

        if (bLeafNode == FALSE)
        {
            retVal = LDAP_NOT_ALLOWED_ON_NONLEAF;
            BAIL_ON_VMDIR_ERROR_WITH_MSG(
                    retVal, pszLocalErrMsg,
                    "Rename of a non-leaf node is not allowed.");
        }

        // Verify not a member of any groups
        retVal = VmDirFindMemberOfAttribute(pEntry, &pAttrMemberOf);
        if (pAttrMemberOf && pAttrMemberOf->numVals > 0)
        {
            retVal = LDAP_UNWILLING_TO_PERFORM;
            BAIL_ON_VMDIR_ERROR_WITH_MSG(
                    retVal, pszLocalErrMsg,
                    "Rename of a node with memberships is not allowed.");
        }
    }

    if (pOperation->opType != VDIR_OPERATION_TYPE_REPL)
    {
        // Schema check
        retVal = VmDirSchemaCheck(pEntry);
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "Schema check failed - (%u)(%s)",
                retVal,
                VDIR_SAFE_STRING(VmDirSchemaCtxGetErrorMsg(pEntry->pSchemaCtx)));

        // check and read lock dn referenced entries
        retVal = pOperation->pBEIF->pfnBEChkDNReference(pOperation->pBECtx, pEntry);
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "BECheckDnRef, (%u)(%s)",
                retVal,
                VDIR_SAFE_STRING(pOperation->pBECtx->pszBEErrorMsg));
    }

    // Execute plugin logic that require final entry image.  (Do this for both normal and repl routes)
    retVal = VmDirExecutePreModifyPlugins(pOperation, pEntry, retVal);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "PreModifyPlugins failed - (%u)",
            retVal);

    // Update DB
    retVal = pOperation->pBEIF->pfnBEEntryModify(pOperation->pBECtx, modReq->mods, pEntry);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "BEEntryModify, (%u)(%s)",
            retVal,
            VDIR_SAFE_STRING(pOperation->pBEErrorMsg));

    if (bNoRaftLog == FALSE)
    {
        // Generate raft log only on the orignal Add/Modify/Delete, but not on the derived operation.
        // For instance, a delete may cause a Modify on the referenced entry which shouldn't
        //     initiate a raft log generation.
        retVal = VmDirModifyRaftPreCommit(
                pEntry->pSchemaCtx, entryId, modReq->dn.bvnorm_val,  modReq->mods, pOperation);
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "VmDirModifyRaftPreCommit, (%u)(%s)",
                retVal,
                VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
    }

cleanup:

    VmDirFreeAttribute(pAttrMemberOf);
    VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg);

    return retVal;

error:

    if (retVal == VMDIR_LDAP_ERROR_PRE_CONDITION)
    {
        VMDIR_LOG_VERBOSE(
                LDAP_DEBUG_ANY,
                "CoreLogicModifyEntry failed, DN = %s, (%u)(%s)",
                VDIR_SAFE_STRING(modReq->dn.lberbv.bv_val),
                retVal, VDIR_SAFE_STRING(pszLocalErrMsg));
    }
    else
    {
        VMDIR_LOG_ERROR(
                LDAP_DEBUG_ANY,
                "CoreLogicModifyEntry failed, DN = %s, (%u)(%s)",
                VDIR_SAFE_STRING(modReq->dn.lberbv.bv_val),
                retVal, VDIR_SAFE_STRING(pszLocalErrMsg));
    }

    if (pOperation->ldapResult.pszErrMsg == NULL)
    {
        pOperation->ldapResult.pszErrMsg = pszLocalErrMsg;
        pszLocalErrMsg = NULL;
    }

    goto cleanup;
}
예제 #12
0
/*
 * Simple (but not efficient) function to convert list of attribute,value
 * into an ADD_REQUEST type entry.
 * (e.g. ppszAttrList = { "objectclass","person",
 *                        "objectclass", "masterdiver",
 *                        "cn","my common name",
 *                         NULL};
 */
static
DWORD
AttrListToEntry(
    PVDIR_SCHEMA_CTX    pSchemaCtx,
    PSTR                pszDN,
    PSTR*               ppszAttrList,
    PVDIR_ENTRY         pEntry)
{
    DWORD   dwError = 0;
    VDIR_ATTRIBUTE* pAttr = NULL;
    PSTR*    ppszNext = NULL;

    assert(pSchemaCtx && pszDN && ppszAttrList && pEntry);
    pEntry->allocType = ENTRY_STORAGE_FORMAT_NORMAL;

    // establish entry schema context association
    pEntry->pSchemaCtx = VmDirSchemaCtxClone(pSchemaCtx);
    assert(pEntry->pSchemaCtx);

    dwError = VmDirAllocateStringA(
            pszDN,
            &pEntry->dn.lberbv.bv_val);
    BAIL_ON_VMDIR_ERROR(dwError);

    pEntry->dn.bOwnBvVal = TRUE;
    pEntry->dn.lberbv.bv_len = VmDirStringLenA(pEntry->dn.lberbv.bv_val);

    dwError = VmDirNormalizeDN( &(pEntry->dn), pSchemaCtx );
    BAIL_ON_VMDIR_ERROR(dwError);

    for (ppszNext = ppszAttrList; *ppszNext && *(ppszNext+1); ppszNext += 2)
    {
        assert (!pAttr);

        if ( (*(ppszNext+1))[0] != '\0')    // skip attribute with empty value
        {
            dwError = VmDirAttributeAllocate(
                    *ppszNext,
                    1,
                    pSchemaCtx,
                    &pAttr);
            BAIL_ON_VMDIR_ERROR(dwError);

            dwError = VmDirAllocateStringA(
                    *(ppszNext+1),
                    &pAttr->vals[0].lberbv.bv_val);
            BAIL_ON_VMDIR_ERROR(dwError);

            pAttr->vals[0].bOwnBvVal = TRUE;
            pAttr->vals[0].lberbv.bv_len = VmDirStringLenA(pAttr->vals[0].lberbv.bv_val);

            dwError = VmDirEntryAddAttribute(
                    pEntry,
                    pAttr);
            BAIL_ON_VMDIR_ERROR(dwError);
            pAttr = NULL; // pEntry takes over pAttr
        }
    }

cleanup:

    return dwError;

error:

    if (pAttr)
    {
        VmDirFreeAttribute(pAttr);
    }

    VmDirFreeEntryContent(pEntry);
    memset(pEntry, 0, sizeof(*pEntry));

    goto cleanup;
}
예제 #13
0
파일: metadata.c 프로젝트: vmware/lightwave
/*
 * 1) Find the attribute that holds attribute meta data.
 * 2) Attributes for usnCreated/usnChanged are updated with current local USN
 * 3) If we are doing a modify/delete, attribute meta data is checked to see supplier/consumer wins.
 *        - If supplier attribute won, update its meta data with current local USN.
 *        - If consumer wins don't write corresponding attribute.
 *        - Special case: supplier lost for UsnChanged, replace the metaData with consumer's metaData.
 * 4) If no attribute metaData exists, create it.
 */
DWORD
VmDirReplSetAttrNewMetaData(
    PVDIR_OPERATION     pOperation,
    PVDIR_ENTRY         pEntry,
    PLW_HASHMAP*        ppMetaDataMap
    )
{
    DWORD               dwError = LDAP_SUCCESS;
    PVDIR_ATTRIBUTE     pCurrAttr = NULL;
    PVDIR_ATTRIBUTE     pPrevAttr = NULL;
    PVDIR_ATTRIBUTE     pAttrAttrMetaData = NULL;
    PLW_HASHMAP         pMetaDataMap = NULL;

    if (!pOperation || !pEntry || !ppMetaDataMap)
    {
        BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER);
    }

    for (pPrevAttr = NULL, pCurrAttr = pEntry->attrs;
         pCurrAttr;
         pPrevAttr = pCurrAttr, pCurrAttr = pCurrAttr->next)
    {
        if (VmDirStringCompareA(pCurrAttr->type.lberbv.bv_val, ATTR_ATTR_META_DATA, FALSE) == 0)
        {
            if (pPrevAttr == NULL)
            {
                pEntry->attrs = pCurrAttr->next;
            }
            else
            {
                pPrevAttr->next = pCurrAttr->next;
            }

            pAttrAttrMetaData = pCurrAttr;

            dwError = VmDirAttributeMetaDataToHashMap(pAttrAttrMetaData, &pMetaDataMap);
            BAIL_ON_VMDIR_ERROR(dwError);

            *ppMetaDataMap = pMetaDataMap;
            continue;
        }

        if (VmDirStringCompareA(pCurrAttr->type.lberbv.bv_val, ATTR_USN_CREATED, FALSE) == 0 ||
            VmDirStringCompareA(pCurrAttr->type.lberbv.bv_val, ATTR_USN_CHANGED, FALSE) == 0)
        {
            char      pszLocalUsn[VMDIR_MAX_USN_STR_LEN] = {'\0'};
            size_t    localUsnStrlen = 0;

            dwError = VmDirStringNPrintFA(
                    pszLocalUsn,
                    sizeof(pszLocalUsn),
                    sizeof(pszLocalUsn) - 1,
                    "%"PRId64,
                    pOperation->pWriteQueueEle->usn);
            BAIL_ON_VMDIR_ERROR(dwError);

            localUsnStrlen = VmDirStringLenA(pszLocalUsn);

            VmDirFreeBervalContent(&pCurrAttr->vals[0]);

            dwError = VmDirAllocateAndCopyMemory(pszLocalUsn, localUsnStrlen, (PVOID*)&pCurrAttr->vals[0].lberbv.bv_val);
            BAIL_ON_VMDIR_ERROR(dwError);

            pCurrAttr->vals[0].lberbv.bv_len = localUsnStrlen;
            pCurrAttr->vals[0].bOwnBvVal = TRUE;
            continue;
        }
    }

    if (pAttrAttrMetaData == NULL)
    {
        VMDIR_LOG_ERROR(
                VMDIR_LOG_MASK_ALL,
                "%s: attrMetaData attribute not present in Entry: %s",
                __FUNCTION__,
                pEntry->dn.lberbv.bv_val);
        BAIL_WITH_VMDIR_ERROR(dwError, LDAP_OPERATIONS_ERROR);
    }

    if (pOperation->reqCode == LDAP_REQ_MODIFY)
    {
        dwError = VmDirReplResolveConflicts(
                pOperation,
                pEntry,
                pMetaDataMap);
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    dwError = _VmDirReplPopulateAttrNewMetaData(
            pEntry,
            pOperation->pWriteQueueEle->usn,
            pMetaDataMap);
    BAIL_ON_VMDIR_ERROR(dwError);

cleanup:
    VmDirFreeAttribute(pAttrAttrMetaData);
    return dwError;

error:
    goto cleanup;
}
예제 #14
0
파일: init.c 프로젝트: divyamehta/lightwave
static
DWORD
schemaInitFillAttrFromFile(
    PVDIR_SCHEMA_CTX    pCtx,
    PSTR*   ppszDescs,
    USHORT  dwDescSize,
    PSTR    pszTag,
    size_t  dwTagSize,
    PVDIR_ENTRY  pEntry
    )
{
    DWORD dwError = 0;
    DWORD dwCnt = 0;
    VDIR_ATTRIBUTE* pAttr = NULL;

    pszTag[dwTagSize] = '\0';
    dwError = VmDirAttributeAllocate(
            pszTag,
            dwDescSize,
            pCtx,
            &pAttr);
    pszTag[dwTagSize] = ':';
    BAIL_ON_VMDIR_ERROR(dwError);

    for (dwCnt = 0; dwCnt < dwDescSize; dwCnt++)
    {
        char* pszStr = &ppszDescs[dwCnt][dwTagSize+1];
        char* pszEndStr = &ppszDescs[dwCnt][VmDirStringLenA(ppszDescs[dwCnt])-1];

        assert(ppszDescs[dwCnt][dwTagSize] == ':');

        //ignore leading spaces
        while (*pszStr == ' ') pszStr++;

        //ignore trailing spaces
        while (*pszEndStr == ' ') pszEndStr--;
        *(pszEndStr+1) = '\0';

        dwError = VmDirAllocateStringA(
                pszStr,
                &pAttr->vals[dwCnt].lberbv.bv_val);
        BAIL_ON_VMDIR_ERROR(dwError);

        pAttr->vals[dwCnt].bOwnBvVal = TRUE;
        pAttr->vals[dwCnt].lberbv.bv_len = VmDirStringLenA(pAttr->vals[dwCnt].lberbv.bv_val);
    }

    dwError = VmDirEntryAddAttribute(
            pEntry,
            pAttr);
    BAIL_ON_VMDIR_ERROR(dwError);
    pAttr = NULL;

cleanup:

    return dwError;

error:

    if (pAttr)
    {
        VmDirFreeAttribute(pAttr);
    }

    goto cleanup;
}
예제 #15
0
파일: auth.c 프로젝트: vmware/lightwave
DWORD
VmDirGetUPNMemberships(
    PCSTR pszUpnName,
    PSTR **pppszMemberships,
    PDWORD pdwMemberships
    )
{
    DWORD dwError = 0;
    VDIR_ENTRY_ARRAY entryArray = {0};
    VDIR_OPERATION searchOp = {0};
    BOOLEAN bHasTxn = FALSE;
    PVDIR_ATTRIBUTE pMemberOf = NULL;
    PSTR *ppszMemberships = NULL;
    DWORD dwMemberships = 0;
    DWORD i = 0;

    if (IsNullOrEmptyString(pszUpnName) ||
        pppszMemberships == NULL ||
        pdwMemberships == NULL)
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    dwError = VmDirSimpleEqualFilterInternalSearch(
                "",
                LDAP_SCOPE_SUBTREE,
                ATTR_KRB_UPN,
                pszUpnName,
                &entryArray);
    BAIL_ON_VMDIR_ERROR(dwError);

    if (entryArray.iSize == 0)
    {
        dwError = VMDIR_ERROR_ENTRY_NOT_FOUND;
        BAIL_ON_VMDIR_ERROR(dwError);
    }
    else if (entryArray.iSize > 1)
    {
        dwError = VMDIR_ERROR_DATA_CONSTRAINT_VIOLATION;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    dwError = VmDirInitStackOperation(&searchOp, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_SEARCH, NULL);
    BAIL_ON_VMDIR_ERROR(dwError);

    searchOp.pBEIF = VmDirBackendSelect(NULL);

    dwError = searchOp.pBEIF->pfnBETxnBegin(searchOp.pBECtx, VDIR_BACKEND_TXN_READ);
    BAIL_ON_VMDIR_ERROR(dwError);
    bHasTxn = TRUE;

    dwError = VmDirBuildMemberOfAttribute(&searchOp, entryArray.pEntry, &pMemberOf);
    BAIL_ON_VMDIR_ERROR(dwError);

    if (pMemberOf)
    {
        dwMemberships = pMemberOf->numVals;
    }

    if (dwMemberships)
    {
        dwError = VmDirAllocateMemory(dwMemberships * sizeof(PSTR), (PVOID)&ppszMemberships);
        BAIL_ON_VMDIR_ERROR(dwError);

        for (i = 0; i < dwMemberships; i++)
        {
            PCSTR pszMemberOf = pMemberOf->vals[i].lberbv.bv_val;

            dwError = VmDirAllocateStringA(pszMemberOf, &ppszMemberships[i]);
            BAIL_ON_VMDIR_ERROR(dwError);
        }
    }

    *pppszMemberships = ppszMemberships;
    *pdwMemberships = dwMemberships;

cleanup:

    if (pMemberOf)
    {
        VmDirFreeAttribute(pMemberOf);
    }
    if (bHasTxn)
    {
        searchOp.pBEIF->pfnBETxnCommit(searchOp.pBECtx);
    }
    VmDirFreeOperationContent(&searchOp);
    VmDirFreeEntryArrayContent(&entryArray);

    return dwError;

error:
    VmDirFreeMemberships(ppszMemberships, dwMemberships);

    goto cleanup;
}
예제 #16
0
int
VmDirReplResolveConflicts(
    PVDIR_OPERATION     pOperation,
    PVDIR_ENTRY         pEntry,
    PLW_HASHMAP         pMetaDataMap
    )
{
    int                          retVal = LDAP_SUCCESS;
    int                          dbRetVal = 0;
    PSTR                         pszAttrType = NULL;
    DWORD                        dwConflictCnt = 0;
    LW_HASHMAP_ITER              iter = LW_HASHMAP_ITER_INIT;
    LW_HASHMAP_PAIR              pair = {NULL, NULL};
    PVDIR_ATTRIBUTE              pConsumerAttr = NULL;
    PVMDIR_ATTRIBUTE_METADATA    pSupplierMetaData = NULL;
    PVMDIR_REPLICATION_METRICS   pReplMetrics = NULL;

    if (!pOperation || !pEntry || !pMetaDataMap)
    {
        BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_INVALID_PARAMETER);
    }

    while (LwRtlHashMapIterate(pMetaDataMap, &iter, &pair))
    {
        pszAttrType = (PSTR) pair.pKey;
        pSupplierMetaData = (PVMDIR_ATTRIBUTE_METADATA) pair.pValue;

        if (VmDirStringCompareA(pszAttrType, ATTR_OBJECT_GUID, FALSE) == 0)
        {
            continue;
        }

        VmDirFreeAttribute(pConsumerAttr);
        pConsumerAttr = NULL;

        retVal = VmDirAttributeAllocate(pszAttrType, 0, pOperation->pSchemaCtx, &pConsumerAttr);
        BAIL_ON_LDAP_ERROR(
                retVal,
                LDAP_OPERATIONS_ERROR,
                (pOperation->ldapResult.pszErrMsg),
                "VmDirAttributeAllocate failed", VDIR_SAFE_STRING(pOperation->pBEErrorMsg));

        dbRetVal = pOperation->pBEIF->pfnBEGetAttrMetaData(
                pOperation->pBECtx, pConsumerAttr, pEntry->eId);

        if (dbRetVal)
        {
            switch (dbRetVal)
            {
                case ERROR_BACKEND_ATTR_META_DATA_NOTFOUND: //When a new attribute is being added
                    // => Supplier attribute meta data WINS against consumer attribute meta data
                    break;

                default:
                     BAIL_ON_LDAP_ERROR(
                             retVal,
                             LDAP_OPERATIONS_ERROR,
                             (pOperation->ldapResult.pszErrMsg),
                             "pfnBEGetAttrMetaData failed - (%d)(%s)",
                             dbRetVal,
                             VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
            }
        }
        else
        {
            BOOLEAN             bSupplierWon = FALSE;
            BOOLEAN             bIsSameAttrValue = FALSE;
            PSZ_METADATA_BUF    pszSupplierMetaData = {'\0'};
            PSZ_METADATA_BUF    pszConsumerMetaData = {'\0'};

            bSupplierWon = _VmDirReplAttrConflictCheck(
                    pSupplierMetaData, pConsumerAttr->pMetaData);

            bIsSameAttrValue = _VmDirIsBenignReplConflict(
                    pEntry, pConsumerAttr);

            //Ignore error - used only for logging
            VmDirMetaDataSerialize(pSupplierMetaData, &pszSupplierMetaData[0]);
            VmDirMetaDataSerialize(pConsumerAttr->pMetaData, &pszConsumerMetaData[0]);

            if (bSupplierWon == FALSE)
            {
                if (VmDirStringCompareA(pszAttrType, ATTR_USN_CHANGED, FALSE) == 0)
                {
                    // Need to keep usnChanged to advance localUSN for this replication change.
                    retVal = VmDirMetaDataCopyContent(pConsumerAttr->pMetaData, pSupplierMetaData);
                    BAIL_ON_VMDIR_ERROR(retVal);
                }
                else
                {
                    VMDIR_FREE_REPL_ATTR_IN_CONFLICT(pSupplierMetaData);
                }

                dwConflictCnt++;

                if (!bIsSameAttrValue)
                {
                    VMDIR_LOG_WARNING(
                            VMDIR_LOG_MASK_ALL,
                            "%s: supplier version loses."
                            " pszAttrType: %s supplier attr meta: %s, consumer attr meta: %s ",
                            __FUNCTION__,
                            pEntry->dn.lberbv.bv_val,
                            pszAttrType,
                            pszSupplierMetaData,
                            pszConsumerMetaData);
                }
            }
            else
            {
                VMDIR_LOG_VERBOSE(
                        VMDIR_LOG_MASK_ALL,
                        "%s: supplier version wins."
                        " pszAttrType: %s supplier attr meta: %s, consumer attr meta: %s ",
                        __FUNCTION__,
                        pEntry->dn.lberbv.bv_val,
                        pszAttrType,
                        pszSupplierMetaData,
                        pszConsumerMetaData);
            }
        }
    }

    if (dwConflictCnt > 0)
    {
        if (VmDirReplMetricsCacheFind(pOperation->pszPartner, &pReplMetrics) == 0)
        {
            VmMetricsCounterAdd(pReplMetrics->pCountConflictResolved, dwConflictCnt);
        }
    }

cleanup:
    VmDirFreeAttribute(pConsumerAttr);
    return retVal;

ldaperror:
error:
    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "failed, error (%d)", retVal);
    goto cleanup;
}
예제 #17
0
/*
 * Convert entry allocType from FORMAT_PACK to FORMAT_NORMAL
 */
DWORD
VmDirEntryUnpack(
    PVDIR_ENTRY  pEntry
    )
{
    DWORD   dwError = 0;
    PVDIR_ATTRIBUTE      pAttr = NULL;
    PVDIR_ATTRIBUTE      pDupAttr = NULL;
    VDIR_ENTRY           newEntry = {0};

    assert(pEntry);

    if (pEntry->allocType != ENTRY_STORAGE_FORMAT_PACK)
    {
        return 0;
    }

    newEntry.allocType = ENTRY_STORAGE_FORMAT_NORMAL;
    newEntry.eId = pEntry->eId;

    dwError = VmDirBervalContentDup(&pEntry->dn, &newEntry.dn);
    BAIL_ON_VMDIR_ERROR(dwError);

    // pdn.lberbv.bv_val is always in-place of dn.lberbv.bv_val (compatible with DeleteEntry)
    if (pEntry->pdn.lberbv.bv_val && pEntry->pdn.lberbv.bv_len > 0)
    {
        newEntry.pdn.lberbv.bv_val = newEntry.dn.lberbv.bv_val + (pEntry->pdn.lberbv.bv_val - pEntry->dn.lberbv.bv_val);
    }

    // pdn.bvnorm_val is ok to heap allocated
    if (pEntry->pdn.bvnorm_val && pEntry->pdn.bvnorm_len > 0)
    {
        dwError = VmDirAllocateStringA(
                pEntry->pdn.bvnorm_val,
                &newEntry.pdn.bvnorm_val);
        BAIL_ON_VMDIR_ERROR(dwError);

        newEntry.pdn.bvnorm_len = VmDirStringLenA(newEntry.pdn.bvnorm_val);
    }

    // copy attribute
    for (pAttr = pEntry->attrs, pDupAttr = NULL; pAttr; pAttr = pAttr->next)
    {
        dwError = VmDirAttributeDup(pAttr, &pDupAttr);
        BAIL_ON_VMDIR_ERROR(dwError);

        dwError = VmDirEntryAddAttribute(&newEntry, pDupAttr);
        BAIL_ON_VMDIR_ERROR(dwError);
        pDupAttr = NULL;
    }

    /////////////////////////////////////////////////////////////////////
    // should never fail from here to the end
    /////////////////////////////////////////////////////////////////////

    // takes over schema ctx (we copy attributes)
    newEntry.pSchemaCtx = pEntry->pSchemaCtx;
    assert(newEntry.pSchemaCtx);
    pEntry->pSchemaCtx = NULL;

// TODO, other fields?
    // takes over pParentEntry
    newEntry.pParentEntry = pEntry->pParentEntry;
    pEntry->pParentEntry = NULL;

    // fee resources
    VmDirFreeEntryContent(pEntry);

    // takes over newEntry content
    VmDirCopyMemory(pEntry, sizeof(VDIR_ENTRY), &newEntry, sizeof(newEntry));

cleanup:

    return dwError;

error:

    if (pDupAttr)
    {
        VmDirFreeAttribute(pDupAttr);
    }

    VmDirFreeEntryContent(&newEntry);

    goto cleanup;
}
예제 #18
0
파일: modify.c 프로젝트: vmware/lightwave
/*
 * DelAttrValsFromEntryStruct: Deletes a complete attribute or specific attribute values from the entry.
 * Assumption: This function assumes/asserts that the modAttr does exist in the entry.
 *
 */
static
int
DelAttrValsFromEntryStruct(
   PVDIR_SCHEMA_CTX  pSchemaCtx,
   VDIR_ENTRY *      e,
   VDIR_ATTRIBUTE *  modAttr,
   PSTR*             ppszErrorMsg
   )
{
    int                 retVal = LDAP_SUCCESS;
    VDIR_ATTRIBUTE *    prevAttr = NULL;
    VDIR_ATTRIBUTE *    currAttr = NULL;
    VDIR_ATTRIBUTE *    eAttr = NULL;
    unsigned int        i = 0;
    unsigned int        j = 0;
    PSTR                pszLocalErrorMsg = NULL;

    assert(e->allocType == ENTRY_STORAGE_FORMAT_NORMAL);

    // Locate which attribute (values) we are trying to delete
    for (currAttr = e->attrs; currAttr != NULL; prevAttr = currAttr, currAttr = currAttr->next)
    {
        if (VmDirStringCompareA(modAttr->type.lberbv.bv_val, currAttr->type.lberbv.bv_val, FALSE) == 0)
        {
            break;
        }
    }

    assert(currAttr != NULL);

    eAttr = currAttr;

    // Normalize eAttr values
    for (i = 0; i < eAttr->numVals; i++)
    {
        retVal = VmDirSchemaBervalNormalize(pSchemaCtx, eAttr->pATDesc, &eAttr->vals[i]);
        BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg),
                            "normalize (%s)(%.*s)",
                            VDIR_SAFE_STRING(eAttr->pATDesc->pszName),
                            VMDIR_MIN(eAttr->vals[i].lberbv.bv_len, VMDIR_MAX_LOG_OUTPUT_LEN),
                            VDIR_SAFE_STRING(eAttr->vals[i].lberbv.bv_val));
    }

    if (modAttr->numVals == 1 && eAttr->pATDesc->bSingleValue &&
        (VmDirStringCompareA(eAttr->pATDesc->pszName, ATTR_MODIFYTIMESTAMP, FALSE) == 0 ||
         VmDirStringCompareA(eAttr->pATDesc->pszName, ATTR_CREATETIMESTAMP, FALSE) == 0 ||
         VmDirStringCompareA(eAttr->pATDesc->pszName, ATTR_CREATORS_NAME, FALSE) == 0 ||
         VmDirStringCompareA(eAttr->pATDesc->pszName, ATTR_MODIFIERS_NAME, FALSE) == 0))
    {
        /* Force deleting the attribute value whether or not the value matches.
         * A raft follower may alter the timestamps/creator locally, e.g. rollback vmwAttrUniquenessScope,
         * which may fail to remove the value if it doesn't match that value seen  at the raft leader.
         */
        VmDirFreeBervalContent(&modAttr->vals[0]);
        modAttr->numVals = 0;
    }

    // Complete attribute is to be deleted.
    if (modAttr->numVals == 0)
    {
        // Make a copy of BerValues into modAttr so that these values can be used to delete from the index,
        // if it is an indexed attribute.

        VMDIR_SAFE_FREE_MEMORY(modAttr->vals);
        retVal = VmDirAllocateMemory((eAttr->numVals + 1) * sizeof(VDIR_BERVALUE), (PVOID *)&modAttr->vals);
        BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "no memory");

        for (i = 0; i < eAttr->numVals; i++)
        {
            VmDirBervalContentDup(&eAttr->vals[i], &modAttr->vals[i]);
        }
        modAttr->numVals = eAttr->numVals;

        // Adjust the "next" pointer of the attribute before the attribute being deleted. => Altering the attribute
        // chain.
        if (prevAttr == NULL) // if it is the first attribute
        {
            e->attrs = eAttr->next;
        }
        else
        {
            prevAttr->next = eAttr->next;
        }

        VmDirFreeAttribute(eAttr);
    }
    else // Specific attribute values need to be deleted.
    {
        // Check if all attribute values that are being deleted exist in the Attribute
        for (i=0; i < modAttr->numVals; i++)
        {
            // modAttr values are already normalized.
            assert(modAttr->vals[i].bvnorm_val);

            for (j = 0; j < eAttr->numVals; j++)
            {
                // eAttr values are already normalized.
                assert(eAttr->vals[j].bvnorm_val);

                if (modAttr->vals[i].bvnorm_len == eAttr->vals[j].bvnorm_len &&
                    memcmp(modAttr->vals[i].bvnorm_val, eAttr->vals[j].bvnorm_val, modAttr->vals[i].bvnorm_len) == 0)
                {
                    break;
                }
            }
            if (j == eAttr->numVals) // did not find a match
            {
                retVal = VMDIR_ERROR_NO_SUCH_ATTRIBUTE;
                BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg),
                                        "Attribute (%s) value (%.*s) being deleted does not exist.",
                                        VDIR_SAFE_STRING(modAttr->type.lberbv.bv_val),
                                        VMDIR_MIN(modAttr->vals[i].lberbv.bv_len, VMDIR_MAX_LOG_OUTPUT_LEN),
                                        VDIR_SAFE_STRING(modAttr->vals[i].lberbv.bv_val));
            }
        }
        // All values are being deleted. => Delete the whole attribute
        if (modAttr->numVals == eAttr->numVals)
        {
            // Adjust the "next" pointer of the attribute before the attribute being deleted. => Altering the attribute
            // chain.
            if (prevAttr == NULL) // if it is the first attribute
            {
                e->attrs = eAttr->next;
            }
            else
            {
                prevAttr->next = eAttr->next;
            }
            VmDirFreeAttribute(eAttr);
        }
        else
        {
            RemoveAttrVals(eAttr, modAttr);
        }
    }

cleanup:

    if (ppszErrorMsg)
    {
        *ppszErrorMsg = pszLocalErrorMsg;
    }
    else
    {
        VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg);
    }

    return retVal;

error:
    goto cleanup;
}