// WbemProv.cpp : Implementation of CAdreplpvApp and DLL registration. #include "stdafx.h" #include "dbg.cpp" //#include "adreplpv.h" #include "Wbem.h" #include #include #include #define INITGUID #include DEFINE_GUID(CLSID_ADReplProvider,0x96FA95C4,0x0AF3,0x4EF9,0xA1,0xEB,0xC8,0x15,0x13,0x22,0x15,0x7B); ///////////////////////////////////////////////////////////////////////////// // // CODEWORK should only have one definition of classname and GUID #define CLASSNAME_STRING_STATUS L"Microsoft_ADReplStatus" #define CLASSNAME_STRING_DC L"Microsoft_ADReplDomainController" CProvider::CProvider() { } CProvider::~CProvider() { } // IWbemProviderInit STDMETHODIMP CProvider::Initialize( IN LPWSTR pszUser, IN LONG lFlags, IN LPWSTR pszNamespace, IN LPWSTR pszLocale, IN IWbemServices *pNamespace, IN IWbemContext *pCtx, IN IWbemProviderInitSink *pInitSink ) { WBEM_VALIDATE_INTF_PTR( pNamespace ); WBEM_VALIDATE_INTF_PTR( pCtx ); WBEM_VALIDATE_INTF_PTR( pInitSink ); HRESULT hr = WBEM_S_NO_ERROR; do { m_sipNamespace = pNamespace; CComBSTR sbstrObjectName = CLASSNAME_STRING_STATUS; // is this necessary? hr = m_sipNamespace->GetObject( sbstrObjectName, WBEM_FLAG_RETURN_WBEM_COMPLETE, pCtx, &m_sipClassDefStatus, NULL ); BREAK_ON_FAIL; sbstrObjectName = CLASSNAME_STRING_DC; hr = m_sipNamespace->GetObject( sbstrObjectName, WBEM_FLAG_RETURN_WBEM_COMPLETE, pCtx, &m_sipClassDefDC, NULL ); BREAK_ON_FAIL; // Let CIMOM know you are initialized // return value and SetStatus param should be consistent, so ignore // the return value from SetStatus itself (in retail builds) HRESULT hr2 = pInitSink->SetStatus( WBEM_S_INITIALIZED, 0 ); ASSERT( !FAILED(hr2) ); } while (false); return hr; } // IWbemServices // BUGBUG should this ever indicate more than one? STDMETHODIMP CProvider::GetObjectAsync( IN const BSTR bstrObjectPath, IN long lFlags, IN IWbemContext *pCtx, IN IWbemObjectSink *pResponseHandler) { WBEM_VALIDATE_IN_STRING_PTR( bstrObjectPath ); // CODEWORK check lFlags? WBEM_VALIDATE_INTF_PTR( pCtx ); WBEM_VALIDATE_INTF_PTR( pResponseHandler ); static LPCWSTR ROOTSTR_STATUS = L"Microsoft_ADReplStatus.CompositeName=\""; static LPCWSTR ROOTSTR_DC = L"Microsoft_ADReplDomainController.SiteName=\""; int rootlen = lstrlen(ROOTSTR_STATUS); if ( lstrlen(bstrObjectPath) > rootlen && 0 == _tcsnicmp(bstrObjectPath, ROOTSTR_STATUS, rootlen) ) { // remove prefix CComBSTR sbstrFilterValue = (BSTR)bstrObjectPath + rootlen; // remove trailing doublequote sbstrFilterValue[lstrlen(sbstrFilterValue)-1] = L'\0'; return _EnumAndIndicateStatus( CLASS_STATUS, pCtx, pResponseHandler, sbstrFilterValue ); } rootlen = lstrlen(ROOTSTR_DC); if ( lstrlen(bstrObjectPath) > rootlen && 0 == _tcsnicmp(bstrObjectPath, ROOTSTR_DC, rootlen) ) { // remove prefix CComBSTR sbstrFilterValue = (BSTR)bstrObjectPath + rootlen; // remove trailing doublequote sbstrFilterValue[lstrlen(sbstrFilterValue)-1] = L'\0'; return _EnumAndIndicateDC( pCtx, pResponseHandler, sbstrFilterValue ); } ASSERT(false); return WBEM_E_INVALID_OBJECT_PATH; } STDMETHODIMP CProvider::CreateInstanceEnumAsync( IN const BSTR bstrClass, IN long lFlags, IN IWbemContext *pCtx, IN IWbemObjectSink *pResponseHandler) { WBEM_VALIDATE_IN_STRING_PTR( bstrClass ); // CODEWORK check lFlags? WBEM_VALIDATE_INTF_PTR( pCtx ); WBEM_VALIDATE_INTF_PTR( pResponseHandler ); if ( 0 == lstrcmp( bstrClass, CLASSNAME_STRING_STATUS ) ) return _EnumAndIndicateStatus( CLASS_STATUS, pCtx, pResponseHandler ); else if ( 0 == lstrcmp( bstrClass, CLASSNAME_STRING_DC ) ) return _EnumAndIndicateDC( pCtx, pResponseHandler ); return WBEM_E_INVALID_OBJECT_PATH; } HRESULT CProvider::_EnumAndIndicateStatus( IN ProviderClass provclass, // BUGBUG don't need this parameter IN IWbemContext *pCtx, IN IWbemObjectSink *pResponseHandler, IN const BSTR bstrFilterValue ) { HRESULT hr = WBEM_S_NO_ERROR; DSROLE_PRIMARY_DOMAIN_INFO_BASIC* pdomaininfo = NULL; HANDLE hDS = NULL; bool fImpersonating = false; do { hr = CoImpersonateClient(); BREAK_ON_FAIL; fImpersonating = true; // Check whether this is a DC hr = HRESULT_FROM_WIN32(DsRoleGetPrimaryDomainInformation( NULL, // lpServer = local machine DsRolePrimaryDomainInfoBasic, // InfoLevel (PBYTE*)&pdomaininfo // pBuffer )); BREAK_ON_FAIL; ASSERT( NULL != pdomaininfo ); bool fIsDC = true; switch (pdomaininfo->MachineRole) { case DsRole_RoleBackupDomainController: case DsRole_RolePrimaryDomainController: break; default: fIsDC = false; break; } if ( !fIsDC ) { // this is not a DC, return no connections break; } TCHAR achComputerName[MAX_PATH]; DWORD dwSize = sizeof(achComputerName)/sizeof(TCHAR); if ( !GetComputerNameEx( ComputerNameDnsFullyQualified, achComputerName, &dwSize )) { hr = HRESULT_FROM_WIN32(::GetLastError()); } BREAK_ON_FAIL; hr = HRESULT_FROM_WIN32(DsBind( achComputerName, // DomainControllerName NULL, // DnsDomainName &hDS // phDS )); // RPC_S_UUID_NO_ADDRESS means this is not a DC BREAK_ON_FAIL; ASSERT( NULL != hDS ); switch (provclass) { case CLASS_DC: ASSERT(false); break; case CLASS_STATUS: hr = _EnumAndIndicateWorker( provclass, hDS, pCtx, pResponseHandler, bstrFilterValue ); break; default: ASSERT(false); } } while (false); if (fImpersonating) { // CODEWORK do we want to keep impersonating and reverting? HRESULT hr2 = CoRevertToSelf(); ASSERT( !FAILED(hr2) ); } if (NULL != hDS) { (void) DsUnBind( &hDS ); } if (NULL != pdomaininfo) { DsRoleFreeMemory( pdomaininfo ); } return hr; } /* HRESULT CProvider::_EnumAndIndicateDCWorker( IN HANDLE hDS, IN IWbemContext *pCtx, IN IWbemObjectSink *pResponseHandler, IN const BSTR bstrFilterValue ) { HRESULT hr = WBEM_S_NO_ERROR; DS_DOMAIN_TRUSTS* ptrusts = NULL; ULONG ctrusts = 0; do { hr = HRESULT_FROM_WIN32(DsEnumerateDomainTrustsW( NULL, // ServerName DS_DOMAIN_IN_FOREST, // Flags, &ptrusts, // Domains, &ctrusts // DomainCount )); BREAK_ON_FAIL; if (0 == ctrusts) break; if ( BAD_IN_MULTISTRUCT_PTR(ptrusts,ctrusts) ) { ASSERT(false); break; } for (ULONG i = 0; i < ctrusts; i++) { if ( BAD_IN_STRING_PTR(ptrusts[i].DnsDomainName) ) { // skip this one break; } hr = _EnumAndIndicateWorker( CLASS_DC, hDS, pCtx, pResponseHandler, bstrFilterValue, ptrusts[i].DnsDomainName ); BREAK_ON_FAIL; } } while (false); if ( NULL != ptrusts ) { (void) NetApiBufferFree( ptrusts ); } return hr; } */ HRESULT CProvider::_EnumAndIndicateWorker( IN ProviderClass provclass, // BUGBUG parameter not needed IN HANDLE hDS, IN IWbemContext *pCtx, IN IWbemObjectSink *pResponseHandler, IN const BSTR bstrFilterValue, IN const BSTR bstrDnsDomainName ) { WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL(bstrFilterValue); WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL(bstrDnsDomainName); HRESULT hr = WBEM_S_NO_ERROR; DS_REPL_NEIGHBORS* pneighborsstruct = NULL; DS_DOMAIN_CONTROLLER_INFO_1 * pDCs = NULL; // BUGBUG not needed ULONG cDCs = 0; DWORD cIndicateItems = 0; IWbemClassObject** paIndicateItems = NULL; do { switch (provclass) { case CLASS_STATUS: hr = _BuildListStatus( hDS, &pneighborsstruct ); break; /* case CLASS_DC: hr = _BuildListDC( hDS, bstrDnsDomainName, &pDCs, &cDCs ); break; */ default: ASSERT(false); break; } BREAK_ON_FAIL; switch (provclass) { case CLASS_STATUS: hr = _BuildIndicateArrayStatus( pneighborsstruct, bstrFilterValue, &paIndicateItems, &cIndicateItems ); break; /* case CLASS_DC: hr = _BuildIndicateArrayDC( pDCs, cDCs, bstrFilterValue, &paIndicateItems, &cIndicateItems ); break; */ default: ASSERT(false); break; } // // Send the objects to the caller // // [In] param, no need to addref. if (cIndicateItems > 0) { hr = pResponseHandler->Indicate( cIndicateItems, paIndicateItems ); BREAK_ON_FAIL; } // Let CIMOM know you are finished // return value and SetStatus param should be consistent, so ignore // the return value from SetStatus itself (in retail builds) HRESULT hr2 = pResponseHandler->SetStatus( WBEM_STATUS_COMPLETE, hr, NULL, NULL ); ASSERT( !FAILED(hr2) ); } while (false); _ReleaseIndicateArray( paIndicateItems, cIndicateItems ); if ( NULL != pneighborsstruct ) { (void) DsReplicaFreeInfo( DS_REPL_INFO_NEIGHBORS, pneighborsstruct ); } if ( NULL != pDCs ) { (void) NetApiBufferFree( pDCs ); } return hr; } /* // does not validate resultant structs coming from API HRESULT CProvider::_BuildConnectionList( IN ProviderClass provclass, OUT void** ppitems ) { WBEM_VALIDATE_OUT_PTRPTR( ppitems ); HRESULT hr = WBEM_S_NO_ERROR; bool fImpersonating = false; do { hr = CoImpersonateClient(); BREAK_ON_FAIL; fImpersonating = true; switch (provclass) { case CLASS_STATUS: hr = _BuildListStatus( ppitems ); break; case CLASS_DC: hr = _BuildListDC( ppitems ); break; default: ASSERT(false); break; } } while (false); if (fImpersonating) { HRESULT hr2 = CoRevertToSelf(); ASSERT( !FAILED(hr2) ); } return hr; } */ // does not validate resultant structs coming from API HRESULT CProvider::_BuildListStatus( IN HANDLE hDS, OUT DS_REPL_NEIGHBORS** ppneighborsstruct ) { WBEM_VALIDATE_OUT_STRUCT_PTR(ppneighborsstruct); HRESULT hr = WBEM_S_NO_ERROR; do { hr = HRESULT_FROM_WIN32(DsReplicaGetInfo( hDS, // hDS DS_REPL_INFO_NEIGHBORS, // InfoType NULL, // pszObject NULL, // puuidForSourceDsaObjGuid, (void**)ppneighborsstruct // ppinfo )); BREAK_ON_FAIL; if ( BAD_IN_STRUCT_PTR(*ppneighborsstruct) ) { ASSERT(false); break; } } while (false); return hr; } HRESULT CProvider::_EnumAndIndicateDC( IN IWbemContext *pCtx, IN IWbemObjectSink *pResponseHandler, IN const BSTR bstrFilterValue ) { WBEM_VALIDATE_INTF_PTR( pCtx ); WBEM_VALIDATE_INTF_PTR( pResponseHandler ); WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL( bstrFilterValue ); HRESULT hr = WBEM_S_NO_ERROR; CComPtr spIADsRootDSE; CComVariant svarSchema; CComPtr spIADsPathname; CComPtr spIADsSearch; CComPtr spPathCracker; do { // // Enumerate all nTDSDSA objects // hr = ADsOpenObject( L"LDAP://RootDSE", NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IADs, OUT (void **)&spIADsRootDSE); BREAK_ON_FAIL; hr = spIADsRootDSE->Get(L"configurationNamingContext", &svarSchema); BREAK_ON_FAIL; ASSERT( VT_BSTR == svarSchema.vt ); hr = spIADsPathname.CoCreateInstance( CLSID_Pathname ); BREAK_ON_FAIL; ASSERT( !!spIADsPathname ); CComBSTR sbstr = L"LDAP://CN=Sites,"; sbstr += svarSchema.bstrVal; hr = ADsOpenObject( sbstr, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (void **)&spIADsSearch); BREAK_ON_FAIL; ADS_SEARCHPREF_INFO aSearchPref[4]; aSearchPref[0].dwSearchPref = ADS_SEARCHPREF_CHASE_REFERRALS; aSearchPref[0].vValue.dwType = ADSTYPE_INTEGER; aSearchPref[0].vValue.Integer = ADS_CHASE_REFERRALS_EXTERNAL; aSearchPref[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; aSearchPref[1].vValue.dwType = ADSTYPE_INTEGER; aSearchPref[1].vValue.Integer = 50; aSearchPref[2].dwSearchPref = ADS_SEARCHPREF_CACHE_RESULTS; aSearchPref[2].vValue.dwType = ADSTYPE_BOOLEAN; aSearchPref[2].vValue.Integer = FALSE; aSearchPref[3].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; aSearchPref[3].vValue.dwType = ADSTYPE_INTEGER; aSearchPref[3].vValue.Integer = ADS_SCOPE_SUBTREE; hr = spIADsSearch->SetSearchPreference (aSearchPref, 4); BREAK_ON_FAIL; CComBSTR sbstr1 = L"objectGUID"; CComBSTR sbstr2 = L"distinguishedName"; LPWSTR apAttributeNames[2] = {sbstr1,sbstr2}; ADS_SEARCH_HANDLE hSearch = NULL; hr = spIADsSearch->ExecuteSearch( L"(objectclass=nTDSDSA)", apAttributeNames, // CODEWORK must use BSTRs? 2, &hSearch ); BREAK_ON_FAIL; // // Prepare a path cracker object // hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (PVOID *)&spPathCracker); BREAK_ON_FAIL; ASSERT( !!spPathCracker ); hr = spPathCracker->SetDisplayType( ADS_DISPLAY_VALUE_ONLY ); BREAK_ON_FAIL; while ( S_OK == (hr = spIADsSearch->GetNextRow ( hSearch )) ) { CComPtr spIndicateItem; hr = m_sipClassDefDC->SpawnInstance( 0, &spIndicateItem ); BREAK_ON_FAIL; IWbemClassObject* pIndicateItem = spIndicateItem; ASSERT( NULL != pIndicateItem ); hr = _PutAttributesDC( pIndicateItem, spPathCracker, bstrFilterValue, spIADsSearch, hSearch ); if (S_FALSE == hr) continue; BREAK_ON_FAIL; // // Send the object to the caller // // [In] param, no need to addref. // ATL asserts on CComPtr<>::operator& if contents not NULL hr = pResponseHandler->Indicate( 1, &pIndicateItem ); BREAK_ON_FAIL; // Let CIMOM know you are finished // return value and SetStatus param should be consistent, // so ignore the return value from SetStatus itself // (in retail builds) HRESULT hr2 = pResponseHandler->SetStatus( WBEM_STATUS_COMPLETE, hr, NULL, NULL ); ASSERT( !FAILED(hr2) ); } } while (false); return hr; } /* HRESULT CProvider::_BuildListDC( IN HANDLE hDS, IN const BSTR bstrDnsDomainName, OUT DS_DOMAIN_CONTROLLER_INFO_1** ppDCs, OUT ULONG* pcDCs ) { WBEM_VALIDATE_OUT_STRUCT_PTR(ppDCs); WBEM_VALIDATE_OUT_STRUCT_PTR(pcDCs); HRESULT hr = WBEM_S_NO_ERROR; do { hr = HRESULT_FROM_WIN32(DsGetDomainControllerInfo( hDS, // hDS bstrDnsDomainName, // DomainName 1, // InfoLevel pcDCs, // pcOut, (void**)ppDCs // ppInfo )); BREAK_ON_FAIL; if ( BAD_IN_MULTISTRUCT_PTR(*ppDCs,*pcDCs) ) { ASSERT(false); break; } } while (false); return hr; } */ HRESULT _PutUUIDAttribute( IWbemClassObject* ipNewInst, LPCTSTR pcszAttributeName, UUID& refuuid) { CComVariant svar; OLECHAR ach[MAX_PATH]; ::ZeroMemory( ach, sizeof(ach) ); if ( 0 >= StringFromGUID2( refuuid, ach, MAX_PATH ) ) { ASSERT(false); } svar = ach; return ipNewInst->Put( pcszAttributeName, 0, &svar, 0 ); } HRESULT _PutLONGLONGAttribute( IWbemClassObject* ipNewInst, LPCTSTR pcszAttributeName, LONGLONG longlong) { CComVariant svar; OLECHAR ach[MAX_PATH]; ::ZeroMemory( ach, sizeof(ach) ); _ui64tot( longlong, ach, 10 ); svar = ach; return ipNewInst->Put( pcszAttributeName, 0, &svar, 0 ); } HRESULT _PutFILETIMEAttribute( IWbemClassObject* ipNewInst, LPCTSTR pcszAttributeName, FILETIME& reffiletime) { SYSTEMTIME systime; ::ZeroMemory( &systime, sizeof(SYSTEMTIME) ); if ( !FileTimeToSystemTime( &reffiletime, &systime ) ) { ASSERT(false); return HRESULT_FROM_WIN32(::GetLastError()); } CComVariant svar; OLECHAR ach[MAX_PATH]; ::ZeroMemory( ach, sizeof(ach) ); swprintf( ach, L"%04u%02u%02u%02u%02u%02u.%06u+000", systime.wYear, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond, systime.wMilliseconds ); svar = ach; return ipNewInst->Put( pcszAttributeName, 0, &svar, 0 ); } HRESULT _PutBooleanAttributes( IWbemClassObject* ipNewInst, UINT cNumAttributes, LPCTSTR* aAttributeNames, DWORD* aBitmasks, DWORD dwValue) { WBEM_VALIDATE_READ_PTR( aAttributeNames, cNumAttributes*sizeof(LPCTSTR) ); WBEM_VALIDATE_READ_PTR( aBitmasks, cNumAttributes*sizeof(DWORD) ); HRESULT hr = WBEM_S_NO_ERROR; CComVariant svar = true; for (UINT i = 0; i < cNumAttributes; i++) { WBEM_VALIDATE_IN_STRING_PTR( aAttributeNames[i] ); if (dwValue & aBitmasks[i]) { hr = ipNewInst->Put( aAttributeNames[i], 0, &svar, 0 ); BREAK_ON_FAIL; } } return hr; } HRESULT _ExtractDomainName( LPCTSTR pszNamingContext, BSTR* pbstrDomainName ) { WBEM_VALIDATE_IN_STRING_PTR( pszNamingContext ); WBEM_VALIDATE_OUT_PTRPTR( pbstrDomainName ); PDS_NAME_RESULTW pDsNameResult = NULL; HRESULT hr = WBEM_S_NO_ERROR; do { DWORD dwErr = DsCrackNamesW( (HANDLE)-1, DS_NAME_FLAG_SYNTACTICAL_ONLY, DS_FQDN_1779_NAME, DS_CANONICAL_NAME, 1, &pszNamingContext, &pDsNameResult); if (NO_ERROR != dwErr) { hr = HRESULT_FROM_WIN32( dwErr ); ASSERT(false); break; } if ( BAD_IN_STRUCT_PTR(pDsNameResult) || 1 != pDsNameResult->cItems || DS_NAME_NO_ERROR != pDsNameResult->rItems->status || BAD_IN_STRUCT_PTR(pDsNameResult->rItems) || BAD_IN_STRING_PTR(pDsNameResult->rItems->pDomain) ) { hr = E_FAIL; ASSERT(false); break; } *pbstrDomainName = ::SysAllocString(pDsNameResult->rItems->pDomain); if (NULL == *pbstrDomainName) { hr = WBEM_E_OUT_OF_MEMORY; break; } } while (false); if (pDsNameResult) { DsFreeNameResultW(pDsNameResult); } return hr; } // if this returns S_FALSE, skip this connection but do not consider this an error HRESULT CProvider::_PutAttributesStatus( IWbemClassObject** pipNewInst, const BSTR bstrFilterValue, DS_REPL_NEIGHBOR* pneighbor) { HRESULT hr = WBEM_S_NO_ERROR; if ( BAD_IN_STRING_PTR(pneighbor->pszNamingContext) || BAD_IN_STRING_PTR(pneighbor->pszSourceDsaDN) || BAD_IN_STRING_PTR_OPTIONAL(pneighbor->pszSourceDsaAddress) || BAD_IN_STRING_PTR_OPTIONAL(pneighbor->pszAsyncIntersiteTransportDN) ) { ASSERT(false); return S_FALSE; } CComPtr spPathCracker; CComBSTR sbstrReplicatedDomain, // DNS name of replicated domain sbstrSourceServer, // CN= name of source server sbstrSourceSite, // name of site containing source server sbstrCompositeName; // composite name for WMI do { hr = _ExtractDomainName( pneighbor->pszNamingContext, &sbstrReplicatedDomain ); BREAK_ON_FAIL; boolean bIsConfigNC = (0 == wcsnicmp(pneighbor->pszNamingContext, L"CN=Configuration,", 17)); boolean bIsSchemaNC = (0 == wcsnicmp(pneighbor->pszNamingContext, L"CN=Schema,", 10)); boolean bIsDeleted = (NULL != wcsstr(pneighbor->pszSourceDsaAddress, L"\nDEL:")); // retrieve source server name and site name hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (PVOID *)&spPathCracker); BREAK_ON_FAIL; ASSERT( !!spPathCracker ); hr = spPathCracker->Set( pneighbor->pszSourceDsaDN, ADS_SETTYPE_DN ); BREAK_ON_FAIL; hr = spPathCracker->SetDisplayType( ADS_DISPLAY_VALUE_ONLY ); BREAK_ON_FAIL; hr = spPathCracker->GetElement( 1L, &sbstrSourceServer ); BREAK_ON_FAIL; hr = spPathCracker->GetElement( 3L, &sbstrSourceSite ); BREAK_ON_FAIL; // Build the composite name sbstrCompositeName = sbstrSourceSite; sbstrCompositeName += L"\\"; sbstrCompositeName += sbstrSourceServer; sbstrCompositeName += L";"; sbstrCompositeName += sbstrReplicatedDomain; if (bIsConfigNC) sbstrCompositeName += L",Configuration"; else if (bIsSchemaNC) sbstrCompositeName += L",Schema"; else sbstrCompositeName += L",Domain"; // Test the composite name against the filter if ( NULL != bstrFilterValue && !lstrcmpi(sbstrCompositeName, bstrFilterValue) ) { hr = S_FALSE; break; } // // Create a new instance of the data object // hr = m_sipClassDefStatus->SpawnInstance( 0, pipNewInst ); BREAK_ON_FAIL; IWbemClassObject* ipNewInst = *pipNewInst; if (NULL == ipNewInst) { ASSERT(false); hr = S_FALSE; break; } CComVariant svar; svar = sbstrCompositeName; hr = ipNewInst->Put( L"CompositeName", 0, &svar, 0 ); BREAK_ON_FAIL; svar = pneighbor->pszNamingContext; hr = ipNewInst->Put( L"NamingContext", 0, &svar, 0 ); BREAK_ON_FAIL; svar = pneighbor->pszSourceDsaDN; hr = ipNewInst->Put( L"SourceDsaDN", 0, &svar, 0 ); BREAK_ON_FAIL; svar = pneighbor->pszSourceDsaAddress; hr = ipNewInst->Put( L"SourceDsaAddress", 0, &svar, 0 ); BREAK_ON_FAIL; svar = pneighbor->pszAsyncIntersiteTransportDN; hr = ipNewInst->Put( L"AsyncIntersiteTransportDN", 0, &svar, 0 ); BREAK_ON_FAIL; svar = (long)pneighbor->dwReplicaFlags; hr = ipNewInst->Put( L"ReplicaFlags", 0, &svar, 0 ); BREAK_ON_FAIL; if (bIsConfigNC) { svar = TRUE; hr = ipNewInst->Put( L"IsConfigurationNamingContext", 0, &svar, 0 ); BREAK_ON_FAIL; } if (bIsSchemaNC) { svar = TRUE; hr = ipNewInst->Put( L"IsSchemaNamingContext", 0, &svar, 0 ); BREAK_ON_FAIL; } if (bIsDeleted) { svar = TRUE; hr = ipNewInst->Put( L"IsDeletedSourceDsa", 0, &svar, 0 ); BREAK_ON_FAIL; } svar = sbstrSourceSite; hr = ipNewInst->Put( L"SourceDsaSite", 0, &svar, 0 ); BREAK_ON_FAIL; svar = sbstrSourceServer; hr = ipNewInst->Put( L"SourceDsaCN", 0, &svar, 0 ); BREAK_ON_FAIL; svar = sbstrReplicatedDomain; hr = ipNewInst->Put( L"Domain", 0, &svar, 0 ); BREAK_ON_FAIL; LPCTSTR aBooleanAttrNames[12] = { TEXT("Writeable"), TEXT("SyncOnStartup"), TEXT("DoScheduledSyncs"), TEXT("UseAsyncIntersiteTransport"), TEXT("TwoWaySync"), TEXT("FullSyncInProgress"), TEXT("FullSyncNextPacket"), TEXT("NeverSynced"), TEXT("IgnoreChangeNotifications"), TEXT("DisableScheduledSync"), TEXT("CompressChanges"), TEXT("NoChangeNotifications") }; DWORD aBitmasks[12] = { DS_REPL_NBR_WRITEABLE, DS_REPL_NBR_SYNC_ON_STARTUP, DS_REPL_NBR_DO_SCHEDULED_SYNCS, DS_REPL_NBR_USE_ASYNC_INTERSITE_TRANSPORT, DS_REPL_NBR_TWO_WAY_SYNC, DS_REPL_NBR_FULL_SYNC_IN_PROGRESS, DS_REPL_NBR_FULL_SYNC_NEXT_PACKET, DS_REPL_NBR_NEVER_SYNCED, DS_REPL_NBR_IGNORE_CHANGE_NOTIFICATIONS, DS_REPL_NBR_DISABLE_SCHEDULED_SYNC, DS_REPL_NBR_COMPRESS_CHANGES, DS_REPL_NBR_NO_CHANGE_NOTIFICATIONS }; hr = _PutBooleanAttributes( ipNewInst, 12, aBooleanAttrNames, aBitmasks, pneighbor->dwReplicaFlags ); BREAK_ON_FAIL; hr = _PutUUIDAttribute( ipNewInst, L"NamingContextObjGuid", pneighbor->uuidNamingContextObjGuid ); BREAK_ON_FAIL; hr = _PutUUIDAttribute( ipNewInst, L"SourceDsaObjGuid", pneighbor->uuidSourceDsaObjGuid ); BREAK_ON_FAIL; hr = _PutUUIDAttribute( ipNewInst, L"SourceDsaInvocationID", pneighbor->uuidSourceDsaInvocationID ); BREAK_ON_FAIL; hr = _PutUUIDAttribute( ipNewInst, L"AsyncIntersiteTransportObjGuid", pneighbor->uuidAsyncIntersiteTransportObjGuid ); BREAK_ON_FAIL; hr = _PutLONGLONGAttribute( ipNewInst, L"LastObjChangeSynced", pneighbor->usnLastObjChangeSynced); BREAK_ON_FAIL; hr = _PutLONGLONGAttribute( ipNewInst, L"AttributeFilter", pneighbor->usnAttributeFilter); BREAK_ON_FAIL; hr = _PutFILETIMEAttribute( ipNewInst, L"LastSyncSuccess", pneighbor->ftimeLastSyncSuccess); BREAK_ON_FAIL; hr = _PutFILETIMEAttribute( ipNewInst, L"LastSyncAttempt", pneighbor->ftimeLastSyncAttempt); BREAK_ON_FAIL; svar = (long)pneighbor->dwLastSyncResult; hr = ipNewInst->Put( L"LastSyncResult", 0, &svar, 0 ); BREAK_ON_FAIL; svar = (long)pneighbor->cNumConsecutiveSyncFailures; hr = ipNewInst->Put( L"NumConsecutiveSyncFailures", 0, &svar, 0 ); BREAK_ON_FAIL; svar = (long)((bIsDeleted) ? 0L : pneighbor->cNumConsecutiveSyncFailures); hr = ipNewInst->Put( L"ModifiedNumConsecutiveSyncFailures", 0, &svar, 0 ); BREAK_ON_FAIL; } while (false); return hr; } // if this returns S_FALSE, skip this connection but do not consider this an error // note, this version does not create or release the instance HRESULT CProvider::_PutAttributesDC( IN IWbemClassObject* pIndicateItem, IN IADsPathname* pPathCracker, IN const BSTR bstrFilterValue, IN IDirectorySearch* pIADsSearch, IN ADS_SEARCH_HANDLE hSearch) { WBEM_VALIDATE_INTF_PTR( pIndicateItem ); WBEM_VALIDATE_INTF_PTR( pPathCracker ); HRESULT hr = WBEM_S_NO_ERROR; ADS_SEARCH_COLUMN adscolDN, adscolGUID; boolean fFreeColumnDN = false, fFreeColumnGUID = false; CComVariant svar; CComBSTR sbstrServerCN, sbstrSite; do { hr = pIADsSearch->GetColumn( hSearch, L"distinguishedName", &adscolDN ); BREAK_ON_FAIL; fFreeColumnDN = true; if ( ADSTYPE_DN_STRING != adscolDN.dwADsType || 1 != adscolDN.dwNumValues || BAD_IN_STRUCT_PTR(adscolDN.pADsValues) || BAD_IN_STRING_PTR(adscolDN.pADsValues[0].DNString) ) { // skip this one hr = S_FALSE; break; } hr = pIADsSearch->GetColumn( hSearch, L"objectGUID", &adscolGUID ); BREAK_ON_FAIL; fFreeColumnGUID = true; if ( ADSTYPE_OCTET_STRING != adscolGUID.dwADsType || 1 != adscolGUID.dwNumValues || BAD_IN_STRUCT_PTR(adscolGUID.pADsValues) || 0 == adscolGUID.pADsValues[0].OctetString.dwLength || BAD_IN_READ_PTR(adscolGUID.pADsValues[0].OctetString.lpValue, adscolGUID.pADsValues[0].OctetString.dwLength) ) { // skip this one hr = S_FALSE; break; } hr = pPathCracker->Set( adscolDN.pADsValues[0].DNString, ADS_SETTYPE_DN ); BREAK_ON_FAIL; hr = pPathCracker->GetElement( 1L, &sbstrServerCN ); BREAK_ON_FAIL; hr = pPathCracker->GetElement( 3L, &sbstrSite ); BREAK_ON_FAIL; // Test the site name against the filter if ( NULL != bstrFilterValue && !lstrcmpi(sbstrSite, bstrFilterValue) ) { hr = S_FALSE; break; } svar = adscolDN.pADsValues[0].DNString; hr = pIndicateItem->Put( L"DistinguishedName", 0, &svar, 0 ); BREAK_ON_FAIL; svar = sbstrServerCN; hr = pIndicateItem->Put( L"CommonName", 0, &svar, 0 ); BREAK_ON_FAIL; svar = sbstrSite; hr = pIndicateItem->Put( L"SiteName", 0, &svar, 0 ); BREAK_ON_FAIL; hr = _PutUUIDAttribute( pIndicateItem, L"ObjectGUID", (GUID&)adscolGUID.pADsValues[0].OctetString.lpValue ); BREAK_ON_FAIL; } while (false); if (fFreeColumnDN) { HRESULT hr2 = pIADsSearch->FreeColumn( &adscolDN ); ASSERT( SUCCEEDED(hr2) ); } if (fFreeColumnGUID) { HRESULT hr2 = pIADsSearch->FreeColumn( &adscolGUID ); ASSERT( SUCCEEDED(hr2) ); } return hr; } HRESULT CProvider::_BuildIndicateArrayStatus( IN DS_REPL_NEIGHBORS* pneighborstruct, IN const BSTR bstrFilterValue, OUT IWbemClassObject*** ppaIndicateItems, OUT DWORD* pcIndicateItems) { WBEM_VALIDATE_IN_STRUCT_PTR( pneighborstruct ); WBEM_VALIDATE_IN_MULTISTRUCT_PTR( pneighborstruct->rgNeighbor, pneighborstruct->cNumNeighbors ); WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL( bstrFilterValue ); WBEM_VALIDATE_OUT_PTRPTR( ppaIndicateItems ); WBEM_VALIDATE_OUT_STRUCT_PTR( pcIndicateItems ); HRESULT hr = WBEM_S_NO_ERROR; DS_REPL_NEIGHBOR* pneighbors = pneighborstruct->rgNeighbor; DWORD cneighbors = pneighborstruct->cNumNeighbors; if (0 == cneighbors) return WBEM_S_NO_ERROR; IWbemClassObject** paIndicateItems = NULL; DWORD cIndicateItems = 0; *ppaIndicateItems = NULL; *pcIndicateItems = 0; do { paIndicateItems = new IWbemClassObject*[cneighbors]; if (NULL == paIndicateItems) { ASSERT(false); hr = WBEM_E_OUT_OF_MEMORY; break; } ::ZeroMemory( paIndicateItems, cneighbors * sizeof(IWbemClassObject*) ); for (DWORD i = 0; i < cneighbors; i++) { DS_REPL_NEIGHBOR* pneighbor = &(pneighbors[i]); hr = _PutAttributesStatus( &paIndicateItems[cIndicateItems], bstrFilterValue, pneighbor ); if (S_FALSE == hr) continue; cIndicateItems++; BREAK_ON_FAIL; } } while (false); if (!FAILED(hr)) { *ppaIndicateItems = paIndicateItems; *pcIndicateItems = cIndicateItems; } else { _ReleaseIndicateArray( paIndicateItems, cneighbors ); } return hr; } /* HRESULT CProvider::_BuildIndicateArrayDC( IN DS_DOMAIN_CONTROLLER_INFO_1* pDCs, IN ULONG cDCs, IN const BSTR bstrFilterValue, OUT IWbemClassObject*** ppaIndicateItems, OUT DWORD* pcIndicateItems) { WBEM_VALIDATE_IN_MULTISTRUCT_PTR( pDCs, cDCs ); WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL( bstrFilterValue ); WBEM_VALIDATE_OUT_PTRPTR( ppaIndicateItems ); WBEM_VALIDATE_OUT_STRUCT_PTR( pcIndicateItems ); HRESULT hr = WBEM_S_NO_ERROR; if (0 == cDCs) return WBEM_S_NO_ERROR; IWbemClassObject** paIndicateItems = NULL; DWORD cIndicateItems = 0; *ppaIndicateItems = NULL; *pcIndicateItems = 0; do { paIndicateItems = new IWbemClassObject*[cDCs]; if (NULL == paIndicateItems) { ASSERT(false); hr = WBEM_E_OUT_OF_MEMORY; break; } ::ZeroMemory( paIndicateItems, cDCs * sizeof(IWbemClassObject*) ); for (DWORD i = 0; i < cDCs; i++) { DS_DOMAIN_CONTROLLER_INFO_1* pDC = &(pDCs[i]); hr = _PutAttributesDC( &paIndicateItems[cIndicateItems], bstrFilterValue, pDC ); if (S_FALSE == hr) continue; cIndicateItems++; BREAK_ON_FAIL; } } while (false); if (!FAILED(hr)) { *ppaIndicateItems = paIndicateItems; *pcIndicateItems = cIndicateItems; } else { _ReleaseIndicateArray( paIndicateItems, cDCs ); } return hr; } */ void CProvider::_ReleaseIndicateArray( IWbemClassObject** paIndicateItems, DWORD cIndicateItems, bool fReleaseArray) { if (paIndicateItems != NULL) { for (DWORD i = 0; i < cIndicateItems; i++) { if (NULL != paIndicateItems[i]) paIndicateItems[i]->Release(); } if (fReleaseArray) { delete[] paIndicateItems; } else { ::ZeroMemory( *paIndicateItems, cIndicateItems * sizeof(IWbemClassObject*) ); } } }