示例#1
0
VOID
VmDirUnsetAndFreeThrTxnCtx(
    PVMDIR_THREAD_TXN_CONTEXT   pThrTxnCtx
    )
{
    PVMDIR_THREAD_TXN_CONTEXT pLocalTxnCtx = NULL;

    if (pThrTxnCtx)
    {
        VmDirGetThreadTxnContextValue(&pLocalTxnCtx);
        if (pLocalTxnCtx)
        {
            if (pLocalTxnCtx == pThrTxnCtx)
            {
                VmDirSetThreadTxnContextValue(NULL);
            }
            else
            {
                VMDIR_LOG_WARNING(VMDIR_LOG_MASK_ALL, "%s thrtxnctx mismatch. curr ctx (%p), parm ctx (%p)",
                    __FUNCTION__,
                    pLocalTxnCtx,
                    pThrTxnCtx);
            }
        }

        _VmDirFreeThreadTxnContext(pThrTxnCtx);
    }
}
示例#2
0
static
DWORD
_VmDirStopRESTHandle(
    PVMREST_HANDLE    pHandle
    )
{
    DWORD dwError = 0;

    if (pHandle)
    {
        /*
         * REST library have detached threads, maximum time out specified is the max time
         * allowed for the threads to  finish their execution.
         * If finished early, it will return success.
         * If not able to finish in specified time, failure will be returned
         */
        dwError = VmRESTStop(pHandle, VMDIR_REST_STOP_TIMEOUT_SEC);
        if (dwError != 0)
        {
            VMDIR_LOG_WARNING(
                    VMDIR_LOG_MASK_ALL,
                    "%s : Error: %d",
                    __FUNCTION__,
                   dwError);
        }
    }

    return dwError;
}
示例#3
0
// TODO
// should we call this only if promoted? or we need rest-head
// to return unwilling to perform in unpromoted state.
DWORD
VmDirRESTServerInit(
    VOID
    )
{
    DWORD   dwError = 0;

    MODULE_REG_MAP stRegMap[] =
    {
        {"idp", VmDirRESTGetIDPModule},
        {"ldap", VmDirRESTGetLdapModule},
        {"object", VmDirRESTGetObjectModule},
        {"etcd", VmDirRESTGetEtcdModule},
        {"metrics", VmDirRESTGetMetricsModule},
        {NULL, NULL}
    };

    dwError = VmDirRESTLoadVmAfdAPI(&gpVdirVmAfdApi);
    BAIL_ON_VMDIR_ERROR(dwError);

    // cache is only required for token auth
    // post should still handle simple auth
    (VOID)VmDirRESTCacheInit(&gpVdirRestCache);

    dwError = VmDirRESTCurlHandleCacheInit(&gpVdirRestCurlHandleCache);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = coapi_load_from_file(REST_API_SPEC, &gpVdirRestApiDef);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = coapi_map_api_impl(gpVdirRestApiDef, stRegMap);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = _VmDirRESTServerInitHTTP();
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = _VmDirRESTServerInitHTTPS();
    if (dwError != 0)
    {
        VMDIR_LOG_WARNING(
                VMDIR_LOG_MASK_ALL,
                "VmDirRESTServerInit: HTTPS port init failed with error %d, (failure is expected before promote)",
                dwError);
        dwError = 0;
    }

cleanup:
    return dwError;

error:
    if (VmDirRESTServerStop() == 0)
    {
        VmDirRESTServerShutdown();
    }
    goto cleanup;
}
示例#4
0
文件: dbswap.c 项目: vmware/lightwave
static
DWORD
_VmDirComposeHighWaterMark(
    PVMDIR_SWAP_DB_INFO pSwapDBInfo
    )
{
    DWORD               dwError = 0;
    PVDIR_ENTRY         pServerEntry = NULL;
    PVDIR_ATTRIBUTE     pAttrInvocationId = NULL;
    VDIR_OPERATION      searchOp = {0};
    USN                 hwmUSN = 0;

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

    dwError = VmDirInternalSearchSeverObj(pSwapDBInfo->pszPartnerServerName, &searchOp);
    BAIL_ON_VMDIR_ERROR(dwError);

    pServerEntry = searchOp.internalSearchEntryArray.pEntry;
    pAttrInvocationId = VmDirEntryFindAttribute(ATTR_INVOCATION_ID, pServerEntry);

    // use this node max originating usn as high water mark
    dwError = VmDirUTDVectorCacheLookup(
            pSwapDBInfo->pMyUTDVector, pAttrInvocationId->vals[0].lberbv_val, &hwmUSN);
    if (dwError == LW_STATUS_NOT_FOUND)
    {
        VMDIR_LOG_WARNING(VMDIR_LOG_MASK_ALL,
            "Partner (%s,%s) not found in ORG DB UTDVector (%s).  Join scenario NOT supported.",
            pSwapDBInfo->pszPartnerServerName,
            pAttrInvocationId->vals[0].lberbv_val,
            pSwapDBInfo->pMyUTDVector->pszUtdVector);
    }
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirAllocateStringPrintf(&pSwapDBInfo->pszMyHighWaterMark, "%" PRId64, hwmUSN);
    BAIL_ON_VMDIR_ERROR(dwError);

cleanup:
    VmDirFreeOperationContent(&searchOp);

    return dwError;

error:
    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "error (%u)", dwError);
    goto cleanup;
}
示例#5
0
VOID
VmDirInternalMetricsLogInefficientOp(
    PVDIR_OPERATION pOperation
    )
{
    uint64_t                  iRespTime = 0;
    PVDIR_OPERATION_ML_METRIC pMLMetrics = NULL;
    METRICS_LDAP_OPS          op = VmDirMetricsMapLdapOperationToEnum(pOperation->reqCode);

    if (pOperation)
    {
        pMLMetrics = &pOperation->MLMetrics;
        iRespTime = VMDIR_RESPONSE_TIME(pMLMetrics->iMLStartTime, pMLMetrics->iMLEndTime);

        if ((op == METRICS_LDAP_OP_SEARCH && iRespTime > gVmdirServerGlobals.dwEfficientReadOpTimeMS)
                || iRespTime > gVmdirServerGlobals.dwEfficientWriteOpTimeMS)
        {
            VMDIR_LOG_WARNING(
                    VMDIR_LOG_MASK_ALL,
                    "[Middle Layer] Inefficient operation of type %s"
                    " total time(%d) Preplugin(%d) WriteQueue(%d)BETxnBegin(%d) BETxnCommit(%d) PostPlugin(%d)",
                    VmDirMetricsLdapOperationString(op),
                    VMDIR_RESPONSE_TIME(pMLMetrics->iMLStartTime, pMLMetrics->iMLEndTime),
                    VMDIR_RESPONSE_TIME(
                        pMLMetrics->iPrePluginsStartTime, pMLMetrics->iPrePluginsEndTime),
                    VMDIR_RESPONSE_TIME(
                        pMLMetrics->iWriteQueueWaitStartTime, pMLMetrics->iWriteQueueWaitEndTime),
                    VMDIR_RESPONSE_TIME(
                        pMLMetrics->iBETxnBeginStartTime, pMLMetrics->iBETxnBeginEndTime),
                    VMDIR_RESPONSE_TIME(
                        pMLMetrics->iBETxnCommitStartTime, pMLMetrics->iBETxnCommitEndTime),
                    VMDIR_RESPONSE_TIME(
                        pMLMetrics->iPostPluginsStartTime, pMLMetrics->iPostPluginsEndTime));
        }
    }
}
示例#6
0
文件: search.c 项目: vmware/lightwave
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;
}
示例#7
0
文件: search.c 项目: vmware/lightwave
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;
}
示例#8
0
static
DWORD
_VmDirRESTServerInitHTTPS(
    VOID
    )
{
    DWORD   dwError = 0;
    REST_CONF   config = {0};
    PREST_PROCESSOR     pHandlers = &sVmDirHTTPSHandlers;
    PREST_API_MODULE    pModule = NULL;
    PVMREST_HANDLE      pHTTPSHandle = NULL;

    /*
     * If dwHTTPSListenPort is '0' user wants to disable HTTPS service
     * Initializing openssl context is treated as soft fail, gpVdirSslCtx can be NULL
     * If gpVdirSslCtx NULL, don't start the service
     */
    if (gVmdirGlobals.dwHTTPSListenPort == 0 || gVmdirGlobals.gpVdirSslCtx == NULL)
    {
        VMDIR_LOG_WARNING(
                VMDIR_LOG_MASK_ALL,
                "%s : not listening in HTTPS port",
                __FUNCTION__);
        goto cleanup;
    }

    config.serverPort = gVmdirGlobals.dwHTTPSListenPort;
    config.connTimeoutSec = VMDIR_REST_CONN_TIMEOUT_SEC;
    config.maxDataPerConnMB = VMDIR_MAX_DATA_PER_CONN_MB;
    config.pSSLContext = gVmdirGlobals.gpVdirSslCtx;
    config.nWorkerThr = gVmdirServerGlobals.dwRESTWorker;
    config.nClientCnt = gVmdirServerGlobals.dwRESTWorker;
    config.SSLCtxOptionsFlag = 0;
    config.pszSSLCertificate = NULL;
    config.pszSSLKey = NULL;
    config.pszSSLCipherList = NULL;
    config.pszDebugLogFile = NULL;
    config.pszDaemonName = VMDIR_DAEMON_NAME;
    config.isSecure = TRUE;
    config.useSysLog = TRUE;
    config.debugLogLevel = VmDirToCRestEngineLogLevel();

    dwError = VmRESTInit(&config, &pHTTPSHandle);
    BAIL_ON_VMDIR_ERROR(dwError);

    for (pModule = gpVdirRestApiDef->pModules; pModule; pModule = pModule->pNext)
    {
        PREST_API_ENDPOINT pEndPoint = pModule->pEndPoints;
        for (; pEndPoint; pEndPoint = pEndPoint->pNext)
        {
            dwError = VmRESTRegisterHandler(
                    pHTTPSHandle, pEndPoint->pszName, pHandlers, NULL);
            BAIL_ON_VMDIR_ERROR(dwError);
        }
    }

    dwError = VmRESTStart(pHTTPSHandle);
    BAIL_ON_VMDIR_ERROR(dwError);

    gpVdirRestHTTPSHandle = pHTTPSHandle;

cleanup:
    return dwError;

error:
    if (_VmDirStopRESTHandle(pHTTPSHandle) == 0)
    {
        _VmDirFreeRESTHandle(pHTTPSHandle);
    }
    VMDIR_LOG_ERROR(
            VMDIR_LOG_MASK_ALL,
            "%s failed with error %d, not going to listen on REST port (expected before promote)",
            __FUNCTION__,
            dwError);

    goto cleanup;
}
示例#9
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;
}
示例#10
0
DWORD
VmDirUTDVectorUpdateNew(
    PVMDIR_UTDVECTOR_CACHE    pNewUTDVectorCache
    )
{
    USN                origUsnInDB = 0;
    USN                newOrigUsn = 0;
    DWORD              dwError = 0;
    PSTR               pszInvocationId = NULL;
    PSTR               pszKey = NULL;
    LW_HASHMAP_ITER    iter = LW_HASHMAP_ITER_INIT;
    LW_HASHMAP_PAIR    pair = {NULL, NULL};

    if (!pNewUTDVectorCache)
    {
        BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER);
    }

    while (LwRtlHashMapIterate(pNewUTDVectorCache->pUtdVectorMap, &iter, &pair))
    {
        origUsnInDB = 0;
        pszInvocationId = (PSTR) pair.pKey;
        newOrigUsn = (USN) pair.pValue;

        dwError = VmDirUTDVectorGlobalCacheLookup(pszInvocationId, &origUsnInDB);
        if (dwError == LW_STATUS_NOT_FOUND)
        {
            dwError = 0;
        }
        BAIL_ON_VMDIR_ERROR(dwError);

        if (origUsnInDB > newOrigUsn)
        {
            dwError = VmDirAllocateStringA(pszInvocationId, &pszKey);
            BAIL_ON_VMDIR_ERROR(dwError);

            dwError = LwRtlHashMapInsert(
                    pNewUTDVectorCache->pUtdVectorMap,
                    pszKey,
                    (PVOID)origUsnInDB,
                    &pair);
            BAIL_ON_VMDIR_ERROR(dwError);

            pszKey = NULL;
            VmDirSimpleHashMapPairFreeKeyOnly(&pair, NULL);

            VMDIR_LOG_WARNING(
                    VMDIR_LOG_MASK_ALL,
                    "%s: smaller origUsn InvoId: %s origUsnInDB: %"PRId64 "newOrigUsn: %" PRId64,
                    __FUNCTION__,
                    VDIR_SAFE_STRING(pszInvocationId),
                    origUsnInDB,
                    newOrigUsn);
        }
    }

cleanup:
    return dwError;

error:
    VMDIR_SAFE_FREE_MEMORY(pszKey);
    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "failed, error (%d)", dwError);
    goto cleanup;
}
示例#11
0
文件: init.c 项目: vmware/lightwave
/*
 * Initialize MDB db
 * (reference openldap 2.4.31 back-mdb/init.c)
 */
DWORD
VmDirMDBInitializeDB(
    BOOLEAN bMainDB,
    const char *dbHomeDir,
    PVDIR_DB_HANDLE *phHandle
    )
{
    DWORD           dwError = 0;
    unsigned int    envFlags = 0;
    mdb_mode_t      mode = 0;
    uint64_t        db_max_mapsize = BE_MDB_ENV_MAX_MEM_MAPSIZE;
    DWORD           db_max_size_mb = 0;
    DWORD           db_chkpt_interval = 0;
    BOOLEAN         bMdbWalEnable = TRUE;
    PVDIR_MDB_DB pDB = NULL;

    VmDirLog( LDAP_DEBUG_TRACE, "MDBInitializeDB: Begin, DB Home Dir = %s", dbHomeDir );

    //Make a db entry for path. fail if already exist
    dwError = _VmDirMDBInitializeDBEntry(dbHomeDir, &pDB);
    BAIL_ON_VMDIR_ERROR( dwError );

    if (bMainDB)
    {
      pDB->bIsMainDB = TRUE;
    } else
    {
      pDB->bIsMainDB = FALSE;
    }

    dwError = (sizeof(ENTRYID) == sizeof(VDIR_DB_SEQ_T)) ? 0 : ERROR_BACKEND_ERROR;
    BAIL_ON_VMDIR_ERROR( dwError );

    dwError = MDBInitConfig(pDB);
    BAIL_ON_VMDIR_ERROR( dwError );

    /* Create the environment */
    dwError = mdb_env_create ( &pDB->mdbEnv );
    BAIL_ON_VMDIR_ERROR( dwError );

    dwError = mdb_env_set_maxreaders( pDB->mdbEnv, BE_MDB_ENV_MAX_READERS );
    BAIL_ON_VMDIR_ERROR( dwError );

    /* FROM mdb.h
     * The size should be a multiple of the OS page size. The default is
     * 10485760 bytes. The size of the memory map is also the maximum size
     * of the database. The value should be chosen as large as possible,
     * to accommodate future growth of the database.
     *
     * // TODO, this is also the max size of database (per logical mdb db or the total dbs)
     */

     dwError = VmDirGetMaxDbSizeMb(&db_max_size_mb);
     if (dwError != 0)
     {
         VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "Use default max-database-size %llu", BE_MDB_ENV_MAX_MEM_MAPSIZE);
     } else
     {
         db_max_mapsize = (uint64_t)(db_max_size_mb)*1024*1024;
         if (db_max_mapsize < BE_MDB_ENV_MAX_MEM_MAPSIZE)
         {
             db_max_mapsize = BE_MDB_ENV_MAX_MEM_MAPSIZE;
             VMDIR_LOG_WARNING(VMDIR_LOG_MASK_ALL, "RegKey %s value (%u) is too small. Use default max-database-size %llu",
                            VMDIR_REG_KEY_MAXIMUM_DB_SIZE_MB, db_max_size_mb, db_max_mapsize);
         } else
         {
             VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "max-database-size is set to %llu per RegKey %s",
                            db_max_mapsize, VMDIR_REG_KEY_MAXIMUM_DB_SIZE_MB);
         }
     }

     dwError = mdb_env_set_mapsize( pDB->mdbEnv, db_max_mapsize);
     BAIL_ON_VMDIR_ERROR( dwError );

     dwError = mdb_env_set_maxdbs ( pDB->mdbEnv, BE_MDB_ENV_MAX_DBS );
     BAIL_ON_VMDIR_ERROR( dwError );

     dwError = VmDirGetMdbChkptInterval(&db_chkpt_interval);
     if (dwError)
     {
         db_chkpt_interval = VMDIR_REG_KEY_MDB_CHKPT_INTERVAL_DEFAULT;
         dwError = 0;
     }

     VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "%s: %s is set to %d",
        __func__, VMDIR_REG_KEY_MDB_CHKPT_INTERVAL, db_chkpt_interval);

     dwError = mdb_env_set_chkpt_interval(pDB->mdbEnv, db_chkpt_interval);
     BAIL_ON_VMDIR_ERROR( dwError );

     if(bMainDB)
     {
         mdb_set_raft_prepare_commit_func(pDB->mdbEnv, VmDirRaftPrepareCommit);

         mdb_set_raft_post_commit_func(pDB->mdbEnv, VmDirRaftPostCommit);

         mdb_set_raft_commit_fail_func(pDB->mdbEnv, VmDirRaftCommitFail);
     }

#ifdef MDB_NOTLS
     envFlags = MDB_NOTLS; // Required for versions of mdb which have this flag
#endif

     // this is experimental from mdb.h comments
     //envFlags = MDB_FIXEDMAP;        /* use a fixed address for the mmap region */

     //envFlags |= MDB_NOSYNC       need sync for durability
     //envFlags |= MDB_RDONLY       need to open for read and write

    /* Open the environment.  */

#ifndef _WIN32
    mode = S_IRUSR | S_IWUSR;
#else
    mode = GENERIC_READ|GENERIC_WRITE;
#endif

    //MDB WAL is the default mode and can be turned off with reg key MdbEnableWal set to 0
    dwError = VmDirGetMdbWalEnable(&bMdbWalEnable);
    if (dwError)
    {
        bMdbWalEnable = TRUE;
        dwError = 0;
    }

    VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "%s: %s is set to %s",
      __func__, VMDIR_REG_KEY_MDB_ENABLE_WAL, bMdbWalEnable?"True":"False");

    if (bMdbWalEnable)
    {
        envFlags |= MDB_WAL;
    }

    dwError = mdb_env_open ( pDB->mdbEnv, dbHomeDir, envFlags, mode );
//TODO, what if open failed?  how to recover??
    BAIL_ON_VMDIR_ERROR( dwError );

    mdb_set_error_log_func(&VmDirMdbErrorLog);

    /* Open main database. */
    dwError = MDBOpenMainDB(pDB);
    BAIL_ON_VMDIR_ERROR( dwError );

    /* Open sequences */
    dwError = MDBOpenSequence(pDB);
    BAIL_ON_VMDIR_ERROR( dwError );

    /* Open generic */
    dwError = MDBOpenGeneric(pDB);
    BAIL_ON_VMDIR_ERROR( dwError );

    /* Initialize indices */
    dwError = VmDirMDBInitializeIndexDB(pDB);
    BAIL_ON_VMDIR_ERROR( dwError );

    dwError = VmDirInitMdbStateGlobals();
    BAIL_ON_VMDIR_ERROR(dwError);

    VmDirLogDBStats(pDB);

    /* TODO: require per db txn stats for raft groups */
    if (bMainDB)
    {
        dwError = _VmDirWtxnStatsInit();
        BAIL_ON_VMDIR_ERROR( dwError );
    }

    *phHandle = pDB;

    VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "%s: succeeded with dbHomeDir %s", __func__, dbHomeDir); 

cleanup:
    VmDirLog( LDAP_DEBUG_TRACE, "MDBInitializeDB: End" );

    return dwError;

error:

    VmDirLog( LDAP_DEBUG_ANY, "MDBInitializeDB failed with error code: %d, error string: %s", dwError, mdb_strerror(dwError) );

//TODO, should shutdown here or caller will do that?
//gVdirMdbGlobals.mdbEnv = NULL;

    goto cleanup;
}
示例#12
0
DWORD
VmDirRESTServerInit(
    VOID
    )
{
    DWORD dwError = 0;

    MODULE_REG_MAP stRegMap[] =
    {
        {"ldap", VmDirRESTGetLdapModule},
        {"metrics", VmDirRESTGetMetricsModule},
        {"account", VmDirRESTGetAccountModule},
        {NULL, NULL}
    };

    MODULE_REG_MAP stRegMapApi[] =
    {
        {"certs", VmDirRESTApiGetCertsModule},
        {"password", VmDirRESTApiGetPasswordModule},
        {"join", VmDirRESTApiGetJoinModule},
        {NULL, NULL}
    };

    // cache is only required for token auth
    // vmdir should still handle simple auth
    (VOID)VmDirRESTCacheInit(&gpVdirRestCache);

    /*
     * We can use the same REST_API_SPEC for both HTTP and HTTPS because vmdir
     * rest init code only refers to API definitions (which is common)
     */
    dwError = coapi_load_from_file(REST_API_SPEC, &gpVdirRestApiDef);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = coapi_map_api_impl(gpVdirRestApiDef, stRegMap);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = _VmDirRESTServerInitHTTP();
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = _VmDirRESTServerInitHTTPS();
    if (dwError != 0)
    {
        /*
         * Before promoting lightwave node, obtaining cert from VECS will fail which is expected
         * hence treat it as soft fail
         */
         VMDIR_LOG_WARNING(
                 VMDIR_LOG_MASK_ALL,
                 "VmRESTServerInit: HTTPS port init failed with error %d, (failure is expected before promote)",
                 dwError);
         dwError = 0;
    }

    dwError = coapi_load_from_file(REST_API_SPEC_2, &gpVdirRestApiDef2);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = coapi_map_api_impl(gpVdirRestApiDef2, stRegMapApi);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = _VmDirRESTServerInitApiHTTPS();
    if (dwError != 0)
    {
        /*
         * Before promoting lightwave node, obtaining cert from VECS will fail which is expected
         * hence treat it as soft fail
         */
         VMDIR_LOG_WARNING(
                 VMDIR_LOG_MASK_ALL,
                 "VmRESTServerInit: Api server HTTPS port init failed with error %d, (failure is expected before promote)",
                 dwError);
         dwError = 0;
    }

cleanup:
    return dwError;

error:
    if (VmDirRESTServerStop() == 0)
    {
        VmDirRESTServerShutdown();
    }
    VMDIR_LOG_ERROR(
            VMDIR_LOG_MASK_ALL,
            "%s failed, error (%d)",
            __FUNCTION__,
            dwError);

    goto cleanup;
}
示例#13
0
static
DWORD
_VmDirRESTServerInitHTTP(
    VOID
    )
{
    DWORD   dwError = 0;
    REST_CONF   config = {0};
    PREST_PROCESSOR    pHandlers = &sVmDirRESTLdapHandlers;
    PREST_API_MODULE   pModule = NULL;
    PVMREST_HANDLE     pHTTPHandle = NULL;

    /*
     * dwHTTPListenPort is '0' then user wants to disable HTTP endpoint
     */
    if (gVmdirGlobals.dwHTTPListenPort == 0)
    {
        VMDIR_LOG_WARNING(
                VMDIR_LOG_MASK_ALL,
                "%s : not listening in HTTP port",
                __FUNCTION__);
        goto cleanup;
    }

    config.serverPort = gVmdirGlobals.dwHTTPListenPort;
    config.connTimeoutSec = VMDIR_REST_CONN_TIMEOUT_SEC;
    config.maxDataPerConnMB = VMDIR_MAX_DATA_PER_CONN_MB;
    config.pSSLContext = NULL;
    config.nWorkerThr = VMDIR_REST_WORKERTHCNT;
    config.nClientCnt = VMDIR_REST_CLIENTCNT;
    config.SSLCtxOptionsFlag = 0;
    config.pszSSLCertificate = NULL;
    config.pszSSLKey = NULL;
    config.pszSSLCipherList = NULL;
    config.pszDebugLogFile = NULL;
    config.pszDaemonName = VMDIR_DAEMON_NAME;
    config.isSecure = FALSE;
    config.useSysLog = TRUE;
    config.debugLogLevel = VmDirToCRestEngineLogLevel();

    dwError = VmRESTInit(&config, &pHTTPHandle);
    BAIL_ON_VMDIR_ERROR(dwError);

    for (pModule = gpVdirRestApiDef->pModules; pModule; pModule = pModule->pNext)
    {
        PREST_API_ENDPOINT pEndPoint = pModule->pEndPoints;
        for (; pEndPoint; pEndPoint = pEndPoint->pNext)
        {
            dwError = VmRESTRegisterHandler(
                     pHTTPHandle, pEndPoint->pszName, pHandlers, NULL);
            BAIL_ON_VMDIR_ERROR(dwError);
        }
    }

    dwError = VmRESTStart(pHTTPHandle);
    BAIL_ON_VMDIR_ERROR(dwError);

    gpVdirRestHTTPHandle = pHTTPHandle;

cleanup:
    return dwError;

error:
    if (_VmDirStopRESTHandle(pHTTPHandle) == 0)
    {
        _VmDirFreeRESTHandle(pHTTPHandle, gpVdirRestApiDef);
    }
    VMDIR_LOG_ERROR(
            VMDIR_LOG_MASK_ALL,
            "%s failed, error (%d)",
            __FUNCTION__,
            dwError);

    goto cleanup;
}
示例#14
0
static
DWORD
_VmDirDCConnThreadFun(
    PVOID pArg
    )
{
    DWORD dwError = 0;
    DWORD dwSleepTimeSec = 0;
    DWORD dwThrStartTime = time(NULL);
    PVMDIR_DC_CONNECTION pDCConn = (PVMDIR_DC_CONNECTION)pArg;

    pDCConn->connState = DC_CONNECTION_STATE_CONNECTING;

    VMDIR_LOG_VERBOSE(VMDIR_LOG_MASK_ALL,
        "%s user (%s) connecting to (%s) started",
        __FUNCTION__,
        VDIR_SAFE_STRING(pDCConn->creds.pszUPN),
        VDIR_SAFE_STRING(pDCConn->pszRemoteDCHostName));

    while (TRUE)
    {
        if (!_VmDirHasCredInfo(&pDCConn->creds))
        {
            BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_USER_INVALID_CREDENTIAL);
        }

        dwError = _VmDirConnectToDC(pDCConn);
        if (dwError == 0)
        {
            VMDIR_LOG_VERBOSE(VMDIR_LOG_MASK_ALL,
                "%s user (%s) connected to (%s) done",
                __FUNCTION__,
                VDIR_SAFE_STRING(pDCConn->creds.pszUPN),
                VDIR_SAFE_STRING(pDCConn->pszRemoteDCHostName));

            // have a live connection, transfer ownership back to owner
            pDCConn->connState = DC_CONNECTION_STATE_CONNECTED;
            goto cleanup;
        }

        if (pDCConn->connType == DC_CONNECTION_TYPE_BASIC)
        {
            goto error;  // no retry, bail
        }

        if (dwError == VMDIR_ERROR_USER_INVALID_CREDENTIAL)
        {
            dwSleepTimeSec = MAX_DC_CONNECT_SLEEP_TIME_SEC;
        }
        else if (dwError == VMDIR_ERROR_SERVER_DOWN || dwError == VMDIR_ERROR_NETWORK_TIMEOUT)
        {
            dwSleepTimeSec = UNIT_DC_CONNECT_SLEEP_TIME_SEC * pDCConn->dwConsecutiveFailAttempt;
        }
        else
        {
            goto error;
        }

        if (dwSleepTimeSec >= MAX_DC_CONNECT_SLEEP_TIME_SEC)
        {
            dwSleepTimeSec = MAX_DC_CONNECT_SLEEP_TIME_SEC;
        }

        VMDIR_LOG_WARNING(VMDIR_LOG_MASK_ALL,
            "%s URGENT %s (%s) connection to (%s) failed (%d) times, last error (%d), sleep (%d)",
            __FUNCTION__,
            _VmDirDCConnType(pDCConn->connType),
            VDIR_SAFE_STRING(pDCConn->creds.pszUPN),
            VDIR_SAFE_STRING(pDCConn->pszRemoteDCHostName),
            pDCConn->dwConsecutiveFailAttempt,
            pDCConn->dwlastFailedError,
            dwSleepTimeSec);

        if (time(NULL) - dwThrStartTime >= MAX_DC_CONNECT_DURATION_TIME_SEC)
        {
            // bail to allow deleted RA cache clean up
            BAIL_WITH_VMDIR_ERROR(dwError, pDCConn->dwlastFailedError);
        }

        while (dwSleepTimeSec)
        {
            VmDirSleep(1000);  // pause 1 second
            dwSleepTimeSec--;

            if (VmDirdState() == VMDIRD_STATE_SHUTDOWN)
            {
                goto cleanup;
            }
        }
    }

cleanup:
    VmDirFreeConnCredContent(&pDCConn->creds);

    return dwError;

error:
    pDCConn->connState = DC_CONNECTION_STATE_FAILED;

    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL,
        "%s user (%s) connect to (%s) failed (%d), connection state set to failed",
        __FUNCTION__,
        VDIR_SAFE_STRING(pDCConn->creds.pszUPN),
        VDIR_SAFE_STRING(pDCConn->pszRemoteDCHostName),
        dwError);

    goto cleanup;
}
示例#15
0
static
int
BindListenOnPort(
#ifndef _WIN32
   sa_family_t   addr_type,
   size_t        addr_size,
#else
   short         addr_type,
   int           addr_size,
#endif
    void         *pServ_addr,
    ber_socket_t *pSockfd
)
{
#define LDAP_PORT_LISTEN_BACKLOG 128
   int  optname = 0;
   int  retVal = LDAP_SUCCESS;
   int  retValBind = 0;
   PSTR pszLocalErrMsg = NULL;
   int  on = 1;
#ifdef _WIN32
   DWORD sTimeout = 0;
   int  reTries = 0;
#else
   struct timeval sTimeout = {0};
#endif

   *pSockfd = -1;
   *pSockfd = socket(addr_type, SOCK_STREAM, 0);
   if (*pSockfd < 0)
   {
#ifdef _WIN32
      errno = WSAGetLastError();
#endif
      retVal = LDAP_OPERATIONS_ERROR;
      BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg,
                      "%s: socket() call failed with errno: %d", __func__, errno );
   }

#ifdef _WIN32
    optname = SO_EXCLUSIVEADDRUSE;
#else
    optname = SO_REUSEADDR;
#endif

   if (setsockopt(*pSockfd, SOL_SOCKET, optname, (const char *)(&on), sizeof(on)) < 0)
   {
#ifdef _WIN32
      errno = WSAGetLastError();
#endif
      retVal = LDAP_OPERATIONS_ERROR;
      BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg,
                      "%s: setsockopt() call failed with errno: %d", __func__, errno );
   }

   on = 1;  // turn on TCP_NODELAY below

   if (setsockopt(*pSockfd,  IPPROTO_TCP, TCP_NODELAY, (const char *)(&on), sizeof(on) ) < 0)
   {
#ifdef _WIN32
      errno = WSAGetLastError();
#endif
      retVal = LDAP_OPERATIONS_ERROR;
      BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg,
                      "%s: setsockopt() TCP_NODELAY call failed with errno: %d", __func__, errno );
   }

   if (addr_type == AF_INET6)
   {
#ifdef _WIN32
       if (setsockopt(*pSockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)(&on), sizeof(on) ) < 0)
       {
           errno = WSAGetLastError();
#else
       if (setsockopt(*pSockfd, SOL_IPV6, IPV6_V6ONLY, (const char *)(&on), sizeof(on) ) < 0)
       {
#endif
           retVal = LDAP_OPERATIONS_ERROR;
           BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg,
                      "%s: setsockopt() IPV6_V6ONLY call failed with errno: %d", __func__, errno );
       }
   }

   if (gVmdirGlobals.dwLdapRecvTimeoutSec > 0)
   {
#ifdef _WIN32
       sTimeout = gVmdirGlobals.dwLdapRecvTimeoutSec*1000;
#else
       sTimeout.tv_sec = gVmdirGlobals.dwLdapRecvTimeoutSec;
       sTimeout.tv_usec = 0;
#endif
       if (setsockopt(*pSockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &sTimeout, sizeof(sTimeout)) < 0)
       {
#ifdef _WIN32
           errno = WSAGetLastError();
#endif
           retVal = LDAP_OPERATIONS_ERROR;
           BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg,
                      "%s: setsockopt() SO_RCVTIMEO failed, errno: %d", __func__, errno );
       }
   }

   retValBind = bind(*pSockfd, (struct sockaddr *) pServ_addr, addr_size);

#ifdef _WIN32
   // Add retry logic per PR 1347783
   reTries = 0;
   while (retValBind != 0 && reTries < MAX_NUM_OF_BIND_PORT_RETRIES)
   {
      errno = WSAGetLastError();
      if (errno != WSAEADDRINUSE)
      {
         break;
      }
      reTries++;
      VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "%s: bind() call failed with errno: %d, re-trying (%d)",
                                   __func__, errno, reTries);
      VmDirSleep(1000);
      retValBind = bind(*pSockfd, (struct sockaddr *) pServ_addr, addr_size);
   }
#endif

   if (retValBind != 0)
   {
      retVal = LDAP_OPERATIONS_ERROR;
      //need to free socket ...
      BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg,
                      "%s: bind() call failed with errno: %d", __func__, errno );
   }

   if (listen(*pSockfd, LDAP_PORT_LISTEN_BACKLOG) != 0)
   {
#ifdef _WIN32
      errno = WSAGetLastError();
#endif
      retVal = LDAP_OPERATIONS_ERROR;
      BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg,
                      "%s: listen() call failed with errno: %d", __func__, errno );
   }

cleanup:

    VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg);
    return retVal;

error:

    if (*pSockfd >= 0)
    {
        tcp_close(*pSockfd);
        *pSockfd = -1;
    }
    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, VDIR_SAFE_STRING(pszLocalErrMsg));
    goto cleanup;
}

/*
 *  We own pConnection and delete it when done.
 */
static
DWORD
ProcessAConnection(
   PVOID pArg
   )
{
   VDIR_CONNECTION *pConn = NULL;
   int            retVal = LDAP_SUCCESS;
   ber_tag_t      tag = LBER_ERROR;
   ber_len_t      len = 0;
   BerElement *   ber = NULL;
   ber_int_t      msgid = -1;
   PVDIR_OPERATION pOperation = NULL;
   int            reTries = 0;
   BOOLEAN                      bDownOpThrCount = FALSE;
   PVDIR_CONNECTION_CTX pConnCtx = NULL;

   // increment operation thread counter
   retVal = VmDirSyncCounterIncrement(gVmdirGlobals.pOperationThrSyncCounter);
   BAIL_ON_VMDIR_ERROR(retVal);
   bDownOpThrCount = TRUE;

   pConnCtx = (PVDIR_CONNECTION_CTX)pArg;
   assert(pConnCtx);

   retVal = NewConnection(pConnCtx->sockFd, &pConn, pConnCtx->pSockbuf_IO);
   if (retVal != LDAP_SUCCESS)
   {
       VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: NewConnection [%d] failed with error: %d",
                        __func__, pConnCtx->sockFd, retVal);
       goto error;
   }

   while (TRUE)
   {
       if (VmDirdState() == VMDIRD_STATE_SHUTDOWN)
       {
           goto cleanup;
       }

      ber = ber_alloc();
      assert( ber != NULL);

      /* An LDAP request message looks like:
       * LDAPMessage ::= SEQUENCE {
       *                    messageID       MessageID,
       *                    protocolOp      CHOICE {
       *                       bindRequest     BindRequest,
       *                       unbindRequest   UnbindRequest,
       *                       searchRequest   SearchRequest,
       *                       ... },
       *                       controls       [0] Controls OPTIONAL }
       */


      // reset retry count
      reTries = 0;
      // Read complete LDAP request message (tag, length, and real message).
      while( reTries < MAX_NUM_OF_SOCK_READ_RETRIES )
      {
         if ((tag = ber_get_next( pConn->sb, &len, ber )) == LDAP_TAG_MESSAGE )
         {
            break;
         }

#ifdef _WIN32
         // in ber_get_next (liblber) call, sock_errset() call WSASetLastError()
         errno = WSAGetLastError();
         if ( errno == EWOULDBLOCK || errno == EAGAIN || errno == WSAETIMEDOUT)
#else
         if ( errno == EWOULDBLOCK || errno == EAGAIN)
#endif
         {
            if (gVmdirGlobals.dwLdapRecvTimeoutSec > 0 && ber->ber_len == 0)
            {
                VMDIR_LOG_INFO( LDAP_DEBUG_CONNS,
                    "%s: disconnecting peer (%s), idle > %d seconds",
                    __func__, pConn->szClientIP, gVmdirGlobals.dwLdapRecvTimeoutSec);
                retVal = LDAP_NOTICE_OF_DISCONNECT;
                BAIL_ON_VMDIR_ERROR( retVal );
            }

            //This may occur when not all data have recieved - set to EAGAIN/EWOULDBLOCK by ber_get_next,
            // and in such case ber->ber_len > 0;
            if (reTries > 0 && reTries % 5 == 0)
            {
                VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "%s: ber_get_next() failed with errno = %d, peer (%s), re-trying (%d)",
                                   __func__, errno , pConn->szClientIP, reTries);
            }
            VmDirSleep(200);
            reTries++;
            continue;
         }
         // Unexpected error case.
         if (errno == 0)
         {
             VMDIR_LOG_INFO( LDAP_DEBUG_CONNS, "%s: ber_get_next() peer (%s) disconnected",
                 __func__, pConn->szClientIP);
         } else
         {
             VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: ber_get_next() call failed with errno = %d peer (%s)",
                  __func__, errno, pConn->szClientIP);
         }
         retVal = LDAP_NOTICE_OF_DISCONNECT;
         BAIL_ON_VMDIR_ERROR( retVal );
      }

      // Read LDAP request messageID (tag, length (not returned since it is implicit/integer), and messageID value)
      if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID )
      {
         VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ProcessAConnection: ber_get_int() call failed." );
         retVal = LDAP_NOTICE_OF_DISCONNECT;
         BAIL_ON_VMDIR_ERROR( retVal );
      }

      // Read protocolOp (tag) and length of the LDAP operation message, and leave the pointer at the beginning
      // of the LDAP operation message (to be parsed by PerformXYZ methods).
      if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR )
      {
         VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ProcessAConnection: ber_peek_tag() call failed." );
         retVal = LDAP_NOTICE_OF_DISCONNECT;
         BAIL_ON_VMDIR_ERROR( retVal );
      }

      retVal = VmDirNewOperation(ber, msgid, tag, pConn, &pOperation);
      if (retVal)
      {
          VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ProcessAConnection: NewOperation() call failed." );
          retVal = LDAP_OPERATIONS_ERROR;
      }
      BAIL_ON_VMDIR_ERROR( retVal );

      //
      // If this is a multi-stage operation don't overwrite the start time if it's already set.
      //
      pConn->SuperLogRec.iStartTime = pConn->SuperLogRec.iStartTime ? pConn->SuperLogRec.iStartTime : VmDirGetTimeInMilliSec();

      switch (tag)
      {
         case LDAP_REQ_BIND:
            retVal = VmDirPerformBind(pOperation);
            if (retVal != LDAP_SASL_BIND_IN_PROGRESS)
            {
                _VmDirCollectBindSuperLog(pConn, pOperation); // ignore error
            }

            break;

         case LDAP_REQ_ADD:
            retVal = VmDirPerformAdd(pOperation);
            break;

         case LDAP_REQ_SEARCH:
            retVal = VmDirPerformSearch(pOperation);
            break;

         case LDAP_REQ_UNBIND:
            retVal = VmDirPerformUnbind(pOperation);
            break;

         case LDAP_REQ_MODIFY:
             retVal = VmDirPerformModify(pOperation);
             break;

         case LDAP_REQ_DELETE:
             retVal = VmDirPerformDelete(pOperation);
             break;

         case LDAP_REQ_MODDN:
         case LDAP_REQ_COMPARE:
         case LDAP_REQ_ABANDON:
         case LDAP_REQ_EXTENDED:
            VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "ProcessAConnection: Operation is not yet implemented.." );
            pOperation->ldapResult.errCode = retVal = LDAP_UNWILLING_TO_PERFORM;
            // ignore following VmDirAllocateStringA error.
            VmDirAllocateStringA( "Operation is not yet implemented.", &pOperation->ldapResult.pszErrMsg);
            VmDirSendLdapResult( pOperation );
            break;

         default:
            pOperation->ldapResult.errCode = LDAP_PROTOCOL_ERROR;
            retVal = LDAP_NOTICE_OF_DISCONNECT;
            break;
      }

      pConn->SuperLogRec.iEndTime = VmDirGetTimeInMilliSec();
      VmDirOPStatisticUpdate(tag, pConn->SuperLogRec.iEndTime - pConn->SuperLogRec.iStartTime);

      if (tag != LDAP_REQ_BIND)
      {
         VmDirLogOperation(gVmdirGlobals.pLogger, tag, pConn, pOperation->ldapResult.errCode);

         _VmDirScrubSuperLogContent(tag, &pConn->SuperLogRec);
      }

      VmDirFreeOperation(pOperation);
      pOperation = NULL;

      ber_free( ber, 1);
      ber = NULL;

      if (retVal == LDAP_NOTICE_OF_DISCONNECT) // returned as a result of protocol parsing error.
      {
         // RFC 4511, section 4.1.1: If the server receives an LDAPMessage from the client in which the LDAPMessage
         // SEQUENCE tag cannot be recognized, the messageID cannot be parsed, the tag of the protocolOp is not
         // recognized as a request, or the encoding structures or lengths of data fields are found to be incorrect,
         // then the server **SHOULD** return the Notice of Disconnection, with the resultCode
         // set to protocolError, and **MUST** immediately terminate the LDAP session as described in Section 5.3.

         goto cleanup;
      }
   }

cleanup:
   if (retVal == LDAP_NOTICE_OF_DISCONNECT)
   {
      // Optionally send Notice of Disconnection with rs->err.
   }
   if (ber != NULL)
   {
      ber_free( ber, 1 );
   }
    VmDirDeleteConnection(&pConn);
    VMDIR_SAFE_FREE_MEMORY(pConnCtx);
    VmDirFreeOperation(pOperation);

    if (bDownOpThrCount)
    {
        VmDirSyncCounterDecrement(gVmdirGlobals.pOperationThrSyncCounter);
    }

    _VmDirFlowCtrlThrExit();

    // TODO: should we return dwError ?
    return 0;

error:
    goto cleanup;
}
示例#16
0
DWORD
VmDirCreateThread(
    PVMDIR_THREAD pThread,
    BOOLEAN bJoinThr,
    VmDirStartRoutine* pStartRoutine,
    PVOID pArgs
    )
{
    DWORD                       dwError = ERROR_SUCCESS;
    PVMDIR_THREAD_START_INFO    pThreadStartInfo = NULL;
    pthread_attr_t              thrAttr;
    BOOLEAN                     bThreadAttrInited = FALSE;
    int                         iRetryCnt = 0;

    if (!pThread || !pStartRoutine)
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    if (!bJoinThr)
    {
        pthread_attr_init(&thrAttr);
        bThreadAttrInited = TRUE;
        pthread_attr_setdetachstate(&thrAttr, PTHREAD_CREATE_DETACHED);
    }

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

    pThreadStartInfo->pStartRoutine = pStartRoutine;
    pThreadStartInfo->pArgs = pArgs;

    do
    {
        dwError = pthread_create(
                        pThread,
                        (bJoinThr ? NULL : &thrAttr),
                        ThreadFunction,
                        pThreadStartInfo
                        );
        if (dwError == EAGAIN)  // no resources, retry after 1 second pause
        {
            iRetryCnt++ ;
            VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "pthread_create EAGAIN, retry (%d)", iRetryCnt );
            VmDirSleep(1 * 1000); // sleep one second
        }
        else
        {
            iRetryCnt = VMDIR_MAX_EAGAIN_RETRY;
        }
    } while (iRetryCnt < VMDIR_MAX_EAGAIN_RETRY);
    BAIL_ON_VMDIR_ERROR(dwError);

    // we started successfully -> pThreadStartInfo is now owned by
    // ThreadFunction
    pThreadStartInfo = NULL;

error:
    if (bThreadAttrInited)
    {
        pthread_attr_destroy(&thrAttr);
    }
    VMDIR_SAFE_FREE_MEMORY(pThreadStartInfo);
    return dwError;
}
示例#17
0
static
DWORD
vmdirConnAccept(
    Sockbuf_IO*         pSockbuf_IO,
    DWORD               dwPort,
    BOOLEAN             bIsLdaps
    )
{
    ber_socket_t         newsockfd = -1;
    int                  retVal = LDAP_SUCCESS;
    ber_socket_t         ip4_fd = -1;
    ber_socket_t         ip6_fd = -1;
    ber_socket_t         max_fd = -1;
    VMDIR_THREAD         threadId;
    BOOLEAN              bInLock = FALSE;
    int                  iLocalLogMask = 0;
    PVDIR_CONNECTION_CTX pConnCtx = NULL;
    fd_set               event_fd_set;
    fd_set               poll_fd_set;
    struct timeval       timeout = {0};

    // Wait for ***1st*** replication cycle to be over.
    if (gVmdirServerGlobals.serverId == 0) // instance has not been initialized
    {
        VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "Connection accept thread: Have NOT yet started listening on LDAP port (%u),"
                  " waiting for the 1st replication cycle to be over.", dwPort);

        VMDIR_LOCK_MUTEX(bInLock, gVmdirGlobals.replCycleDoneMutex);
        // wait till 1st replication cycle is over
        if (VmDirConditionWait( gVmdirGlobals.replCycleDoneCondition, gVmdirGlobals.replCycleDoneMutex ) != 0)
        {
            VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "Connection accept thread: VmDirConditionWait failed." );
            retVal = LDAP_OPERATIONS_ERROR;
            goto cleanup;
        }
        // also wake up the other (normal LDAP port/SSL LDAP port listner) LDAP connection accept thread,
        // waiting on 1st replication cycle to be over
        // BUGBUG Does not handle spurious wake up
        VmDirConditionSignal(gVmdirGlobals.replCycleDoneCondition);
        VMDIR_UNLOCK_MUTEX(bInLock, gVmdirGlobals.replCycleDoneMutex);

        if (VmDirdState() == VMDIRD_STATE_SHUTDOWN) // Asked to shutdown before we started accepting
        {
            goto cleanup;
        }

        VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Connection accept thread: listening on LDAP port (%u).", dwPort);
    }

    iLocalLogMask = VmDirLogGetMask();
    ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &iLocalLogMask);

    SetupLdapPort(dwPort, &ip4_fd, &ip6_fd);
    if (ip4_fd < 0 && ip6_fd < 0)
    {
        VmDirSleep(1000);
        goto cleanup;
    }

    FD_ZERO(&event_fd_set);
    if (ip4_fd >= 0)
    {
        FD_SET (ip4_fd, &event_fd_set);
        if (ip4_fd > max_fd)
        {
            max_fd = ip4_fd;
        }
    }

    if (ip6_fd >= 0)
    {
        FD_SET (ip6_fd, &event_fd_set);
        if (ip6_fd > max_fd)
        {
            max_fd = ip6_fd;
        }
    }

    retVal = VmDirSyncCounterIncrement(gVmdirGlobals.pPortListenSyncCounter);
    if (retVal != 0 )
    {
        VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "%s: VmDirSyncCounterIncrement(gVmdirGlobals.pPortListenSyncCounter) returned error", __func__);
        BAIL_ON_VMDIR_ERROR(retVal);
    }

    while (TRUE)
    {
        if (VmDirdState() == VMDIRD_STATE_SHUTDOWN)
        {
            goto cleanup;
        }

        poll_fd_set = event_fd_set;
        timeout.tv_sec = 3;
        timeout.tv_usec = 0;
        retVal = select ((int)max_fd+1, &poll_fd_set, NULL, NULL, &timeout);
        if (retVal < 0 )
        {
#ifdef _WIN32
            errno = WSAGetLastError();
#endif
            VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: select() (port %d) call failed: %d.", __func__, dwPort, errno);
            VmDirSleep( 1000 );
            continue;
        } else if (retVal == 0)
        {
            //VMDIR_LOG_INFO( LDAP_DEBUG_CONNS, "%s: select() timeout (port %d)", __func__, dwPort);
            continue;
        }

        if (ip4_fd >= 0 && FD_ISSET(ip4_fd, &poll_fd_set))
        {
            newsockfd = accept(ip4_fd, (struct sockaddr *) NULL, NULL);
        } else if (ip6_fd >= 0 && FD_ISSET(ip6_fd, &poll_fd_set))
        {
            newsockfd = accept(ip6_fd, (struct sockaddr *) NULL, NULL);
        } else
        {
            VMDIR_LOG_INFO( LDAP_DEBUG_CONNS, "%s: select() returned with no data (port %d), return: %d",
                            __func__, dwPort, retVal);
            continue;
        }

        if (newsockfd < 0)
        {
#ifdef _WIN32
            errno = WSAGetLastError();
#endif
            if (errno != EAGAIN && errno != EWOULDBLOCK )
            {
                VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: accept() (port %d) failed with errno: %d.",
                                 __func__, dwPort, errno );
            }
            continue;
        }

        if ( _VmDirFlowCtrlThrEnter() == TRUE )
        {
            tcp_close(newsockfd);
            newsockfd = -1;
            VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "Maxmimum number of concurrent LDAP threads reached. Blocking new connection" );

            continue;
        }

        retVal = VmDirAllocateMemory(
                sizeof(VDIR_CONNECTION_CTX),
                (PVOID*)&pConnCtx);
        BAIL_ON_VMDIR_ERROR(retVal);

        pConnCtx->sockFd  = newsockfd;
        newsockfd = -1;
        pConnCtx->pSockbuf_IO = pSockbuf_IO;

        retVal = VmDirCreateThread(&threadId, TRUE, ProcessAConnection, (PVOID)pConnCtx);
        if (retVal != 0)
        {
            VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: VmDirCreateThread() (port) failed with errno: %d",
                             __func__, dwPort, errno );

            tcp_close(pConnCtx->sockFd);
            _VmDirFlowCtrlThrExit();
            VMDIR_SAFE_FREE_MEMORY(pConnCtx);
            continue;
        }
        else
        {
            pConnCtx = NULL; //thread take ownership on pConnCtx
            VmDirFreeVmDirThread(&threadId);
        }
    }

cleanup:

    VMDIR_UNLOCK_MUTEX(bInLock, gVmdirGlobals.replCycleDoneMutex);

    if (ip4_fd >= 0)
    {
        tcp_close(ip4_fd);
    }
    if (ip6_fd >= 0)
    {
        tcp_close(ip6_fd);
    }
    if (newsockfd >= 0)
    {
        tcp_close(newsockfd);
    }
#ifndef _WIN32
    raise(SIGTERM);
#endif

    VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "%s: Connection accept thread: stop (port %d)", __func__, dwPort);

    return retVal;

error:
    goto cleanup;
}
示例#18
0
static
int
_VmDirSwapDB(
    PCSTR dbHomeDir,
    BOOLEAN bHasXlog)
{
    int                     retVal = LDAP_SUCCESS;
    char                    dbExistingName[VMDIR_MAX_FILE_NAME_LEN] = {0};
    char                    dbNewName[VMDIR_MAX_FILE_NAME_LEN] = {0};
    PSTR                    pszLocalErrorMsg = NULL;
    int                     errorCode = 0;
    BOOLEAN                 bLegacyDataLoaded = FALSE;
    PVDIR_BACKEND_INTERFACE pBE = NULL;

#ifndef _WIN32
    const char   fileSeperator = '/';
#else
    const char   fileSeperator = '\\';
#endif

    // Shutdown backend
    pBE = VmDirBackendSelect(NULL);
    assert(pBE);

    VmDirdStateSet(VMDIRD_STATE_SHUTDOWN);

    VmDirIndexLibShutdown();

    VmDirSchemaLibShutdown();

    pBE->pfnBEShutdown();
    VmDirBackendContentFree(pBE);

    // move .mdb files
    retVal = VmDirStringPrintFA( dbExistingName, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s%c%s", dbHomeDir, fileSeperator,
                                 LOCAL_PARTNER_DIR, fileSeperator, VMDIR_MDB_DATA_FILE_NAME);
    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
            "_VmDirSwapDB: VmDirStringPrintFA() call failed with error: %d", retVal );

    retVal = VmDirStringPrintFA( dbNewName, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s", dbHomeDir, fileSeperator,
                                 VMDIR_MDB_DATA_FILE_NAME );
    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
            "_VmDirSwapDB: VmDirStringPrintFA() call failed with error: %d", retVal );

#ifdef WIN32
    if (MoveFileEx(dbExistingName, dbNewName, MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING) == 0)
    {
        retVal = LDAP_OPERATIONS_ERROR;
        errorCode = GetLastError();
#else
    if (rename(dbExistingName, dbNewName) != 0)
    {
        retVal = LDAP_OPERATIONS_ERROR;
        errorCode = errno;
#endif
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
            "_VmDirSwapDB: rename file from %s to %s failed, errno %d", dbExistingName, dbNewName, errorCode );
    }

    retVal = VmDirStringPrintFA(dbNewName, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s%c%s", dbHomeDir, fileSeperator, VMDIR_MDB_XLOGS_DIR_NAME);
    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
            "_VmDirSwapDB: VmDirStringPrintFA() call failed with error: %d", retVal );

    if (bHasXlog)
    {
        //move xlog directory
        retVal = VmDirStringPrintFA(dbExistingName, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s%c%s", dbHomeDir, fileSeperator,
                                    LOCAL_PARTNER_DIR, fileSeperator, VMDIR_MDB_XLOGS_DIR_NAME);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
                "_VmDirSwapDB: VmDirStringPrintFA() call failed with error: %d", retVal );

#ifdef     WIN32
        if (MoveFileEx(dbExistingName, dbNewName, MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING) == 0)
        {
            retVal = LDAP_OPERATIONS_ERROR;
            errorCode = GetLastError();
#else
        if (rmdir(dbNewName) != 0)
        {
            retVal = LDAP_OPERATIONS_ERROR;
            errorCode = errno;
            BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "_VmDirSwapDB cannot remove directory %s, errno %d",
                                         dbNewName, errorCode);
        }

        if (rename(dbExistingName, dbNewName) != 0)
        {
            retVal = LDAP_OPERATIONS_ERROR;
            errorCode = errno;
#endif
            BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "_VmDirSwapDB cannot move directory from %s to %s, errno %d",
                                         dbNewName, dbExistingName, errorCode);
        }
    }

    retVal = VmDirStringPrintFA(dbExistingName, VMDIR_MAX_FILE_NAME_LEN, "%s%c%s", dbHomeDir, fileSeperator, LOCAL_PARTNER_DIR);
    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
            "_VmDirSwapDB: VmDirStringPrintFA() call failed with error: %d", retVal );

#ifdef WIN32
    if (RemoveDirectory(dbExistingName)==0)
    {
        errorCode = GetLastError();
#else
    if (rmdir(dbExistingName))
    {
        errorCode = errno;
#endif

        VMDIR_LOG_WARNING(VMDIR_LOG_MASK_ALL, "cannot remove directory %s errno %d", dbExistingName, errorCode);
    }

    VmDirdStateSet(VMDIRD_STATE_STARTUP);

    retVal = VmDirInitBackend(&bLegacyDataLoaded);
    BAIL_ON_VMDIR_ERROR(retVal);

    if (bLegacyDataLoaded)
    {
        retVal = VmDirPatchLocalSubSchemaSubEntry();
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrorMsg,
                "_VmDirSwapDB: failed to patch subschema subentry: %d", retVal );

        retVal = VmDirWriteSchemaObjects();
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrorMsg,
                "_VmDirSwapDB: failed to create schema tree: %d", retVal );
    }

    VmDirdStateSet(VMDIRD_STATE_NORMAL);

cleanup:
    VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg);
    return retVal;

error:
    retVal = LDAP_OPERATIONS_ERROR;
    VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s", VDIR_SAFE_STRING(pszLocalErrorMsg) );
    goto cleanup;
}

static
int
_VmDirWrapUpFirstReplicationCycle(
    PCSTR                           pszHostname,
    VMDIR_REPLICATION_AGREEMENT *   pReplAgr)
{
    int                 retVal = LDAP_SUCCESS;
    PVDIR_ENTRY         pPartnerServerEntry = NULL;
    PVDIR_ATTRIBUTE     pAttrUpToDateVector = NULL;
    PVDIR_ATTRIBUTE     pAttrInvocationId = NULL;
    USN                 localUsn = 0;
    USN                 partnerLocalUsn = 0;
    char                partnerlocalUsnStr[VMDIR_MAX_USN_STR_LEN];
    VDIR_BACKEND_CTX    beCtx = {0};
    struct berval       syncDoneCtrlVal = {0};
    PVDIR_SCHEMA_CTX    pSchemaCtx = NULL;
    VDIR_OPERATION      searchOp = {0};
    PVDIR_FILTER        pSearchFilter = NULL;
    PSTR                pszSeparator = NULL;

    retVal = VmDirSchemaCtxAcquire(&pSchemaCtx);
    BAIL_ON_VMDIR_ERROR( retVal );

    retVal = VmDirInitStackOperation( &searchOp, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_SEARCH, pSchemaCtx );
    BAIL_ON_VMDIR_ERROR(retVal);

    searchOp.pBEIF = VmDirBackendSelect(NULL);
    assert(searchOp.pBEIF);

    searchOp.reqDn.lberbv.bv_val = "";
    searchOp.reqDn.lberbv.bv_len = 0;
    searchOp.request.searchReq.scope = LDAP_SCOPE_SUBTREE;

    retVal = VmDirConcatTwoFilters(searchOp.pSchemaCtx, ATTR_CN, (PSTR) pszHostname, ATTR_OBJECT_CLASS, OC_DIR_SERVER,
                                    &pSearchFilter);
    BAIL_ON_VMDIR_ERROR(retVal);

    searchOp.request.searchReq.filter = pSearchFilter;

    retVal = VmDirInternalSearch(&searchOp);
    BAIL_ON_VMDIR_ERROR(retVal);

    if (searchOp.internalSearchEntryArray.iSize != 1)
    {
        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL,
                    "_VmDirWrapUpFirstReplicationCycle: Unexpected (not 1) number of partner server entries found (%d)",
                    searchOp.internalSearchEntryArray.iSize );
        retVal = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR(retVal);
    }

    pPartnerServerEntry = searchOp.internalSearchEntryArray.pEntry;

    pAttrUpToDateVector = VmDirEntryFindAttribute( ATTR_UP_TO_DATE_VECTOR, pPartnerServerEntry );

    pAttrInvocationId = VmDirEntryFindAttribute( ATTR_INVOCATION_ID, pPartnerServerEntry );
    assert( pAttrInvocationId != NULL );

    beCtx.pBE = VmDirBackendSelect(NULL);
    assert(beCtx.pBE);

    if ((retVal = beCtx.pBE->pfnBEGetNextUSN( &beCtx, &localUsn )) != 0)
    {
        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "_VmDirWrapUpFirstReplicationCycle: pfnBEGetNextUSN failed with error code: %d, "
                  "error message: %s", retVal, VDIR_SAFE_STRING(beCtx.pszBEErrorMsg) );
        BAIL_ON_VMDIR_ERROR( retVal );
    }

    retVal = _VmGetHighestCommittedUSN(localUsn, &partnerLocalUsn);
    BAIL_ON_VMDIR_ERROR( retVal );

    VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "_VmDirWrapUpFirstReplicationCycle: partnerLocalUsn %llu locaUsn %llu", partnerLocalUsn, localUsn);

    if ((retVal = VmDirStringNPrintFA( partnerlocalUsnStr, sizeof(partnerlocalUsnStr), sizeof(partnerlocalUsnStr) - 1,
                                       "%" PRId64, partnerLocalUsn)) != 0)
    {
        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "_VmDirWrapUpFirstReplicationCycle: VmDirStringNPrintFA failed with error code: %d",
                  retVal );
        BAIL_ON_VMDIR_ERROR( retVal );
    }

    if (pAttrUpToDateVector)
    {
        if (VmDirStringEndsWith( pAttrUpToDateVector->vals[0].lberbv.bv_val, ",", FALSE))
        {
            pszSeparator = "";
        }
        else
        {
            pszSeparator = ",";
        }

        // <partnerLocalUSN>,<partner up-to-date vector>,<partner server GUID>:<partnerLocalUSN>,
        retVal = VmDirAllocateStringPrintf( &(syncDoneCtrlVal.bv_val), "%s,%s%s%s:%s,",
                                                partnerlocalUsnStr,
                                                pAttrUpToDateVector->vals[0].lberbv.bv_val,
                                                pszSeparator,
                                                pAttrInvocationId->vals[0].lberbv.bv_val,
                                                partnerlocalUsnStr);
        BAIL_ON_VMDIR_ERROR(retVal);
    }
    else
    {
        // <partnerLocalUSN>,<partner server GUID>:<partnerLocalUSN>,
        retVal = VmDirAllocateStringPrintf( &(syncDoneCtrlVal.bv_val), "%s,%s:%s,",
                                                partnerlocalUsnStr,
                                                pAttrInvocationId->vals[0].lberbv.bv_val,
                                                partnerlocalUsnStr);
        BAIL_ON_VMDIR_ERROR(retVal);
    }

    VmDirSetACLMode();

    syncDoneCtrlVal.bv_len = VmDirStringLenA(syncDoneCtrlVal.bv_val);

    if ((retVal = VmDirReplUpdateCookies( pSchemaCtx, &(syncDoneCtrlVal), pReplAgr )) != LDAP_SUCCESS)
    {
        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "vdirReplicationThrFun: UpdateCookies failed. Error: %d", retVal );
        BAIL_ON_VMDIR_ERROR( retVal );
    }

    if ((retVal = _VmDirPatchDSERoot(pSchemaCtx)) != LDAP_SUCCESS)
    {
        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "vdirReplicationThrFun: _VmDirPatchDSERoot failed. Error: %d", retVal );
        BAIL_ON_VMDIR_ERROR( retVal );
    }

cleanup:
    VmDirFreeOperationContent(&searchOp);
    VmDirBackendCtxContentFree(&beCtx);
    VMDIR_SAFE_FREE_MEMORY(syncDoneCtrlVal.bv_val);
    VmDirSchemaCtxRelease(pSchemaCtx);
    return retVal;

error:
    retVal = LDAP_OPERATIONS_ERROR;
    goto cleanup;
}

#ifndef VDIR_PSC_VERSION
#define VDIR_PSC_VERSION "6.7.0"
#endif

static
int
_VmDirPatchDSERoot(
    PVDIR_SCHEMA_CTX    pSchemaCtx)
{
    int                      retVal = LDAP_SUCCESS;
    VDIR_OPERATION           op = {0};
    VDIR_BERVALUE            bvDSERootDN = VDIR_BERVALUE_INIT;

    VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "_VmDirPatchDSERoot: Begin" );

    bvDSERootDN.lberbv.bv_val = PERSISTED_DSE_ROOT_DN;
    bvDSERootDN.lberbv.bv_len = VmDirStringLenA( bvDSERootDN.lberbv.bv_val );

    retVal = VmDirInitStackOperation( &op,
                                      VDIR_OPERATION_TYPE_INTERNAL,
                                      LDAP_REQ_MODIFY,
                                      pSchemaCtx );
    BAIL_ON_VMDIR_ERROR(retVal);

    retVal = VmDirNormalizeDN( &bvDSERootDN, pSchemaCtx);
    BAIL_ON_VMDIR_ERROR(retVal);

    retVal = VmDirBervalContentDup( &bvDSERootDN, &op.reqDn );
    BAIL_ON_VMDIR_ERROR(retVal);

    op.pBEIF = VmDirBackendSelect(op.reqDn.lberbv.bv_val);
    assert(op.pBEIF);

    if (VmDirBervalContentDup( &op.reqDn, &op.request.modifyReq.dn ) != 0)
    {
        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "_VmDirPatchDSERoot: BervalContentDup failed." );
        BAIL_ON_VMDIR_ERROR( retVal );
    }

    retVal = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_DC_ACCOUNT_UPN, ATTR_DC_ACCOUNT_UPN_LEN,
                              gVmdirServerGlobals.dcAccountUPN.lberbv.bv_val,
                              gVmdirServerGlobals.dcAccountUPN.lberbv.bv_len );
    BAIL_ON_VMDIR_ERROR( retVal );

    retVal = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_DC_ACCOUNT_DN, ATTR_DC_ACCOUNT_DN_LEN,
                              gVmdirServerGlobals.dcAccountDN.lberbv.bv_val,
                              gVmdirServerGlobals.dcAccountDN.lberbv.bv_len );
    BAIL_ON_VMDIR_ERROR( retVal );

    retVal = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_SERVER_NAME, ATTR_SERVER_NAME_LEN,
                              gVmdirServerGlobals.serverObjDN.lberbv.bv_val,
                              gVmdirServerGlobals.serverObjDN.lberbv.bv_len );
    BAIL_ON_VMDIR_ERROR( retVal );

    retVal = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_SITE_NAME, ATTR_SITE_NAME_LEN,
                              gVmdirServerGlobals.pszSiteName,
                              VmDirStringLenA(gVmdirServerGlobals.pszSiteName) );
    BAIL_ON_VMDIR_ERROR( retVal );

    retVal = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_PSC_VERSION, ATTR_PSC_VERSION_LEN,
                              VDIR_PSC_VERSION,
                              VmDirStringLenA(VDIR_PSC_VERSION) );
    BAIL_ON_VMDIR_ERROR( retVal );

    retVal = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_MAX_DOMAIN_FUNCTIONAL_LEVEL,
                              ATTR_MAX_DOMAIN_FUNCTIONAL_LEVEL_LEN,
                              VMDIR_MAX_DFL_STRING,
                              VmDirStringLenA(VMDIR_MAX_DFL_STRING) );
    BAIL_ON_VMDIR_ERROR( retVal );

    if ((retVal = VmDirInternalModifyEntry( &op )) != 0)
    {
        // If VmDirInternall call failed, reset retVal to LDAP level error space (for B/C)
        retVal = op.ldapResult.errCode;

        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "_VmDirPatchDSERoot: InternalModifyEntry failed. "
                  "Error code: %d, Error string: %s", retVal, VDIR_SAFE_STRING( op.ldapResult.pszErrMsg ) );
        BAIL_ON_VMDIR_ERROR( retVal );
    }

cleanup:
    VmDirFreeOperationContent(&op);

    VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "_VmDirPatchDSERoot: End" );
    return retVal;

error:
    retVal = LDAP_OPERATIONS_ERROR;
    goto cleanup;
}
示例#19
0
static
DWORD
VmKdcRegGetConfig(
    PCSTR               pszSubKey,
    PVMKDC_CONFIG_ENTRY pCfgTable,
    DWORD               dwNumEntries
    )
{
    DWORD dwError = 0;
    DWORD iEntry = 0;
    PVMKDC_CONFIG_CONNECTION_HANDLE pCfgHandle = NULL;

    dwError = VmKdcRegConfigHandleOpen(&pCfgHandle);
    BAIL_ON_VMKDC_ERROR(dwError);

    for (; iEntry < dwNumEntries; iEntry++)
    {
        PVMKDC_CONFIG_ENTRY pEntry = &pCfgTable[iEntry];

        switch (pEntry->Type)
        {
            case VMKDC_CONFIG_VALUE_TYPE_STRING:

                dwError = VmKdcRegConfigGetString(
                            pCfgHandle,
                            pszSubKey,
                            pEntry->pszName,
                            &pEntry->cfgValue.pszValue);
                if (dwError != 0)
                {   // use default value
                    dwError = VmKdcAllocateStringA(
                                    pEntry->defaultValue.pszDefault,
                                    &pEntry->cfgValue.pszValue);
                    BAIL_ON_VMKDC_ERROR(dwError);
                }
                break;

            case VMKDC_CONFIG_VALUE_TYPE_DWORD:

                dwError = VmKdcRegConfigGetDword(
                            pCfgHandle,
                            pszSubKey,
                            pEntry->pszName,
                            &pEntry->cfgValue.dwValue);
                if (dwError != 0)
                {   // use default value
                    pEntry->cfgValue.dwValue = pEntry->defaultValue.dwDefault;
                }

                if (pCfgTable[iEntry].cfgValue.dwValue > pCfgTable[iEntry].dwMax)
                {
                    VMDIR_LOG_WARNING(
                            VMDIR_LOG_MASK_ALL,
                            "Config [%s] value (%d) too big, using (%d).",
                            pEntry->pszName,
                            pEntry->cfgValue.dwValue,
                            pEntry->dwMax);

                    pEntry->cfgValue.dwValue = pEntry->dwMax;

                }

                if (pEntry->cfgValue.dwValue < pEntry->dwMin)
                {
                    VMDIR_LOG_WARNING(
                            VMDIR_LOG_MASK_ALL,
                            "Config [%s] value (%d) too small, using (%d).",
                            pEntry->pszName,
                            pEntry->cfgValue.dwValue,
                            pEntry->dwMin);

                    pEntry->cfgValue.dwValue = pEntry->dwMin;
                }

                break;

            case VMKDC_CONFIG_VALUE_TYPE_BOOLEAN:

                dwError = VmKdcRegConfigGetDword(
                            pCfgHandle,
                            pszSubKey,
                            pEntry->pszName,
                            &pEntry->cfgValue.dwValue);

                if (dwError != 0)
                {   // use default value
                    pEntry->cfgValue.dwValue = pEntry->defaultValue.dwDefault;
                }

                pEntry->cfgValue.dwValue =
                        pEntry->cfgValue.dwValue == 0 ? FALSE : TRUE;

                break;

            default:

                VMDIR_LOG_ERROR(
                        VMDIR_LOG_MASK_ALL,
                        "VmKdcRegConfigProcess key [%s] type (%d) not supported.",
                        pEntry->pszName,
                        pEntry->Type);

                break;
        }
    }

    dwError = 0;

cleanup:

    if (pCfgHandle)
    {
        VmKdcRegConfigHandleClose(pCfgHandle);
    }

    return dwError;

error:

    goto cleanup;
}
示例#20
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;
}