Leaked source code of windows server 2003
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.

1196 lines
33 KiB

  1. //=============================================================================
  2. //
  3. // Copyright (c) 1996-1999, Microsoft Corporation, All rights reserved
  4. //
  5. // CONPROV.CPP
  6. //
  7. // This file implements the classes for event consumer provider caching.
  8. //
  9. // Classes implemented:
  10. //
  11. // CConsumerProviderRecord --- a single consumer provider record
  12. // CConsumerProviderCache --- a collection of records.
  13. //
  14. // History:
  15. //
  16. // 11/27/96 a-levn Compiles.
  17. //
  18. //=============================================================================
  19. #include "precomp.h"
  20. #include "ess.h"
  21. #include "consprov.h"
  22. #include <genutils.h>
  23. #include <cominit.h>
  24. #include "NCEvents.h"
  25. CConsumerProviderRecord::CConsumerProviderRecord(CEssNamespace* pNamespace)
  26. : m_pLogicalProvider(NULL), m_pConsumerProvider(NULL),
  27. m_pSink(NULL), m_bResolved(FALSE), m_pNamespace(pNamespace),
  28. m_lRef(0), m_wszMachineName(NULL), m_wszProviderName(NULL),
  29. m_wszProviderRef(NULL), m_bAnonymous(FALSE)
  30. {
  31. m_pNamespace->AddRef();
  32. }
  33. HRESULT CConsumerProviderRecord::Initialize(
  34. IWbemClassObject* pLogicalProvider,
  35. LPCWSTR wszProviderRef,
  36. LPCWSTR wszProviderName,
  37. LPCWSTR wszMachineName)
  38. {
  39. m_LastAccess = CWbemTime::GetCurrentTime();
  40. m_pLogicalProvider = pLogicalProvider;
  41. m_pLogicalProvider->AddRef();
  42. if(wszMachineName)
  43. m_wszMachineName = CloneWstr(wszMachineName);
  44. m_wszProviderName = CloneWstr(wszProviderName);
  45. m_wszProviderRef = CloneWstr(wszProviderRef);
  46. if(m_wszProviderName == NULL || m_wszProviderRef == NULL)
  47. return WBEM_E_OUT_OF_MEMORY;
  48. // Extract the CLSID
  49. // =================
  50. VARIANT vClassId;
  51. VariantInit(&vClassId);
  52. CClearMe cm(&vClassId);
  53. HRESULT hres = pLogicalProvider->Get(CONSPROV_CLSID_PROPNAME, 0, &vClassId,
  54. NULL, NULL);
  55. if(FAILED(hres) || V_VT(&vClassId) != VT_BSTR)
  56. {
  57. ERRORTRACE((LOG_ESS, "Class ID is missing from consumer "
  58. "provider record!!\n"));
  59. return hres;
  60. }
  61. if(FAILED(CLSIDFromString(V_BSTR(&vClassId), &m_clsid)))
  62. {
  63. ERRORTRACE((LOG_ESS, "INVALID Class ID in consumer "
  64. "provider record!!\n"));
  65. return WBEM_E_INVALID_PROVIDER_REGISTRATION;
  66. }
  67. return WBEM_S_NO_ERROR;
  68. }
  69. CConsumerProviderRecord::~CConsumerProviderRecord()
  70. {
  71. _DBG_ASSERT( m_pNamespace != NULL );
  72. if(m_pLogicalProvider)
  73. m_pLogicalProvider->Release();
  74. if(m_pSink)
  75. m_pNamespace->PostponeRelease(m_pSink);
  76. if(m_pConsumerProvider)
  77. m_pNamespace->PostponeRelease(m_pConsumerProvider);
  78. if(m_pSink || m_pConsumerProvider)
  79. {
  80. //
  81. // Report the MSFT_WmiConsumerProviderUnloaded event.
  82. //
  83. FIRE_NCEVENT(
  84. g_hNCEvents[MSFT_WmiConsumerProviderUnloaded],
  85. WMI_SENDCOMMIT_SET_NOT_REQUIRED,
  86. // Data follows...
  87. m_pNamespace->GetName(),
  88. m_wszProviderName,
  89. m_wszMachineName);
  90. }
  91. if(m_pNamespace)
  92. m_pNamespace->Release();
  93. delete [] m_wszMachineName;
  94. delete [] m_wszProviderName;
  95. delete [] m_wszProviderRef;
  96. }
  97. long CConsumerProviderRecord::AddRef()
  98. {
  99. return InterlockedIncrement(&m_lRef);
  100. }
  101. long CConsumerProviderRecord::Release()
  102. {
  103. long lRef = InterlockedDecrement(&m_lRef);
  104. if(lRef == 0)
  105. delete this;
  106. return lRef;
  107. }
  108. void CConsumerProviderRecord::Invalidate()
  109. {
  110. IWbemUnboundObjectSink* pSink;
  111. IWbemEventConsumerProvider* pConsumerProvider;
  112. {
  113. CInCritSec ics(&m_cs);
  114. pSink = m_pSink;
  115. m_pSink = NULL;
  116. pConsumerProvider = m_pConsumerProvider;
  117. m_pConsumerProvider = NULL;
  118. m_bResolved = FALSE;
  119. }
  120. _DBG_ASSERT( m_pNamespace != NULL );
  121. if (pSink)
  122. m_pNamespace->PostponeRelease(pSink);
  123. if (pConsumerProvider)
  124. m_pNamespace->PostponeRelease(pConsumerProvider);
  125. if (pConsumerProvider || pSink)
  126. {
  127. //
  128. // Report the MSFT_WmiConsumerProviderUnloaded event.
  129. //
  130. FIRE_NCEVENT(
  131. g_hNCEvents[MSFT_WmiConsumerProviderUnloaded],
  132. WMI_SENDCOMMIT_SET_NOT_REQUIRED,
  133. // Data follows...
  134. m_pNamespace->GetName(),
  135. m_wszProviderName,
  136. m_wszMachineName);
  137. }
  138. }
  139. HRESULT CConsumerProviderRecord::ValidateConsumer(
  140. IWbemClassObject* pLogicalConsumer)
  141. {
  142. HRESULT hres;
  143. // Check if consumer provider is cached
  144. // ====================================
  145. IWbemEventConsumerProvider* pConsumerProvider = NULL;
  146. IWbemEventConsumerProviderEx* pConsumerProviderEx = NULL;
  147. BOOL bResolved = FALSE;
  148. {
  149. CInCritSec ics(&m_cs);
  150. m_LastAccess = CWbemTime::GetCurrentTime();
  151. if(m_bResolved)
  152. {
  153. if(m_pConsumerProviderEx)
  154. {
  155. pConsumerProviderEx = m_pConsumerProviderEx;
  156. pConsumerProviderEx->AddRef();
  157. }
  158. else
  159. {
  160. pConsumerProvider = m_pConsumerProvider;
  161. if(pConsumerProvider)
  162. pConsumerProvider->AddRef();
  163. }
  164. bResolved = TRUE;
  165. }
  166. }
  167. // Resolve if not cached
  168. // =====================
  169. if(!bResolved)
  170. {
  171. IWbemUnboundObjectSink* pGlobalSink;
  172. hres = ResolveAndCache(&pGlobalSink, &pConsumerProvider,
  173. &pConsumerProviderEx);
  174. if(FAILED(hres)) return hres;
  175. if(pGlobalSink)
  176. pGlobalSink->Release();
  177. }
  178. CReleaseMe rm1(pConsumerProvider);
  179. CReleaseMe rm2(pConsumerProviderEx);
  180. if(pConsumerProvider == NULL && pConsumerProviderEx)
  181. {
  182. //
  183. // Clearly, this consumer does not support validation
  184. //
  185. return WBEM_S_FALSE;
  186. }
  187. try
  188. {
  189. if(pConsumerProviderEx)
  190. {
  191. hres = pConsumerProviderEx->ValidateSubscription(pLogicalConsumer);
  192. }
  193. else
  194. {
  195. //
  196. // Old-type provider --- we can still achieve validation by calling
  197. // FindConsumer --- it might reject this consumer at that time
  198. //
  199. IWbemUnboundObjectSink* pSink = NULL;
  200. hres = pConsumerProvider->FindConsumer(pLogicalConsumer, &pSink);
  201. if(SUCCEEDED(hres) && pSink)
  202. pSink->Release();
  203. }
  204. }
  205. catch(...)
  206. {
  207. ERRORTRACE((LOG_ESS, "Event consumer provider %S in namespace %S "
  208. "threw an exception in ValidateConsumer/FindConsumer\n",
  209. m_wszProviderName, m_pNamespace->GetName()));
  210. hres = WBEM_E_PROVIDER_FAILURE;
  211. }
  212. return hres;
  213. }
  214. HRESULT CConsumerProviderRecord::GetGlobalObjectSink(
  215. OUT IWbemUnboundObjectSink** ppSink,
  216. IN IWbemClassObject *pLogicalProvider)
  217. {
  218. *ppSink = NULL;
  219. // Check of a cached version is available
  220. // ======================================
  221. {
  222. CInCritSec ics(&m_cs);
  223. m_LastAccess = CWbemTime::GetCurrentTime();
  224. if(m_bResolved)
  225. {
  226. // It is --- return it
  227. // ===================
  228. *ppSink = m_pSink;
  229. if(m_pSink)
  230. m_pSink->AddRef();
  231. return WBEM_S_NO_ERROR;
  232. }
  233. }
  234. // No cached version --- retrieve it
  235. // =================================
  236. IWbemUnboundObjectSink* pSink;
  237. IWbemEventConsumerProvider* pConsumerProvider;
  238. IWbemEventConsumerProviderEx* pConsumerProviderEx;
  239. HRESULT hres = ResolveAndCache(&pSink, &pConsumerProvider,
  240. &pConsumerProviderEx);
  241. if(FAILED(hres))
  242. return hres;
  243. if(pConsumerProvider)
  244. pConsumerProvider->Release();
  245. if(pConsumerProviderEx)
  246. pConsumerProviderEx->Release();
  247. *ppSink = pSink;
  248. if (*ppSink != NULL)
  249. {
  250. //
  251. // Report the MSFT_WmiConsumerProviderSinkLoaded event.
  252. //
  253. FireNCSinkEvent(
  254. MSFT_WmiConsumerProviderSinkLoaded,
  255. pLogicalProvider);
  256. }
  257. return WBEM_S_NO_ERROR;
  258. }
  259. HRESULT CConsumerProviderRecord::ResolveAndCache(
  260. IWbemUnboundObjectSink** ppSink,
  261. IWbemEventConsumerProvider** ppConsumerProvider,
  262. IWbemEventConsumerProviderEx** ppConsumerProviderEx)
  263. {
  264. // Resolve it first
  265. // ================
  266. HRESULT hres = Resolve(ppSink, ppConsumerProvider, ppConsumerProviderEx);
  267. if(FAILED(hres))
  268. return hres;
  269. // Cache if needed
  270. // ===============
  271. {
  272. CInCritSec ics(&m_cs);
  273. m_LastAccess = CWbemTime::GetCurrentTime();
  274. if(m_bResolved)
  275. {
  276. // Already cached. Release ours.
  277. // ==============================
  278. if(*ppSink)
  279. (*ppSink)->Release();
  280. if(*ppConsumerProvider)
  281. (*ppConsumerProvider)->Release();
  282. if(*ppConsumerProviderEx)
  283. (*ppConsumerProviderEx)->Release();
  284. // Use the cached one
  285. // ==================
  286. *ppSink = m_pSink;
  287. if(m_pSink)
  288. m_pSink->AddRef();
  289. *ppConsumerProvider = m_pConsumerProvider;
  290. if(m_pConsumerProvider)
  291. m_pConsumerProvider->AddRef();
  292. *ppConsumerProviderEx = m_pConsumerProviderEx;
  293. if(m_pConsumerProviderEx)
  294. m_pConsumerProviderEx->AddRef();
  295. }
  296. else
  297. {
  298. // Cache it
  299. // ========
  300. m_pSink = *ppSink;
  301. if(m_pSink)
  302. m_pSink->AddRef();
  303. m_pConsumerProvider = *ppConsumerProvider;
  304. if(m_pConsumerProvider)
  305. m_pConsumerProvider->AddRef();
  306. m_pConsumerProviderEx = *ppConsumerProviderEx;
  307. if(m_pConsumerProviderEx)
  308. m_pConsumerProviderEx->AddRef();
  309. m_bResolved = TRUE;
  310. }
  311. }
  312. return S_OK;
  313. }
  314. void CConsumerProviderRecord::FireNCSinkEvent(
  315. DWORD dwIndex,
  316. IWbemClassObject *pLogicalConsumer)
  317. {
  318. if (IS_NCEVENT_ACTIVE(dwIndex))
  319. {
  320. // Get the path of the logical consumer.
  321. VARIANT vPath;
  322. BSTR strLogicalConsumerPath;
  323. VariantInit(&vPath);
  324. if (pLogicalConsumer &&
  325. SUCCEEDED(pLogicalConsumer->Get(L"__PATH", 0, &vPath, NULL, NULL)))
  326. strLogicalConsumerPath = V_BSTR(&vPath);
  327. else
  328. strLogicalConsumerPath = NULL;
  329. //
  330. // Report the event.
  331. //
  332. FIRE_NCEVENT(
  333. g_hNCEvents[dwIndex],
  334. WMI_SENDCOMMIT_SET_NOT_REQUIRED,
  335. // Data follows...
  336. m_pNamespace->GetName(),
  337. m_wszProviderName,
  338. m_wszMachineName,
  339. strLogicalConsumerPath);
  340. VariantClear(&vPath);
  341. }
  342. }
  343. HRESULT CConsumerProviderRecord::FindConsumer(
  344. IN IWbemClassObject* pLogicalConsumer,
  345. OUT IWbemUnboundObjectSink** ppSink)
  346. {
  347. HRESULT hres;
  348. // Check if consumer provider is cached
  349. // ====================================
  350. IWbemEventConsumerProvider* pConsumerProvider = NULL;
  351. BOOL bResolved = FALSE;
  352. {
  353. CInCritSec ics(&m_cs);
  354. m_LastAccess = CWbemTime::GetCurrentTime();
  355. if(m_bResolved)
  356. {
  357. pConsumerProvider = m_pConsumerProvider;
  358. if(pConsumerProvider)
  359. pConsumerProvider->AddRef();
  360. bResolved = TRUE;
  361. }
  362. }
  363. // Resolve if not cached
  364. // =====================
  365. if(!bResolved)
  366. {
  367. IWbemUnboundObjectSink* pGlobalSink;
  368. IWbemEventConsumerProviderEx* pConsumerProviderEx = NULL;
  369. hres = ResolveAndCache(&pGlobalSink, &pConsumerProvider,
  370. &pConsumerProviderEx);
  371. if(FAILED(hres)) return hres;
  372. if(pGlobalSink)
  373. pGlobalSink->Release();
  374. if(pConsumerProviderEx)
  375. pConsumerProviderEx->Release();
  376. }
  377. if(pConsumerProvider == NULL)
  378. return E_NOINTERFACE;
  379. try
  380. {
  381. hres = pConsumerProvider->FindConsumer(pLogicalConsumer, ppSink);
  382. }
  383. catch(...)
  384. {
  385. ERRORTRACE((LOG_ESS, "Event consumer provider %S in namespace %S "
  386. "threw an exception in FindConsumer\n",
  387. m_wszProviderName, m_pNamespace->GetName()));
  388. hres = WBEM_E_PROVIDER_FAILURE;
  389. }
  390. if(SUCCEEDED(hres) && ppSink != NULL)
  391. {
  392. if(*ppSink == NULL)
  393. {
  394. ERRORTRACE((LOG_ESS, "Event consumer provider %S in namespace %S "
  395. "returned success from IWbemEventConsumerProvider::FindConsumer"
  396. " call while returning a NULL sink. This behavior is invalid! "
  397. " Consumers will not receive events.\n",
  398. m_wszProviderName, m_pNamespace->GetName()));
  399. return E_NOINTERFACE;
  400. }
  401. //
  402. // Report the MSFT_WmiConsumerProviderSinkLoaded event.
  403. //
  404. FireNCSinkEvent(
  405. MSFT_WmiConsumerProviderSinkLoaded,
  406. pLogicalConsumer);
  407. // Configure proxy settings
  408. // ========================
  409. if(m_bAnonymous)
  410. {
  411. hres = SetInterfaceSecurity(*ppSink, NULL, NULL, NULL,
  412. RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS);
  413. }
  414. else
  415. {
  416. hres = WbemSetDynamicCloaking(*ppSink, RPC_C_AUTHN_LEVEL_CONNECT,
  417. RPC_C_IMP_LEVEL_IDENTIFY);
  418. }
  419. if(FAILED(hres))
  420. return hres;
  421. else
  422. hres = WBEM_S_NO_ERROR;
  423. }
  424. pConsumerProvider->Release();
  425. return hres;
  426. }
  427. HRESULT CConsumerProviderRecord::Resolve(
  428. IWbemUnboundObjectSink** ppSink,
  429. IWbemEventConsumerProvider** ppConsumerProvider,
  430. IWbemEventConsumerProviderEx** ppConsumerProviderEx)
  431. {
  432. HRESULT hres;
  433. // Prepare for CoCreateInstance(Ex)
  434. // ================================
  435. COSERVERINFO* pServerInfo = NULL;
  436. DWORD dwClsCtx;
  437. if(m_wszMachineName)
  438. {
  439. pServerInfo = _new COSERVERINFO;
  440. if(pServerInfo == NULL)
  441. return WBEM_E_OUT_OF_MEMORY;
  442. pServerInfo->pwszName = m_wszMachineName;
  443. pServerInfo->pAuthInfo = NULL;
  444. pServerInfo->dwReserved1 = 0;
  445. pServerInfo->dwReserved2 = 0;
  446. dwClsCtx = CLSCTX_REMOTE_SERVER | CLSCTX_LOCAL_SERVER;
  447. }
  448. else
  449. {
  450. dwClsCtx = CLSCTX_ALL;
  451. }
  452. CDeleteMe<COSERVERINFO> dm(pServerInfo);
  453. IUnknown* pProtoSink = NULL;
  454. if(m_wszMachineName)
  455. {
  456. //
  457. // Remote activation --- do everything ourselves
  458. //
  459. IClassFactory* pFactory;
  460. hres = WbemCoGetClassObject(m_clsid, dwClsCtx, pServerInfo,
  461. IID_IClassFactory, (void**)&pFactory);
  462. if(FAILED(hres))
  463. {
  464. ERRORTRACE((LOG_ESS,
  465. "Failed to get a class factory for CLSID on server %S. "
  466. "Return code %X\n",
  467. (pServerInfo?pServerInfo->pwszName:L"(local)"), hres));
  468. return hres;
  469. }
  470. CReleaseMe rm0(pFactory);
  471. if(pFactory == NULL)
  472. {
  473. ERRORTRACE((LOG_ESS, "NULL Class Factory received from event consumer "
  474. "%S. Consumer needs to have its code examined\n",
  475. m_wszProviderName));
  476. return WBEM_E_PROVIDER_LOAD_FAILURE;
  477. }
  478. // Get the instance
  479. // ================
  480. hres = pFactory->CreateInstance(NULL, IID_IUnknown, (void**)&pProtoSink);
  481. if(FAILED(hres))
  482. {
  483. //
  484. // Try again at lower security
  485. //
  486. SetInterfaceSecurity(pFactory, NULL, NULL, NULL,
  487. RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS);
  488. hres = pFactory->CreateInstance(NULL, IID_IUnknown, (void**)&pProtoSink);
  489. if(SUCCEEDED(hres))
  490. m_bAnonymous = TRUE;
  491. }
  492. if(FAILED(hres))
  493. {
  494. ERRORTRACE((LOG_ESS,
  495. "Failed to create an instance from a class factory for %S. "
  496. " Return code: %X\n", m_wszProviderName, hres));
  497. return hres;
  498. }
  499. if(pProtoSink == NULL)
  500. {
  501. ERRORTRACE((LOG_ESS, "NULL object received from event consumer "
  502. "%S factory. Consumer needs to have its code examined\n",
  503. m_wszProviderName));
  504. return WBEM_E_PROVIDER_LOAD_FAILURE;
  505. }
  506. }
  507. else // not REMOTE_SERVER
  508. {
  509. //
  510. // Use PSS
  511. //
  512. hres = m_pNamespace->LoadConsumerProvider(m_wszProviderName,
  513. &pProtoSink);
  514. if(FAILED(hres))
  515. {
  516. ERRORTRACE((LOG_ESS, "ESS unable to load consumer provider %S from "
  517. "provider subsystem: 0x%X\n",
  518. (LPCWSTR)m_wszProviderName, hres));
  519. return hres;
  520. }
  521. }
  522. CReleaseMe rm1(pProtoSink);
  523. if(m_bAnonymous)
  524. SetInterfaceSecurity(pProtoSink, NULL, NULL, NULL,
  525. RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS);
  526. // Query for the interfaces
  527. // ========================
  528. *ppSink = NULL;
  529. hres = pProtoSink->QueryInterface(IID_IWbemUnboundObjectSink,
  530. (void**)ppSink);
  531. if(FAILED(hres))
  532. {
  533. DEBUGTRACE((LOG_ESS,
  534. "Consumer provider %S does not support "
  535. "IWbemUnboundObjectSink: error code %X\n",
  536. m_wszProviderName, hres));
  537. }
  538. else
  539. {
  540. if(*ppSink == NULL)
  541. {
  542. ERRORTRACE((LOG_ESS, "NULL object received from event consumer "
  543. "%S QueryInterface. Consumer needs to have its code examined\n",
  544. m_wszProviderName));
  545. return WBEM_E_PROVIDER_LOAD_FAILURE;
  546. }
  547. // Configure proxy settings
  548. // ========================
  549. if(m_bAnonymous)
  550. {
  551. hres = SetInterfaceSecurity(*ppSink, NULL, NULL, NULL,
  552. RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS);
  553. }
  554. else
  555. {
  556. hres = WbemSetDynamicCloaking(*ppSink, RPC_C_AUTHN_LEVEL_CONNECT,
  557. RPC_C_IMP_LEVEL_IDENTIFY);
  558. }
  559. if(FAILED(hres))
  560. return hres;
  561. }
  562. *ppConsumerProvider = NULL;
  563. hres = pProtoSink->QueryInterface(IID_IWbemEventConsumerProvider,
  564. (void**)ppConsumerProvider);
  565. if(FAILED(hres))
  566. {
  567. }
  568. else if(*ppConsumerProvider == NULL)
  569. {
  570. ERRORTRACE((LOG_ESS, "NULL object received from event consumer "
  571. "%S QueryInterface. Consumer needs to have its code examined\n",
  572. m_wszProviderName));
  573. return WBEM_E_PROVIDER_LOAD_FAILURE;
  574. }
  575. else
  576. {
  577. if(m_bAnonymous)
  578. SetInterfaceSecurity(*ppConsumerProvider, NULL, NULL, NULL,
  579. RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS);
  580. }
  581. *ppConsumerProviderEx = NULL;
  582. hres = pProtoSink->QueryInterface(IID_IWbemEventConsumerProviderEx,
  583. (void**)ppConsumerProviderEx);
  584. if(FAILED(hres))
  585. {
  586. }
  587. else if(*ppConsumerProviderEx == NULL)
  588. {
  589. ERRORTRACE((LOG_ESS, "NULL object received from event consumer "
  590. "%S QueryInterface. Consumer needs to have its code examined\n",
  591. m_wszProviderName));
  592. return WBEM_E_PROVIDER_LOAD_FAILURE;
  593. }
  594. else
  595. {
  596. if(m_bAnonymous)
  597. SetInterfaceSecurity(*ppConsumerProviderEx, NULL, NULL, NULL,
  598. RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS);
  599. }
  600. // Inform the cache that unloading may be required
  601. // ===============================================
  602. m_pNamespace->GetConsumerProviderCache().EnsureUnloadInstruction();
  603. //
  604. // Report the MSFT_WmiConsumerProviderLoaded event.
  605. //
  606. FIRE_NCEVENT(
  607. g_hNCEvents[MSFT_WmiConsumerProviderLoaded],
  608. WMI_SENDCOMMIT_SET_NOT_REQUIRED,
  609. // Data follows...
  610. m_pNamespace->GetName(),
  611. m_wszProviderName,
  612. m_wszMachineName);
  613. return S_OK;
  614. }
  615. CConsumerProviderCache::~CConsumerProviderCache()
  616. {
  617. if(m_pInstruction)
  618. {
  619. m_pInstruction->Terminate();
  620. m_pInstruction->Release();
  621. }
  622. }
  623. BOOL CConsumerProviderCache::DoesContain(IWbemClassObject* pProvReg,
  624. IWbemClassObject* pConsumerReg)
  625. {
  626. HRESULT hres;
  627. // Get its class list
  628. // ==================
  629. VARIANT v;
  630. VariantInit(&v);
  631. CClearMe cm(&v);
  632. hres = pProvReg->Get(L"ConsumerClassNames", 0, &v, NULL, NULL);
  633. if(SUCCEEDED(hres) && V_VT(&v) == (VT_BSTR | VT_ARRAY))
  634. {
  635. SAFEARRAY* psa = V_ARRAY(&v);
  636. long lLBound, lUBound;
  637. BSTR* astrData;
  638. SafeArrayGetLBound(psa, 1, &lLBound);
  639. SafeArrayGetUBound(psa, 1, &lUBound);
  640. SafeArrayAccessData(psa, (void**)&astrData);
  641. CUnaccessMe um(psa);
  642. for(int i = 0; i <= lUBound - lLBound; i++)
  643. {
  644. if(pConsumerReg->InheritsFrom(astrData[i]) == S_OK)
  645. return TRUE;
  646. }
  647. }
  648. return FALSE;
  649. }
  650. //
  651. // Need a class for dynamic enumeration of consumer provider registrations
  652. //
  653. class CProviderRegistrationSink : public CObjectSink
  654. {
  655. protected:
  656. CConsumerProviderCache* m_pCache;
  657. IWbemClassObject* m_pLogicalConsumer;
  658. IWbemClassObject** m_ppReg;
  659. public:
  660. CProviderRegistrationSink(CConsumerProviderCache* pCache,
  661. IWbemClassObject* pLogicalConsumer, IWbemClassObject** ppReg) :
  662. m_pCache(pCache), m_pLogicalConsumer(pLogicalConsumer),
  663. m_ppReg(ppReg)
  664. {
  665. AddRef();
  666. // same thread --- no need to AddRef paramters
  667. }
  668. ~CProviderRegistrationSink(){}
  669. STDMETHOD(Indicate)(long lNumObjects, IWbemClassObject** apObjects)
  670. {
  671. for(long i = 0; i < lNumObjects; i++)
  672. {
  673. //
  674. // Check if this one is ours
  675. //
  676. if(m_pCache->DoesContain(apObjects[i], m_pLogicalConsumer))
  677. {
  678. *m_ppReg = apObjects[i];
  679. (*m_ppReg)->AddRef();
  680. return WBEM_E_CALL_CANCELLED;
  681. }
  682. }
  683. return WBEM_S_NO_ERROR;
  684. }
  685. };
  686. INTERNAL CConsumerProviderRecord*
  687. CConsumerProviderCache::GetRecord(IN IWbemClassObject* pLogicalConsumer)
  688. {
  689. CInCritSec ics(&m_cs);
  690. HRESULT hres;
  691. //
  692. // Enumerate all the registrations into a sink that will check if this
  693. // one is the right one
  694. //
  695. IWbemClassObject* pReg = NULL;
  696. CProviderRegistrationSink Sink(this, pLogicalConsumer, &pReg);
  697. hres = m_pNamespace->CreateInstanceEnum(
  698. CONSUMER_PROVIDER_REGISTRATION_CLASS, 0, &Sink);
  699. if(pReg == NULL)
  700. {
  701. // Not found
  702. return NULL;
  703. }
  704. CReleaseMe rm1(pReg);
  705. // Get the Win32Provider record
  706. // ============================
  707. VARIANT vPath;
  708. hres = pReg->Get(CONSPROV_PROVIDER_REF_PROPNAME, 0, &vPath, NULL, NULL);
  709. if(FAILED(hres) || V_VT(&vPath) != VT_BSTR)
  710. {
  711. ERRORTRACE((LOG_ESS, "Event consumer provider registration is invalid: "
  712. "Provider property is missing\n"));
  713. return NULL;
  714. }
  715. INTERNAL BSTR strProviderRef = V_BSTR(&vPath);
  716. CClearMe cm2(&vPath);
  717. _IWmiObject* pProv = NULL;
  718. hres = m_pNamespace->GetInstance(V_BSTR(&vPath), &pProv);
  719. if(FAILED(hres))
  720. {
  721. ERRORTRACE((LOG_ESS, "Invalid event consumer provider registration: "
  722. "dangling provider reference %S\n",
  723. V_BSTR(&vPath)));
  724. return NULL;
  725. }
  726. CReleaseMe rm(pProv);
  727. // Get the name of the provider
  728. // ============================
  729. VARIANT vProvName;
  730. VariantInit(&vProvName);
  731. CClearMe cm3(&vProvName);
  732. hres = pProv->Get(PROVIDER_NAME_PROPNAME, 0, &vProvName, NULL, NULL);
  733. if(FAILED(hres) || V_VT(&vProvName) != VT_BSTR)
  734. {
  735. ERRORTRACE((LOG_ESS, "Event provider registration without a name at "
  736. "%S\n", V_BSTR(&vPath)));
  737. return NULL;
  738. }
  739. INTERNAL BSTR strProviderName = V_BSTR(&vProvName);
  740. // Get the machine name
  741. // ====================
  742. VARIANT vMachine;
  743. VariantInit(&vMachine);
  744. CClearMe cm4(&vMachine);
  745. hres = pLogicalConsumer->Get(CONSUMER_MACHINE_NAME_PROPNAME, 0, &vMachine,
  746. NULL, NULL);
  747. if(FAILED(hres)) return NULL;
  748. INTERNAL BSTR strMachineName = NULL;
  749. if(V_VT(&vMachine) != VT_NULL)
  750. strMachineName = V_BSTR(&vMachine);
  751. // Search for the record
  752. // =====================
  753. BOOL bFound = FALSE;
  754. CConsumerProviderRecord* pRecord;
  755. for(int i = 0; i < m_apRecords.GetSize(); i++)
  756. {
  757. pRecord = m_apRecords[i];
  758. if(wbem_wcsicmp(pRecord->GetProviderName(), strProviderName))
  759. continue;
  760. if(pRecord->GetMachineName() && strMachineName)
  761. {
  762. if(wbem_wcsicmp(pRecord->GetMachineName(), strMachineName))
  763. continue;
  764. }
  765. else
  766. {
  767. if(pRecord->GetMachineName() != strMachineName)
  768. continue;
  769. }
  770. bFound = TRUE;
  771. break;
  772. }
  773. if(!bFound)
  774. {
  775. pRecord = new CConsumerProviderRecord(m_pNamespace);
  776. if(pRecord == NULL)
  777. return NULL;
  778. hres = pRecord->Initialize(pProv, strProviderRef, strProviderName,
  779. strMachineName);
  780. if(m_apRecords.Add(pRecord) < 0)
  781. {
  782. delete pRecord;
  783. return NULL;
  784. }
  785. }
  786. pRecord->AddRef();
  787. return pRecord;
  788. }
  789. void CConsumerProviderCache::EnsureUnloadInstruction()
  790. {
  791. CInCritSec ics(&m_cs);
  792. if(m_pInstruction == NULL)
  793. {
  794. m_pInstruction = new CConsumerProviderWatchInstruction(this);
  795. if(m_pInstruction)
  796. {
  797. m_pInstruction->AddRef();
  798. m_pNamespace->GetTimerGenerator().Set(m_pInstruction);
  799. }
  800. }
  801. }
  802. HRESULT CConsumerProviderCache::UnloadUnusedProviders(CWbemInterval Interval)
  803. {
  804. CRefedPointerArray<CConsumerProviderRecord> apToInvalidate;
  805. BOOL bUnloaded = FALSE;
  806. {
  807. CInCritSec ics(&m_cs);
  808. BOOL bActiveLeft = FALSE;
  809. for(int i = 0; i < m_apRecords.GetSize(); i++)
  810. {
  811. CConsumerProviderRecord* pRecord = m_apRecords[i];
  812. // Prevent the record from being used while its fate is determined
  813. // ===============================================================
  814. if(pRecord->IsActive())
  815. {
  816. if(CWbemTime::GetCurrentTime() - pRecord->GetLastAccess() >
  817. Interval)
  818. {
  819. apToInvalidate.Add(pRecord);
  820. DEBUGTRACE((LOG_ESS, "Unloading consumer provider %S on "
  821. "%S\n", pRecord->GetProviderName(),
  822. pRecord->GetMachineName()));
  823. bUnloaded = TRUE;
  824. }
  825. else
  826. bActiveLeft = TRUE;
  827. }
  828. }
  829. if(m_pInstruction && !bActiveLeft)
  830. {
  831. m_pInstruction->Terminate();
  832. m_pInstruction->Release();
  833. m_pInstruction = NULL;
  834. }
  835. }
  836. // Actually unload
  837. // ===============
  838. for(int i = 0; i < apToInvalidate.GetSize(); i++)
  839. {
  840. apToInvalidate[i]->Invalidate();
  841. }
  842. if(bUnloaded)
  843. m_pNamespace->GetTimerGenerator().ScheduleFreeUnusedLibraries();
  844. return WBEM_S_NO_ERROR;
  845. }
  846. HRESULT CConsumerProviderCache::RemoveConsumerProvider(LPCWSTR wszProviderRef)
  847. {
  848. CInCritSec ics(&m_cs);
  849. for(int i = 0; i < m_apRecords.GetSize(); i++)
  850. {
  851. CConsumerProviderRecord* pRecord = m_apRecords[i];
  852. if(!wbem_wcsicmp(pRecord->GetProviderRef(), wszProviderRef))
  853. {
  854. // Matches --- remove
  855. // ==================
  856. DEBUGTRACE((LOG_ESS, "Removing consumer provider record: %S in %S"
  857. "\n", m_pNamespace->GetName(), wszProviderRef));
  858. m_apRecords.RemoveAt(i);
  859. i--;
  860. }
  861. }
  862. return WBEM_S_NO_ERROR;
  863. }
  864. // static
  865. SYSFREE_ME BSTR CConsumerProviderCache::GetProviderRefFromRecord(
  866. IWbemClassObject* pReg)
  867. {
  868. VARIANT v;
  869. VariantInit(&v);
  870. if(FAILED(pReg->Get(CONSPROV_PROVIDER_REF_PROPNAME, 0, &v, NULL, NULL)) ||
  871. V_VT(&v) != VT_BSTR)
  872. {
  873. VariantClear(&v);
  874. return NULL;
  875. }
  876. else
  877. {
  878. // Variant intentionally not cleared
  879. return V_BSTR(&v);
  880. }
  881. }
  882. class CSingleElementSink : public CObjectSink
  883. {
  884. protected:
  885. IWbemClassObject** m_ppObj;
  886. public:
  887. CSingleElementSink(IWbemClassObject** ppObj) : m_ppObj(ppObj)
  888. {
  889. AddRef();
  890. }
  891. STDMETHOD(Indicate)(long lNumObjects, IWbemClassObject** apObjects)
  892. {
  893. if(lNumObjects > 0)
  894. {
  895. *m_ppObj = apObjects[0];
  896. apObjects[0]->AddRef();
  897. }
  898. return S_OK;
  899. }
  900. };
  901. HRESULT CConsumerProviderCache::GetConsumerProviderRegFromProviderReg(
  902. IWbemClassObject* pProv,
  903. IWbemClassObject** ppConsProv)
  904. {
  905. HRESULT hres;
  906. // Get the path
  907. // ============
  908. VARIANT vPath;
  909. VariantInit(&vPath);
  910. if(FAILED(pProv->Get(L"__RELPATH", 0, &vPath, NULL, NULL)) ||
  911. V_VT(&vPath) != VT_BSTR)
  912. {
  913. return WBEM_E_INVALID_PROVIDER_REGISTRATION;
  914. }
  915. WString wsPath = WString(V_BSTR(&vPath)).EscapeQuotes();
  916. VariantClear(&vPath);
  917. // Construct the query
  918. // ===================
  919. DWORD cLen = wsPath.Length()*2 + 100;
  920. BSTR strQuery = SysAllocStringLen( NULL, cLen );
  921. if ( NULL == strQuery )
  922. {
  923. return WBEM_E_OUT_OF_MEMORY;
  924. }
  925. CSysFreeMe sfm(strQuery);
  926. StringCchPrintfW(
  927. strQuery,
  928. cLen,
  929. L"select * from " CONSUMER_PROVIDER_REGISTRATION_CLASS L" where "
  930. L"Provider = \"%s\"", (LPWSTR)wsPath);
  931. // Issue the query
  932. // ===============
  933. *ppConsProv = NULL;
  934. CSingleElementSink Sink(ppConsProv);
  935. hres = m_pNamespace->ExecQuery(strQuery, 0, &Sink);
  936. if(FAILED(hres))
  937. return hres;
  938. else if(*ppConsProv == NULL)
  939. return WBEM_E_NOT_FOUND;
  940. else
  941. return WBEM_S_NO_ERROR;
  942. }
  943. void CConsumerProviderCache::Clear()
  944. {
  945. CInCritSec ics(&m_cs);
  946. m_apRecords.RemoveAll();
  947. if(m_pInstruction)
  948. {
  949. m_pInstruction->Terminate();
  950. m_pInstruction->Release();
  951. m_pInstruction = NULL;
  952. }
  953. }
  954. void CConsumerProviderCache::DumpStatistics(FILE* f, long lFlags)
  955. {
  956. fprintf(f, "%d consumer provider records\n", m_apRecords.GetSize());
  957. }
  958. // static
  959. CWbemInterval CConsumerProviderWatchInstruction::mstatic_Interval;
  960. void CConsumerProviderWatchInstruction::staticInitialize(IWbemServices* pRoot)
  961. {
  962. mstatic_Interval =
  963. CBasicUnloadInstruction::staticRead(pRoot, GetCurrentEssContext(),
  964. L"__EventConsumerProviderCacheControl=@");
  965. }
  966. CConsumerProviderWatchInstruction::CConsumerProviderWatchInstruction(
  967. CConsumerProviderCache* pCache)
  968. : CBasicUnloadInstruction(mstatic_Interval), m_pCache(pCache)
  969. {}
  970. HRESULT CConsumerProviderWatchInstruction::Fire(long, CWbemTime)
  971. {
  972. if(!m_bTerminate)
  973. {
  974. CEssThreadObject Obj(NULL);
  975. SetConstructedEssThreadObject(&Obj);
  976. m_pCache->UnloadUnusedProviders(m_Interval);
  977. m_pCache->m_pNamespace->FirePostponedOperations();
  978. ClearCurrentEssThreadObject();
  979. return WBEM_S_NO_ERROR;
  980. }
  981. else
  982. return WBEM_S_FALSE;
  983. }