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