예제 #1
0
static
int
IsAttrInReplScope(
    VDIR_OPERATION *    op,
    char *              attrType,
    char *              attrMetaData,
    BOOLEAN *           inScope,
    PSTR*               ppszErrorMsg
    )
{
    int                     retVal = LDAP_SUCCESS;
    PLW_HASHTABLE_NODE      pNode = NULL;
    char                    origInvocationId[VMDIR_GUID_STR_LEN];
    USN                     origUsn = VmDirStringToLA( VmDirStringRChrA( attrMetaData, ':' ) + 1, NULL, 10 );
    int                     rc = 0;
    PSTR                    pszLocalErrorMsg = NULL;

    *inScope = FALSE;

    // attrMetaData format is: <local USN>:<version no>:<originating server ID>:<originating time>:<originating USN>
    VmDirStringNCpyA( origInvocationId, VMDIR_GUID_STR_LEN,
                      VmDirStringChrA( VmDirStringChrA( attrMetaData, ':' ) + 1, ':') + 1, VMDIR_GUID_STR_LEN - 1);
    origInvocationId[VMDIR_GUID_STR_LEN - 1] = '\0';

    // Skip the attribute:
    //    - if the originating server for the current state is same as the requesting server or if it is one of those
    //      attributes that have "local" scope only. E.g. sending ATTR_LAST_LOCAL_USN_PROCESSED and
    //      ATTR_UP_TO_DATE_VECTOR, causes continuous back-forth replication of Replication Agreements and Server
    //      entries between various servers.

    assert( op->syncReqCtrl != NULL );

    if ((attrType != NULL && (VmDirStringCompareA( attrType, ATTR_LAST_LOCAL_USN_PROCESSED, FALSE) == 0 ||
                              VmDirStringCompareA( attrType, ATTR_UP_TO_DATE_VECTOR, FALSE) == 0 ||
                              VmDirStringCompareA( attrType, VDIR_ATTRIBUTE_SEQUENCE_RID, FALSE) == 0)))

    {
        // Reset metaData value so that we don't send local only attribute back.
        attrMetaData[0] = '\0';
        *inScope = FALSE;
        goto cleanup;
    }
    else if ( attrType != NULL && (VmDirStringCompareA( attrType, ATTR_USN_CHANGED, FALSE) == 0))
    {
        ; // always send uSNChanged. (PR 1573117)
    }
    else if (VmDirStringCompareA( origInvocationId,
                  op->syncReqCtrl->value.syncReqCtrlVal.reqInvocationId.lberbv.bv_val,TRUE ) == 0)
    {
        // Change is originated from the requesting server.
        // Reset metaData value so that we don't send metaData as well as this attribute back.
        attrMetaData[0] = '\0';
        *inScope = FALSE;
        goto cleanup;
    }
    else
    {
        rc = LwRtlHashTableFindKey( op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector, &pNode, origInvocationId );
        rc = LwNtStatusToWin32Error(rc);
        if (rc != 0 && rc != ERROR_NOT_FOUND)
        {
            VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "IsAttrInReplScope: LwRtlHashTableFindKey failed for origInvocationId: %s",
                      origInvocationId );
            retVal = LDAP_OPERATIONS_ERROR;
            BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                            "LwRtlHashTableFindKey failed.");
        }

        if (pNode == NULL) // Attribute is to be sent in the result entry.
        {
            UptoDateVectorEntry * utdVectorEntry = NULL;
            VDIR_BERVALUE         bvServerId = VDIR_BERVALUE_INIT;

            if (VmDirAllocateMemory( sizeof( UptoDateVectorEntry ), (PVOID *)&utdVectorEntry) != 0)
            {
                retVal = LDAP_OPERATIONS_ERROR;
                BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                                "IsAttrInReplScope: BervalContentDup failed.");
            }
            bvServerId.lberbv.bv_val = origInvocationId;
            bvServerId.lberbv.bv_len = VmDirStringLenA( origInvocationId );
            if (VmDirBervalContentDup( &bvServerId, &utdVectorEntry->invocationId ) != 0)
            {
                retVal = LDAP_OPERATIONS_ERROR;
                BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                                "IsAttrInReplScope: BervalContentDup failed.");
            }
            utdVectorEntry->currMaxOrigUsnProcessed = origUsn;
            LwRtlHashTableResizeAndInsert( op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector,
                                           &utdVectorEntry->Node, &pNode);
            assert( pNode == NULL );    // assert the key of added node is unique
        }
        else
        {
            UptoDateVectorEntry *   utdVectorEntry = NULL;
            utdVectorEntry = (UptoDateVectorEntry *)LW_STRUCT_FROM_FIELD(pNode, UptoDateVectorEntry, Node);

            if (origUsn > utdVectorEntry->reqLastOrigUsnProcessed )
            { // Attribute is to be sent in the result entry.
                // Update if origUsn of this attribute is > the current highest
                if (origUsn > utdVectorEntry->currMaxOrigUsnProcessed )
                {
                    utdVectorEntry->currMaxOrigUsnProcessed = origUsn;
                }
            }
            else
            {
                VMDIR_LOG_VERBOSE( LDAP_DEBUG_REPL_ATTR,
                          "IsAttrInReplScope: Attribute: %s, metaData: %s, replication scope = FALSE",
                          attrType, attrMetaData );

                // Reset metaData value so that we don't send metaData for this attribute back.
                attrMetaData[0] = '\0';
                *inScope = FALSE;
                goto cleanup;
            }
        }
    }

    VMDIR_LOG_INFO( LDAP_DEBUG_REPL_ATTR, "IsAttrInReplScope: Attribute: %s, metaData: %s, replication scope = TRUE",
              attrType, attrMetaData );
    *inScope = TRUE;

cleanup:

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

    return( retVal );

error:

    goto cleanup;
}
예제 #2
0
파일: controls.c 프로젝트: vmware/lightwave
static int
ParseSyncRequestControlVal(
    VDIR_OPERATION *            op,
    BerValue *                  controlValue,       // Input: control value encoded as ber
    SyncRequestControlValue *   syncReqCtrlVal,     // Output
    VDIR_LDAP_RESULT *          lr                  // Output
    )
{
    int                     retVal = LDAP_SUCCESS;
    ber_tag_t               tag = LBER_ERROR;
    ber_len_t               len = 0;
    UptoDateVectorEntry *   utdVectorEntry = NULL;
    BerElementBuffer        berbuf;
    BerElement *            ber = (BerElement *)&berbuf;
    PSTR                    pszLocalErrorMsg = NULL;
    VDIR_BACKEND_CTX        backendCtx = {0};
    USN                     maxPartnerVisibleUSN = 0;

    VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "ParseSyncRequestControlVal: Begin." );

    ber_init2( ber, controlValue, LBER_USE_DER );

    /* http://www.rfc-editor.org/rfc/rfc4533.txt
     *
     *  syncCookie ::= OCTET STRING
     *
     *  syncRequestValue ::= SEQUENCE {
     *          mode ENUMERATED {
     *              -- 0 unused
     *              refreshOnly       (1),
     *              -- 2 reserved
     *              refreshAndPersist (3)
     *          },
     *          cookie     syncCookie OPTIONAL,
     *          reloadHint BOOLEAN DEFAULT FALSE
     *  }
    */

    if (ber_scanf( ber, "{i", &(syncReqCtrlVal->mode) ) == LBER_ERROR)
    {
        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: ber_scanf failed while parsing the sync request "
                  "control mode" );
        lr->errCode = LDAP_PROTOCOL_ERROR;
        retVal = LDAP_NOTICE_OF_DISCONNECT;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                        "Error in reading sync request control mode from PDU.");
    }

    syncReqCtrlVal->bvLastLocalUsnProcessed.lberbv.bv_val = "";
    syncReqCtrlVal->intLastLocalUsnProcessed = 0;

    if (VmDirAllocateMemory( sizeof( VDIR_LDAP_CONTROL ), (PVOID *)&op->syncDoneCtrl) != 0)
    {
        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: VmDirAllocateMemory failed " );
        lr->errCode = retVal = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                        "ParseSyncRequestControlVal: VmDirAllocateMemory failed.");
    }
    op->syncDoneCtrl->type = LDAP_CONTROL_SYNC_DONE;
    if (LwRtlCreateHashTable( &op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector, UtdVectorEntryGetKey,
                              LwRtlHashDigestPstr, LwRtlHashEqualPstr, NULL, VMDIR_UTD_VECTOR_HASH_TABLE_SIZE ) != 0)
    {
        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "UpdateSyncDoneUtdVectorEntry: LwRtlCreateHashTable failed" );
        lr->errCode = retVal = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                        "UpdateSyncDoneUtdVectorEntry: LwRtlCreateHashTable failed");

    }

    tag = ber_peek_tag( ber, &len );

    if (tag == LBER_SEQUENCE)
    { // syncCookie

        /* syncCookie ::= SEQUENCE {
         *                      reqServerId             LDAPString,
         *                      lastLocalUsnProcessed   INTEGER (0 .. maxInt),
         *                      utdVector               UptoDateVectorEntryList }
         *
         *   UptoDateVectorEntryList ::= SEQUENCE OF uptoDateVectorEntry UptoDateVectorEntry
         *
         *   UptoDateVectorEntry ::= SEQUENCE {
         *                            serverId              LDAPString,
         *                            lastOrigUsnProcessed  INTEGER (0 .. maxInt) }
         */
        // {lastLocalUsnProcessed{{<serverid1><lastOrigUsnProcessed1>}{<serverid2><lastOrigUsnProcessed2>}...}}

        if (ber_scanf( ber, "{mmm}",
                        &syncReqCtrlVal->reqInvocationId.lberbv,
                        &syncReqCtrlVal->bvLastLocalUsnProcessed.lberbv,
                        &syncReqCtrlVal->bvUtdVector.lberbv ) == LBER_ERROR )
        {
            VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: ber_scanf failed while parsing "
                      "lastLocalUsnProcessed in the sync request control value" );
            lr->errCode = LDAP_PROTOCOL_ERROR;
            retVal = LDAP_NOTICE_OF_DISCONNECT;
            BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                            "Error in reading lastLocalUsnProcessed in the sync request control value");
        }

        VMDIR_LOG_DEBUG( LDAP_DEBUG_REPL, "ParseSyncRequestControlVal: ServerId: %s, lastLocalUsnProcessed: %s, utdVector: %s",
                  syncReqCtrlVal->reqInvocationId.lberbv.bv_val, syncReqCtrlVal->bvLastLocalUsnProcessed.lberbv.bv_val,
                  syncReqCtrlVal->bvUtdVector.lberbv.bv_val );

        syncReqCtrlVal->intLastLocalUsnProcessed = op->syncDoneCtrl->value.syncDoneCtrlVal.intLastLocalUsnProcessed =
                                   VmDirStringToLA( syncReqCtrlVal->bvLastLocalUsnProcessed.lberbv.bv_val, NULL, 10 );
        {
            char *                  nextServerIdStr = NULL;
            char *                  nextOrigUsnStr = NULL;

            nextServerIdStr = syncReqCtrlVal->bvUtdVector.lberbv.bv_val;

            while( nextServerIdStr != NULL && nextServerIdStr[0] != '\0')
            {
                PLW_HASHTABLE_NODE pNode = NULL;

                if (VmDirAllocateMemory( sizeof(UptoDateVectorEntry), (PVOID *)&utdVectorEntry ) != 0)
                {
                    VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: VmDirAllocateMemory failed " );
                    lr->errCode = retVal = LDAP_OPERATIONS_ERROR;
                    BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                                    "ParseSyncRequestControlVal: VmDirAllocateMemory failed");
                }

                nextOrigUsnStr = VmDirStringChrA( nextServerIdStr, ':');
                *nextOrigUsnStr = '\0';
                nextOrigUsnStr++;
                utdVectorEntry->invocationId.lberbv.bv_val = nextServerIdStr;
                utdVectorEntry->invocationId.lberbv.bv_len = VmDirStringLenA( nextServerIdStr );

                nextServerIdStr = VmDirStringChrA( nextOrigUsnStr, ',');
                *nextServerIdStr = '\0';
                nextServerIdStr++;

                utdVectorEntry->currMaxOrigUsnProcessed = utdVectorEntry->reqLastOrigUsnProcessed =
                                                              atol( nextOrigUsnStr );

                LwRtlHashTableResizeAndInsert( op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector,
                                               &utdVectorEntry->Node, &pNode);
                assert( pNode == NULL );    // assert the key of added node is unique.
            }
        }

        tag = ber_peek_tag( ber, &len );
    }
    if (tag == LBER_BOOLEAN)
    {
        ber_int_t reloadHint;
        if (ber_scanf( ber, "b", &reloadHint) == LBER_ERROR)
        {
            VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: Error in reading reloadHint from the PDU" );
            lr->errCode = LDAP_PROTOCOL_ERROR;
            retVal = LDAP_NOTICE_OF_DISCONNECT;
            BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                            "Error in reading reloadHint from the PDU.");
        }
        if (reloadHint)
        {
            syncReqCtrlVal->reloadHint = TRUE;
        }
    }
    if ( ber_scanf( ber, "}") == LBER_ERROR ) // End of control value
    {
        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: ber_scanf failed while parsing the end of "
                  "sync request control value." );
        lr->errCode = LDAP_PROTOCOL_ERROR;
        retVal = LDAP_NOTICE_OF_DISCONNECT;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                        "Decoding error while parsing the end of sync request control value.");
    }

    backendCtx.pBE = VmDirBackendSelect("");
    maxPartnerVisibleUSN = backendCtx.pBE->pfnBEGetLeastOutstandingUSN( &backendCtx, FALSE ) - 1;

    if (syncReqCtrlVal->intLastLocalUsnProcessed > maxPartnerVisibleUSN)
    {
        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: ServerId %s has processed my USN (%u), my max USN is (%u).",
                         syncReqCtrlVal->reqInvocationId.lberbv.bv_val, syncReqCtrlVal->intLastLocalUsnProcessed, maxPartnerVisibleUSN );
        lr->errCode = LDAP_UNWILLING_TO_PERFORM;
        retVal = LDAP_NOTICE_OF_DISCONNECT;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg), "Partner is ahead of my changes.");
    }

cleanup:
    // Even in the error case, syncDoneCtrl should be freed during operation delete.
    VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "ParseSyncRequestControlVal: End." );
    VmDirBackendCtxContentFree( &backendCtx );
    VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg);

    return retVal;

error:

    VMDIR_APPEND_ERROR_MSG(lr->pszErrMsg, pszLocalErrorMsg);

    goto cleanup;
}
예제 #3
0
/*
 * Test whether the origUsn is in scope so that attribute, attr-meta-data or
 * attr-value-meta-data be sent back to the replicaiton consumer based on whether
 * the origUsn for that invocationId has been processed already by the consumer
 * TODO: Needed Refractoring
 */
DWORD
VmDirIsUsnInScope(
    PVDIR_OPERATION     pOperation,
    PCSTR               pAttrName,
    PCSTR               pszOrigInvocationId,
    USN                 origUsn,
    USN                 localUSN,
    USN                 priorSentUSNCreated,
    PBOOLEAN            pbIsUsnInScope
    )
{
    DWORD                   dwError = 0;
    PLW_HASHTABLE_NODE      pNode = NULL;
    PSTR                    pszLocalErrorMsg = NULL;
    UptoDateVectorEntry     *pUtdVectorEntry = NULL;
    UptoDateVectorEntry     *pNewUtdVectorEntry = NULL;
    int                     retVal = 0;

    if (!pOperation ||
        !pszOrigInvocationId ||
        !pbIsUsnInScope ||
        !pOperation->syncReqCtrl ||
        !pOperation->syncDoneCtrl)
    {
        BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER);
    }

    *pbIsUsnInScope = FALSE;

    //Originating server for the current state is same as the requesting server
    if (VmDirStringCompareA(
                pszOrigInvocationId,
                pOperation->syncReqCtrl->value.syncReqCtrlVal.reqInvocationId.lberbv.bv_val,
                TRUE) == 0)
    {
        *pbIsUsnInScope = FALSE;
        goto cleanup;
    }

    retVal = LwRtlHashTableFindKey(
            pOperation->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector, &pNode, pszOrigInvocationId);

    retVal = LwNtStatusToWin32Error(retVal);

    if (retVal != 0 && retVal != ERROR_NOT_FOUND)
    {
        VMDIR_LOG_VERBOSE(
                VMDIR_LOG_MASK_ALL,
                "%s: LwRtlHashTableFindKey failed for origInvocationId: %s",
                __FUNCTION__,
                pszOrigInvocationId);
        dwError = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, (pszLocalErrorMsg), "LwRtlHashTableFindKey failed.");
    }

    if (pNode == NULL)
    {
        VDIR_BERVALUE    bvServerId = VDIR_BERVALUE_INIT;

        dwError = VmDirAllocateMemory(sizeof(UptoDateVectorEntry), (PVOID *)&pNewUtdVectorEntry);
        BAIL_ON_VMDIR_ERROR(dwError);

        bvServerId.lberbv.bv_val = (PSTR)pszOrigInvocationId;
        bvServerId.lberbv.bv_len = VmDirStringLenA(pszOrigInvocationId);

        dwError = VmDirBervalContentDup(&bvServerId, &pNewUtdVectorEntry->invocationId);
        BAIL_ON_VMDIR_ERROR(dwError);

        pNewUtdVectorEntry->currMaxOrigUsnProcessed = origUsn;

        LwRtlHashTableResizeAndInsert(
                pOperation->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector,
                &pNewUtdVectorEntry->Node,
                &pNode);

        // assert the key of added node is unique
        assert(pNode == NULL);

        pNewUtdVectorEntry = NULL;
        *pbIsUsnInScope = TRUE;

        goto cleanup;
    }

    pUtdVectorEntry = (UptoDateVectorEntry *)LW_STRUCT_FROM_FIELD(pNode, UptoDateVectorEntry, Node);

    if (origUsn > pUtdVectorEntry->reqLastOrigUsnProcessed )
    {
        // attribute or the valueMetaData item in scope if origUsn valueMetaData is > the current highest
        if (origUsn > pUtdVectorEntry->currMaxOrigUsnProcessed )
        {
            pUtdVectorEntry->currMaxOrigUsnProcessed = origUsn;
        }

        // Note, this handles ADD->MODIFY case but not multiple MODIFYs scenario.
        // However, it is fine as consumer should be able to handle redundant feed from supplier.
        // The key point here is to NOT send ATTR_USN_CREATED, so we can derive correct sync_state in WriteSyncStateControl.
        if (localUSN > priorSentUSNCreated)
        {
            *pbIsUsnInScope = TRUE;

            if (priorSentUSNCreated > 0)
            {
                VMDIR_LOG_INFO(
                        LDAP_DEBUG_REPL,
                        "%s new usn %llu after prior usncreated %llu attr %s",
                        __FUNCTION__,
                        origUsn,
                        priorSentUSNCreated,
                        VDIR_SAFE_STRING(pAttrName));
            }
        }
        else
        {
            VMDIR_LOG_INFO(
                    LDAP_DEBUG_REPL,
                    "%s (add->modify) race condition avoided. skip prior usncreated %llu attr %s",
                    __FUNCTION__,
                    priorSentUSNCreated,
                    VDIR_SAFE_STRING(pAttrName));
        }

        goto cleanup;
    }

    VMDIR_LOG_INFO(
            LDAP_DEBUG_REPL,
            "%s: (not in scope) attr name: %s orig invo: %s utdUsn: %"PRId64" usn: %"PRId64,
            __FUNCTION__,
            VDIR_SAFE_STRING(pAttrName),
            VDIR_SAFE_STRING(pszOrigInvocationId),
            pUtdVectorEntry->reqLastOrigUsnProcessed,
            origUsn);

cleanup:
    VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg);
    return dwError;

error:
    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "failed, error (%d)", dwError);
    if (pNewUtdVectorEntry)
    {
        VmDirFreeBervalContent(&pNewUtdVectorEntry->invocationId);
    }
    VMDIR_SAFE_FREE_MEMORY(pNewUtdVectorEntry);
    goto cleanup;
}
예제 #4
0
파일: pscache.c 프로젝트: vmware/lightwave
static
DWORD
VmDirPagedSearchCacheNodeAllocate(
    PVDIR_PAGED_SEARCH_RECORD *ppSearchRec,
    PVDIR_OPERATION pOperation,
    DWORD dwCandidatesProcessed
    )
{
    DWORD dwError = 0;
    PVDIR_PAGED_SEARCH_RECORD pSearchRecord = NULL;
    char szGuidStr[VMDIR_GUID_STR_LEN] = {0};
    uuid_t guid = {0};
    VDIR_BERVALUE strFilter = VDIR_BERVALUE_INIT;

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

    dwError = VmDirUuidGenerate(&guid);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirUuidToStringLower(&guid, szGuidStr, sizeof(szGuidStr));
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirAllocateStringA(szGuidStr, &pSearchRecord->pszGuid);
    BAIL_ON_VMDIR_ERROR(dwError);

    //
    // Capture the original search filter and mark it as undeletable. Because
    // the ava strings aren't allocated separately but are part of the request
    // we have to specifically clone them.
    //
    dwError = FilterToStrFilter(pOperation->request.searchReq.filter, &strFilter);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = StrFilterToFilter(strFilter.lberbv.bv_val, &pSearchRecord->pFilter);
    BAIL_ON_VMDIR_ERROR(dwError);

    pSearchRecord->pTotalCandidates = pOperation->request.searchReq.filter->candidates;
    pOperation->request.searchReq.filter->candidates = NULL;
    pSearchRecord->dwPageSize = pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.pageSize;
    //
    // dwCandidatesProcessed is the count of entries of pFilter->candidates
    // that we went through building up the first page of results. We add
    // one because we want to start our next search past the point of where
    // we've already been.
    //
    pSearchRecord->dwCandidatesProcessed = dwCandidatesProcessed + 1;

    dwError = dequeCreate(&pSearchRecord->pQueue);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirAllocateMutex(&pSearchRecord->mutex);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirAllocateCondition(&pSearchRecord->pDataAvailable);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirPagedSearchCreateThread(pSearchRecord);
    BAIL_ON_VMDIR_ERROR(dwError);

    LwRtlHashTableResizeAndInsert(
                gPagedSearchCache.pHashTbl,
                &pSearchRecord->Node,
                NULL);

    pSearchRecord->dwRefCount = 1;

    pSearchRecord->tLastClientRead = time(NULL);

    *ppSearchRec = pSearchRecord;

cleanup:
    VmDirFreeBervalContent(&strFilter);
    return dwError;
error:
    VmDirPagedSearchCacheRecordFree(pSearchRecord);
    goto cleanup;
}