Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1248 lines
37 KiB

  1. // WbemProv.cpp : Implementation of CAdreplpvApp and DLL registration.
  2. #include "stdafx.h"
  3. #include "dbg.cpp"
  4. //#include "adreplpv.h"
  5. #include "Wbem.h"
  6. #include <lmcons.h>
  7. #include <lmapibuf.h>
  8. #include <adshlp.h>
  9. #define INITGUID
  10. #include <initguid.h>
  11. DEFINE_GUID(CLSID_ADReplProvider,0x96FA95C4,0x0AF3,0x4EF9,0xA1,0xEB,0xC8,0x15,0x13,0x22,0x15,0x7B);
  12. /////////////////////////////////////////////////////////////////////////////
  13. //
  14. // CODEWORK should only have one definition of classname and GUID
  15. #define CLASSNAME_STRING_STATUS L"Microsoft_ADReplStatus"
  16. #define CLASSNAME_STRING_DC L"Microsoft_ADReplDomainController"
  17. CProvider::CProvider()
  18. {
  19. }
  20. CProvider::~CProvider()
  21. {
  22. }
  23. // IWbemProviderInit
  24. STDMETHODIMP CProvider::Initialize(
  25. IN LPWSTR pszUser,
  26. IN LONG lFlags,
  27. IN LPWSTR pszNamespace,
  28. IN LPWSTR pszLocale,
  29. IN IWbemServices *pNamespace,
  30. IN IWbemContext *pCtx,
  31. IN IWbemProviderInitSink *pInitSink
  32. )
  33. {
  34. WBEM_VALIDATE_INTF_PTR( pNamespace );
  35. WBEM_VALIDATE_INTF_PTR( pCtx );
  36. WBEM_VALIDATE_INTF_PTR( pInitSink );
  37. HRESULT hr = WBEM_S_NO_ERROR;
  38. do
  39. {
  40. m_sipNamespace = pNamespace;
  41. CComBSTR sbstrObjectName = CLASSNAME_STRING_STATUS; // is this necessary?
  42. hr = m_sipNamespace->GetObject( sbstrObjectName,
  43. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  44. pCtx,
  45. &m_sipClassDefStatus,
  46. NULL );
  47. BREAK_ON_FAIL;
  48. sbstrObjectName = CLASSNAME_STRING_DC;
  49. hr = m_sipNamespace->GetObject( sbstrObjectName,
  50. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  51. pCtx,
  52. &m_sipClassDefDC,
  53. NULL );
  54. BREAK_ON_FAIL;
  55. // Let CIMOM know you are initialized
  56. // return value and SetStatus param should be consistent, so ignore
  57. // the return value from SetStatus itself (in retail builds)
  58. HRESULT hr2 = pInitSink->SetStatus( WBEM_S_INITIALIZED, 0 );
  59. ASSERT( !FAILED(hr2) );
  60. } while (false);
  61. return hr;
  62. }
  63. // IWbemServices
  64. // BUGBUG should this ever indicate more than one?
  65. STDMETHODIMP CProvider::GetObjectAsync(
  66. IN const BSTR bstrObjectPath,
  67. IN long lFlags,
  68. IN IWbemContext *pCtx,
  69. IN IWbemObjectSink *pResponseHandler)
  70. {
  71. WBEM_VALIDATE_IN_STRING_PTR( bstrObjectPath );
  72. // CODEWORK check lFlags?
  73. WBEM_VALIDATE_INTF_PTR( pCtx );
  74. WBEM_VALIDATE_INTF_PTR( pResponseHandler );
  75. static LPCWSTR ROOTSTR_STATUS = L"Microsoft_ADReplStatus.CompositeName=\"";
  76. static LPCWSTR ROOTSTR_DC = L"Microsoft_ADReplDomainController.SiteName=\"";
  77. int rootlen = lstrlen(ROOTSTR_STATUS);
  78. if ( lstrlen(bstrObjectPath) > rootlen
  79. && 0 == _tcsnicmp(bstrObjectPath, ROOTSTR_STATUS, rootlen)
  80. )
  81. {
  82. // remove prefix
  83. CComBSTR sbstrFilterValue = (BSTR)bstrObjectPath + rootlen;
  84. // remove trailing doublequote
  85. sbstrFilterValue[lstrlen(sbstrFilterValue)-1] = L'\0';
  86. return _EnumAndIndicateStatus( CLASS_STATUS,
  87. pCtx,
  88. pResponseHandler,
  89. sbstrFilterValue );
  90. }
  91. rootlen = lstrlen(ROOTSTR_DC);
  92. if ( lstrlen(bstrObjectPath) > rootlen
  93. && 0 == _tcsnicmp(bstrObjectPath, ROOTSTR_DC, rootlen)
  94. )
  95. {
  96. // remove prefix
  97. CComBSTR sbstrFilterValue = (BSTR)bstrObjectPath + rootlen;
  98. // remove trailing doublequote
  99. sbstrFilterValue[lstrlen(sbstrFilterValue)-1] = L'\0';
  100. return _EnumAndIndicateDC( pCtx,
  101. pResponseHandler,
  102. sbstrFilterValue );
  103. }
  104. ASSERT(false);
  105. return WBEM_E_INVALID_OBJECT_PATH;
  106. }
  107. STDMETHODIMP CProvider::CreateInstanceEnumAsync(
  108. IN const BSTR bstrClass,
  109. IN long lFlags,
  110. IN IWbemContext *pCtx,
  111. IN IWbemObjectSink *pResponseHandler)
  112. {
  113. WBEM_VALIDATE_IN_STRING_PTR( bstrClass );
  114. // CODEWORK check lFlags?
  115. WBEM_VALIDATE_INTF_PTR( pCtx );
  116. WBEM_VALIDATE_INTF_PTR( pResponseHandler );
  117. if ( 0 == lstrcmp( bstrClass, CLASSNAME_STRING_STATUS ) )
  118. return _EnumAndIndicateStatus( CLASS_STATUS, pCtx, pResponseHandler );
  119. else if ( 0 == lstrcmp( bstrClass, CLASSNAME_STRING_DC ) )
  120. return _EnumAndIndicateDC( pCtx, pResponseHandler );
  121. return WBEM_E_INVALID_OBJECT_PATH;
  122. }
  123. HRESULT CProvider::_EnumAndIndicateStatus(
  124. IN ProviderClass provclass, // BUGBUG don't need this parameter
  125. IN IWbemContext *pCtx,
  126. IN IWbemObjectSink *pResponseHandler,
  127. IN const BSTR bstrFilterValue )
  128. {
  129. HRESULT hr = WBEM_S_NO_ERROR;
  130. DSROLE_PRIMARY_DOMAIN_INFO_BASIC* pdomaininfo = NULL;
  131. HANDLE hDS = NULL;
  132. bool fImpersonating = false;
  133. do
  134. {
  135. hr = CoImpersonateClient();
  136. BREAK_ON_FAIL;
  137. fImpersonating = true;
  138. // Check whether this is a DC
  139. hr = HRESULT_FROM_WIN32(DsRoleGetPrimaryDomainInformation(
  140. NULL, // lpServer = local machine
  141. DsRolePrimaryDomainInfoBasic, // InfoLevel
  142. (PBYTE*)&pdomaininfo // pBuffer
  143. ));
  144. BREAK_ON_FAIL;
  145. ASSERT( NULL != pdomaininfo );
  146. bool fIsDC = true;
  147. switch (pdomaininfo->MachineRole)
  148. {
  149. case DsRole_RoleBackupDomainController:
  150. case DsRole_RolePrimaryDomainController:
  151. break;
  152. default:
  153. fIsDC = false;
  154. break;
  155. }
  156. if ( !fIsDC )
  157. {
  158. // this is not a DC, return no connections
  159. break;
  160. }
  161. TCHAR achComputerName[MAX_PATH];
  162. DWORD dwSize = sizeof(achComputerName)/sizeof(TCHAR);
  163. if ( !GetComputerNameEx(
  164. ComputerNameDnsFullyQualified,
  165. achComputerName,
  166. &dwSize ))
  167. {
  168. hr = HRESULT_FROM_WIN32(::GetLastError());
  169. }
  170. BREAK_ON_FAIL;
  171. hr = HRESULT_FROM_WIN32(DsBind(
  172. achComputerName, // DomainControllerName
  173. NULL, // DnsDomainName
  174. &hDS // phDS
  175. ));
  176. // RPC_S_UUID_NO_ADDRESS means this is not a DC
  177. BREAK_ON_FAIL;
  178. ASSERT( NULL != hDS );
  179. switch (provclass)
  180. {
  181. case CLASS_DC:
  182. ASSERT(false);
  183. break;
  184. case CLASS_STATUS:
  185. hr = _EnumAndIndicateWorker( provclass,
  186. hDS,
  187. pCtx,
  188. pResponseHandler,
  189. bstrFilterValue );
  190. break;
  191. default:
  192. ASSERT(false);
  193. }
  194. } while (false);
  195. if (fImpersonating)
  196. {
  197. // CODEWORK do we want to keep impersonating and reverting?
  198. HRESULT hr2 = CoRevertToSelf();
  199. ASSERT( !FAILED(hr2) );
  200. }
  201. if (NULL != hDS)
  202. {
  203. (void) DsUnBind( &hDS );
  204. }
  205. if (NULL != pdomaininfo)
  206. {
  207. DsRoleFreeMemory( pdomaininfo );
  208. }
  209. return hr;
  210. }
  211. /*
  212. HRESULT CProvider::_EnumAndIndicateDCWorker(
  213. IN HANDLE hDS,
  214. IN IWbemContext *pCtx,
  215. IN IWbemObjectSink *pResponseHandler,
  216. IN const BSTR bstrFilterValue )
  217. {
  218. HRESULT hr = WBEM_S_NO_ERROR;
  219. DS_DOMAIN_TRUSTS* ptrusts = NULL;
  220. ULONG ctrusts = 0;
  221. do
  222. {
  223. hr = HRESULT_FROM_WIN32(DsEnumerateDomainTrustsW(
  224. NULL, // ServerName
  225. DS_DOMAIN_IN_FOREST, // Flags,
  226. &ptrusts, // Domains,
  227. &ctrusts // DomainCount
  228. ));
  229. BREAK_ON_FAIL;
  230. if (0 == ctrusts)
  231. break;
  232. if ( BAD_IN_MULTISTRUCT_PTR(ptrusts,ctrusts) )
  233. {
  234. ASSERT(false);
  235. break;
  236. }
  237. for (ULONG i = 0; i < ctrusts; i++)
  238. {
  239. if ( BAD_IN_STRING_PTR(ptrusts[i].DnsDomainName) )
  240. {
  241. // skip this one
  242. break;
  243. }
  244. hr = _EnumAndIndicateWorker( CLASS_DC,
  245. hDS,
  246. pCtx,
  247. pResponseHandler,
  248. bstrFilterValue,
  249. ptrusts[i].DnsDomainName );
  250. BREAK_ON_FAIL;
  251. }
  252. } while (false);
  253. if ( NULL != ptrusts )
  254. {
  255. (void) NetApiBufferFree( ptrusts );
  256. }
  257. return hr;
  258. }
  259. */
  260. HRESULT CProvider::_EnumAndIndicateWorker(
  261. IN ProviderClass provclass, // BUGBUG parameter not needed
  262. IN HANDLE hDS,
  263. IN IWbemContext *pCtx,
  264. IN IWbemObjectSink *pResponseHandler,
  265. IN const BSTR bstrFilterValue,
  266. IN const BSTR bstrDnsDomainName )
  267. {
  268. WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL(bstrFilterValue);
  269. WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL(bstrDnsDomainName);
  270. HRESULT hr = WBEM_S_NO_ERROR;
  271. DS_REPL_NEIGHBORS* pneighborsstruct = NULL;
  272. DS_DOMAIN_CONTROLLER_INFO_1 * pDCs = NULL; // BUGBUG not needed
  273. ULONG cDCs = 0;
  274. DWORD cIndicateItems = 0;
  275. IWbemClassObject** paIndicateItems = NULL;
  276. do
  277. {
  278. switch (provclass)
  279. {
  280. case CLASS_STATUS:
  281. hr = _BuildListStatus( hDS, &pneighborsstruct );
  282. break;
  283. /*
  284. case CLASS_DC:
  285. hr = _BuildListDC( hDS, bstrDnsDomainName, &pDCs, &cDCs );
  286. break;
  287. */
  288. default:
  289. ASSERT(false);
  290. break;
  291. }
  292. BREAK_ON_FAIL;
  293. switch (provclass)
  294. {
  295. case CLASS_STATUS:
  296. hr = _BuildIndicateArrayStatus( pneighborsstruct,
  297. bstrFilterValue,
  298. &paIndicateItems,
  299. &cIndicateItems );
  300. break;
  301. /*
  302. case CLASS_DC:
  303. hr = _BuildIndicateArrayDC( pDCs,
  304. cDCs,
  305. bstrFilterValue,
  306. &paIndicateItems,
  307. &cIndicateItems );
  308. break;
  309. */
  310. default:
  311. ASSERT(false);
  312. break;
  313. }
  314. //
  315. // Send the objects to the caller
  316. //
  317. // [In] param, no need to addref.
  318. if (cIndicateItems > 0)
  319. {
  320. hr = pResponseHandler->Indicate( cIndicateItems, paIndicateItems );
  321. BREAK_ON_FAIL;
  322. }
  323. // Let CIMOM know you are finished
  324. // return value and SetStatus param should be consistent, so ignore
  325. // the return value from SetStatus itself (in retail builds)
  326. HRESULT hr2 = pResponseHandler->SetStatus( WBEM_STATUS_COMPLETE, hr,
  327. NULL, NULL );
  328. ASSERT( !FAILED(hr2) );
  329. } while (false);
  330. _ReleaseIndicateArray( paIndicateItems, cIndicateItems );
  331. if ( NULL != pneighborsstruct )
  332. {
  333. (void) DsReplicaFreeInfo( DS_REPL_INFO_NEIGHBORS, pneighborsstruct );
  334. }
  335. if ( NULL != pDCs )
  336. {
  337. (void) NetApiBufferFree( pDCs );
  338. }
  339. return hr;
  340. }
  341. /*
  342. // does not validate resultant structs coming from API
  343. HRESULT CProvider::_BuildConnectionList(
  344. IN ProviderClass provclass,
  345. OUT void** ppitems )
  346. {
  347. WBEM_VALIDATE_OUT_PTRPTR( ppitems );
  348. HRESULT hr = WBEM_S_NO_ERROR;
  349. bool fImpersonating = false;
  350. do {
  351. hr = CoImpersonateClient();
  352. BREAK_ON_FAIL;
  353. fImpersonating = true;
  354. switch (provclass)
  355. {
  356. case CLASS_STATUS:
  357. hr = _BuildListStatus( ppitems );
  358. break;
  359. case CLASS_DC:
  360. hr = _BuildListDC( ppitems );
  361. break;
  362. default:
  363. ASSERT(false);
  364. break;
  365. }
  366. } while (false);
  367. if (fImpersonating)
  368. {
  369. HRESULT hr2 = CoRevertToSelf();
  370. ASSERT( !FAILED(hr2) );
  371. }
  372. return hr;
  373. }
  374. */
  375. // does not validate resultant structs coming from API
  376. HRESULT CProvider::_BuildListStatus(
  377. IN HANDLE hDS,
  378. OUT DS_REPL_NEIGHBORS** ppneighborsstruct )
  379. {
  380. WBEM_VALIDATE_OUT_STRUCT_PTR(ppneighborsstruct);
  381. HRESULT hr = WBEM_S_NO_ERROR;
  382. do {
  383. hr = HRESULT_FROM_WIN32(DsReplicaGetInfo(
  384. hDS, // hDS
  385. DS_REPL_INFO_NEIGHBORS, // InfoType
  386. NULL, // pszObject
  387. NULL, // puuidForSourceDsaObjGuid,
  388. (void**)ppneighborsstruct // ppinfo
  389. ));
  390. BREAK_ON_FAIL;
  391. if ( BAD_IN_STRUCT_PTR(*ppneighborsstruct) )
  392. {
  393. ASSERT(false);
  394. break;
  395. }
  396. } while (false);
  397. return hr;
  398. }
  399. HRESULT CProvider::_EnumAndIndicateDC(
  400. IN IWbemContext *pCtx,
  401. IN IWbemObjectSink *pResponseHandler,
  402. IN const BSTR bstrFilterValue
  403. )
  404. {
  405. WBEM_VALIDATE_INTF_PTR( pCtx );
  406. WBEM_VALIDATE_INTF_PTR( pResponseHandler );
  407. WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL( bstrFilterValue );
  408. HRESULT hr = WBEM_S_NO_ERROR;
  409. CComPtr<IADs> spIADsRootDSE;
  410. CComVariant svarSchema;
  411. CComPtr<IADsPathname> spIADsPathname;
  412. CComPtr<IDirectorySearch> spIADsSearch;
  413. CComPtr<IADsPathname> spPathCracker;
  414. do {
  415. //
  416. // Enumerate all nTDSDSA objects
  417. //
  418. hr = ADsOpenObject( L"LDAP://RootDSE",
  419. NULL, NULL, ADS_SECURE_AUTHENTICATION,
  420. IID_IADs, OUT (void **)&spIADsRootDSE);
  421. BREAK_ON_FAIL;
  422. hr = spIADsRootDSE->Get(L"configurationNamingContext", &svarSchema);
  423. BREAK_ON_FAIL;
  424. ASSERT( VT_BSTR == svarSchema.vt );
  425. hr = spIADsPathname.CoCreateInstance( CLSID_Pathname );
  426. BREAK_ON_FAIL;
  427. ASSERT( !!spIADsPathname );
  428. CComBSTR sbstr = L"LDAP://CN=Sites,";
  429. sbstr += svarSchema.bstrVal;
  430. hr = ADsOpenObject( sbstr,
  431. NULL, NULL, ADS_SECURE_AUTHENTICATION,
  432. IID_IDirectorySearch, (void **)&spIADsSearch);
  433. BREAK_ON_FAIL;
  434. ADS_SEARCHPREF_INFO aSearchPref[4];
  435. aSearchPref[0].dwSearchPref = ADS_SEARCHPREF_CHASE_REFERRALS;
  436. aSearchPref[0].vValue.dwType = ADSTYPE_INTEGER;
  437. aSearchPref[0].vValue.Integer = ADS_CHASE_REFERRALS_EXTERNAL;
  438. aSearchPref[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
  439. aSearchPref[1].vValue.dwType = ADSTYPE_INTEGER;
  440. aSearchPref[1].vValue.Integer = 50;
  441. aSearchPref[2].dwSearchPref = ADS_SEARCHPREF_CACHE_RESULTS;
  442. aSearchPref[2].vValue.dwType = ADSTYPE_BOOLEAN;
  443. aSearchPref[2].vValue.Integer = FALSE;
  444. aSearchPref[3].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  445. aSearchPref[3].vValue.dwType = ADSTYPE_INTEGER;
  446. aSearchPref[3].vValue.Integer = ADS_SCOPE_SUBTREE;
  447. hr = spIADsSearch->SetSearchPreference (aSearchPref, 4);
  448. BREAK_ON_FAIL;
  449. CComBSTR sbstr1 = L"objectGUID";
  450. CComBSTR sbstr2 = L"distinguishedName";
  451. LPWSTR apAttributeNames[2] = {sbstr1,sbstr2};
  452. ADS_SEARCH_HANDLE hSearch = NULL;
  453. hr = spIADsSearch->ExecuteSearch( L"(objectclass=nTDSDSA)",
  454. apAttributeNames, // CODEWORK must use BSTRs?
  455. 2,
  456. &hSearch );
  457. BREAK_ON_FAIL;
  458. //
  459. // Prepare a path cracker object
  460. //
  461. hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
  462. IID_IADsPathname, (PVOID *)&spPathCracker);
  463. BREAK_ON_FAIL;
  464. ASSERT( !!spPathCracker );
  465. hr = spPathCracker->SetDisplayType( ADS_DISPLAY_VALUE_ONLY );
  466. BREAK_ON_FAIL;
  467. while ( S_OK == (hr = spIADsSearch->GetNextRow ( hSearch )) )
  468. {
  469. CComPtr<IWbemClassObject> spIndicateItem;
  470. hr = m_sipClassDefDC->SpawnInstance( 0, &spIndicateItem );
  471. BREAK_ON_FAIL;
  472. IWbemClassObject* pIndicateItem = spIndicateItem;
  473. ASSERT( NULL != pIndicateItem );
  474. hr = _PutAttributesDC( pIndicateItem,
  475. spPathCracker,
  476. bstrFilterValue,
  477. spIADsSearch,
  478. hSearch );
  479. if (S_FALSE == hr)
  480. continue;
  481. BREAK_ON_FAIL;
  482. //
  483. // Send the object to the caller
  484. //
  485. // [In] param, no need to addref.
  486. // ATL asserts on CComPtr<>::operator& if contents not NULL
  487. hr = pResponseHandler->Indicate( 1, &pIndicateItem );
  488. BREAK_ON_FAIL;
  489. // Let CIMOM know you are finished
  490. // return value and SetStatus param should be consistent,
  491. // so ignore the return value from SetStatus itself
  492. // (in retail builds)
  493. HRESULT hr2 = pResponseHandler->SetStatus(
  494. WBEM_STATUS_COMPLETE, hr, NULL, NULL );
  495. ASSERT( !FAILED(hr2) );
  496. }
  497. } while (false);
  498. return hr;
  499. }
  500. /*
  501. HRESULT CProvider::_BuildListDC(
  502. IN HANDLE hDS,
  503. IN const BSTR bstrDnsDomainName,
  504. OUT DS_DOMAIN_CONTROLLER_INFO_1** ppDCs,
  505. OUT ULONG* pcDCs )
  506. {
  507. WBEM_VALIDATE_OUT_STRUCT_PTR(ppDCs);
  508. WBEM_VALIDATE_OUT_STRUCT_PTR(pcDCs);
  509. HRESULT hr = WBEM_S_NO_ERROR;
  510. do {
  511. hr = HRESULT_FROM_WIN32(DsGetDomainControllerInfo(
  512. hDS, // hDS
  513. bstrDnsDomainName, // DomainName
  514. 1, // InfoLevel
  515. pcDCs, // pcOut,
  516. (void**)ppDCs // ppInfo
  517. ));
  518. BREAK_ON_FAIL;
  519. if ( BAD_IN_MULTISTRUCT_PTR(*ppDCs,*pcDCs) )
  520. {
  521. ASSERT(false);
  522. break;
  523. }
  524. } while (false);
  525. return hr;
  526. }
  527. */
  528. HRESULT _PutUUIDAttribute(
  529. IWbemClassObject* ipNewInst,
  530. LPCTSTR pcszAttributeName,
  531. UUID& refuuid)
  532. {
  533. CComVariant svar;
  534. OLECHAR ach[MAX_PATH];
  535. ::ZeroMemory( ach, sizeof(ach) );
  536. if ( 0 >= StringFromGUID2( refuuid, ach, MAX_PATH ) )
  537. {
  538. ASSERT(false);
  539. }
  540. svar = ach;
  541. return ipNewInst->Put( pcszAttributeName, 0, &svar, 0 );
  542. }
  543. HRESULT _PutLONGLONGAttribute(
  544. IWbemClassObject* ipNewInst,
  545. LPCTSTR pcszAttributeName,
  546. LONGLONG longlong)
  547. {
  548. CComVariant svar;
  549. OLECHAR ach[MAX_PATH];
  550. ::ZeroMemory( ach, sizeof(ach) );
  551. _ui64tot( longlong, ach, 10 );
  552. svar = ach;
  553. return ipNewInst->Put( pcszAttributeName, 0, &svar, 0 );
  554. }
  555. HRESULT _PutFILETIMEAttribute(
  556. IWbemClassObject* ipNewInst,
  557. LPCTSTR pcszAttributeName,
  558. FILETIME& reffiletime)
  559. {
  560. SYSTEMTIME systime;
  561. ::ZeroMemory( &systime, sizeof(SYSTEMTIME) );
  562. if ( !FileTimeToSystemTime( &reffiletime, &systime ) )
  563. {
  564. ASSERT(false);
  565. return HRESULT_FROM_WIN32(::GetLastError());
  566. }
  567. CComVariant svar;
  568. OLECHAR ach[MAX_PATH];
  569. ::ZeroMemory( ach, sizeof(ach) );
  570. swprintf( ach, L"%04u%02u%02u%02u%02u%02u.%06u+000",
  571. systime.wYear,
  572. systime.wMonth,
  573. systime.wDay,
  574. systime.wHour,
  575. systime.wMinute,
  576. systime.wSecond,
  577. systime.wMilliseconds
  578. );
  579. svar = ach;
  580. return ipNewInst->Put( pcszAttributeName, 0, &svar, 0 );
  581. }
  582. HRESULT _PutBooleanAttributes(
  583. IWbemClassObject* ipNewInst,
  584. UINT cNumAttributes,
  585. LPCTSTR* aAttributeNames,
  586. DWORD* aBitmasks,
  587. DWORD dwValue)
  588. {
  589. WBEM_VALIDATE_READ_PTR( aAttributeNames, cNumAttributes*sizeof(LPCTSTR) );
  590. WBEM_VALIDATE_READ_PTR( aBitmasks, cNumAttributes*sizeof(DWORD) );
  591. HRESULT hr = WBEM_S_NO_ERROR;
  592. CComVariant svar = true;
  593. for (UINT i = 0; i < cNumAttributes; i++)
  594. {
  595. WBEM_VALIDATE_IN_STRING_PTR( aAttributeNames[i] );
  596. if (dwValue & aBitmasks[i])
  597. {
  598. hr = ipNewInst->Put( aAttributeNames[i], 0, &svar, 0 );
  599. BREAK_ON_FAIL;
  600. }
  601. }
  602. return hr;
  603. }
  604. HRESULT _ExtractDomainName(
  605. LPCTSTR pszNamingContext,
  606. BSTR* pbstrDomainName )
  607. {
  608. WBEM_VALIDATE_IN_STRING_PTR( pszNamingContext );
  609. WBEM_VALIDATE_OUT_PTRPTR( pbstrDomainName );
  610. PDS_NAME_RESULTW pDsNameResult = NULL;
  611. HRESULT hr = WBEM_S_NO_ERROR;
  612. do {
  613. DWORD dwErr = DsCrackNamesW(
  614. (HANDLE)-1,
  615. DS_NAME_FLAG_SYNTACTICAL_ONLY,
  616. DS_FQDN_1779_NAME,
  617. DS_CANONICAL_NAME,
  618. 1,
  619. &pszNamingContext,
  620. &pDsNameResult);
  621. if (NO_ERROR != dwErr)
  622. {
  623. hr = HRESULT_FROM_WIN32( dwErr );
  624. ASSERT(false);
  625. break;
  626. }
  627. if ( BAD_IN_STRUCT_PTR(pDsNameResult)
  628. || 1 != pDsNameResult->cItems
  629. || DS_NAME_NO_ERROR != pDsNameResult->rItems->status
  630. || BAD_IN_STRUCT_PTR(pDsNameResult->rItems)
  631. || BAD_IN_STRING_PTR(pDsNameResult->rItems->pDomain)
  632. )
  633. {
  634. hr = E_FAIL;
  635. ASSERT(false);
  636. break;
  637. }
  638. *pbstrDomainName = ::SysAllocString(pDsNameResult->rItems->pDomain);
  639. if (NULL == *pbstrDomainName)
  640. {
  641. hr = WBEM_E_OUT_OF_MEMORY;
  642. break;
  643. }
  644. } while (false);
  645. if (pDsNameResult)
  646. {
  647. DsFreeNameResultW(pDsNameResult);
  648. }
  649. return hr;
  650. }
  651. // if this returns S_FALSE, skip this connection but do not consider this an error
  652. HRESULT CProvider::_PutAttributesStatus(
  653. IWbemClassObject** pipNewInst,
  654. const BSTR bstrFilterValue,
  655. DS_REPL_NEIGHBOR* pneighbor)
  656. {
  657. HRESULT hr = WBEM_S_NO_ERROR;
  658. if ( BAD_IN_STRING_PTR(pneighbor->pszNamingContext)
  659. || BAD_IN_STRING_PTR(pneighbor->pszSourceDsaDN)
  660. || BAD_IN_STRING_PTR_OPTIONAL(pneighbor->pszSourceDsaAddress)
  661. || BAD_IN_STRING_PTR_OPTIONAL(pneighbor->pszAsyncIntersiteTransportDN)
  662. )
  663. {
  664. ASSERT(false);
  665. return S_FALSE;
  666. }
  667. CComPtr<IADsPathname> spPathCracker;
  668. CComBSTR sbstrReplicatedDomain, // DNS name of replicated domain
  669. sbstrSourceServer, // CN= name of source server
  670. sbstrSourceSite, // name of site containing source server
  671. sbstrCompositeName; // composite name for WMI
  672. do {
  673. hr = _ExtractDomainName( pneighbor->pszNamingContext, &sbstrReplicatedDomain );
  674. BREAK_ON_FAIL;
  675. boolean bIsConfigNC = (0 == wcsnicmp(pneighbor->pszNamingContext,
  676. L"CN=Configuration,",
  677. 17));
  678. boolean bIsSchemaNC = (0 == wcsnicmp(pneighbor->pszNamingContext,
  679. L"CN=Schema,",
  680. 10));
  681. boolean bIsDeleted = (NULL != wcsstr(pneighbor->pszSourceDsaAddress, L"\nDEL:"));
  682. // retrieve source server name and site name
  683. hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
  684. IID_IADsPathname, (PVOID *)&spPathCracker);
  685. BREAK_ON_FAIL;
  686. ASSERT( !!spPathCracker );
  687. hr = spPathCracker->Set( pneighbor->pszSourceDsaDN, ADS_SETTYPE_DN );
  688. BREAK_ON_FAIL;
  689. hr = spPathCracker->SetDisplayType( ADS_DISPLAY_VALUE_ONLY );
  690. BREAK_ON_FAIL;
  691. hr = spPathCracker->GetElement( 1L, &sbstrSourceServer );
  692. BREAK_ON_FAIL;
  693. hr = spPathCracker->GetElement( 3L, &sbstrSourceSite );
  694. BREAK_ON_FAIL;
  695. // Build the composite name
  696. sbstrCompositeName = sbstrSourceSite;
  697. sbstrCompositeName += L"\\";
  698. sbstrCompositeName += sbstrSourceServer;
  699. sbstrCompositeName += L";";
  700. sbstrCompositeName += sbstrReplicatedDomain;
  701. if (bIsConfigNC)
  702. sbstrCompositeName += L",Configuration";
  703. else if (bIsSchemaNC)
  704. sbstrCompositeName += L",Schema";
  705. else
  706. sbstrCompositeName += L",Domain";
  707. // Test the composite name against the filter
  708. if ( NULL != bstrFilterValue
  709. && !lstrcmpi(sbstrCompositeName, bstrFilterValue)
  710. )
  711. {
  712. hr = S_FALSE;
  713. break;
  714. }
  715. //
  716. // Create a new instance of the data object
  717. //
  718. hr = m_sipClassDefStatus->SpawnInstance( 0, pipNewInst );
  719. BREAK_ON_FAIL;
  720. IWbemClassObject* ipNewInst = *pipNewInst;
  721. if (NULL == ipNewInst)
  722. {
  723. ASSERT(false);
  724. hr = S_FALSE;
  725. break;
  726. }
  727. CComVariant svar;
  728. svar = sbstrCompositeName;
  729. hr = ipNewInst->Put( L"CompositeName", 0, &svar, 0 );
  730. BREAK_ON_FAIL;
  731. svar = pneighbor->pszNamingContext;
  732. hr = ipNewInst->Put( L"NamingContext", 0, &svar, 0 );
  733. BREAK_ON_FAIL;
  734. svar = pneighbor->pszSourceDsaDN;
  735. hr = ipNewInst->Put( L"SourceDsaDN", 0, &svar, 0 );
  736. BREAK_ON_FAIL;
  737. svar = pneighbor->pszSourceDsaAddress;
  738. hr = ipNewInst->Put( L"SourceDsaAddress", 0, &svar, 0 );
  739. BREAK_ON_FAIL;
  740. svar = pneighbor->pszAsyncIntersiteTransportDN;
  741. hr = ipNewInst->Put( L"AsyncIntersiteTransportDN", 0, &svar, 0 );
  742. BREAK_ON_FAIL;
  743. svar = (long)pneighbor->dwReplicaFlags;
  744. hr = ipNewInst->Put( L"ReplicaFlags", 0, &svar, 0 );
  745. BREAK_ON_FAIL;
  746. if (bIsConfigNC)
  747. {
  748. svar = TRUE;
  749. hr = ipNewInst->Put( L"IsConfigurationNamingContext", 0, &svar, 0 );
  750. BREAK_ON_FAIL;
  751. }
  752. if (bIsSchemaNC)
  753. {
  754. svar = TRUE;
  755. hr = ipNewInst->Put( L"IsSchemaNamingContext", 0, &svar, 0 );
  756. BREAK_ON_FAIL;
  757. }
  758. if (bIsDeleted)
  759. {
  760. svar = TRUE;
  761. hr = ipNewInst->Put( L"IsDeletedSourceDsa", 0, &svar, 0 );
  762. BREAK_ON_FAIL;
  763. }
  764. svar = sbstrSourceSite;
  765. hr = ipNewInst->Put( L"SourceDsaSite", 0, &svar, 0 );
  766. BREAK_ON_FAIL;
  767. svar = sbstrSourceServer;
  768. hr = ipNewInst->Put( L"SourceDsaCN", 0, &svar, 0 );
  769. BREAK_ON_FAIL;
  770. svar = sbstrReplicatedDomain;
  771. hr = ipNewInst->Put( L"Domain", 0, &svar, 0 );
  772. BREAK_ON_FAIL;
  773. LPCTSTR aBooleanAttrNames[12] = {
  774. TEXT("Writeable"),
  775. TEXT("SyncOnStartup"),
  776. TEXT("DoScheduledSyncs"),
  777. TEXT("UseAsyncIntersiteTransport"),
  778. TEXT("TwoWaySync"),
  779. TEXT("FullSyncInProgress"),
  780. TEXT("FullSyncNextPacket"),
  781. TEXT("NeverSynced"),
  782. TEXT("IgnoreChangeNotifications"),
  783. TEXT("DisableScheduledSync"),
  784. TEXT("CompressChanges"),
  785. TEXT("NoChangeNotifications")
  786. };
  787. DWORD aBitmasks[12] = {
  788. DS_REPL_NBR_WRITEABLE,
  789. DS_REPL_NBR_SYNC_ON_STARTUP,
  790. DS_REPL_NBR_DO_SCHEDULED_SYNCS,
  791. DS_REPL_NBR_USE_ASYNC_INTERSITE_TRANSPORT,
  792. DS_REPL_NBR_TWO_WAY_SYNC,
  793. DS_REPL_NBR_FULL_SYNC_IN_PROGRESS,
  794. DS_REPL_NBR_FULL_SYNC_NEXT_PACKET,
  795. DS_REPL_NBR_NEVER_SYNCED,
  796. DS_REPL_NBR_IGNORE_CHANGE_NOTIFICATIONS,
  797. DS_REPL_NBR_DISABLE_SCHEDULED_SYNC,
  798. DS_REPL_NBR_COMPRESS_CHANGES,
  799. DS_REPL_NBR_NO_CHANGE_NOTIFICATIONS
  800. };
  801. hr = _PutBooleanAttributes( ipNewInst,
  802. 12,
  803. aBooleanAttrNames,
  804. aBitmasks,
  805. pneighbor->dwReplicaFlags );
  806. BREAK_ON_FAIL;
  807. hr = _PutUUIDAttribute( ipNewInst,
  808. L"NamingContextObjGuid",
  809. pneighbor->uuidNamingContextObjGuid );
  810. BREAK_ON_FAIL;
  811. hr = _PutUUIDAttribute( ipNewInst,
  812. L"SourceDsaObjGuid",
  813. pneighbor->uuidSourceDsaObjGuid );
  814. BREAK_ON_FAIL;
  815. hr = _PutUUIDAttribute( ipNewInst,
  816. L"SourceDsaInvocationID",
  817. pneighbor->uuidSourceDsaInvocationID );
  818. BREAK_ON_FAIL;
  819. hr = _PutUUIDAttribute( ipNewInst,
  820. L"AsyncIntersiteTransportObjGuid",
  821. pneighbor->uuidAsyncIntersiteTransportObjGuid );
  822. BREAK_ON_FAIL;
  823. hr = _PutLONGLONGAttribute( ipNewInst,
  824. L"LastObjChangeSynced",
  825. pneighbor->usnLastObjChangeSynced);
  826. BREAK_ON_FAIL;
  827. hr = _PutLONGLONGAttribute( ipNewInst,
  828. L"AttributeFilter",
  829. pneighbor->usnAttributeFilter);
  830. BREAK_ON_FAIL;
  831. hr = _PutFILETIMEAttribute( ipNewInst,
  832. L"LastSyncSuccess",
  833. pneighbor->ftimeLastSyncSuccess);
  834. BREAK_ON_FAIL;
  835. hr = _PutFILETIMEAttribute( ipNewInst,
  836. L"LastSyncAttempt",
  837. pneighbor->ftimeLastSyncAttempt);
  838. BREAK_ON_FAIL;
  839. svar = (long)pneighbor->dwLastSyncResult;
  840. hr = ipNewInst->Put( L"LastSyncResult", 0, &svar, 0 );
  841. BREAK_ON_FAIL;
  842. svar = (long)pneighbor->cNumConsecutiveSyncFailures;
  843. hr = ipNewInst->Put( L"NumConsecutiveSyncFailures", 0, &svar, 0 );
  844. BREAK_ON_FAIL;
  845. svar = (long)((bIsDeleted) ? 0L : pneighbor->cNumConsecutiveSyncFailures);
  846. hr = ipNewInst->Put( L"ModifiedNumConsecutiveSyncFailures", 0, &svar, 0 );
  847. BREAK_ON_FAIL;
  848. } while (false);
  849. return hr;
  850. }
  851. // if this returns S_FALSE, skip this connection but do not consider this an error
  852. // note, this version does not create or release the instance
  853. HRESULT CProvider::_PutAttributesDC(
  854. IN IWbemClassObject* pIndicateItem,
  855. IN IADsPathname* pPathCracker,
  856. IN const BSTR bstrFilterValue,
  857. IN IDirectorySearch* pIADsSearch,
  858. IN ADS_SEARCH_HANDLE hSearch)
  859. {
  860. WBEM_VALIDATE_INTF_PTR( pIndicateItem );
  861. WBEM_VALIDATE_INTF_PTR( pPathCracker );
  862. HRESULT hr = WBEM_S_NO_ERROR;
  863. ADS_SEARCH_COLUMN adscolDN, adscolGUID;
  864. boolean fFreeColumnDN = false, fFreeColumnGUID = false;
  865. CComVariant svar;
  866. CComBSTR sbstrServerCN, sbstrSite;
  867. do {
  868. hr = pIADsSearch->GetColumn( hSearch, L"distinguishedName", &adscolDN );
  869. BREAK_ON_FAIL;
  870. fFreeColumnDN = true;
  871. if ( ADSTYPE_DN_STRING != adscolDN.dwADsType
  872. || 1 != adscolDN.dwNumValues
  873. || BAD_IN_STRUCT_PTR(adscolDN.pADsValues)
  874. || BAD_IN_STRING_PTR(adscolDN.pADsValues[0].DNString)
  875. )
  876. {
  877. // skip this one
  878. hr = S_FALSE;
  879. break;
  880. }
  881. hr = pIADsSearch->GetColumn( hSearch, L"objectGUID", &adscolGUID );
  882. BREAK_ON_FAIL;
  883. fFreeColumnGUID = true;
  884. if ( ADSTYPE_OCTET_STRING != adscolGUID.dwADsType
  885. || 1 != adscolGUID.dwNumValues
  886. || BAD_IN_STRUCT_PTR(adscolGUID.pADsValues)
  887. || 0 == adscolGUID.pADsValues[0].OctetString.dwLength
  888. || BAD_IN_READ_PTR(adscolGUID.pADsValues[0].OctetString.lpValue,
  889. adscolGUID.pADsValues[0].OctetString.dwLength)
  890. )
  891. {
  892. // skip this one
  893. hr = S_FALSE;
  894. break;
  895. }
  896. hr = pPathCracker->Set( adscolDN.pADsValues[0].DNString, ADS_SETTYPE_DN );
  897. BREAK_ON_FAIL;
  898. hr = pPathCracker->GetElement( 1L, &sbstrServerCN );
  899. BREAK_ON_FAIL;
  900. hr = pPathCracker->GetElement( 3L, &sbstrSite );
  901. BREAK_ON_FAIL;
  902. // Test the site name against the filter
  903. if ( NULL != bstrFilterValue
  904. && !lstrcmpi(sbstrSite, bstrFilterValue)
  905. )
  906. {
  907. hr = S_FALSE;
  908. break;
  909. }
  910. svar = adscolDN.pADsValues[0].DNString;
  911. hr = pIndicateItem->Put( L"DistinguishedName", 0, &svar, 0 );
  912. BREAK_ON_FAIL;
  913. svar = sbstrServerCN;
  914. hr = pIndicateItem->Put( L"CommonName", 0, &svar, 0 );
  915. BREAK_ON_FAIL;
  916. svar = sbstrSite;
  917. hr = pIndicateItem->Put( L"SiteName", 0, &svar, 0 );
  918. BREAK_ON_FAIL;
  919. hr = _PutUUIDAttribute( pIndicateItem,
  920. L"ObjectGUID",
  921. (GUID&)adscolGUID.pADsValues[0].OctetString.lpValue );
  922. BREAK_ON_FAIL;
  923. } while (false);
  924. if (fFreeColumnDN)
  925. {
  926. HRESULT hr2 = pIADsSearch->FreeColumn( &adscolDN );
  927. ASSERT( SUCCEEDED(hr2) );
  928. }
  929. if (fFreeColumnGUID)
  930. {
  931. HRESULT hr2 = pIADsSearch->FreeColumn( &adscolGUID );
  932. ASSERT( SUCCEEDED(hr2) );
  933. }
  934. return hr;
  935. }
  936. HRESULT CProvider::_BuildIndicateArrayStatus(
  937. IN DS_REPL_NEIGHBORS* pneighborstruct,
  938. IN const BSTR bstrFilterValue,
  939. OUT IWbemClassObject*** ppaIndicateItems,
  940. OUT DWORD* pcIndicateItems)
  941. {
  942. WBEM_VALIDATE_IN_STRUCT_PTR( pneighborstruct );
  943. WBEM_VALIDATE_IN_MULTISTRUCT_PTR( pneighborstruct->rgNeighbor,
  944. pneighborstruct->cNumNeighbors );
  945. WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL( bstrFilterValue );
  946. WBEM_VALIDATE_OUT_PTRPTR( ppaIndicateItems );
  947. WBEM_VALIDATE_OUT_STRUCT_PTR( pcIndicateItems );
  948. HRESULT hr = WBEM_S_NO_ERROR;
  949. DS_REPL_NEIGHBOR* pneighbors = pneighborstruct->rgNeighbor;
  950. DWORD cneighbors = pneighborstruct->cNumNeighbors;
  951. if (0 == cneighbors)
  952. return WBEM_S_NO_ERROR;
  953. IWbemClassObject** paIndicateItems = NULL;
  954. DWORD cIndicateItems = 0;
  955. *ppaIndicateItems = NULL;
  956. *pcIndicateItems = 0;
  957. do
  958. {
  959. paIndicateItems = new IWbemClassObject*[cneighbors];
  960. if (NULL == paIndicateItems)
  961. {
  962. ASSERT(false);
  963. hr = WBEM_E_OUT_OF_MEMORY;
  964. break;
  965. }
  966. ::ZeroMemory( paIndicateItems, cneighbors * sizeof(IWbemClassObject*) );
  967. for (DWORD i = 0; i < cneighbors; i++)
  968. {
  969. DS_REPL_NEIGHBOR* pneighbor = &(pneighbors[i]);
  970. hr = _PutAttributesStatus( &paIndicateItems[cIndicateItems],
  971. bstrFilterValue,
  972. pneighbor );
  973. if (S_FALSE == hr)
  974. continue;
  975. cIndicateItems++;
  976. BREAK_ON_FAIL;
  977. }
  978. } while (false);
  979. if (!FAILED(hr))
  980. {
  981. *ppaIndicateItems = paIndicateItems;
  982. *pcIndicateItems = cIndicateItems;
  983. }
  984. else
  985. {
  986. _ReleaseIndicateArray( paIndicateItems, cneighbors );
  987. }
  988. return hr;
  989. }
  990. /*
  991. HRESULT CProvider::_BuildIndicateArrayDC(
  992. IN DS_DOMAIN_CONTROLLER_INFO_1* pDCs,
  993. IN ULONG cDCs,
  994. IN const BSTR bstrFilterValue,
  995. OUT IWbemClassObject*** ppaIndicateItems,
  996. OUT DWORD* pcIndicateItems)
  997. {
  998. WBEM_VALIDATE_IN_MULTISTRUCT_PTR( pDCs, cDCs );
  999. WBEM_VALIDATE_IN_STRING_PTR_OPTIONAL( bstrFilterValue );
  1000. WBEM_VALIDATE_OUT_PTRPTR( ppaIndicateItems );
  1001. WBEM_VALIDATE_OUT_STRUCT_PTR( pcIndicateItems );
  1002. HRESULT hr = WBEM_S_NO_ERROR;
  1003. if (0 == cDCs)
  1004. return WBEM_S_NO_ERROR;
  1005. IWbemClassObject** paIndicateItems = NULL;
  1006. DWORD cIndicateItems = 0;
  1007. *ppaIndicateItems = NULL;
  1008. *pcIndicateItems = 0;
  1009. do
  1010. {
  1011. paIndicateItems = new IWbemClassObject*[cDCs];
  1012. if (NULL == paIndicateItems)
  1013. {
  1014. ASSERT(false);
  1015. hr = WBEM_E_OUT_OF_MEMORY;
  1016. break;
  1017. }
  1018. ::ZeroMemory( paIndicateItems, cDCs * sizeof(IWbemClassObject*) );
  1019. for (DWORD i = 0; i < cDCs; i++)
  1020. {
  1021. DS_DOMAIN_CONTROLLER_INFO_1* pDC = &(pDCs[i]);
  1022. hr = _PutAttributesDC( &paIndicateItems[cIndicateItems],
  1023. bstrFilterValue,
  1024. pDC );
  1025. if (S_FALSE == hr)
  1026. continue;
  1027. cIndicateItems++;
  1028. BREAK_ON_FAIL;
  1029. }
  1030. } while (false);
  1031. if (!FAILED(hr))
  1032. {
  1033. *ppaIndicateItems = paIndicateItems;
  1034. *pcIndicateItems = cIndicateItems;
  1035. }
  1036. else
  1037. {
  1038. _ReleaseIndicateArray( paIndicateItems, cDCs );
  1039. }
  1040. return hr;
  1041. }
  1042. */
  1043. void CProvider::_ReleaseIndicateArray(
  1044. IWbemClassObject** paIndicateItems,
  1045. DWORD cIndicateItems,
  1046. bool fReleaseArray)
  1047. {
  1048. if (paIndicateItems != NULL)
  1049. {
  1050. for (DWORD i = 0; i < cIndicateItems; i++)
  1051. {
  1052. if (NULL != paIndicateItems[i])
  1053. paIndicateItems[i]->Release();
  1054. }
  1055. if (fReleaseArray)
  1056. {
  1057. delete[] paIndicateItems;
  1058. }
  1059. else
  1060. {
  1061. ::ZeroMemory( *paIndicateItems,
  1062. cIndicateItems * sizeof(IWbemClassObject*) );
  1063. }
  1064. }
  1065. }