DWORD VmDirPrepareSwapDBInfo( PCSTR pszHostName, // partner server object cn PVMDIR_SWAP_DB_INFO* ppSwapDBInfo ) { DWORD dwError = 0; PVMDIR_SWAP_DB_INFO pLocalSwapDBInfo = NULL; if (!ppSwapDBInfo) { BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER); } dwError = VmDirAllocateMemory(sizeof(VMDIR_SWAP_DB_INFO), (PVOID*)&pLocalSwapDBInfo); BAIL_ON_VMDIR_ERROR(dwError); if (pszHostName) { dwError = VmDirAllocateStringA(pszHostName, &pLocalSwapDBInfo->pszPartnerServerName); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "My partner %s", pLocalSwapDBInfo->pszPartnerServerName); } dwError = VmDirInternalGetDSERootServerCN(&pLocalSwapDBInfo->pszOrgDBServerName); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "DB was from %s", pLocalSwapDBInfo->pszOrgDBServerName); dwError = _VmDirComposeUtdVector(pLocalSwapDBInfo); BAIL_ON_VMDIR_ERROR(dwError); if (!pLocalSwapDBInfo->pszPartnerServerName || // no partner, DR case VmDirStringCompareA( // DB copied from joining partner pLocalSwapDBInfo->pszPartnerServerName, pLocalSwapDBInfo->pszOrgDBServerName, FALSE) == 0) { dwError = VmDirAllocateStringA(pLocalSwapDBInfo->pszOrgDBMaxUSN, &pLocalSwapDBInfo->pszMyHighWaterMark); BAIL_ON_VMDIR_ERROR(dwError); } else { // DB from one node but join to another dwError = _VmDirComposeHighWaterMark(pLocalSwapDBInfo); BAIL_ON_VMDIR_ERROR(dwError); } VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "My High Water Mark %s", pLocalSwapDBInfo->pszMyHighWaterMark); *ppSwapDBInfo = pLocalSwapDBInfo; cleanup: return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, " error (%u)", dwError); VmDirFreeSwapDBInfo(pLocalSwapDBInfo); goto cleanup; }
DWORD VmDirResetVmdir( VOID) { DWORD dwError = 0; dwError = VmDirStopService(); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "VMWare Directory Service stopped." ); //Test for bug#1034595. On Windows, vmdird may fail to stop. Wait 2 seconds here. //Remove it if it's not useful VmDirSleep(2000); dwError = VmDirCleanupData(); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "VMWare Directory Service database removed." ); dwError = VmDirStartService(); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "VMWare Directory Service ready for re-promotion." ); error: return dwError; }
DWORD VmDirIndexUpdateCommit( PVDIR_INDEX_UPD pIndexUpd ) { DWORD dwError = 0; LW_HASHMAP_ITER iter = LW_HASHMAP_ITER_INIT; LW_HASHMAP_PAIR pair = {NULL, NULL}; PSTR pszStatus = NULL; if (!pIndexUpd) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } while (LwRtlHashMapIterate(pIndexUpd->pUpdIndexCfgMap, &iter, &pair)) { PVDIR_INDEX_CFG pIndexCfg = (PVDIR_INDEX_CFG)pair.pValue; dwError = VmDirIndexCfgRecordProgress(pIndexUpd->pBECtx, pIndexCfg); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_SAFE_FREE_MEMORY(pszStatus); dwError = VmDirIndexCfgStatusStringfy(pIndexCfg, &pszStatus); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, pszStatus ); } if (pIndexUpd->bHasBETxn) { PVDIR_BACKEND_INTERFACE pBE = pIndexUpd->pBECtx->pBE; dwError = pBE->pfnBETxnCommit(pIndexUpd->pBECtx); BAIL_ON_VMDIR_ERROR(dwError); pIndexUpd->bHasBETxn = FALSE; } VmDirIndexUpdFree(gVdirIndexGlobals.pIndexUpd); gVdirIndexGlobals.pIndexUpd = pIndexUpd; VmDirConditionSignal(gVdirIndexGlobals.cond); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "%s succeeded", __FUNCTION__ ); cleanup: VMDIR_SAFE_FREE_MEMORY(pszStatus); return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s failed, error (%d)", __FUNCTION__, dwError ); goto cleanup; }
/* * After copying DB from partner, we need to derive UTDVector for new node from partner. * i.e. <whatever partner node current UTDVector> + <partner invoactionid:partner max commited USN> */ static DWORD _VmDirComposeUtdVector( PVMDIR_SWAP_DB_INFO pSwapDBInfo ) { DWORD dwError = 0; PVDIR_ENTRY pServerEntry = NULL; PVDIR_ATTRIBUTE pAttrUTDVector = NULL; PVDIR_ATTRIBUTE pAttrInvocationId = NULL; VDIR_OPERATION searchOp = {0}; dwError = VmDirInitStackOperation(&searchOp, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_SEARCH, NULL); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirInternalSearchSeverObj(pSwapDBInfo->pszOrgDBServerName, &searchOp); BAIL_ON_VMDIR_ERROR(dwError); pServerEntry = searchOp.internalSearchEntryArray.pEntry; pAttrUTDVector = VmDirEntryFindAttribute(ATTR_UP_TO_DATE_VECTOR, pServerEntry); pAttrInvocationId = VmDirEntryFindAttribute(ATTR_INVOCATION_ID, pServerEntry); dwError = _VmGetHighestCommittedUSN(&pSwapDBInfo->pszOrgDBMaxUSN); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "DB maxCommittedUSN %s", pSwapDBInfo->pszOrgDBMaxUSN); dwError = VmDirUTDVectorCacheInit(&pSwapDBInfo->pMyUTDVector); BAIL_ON_VMDIR_ERROR(dwError); if (pAttrUTDVector) { dwError = VmDirUTDVectorCacheReplace(pSwapDBInfo->pMyUTDVector, pAttrUTDVector->vals[0].lberbv.bv_val); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "DB UTDVector %s", pSwapDBInfo->pMyUTDVector->pszUtdVector); } dwError = VmDirUTDVectorCacheAdd( pSwapDBInfo->pMyUTDVector, pAttrInvocationId->vals[0].lberbv.bv_val, pSwapDBInfo->pszOrgDBMaxUSN); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "My UTDVector %s", pSwapDBInfo->pMyUTDVector->pszUtdVector); cleanup: VmDirFreeOperationContent(&searchOp); return dwError; error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "error (%u)", dwError); goto cleanup; }
static DWORD _VmDirSchemaAttrReplaceValue( PVDIR_ATTRIBUTE pAttr, PCSTR pszMatchSubstr, PCSTR pszValue ) { #define MAX_BUF_SIZE_256 256 DWORD dwError = 0; unsigned iCnt = 0; CHAR pszBuf[MAX_BUF_SIZE_256] = {0}; dwError = VmDirStringPrintFA( pszBuf, MAX_BUF_SIZE_256 -1 , "NAME '%s' ", pszMatchSubstr ); BAIL_ON_VMDIR_ERROR(dwError); for (iCnt = 0; iCnt < pAttr->numVals; iCnt++) { if ( VmDirCaselessStrStrA( pAttr->vals[iCnt].lberbv_val, pszBuf ) != NULL ) { if ( VmDirStringCompareA( VDIR_SAFE_STRING(pAttr->vals[iCnt].lberbv_val), pszValue, FALSE ) != 0 ) { VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Merge schema, replace old - %s", VDIR_SAFE_STRING(pAttr->vals[iCnt].lberbv_val)); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Merge schema, replace new - %s", pszValue ); } VMDIR_LOG_DEBUG( VMDIR_LOG_MASK_ALL, "Merge schema, replace old - %s", VDIR_SAFE_STRING(pAttr->vals[iCnt].lberbv_val)); VmDirFreeBervalContent( &(pAttr->vals[iCnt]) ); dwError = VmDirAllocateStringA( pszValue, &(pAttr->vals[iCnt].lberbv_val) ); BAIL_ON_VMDIR_ERROR(dwError); pAttr->vals[iCnt].lberbv_len = VmDirStringLenA( pszValue ); pAttr->vals[iCnt].bOwnBvVal = TRUE; VMDIR_LOG_DEBUG( VMDIR_LOG_MASK_ALL, "Merge schema, replace new - %s", VDIR_SAFE_STRING(pAttr->vals[iCnt].lberbv_val)); break; } } cleanup: return dwError; error: goto cleanup; }
/* * Commit schema modification into cache. * * 1. commit pending cache to go live * 2. create self reference ctx * 3. release old self reference ctx * 4. update pEntry to have new live schema ctx association */ VOID VmDirSchemaCacheModifyCommit( PVDIR_ENTRY pSchemaEntry ) { DWORD dwError = 0; BOOLEAN bInLock = FALSE; PVDIR_SCHEMA_CTX pOldCtx = NULL; if ( !pSchemaEntry || !pSchemaEntry->pSchemaCtx ) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } VMDIR_LOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); if ( ! gVdirSchemaGlobals.bHasPendingChange ) { VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Schema cache update pass through" ); goto cleanup; // no schema definition change, just pass through. } gVdirSchemaGlobals.bHasPendingChange = FALSE; gVdirSchemaGlobals.pSchema = pSchemaEntry->pSchemaCtx->pSchema; pOldCtx = gVdirSchemaGlobals.pCtx; gVdirSchemaGlobals.pCtx = NULL; VdirSchemaCtxAcquireInLock(TRUE, &gVdirSchemaGlobals.pCtx); // add global instance self reference assert(gVdirSchemaGlobals.pCtx); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Enable schema instance (%p)", gVdirSchemaGlobals.pSchema); VMDIR_UNLOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); cleanup: VMDIR_UNLOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); if (pOldCtx) { VmDirSchemaCtxRelease(pOldCtx); } return; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirSchemaCacheModifyCommit failed (%d)", dwError); goto cleanup; }
//The log is to detect bursting traffic that // caused write transaction avg. latency to spike. VOID VmDirWtxnOutstandingInc() { BOOLEAN bLock = FALSE; double stats_peroid_ms = 0.0; double offered_rate = 0.0; VMDIR_LOCK_MUTEX(bLock, g_w_txns_mutex); if (g_w_txns_outstanding == 0) { g_start_ts_ms = VmDirGetTimeInMilliSec(); g_stats_cnt = 0; } g_w_txns_outstanding++; g_stats_cnt++; if (g_w_txns_outstanding >= g_w_txns_outstanding_thresh && g_stats_cnt >= g_w_txns_outstanding_thresh) { stats_peroid_ms = (double)(VmDirGetTimeInMilliSec() - g_start_ts_ms); if (stats_peroid_ms > 1) //avoid float point division overflow { offered_rate = (double)g_stats_cnt * 1000.0 / stats_peroid_ms; VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "%s: write transactions outstanding %d for peroid %.2g ms with offered rate %.3g on %d write requests", __func__, g_w_txns_outstanding, stats_peroid_ms, offered_rate, g_stats_cnt); } g_stats_cnt = 0; g_start_ts_ms = VmDirGetTimeInMilliSec(); } VMDIR_UNLOCK_MUTEX(bLock, g_w_txns_mutex); }
static DWORD _VmDirWtxnStatsInit() { DWORD dwWtxnOutstandingThresh = W_TXNS_OUTSTANDING_THRESH_D; DWORD dwError = 0; if (g_w_txns_mutex == NULL) { dwError = VmDirAllocateMutex(&g_w_txns_mutex); BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirGetRegKeyValueDword( VMDIR_CONFIG_PARAMETER_V1_KEY_PATH, VMDIR_REG_KEY_WTXN_OUTSTANDING_THRESH, &dwWtxnOutstandingThresh, 0); if (dwError == 0) { g_w_txns_outstanding_thresh = dwWtxnOutstandingThresh; } else { //Use the default value. dwError = 0; } VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "%s: W_TXNS_OUTSTANDING_THRESH = %d", __func__, g_w_txns_outstanding_thresh); done: return dwError; error: goto done; }
/* last_pgno and max_pgs are logged. If last_pgno + pages for adding new data > max_pgs, mdb_put will fail with error MDB_MAP_FULL. Mdb first tries to reuse released pages before trying to get new pages from the free list. Thus even if an operation request new pages failed (last_pgno + pages > max_pgs), adding smaller data may still succeeded if the there are enough pages in the released pages. Max memory can be calculated from max_pgs * page size which is the same as the OS page size. */ void VmDirLogDBStats( PVDIR_MDB_DB pDB ) { MDB_envinfo env_stats = {0}; MDB_stat db_stats = {0}; assert(pDB); if (mdb_env_info(pDB->mdbEnv, &env_stats) != MDB_SUCCESS || mdb_env_stat(pDB->mdbEnv, &db_stats)!= MDB_SUCCESS) { goto error; } VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "mdb stats: last_pgno %llu, max_pgs %lld", env_stats.me_last_pgno, env_stats.me_mapsize/db_stats.ms_psize); cleanup: return; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "Error retrieving MDB statistics"); goto cleanup; }
DWORD VmDirIndexUpdateAbort( PVDIR_INDEX_UPD pIndexUpd ) { DWORD dwError = 0; if (!pIndexUpd) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } if (pIndexUpd->bHasBETxn) { PVDIR_BACKEND_INTERFACE pBE = pIndexUpd->pBECtx->pBE; dwError = pBE->pfnBETxnAbort(pIndexUpd->pBECtx); BAIL_ON_VMDIR_ERROR(dwError); pIndexUpd->bHasBETxn = FALSE; } VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "%s succeeded", __FUNCTION__ ); cleanup: VmDirIndexUpdFree(pIndexUpd); return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s failed, error (%d)", __FUNCTION__, dwError ); goto cleanup; }
static DWORD _VmDirDeadlockDetectionVectorPairToStr( LW_HASHMAP_PAIR pair, BOOLEAN bStart, PSTR* ppOutStr ) { PSTR pszTempStr = NULL; DWORD dwError = 0; VMDIR_LOG_INFO(LDAP_DEBUG_REPL, "%s: key: %s value: %d", (PSTR)pair.pKey, *(PDWORD)pair.pValue); if (bStart) { dwError = VmDirAllocateStringPrintf(&pszTempStr, "vector:%s:%d", pair.pKey, *(PDWORD)pair.pValue); BAIL_ON_VMDIR_ERROR(dwError); } else { dwError = VmDirAllocateStringPrintf(&pszTempStr, ",%s:%d", pair.pKey, *(PDWORD)pair.pValue); BAIL_ON_VMDIR_ERROR(dwError); } *ppOutStr = pszTempStr; pszTempStr = NULL; cleanup: VMDIR_SAFE_FREE_MEMORY(pszTempStr); return dwError; error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "failed, error (%d)", dwError); goto cleanup; }
/* 4.2.2. Bind Response The Bind response is defined as follows. BindResponse ::= [APPLICATION 1] SEQUENCE { COMPONENTS OF LDAPResult, serverSaslCreds [7] OCTET STRING OPTIONAL } */ VOID VmDirSendSASLBindResponse( PVDIR_OPERATION pOperation ) { DWORD dwError = 0; BerElementBuffer berbuf; BerElement * ber = (BerElement *) &berbuf; PVDIR_LDAP_RESULT pResult = &(pOperation->ldapResult); ber_tag_t respType = GetResultTag(pOperation->reqCode); (void) memset( (char *)&berbuf, '\0', sizeof( BerElementBuffer )); ber_init2( ber, NULL, LBER_USE_DER ); VMDIR_LOG_INFO( LDAP_DEBUG_ARGS, "VmDirSendLdapResponse: code (%d), Error (%d)(%s)", respType, pResult->errCode, VDIR_SAFE_STRING(pResult->pszErrMsg)); dwError = ber_printf( ber, "{it{ess" /*"}}"*/, pOperation->msgId, // message sequence id GetResultTag(pOperation->reqCode), // ldap response type pResult->errCode, // ldap return code e.g. LDAP_SASL_CONNTINUE pResult->matchedDn.lberbv.bv_len > 0 ? pResult->matchedDn.lberbv.bv_val : "", VDIR_SAFE_STRING(pResult->pszErrMsg)); // error text detail BAIL_ON_LBER_ERROR(dwError); // Send back TAG and SASL reply blob // NOTE, not exactly sure if we ever need to send Tag but WITHOUT blob reply if blob is empty. // but this should NOT happen in GSSAPI scenario. if ( pResult->replyInfo.type == REP_SASL && pResult->replyInfo.replyData.bvSaslReply.lberbv.bv_len > 0 ) { dwError = ber_printf( ber, "tO", LDAP_TAG_SASL_RES_CREDS, &pResult->replyInfo.replyData.bvSaslReply.lberbv ); BAIL_ON_LBER_ERROR(dwError); } dwError = ber_printf( ber, "N}N}" ); BAIL_ON_LBER_ERROR(dwError); dwError = WriteBerOnSocket( pOperation->conn, ber ); BAIL_ON_VMDIR_ERROR(dwError); cleanup: ber_free_buf( ber ); return; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "lber error (%d)", dwError); goto cleanup; }
DWORD VmDirWriteQueuePush( PVDIR_BACKEND_CTX pBECtx, PVMDIR_WRITE_QUEUE pWriteQueue, PVMDIR_WRITE_QUEUE_ELEMENT pWriteQueueEle ) { int dbRetVal = 0; USN localUsn = 0; DWORD dwError = 0; BOOLEAN bInLock = FALSE; if (!pBECtx || !pWriteQueue || !pWriteQueueEle) { BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER); } if (pBECtx->wTxnUSN != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: acquiring multiple usn in same operation context, USN: %" PRId64, __FUNCTION__, pBECtx->wTxnUSN); BAIL_WITH_VMDIR_ERROR(dwError, LDAP_OPERATIONS_ERROR); } VMDIR_LOCK_MUTEX(bInLock, gVmDirServerOpsGlobals.pMutex); if ((dbRetVal = pBECtx->pBE->pfnBEGetNextUSN(pBECtx, &localUsn)) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: pfnBEGetNextUSN failed with error code: %d", __FUNCTION__, dbRetVal); BAIL_WITH_VMDIR_ERROR(dwError, LDAP_OPERATIONS_ERROR); } pWriteQueueEle->usn = localUsn; dwError = VmDirLinkedListInsertTail( pWriteQueue->pList, (PVOID) pWriteQueueEle, NULL); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOG_INFO(LDAP_DEBUG_WRITE_QUEUE, "%s: usn: %"PRId64, __FUNCTION__, localUsn); cleanup: VMDIR_UNLOCK_MUTEX(bInLock, gVmDirServerOpsGlobals.pMutex); return dwError; error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "failed, error (%d) localUsn %"PRId64, dwError, localUsn); goto cleanup; }
int VmDirFirstReplicationCycle( PCSTR pszHostname, VMDIR_REPLICATION_AGREEMENT * pReplAgr) { int retVal = LDAP_SUCCESS; PSTR pszLocalErrorMsg = NULL; BOOLEAN bWriteInvocationId = FALSE; BOOLEAN bHasXlog = FALSE; #ifndef _WIN32 const char *dbHomeDir = VMDIR_DB_DIR; #else _TCHAR dbHomeDir[MAX_PATH]; size_t last_char_pos = 0; const char fileSeperator = '\\'; retVal = VmDirMDBGetHomeDir(dbHomeDir); BAIL_ON_VMDIR_ERROR ( retVal ); last_char_pos = strlen(dbHomeDir) - 1; if (dbHomeDir[last_char_pos] == fileSeperator) { dbHomeDir[last_char_pos] = '\0'; } #endif assert( gFirstReplCycleMode == FIRST_REPL_CYCLE_MODE_COPY_DB ); retVal = _VmDirGetRemoteDBUsingRPC(pszHostname, dbHomeDir, &bHasXlog); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "VmDirFirstReplicationCycle: _VmDirGetRemoteDBUsingRPC() call failed with error: %d", retVal ); retVal = _VmDirSwapDB(dbHomeDir, bHasXlog); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "VmDirFirstReplicationCycle: _VmDirSwapDB() call failed, error: %d.", retVal ); VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "Remote DB copied from %s, and swapped successfully", pszHostname); // Wrap up the 1st replication cycle by updating replication cookies. retVal = _VmDirWrapUpFirstReplicationCycle( pszHostname, pReplAgr ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "VmDirFirstReplicationCycle: _VmDirWrapUpFirstReplicationCycle() call failed, error: %d.", retVal ); retVal = LoadServerGlobals(&bWriteInvocationId); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "VmDirFirstReplicationCycle: LoadServerGlobals call failed, error: %d.", retVal ); 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 VmDirSASL2PATH( PSTR *ppszPath ) { DWORD dwError = 0; PSTR pszLocalPath = NULL; #ifdef _WIN32 char sasl2SearchPathBuf[MAX_PATH] = {0}; char vmdirInstallPathBuf[MAX_PATH] = {0}; // base sasl lib path dwError = VmDirGetRegKeyValue( VDMIR_CONFIG_SASL2_KEY_PATH, "SearchPath", sasl2SearchPathBuf, MAX_PATH ); BAIL_ON_VMDIR_ERROR(dwError); // vmdir specific sasl lib path dwError = VmDirGetRegKeyValue( VMDIR_CONFIG_SOFTWARE_KEY_PATH, "InstallPath", vmdirInstallPathBuf, MAX_PATH ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringAVsnprintf( &pszLocalPath, "%s;%s\\sasl2", sasl2SearchPathBuf, vmdirInstallPathBuf); #else dwError = VmDirAllocateStringAVsnprintf( &pszLocalPath, "%s:%s/sasl2", VMDIR_CONFIG_SASL2_LIB_PATH, VMDIR_LIB_DIR); #endif BAIL_ON_VMDIR_ERROR(dwError); *ppszPath = pszLocalPath; VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "SASL2PATH=%s", pszLocalPath); cleanup: return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirSASL2PATH failed (%d)", dwError); VMDIR_SAFE_FREE_MEMORY( pszLocalPath ); goto cleanup; }
/* * If you want this update to be a part of bigger transaction, * provide pBECtx. Or leave it NULL otherwise. */ DWORD VmDirIndexUpdateBegin( PVDIR_BACKEND_CTX pBECtx, PVDIR_INDEX_UPD* ppIndexUpd ) { DWORD dwError = 0; PVDIR_INDEX_UPD pIndexUpd = NULL; if (!ppIndexUpd) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirIndexUpdInit(pBECtx, &pIndexUpd); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirIndexUpdCopy(gVdirIndexGlobals.pIndexUpd, pIndexUpd); BAIL_ON_VMDIR_ERROR(dwError); if (pIndexUpd->bOwnBECtx) { PVDIR_BACKEND_INTERFACE pBE = VmDirBackendSelect(NULL); pIndexUpd->pBECtx->pBE = pBE; dwError = pBE->pfnBETxnBegin(pIndexUpd->pBECtx, VDIR_BACKEND_TXN_WRITE); BAIL_ON_VMDIR_ERROR(dwError); pIndexUpd->bHasBETxn = TRUE; } *ppIndexUpd = pIndexUpd; VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "%s succeeded", __FUNCTION__ ); cleanup: return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s failed, error (%d)", __FUNCTION__, dwError ); VmDirIndexUpdFree(pIndexUpd); goto cleanup; }
DWORD VmDirSrvSetupTenantInstance( PCSTR pszFQDomainName, PCSTR pszUsername, PCSTR pszPassword ) { DWORD dwError = 0; PSTR pszDomainDN = NULL; PVDIR_SCHEMA_CTX pSchemaCtx = NULL; VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "Setting up a tenant instance (%s).", VDIR_SAFE_STRING(pszFQDomainName)); dwError = VmDirSrvCreateDomainDN(pszFQDomainName, &pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSchemaCtxAcquire(&pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSrvSetupDomainInstance( pSchemaCtx, FALSE, FALSE, pszFQDomainName, pszDomainDN, pszUsername, pszPassword); BAIL_ON_VMDIR_ERROR(dwError); cleanup: VMDIR_SAFE_FREE_MEMORY(pszDomainDN); if (pSchemaCtx) { VmDirSchemaCtxRelease(pSchemaCtx); } return dwError; error: VmDirLog(LDAP_DEBUG_ANY, "VmDirSrvSetupTenantInstance failed. Error(%u)", dwError); goto cleanup; }
DWORD VmKdcRpcAuthCallback( PVOID Context ) { rpc_authz_handle_t hPrivs = NULL; DWORD dwAuthnLevel = 0; DWORD dwAuthnSvc = 0; DWORD dwAuthzSvc = 0; DWORD dwError = ERROR_SUCCESS; dwError = VmKdcRpcBindingInqAuthClient( Context, &hPrivs, // The data referenced by this parameter is read-only, // and therefore should not be modified/freed. NULL, // ServerPrincipalName - we don't need it &dwAuthnLevel, &dwAuthnSvc, &dwAuthzSvc); BAIL_ON_VMKDC_ERROR(dwError); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Authentication Level = %d, Authentication Service = %d," "Authorization Service = %d.", dwAuthnLevel, dwAuthnSvc, dwAuthzSvc); // Now check the authentication level. We require at least packet-level // authentication. if (dwAuthnLevel < rpc_c_authn_level_pkt) { VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "Attempt by client to use weak authentication."); dwError = ERROR_ACCESS_DENIED; BAIL_ON_VMKDC_ERROR(dwError); } error: return dwError; }
/* * Initialize vmkdcd components */ DWORD VmKdcInit() { DWORD dwError = 0; extern VMKDC_GLOBALS gVmkdcGlobals; InitializeGlobals(&gVmkdcGlobals); #ifndef _WIN32 dwError = InitializeResourceLimit(); BAIL_ON_VMKDC_ERROR(dwError); #endif dwError = VmKdcInitKrb5(&gVmkdcGlobals.pKrb5Ctx); BAIL_ON_VMKDC_ERROR(dwError); dwError = VmKdcSrvOpenServicePort(&gVmkdcGlobals, TRUE, VMKDC_SERVICE_PORT_TCP); BAIL_ON_VMKDC_ERROR(dwError); dwError = VmKdcSrvOpenServicePort(&gVmkdcGlobals, FALSE, VMKDC_SERVICE_PORT_TCP); BAIL_ON_VMKDC_ERROR(dwError); dwError = VmKdcSrvOpenServicePort(&gVmkdcGlobals, TRUE, VMKDC_SERVICE_PORT_UDP); BAIL_ON_VMKDC_ERROR(dwError); dwError = VmKdcSrvOpenServicePort(&gVmkdcGlobals, FALSE, VMKDC_SERVICE_PORT_UDP); BAIL_ON_VMKDC_ERROR(dwError); dwError = VmKdcSrvServicePortListen(&gVmkdcGlobals); BAIL_ON_VMKDC_ERROR(dwError); #if 0 dwError = VmKdcRpcServerInit(); BAIL_ON_VMKDC_ERROR(dwError); #endif dwError = VmKdcInitConnAcceptThread(&gVmkdcGlobals); BAIL_ON_VMKDC_ERROR(dwError); VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "VmKdcInit: done!"); error: return dwError; }
/* * Ldap operation thr exit */ static VOID _VmDirFlowCtrlThrExit( VOID ) { BOOLEAN bInLock = FALSE; DWORD dwFlowCtrl = 0; VMDIR_LOCK_MUTEX(bInLock, gVmdirGlobals.pFlowCtrlMutex); gVmdirGlobals.dwMaxFlowCtrlThr++; dwFlowCtrl = gVmdirGlobals.dwMaxFlowCtrlThr; VMDIR_UNLOCK_MUTEX(bInLock, gVmdirGlobals.pFlowCtrlMutex); VMDIR_LOG_INFO( LDAP_DEBUG_CONNS, "FlowCtrlThr++ %d", dwFlowCtrl); return; }
int VmDirPerformDelete( PVDIR_OPERATION pOperation ) { int retVal = LDAP_SUCCESS; DeleteReq * dr = &(pOperation->request.deleteReq); BOOLEAN bResultAlreadySent = FALSE; // Get entry DN. 'm' => pOperation->reqDn.lberbv.bv_val points to DN within (in-place) ber if ( ber_scanf( pOperation->ber, "m", &(pOperation->reqDn.lberbv) ) == LBER_ERROR ) { VMDIR_LOG_ERROR( LDAP_DEBUG_ARGS, "PerformDelete: ber_scanf failed" ); retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR( retVal ); } VMDIR_LOG_INFO( LDAP_DEBUG_ARGS, "Delete Request: dn (%s)", pOperation->reqDn.lberbv.bv_val ); memset( dr, 0, sizeof( DeleteReq )); // NOTE: pOperation->reqDn.lberbv.bv_val is NULL terminated (TODO, verify this) dr->dn.lberbv.bv_val = pOperation->reqDn.lberbv.bv_val; dr->dn.lberbv.bv_len = pOperation->reqDn.lberbv.bv_len; retVal = VmDirMLDelete( pOperation ); bResultAlreadySent = TRUE; BAIL_ON_VMDIR_ERROR(retVal); cleanup: return retVal; error: if (retVal != LDAP_NOTICE_OF_DISCONNECT && bResultAlreadySent == FALSE) { VmDirSendLdapResult( pOperation ); } goto cleanup; }
static VOID _VmDirPrintWriteQueueContentsInLock( PVMDIR_WRITE_QUEUE pWriteQueue ) { PVDIR_LINKED_LIST_NODE pNode = NULL; if (VmDirLogGetMask() & LDAP_DEBUG_WRITE_QUEUE) { VmDirLinkedListGetHead(pWriteQueue->pList, &pNode); while (pNode) { VMDIR_LOG_INFO( LDAP_DEBUG_WRITE_QUEUE, "%s: USNs in the write queue: %"PRId64, __FUNCTION__, ((PVMDIR_WRITE_QUEUE_ELEMENT)pNode->pElement)->usn); pNode = pNode->pNext; } } }
/* * return TRUE if we are over the limit of MaxLdapOpThrs */ static BOOLEAN _VmDirFlowCtrlThrEnter( VOID ) { BOOLEAN bInLock = FALSE; DWORD dwFlowCtrl = 0; VMDIR_LOCK_MUTEX(bInLock, gVmdirGlobals.pFlowCtrlMutex); if ( gVmdirGlobals.dwMaxFlowCtrlThr > 0 ) { dwFlowCtrl = gVmdirGlobals.dwMaxFlowCtrlThr; gVmdirGlobals.dwMaxFlowCtrlThr--; } VMDIR_UNLOCK_MUTEX(bInLock, gVmdirGlobals.pFlowCtrlMutex); VMDIR_LOG_INFO( LDAP_DEBUG_CONNS, "FlowCtrlThr-- %d", dwFlowCtrl); return ( dwFlowCtrl == 0 ); }
DWORD VmDirSrvSetupHostInstance( PCSTR pszFQDomainName, PCSTR pszUsername, PCSTR pszPassword, PCSTR pszSiteName, PCSTR pszReplURI, UINT32 firstReplCycleMode ) { DWORD dwError = 0; PCSTR pszDelObjsContainerName = "Deleted Objects"; PCSTR pszConfigContainerName = VMDIR_CONFIGURATION_CONTAINER_NAME; PCSTR pszCAContainerName = VMDIR_CA_CONTAINER_NAME; PCSTR pszSitesContainerName = VMDIR_SITES_RDN_VAL; PCSTR pszSiteContainerName = "Default-First-Site"; PCSTR pszServersContainerName = VMDIR_SERVERS_CONTAINER_NAME; PCSTR pszReplAgrsContainerName = VMDIR_REPL_AGRS_CONTAINER_NAME; PCSTR pszDCsContainerName = VMDIR_DOMAIN_CONTROLLERS_RDN_VAL; PCSTR pszComputersContainerName = VMDIR_COMPUTERS_RDN_VAL; PCSTR pszMSAsContainerName = VMDIR_MSAS_RDN_VAL; PSTR pszDomainDN = NULL; PSTR pszDelObjsContainerDN = NULL; // CN=Deleted Objects,<domain DN> PSTR pszConfigContainerDN = NULL; // CN=Configuration,<domain DN> PSTR pszCAContainerDN = NULL; // CN=Certificate-Authorities,CN=Configuration,<domain DN> PSTR pszSitesContainerDN = NULL; // CN=Sites,<configuration DN> PSTR pszSiteContainerDN = NULL; // CN=<Site-Name>,<Sites container DN> PSTR pszServersContainerDN = NULL; // CN=Servers,<Site container DN> PSTR pszServerDN = NULL; // CN=<fully qualified host name>,<Servers container DN> PSTR pszReplAgrsContainerDN = NULL; // CN=Replication Agreements,<Server DN> PSTR pszReplAgrDN = NULL; // labeledURI=<ldap://192.165.226.127>,<ReplAgrsContainerDN> PSTR pszDCsContainerDN = NULL; // OU=Domain Controllers,<domain DN> PSTR pszComputersContainerDN = NULL; // OU=Computers,<domain DN> PSTR pszDCAccountDN = NULL; // CN=<fully qualified host name>,OU=Domain Controllers,<domain DN> PSTR pszDCAccountUPN = NULL; // <hostname>@<domain name> PSTR pszComputerAccountDN = NULL; // CN=<fully qualified host name>,OU=Domain Computers,<domain DN> PSTR pszMSAsDN = NULL; // CN=<Managed Service Accounts>,<domain DN> PSTR pszUpperCaseFQDomainName = NULL; PSTR pszLowerCaseHostName = NULL; PSTR pszDefaultAdminDN = NULL; PVDIR_SCHEMA_CTX pSchemaCtx = NULL; char pszHostName[VMDIR_MAX_HOSTNAME_LEN]; VDIR_BERVALUE bv = VDIR_BERVALUE_INIT; BOOLEAN bInLockReplCycle = FALSE; PVMDIR_REPLICATION_AGREEMENT pReplAgr = NULL; BOOLEAN bInLock = FALSE; PSTR pszUserDN = NULL; PCSTR pszUsersContainerName = "Users"; PSTR pszUsersContainerDN = NULL; // CN=Users,<domain DN> VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "Setting up a host instance (%s).", VDIR_SAFE_STRING(pszFQDomainName)); if (pszSiteName) { pszSiteContainerName = pszSiteName; } // If joining another node, copy schema from the partner first. if (!IsNullOrEmptyString(pszReplURI)) { dwError = VmDirCopyPartnerSchema( pszFQDomainName, pszUsername, pszPassword, pszReplURI); BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirSchemaCtxAcquire( &pSchemaCtx ); BAIL_ON_VMDIR_ERROR(dwError); // Construct important DNs and create the persisted DSE Root entry // Domain DN dwError = VmDirSrvCreateDomainDN( pszFQDomainName, &pszDomainDN ); BAIL_ON_VMDIR_ERROR(dwError); // Deleted objects container DN dwError = VmDirSrvCreateDN( pszDelObjsContainerName, pszDomainDN, &pszDelObjsContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Configuration container DN dwError = VmDirSrvCreateDN( pszConfigContainerName, pszDomainDN, &pszConfigContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Domain Controllers container DN dwError = VmDirAllocateStringAVsnprintf(&pszDCsContainerDN, "%s=%s,%s", ATTR_OU, pszDCsContainerName, pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); // Domain Computers container DN dwError = VmDirAllocateStringAVsnprintf(&pszComputersContainerDN, "%s=%s,%s", ATTR_OU, pszComputersContainerName, pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); // Sites container DN dwError = VmDirSrvCreateDN( pszSitesContainerName, pszConfigContainerDN, &pszSitesContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Certificate-Authorities container DN dwError = VmDirSrvCreateDN( pszCAContainerName, pszConfigContainerDN, &pszCAContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Particular site container DN dwError = VmDirSrvCreateDN( pszSiteContainerName, pszSitesContainerDN, &pszSiteContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Servers within the site container DN dwError = VmDirSrvCreateDN( pszServersContainerName, pszSiteContainerDN, &pszServersContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // This server DN // vdcpromo sets this key. dwError = VmDirGetRegKeyValue( VMDIR_CONFIG_PARAMETER_KEY_PATH, VMDIR_REG_KEY_DC_ACCOUNT, pszHostName, sizeof(pszHostName)-1); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocASCIIUpperToLower( pszHostName, &pszLowerCaseHostName ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSrvCreateDN( pszLowerCaseHostName, pszServersContainerDN, &pszServerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Domain controller account DN dwError = VmDirSrvCreateDN( pszLowerCaseHostName, pszDCsContainerDN, &pszDCAccountDN ); BAIL_ON_VMDIR_ERROR(dwError); // Domain controller account UPN dwError = VmDirAllocASCIILowerToUpper( pszFQDomainName, &pszUpperCaseFQDomainName ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringAVsnprintf(&pszDCAccountUPN, "%s@%s", pszLowerCaseHostName, pszUpperCaseFQDomainName ); BAIL_ON_VMDIR_ERROR(dwError); // Computer account DN dwError = VmDirSrvCreateDN( pszLowerCaseHostName, pszComputersContainerDN, &pszComputerAccountDN ); BAIL_ON_VMDIR_ERROR(dwError); // Replication agreements container DN dwError = VmDirSrvCreateDN( pszReplAgrsContainerName, pszServerDN, &pszReplAgrsContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Managed Service Accounts container DN dwError = VmDirSrvCreateDN( pszMSAsContainerName, pszDomainDN, &pszMSAsDN ); BAIL_ON_VMDIR_ERROR(dwError); // Default administrator DN dwError = VmDirAllocateStringAVsnprintf( &pszDefaultAdminDN, "cn=%s,cn=%s,%s", pszUsername, pszUsersContainerName, pszDomainDN ); BAIL_ON_VMDIR_ERROR(dwError); if (firstReplCycleMode != FIRST_REPL_CYCLE_MODE_USE_COPIED_DB) { // Modify persisted DSE Root entry dwError = VmDirSrvModifyPersistedDSERoot( pSchemaCtx, pszDomainDN, pszConfigContainerDN, SCHEMA_NAMING_CONTEXT_DN, SUB_SCHEMA_SUB_ENTRY_DN, pszServerDN, pszDefaultAdminDN, pszDCAccountDN, pszDCAccountUPN, pszDelObjsContainerDN, (PSTR) pszSiteContainerName ); } BAIL_ON_VMDIR_ERROR(dwError); // set gVmdirServerGlobals.bvDefaultAdminDN dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.bvDefaultAdminDN, "%s", pszDefaultAdminDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &gVmdirServerGlobals.bvDefaultAdminDN, pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); // set systemDomainDN dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.systemDomainDN, "%s", pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &gVmdirServerGlobals.systemDomainDN, pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); // set serverObjDN dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.serverObjDN, "%s", pszServerDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &gVmdirServerGlobals.serverObjDN, pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); // set dcAccountDN dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.dcAccountDN, "%s", pszDCAccountDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &gVmdirServerGlobals.dcAccountDN, pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); // set dcAccountUPN dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.dcAccountUPN, "%s", pszDCAccountUPN); BAIL_ON_VMDIR_ERROR(dwError); // Set replInterval and replPageSize gVmdirServerGlobals.replInterval = VmDirStringToIA(VMDIR_DEFAULT_REPL_INTERVAL); gVmdirServerGlobals.replPageSize = VmDirStringToIA(VMDIR_DEFAULT_REPL_PAGE_SIZE); // Set utdVector VmDirFreeBervalContent(&bv); bv.lberbv.bv_val = ""; bv.lberbv.bv_len = 0; dwError = VmDirBervalContentDup( &bv, &gVmdirServerGlobals.utdVector ); BAIL_ON_VMDIR_ERROR(dwError); // Set delObjsContainerDN VmDirFreeBervalContent(&bv); bv.lberbv.bv_val = pszDelObjsContainerDN; bv.lberbv.bv_len = VmDirStringLenA( bv.lberbv.bv_val ); dwError = VmDirBervalContentDup( &bv, &gVmdirServerGlobals.delObjsContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN(&gVmdirServerGlobals.delObjsContainerDN, pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringA( pszSiteContainerName, &gVmdirServerGlobals.pszSiteName); BAIL_ON_VMDIR_ERROR(dwError); // Create Administrator DN dwError = VmDirSrvCreateDN( pszUsersContainerName, pszDomainDN, &pszUsersContainerDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSrvCreateUserDN( pszUsername, pszUsersContainerDN, &pszUserDN); BAIL_ON_VMDIR_ERROR(dwError); // set DomainControllerGroupDN for first,second+ host setup dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.bvDCGroupDN, "cn=%s,cn=%s,%s", VMDIR_DC_GROUP_NAME, VMDIR_BUILTIN_CONTAINER_NAME, pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &(gVmdirServerGlobals.bvDCGroupDN), pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); // set DCClientGroupDN for first,second+ host setup dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.bvDCClientGroupDN, "cn=%s,cn=%s,%s", VMDIR_DCCLIENT_GROUP_NAME, VMDIR_BUILTIN_CONTAINER_NAME, pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &(gVmdirServerGlobals.bvDCClientGroupDN), pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); // set ServicesRootDN for first,second+ host setup dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.bvServicesRootDN, "cn=%s,%s", VMDIR_SERVICES_CONTAINER_NAME, pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &(gVmdirServerGlobals.bvServicesRootDN), pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); if (IsNullOrEmptyString(pszReplURI)) // 1st directory instance is being setup { // Set gVmdirServerGlobals.serverId FIRST, so that correct SID can be generated for the objects added subsequently. gVmdirServerGlobals.serverId = 1; dwError = VmDirSrvSetupDomainInstance( pSchemaCtx, TRUE, TRUE, pszFQDomainName, pszDomainDN, pszUsername, pszPassword ); BAIL_ON_VMDIR_ERROR(dwError); // Create Deleted Objects container dwError = VmDirSrvCreateContainerWithEID( pSchemaCtx, pszDelObjsContainerDN, pszDelObjsContainerName, DEL_ENTRY_CONTAINER_ENTRY_ID ); BAIL_ON_VMDIR_ERROR(dwError); // Create Domain Controllers container dwError = VmDirSrvCreateOUContainer( pSchemaCtx, pszDCsContainerDN, pszDCsContainerName ); BAIL_ON_VMDIR_ERROR(dwError); // Create Computers container dwError = VmDirSrvCreateOUContainer( pSchemaCtx, pszComputersContainerDN, pszComputersContainerName ); BAIL_ON_VMDIR_ERROR(dwError); // Create Managed Service Accounts container dwError = VmDirSrvCreateContainer( pSchemaCtx, pszMSAsDN, pszMSAsContainerName ); BAIL_ON_VMDIR_ERROR(dwError); // Create Configuration container dwError = VmDirSrvCreateConfigContainer( pSchemaCtx, pszConfigContainerDN, pszConfigContainerName ); BAIL_ON_VMDIR_ERROR(dwError); // Create Certificate-Authorities container dwError = VmDirSrvCreateContainer( pSchemaCtx, pszCAContainerDN, pszCAContainerName ); BAIL_ON_VMDIR_ERROR(dwError); // Create Sites container dwError = VmDirSrvCreateContainer( pSchemaCtx, pszSitesContainerDN, pszSitesContainerName ); BAIL_ON_VMDIR_ERROR(dwError); /* // Create Site-Name container dwError = VmDirSrvCreateContainer( pSchemaCtx, pszSiteContainerDN, pszSiteContainerName ); BAIL_ON_VMDIR_ERROR(dwError); // Create Servers container dwError = VmDirSrvCreateContainer( pSchemaCtx, pszServersContainerDN, pszServersContainerName ); BAIL_ON_VMDIR_ERROR(dwError); */ // Create Site-Name container, Servers container, and THE Server object dwError = VmDirSrvCreateServerObj( pSchemaCtx ); BAIL_ON_VMDIR_ERROR(dwError); // Create Replication Agreements container dwError = VmDirSrvCreateReplAgrsContainer( pSchemaCtx ); BAIL_ON_VMDIR_ERROR(dwError); // 1st replica => no replication agreements => 1st replication cycle done VMDIR_LOCK_MUTEX(bInLockReplCycle, gVmdirGlobals.replCycleDoneMutex); VmDirConditionSignal(gVmdirGlobals.replCycleDoneCondition); VMDIR_UNLOCK_MUTEX(bInLockReplCycle, gVmdirGlobals.replCycleDoneMutex); } else { dwError = VmDirAllocateStringAVsnprintf( &pszReplAgrDN, "labeledURI=%s,%s", pszReplURI, pszReplAgrsContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirConstructReplAgr( pSchemaCtx, pszReplURI, VMDIR_DEFAULT_REPL_LAST_USN_PROCESSED, pszReplAgrDN, &pReplAgr ); BAIL_ON_VMDIR_ERROR(dwError); gFirstReplCycleMode = firstReplCycleMode; VMDIR_LOCK_MUTEX(bInLock, gVmdirGlobals.replAgrsMutex); pReplAgr->next = gVmdirReplAgrs; gVmdirReplAgrs = pReplAgr; // ownership transfer // wake up replication thread waiting on the existence // of a replication agreement. VmDirConditionSignal(gVmdirGlobals.replAgrsCondition); VMDIR_UNLOCK_MUTEX(bInLock, gVmdirGlobals.replAgrsMutex); } cleanup: if (pSchemaCtx) { VmDirSchemaCtxRelease(pSchemaCtx); } VMDIR_SAFE_FREE_MEMORY(pszDomainDN); VMDIR_SAFE_FREE_MEMORY(pszDelObjsContainerDN); VMDIR_SAFE_FREE_MEMORY(pszConfigContainerDN); VMDIR_SAFE_FREE_MEMORY(pszCAContainerDN); VMDIR_SAFE_FREE_MEMORY(pszSitesContainerDN); VMDIR_SAFE_FREE_MEMORY(pszSiteContainerDN); VMDIR_SAFE_FREE_MEMORY(pszServersContainerDN); VMDIR_SAFE_FREE_MEMORY(pszServerDN); VMDIR_SAFE_FREE_MEMORY(pszReplAgrsContainerDN); VMDIR_SAFE_FREE_MEMORY(pszReplAgrDN); VMDIR_SAFE_FREE_MEMORY(pszDCsContainerDN); VMDIR_SAFE_FREE_MEMORY(pszDCAccountDN); VMDIR_SAFE_FREE_MEMORY(pszDCAccountUPN); VMDIR_SAFE_FREE_MEMORY(pszComputersContainerDN); VMDIR_SAFE_FREE_MEMORY(pszComputerAccountDN); VMDIR_SAFE_FREE_MEMORY(pszMSAsDN); VMDIR_SAFE_FREE_MEMORY(pszUpperCaseFQDomainName); VMDIR_SAFE_FREE_MEMORY(pszUsersContainerDN); VMDIR_SAFE_FREE_MEMORY(pszUserDN); VMDIR_SAFE_FREE_MEMORY(pszDefaultAdminDN); VMDIR_SAFE_FREE_MEMORY(pszLowerCaseHostName); VmDirFreeBervalContent(&bv); return dwError; error: VmDirLog(LDAP_DEBUG_ANY, "VmDirSrvSetupHostInstance failed. Error(%u)", dwError); goto cleanup; }
/* * Main initialization loop. */ DWORD VmKdcInitLoop( PVMKDC_GLOBALS pGlobals) { DWORD dwError = 0; int sts = 0; time_t now = 0; struct timespec timeout = {0}; while (1) { switch (VmKdcdState()) { case VMKDCD_STARTUP: /* * Try to initialize the directory. */ VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "Vmkdc: initializing directory"); dwError = VmKdcInitializeDirectory(pGlobals); if ( VmKdcdState() == VMKDCD_STARTUP && dwError == 0 ) { VmKdcdStateSet(VMKDCD_RUNNING); continue; } /* * Initialization of the directory failed or stopping/shutdown noticed. * Wait for a while before retrying. */ pthread_mutex_lock(&pGlobals->mutex); now = time(NULL); timeout.tv_sec = now + VMKDC_DIRECTORY_POLL_SECS; timeout.tv_nsec = 0; sts = 0; while (pGlobals->vmkdcdState == VMKDCD_STARTUP && sts == 0) { sts = pthread_cond_timedwait(&pGlobals->stateCond, &pGlobals->mutex, &timeout); } pthread_mutex_unlock(&pGlobals->mutex); break; case VMKDCD_RUNNING: /* * Wait until the server state changes. */ pthread_mutex_lock(&pGlobals->mutex); while (pGlobals->vmkdcdState == VMKDCD_RUNNING) { pthread_cond_wait(&pGlobals->stateCond, &pGlobals->mutex); } pthread_mutex_unlock(&pGlobals->mutex); break; case VMKDC_STOPPING: /* * Notify VmKdcShutdown() STOPPING has been received. * It is now safe to tear down pGlobal mutex/condition * variable resources after this point. */ VmKdcdStateSet(VMKDC_SHUTDOWN); /* don't break here because we can't use the global mutex any more */ goto cleanup; case VMKDC_SHUTDOWN: goto cleanup; } } cleanup: return dwError; }
void VmDirSendLdapResult( VDIR_OPERATION * op ) { BerElementBuffer berbuf; BerElement * ber = (BerElement *) &berbuf; ber_int_t msgId = 0; ber_tag_t resCode = 0; size_t iNumSearchEntrySent = 0; PCSTR pszSocketInfo = NULL; (void) memset( (char *)&berbuf, '\0', sizeof( BerElementBuffer )); resCode = GetResultTag( op->reqCode ); msgId = (resCode != LBER_SEQUENCE) ? op->msgId : 0; if ( resCode == LDAP_RES_SEARCH_RESULT ) { iNumSearchEntrySent = op->request.searchReq.iNumEntrySent; } ber_init2( ber, NULL, LBER_USE_DER ); if (op->conn) { pszSocketInfo = op->conn->szClientIP; } if (op->ldapResult.errCode && op->ldapResult.errCode != LDAP_SASL_BIND_IN_PROGRESS) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirSendLdapResult: Request (%d), Error (%d), Message (%s), (%u) socket (%s)", op->reqCode, op->ldapResult.errCode, VDIR_SAFE_STRING(op->ldapResult.pszErrMsg), iNumSearchEntrySent, VDIR_SAFE_STRING(pszSocketInfo)); } else if ( op->reqCode == LDAP_REQ_SEARCH ) { VMDIR_LOG_INFO( LDAP_DEBUG_ARGS, "VmDirSendLdapResult: Request (%d), Error (%d), Message (%s), (%u) socket (%s)", op->reqCode, op->ldapResult.errCode, VDIR_SAFE_STRING(op->ldapResult.pszErrMsg), iNumSearchEntrySent, VDIR_SAFE_STRING(pszSocketInfo)); } if (ber_printf( ber, "{it{essN}", msgId, resCode, op->ldapResult.errCode, "", VDIR_SAFE_STRING(op->ldapResult.pszErrMsg)) == -1) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendLdapResult: ber_printf (to print msgId ...) failed" ); goto done; } // If Search, Replication, and one or more entries were sent back => Send back Sync Done Control if ( op->reqCode == LDAP_REQ_SEARCH && op->syncReqCtrl != NULL && op->syncDoneCtrl != NULL) { if (WriteSyncDoneControl( op, ber ) != LDAP_SUCCESS) { goto done; } } if ( op->reqCode == LDAP_REQ_SEARCH && op->showPagedResultsCtrl != NULL) { if (WritePagedSearchDoneControl( op, ber ) != LDAP_SUCCESS) { goto done; } } if (ber_printf( ber, "N}" ) == -1) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendLdapResult: ber_printf (to print msgId ...) failed" ); goto done; } if (WriteBerOnSocket( op->conn, ber ) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendLdapResult: WriteBerOnSocket failed" ); goto done; } done: ber_free_buf( ber ); }
/* * Create a new schema cache via pEntry, then active this cache. */ DWORD VmDirSchemaInitializeViaEntry( PVDIR_ENTRY pEntry ) { BOOLEAN bLoadOk = TRUE; BOOLEAN bInLock = FALSE; DWORD dwError = 0; PVDIR_SCHEMA_CTX pLiveCtx = NULL; PVDIR_SCHEMA_INSTANCE pInstance = NULL; PVDIR_SCHEMA_INSTANCE pLiveInstance = NULL; VMDIR_LOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); // get reference to current schema, to clean up later pLiveInstance = gVdirSchemaGlobals.pSchema; pLiveCtx = gVdirSchemaGlobals.pCtx; // instantiate a schema cache - pInstance dwError = VdirSchemaInstanceInitViaEntry( pEntry, &pInstance); BAIL_ON_VMDIR_ERROR(dwError); gVdirSchemaGlobals.pSchema = pInstance; dwError = VdirSchemaCtxAcquireInLock(TRUE, &gVdirSchemaGlobals.pCtx); // add self reference BAIL_ON_VMDIR_ERROR(dwError); assert(gVdirSchemaGlobals.pCtx); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Startup schema instance (%p)", gVdirSchemaGlobals.pSchema); VMDIR_UNLOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); cleanup: if (bLoadOk) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "Schema - AttributeTypes:(size=%d, nextid=%d) Objectclasses:(size=%d)", pEntry->pSchemaCtx->pSchema->ats.usNumATs, pEntry->pSchemaCtx->pSchema->ats.usNextId, pEntry->pSchemaCtx->pSchema->ocs.usNumOCs); } VMDIR_UNLOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); if (pLiveCtx) { VmDirSchemaCtxRelease(pLiveCtx); } return dwError; error: if (pInstance) { VdirSchemaInstanceFree(pInstance); } gVdirSchemaGlobals.pSchema = pLiveInstance; gVdirSchemaGlobals.pCtx = pLiveCtx; pLiveCtx = NULL; bLoadOk = FALSE; goto cleanup; }
int VmDirSendSearchEntry( PVDIR_OPERATION pOperation, PVDIR_ENTRY pSrEntry ) { int retVal = LDAP_SUCCESS; BerElementBuffer berbuf; BerElement * ber = (BerElement *) &berbuf; BOOLEAN bFreeBer = FALSE; ber_len_t iBlobSize = 0; BerValue lberBervEntryBlob = {0}; int nAttrs = 0; int nVals = 0; BOOLEAN attrMetaDataReqd = FALSE; SearchReq * sr = &(pOperation->request.searchReq); int i = 0; BOOLEAN nonTrivialAttrsInReplScope = FALSE; uint32_t iSearchReqSpecialChars = 0; PATTRIBUTE_META_DATA_NODE pAttrMetaData = NULL; int numAttrMetaData = 0; PVDIR_ATTRIBUTE pAttr = NULL; USN usnChanged = 0; PSTR pszLocalErrorMsg = NULL; if ( !pOperation || !pSrEntry ) { retVal = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(retVal); } pSrEntry->bSearchEntrySent = FALSE; // see if client request has "*" and/or "+" ("-" for userpassword internal to vmdir) // WEI TODO: when we have attribute level ACL check, this information will be useful // return result will depend on ACL each on each attribute client is asking before // generating a final result to send back SetSpecialReturnChar(&pOperation->request.searchReq, &iSearchReqSpecialChars); if ( pSrEntry->eId == DSE_ROOT_ENTRY_ID && pOperation->request.searchReq.attrs == NULL ) { // For ADSI, if no specific attributes requested of DSE ROOT search, // return ALL (include operational) attributes. iSearchReqSpecialChars |= LDAP_SEARCH_REQUEST_CHAR_OP; } // ACL check before processing/sending the current srEntry back retVal = VmDirSrvAccessCheck( pOperation, &pOperation->conn->AccessInfo, pSrEntry, VMDIR_RIGHT_DS_READ_PROP ); BAIL_ON_VMDIR_ERROR( retVal ); if ( pOperation->opType == VDIR_OPERATION_TYPE_INTERNAL ) { ; // no op in INTERNAL case } else { // If not replication, and showDeletedObjectsCtrl not present, => don't send back Deleted objects (tombstones). if (pOperation->syncReqCtrl == NULL && pOperation->showDeletedObjectsCtrl == NULL) { pAttr = VmDirEntryFindAttribute(ATTR_IS_DELETED, pSrEntry); if (pAttr) { if (VmDirStringCompareA((PSTR)pAttr->vals[0].lberbv.bv_val, VMDIR_IS_DELETED_TRUE_STR, FALSE) == 0) { goto cleanup; // Don't send this entry } } } // In case of replication request, skip certain updates if (pOperation->syncReqCtrl != NULL) { PVDIR_ATTRIBUTE pAttrUsnCreated = NULL; USN usnCreated = 0; USN limitUsn = 0; VMDIR_REPLICATION_AGREEMENT * replAgr = NULL; pAttr = VmDirEntryFindAttribute(ATTR_USN_CHANGED, pSrEntry); assert( pAttr != NULL ); usnChanged = VmDirStringToLA( pAttr->vals[0].lberbv.bv_val, NULL, 10); // Check if usnChanged is beyond successful replication update state limitUsn = VmDirdGetLimitLocalUsnToBeSupplied(); if (limitUsn != 0 && usnChanged >= limitUsn) { VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "SendSearchEntry: bug# 863244 RACE CONDITION encountered., " "usnChanged = %ld, limitLocalUsnToBeSupplied = %ld, skipping entry: %s", usnChanged, limitUsn, pSrEntry->dn.lberbv.bv_val ); goto cleanup; // Don't send this entry } // Check if usnChanged is beyond lowestPendingUncommittedUsn recorded at the beginning of replication search if (pOperation->lowestPendingUncommittedUsn != 0 && usnChanged >= pOperation->lowestPendingUncommittedUsn) { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: usnChanged = %ld, lowestPendingUncommittedUsn = %ld, " "skipping entry: %s", usnChanged, pOperation->lowestPendingUncommittedUsn, pSrEntry->dn.lberbv.bv_val ); goto cleanup; // Don't send this entry } // Don't send (skip) modifications to my server object, and my RAs pAttrUsnCreated = VmDirEntryFindAttribute(ATTR_USN_CREATED, pSrEntry); assert( pAttrUsnCreated != NULL ); usnCreated = VmDirStringToLA( pAttrUsnCreated->vals[0].lberbv.bv_val, NULL, 10); // Only send back creation of certain objects, and not their modifications. // Check if consumer has already seen the creation. If yes, we are dealing with mods, which should be skipped // for my server object, and my RAs // Note: Skipping mods for RAs and Server Objects will cause inconsistencies with replicas. But these // two types only have local scope regarding functional effects. But if we are looking up / processing // information for these two types of objects on a replica, we need to watch out for potential // inconsistencies against the original source. if (pOperation->syncReqCtrl->value.syncReqCtrlVal.intLastLocalUsnProcessed > usnCreated) { if (strcmp(pSrEntry->dn.bvnorm_val, gVmdirServerGlobals.serverObjDN.bvnorm_val) == 0) { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: Not sending modifications to my server object, DN: %s", gVmdirServerGlobals.serverObjDN.lberbv.bv_val ); goto cleanup; // Don't send this entry } for (replAgr = gVmdirReplAgrs; replAgr != NULL; replAgr = replAgr->next ) { if (strcmp(pSrEntry->dn.bvnorm_val, replAgr->dn.bvnorm_val) == 0) { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: Not sending modifications to my RA object, DN: %s", replAgr->dn.bvnorm_val ); goto cleanup; // Don't send this entry } } } // do not replicate DSE Root entry, because it is a "local" entry. if (pSrEntry->eId == DSE_ROOT_ENTRY_ID) { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: Not sending modifications to DSE Root entry, DN: %s", pSrEntry->dn.bvnorm_val ); goto cleanup; // Don't send this entry } } // Approximate calculation for the required ber size, because apart from lengths and strings, ber also includes // tags. if ( VmDirComputeEncodedEntrySize(pSrEntry, &nAttrs, &nVals, &iBlobSize) != 0 || VmDirAllocateMemory(iBlobSize, (PVOID*)&lberBervEntryBlob.bv_val) != 0 ) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "no memory"); } lberBervEntryBlob.bv_len = iBlobSize; ber_init2( ber, &lberBervEntryBlob, LBER_USE_DER ); // ber takes over lberBervEntryBlob.lberbv.bv_val ownership bFreeBer = TRUE; if ( ber_printf( ber, "{it{O{", pOperation->msgId, LDAP_RES_SEARCH_ENTRY, &pSrEntry->dn ) == -1) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendSearchEntry: ber_printf (to print msgId ...) failed" ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding msgId, RES_SEARCH_ENTRY, DN failed"); } // Determine if we need to send back the attribute metaData if ( pOperation->syncReqCtrl != NULL ) // Replication { attrMetaDataReqd = TRUE; } else // check if attrMetaData attribute has been requested explicitly. { if (sr->attrs != NULL) { for (i = 0; sr->attrs[i].lberbv.bv_val != NULL; i++) { if (VmDirStringCompareA( sr->attrs[i].lberbv.bv_val, ATTR_ATTR_META_DATA, FALSE) == 0) { attrMetaDataReqd = TRUE; break; } } } } if (attrMetaDataReqd) { if ((pOperation->pBEIF->pfnBEGetAllAttrsMetaData( pOperation->pBECtx, pSrEntry->eId, &pAttrMetaData, &numAttrMetaData )) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendSearchEntry: pfnBEGetAllAttrsMetaData failed for entryId: %ld", pSrEntry->eId); retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "pfnBEGetAllAttrsMetaData failed."); } // SJ-TBD: Following double for loop to be optimized // Copy attrMetaData to corresponding attributes for (i=0; i<numAttrMetaData; i++) { for ( pAttr = pSrEntry->attrs; pAttr != NULL; pAttr = pAttr->next) { if (pAttr->pATDesc->usAttrID == pAttrMetaData[i].attrID) { VmDirStringCpyA( pAttr->metaData, VMDIR_MAX_ATTR_META_DATA_LEN, pAttrMetaData[i].metaData ); pAttrMetaData[i].metaData[0] = '\0'; } } } } retVal = WriteAttributes( pOperation, pSrEntry, iSearchReqSpecialChars , ber, &pszLocalErrorMsg ); BAIL_ON_VMDIR_ERROR( retVal ); if (attrMetaDataReqd) { retVal = WriteMetaDataAttribute( pOperation, pSrEntry->attrs, numAttrMetaData, pAttrMetaData, ber, &nonTrivialAttrsInReplScope, &pszLocalErrorMsg ); BAIL_ON_VMDIR_ERROR( retVal ); } if (ber_printf( ber, "N}N}" ) == -1) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ber_printf (to terminate the entry and the complete search result entry message ...) failed" ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding terminating the entry failed."); } if ( pOperation->syncReqCtrl != NULL ) // Replication, => write Sync State Control { retVal = WriteSyncStateControl( pOperation, pSrEntry->attrs, ber, &pszLocalErrorMsg ); BAIL_ON_VMDIR_ERROR( retVal ); } if (ber_printf( ber, "N}" ) == -1) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ber_printf (to terminate the entry and the complete search result entry message ...) failed" );; retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding terminating the entry failed."); } if ((pOperation->syncReqCtrl == NULL) || (pOperation->syncReqCtrl != NULL && nonTrivialAttrsInReplScope )) { if (WriteBerOnSocket( pOperation->conn, ber ) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendSearchEntry: WriteBerOnSocket failed." ); retVal = LDAP_UNAVAILABLE; BAIL_ON_VMDIR_ERROR( retVal ); } pSrEntry->bSearchEntrySent = TRUE; sr->iNumEntrySent++; VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: Send entry: %s", pSrEntry->dn.lberbv.bv_val); } else { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: NOT Sending entry: %s %p %d", pSrEntry->dn.lberbv.bv_val, pOperation->syncReqCtrl, nonTrivialAttrsInReplScope); } // record max local usnChanged in syncControlDone if (pOperation->syncReqCtrl != NULL) { if (usnChanged > pOperation->syncDoneCtrl->value.syncDoneCtrlVal.intLastLocalUsnProcessed) { pOperation->syncDoneCtrl->value.syncDoneCtrlVal.intLastLocalUsnProcessed = usnChanged; } } retVal = LDAP_SUCCESS; } cleanup: if (bFreeBer) { ber_free_buf( ber ); } VMDIR_SAFE_FREE_MEMORY( pAttrMetaData ); VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return( retVal ); error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendSearchEntry failed DN=(%s), (%u)(%s)", (pSrEntry && pSrEntry->dn.lberbv.bv_val) ? pSrEntry->dn.lberbv.bv_val : "", retVal, VDIR_SAFE_STRING( pszLocalErrorMsg)); if ( !pOperation->ldapResult.pszErrMsg && pszLocalErrorMsg ) { pOperation->ldapResult.pszErrMsg = pszLocalErrorMsg; pszLocalErrorMsg = NULL; } goto cleanup; }
/* * Before modify schema cache, make sure new schema is valid. * 1. schema of pEntry must be live one * 2. create new schema instance via pEntry * 3. check active and new schema compatibility * NOT compatible - reject this operation * Compatible but NO semantic chnage - update schema entry * Compatible and has semantic chnage - update schema entry and cache * 4. make new instance pending in gVdirSchemaGlobals */ DWORD VmDirSchemaCacheModifyPrepare( PVDIR_OPERATION pOperation, VDIR_MODIFICATION* pMods, PVDIR_ENTRY pSchemaEntry ) { DWORD dwError = 0; BOOLEAN bInLock = FALSE; PSTR pszLocalErrMsg = NULL; BOOLEAN bOwnNewInstance = FALSE; BOOLEAN bCompatible = FALSE; // schema compatible BOOLEAN bNeedCachePatch = FALSE; // schema semantic/cache change PVDIR_SCHEMA_INSTANCE pNewInstance = NULL; // DO NOT free, pEntry should take over it. PVDIR_SCHEMA_INSTANCE pEntryOrgSchemaInstance = NULL; if ( !pMods || !pSchemaEntry || !pOperation ) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } { PVDIR_MODIFICATION pLocalMods = NULL; PCSTR immutableList[] = VDIR_IMMUTABLE_SCHEMA_ELEMENT_INITIALIZER; int iImmutableSize = sizeof(immutableList)/sizeof(immutableList[0]); for (pLocalMods = pMods; pLocalMods; pLocalMods = pLocalMods->next) { BOOLEAN bImmutableElement = _VmDirIsNameInCaseIgnoreList( pLocalMods->attr.pATDesc->pszName, immutableList, iImmutableSize); if ( bImmutableElement ) { dwError = ERROR_OPERATION_NOT_PERMITTED; BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "modify (%s) not allowed", pLocalMods->attr.pATDesc->pszName); } } } // make sure pEntry uses live schema if (! vdirIsLiveSchema(pSchemaEntry->pSchemaCtx->pSchema)) { dwError = LDAP_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "Out dated schema"); } pEntryOrgSchemaInstance = pSchemaEntry->pSchemaCtx->pSchema; // instantiate a schema cache - pNewInstance // If this call succeed, do NOT free pNewInstance. pEntry->pSchemaCtx takes it over. dwError = VdirSchemaInstanceInitViaEntry( pSchemaEntry, &pNewInstance); if ( dwError != 0 && pSchemaEntry->pSchemaCtx->pSchema != pNewInstance ) { // we still own pNewInstance and need to free it. bOwnNewInstance = TRUE; } BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "Entry to schema instance failed (%d)", dwError); // check if two instances are compatible and if schema patching is needed dwError = VmDirSchemaInstancePatchCheck( pEntryOrgSchemaInstance, pNewInstance, &bCompatible, &bNeedCachePatch); BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "VmDirSchemaInstancePatch (%d)", dwError); if ( !bCompatible ) { dwError = LDAP_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "Schema NOT compatible (%d)", dwError); } if ( !bNeedCachePatch ) { // no semantic change, just update schema entry VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Prepare schema entry update"); } else { // need schema entry and cache update VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Prepare schema entry and instance update (%p)", pNewInstance); } VMDIR_LOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); if ( bNeedCachePatch ) { gVdirSchemaGlobals.bHasPendingChange = TRUE; } VMDIR_UNLOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); cleanup: VMDIR_UNLOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return dwError; error: if ( bOwnNewInstance ) { VdirSchemaInstanceFree( pNewInstance ); } VMDIR_SET_LDAP_RESULT_ERROR( &pOperation->ldapResult, dwError, pszLocalErrMsg ); goto cleanup; }
static int IsAttrInReplScope( VDIR_OPERATION * op, char * attrType, char * attrMetaData, BOOLEAN * inScope, PSTR* ppszErrorMsg ) { int retVal = LDAP_SUCCESS; PLW_HASHTABLE_NODE pNode = NULL; char origInvocationId[VMDIR_GUID_STR_LEN]; USN origUsn = VmDirStringToLA( VmDirStringRChrA( attrMetaData, ':' ) + 1, NULL, 10 ); int rc = 0; PSTR pszLocalErrorMsg = NULL; *inScope = FALSE; // attrMetaData format is: <local USN>:<version no>:<originating server ID>:<originating time>:<originating USN> VmDirStringNCpyA( origInvocationId, VMDIR_GUID_STR_LEN, VmDirStringChrA( VmDirStringChrA( attrMetaData, ':' ) + 1, ':') + 1, VMDIR_GUID_STR_LEN - 1); origInvocationId[VMDIR_GUID_STR_LEN - 1] = '\0'; // Skip the attribute: // - if the originating server for the current state is same as the requesting server or if it is one of those // attributes that have "local" scope only. E.g. sending ATTR_LAST_LOCAL_USN_PROCESSED and // ATTR_UP_TO_DATE_VECTOR, causes continuous back-forth replication of Replication Agreements and Server // entries between various servers. assert( op->syncReqCtrl != NULL ); if ((attrType != NULL && (VmDirStringCompareA( attrType, ATTR_LAST_LOCAL_USN_PROCESSED, FALSE) == 0 || VmDirStringCompareA( attrType, ATTR_UP_TO_DATE_VECTOR, FALSE) == 0 || VmDirStringCompareA( attrType, VDIR_ATTRIBUTE_SEQUENCE_RID, FALSE) == 0))) { // Reset metaData value so that we don't send local only attribute back. attrMetaData[0] = '\0'; *inScope = FALSE; goto cleanup; } else if ( attrType != NULL && (VmDirStringCompareA( attrType, ATTR_USN_CHANGED, FALSE) == 0)) { ; // always send uSNChanged. (PR 1573117) } else if (VmDirStringCompareA( origInvocationId, op->syncReqCtrl->value.syncReqCtrlVal.reqInvocationId.lberbv.bv_val,TRUE ) == 0) { // Change is originated from the requesting server. // Reset metaData value so that we don't send metaData as well as this attribute back. attrMetaData[0] = '\0'; *inScope = FALSE; goto cleanup; } else { rc = LwRtlHashTableFindKey( op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector, &pNode, origInvocationId ); rc = LwNtStatusToWin32Error(rc); if (rc != 0 && rc != ERROR_NOT_FOUND) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "IsAttrInReplScope: LwRtlHashTableFindKey failed for origInvocationId: %s", origInvocationId ); retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "LwRtlHashTableFindKey failed."); } if (pNode == NULL) // Attribute is to be sent in the result entry. { UptoDateVectorEntry * utdVectorEntry = NULL; VDIR_BERVALUE bvServerId = VDIR_BERVALUE_INIT; if (VmDirAllocateMemory( sizeof( UptoDateVectorEntry ), (PVOID *)&utdVectorEntry) != 0) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "IsAttrInReplScope: BervalContentDup failed."); } bvServerId.lberbv.bv_val = origInvocationId; bvServerId.lberbv.bv_len = VmDirStringLenA( origInvocationId ); if (VmDirBervalContentDup( &bvServerId, &utdVectorEntry->invocationId ) != 0) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "IsAttrInReplScope: BervalContentDup failed."); } utdVectorEntry->currMaxOrigUsnProcessed = origUsn; LwRtlHashTableResizeAndInsert( op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector, &utdVectorEntry->Node, &pNode); assert( pNode == NULL ); // assert the key of added node is unique } else { UptoDateVectorEntry * utdVectorEntry = NULL; utdVectorEntry = (UptoDateVectorEntry *)LW_STRUCT_FROM_FIELD(pNode, UptoDateVectorEntry, Node); if (origUsn > utdVectorEntry->reqLastOrigUsnProcessed ) { // Attribute is to be sent in the result entry. // Update if origUsn of this attribute is > the current highest if (origUsn > utdVectorEntry->currMaxOrigUsnProcessed ) { utdVectorEntry->currMaxOrigUsnProcessed = origUsn; } } else { VMDIR_LOG_VERBOSE( LDAP_DEBUG_REPL_ATTR, "IsAttrInReplScope: Attribute: %s, metaData: %s, replication scope = FALSE", attrType, attrMetaData ); // Reset metaData value so that we don't send metaData for this attribute back. attrMetaData[0] = '\0'; *inScope = FALSE; goto cleanup; } } } VMDIR_LOG_INFO( LDAP_DEBUG_REPL_ATTR, "IsAttrInReplScope: Attribute: %s, metaData: %s, replication scope = TRUE", attrType, attrMetaData ); *inScope = TRUE; cleanup: if (ppszErrorMsg) { *ppszErrorMsg = pszLocalErrorMsg; } else { VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); } return( retVal ); error: goto cleanup; }