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