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