Example #1
0
static
DWORD
_VmDirRidSyncThr(
    PVOID    pArg
    )
{
    DWORD               dwError = 0;
    BOOLEAN             bInLock = FALSE;
    PVDIR_THREAD_INFO   pThrInfo = (PVDIR_THREAD_INFO)pArg;
    PVMDIR_SID_GEN_STACK_NODE pSidGenStackNode = NULL;

    VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "_VmDirRidSyc thr started" );

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

        VMDIR_SAFE_FREE_MEMORY(pSidGenStackNode);
        while (VmDirPopTSStack(gSidGenState.pStack, (PVOID*)&pSidGenStackNode) == 0 &&
               pSidGenStackNode != NULL)
        {
            (VOID)VmDirSyncRIDSeqToDB(
                    pSidGenStackNode->pszDomainDn,
                    pSidGenStackNode->dwDomainRidSequence);

            if (VmDirdState() == VMDIRD_STATE_SHUTDOWN)
            {
                //
                // Any pending updates will be performed by VmDirVmAclShutdown.
                //
                goto cleanup;
            }

            VMDIR_SAFE_FREE_MEMORY(pSidGenStackNode);
        }

        VMDIR_LOCK_MUTEX(bInLock, pThrInfo->mutexUsed);

        VmDirConditionTimedWait(
            pThrInfo->conditionUsed,
            pThrInfo->mutexUsed,
            3 * 1000);          // time wait 3 seconds
        // ignore error

        VMDIR_UNLOCK_MUTEX(bInLock, pThrInfo->mutexUsed);
    }

cleanup:

    VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "_VmDirRidSyc thr stopped (%d)", dwError );

    VMDIR_SAFE_FREE_MEMORY(pSidGenStackNode);

    return dwError;
}
Example #2
0
DWORD
VmDirQueueDequeue(
    BOOL        bInLock,
    PVDIR_QUEUE pQueue,
    int64_t     iTimeoutMs,
    PVOID*      ppElement
    )
{
    DWORD dwError = 0;
    PVDIR_QUEUE_NODE pTemp= NULL;

    if (!pQueue || !ppElement)
    {
        BAIL_WITH_VMDIR_ERROR(dwError, ERROR_INVALID_PARAMETER);
    }

    VMDIR_LOCK_MUTEX(bInLock, pQueue->pMutex);

    if (!pQueue->pHead)
    {
        if (iTimeoutMs < 0) // Blocking
        {
            while (!pQueue->pHead)
            {
                dwError = VmDirConditionWait(pQueue->pCond, pQueue->pMutex);
                BAIL_ON_VMDIR_ERROR(dwError);
            }
        }
        else if (iTimeoutMs > 0) // Waiting
        {
            VmDirConditionTimedWait(pQueue->pCond, pQueue->pMutex, iTimeoutMs);
            if (!pQueue->pHead)
            {
                dwError = VMDIR_ERROR_QUEUE_EMPTY;
            }
        }
        else // Non Blocking
        {
            dwError = VMDIR_ERROR_QUEUE_EMPTY;
        }
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    pQueue->iSize--;
    pTemp = pQueue->pHead;
    pQueue->pHead = pQueue->pHead->pNext;
    *ppElement = pTemp->pElement;
    VMDIR_SAFE_FREE_MEMORY(pTemp);

cleanup:
    VMDIR_UNLOCK_MUTEX(bInLock, pQueue->pMutex);
    return dwError;

error:
    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "%s failed, error (%d)", __FUNCTION__, dwError);
    goto cleanup;
}
Example #3
0
/*
 * Waits until there's data from the worker thread to read (or until the
 * server's shutdown).
 */
static
DWORD
_VmDirPagedSearchCacheWaitAndRead_inlock(
    PVDIR_PAGED_SEARCH_RECORD pSearchRecord,
    PVDIR_PAGED_SEARCH_ENTRY_LIST *ppEntryList
    )
{
    DWORD dwError = 0;
    PVDIR_PAGED_SEARCH_ENTRY_LIST pEntryList = NULL;

    while (TRUE)
    {
        dwError = dequePopLeft(pSearchRecord->pQueue, (PVOID*)&pEntryList);
        if (dwError == 0)
        {
            break;
        }
        else if (pSearchRecord->bProcessingCompleted)
        {
            //
            // Nothing in the queue and processing's complete so we must have
            // read all the data.
            //
            pSearchRecord->bSearchCompleted = TRUE;
            dwError = 0;
            break;
        }
        else
        {
            (VOID)VmDirConditionTimedWait(
                    pSearchRecord->pDataAvailable,
                    pSearchRecord->mutex,
                    VMDIR_PSCACHE_READ_TIMEOUT);
        }

        if (VmDirdState() == VMDIRD_STATE_SHUTDOWN)
        {
            BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_UNAVAILABLE);
        }
    }

    *ppEntryList = pEntryList;

    pSearchRecord->tLastClientRead = time(NULL);

cleanup:
    return dwError;
error:
    goto cleanup;
}
Example #4
0
static
VOID
_VmDirPagedSearchCacheWaitForClientCompletion(
    PVDIR_PAGED_SEARCH_RECORD pSearchRecord
    )
{
    BOOLEAN bInLock = FALSE;
    DWORD dwError = 0;

    //
    // Sleep for our timeout period or until the client has read all the data
    // (at which point bSearchCompleted will be set and the condition will be
    // signalled). If we timeout we're going to clear the cache forcibly, which
    // will cause the client to fallback to the old search semantics. Note
    // that the timeout is reset everytime the client issues a read request.
    //
    VMDIR_LOCK_MUTEX(bInLock, pSearchRecord->pThreadInfo->mutexUsed);

    pSearchRecord->bProcessingCompleted = TRUE;

    while (TRUE)
    {
        if (pSearchRecord->bSearchCompleted)
        {
            break;
        }
        dwError = VmDirConditionTimedWait(
                    pSearchRecord->pThreadInfo->conditionUsed,
                    pSearchRecord->pThreadInfo->mutexUsed,
                    gVmdirGlobals.dwLdapRecvTimeoutSec);
        if (dwError == ETIMEDOUT)
        {
            if ((time(NULL) - pSearchRecord->tLastClientRead) > gVmdirGlobals.dwLdapRecvTimeoutSec)
            {
                break;
            }
        }
    }

    VMDIR_UNLOCK_MUTEX(bInLock, pSearchRecord->pThreadInfo->mutexUsed);
}
Example #5
0
/*
 * Thread to handle db checkpoint and log file aging.
 * 1.  it sleep for x (configurable) minutes.
 * 2.  check how long ago was lost check point
 * 2.1   if longer than y (configurable) minutes then check point
 *
 */
static
DWORD
VmDirBdbCheckpointThrFun(
    PVOID   pArg
    )
{
    DWORD   dwError = 0;
    int     iCFGChkpointIntervalinMIN = 0;
    int     iCFGCheckpointSizeinKB = 0;
    int     iCFGLogAgingIntervalInMIN = 0;

    time_t  tLastLogAge = time(NULL);
    PVDIR_THREAD_INFO   pThrInfo = (PVDIR_THREAD_INFO)pArg;

    //TODO, make this configurable (or even changeable during online)
    iCFGChkpointIntervalinMIN = 3;
    iCFGCheckpointSizeinKB = 100;
    iCFGLogAgingIntervalInMIN = 360;

    while (1)
    {
        struct timespec ts = {0};
        BOOLEAN bInLock = FALSE;

        ts.tv_sec = time(NULL) + (iCFGChkpointIntervalinMIN * 60);
        ts.tv_nsec = 0;

        VMDIR_LOCK_MUTEX(bInLock, pThrInfo->mutexUsed);

        dwError = VmDirConditionTimedWait(
                pThrInfo->conditionUsed,
                pThrInfo->mutexUsed,
                (iCFGChkpointIntervalinMIN * 60)*1000);

        VMDIR_UNLOCK_MUTEX(bInLock, pThrInfo->mutexUsed);

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

        // ignore dwError == ETIMEOUT check as rare case and benign checkpoint

        dwError = gVdirBdbGlobals.bdbEnv->txn_checkpoint(
                gVdirBdbGlobals.bdbEnv,
                iCFGCheckpointSizeinKB,
                iCFGChkpointIntervalinMIN ,
                0);
        BAIL_ON_VMDIR_ERROR(dwError);
        VmDirLog( LDAP_DEBUG_TRACE, "Bdb: checkpoint" );

        if (ts.tv_sec - tLastLogAge > (iCFGLogAgingIntervalInMIN * 60))
        {
            dwError = bdbLogfileAging();
            BAIL_ON_VMDIR_ERROR(dwError);

            tLastLogAge = ts.tv_sec;
        }
    }

cleanup:

    // TODO: return dwError ?
    return 0;

error:

    raise(SIGTERM);

    goto cleanup;
}
Example #6
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 #7
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;
}