windows-nt/Source/XPSP1/NT/admin/wmiprov/adreplpv/wbem.cpp
2020-09-26 16:20:57 +08:00

1249 lines
37 KiB
C++

// WbemProv.cpp : Implementation of CAdreplpvApp and DLL registration.
#include "stdafx.h"
#include "dbg.cpp"
//#include "adreplpv.h"
#include "Wbem.h"
#include <lmcons.h>
#include <lmapibuf.h>
#include <adshlp.h>
#define INITGUID
#include <initguid.h>
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<IADs> spIADsRootDSE;
CComVariant svarSchema;
CComPtr<IADsPathname> spIADsPathname;
CComPtr<IDirectorySearch> spIADsSearch;
CComPtr<IADsPathname> 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<IWbemClassObject> 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<IADsPathname> 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*) );
}
}
}