Exemple #1
0
void
VmDirFreeEntry(
    PVDIR_ENTRY pEntry
    )
{
    VmDirFreeEntryContent(pEntry);
    VMDIR_SAFE_FREE_MEMORY(pEntry);
}
static
BOOLEAN
_VmDirIsBenignReplConflict(
    PVDIR_ENTRY     pEntry,
    PVDIR_ATTRIBUTE pAttr
    )
{
    int            i = 0;
    CHAR           excludeAttrs[] = {ATTR_USN_CHANGED};
    DWORD          dwError = 0;
    BOOLEAN        bIsBenign = FALSE;
    VDIR_ENTRY     consumerEntry = {0};

    if (pEntry->eId)
    {
        if (!consumerEntry.dn.lberbv_val)
        {
            PVDIR_BACKEND_INTERFACE pBE = NULL;
            pBE = VmDirBackendSelect(NULL);
            assert(pBE);

            dwError = pBE->pfnBESimpleIdToEntry(pEntry->eId, &consumerEntry);
            BAIL_ON_VMDIR_ERROR(dwError);
        }

        for (i=0; i< VMDIR_ARRAY_SIZE(excludeAttrs); i++)
        {
            if (VmDirStringCompareA(pAttr->type.lberbv_val, &excludeAttrs[i], FALSE) == 0)
            {
                bIsBenign = TRUE;
                goto cleanup;
            }
        }

        bIsBenign = VmDirIsSameConsumerSupplierEntryAttr(pAttr, pEntry, &consumerEntry);
    }

cleanup:
    VmDirFreeEntryContent(&consumerEntry);
    return bIsBenign;

error:
    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "failed, error (%d)", dwError);
    goto cleanup;
}
Exemple #3
0
void
VmDirFreeEntryArrayContent(
    PVDIR_ENTRY_ARRAY   pEntryAry
    )
{
    size_t  iCnt = 0;

    if ( pEntryAry )
    {
        for (iCnt = 0; iCnt < pEntryAry->iSize; iCnt++)
        {
            VmDirFreeEntryContent((pEntryAry->pEntry)+iCnt);
        }

        VMDIR_SAFE_FREE_MEMORY(pEntryAry->pEntry);
        pEntryAry->iSize = 0;
    }
}
Exemple #4
0
static
BOOLEAN
_VmDirPagedSearchProcessEntry(
    PVDIR_OPERATION pOperation,
    ENTRYID eId
    )
{
    DWORD dwError = 0;
    VDIR_ENTRY srEntry = {0};
    BOOLEAN bInclude = FALSE;

    dwError = pOperation->pBEIF->pfnBESimpleIdToEntry(eId, &srEntry);
    if (dwError == 0)
    {
        if (CheckIfEntryPassesFilter(pOperation, &srEntry, pOperation->request.searchReq.filter) == FILTER_RES_TRUE)
        {
            bInclude = TRUE;
        }

        VmDirFreeEntryContent(&srEntry);
    }

    return bInclude;
}
Exemple #5
0
/* MdbEIdToEntry: For a given entry ID, reads an entry from the entry DB.
 *
 * Returns: BE error - BACKEND_ERROR, BACKEND OPERATIONS, BACKEND_ENTRY_NOTFOUND
 *
 */
DWORD
VmDirMDBEIdToEntry(
    PVDIR_BACKEND_CTX           pBECtx,
    PVDIR_SCHEMA_CTX            pSchemaCtx,
    ENTRYID                     eId,
    PVDIR_ENTRY                 pEntry,
    VDIR_BACKEND_ENTRY_LOCKTYPE entryLockType)
{
    DWORD           dwError = 0;
    VDIR_DB         mdbDBi = 0;
    PVDIR_DB_TXN    pTxn = NULL;
    VDIR_DB_DBT     key = {0};
    VDIR_DB_DBT     value = {0};
    unsigned char   eIdBytes[sizeof( ENTRYID )] = {0};
    unsigned char*  pszBlob = NULL;

    assert(pBECtx && pBECtx->pBEPrivate && pSchemaCtx && pEntry);

    pTxn = (PVDIR_DB_TXN)pBECtx->pBEPrivate;

    mdbDBi = gVdirMdbGlobals.mdbEntryDB.pMdbDataFiles[0].mdbDBi;

    // Set key
    key.mv_data = &eIdBytes[0];
    MDBEntryIdToDBT(eId, &key);

    if ((dwError = mdb_get(pTxn, mdbDBi, &key, &value) ) != 0)
    {
        dwError = MDBToBackendError(dwError, MDB_NOTFOUND, ERROR_BACKEND_ENTRY_NOTFOUND, pBECtx, "EIDToEntry");
        BAIL_ON_VMDIR_ERROR( dwError );
    }

    if ((dwError = VmDirAllocateMemory( value.mv_size, (PVOID *)&pszBlob)) != 0)
    {
        dwError = ERROR_BACKEND_OPERATIONS;
        BAIL_ON_VMDIR_ERROR( dwError );
    }

    if ((dwError = VmDirCopyMemory(pszBlob, value.mv_size, value.mv_data, value.mv_size)) != 0)
    {
        dwError = ERROR_BACKEND_OPERATIONS;
        BAIL_ON_VMDIR_ERROR( dwError );
    }

    // encodedEntry takes over pszBlob
    pEntry->encodedEntry = pszBlob;
    pszBlob = NULL;

    pEntry->eId = eId;
    dwError = VmDirDecodeEntry(pSchemaCtx, pEntry );
    BAIL_ON_VMDIR_ERROR(dwError);

cleanup:

    return dwError;

error:

    VMDIR_LOG_ERROR( LDAP_DEBUG_BACKEND, "VmDirMDBEIdToEntry, eid(%u) failed (%u)", eId, dwError);

    VMDIR_SAFE_FREE_MEMORY(pszBlob);
    VmDirFreeEntryContent( pEntry );

    VMDIR_SET_BACKEND_ERROR(dwError);   // if dwError no in BE space, set to ERROR_BACKEND_ERROR

    goto cleanup;
}
Exemple #6
0
static
DWORD
ProcessPreValidatedEntries(
    PVDIR_OPERATION pOperation,
    DWORD dwEntryCount,
    ENTRYID *pValidatedEntries
    )
{
    DWORD   i = 0;
    DWORD   dwError = 0;
    DWORD   dwSentEntries = 0;
    BOOLEAN bInternalSearch = FALSE;
    BOOLEAN bStoreRsltInMem = FALSE;
    VDIR_ENTRY  srEntry = {0};
    PVDIR_ENTRY pSrEntry = NULL;

    if (dwEntryCount == 0)
    {
        goto cleanup;
    }

    bInternalSearch = pOperation->opType == VDIR_OPERATION_TYPE_INTERNAL;
    bStoreRsltInMem = pOperation->request.searchReq.bStoreRsltInMem;

    if (bInternalSearch || bStoreRsltInMem)
    {
        VmDirFreeEntryArrayContent(&pOperation->internalSearchEntryArray);
        dwError = VmDirAllocateMemory(
                sizeof(VDIR_ENTRY) * (dwEntryCount + 1),
                (PVOID*)&pOperation->internalSearchEntryArray.pEntry);
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    for (; i < dwEntryCount; ++i)
    {
        pSrEntry = bInternalSearch || bStoreRsltInMem ?
                (pOperation->internalSearchEntryArray.pEntry +
                 pOperation->internalSearchEntryArray.iSize) : &srEntry;

        dwError = pOperation->pBEIF->pfnBESimpleIdToEntry(
                pValidatedEntries[i], pSrEntry);
        if (dwError != 0)
        {
            // Ignore errors resolving ENTRYIDs.
            VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL,
                    "%s pfnBESimpleIdToEntry EID(%u), error (%u)",
                    __FUNCTION__, pValidatedEntries[i], dwError);
            continue;
        }

        dwError = VmDirBuildComputedAttribute(pOperation, pSrEntry);
        BAIL_ON_VMDIR_ERROR(dwError);

        dwError = VmDirSendSearchEntry(pOperation, pSrEntry);
        if (dwError == VMDIR_ERROR_INSUFFICIENT_ACCESS)
        {
            VMDIR_LOG_WARNING(
                    VMDIR_LOG_MASK_ALL,
                    "Access deny on search entry result [%s,%d] (bindedDN-%s) (targetDn-%s)",
                    __FILE__,
                    __LINE__,
                    pOperation->conn->AccessInfo.pszBindedDn,
                    pSrEntry->dn.lberbv.bv_val);

            // make sure search continues
            dwError = 0;
        }
        BAIL_ON_VMDIR_ERROR(dwError);

        if (pSrEntry->bSearchEntrySent)
        {
            dwSentEntries++;
            if (bInternalSearch || bStoreRsltInMem)
            {
                pOperation->internalSearchEntryArray.iSize++;
                pSrEntry = NULL;    // EntryArray takes over *pSrEntry content
            }
        }

        VmDirFreeEntryContent(pSrEntry);
        pSrEntry = NULL;
    }

    dwError = SetPagedSearchCookie(
                pOperation,
                pValidatedEntries[dwEntryCount - 1],
                0);
    BAIL_ON_VMDIR_ERROR(dwError);

cleanup:
    pOperation->dwSentEntries = dwSentEntries;
    VmDirFreeEntryContent(pSrEntry);
    return dwError;

error:
    goto cleanup;
}
Exemple #7
0
static
int
VmDirProcessCandidateList(
    VDIR_OPERATION * pOperation
    )
{
    int               retVal = LDAP_SUCCESS;
    int               i = 0;
    VDIR_CANDIDATES * cl = pOperation->request.searchReq.filter->candidates;
    VDIR_ENTRY        srEntry = {0};
    VDIR_ENTRY *      pSrEntry = NULL;
    int               numSentEntries = 0;
    BOOLEAN           bExternalSearch = FALSE;
    BOOLEAN           bInternalSearch = FALSE;
    BOOLEAN           bStoreRsltInMem = FALSE;
    BOOLEAN           bPageResultsCtrl = FALSE;
    DWORD             dwPageSize = 0;
    ENTRYID           lastEID = 0;

    /*
     * If the page size is greater than or equal to the sizeLimit value,
     * the server should ignore the control as the request can be satisfied in a single page.
     */
    if (pOperation->showPagedResultsCtrl && (pOperation->request.searchReq.sizeLimit == 0 ||
        pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.pageSize < (DWORD)pOperation->request.searchReq.sizeLimit))
    {
        VmDirLog( LDAP_DEBUG_TRACE, "showPagedResultsCtrl applies to this query." );

        bPageResultsCtrl = TRUE;
        dwPageSize = pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.pageSize;
        lastEID = atoll(pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie);
        pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie[0] = '\0';

        VmDirSortCandidateList(cl);  // sort candidate list if not yet sorted
    }

    bExternalSearch = pOperation->opType == VDIR_OPERATION_TYPE_EXTERNAL;
    bInternalSearch = pOperation->opType == VDIR_OPERATION_TYPE_INTERNAL;
    bStoreRsltInMem = pOperation->request.searchReq.bStoreRsltInMem;

    if (cl && cl->size > 0)
    {
        if (bInternalSearch || bStoreRsltInMem)
        {   //TODO, we should have a hard limit on the cl->size we handle
            VmDirFreeEntryArrayContent(&pOperation->internalSearchEntryArray);
            retVal = VmDirAllocateMemory(   sizeof(VDIR_ENTRY) * cl->size,
                                            (PVOID*)&pOperation->internalSearchEntryArray.pEntry);
            BAIL_ON_VMDIR_ERROR(retVal);
        }

        for (i = 0, numSentEntries = 0;
             (i < cl->size) &&
             (pOperation->request.searchReq.sizeLimit == 0 /* unlimited */ ||
              numSentEntries < pOperation->request.searchReq.sizeLimit);
             i++)
        {
            if (bExternalSearch &&
                VmDirdState() == VMDIRD_STATE_SHUTDOWN &&
                pOperation->syncReqCtrl == NULL)
            {
                retVal = LDAP_UNAVAILABLE; // stop all external search ops, except replication pull
                goto cleanup;
            }

            if (!gVmdirGlobals.bPagedSearchReadAhead)
            {
                //skip entries we sent before in sorted cl->eIds.
                if (bPageResultsCtrl && cl->eIds[i] <= lastEID)
                {
                    continue;
                }
            }

            pSrEntry = bInternalSearch || bStoreRsltInMem ?
                        (pOperation->internalSearchEntryArray.pEntry + pOperation->internalSearchEntryArray.iSize) : &srEntry;

            retVal = pOperation->pBEIF->pfnBEIdToEntry(
                        pOperation->pBECtx,
                        pOperation->pSchemaCtx,
                        cl->eIds[i],
                        pSrEntry,
                        VDIR_BACKEND_ENTRY_LOCK_READ);

            if (retVal)
            {
                // Ignore BdbEIdToEntry errors.
                VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL,
                        "ProcessCandiateList BEIdToEntry EID(%u), error (%u)",
                        cl->eIds[i], retVal);

                continue;
            }

            if (CheckIfEntryPassesFilter(pOperation, pSrEntry, pOperation->request.searchReq.filter) == FILTER_RES_TRUE)
            {
                BOOLEAN bSendEntry = TRUE;
                CHAR    sha1Digest[SHA_DIGEST_LENGTH] = {0};

                retVal = VmDirBuildComputedAttribute( pOperation, pSrEntry );
                BAIL_ON_VMDIR_ERROR( retVal );

                if (pOperation->digestCtrl)
                {
                    retVal = VmDirEntrySHA1Digest(pSrEntry, sha1Digest);
                    BAIL_ON_VMDIR_ERROR(retVal);

                    if (memcmp(sha1Digest, pOperation->digestCtrl->value.digestCtrlVal.sha1Digest, SHA_DIGEST_LENGTH) == 0)
                    {
                        bSendEntry = FALSE;
                        VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL,"%s digest match %s",
                                           __FUNCTION__, pSrEntry->dn.lberbv.bv_val);
                    }
                    else
                    {
                        VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL,"%s digest mismatch %s",
                                           __FUNCTION__, pSrEntry->dn.lberbv.bv_val);
                    }
                }

                if (bSendEntry)
                {
                    retVal = VmDirSendSearchEntry(pOperation, pSrEntry);
                    if (retVal == VMDIR_ERROR_INSUFFICIENT_ACCESS)
                    {
                        VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL,
                                "Access deny on search entry result [%s,%d] (bindedDN-%s) (targetDn-%s)\n",
                                __FILE__,
                                __LINE__,
                                pOperation->conn->AccessInfo.pszBindedDn,
                                pSrEntry->dn.lberbv.bv_val);
                        // make sure search continues
                        retVal = 0;
                    }
                    BAIL_ON_VMDIR_ERROR( retVal );

                    if (pSrEntry->bSearchEntrySent)
                    {
                        numSentEntries++;
                        if (bInternalSearch || bStoreRsltInMem)
                        {
                            pOperation->internalSearchEntryArray.iSize++;
                            pSrEntry = NULL;    // EntryArray takes over *pSrEntry content

                            if (pOperation->internalSearchEntryArray.iSize > gVmdirServerGlobals.dwMaxInternalSearchLimit)
                            {
                                BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_INTERNAL_SEARCH_LIMIT);
                            }
                        }
                    }
                }
            }

            //We have sent one page size of entries, so we can break here
            if (bPageResultsCtrl && numSentEntries == dwPageSize)
            {
                retVal = SetPagedSearchCookie(pOperation, cl->eIds[i], i);
                BAIL_ON_VMDIR_ERROR(retVal);
                break;
            }

            VmDirFreeEntryContent( pSrEntry );
            pSrEntry = NULL; // Reset to NULL so that DeleteEntry is no-op.
        }

        VMDIR_LOG_VERBOSE( LDAP_DEBUG_FILTER, "(%d) candiates processed and (%d) entries sent", cl->size, numSentEntries);
    }

    if ( pOperation->request.searchReq.sizeLimit && numSentEntries < pOperation->request.searchReq.sizeLimit &&
         pOperation->pBECtx->iPartialCandidates)
    {
        retVal = LDAP_UNWILLING_TO_PERFORM;
        VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "ProcessCandiateList may return none or paritial requested entries with sizelimit %d",
                        pOperation->request.searchReq.sizeLimit);
    }

#ifndef REPLICATION_V2
    retVal = VmDirUpdateSyncDoneCtl(
            pOperation,
            numSentEntries);
    BAIL_ON_VMDIR_ERROR(retVal);
#endif

cleanup:
    pOperation->dwSentEntries = numSentEntries;
    VmDirFreeEntryContent(pSrEntry);
    return retVal;

error:
    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "ProcessCandiateList failed. (%u)", retVal);
    goto cleanup;
}
Exemple #8
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" );
}
Exemple #9
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;
}
Exemple #10
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;
}
Exemple #11
0
/* VmDirInternalDeleteEntry: Interface that can be used "internally" by the server code. One of the main differences between
 * this function and MLDelete 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
VmDirInternalDeleteEntry(
    PVDIR_OPERATION    pOperation
    )
{
    int             retVal = LDAP_SUCCESS;
    int             deadLockRetries = 0;
    VDIR_ENTRY      entry = {0};
    PVDIR_ENTRY     pEntry = NULL;
    BOOLEAN         leafNode = FALSE;
    DeleteReq *     delReq = &(pOperation->request.deleteReq);
    ModifyReq *     modReq = &(pOperation->request.modifyReq);
    BOOLEAN         bIsDomainObject = FALSE;
    BOOLEAN         bHasTxn = FALSE;
    PSTR            pszLocalErrMsg = NULL;

    assert(pOperation && pOperation->pBECtx->pBE);

    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" );
    }

    // Normalize DN
    retVal = VmDirNormalizeDN( &(delReq->dn), pOperation->pSchemaCtx );
    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "DN normalization failed - (%u)(%s)",
                                  retVal, VDIR_SAFE_STRING(VmDirSchemaCtxGetErrorMsg(pOperation->pSchemaCtx)) );

    if (pOperation->opType != VDIR_OPERATION_TYPE_REPL)
    {
        // Execute pre modify apply Delete plugin logic
        retVal = VmDirExecutePreModApplyDeletePlugins(pOperation, NULL, retVal);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "PreModApplyDelete plugin failed - (%u)",  retVal );
    }

    retVal = VmDirNormalizeMods( pOperation->pSchemaCtx, modReq->mods, &pszLocalErrMsg );
    BAIL_ON_VMDIR_ERROR( retVal );

    // make sure VDIR_BACKEND_CTX has usn change number by now
    if ( pOperation->pBECtx->wTxnUSN <= 0 )
    {
        retVal = VMDIR_ERROR_NO_USN;
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "BECtx.wTxnUSN not set");
    }

    // BUGBUG, need to protect some system entries such as schema,domain....etc?

    // ************************************************************************************
    // transaction retry loop begin.  make sure all function within are retry agnostic.
    // ************************************************************************************
txnretry:
    if (bHasTxn)
    {
        pOperation->pBEIF->pfnBETxnAbort( pOperation->pBECtx );
        bHasTxn = FALSE;
    }

    deadLockRetries++;
    if (deadLockRetries > MAX_DEADLOCK_RETRIES)
    {
        retVal = VMDIR_ERROR_LOCK_DEADLOCK;
        BAIL_ON_VMDIR_ERROR( retVal );
    }
    else
    {
        if (pEntry)
        {
            VmDirFreeEntryContent(pEntry);
            memset(pEntry, 0, sizeof(VDIR_ENTRY));
            pEntry = NULL;
        }

        retVal = pOperation->pBEIF->pfnBETxnBegin( pOperation->pBECtx, VDIR_BACKEND_TXN_WRITE);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn begin (%u)(%s)",
                                      retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
        bHasTxn = TRUE;

        // Read current entry from DB
        retVal = pOperation->pBEIF->pfnBEDNToEntry(
                                    pOperation->pBECtx,
                                    pOperation->pSchemaCtx,
                                    &(delReq->dn),
                                    &entry,
                                    VDIR_BACKEND_ENTRY_LOCK_WRITE);
        if (retVal != 0)
        {
            switch (retVal)
            {
                case VMDIR_ERROR_BACKEND_DEADLOCK:
                    goto txnretry; // Possible retry.

                default:
                    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "(%u)(%s)",
                                                  retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
            }
        }

        pEntry = &entry;

        // Parse Parent DN
        retVal = VmDirGetParentDN( &pEntry->dn, &pEntry->pdn );
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Get ParentDn failed - (%u)",  retVal );

        // get parent entry
        if (pEntry->pdn.lberbv.bv_val)
        {
            PVDIR_ENTRY     pParentEntry = NULL;

            retVal = VmDirAllocateMemory(sizeof(*pEntry), (PVOID)&pParentEntry);
            BAIL_ON_VMDIR_ERROR(retVal);

            retVal = pOperation->pBEIF->pfnBEDNToEntry(
                                        pOperation->pBECtx,
                                        pOperation->pSchemaCtx,
                                        &pEntry->pdn,
                                        pParentEntry,
                                        VDIR_BACKEND_ENTRY_LOCK_READ);
            if (retVal)
            {
                VmDirFreeEntryContent(pParentEntry);
                VMDIR_SAFE_FREE_MEMORY(pParentEntry);

                switch (retVal)
                {
                    case VMDIR_ERROR_BACKEND_DEADLOCK:
                        goto txnretry; // Possible retry.

                    case VMDIR_ERROR_BACKEND_ENTRY_NOTFOUND:
                        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "parent (%s) not found, (%s)",
                                                      pEntry->pdn.lberbv_val,
                                                      VDIR_SAFE_STRING(pOperation->pBEErrorMsg) );

                    default:
                        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "parent (%s) lookup failed, (%s)",
                                                      pEntry->pdn.lberbv_val,
                                                      VDIR_SAFE_STRING(pOperation->pBEErrorMsg) );
                }
            }

            pEntry->pParentEntry = pParentEntry;        // pEntry takes over pParentEntry
            pParentEntry = NULL;
        }

        // SJ-TBD: Once ACLs are enabled, following check should go in ACLs logic.
        if (VmDirIsInternalEntry( pEntry ) || VmDirIsProtectedEntry(pEntry))
        {
            retVal = VMDIR_ERROR_UNWILLING_TO_PERFORM;
            BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "An internal entry (%s) can NOT be deleted.",
                                          pEntry->dn.lberbv_val );
        }

        // only when there is parent Entry, ACL check is done
        if (pEntry->pParentEntry)
        {
            retVal = VmDirSrvAccessCheck( pOperation, &pOperation->conn->AccessInfo, pEntry->pParentEntry,
                                          VMDIR_RIGHT_DS_DELETE_CHILD);
            BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "VmDirSrvAccessCheck failed - (%u)(%s)",
                                          retVal, VMDIR_ACCESS_DENIED_ERROR_MSG);
        }

        // Make sure it is a leaf node
        retVal = pOperation->pBEIF->pfnBEChkIsLeafEntry(
                                pOperation->pBECtx,
                                pEntry->eId,
                                &leafNode);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "BEChkIsLeafEntry failed, (%u)(%s)",
                                      retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg) );

        if (leafNode == FALSE)
        {
            retVal = VMDIR_ERROR_NOT_ALLOWED_ON_NONLEAF;
            BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Delete of a non-leaf node is not allowed." );
        }

        // Retrieve to determine whether it is domain object earlier
        // before attribute modifications
        // ('bIsDomainObject' is needed for a domain object deletion)
        retVal = VmDirIsDomainObjectWithEntry(pEntry, &bIsDomainObject);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg,
                                      "VmDirIsDomainObjectWithEntry failed - (%u)", retVal );

        if (pOperation->opType != VDIR_OPERATION_TYPE_REPL)
        {
            // Generate mods to delete attributes that need not be present in a DELETED entry
            // Note: in case of executing the deadlock while loop multiple times, same attribute Delete mod be added
            // multiple times in the modReq, which is expected to work correctly.
            retVal = GenerateDeleteAttrsMods( pOperation, pEntry );
            BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "GenerateDeleteAttrsMods failed - (%u)", retVal);

            // Generate new meta-data for the attributes being updated
            if ((retVal = VmDirGenerateModsNewMetaData( pOperation, modReq->mods, pEntry->eId )) != 0)
            {

                switch (retVal)
                {
                    case VMDIR_ERROR_LOCK_DEADLOCK:
                        goto txnretry; // Possible retry.  BUGBUG, is modReq->mods in above call good for retry?

                    default:
                        BAIL_ON_VMDIR_ERROR( retVal );
                }
            }
        }

        // Normalize attribute values in mods
        retVal = VmDirNormalizeMods( pOperation->pSchemaCtx, modReq->mods, &pszLocalErrMsg );
        BAIL_ON_VMDIR_ERROR( retVal );

        // Apply modify operations to the current entry in the DB.
        retVal = VmDirApplyModsToEntryStruct( pOperation->pSchemaCtx, modReq, pEntry, &pszLocalErrMsg );
        BAIL_ON_VMDIR_ERROR( retVal );

        // Update DBs

        // Update Entry
        retVal = pOperation->pBEIF->pfnBEEntryDelete( pOperation->pBECtx, modReq->mods, pEntry );
        if (retVal != 0)
        {
            switch (retVal)
            {
                case VMDIR_ERROR_BACKEND_DEADLOCK:
                    goto txnretry; // Possible retry.

                default:
                    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "BEEntryDelete (%u)(%s)",
                                                  retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
            }
        }

        retVal = DeleteRefAttributesValue(pOperation, &(pEntry->dn));
        if (retVal != 0)
        {
            switch (retVal)
            {
                case VMDIR_ERROR_LOCK_DEADLOCK:
                    goto txnretry; // Possible retry.

                default:
                    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "BEEntryDelete (%u)(%s)",
                                                  retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
            }

        }

        // Use normalized DN value
        if (bIsDomainObject)
        {
            retVal = VmDirInternalRemoveOrgConfig(pOperation,
                                                  BERVAL_NORM_VAL(pEntry->dn));
            BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Update domain list entry failed." );
        }

        retVal = pOperation->pBEIF->pfnBETxnCommit( pOperation->pBECtx);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn commit (%u)(%s)",
                                              retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
        bHasTxn = FALSE;
    }
    // ************************************************************************************
    // transaction retry loop end.
    // ************************************************************************************

    VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Delete Entry (%s)", VDIR_SAFE_STRING(pEntry->dn.lberbv_val));

    // Post delete entry
    // TODO, make it into a separate file deletePlugin.c
    // clean lockout cache record if exists
    VdirLockoutCacheRemoveRec(pEntry->dn.bvnorm_val);

cleanup:

    if (pOperation->opType != VDIR_OPERATION_TYPE_REPL)
    {
        if (retVal == LDAP_SUCCESS)
        {
            int iPostCommitPluginRtn  = 0;

            // Execute post Delete commit plugin logic
            iPostCommitPluginRtn = VmDirExecutePostDeleteCommitPlugins(pOperation, pEntry, retVal);
            if ( iPostCommitPluginRtn != LDAP_SUCCESS
                 &&
                 iPostCommitPluginRtn != pOperation->ldapResult.errCode    // pass through
               )
            {
                VmDirLog( LDAP_DEBUG_ANY, "InternalDeleteEntry: VdirExecutePostDeleteCommitPlugins - code(%d)",
                          iPostCommitPluginRtn);
            }
        }

        // In case of replication, modReq is owned by the Replication thread/logic
        DeleteMods ( modReq );
    }
    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;
}
Exemple #12
0
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;
}
Exemple #13
0
/* VmDirInternalDeleteEntry: Interface that can be used "internally" by the server code. One of the main differences between
 * this function and MLDelete 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
VmDirInternalDeleteEntry(
    PVDIR_OPERATION    pOperation
    )
{
    int         retVal = LDAP_SUCCESS;
    VDIR_ENTRY  entry = {0};
    PVDIR_ENTRY pEntry = NULL;
    BOOLEAN     leafNode = FALSE;
    DeleteReq*  delReq = &(pOperation->request.deleteReq);
    ModifyReq*  modReq = &(pOperation->request.modifyReq);
    BOOLEAN     bIsDomainObject = FALSE;
    BOOLEAN     bHasTxn = FALSE;
    PSTR        pszLocalErrMsg = NULL;
    PVDIR_OPERATION_ML_METRIC   pMLMetrics = NULL;
    extern DWORD VmDirDeleteRaftPreCommit(PVDIR_SCHEMA_CTX, EntryId, char *, PVDIR_OPERATION);

    assert(pOperation && pOperation->pBECtx->pBE);

    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");
    }

    // make sure we have minimum DN length
    if (delReq->dn.lberbv_len < 3)
    {
        retVal = VMDIR_ERROR_INVALID_REQUEST;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "Invalid DN length - (%u)",
                delReq->dn.lberbv_len);
    }

    // Normalize DN
    retVal = VmDirNormalizeDN(&(delReq->dn), pOperation->pSchemaCtx);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "DN normalization failed - (%u)(%s)",
            retVal,
            VDIR_SAFE_STRING(VmDirSchemaCtxGetErrorMsg(pOperation->pSchemaCtx)));

    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 apply Delete plugin logic
    VMDIR_COLLECT_TIME(pMLMetrics->iPrePluginsStartTime);

    retVal = VmDirExecutePreModApplyDeletePlugins(pOperation, NULL, retVal);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "PreModApplyDelete plugin failed - (%u)",
            retVal);

    VMDIR_COLLECT_TIME(pMLMetrics->iPrePlugunsEndTim);

    retVal = VmDirNormalizeMods(pOperation->pSchemaCtx, modReq->mods, &pszLocalErrMsg);
    BAIL_ON_VMDIR_ERROR(retVal);

    // BUGBUG, need to protect some system entries such as schema,domain....etc?

    // Read current entry from DB
    retVal = pOperation->pBEIF->pfnBEDNToEntry(
            pOperation->pBECtx,
            pOperation->pSchemaCtx,
            &(delReq->dn),
            &entry,
            VDIR_BACKEND_ENTRY_LOCK_WRITE);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "(%u)(%s)",
            retVal,
            VDIR_SAFE_STRING(pOperation->pBEErrorMsg));

    pEntry = &entry;

    // Parse Parent DN
    retVal = VmDirGetParentDN(&pEntry->dn, &pEntry->pdn);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "Get ParentDn failed - (%u)",
            retVal);

    // get parent entry
    if (pEntry->pdn.lberbv.bv_val)
    {
        PVDIR_ENTRY     pParentEntry = NULL;

        retVal = VmDirAllocateMemory(sizeof(*pEntry), (PVOID)&pParentEntry);
        BAIL_ON_VMDIR_ERROR(retVal);

        retVal = pOperation->pBEIF->pfnBEDNToEntry(
                pOperation->pBECtx,
                pOperation->pSchemaCtx,
                &pEntry->pdn,
                pParentEntry,
                VDIR_BACKEND_ENTRY_LOCK_READ);
        if (retVal)
        {
            VmDirFreeEntryContent(pParentEntry);
            VMDIR_SAFE_FREE_MEMORY(pParentEntry);

            switch (retVal)
            {
            case VMDIR_ERROR_BACKEND_ENTRY_NOTFOUND:
                BAIL_ON_VMDIR_ERROR_WITH_MSG(
                        retVal, pszLocalErrMsg,
                        "parent (%s) not found, (%s)",
                        pEntry->pdn.lberbv_val,
                        VDIR_SAFE_STRING(pOperation->pBEErrorMsg));

            default:
                BAIL_ON_VMDIR_ERROR_WITH_MSG(
                        retVal, pszLocalErrMsg,
                        "parent (%s) lookup failed, (%s)",
                        pEntry->pdn.lberbv_val,
                        VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
            }
        }

        pEntry->pParentEntry = pParentEntry;    // pEntry takes over pParentEntry
        pParentEntry = NULL;
    }

    //
    // The delete will succeed if the caller either has the explicit right
    // to delete this object or if they have the right to delete children
    // of this object's parent.
    //
    retVal = VmDirSrvAccessCheck(
            pOperation,
            &pOperation->conn->AccessInfo,
            pEntry,
            VMDIR_RIGHT_DS_DELETE_OBJECT);
    if (retVal != ERROR_SUCCESS && pEntry->pParentEntry)
    {
        retVal = VmDirSrvAccessCheck(
                pOperation,
                &pOperation->conn->AccessInfo,
                pEntry->pParentEntry,
                VMDIR_RIGHT_DS_DELETE_CHILD);
    }
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "VmDirSrvAccessCheck failed - (%u)(%s)",
            retVal,
            VMDIR_ACCESS_DENIED_ERROR_MSG);

    // Make sure it is a leaf node
    retVal = pOperation->pBEIF->pfnBEChkIsLeafEntry(
            pOperation->pBECtx,
            pEntry->eId,
            &leafNode);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "BEChkIsLeafEntry failed, (%u)(%s)",
            retVal,
            VDIR_SAFE_STRING(pOperation->pBEErrorMsg));

    if (leafNode == FALSE)
    {
        retVal = VMDIR_ERROR_NOT_ALLOWED_ON_NONLEAF;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "Delete of a non-leaf node is not allowed.");
    }

    // Retrieve to determine whether it is domain object earlier
    // before attribute modifications
    // ('bIsDomainObject' is needed for a domain object deletion)
    retVal = VmDirIsDomainObjectWithEntry(pEntry, &bIsDomainObject);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "VmDirIsDomainObjectWithEntry failed - (%u)",
            retVal);

    retVal = GenerateDeleteAttrsMods(pOperation, pEntry);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "GenerateDeleteAttrsMods failed - (%u)",
            retVal);

    // Normalize attribute values in mods
    retVal = VmDirNormalizeMods(pOperation->pSchemaCtx, modReq->mods, &pszLocalErrMsg);
    BAIL_ON_VMDIR_ERROR(retVal);

    // Apply modify operations to the current entry in the DB.
    retVal = VmDirApplyModsToEntryStruct(pOperation->pSchemaCtx, modReq, pEntry, NULL, &pszLocalErrMsg);
    BAIL_ON_VMDIR_ERROR(retVal);

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

    retVal = DeleteRefAttributesValue(pOperation, &(pEntry->dn));
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "DeleteRefAttributesValue (%u)(%s)",
            retVal,
            VDIR_SAFE_STRING(pOperation->pBEErrorMsg));

    // Use normalized DN value
    if (bIsDomainObject)
    {
        retVal = VmDirInternalRemoveOrgConfig(pOperation, BERVAL_NORM_VAL(pEntry->dn));
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "Update domain list entry failed.");
    }

    if (pOperation->bNoRaftLog == FALSE)
    {
        retVal = VmDirDeleteRaftPreCommit(
            pOperation->pSchemaCtx, pEntry->eId, BERVAL_NORM_VAL(pEntry->dn), pOperation);
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "VmDirDeleteRaftPreCommit error (%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,
                "Delete Entry (%s) logIndex %llu",
                VDIR_SAFE_STRING(pEntry->dn.lberbv_val), pOperation->logIndex);
    }

    // Post delete entry
    // TODO, make it into a separate file deletePlugin.c
    // clean lockout cache record if exists
    VdirLockoutCacheRemoveRec(pEntry->dn.bvnorm_val);

cleanup:

    if (retVal == 0)
    {
        int iPostCommitPluginRtn  = 0;

        VMDIR_COLLECT_TIME(pMLMetrics->iPostPluginsStartTime);

        // Execute post Delete commit plugin logic
        iPostCommitPluginRtn = VmDirExecutePostDeleteCommitPlugins(pOperation, pEntry, retVal);
        if (iPostCommitPluginRtn != LDAP_SUCCESS &&
            iPostCommitPluginRtn != pOperation->ldapResult.errCode) // pass through
        {
            VMDIR_LOG_ERROR(
                    LDAP_DEBUG_ANY,
                    "InternalDeleteEntry: VdirExecutePostDeleteCommitPlugins - code(%d)",
                    iPostCommitPluginRtn);
        }

        VMDIR_COLLECT_TIME(pMLMetrics->iPostPlugunsEndTime);
    }

    // collect metrics
    VMDIR_COLLECT_TIME(pMLMetrics->iMLEndTime);
    VmDirInternalMetricsUpdate(pOperation);
    VmDirInternalMetricsLogInefficientOp(pOperation);

    if (pOperation->opType != VDIR_OPERATION_TYPE_REPL)
    {
        // In case of replication, modReq is owned by the Replication thread/logic
        DeleteMods(modReq);
    }

    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;
}
Exemple #14
0
/* 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;
}
Exemple #15
0
static
int
ProcessCandidateList(
    VDIR_OPERATION * pOperation
    )
{
    int               retVal = LDAP_SUCCESS;
    int               i = 0;
    VDIR_CANDIDATES * cl = pOperation->request.searchReq.filter->candidates;
    VDIR_ENTRY        srEntry = {0};
    VDIR_ENTRY *      pSrEntry = NULL;
    int               numSentEntries = 0;
    BOOLEAN           bInternalSearch = FALSE;
    BOOLEAN           bPageResultsCtrl = FALSE;
    DWORD             dwPageSize = 0;
    ENTRYID           lastEID = 0;

    /*
     * If the page size is greater than or equal to the sizeLimit value,
     * the server should ignore the control as the request can be satisfied in a single page.
     */
    if (pOperation->showPagedResultsCtrl && (pOperation->request.searchReq.sizeLimit == 0 ||
            pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.pageSize < (DWORD)pOperation->request.searchReq.sizeLimit))
    {
        VmDirLog( LDAP_DEBUG_TRACE, "showPagedResultsCtrl applies to this query." );
        bPageResultsCtrl = TRUE;
        dwPageSize = pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.pageSize;
        lastEID = atoi(pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie);
        pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie[0] = '\0';
    }

    if (cl && cl->size > 0)
    {
        if (pOperation->opType == VDIR_OPERATION_TYPE_INTERNAL)
        {   //TODO, we should have a hard limit on the cl->size we handle
            bInternalSearch = TRUE;
            VmDirFreeEntryArrayContent(&pOperation->internalSearchEntryArray);
            retVal = VmDirAllocateMemory(   sizeof(VDIR_ENTRY) * cl->size,
                                            (PVOID*)&pOperation->internalSearchEntryArray.pEntry);
            BAIL_ON_VMDIR_ERROR(retVal);
        }

        for (i = 0, numSentEntries = 0;
             (i < cl->size) && VmDirdState() != VMDIRD_STATE_SHUTDOWN &&
             (pOperation->request.searchReq.sizeLimit == 0 /* unlimited */ ||
              numSentEntries < pOperation->request.searchReq.sizeLimit);
             i++)
        {
            //skip entries we sent before
            if (bPageResultsCtrl && lastEID > 0)
            {
                if (cl->eIds[i] == lastEID)
                {
                    lastEID = 0;
                }
                continue;
            }

            VMDIR_LOG_DEBUG( LDAP_DEBUG_FILTER, "ProcessCandidateList EID(%u)", cl->eIds[i]);

            pSrEntry = bInternalSearch ?
                        (pOperation->internalSearchEntryArray.pEntry + pOperation->internalSearchEntryArray.iSize) : &srEntry;

            retVal = pOperation->pBEIF->pfnBEIdToEntry(
                        pOperation->pBECtx,
                        pOperation->pSchemaCtx,
                        cl->eIds[i],
                        pSrEntry,
                        VDIR_BACKEND_ENTRY_LOCK_READ);

            if (retVal == 0)
            {
                if (CheckIfEntryPassesFilter( pOperation, pSrEntry, pOperation->request.searchReq.filter) == FILTER_RES_TRUE)
                {
                    retVal = VmDirBuildComputedAttribute( pOperation, pSrEntry );
                    BAIL_ON_VMDIR_ERROR( retVal );

                    if (bInternalSearch)
                    {
                        pOperation->internalSearchEntryArray.iSize++;
                        pSrEntry = NULL;    // EntryArray takes over *pSrEntry content
                    }
                    else
                    {
                        retVal = VmDirSendSearchEntry( pOperation, pSrEntry );
                        if (retVal == VMDIR_ERROR_INSUFFICIENT_ACCESS)
                        {
                            VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL,
                                               "Access deny on search entry result [%s,%d] (bindedDN-%s) (targetDn-%s)\n",
                                               __FILE__, __LINE__, pOperation->conn->AccessInfo.pszBindedDn, pSrEntry->dn.lberbv.bv_val);
                            // make sure search continues
                            retVal = 0;
                        }
                        BAIL_ON_VMDIR_ERROR( retVal );

                        if (pSrEntry->bSearchEntrySent)
                        {
                            numSentEntries++;
                        }
                    }
                }

                //We have sent one page size of entries, so we can break here
                if (bPageResultsCtrl && numSentEntries == dwPageSize){
                    retVal = VmDirStringPrintFA(
                            pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie,
                            VMDIR_MAX_I64_ASCII_STR_LEN,
                            "%u",
                            pSrEntry->eId);
                    BAIL_ON_VMDIR_ERROR( retVal );
                    break;
                }

                VmDirFreeEntryContent( pSrEntry );
                pSrEntry = NULL; // Reset to NULL so that DeleteEntry is no-op.
            }
            else
            {
                // Ignore BdbEIdToEntry errors.
                VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "ProcessCandiateList BEIdToEntry EID(%u), error (%u)",
                                                       cl->eIds[i], retVal);
                retVal = 0;
            }
        }

        VMDIR_LOG_VERBOSE( LDAP_DEBUG_FILTER, "(%d) candiates processed and (%d) entries sent", cl->size, numSentEntries);
    }

    if ( pOperation->request.searchReq.sizeLimit && numSentEntries < pOperation->request.searchReq.sizeLimit &&
         pOperation->pBECtx->iPartialCandidates)
    {
        retVal = LDAP_UNWILLING_TO_PERFORM;
        VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "ProcessCandiateList may return none or paritial requested entries with sizelimit %d",
                        pOperation->request.searchReq.sizeLimit);
    }

cleanup:

    pOperation->dwSentEntries = numSentEntries;
    VmDirFreeEntryContent( pSrEntry );

    return retVal;

error:

    VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ProcessCandiateList failed. (%u)", retVal);
    goto cleanup;
}