Example #1
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;
}
DWORD
VmDirDDVectorToString(
    PCSTR   pszInvocationId,
    PSTR*   ppszDeadlockDetectionVectorStr
    )
{
    PSTR      pszDeadlockDetectionVectorStr = NULL;
    DWORD     dwError = 0;
    PDWORD    pdwValue = NULL;
    DWORD     dwCacheEmptyPageCnt = 0;
    BOOLEAN   bInLock = FALSE;
    BOOLEAN   bRevertDefaultValue = FALSE;

    if (ppszDeadlockDetectionVectorStr == NULL)
    {
        BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER);
    }

    VMDIR_LOCK_MUTEX(bInLock, gVmdirServerGlobals.pReplDeadlockDetectionVector->pMutex);

    /*
     * Best effort if invocation id is NULL ignore.
     * Ping-pong state is handled by providing supplier's empty page
     * count as 'gVmdirGlobals.dwEmptyPageCnt' so that partner considers only his state
     */
    if (gVmdirServerGlobals.pReplDeadlockDetectionVector->pszInvocationId &&
        pszInvocationId &&
        VmDirStringCompareA(
                pszInvocationId,
                gVmdirServerGlobals.pReplDeadlockDetectionVector->pszInvocationId,
                FALSE) == 0)
    {
        // will reach here only if key is present
        LwRtlHashMapFindKey(
                gVmdirServerGlobals.pReplDeadlockDetectionVector->pEmptyPageSentMap,
                (PVOID*)&pdwValue,
                gVmdirServerGlobals.bvServerObjName.lberbv_val);

        dwCacheEmptyPageCnt = *pdwValue;

        dwError = _VmDirDDVectorUpdateDefaultsInLock(gVmdirGlobals.dwEmptyPageCnt);
        BAIL_ON_VMDIR_ERROR(dwError);

        bRevertDefaultValue = TRUE;
    }

    dwError = VmDirVectorToStr(
            gVmdirServerGlobals.pReplDeadlockDetectionVector->pEmptyPageSentMap,
            _VmDirDeadlockDetectionVectorPairToStr,
            &pszDeadlockDetectionVectorStr);
    BAIL_ON_VMDIR_ERROR(dwError);

    *ppszDeadlockDetectionVectorStr = pszDeadlockDetectionVectorStr;
    pszDeadlockDetectionVectorStr = NULL;

    if (bRevertDefaultValue)
    {
        dwError = _VmDirDDVectorUpdateDefaultsInLock(dwCacheEmptyPageCnt);
        BAIL_ON_VMDIR_ERROR(dwError);
    }

cleanup:
    VMDIR_UNLOCK_MUTEX(bInLock, gVmdirServerGlobals.pReplDeadlockDetectionVector->pMutex);
    return dwError;

error:
    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "failed, error (%d)", dwError);
    goto cleanup;
}
Example #3
0
/*
 * Create new cache from another cache + an array of VDIR_CFG_ATTR_INDEX_DESC
 */
DWORD
VdirAttrIndexInitViaCacheAndDescs(
    PVDIR_ATTR_INDEX_INSTANCE   pFromCache,
    PVDIR_CFG_ATTR_INDEX_DESC   pIndexDesc,
    USHORT                      dwDescSize)
{
    DWORD   dwError = 0;
    DWORD   dwCnt = 0;
    int     iMaxId = 0;
    BOOLEAN bInLock = FALSE;

    PVDIR_ATTR_INDEX_INSTANCE pCache = NULL;
    PVDIR_ATTR_INDEX_INSTANCE pJunkCache = NULL;

    assert(pFromCache && pIndexDesc);

    dwError = VdirAttrIndexCacheAllocate(
            &pCache,
            (pFromCache->usNumIndex + dwDescSize));
    BAIL_ON_VMDIR_ERROR(dwError);

    // copy all existing data from current cache
    // TODO, need to handle status, so we should only copy ENABLED ones. however,
    // need to be careful for ABORT ones if it appears in pIndexDesc again.  in such
    // case, we need to pick up its old pFromCache->pSortName[dwCnt].iId (bdb db)
    for (dwCnt = 0; dwCnt < pFromCache->usNumIndex; dwCnt++)
    {
        dwError = VmDirAllocateStringA(
                pFromCache->pSortName[dwCnt].pszAttrName,
                &pCache->pSortName[dwCnt].pszAttrName);
        BAIL_ON_VMDIR_ERROR(dwError);

        pCache->pSortName[dwCnt].bIsUnique = pFromCache->pSortName[dwCnt].bIsUnique;
        pCache->pSortName[dwCnt].iTypes = pFromCache->pSortName[dwCnt].iTypes;
        pCache->pSortName[dwCnt].status = pFromCache->pSortName[dwCnt].status;
        pCache->pSortName[dwCnt].iId = pFromCache->pSortName[dwCnt].iId;

        if (pCache->pSortName[dwCnt].iId > iMaxId)
        {
            iMaxId = pCache->pSortName[dwCnt].iId;
        }
    }

    // add new contents from pIndexDesc
    for (dwCnt = 0; dwCnt < dwDescSize; dwCnt++)
    {
        int iIdx = dwCnt + pFromCache->usNumIndex;

        dwError = VmDirAllocateStringA(
                pIndexDesc[dwCnt].pszAttrName,
                &pCache->pSortName[iIdx].pszAttrName);
        BAIL_ON_VMDIR_ERROR(dwError);

        pCache->pSortName[iIdx].bIsUnique = pIndexDesc[dwCnt].bIsUnique;
        pCache->pSortName[iIdx].iTypes = pIndexDesc[dwCnt].iTypes;
        pCache->pSortName[iIdx].status = pIndexDesc[dwCnt].status;
        pCache->pSortName[iIdx].iId = iMaxId + 1 + dwCnt;
    }

    pCache->usNumIndex = pFromCache->usNumIndex + dwDescSize;

    qsort(pCache->pSortName,
          pCache->usNumIndex,
          sizeof(VDIR_CFG_ATTR_INDEX_DESC),
          VdirAttrIndexNameCmp);

    // done create pCache, add it to gVdirAttrIndexGlobals
    VMDIR_LOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex);

    pJunkCache = gVdirAttrIndexGlobals.pNewCache;
    gVdirAttrIndexGlobals.pNewCache = pCache;

cleanup:
    VMDIR_UNLOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex);

    if (pJunkCache)
    {
        VdirAttrIdxCacheFree(pJunkCache);
    }

    return dwError;

error:
    if (pCache)
    {
        VdirAttrIdxCacheFree(pCache);
    }

    goto cleanup;
}
Example #4
0
/*
 * Convert attrIndexDesc attribute into a VDIR_ATTR_INDEX_INSTANCE
 * and enable gVdirAttrIndexCache with version 0.
 */
DWORD
VdirAttrIndexInitViaEntry(
    PVDIR_ENTRY  pEntry
    )
{
    DWORD                       dwError = 0;
    DWORD                       dwCnt = 0;
    BOOLEAN                     bInLock = FALSE;
    PVDIR_ATTRIBUTE             pAttr = NULL;
    PVDIR_ATTR_INDEX_INSTANCE   pAttrIdxCache = NULL;
    USHORT                      usLive = gVdirAttrIndexGlobals.usLive;
    PVDIR_SCHEMA_CTX            pSchemaCtx = NULL;

    assert(pEntry);

    dwError = VmDirSchemaCtxAcquire(&pSchemaCtx);
    BAIL_ON_VMDIR_ERROR(dwError);
    assert(pSchemaCtx);

    pAttr = VmDirEntryFindAttribute(
            ATTR_INDEX_DESC,
            pEntry);
    assert(pAttr);

    dwError = VdirAttrIndexCacheAllocate(
            &pAttrIdxCache,
            pAttr->numVals);
    BAIL_ON_VMDIR_ERROR(dwError);

    for (dwCnt = 0; dwCnt < pAttr->numVals; dwCnt++)
    {
        VDIR_CFG_ATTR_INDEX_DESC indexDesc = {0};

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

        // cache takes over indexDesc.pszAttrName
        pAttrIdxCache->pSortName[dwCnt].pszAttrName = indexDesc.pszAttrName;
        indexDesc.pszAttrName = NULL;

        pAttrIdxCache->pSortName[dwCnt].bIsUnique = indexDesc.bIsUnique;
        pAttrIdxCache->pSortName[dwCnt].iTypes = indexDesc.iTypes;
        pAttrIdxCache->pSortName[dwCnt].status = indexDesc.status;
        pAttrIdxCache->pSortName[dwCnt].bIsNumeric = VmDirSchemaAttrHasIntegerMatchingRule(
                                                            pSchemaCtx,
                                                            pAttrIdxCache->pSortName[dwCnt].pszAttrName);

        pAttrIdxCache->pSortName[dwCnt].iId = dwCnt;
    }

    qsort(pAttrIdxCache->pSortName,
          pAttrIdxCache->usNumIndex,
          sizeof(VDIR_CFG_ATTR_INDEX_DESC),
          VdirAttrIndexNameCmp);

    VMDIR_LOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex);

    // Set up a cache instance
    // In case there is no need to do bootstrape during server start up, usLive == 0
    // is not assigned (i.e.: schema entry is found)
    if ((usLive == 0 && gVdirAttrIndexGlobals.pCaches[usLive] != NULL) || usLive > 0)
    {
        usLive++;
    }
    gVdirAttrIndexGlobals.pCaches[usLive] = pAttrIdxCache;
    gVdirAttrIndexGlobals.usLive = usLive;

cleanup:
    VMDIR_UNLOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex);

    if (pSchemaCtx)
    {
        VmDirSchemaCtxRelease(pSchemaCtx);
    }

    return dwError;

error:
    if (pAttrIdxCache)
    {
        VdirAttrIdxCacheFree(pAttrIdxCache);
    }

    goto cleanup;
}
Example #5
0
DWORD
VmDirIndexingThreadFun(
    PVOID   pArg
    )
{
    DWORD   dwError = 0;
    BOOLEAN bInLock = FALSE;
    BOOLEAN bResume = FALSE;
    VDIR_SERVER_STATE   vmdirState = VMDIRD_STATE_UNDEFINED;
    PVDIR_INDEXING_TASK pTask = NULL;

    VmDirDropThreadPriority(DEFAULT_THREAD_PRIORITY_DELTA);

resume:
    while (1)
    {
        vmdirState = VmDirdState();
        if (vmdirState == VMDIRD_STATE_SHUTDOWN)
        {
            break;
        }
        else if (vmdirState != VMDIRD_STATE_NORMAL)
        {
            VmDirSleep(1000);
            continue;
        }

        VMDIR_LOCK_MUTEX(bInLock, gVdirIndexGlobals.mutex);

        if (!bResume)
        {
            PVDIR_INDEX_UPD pIndexUpd = gVdirIndexGlobals.pIndexUpd;

            // record current progress
            dwError = VmDirIndexingTaskRecordProgress(pTask, pIndexUpd);
            BAIL_ON_VMDIR_ERROR(dwError);

            // apply index updates
            dwError = VmDirIndexUpdApply(pIndexUpd);
            BAIL_ON_VMDIR_ERROR(dwError);

            VmDirIndexUpdFree(pIndexUpd);
            gVdirIndexGlobals.pIndexUpd = NULL;

            // compute new task
            VmDirFreeIndexingTask(pTask);
            dwError = VmDirIndexingTaskCompute(&pTask);
            BAIL_ON_VMDIR_ERROR(dwError);
        }

        if (VmDirIndexingTaskIsNoop(pTask))
        {
            dwError = VmDirConditionWait(
                    gVdirIndexGlobals.cond,
                    gVdirIndexGlobals.mutex);
            BAIL_ON_VMDIR_ERROR(dwError);

            continue;
        }

        VMDIR_UNLOCK_MUTEX(bInLock, gVdirIndexGlobals.mutex);

        dwError = VmDirIndexingTaskPopulateIndices(pTask);
        BAIL_ON_VMDIR_ERROR(dwError);

        dwError = VmDirIndexingTaskValidateScopes(pTask);
        BAIL_ON_VMDIR_ERROR(dwError);

        dwError = VmDirIndexingTaskDeleteIndices(pTask);
        BAIL_ON_VMDIR_ERROR(dwError);
        bResume = FALSE;
    }

cleanup:
    VMDIR_UNLOCK_MUTEX(bInLock, gVdirIndexGlobals.mutex);
    VmDirFreeIndexingTask(pTask);
    return dwError;

error:
    if (dwError == ERROR_INVALID_STATE)
    {
        bResume = TRUE;
        goto resume;
    }
    else
    {
        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL,
                "%s failed, error (%d)", __FUNCTION__, dwError );
    }
    goto cleanup;
}
Example #6
0
/*
 * This thread waits on gVdirAttrIndexGlobals.condition and spawns worker thread
 * to perform indexing in the back ground.
 */
static
DWORD
vdirIndexingThrFun(
    PVOID   pArg
)
{
    DWORD   dwError = 0;
    BOOLEAN bInLock = FALSE;
    PVDIR_CFG_ATTR_INDEX_DESC*  ppIndexDesc = NULL;
    PVDIR_THREAD_INFO           pThrInfo = (PVDIR_THREAD_INFO)pArg;

    while (1)
    {
        DWORD   dwCnt = 0;
        DWORD   dwSize = 0;
        VMDIR_THREAD  tid = {0};
        PVDIR_ATTR_INDEX_INSTANCE pCache = NULL;

        memset(&tid, 0, sizeof(tid));

        // wait till new indices are created
        VMDIR_LOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex);

        dwError = VmDirConditionWait(
                      pThrInfo->conditionUsed,
                      pThrInfo->mutexUsed);
        BAIL_ON_VMDIR_ERROR(dwError);

        // get new cache we want to enable
        pCache = gVdirAttrIndexGlobals.pNewCache;

        VMDIR_UNLOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex);

        if (VmDirdState() == VMDIRD_STATE_SHUTDOWN)
        {
            break;
        }

        if (!pCache)
        {
            continue;
        }

        // get number of indices in building status
        for (dwCnt = 0, dwSize = 0; dwCnt < pCache->usNumIndex; dwCnt++)
        {
            if (pCache->pSortName[dwCnt].status == VDIR_CFG_ATTR_INDEX_BUILDING)
            {
                dwSize++;
            }
        }

        if (dwSize == 0)
        {
            continue;
        }

        dwError  = VmDirAllocateMemory(
                       sizeof(PVDIR_CFG_ATTR_INDEX_DESC) * (dwSize + 1),  // +1 for NULL ending
                       (PVOID)&ppIndexDesc);
        BAIL_ON_VMDIR_ERROR(dwError);

        // fill ppIndexDesc with building index
        // NOTE, ppIndexDesc does NOT own them; pCache does.
        for (dwCnt = 0, dwSize = 0; dwCnt < pCache->usNumIndex; dwCnt++)
        {
            if (pCache->pSortName[dwCnt].status == VDIR_CFG_ATTR_INDEX_BUILDING)
            {
                ppIndexDesc[dwSize] = &pCache->pSortName[dwCnt];
                dwSize++;
            }
        }

        // TODO, detach thr now, need to join to safely finish bdb io...
        dwError = VmDirCreateThread(
                      &tid,
                      TRUE,
                      vdirIndexingWorkerThrFun,
                      (PVOID)ppIndexDesc);
        BAIL_ON_VMDIR_ERROR(dwError);
        // worker takes over ppIndexDesc.
        ppIndexDesc = NULL;

        VmDirFreeVmDirThread(&tid);
    }

cleanup:

    VMDIR_UNLOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex);

    // TODO: should be dwError?
    return 0;

error:

    VMDIR_SAFE_FREE_MEMORY(ppIndexDesc);

    //TODO, should we stop vmdird?

    VmDirLog( LDAP_DEBUG_ANY, "VmdirIndexingThr: error stop" );

    goto cleanup;
}
Example #7
0
DWORD
VmDirWriteQueueWait(
    PVMDIR_WRITE_QUEUE          pWriteQueue,
    PVMDIR_WRITE_QUEUE_ELEMENT  pWriteQueueEle
    )
{
    DWORD      dwError = 0;
    uint64_t   iStartTime = 0;
    uint64_t   iElapsedTime = 0;
    BOOLEAN    bInLock = FALSE;
    PVDIR_LINKED_LIST_NODE      pNode = NULL;
    PVMDIR_WRITE_QUEUE_ELEMENT  pWriteQueueHead = NULL;

    if (!pWriteQueue || !pWriteQueueEle)
    {
        BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER);
    }

    VMDIR_LOCK_MUTEX(bInLock, gVmDirServerOpsGlobals.pMutex);

    iStartTime = VmDirGetTimeInMilliSec();

    //default - timeout 60 seconds
    while (VmDirGetTimeInMilliSec() - iStartTime <= gVmdirGlobals.dwWriteTimeoutInMilliSec)
    {
        VmDirLinkedListGetHead(pWriteQueue->pList, &pNode);

        pWriteQueueHead = ((PVMDIR_WRITE_QUEUE_ELEMENT)pNode->pElement);

        if (pWriteQueueHead->usn == pWriteQueueEle->usn)
        {
            iElapsedTime = VmDirGetTimeInMilliSec() - iStartTime;
            VMDIR_LOG_INFO(LDAP_DEBUG_WRITE_QUEUE, "%s: usn: %"PRId64, __FUNCTION__, pWriteQueueEle->usn);
            break;
        }

        dwError = VmDirConditionTimedWait(
                pWriteQueueEle->pCond,
                gVmDirServerOpsGlobals.pMutex,
                gVmdirGlobals.dwWriteTimeoutInMilliSec);
    }

    if (dwError != 0) //ETIMEDOUT
    {
        // After timeout queueHead could have changed
        VmDirLinkedListGetHead(pWriteQueue->pList, &pNode);

        if (pNode)
        {
            pWriteQueueHead = ((PVMDIR_WRITE_QUEUE_ELEMENT)pNode->pElement);

            VMDIR_LOG_ERROR(
                VMDIR_LOG_MASK_ALL,
                "%s: error: %d QueueHeadUSN: %"PRId64 "MyUSN: %"PRId64,
                __FUNCTION__,
                dwError,
                pWriteQueueHead->usn,
                pWriteQueueEle->usn);
        }

        BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_ML_WRITE_TIMEOUT);
    }
    else if (iElapsedTime > gVmdirServerGlobals.dwEfficientWriteOpTimeMS)
    {
        //log - if more time is spent in the write queue
        pWriteQueueHead = ((PVMDIR_WRITE_QUEUE_ELEMENT)pNode->pElement);

        VMDIR_LOG_INFO(
            VMDIR_LOG_MASK_ALL,
            "%s: (Inefficient) time:"PRId64"(ms) HeadUSN: %"PRId64 "MyUSN: %"PRId64 "Queue size:%u",
            __FUNCTION__,
            iElapsedTime,
            pWriteQueueHead->usn,
            pWriteQueueEle->usn,
            VmDirWriteQueueSizeInLock(pWriteQueue));
    }

cleanup:
    VMDIR_UNLOCK_MUTEX(bInLock, gVmDirServerOpsGlobals.pMutex);
    return dwError;

error:
    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "failed, error (%d)", dwError);
    goto cleanup;
}
Example #8
0
VOID
VmDirWriteQueuePop(
    PVMDIR_WRITE_QUEUE          pWriteQueue,
    PVMDIR_WRITE_QUEUE_ELEMENT  pWriteQueueEle
    )
{
    USN       committedUSN = 0;
    DWORD     dwError = 0;
    BOOLEAN   bInLock = FALSE;
    PVDIR_LINKED_LIST_NODE      pNode = NULL;
    PVMDIR_WRITE_QUEUE_ELEMENT  pWriteQueueHead = NULL;

    if (!pWriteQueue || !pWriteQueueEle)
    {
        BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER);
    }

    VMDIR_LOCK_MUTEX(bInLock, gVmDirServerOpsGlobals.pMutex);

    _VmDirPrintWriteQueueContentsInLock(pWriteQueue);

    VmDirLinkedListGetHead(pWriteQueue->pList, &pNode);

    if (pNode)
    {
        pWriteQueueHead = (PVMDIR_WRITE_QUEUE_ELEMENT) pNode->pElement;

        if (pWriteQueueHead->usn == pWriteQueueEle->usn)
        {
            committedUSN = pWriteQueueEle->usn;
            VmDirUpdateMaxCommittedUSNInLock(committedUSN);
            VMDIR_LOG_INFO(LDAP_DEBUG_WRITE_QUEUE, "%s: usn: %"PRId64, __FUNCTION__, pWriteQueueEle->usn);
        }
        else
        {
            VMDIR_LOG_ERROR(
                VMDIR_LOG_MASK_ALL,
                "%s: writeQueueHeadUSN %" PRId64 "MyUSN: %" PRId64,
                __FUNCTION__,
                pWriteQueueHead->usn,
                pWriteQueueEle->usn);
        }

        while (pNode &&
              ((PVMDIR_WRITE_QUEUE_ELEMENT)pNode->pElement)->usn != pWriteQueueEle->usn)
        {
            pNode = pNode->pNext;
        }

        VmDirLinkedListRemove(pWriteQueue->pList, pNode);
    }

    if (committedUSN)
    {
        VmDirLinkedListGetHead(pWriteQueue->pList, &pNode);

        if (pNode)
        {
            pWriteQueueHead = (PVMDIR_WRITE_QUEUE_ELEMENT) pNode->pElement;

            if (pWriteQueueHead->usn <= committedUSN)
            {
                VMDIR_LOG_ERROR(
                        VMDIR_LOG_MASK_ALL,
                        "%s: out of order usn in the queue committedUSN:%" PRId64 "nextUSN:%" PRId64,
                        __FUNCTION__,
                        committedUSN,
                        pWriteQueueHead->usn);
            }

            VmDirConditionSignal(pWriteQueueHead->pCond);

            VMDIR_LOG_INFO(
                LDAP_DEBUG_WRITE_QUEUE,
                "%s: next USN Signaled %" PRId64,
                __FUNCTION__,
                pWriteQueueHead->usn);
        }
    }

cleanup:
    VMDIR_UNLOCK_MUTEX(bInLock, gVmDirServerOpsGlobals.pMutex);
    return;

error:
    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "failed, error (%d)", dwError);
    goto cleanup;
}
Example #9
0
DWORD
VmKdcInitializeDirectory(
    PVMKDC_GLOBALS pGlobals)
{
    DWORD dwError = 0;
    PBYTE pPrincKeyBlob = NULL;
    PVMKDC_KEY master = NULL;
    PVMKDC_KEY kmEncKey = NULL;
    PVMKDC_CRYPTO pCrypto = NULL;
    PVMKDC_DATA kmKey = NULL;
    PSTR pszMasterName = NULL;
    BOOLEAN     bInLock = FALSE;
#ifdef MIT_KERBEROS_DB
    PVMKDC_KEYTAB_HANDLE hKtFile = NULL;
    PVMKDC_MIT_KEYTAB_FILE ktEntry = NULL;  /* Typedef named "wrong" */
    PVMKDC_KEYSET pKmKeySet = NULL;
#else
    PCSTR pszRealm = NULL;
    DWORD dwPrincKeySize = 0;
#endif

    // wait until vmdir gVmdirKrbGlobals is initialized
    VMDIR_LOCK_MUTEX( bInLock, gVmdirKrbGlobals.pmutex);
    while ( gVmdirKrbGlobals.pszRealm == NULL       &&
            VmKdcdState() == VMKDCD_STARTUP
          )
    {
        VmDirConditionTimedWait( gVmdirKrbGlobals.pcond,
                                 gVmdirKrbGlobals.pmutex,
                                 1 * 1000); // wait 1 second
    }
    VMDIR_UNLOCK_MUTEX( bInLock, gVmdirKrbGlobals.pmutex);

#ifdef MIT_KERBEROS_DB
{
    /* MIT Principal DB stashed master keytab */
    PSTR pszMasterKt = "/storage/db/vmware-vmdir/master.kt";

    /* Open keytab */
    dwError = VmKdcParseKeyTabOpen(pszMasterKt, "r", &hKtFile);
    BAIL_ON_VMKDC_ERROR(dwError);

    /* Master keytab has only one entry */
    dwError = VmKdcParseKeyTabRead(hKtFile, &ktEntry);
    BAIL_ON_VMKDC_ERROR(dwError);

    /* Populate KDC master key structure entry */
    dwError = VmKdcMakeKey(
                  ktEntry->key->type,
                  1,
                  VMKDC_GET_PTR_DATA(ktEntry->key->data),
                  VMKDC_GET_LEN_DATA(ktEntry->key->data),
                  &master);
    BAIL_ON_VMKDC_ERROR(dwError);

    /* Retrieve K/M from MIT dump, and decrypt this entry */
    dwError = VmKdcAllocateStringPrintf(&pszMasterName,
                                        "K/M@%s", ktEntry->realm);
    BAIL_ON_VMKDC_ERROR(dwError);

    /* Get K/M entry for current realm */
    dwError = VmKdcGetUpnKeysMitDb(pszMasterName,
                                   MIT_KERBEROS_DB_NAME, NULL, /* Full UPN, already known */
                                   &pKmKeySet);
    BAIL_ON_VMKDC_ERROR(dwError);

    /* Decrypt K/M using stashed master key */
    dwError = VmKdcMakeKey(
                  pKmKeySet->encKeys[0]->keytype,
                  1,
                  VMKDC_GET_PTR_DATA(pKmKeySet->encKeys[0]->encdata->data),
                  VMKDC_GET_LEN_DATA(pKmKeySet->encKeys[0]->encdata->data),
                  &kmEncKey);
    BAIL_ON_VMKDC_ERROR(dwError);

    dwError = VmKdcInitCrypto(pGlobals->pKrb5Ctx, master, &pCrypto);
    BAIL_ON_VMKDC_ERROR(dwError);

    dwError = VmKdcCryptoDecrypt(pCrypto, 0, kmEncKey->data,  &kmKey);
    BAIL_ON_VMKDC_ERROR(dwError);

    if (VMKDC_GET_LEN_DATA(master->data) != VMKDC_GET_LEN_DATA(kmKey) ||
        memcmp(VMKDC_GET_PTR_DATA(master->data),
               VMKDC_GET_PTR_DATA(kmKey),
               VMKDC_GET_LEN_DATA(kmKey)))
    {
        // TBD: Not quite right error
        dwError = ERROR_ALLOC_KRB5_CRYPTO_CONTEXT;
        BAIL_ON_VMKDC_ERROR(dwError);
    }

    pthread_mutex_lock(&pGlobals->mutex);
    VMKDC_SAFE_FREE_KEY(pGlobals->masterKey);
    pGlobals->masterKey = master;
    master = NULL;
    pthread_mutex_unlock(&pGlobals->mutex);
}
#else
    if ( VmKdcdState() == VMKDCD_STARTUP )
    {
        VMKDC_SAFE_FREE_STRINGA( pGlobals->pszDefaultRealm );
        dwError = VmKdcAllocateStringA( gVmdirKrbGlobals.pszRealm, &pGlobals->pszDefaultRealm );
        BAIL_ON_VMKDC_ERROR(dwError);

        pszRealm = pGlobals->pszDefaultRealm;

        dwError = VmKdcDecodeMasterKey(
                        gVmdirKrbGlobals.bervMasterKey.lberbv.bv_val, //pMasterKeyBlob,
                        (DWORD) gVmdirKrbGlobals.bervMasterKey.lberbv.bv_len, //dwMasterKeySize,
                        &master);
        BAIL_ON_VMKDC_ERROR(dwError);

        dwError = VmKdcAllocateStringPrintf(&pszMasterName,
                                            "K/M@%s", pszRealm);
        BAIL_ON_VMKDC_ERROR(dwError);


        dwError = _VmKdcGetKrbUPNKey(
                      pszMasterName,
                      &pPrincKeyBlob,
                      &dwPrincKeySize);
        BAIL_ON_VMKDC_ERROR(dwError);


        /*
         * The K/M master key is ASN.1 encoded and encrypted in the master key
         */
        dwError = VmKdcDecodeMasterKey(
                      pPrincKeyBlob,
                      dwPrincKeySize,
                      &kmEncKey);
        BAIL_ON_VMKDC_ERROR(dwError);

        dwError = VmKdcInitCrypto(pGlobals->pKrb5Ctx, master, &pCrypto);
        BAIL_ON_VMKDC_ERROR(dwError);

        dwError = VmKdcCryptoDecrypt(pCrypto, 0, kmEncKey->data,  &kmKey);
        BAIL_ON_VMKDC_ERROR(dwError);

        if (VMKDC_GET_LEN_DATA(master->data) != VMKDC_GET_LEN_DATA(kmKey) ||
            memcmp(VMKDC_GET_PTR_DATA(master->data),
                   VMKDC_GET_PTR_DATA(kmKey),
                   VMKDC_GET_LEN_DATA(kmKey)))
        {
            // TBD: Not quite right error
            dwError = ERROR_ALLOC_KRB5_CRYPTO_CONTEXT;
            BAIL_ON_VMKDC_ERROR(dwError);
        }

        pthread_mutex_lock(&pGlobals->mutex);
        VMKDC_SAFE_FREE_KEY(pGlobals->masterKey);
        pGlobals->masterKey = master;
        master = NULL;
        pthread_mutex_unlock(&pGlobals->mutex);
    }
#endif

error:
#ifdef MIT_KERBEROS_DB
    VmKdcParseKeyTabFreeEntry(ktEntry);
    VmKdcParseKeyTabClose(hKtFile);
    VMKDC_SAFE_FREE_KEYSET(pKmKeySet);
#endif
    VMKDC_SAFE_FREE_STRINGA(pszMasterName);
    VMKDC_SAFE_FREE_MEMORY(pPrincKeyBlob);
    VMKDC_SAFE_FREE_KEY(kmEncKey);
    VMKDC_SAFE_FREE_KEY(master);
    VMKDC_SAFE_FREE_DATA(kmKey);
    VmKdcDestroyCrypto(pCrypto);

    VMDIR_UNLOCK_MUTEX( bInLock, gVmdirKrbGlobals.pmutex);

    return dwError;
}