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; }
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; }
/* * 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; }
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); }
/* * 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; }
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; }
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; }