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.

2187 lines
55 KiB

  1. //******************************************************************************
  2. //
  3. // BINDING.CPP
  4. //
  5. // Copyright (C) 1996-1999 Microsoft Corporation
  6. //
  7. //******************************************************************************
  8. #include "precomp.h"
  9. #include <stdio.h>
  10. #include <pragmas.h>
  11. #include <ess.h>
  12. #include <permbind.h>
  13. #include <cominit.h>
  14. #include <callsec.h>
  15. #include <wmimsg.h>
  16. #include "Quota.h"
  17. #include <tchar.h>
  18. #define MIN_TIMEOUT_BETWEEN_TOKEN_ATTEMPTS 60000
  19. //*****************************************************************************
  20. //
  21. // Syncronization model:
  22. //
  23. // 1. Bindings themselves are immutable and do not require protection.
  24. // 2. Releasing a binding (removing from table) can release the other end-point
  25. // and generally cannot be done in a CS.
  26. //
  27. //*************************** Event Consumer **********************************
  28. long g_lNumConsumers = 0;
  29. long g_lNumBindings = 0;
  30. long g_lNumFilters = 0;
  31. CEventConsumer::CEventConsumer( CEssNamespace* pNamespace )
  32. : CQueueingEventSink(pNamespace), m_pOwnerSid(NULL)
  33. {
  34. InterlockedIncrement( &g_lNumConsumers );
  35. }
  36. CEventConsumer::~CEventConsumer()
  37. {
  38. InterlockedDecrement( &g_lNumConsumers );
  39. delete [] m_pOwnerSid;
  40. }
  41. HRESULT CEventConsumer::EnsureReferences(CEventFilter* pFilter,
  42. CBinding* pBinding)
  43. {
  44. CBinding* pOldBinding = NULL;
  45. {
  46. CInCritSec ics(&m_cs);
  47. for(int i = 0; i < m_apBindings.GetSize(); i++)
  48. {
  49. if(m_apBindings[i]->GetFilter() == pFilter)
  50. {
  51. // Replace the binding
  52. // ===================
  53. m_apBindings.SetAt(i, pBinding, &pOldBinding);
  54. break;
  55. }
  56. }
  57. if(pOldBinding == NULL)
  58. {
  59. // Add it to the list
  60. // ==================
  61. if(m_apBindings.Add(pBinding) < 0)
  62. return WBEM_E_OUT_OF_MEMORY;
  63. }
  64. }
  65. if(pOldBinding)
  66. {
  67. // Found
  68. // =====
  69. pOldBinding->Release();
  70. return S_FALSE;
  71. }
  72. else
  73. {
  74. return S_OK;
  75. }
  76. }
  77. HRESULT CEventConsumer::EnsureNotReferences(CEventFilter* pFilter)
  78. {
  79. CBinding* pOldBinding = NULL;
  80. {
  81. CInCritSec ics(&m_cs);
  82. for(int i = 0; i < m_apBindings.GetSize(); i++)
  83. {
  84. if(m_apBindings[i]->GetFilter() == pFilter)
  85. {
  86. // Remove the binding
  87. // ==================
  88. m_apBindings.RemoveAt(i, &pOldBinding);
  89. break;
  90. }
  91. }
  92. }
  93. if(pOldBinding)
  94. {
  95. pOldBinding->Release();
  96. return S_OK;
  97. }
  98. else
  99. {
  100. // Not found
  101. // =========
  102. return S_FALSE;
  103. }
  104. }
  105. HRESULT CEventConsumer::Unbind()
  106. {
  107. // Unbind the binding array from the consumer
  108. // ==========================================
  109. CBinding** apBindings = NULL;
  110. int nNumBindings = 0;
  111. {
  112. CInCritSec ics(&m_cs);
  113. nNumBindings = m_apBindings.GetSize();
  114. apBindings = m_apBindings.UnbindPtr();
  115. if ( NULL == apBindings )
  116. {
  117. return WBEM_S_FALSE;
  118. }
  119. }
  120. // Instruct all the filters that are bound to us to unbind
  121. // =======================================================
  122. HRESULT hres = S_OK;
  123. for(int i = 0; i < nNumBindings; i++)
  124. {
  125. HRESULT hr = apBindings[i]->GetFilter()->EnsureNotReferences(this);
  126. if( FAILED( hr ) )
  127. {
  128. hres = hr;
  129. }
  130. apBindings[i]->Release();
  131. }
  132. delete [] apBindings;
  133. #ifdef __WHISTLER_UNCUT
  134. //
  135. // tell the associated queueing sink that it needs to clean up its queues.
  136. // TODO : this is temporary because we will later support the case where
  137. // there is a many-to-1 mapping between consumers and queueing sinks.
  138. // When that happens, this logic will be moved elsewhere.
  139. //
  140. CleanupPersistentQueues();
  141. #endif
  142. return hres;
  143. }
  144. HRESULT CEventConsumer::ConsumeFromBinding(CBinding* pBinding,
  145. long lNumEvents, IWbemEvent** apEvents,
  146. CEventContext* pContext)
  147. {
  148. DWORD dwQoS = pBinding->GetQoS();
  149. if( dwQoS == WMIMSG_FLAG_QOS_SYNCHRONOUS )
  150. {
  151. // Synchronous delivery --- call the ultimate client
  152. // =================================================
  153. IUnknown* pOldSec = NULL;
  154. if(!pBinding->IsSecure())
  155. {
  156. CoSwitchCallContext(NULL, &pOldSec);
  157. }
  158. HRESULT hres = ActuallyDeliver( lNumEvents,
  159. apEvents,
  160. pBinding->IsSecure(),
  161. pContext );
  162. if(!pBinding->IsSecure())
  163. {
  164. IUnknown* pGarb = NULL;
  165. CoSwitchCallContext(pOldSec, &pGarb);
  166. }
  167. return hres;
  168. }
  169. // Asynchronous delivery --- delegate to queueing sink
  170. // ===================================================
  171. return CQueueingEventSink::SecureIndicate( lNumEvents,
  172. apEvents,
  173. pBinding->IsSecure(),
  174. pBinding->ShouldSlowDown(),
  175. dwQoS,
  176. pContext );
  177. }
  178. HRESULT CEventConsumer::GetAssociatedFilters(
  179. CRefedPointerSmallArray<CEventFilter>& apFilters)
  180. {
  181. CInCritSec ics(&m_cs);
  182. for(int i = 0; i < m_apBindings.GetSize(); i++)
  183. {
  184. if(apFilters.Add(m_apBindings[i]->GetFilter()) < 0)
  185. return WBEM_E_OUT_OF_MEMORY;
  186. }
  187. return WBEM_S_NO_ERROR;
  188. }
  189. HRESULT CEventConsumer::ReportEventDrop(IWbemEvent* pEvent)
  190. {
  191. // Log a message
  192. // =============
  193. ERRORTRACE((LOG_ESS, "Dropping event destined for event consumer %S in "
  194. "namespace %S\n", (LPCWSTR)(WString)GetKey(),
  195. m_pNamespace->GetName()));
  196. if(pEvent->InheritsFrom(EVENT_DROP_CLASS) == S_OK)
  197. {
  198. ERRORTRACE((LOG_ESS, "Unable to deliver an event indicating inability "
  199. "to deliver another event to event consumer %S in namespace %S.\n"
  200. "Not raising an error event to avoid an infinite loop!\n",
  201. (LPCWSTR)(WString)GetKey(), m_pNamespace->GetName()));
  202. return S_FALSE;
  203. }
  204. return S_OK;
  205. }
  206. //*************************** Event Filter **********************************
  207. CEventFilter::CEventFilter(CEssNamespace* pNamespace)
  208. : m_pNamespace(pNamespace), m_eState(e_Inactive),
  209. m_ForwardingSink(this), m_ClassChangeSink(this),
  210. m_eValidity(e_TemporarilyInvalid), m_pOwnerSid(NULL),
  211. m_bSingleAsync(false), m_lSecurityChecksRemaining(0),
  212. m_hresFilterError(WBEM_E_CRITICAL_ERROR), m_bCheckSDs(false),
  213. m_bHasBeenValid(false), m_dwLastTokenAttempt(0), m_pToken(NULL),
  214. m_bDeactivatedByGuard(false), m_bReconstructOnHit(false),
  215. m_pGuardingSink(NULL), m_hresTokenError(WBEM_E_CRITICAL_ERROR),
  216. m_hresPollingError(S_OK)
  217. {
  218. InterlockedIncrement( &g_lNumFilters );
  219. m_pNamespace->AddRef();
  220. }
  221. CEventFilter::~CEventFilter()
  222. {
  223. InterlockedDecrement( &g_lNumFilters );
  224. delete [] m_pOwnerSid;
  225. if(m_pNamespace)
  226. m_pNamespace->Release();
  227. if(m_pToken)
  228. m_pToken->Release();
  229. }
  230. HRESULT CEventFilter::EnsureReferences(CEventConsumer* pConsumer,
  231. CBinding* pBinding)
  232. {
  233. CBinding* pOldBinding = NULL;
  234. {
  235. CInUpdate iu(this);
  236. // Actually change the bindings
  237. // ============================
  238. {
  239. CInCritSec ics(&m_cs);
  240. for(int i = 0; i < m_apBindings.GetSize(); i++)
  241. {
  242. if(m_apBindings[i]->GetConsumer() == pConsumer)
  243. {
  244. // Replace the binding
  245. // ===================
  246. // binding cannot change synchronicity --- in such cases,
  247. // it is first removed, and then re-added. Therefore,
  248. // no m_bSingleAsync adjustment is needed
  249. m_apBindings.SetAt(i, pBinding, &pOldBinding);
  250. break;
  251. }
  252. }
  253. if(pOldBinding == NULL)
  254. {
  255. // Add it to the list
  256. // ==================
  257. if(m_apBindings.Add(pBinding) < 0)
  258. return WBEM_E_OUT_OF_MEMORY;
  259. AdjustSingleAsync();
  260. }
  261. }
  262. // Activate if needed
  263. // ==================
  264. AdjustActivation();
  265. }
  266. if(pOldBinding)
  267. {
  268. // Found
  269. // =====
  270. pOldBinding->Release();
  271. return S_FALSE;
  272. }
  273. else
  274. {
  275. return S_OK;
  276. }
  277. }
  278. HRESULT CEventFilter::EnsureNotReferences(CEventConsumer* pConsumer)
  279. {
  280. CBinding* pOldBinding = NULL;
  281. {
  282. CInUpdate iu(this);
  283. // Make the actual change
  284. // ======================
  285. {
  286. CInCritSec ics(&m_cs);
  287. for(int i = 0; i < m_apBindings.GetSize(); i++)
  288. {
  289. if(m_apBindings[i]->GetConsumer() == pConsumer)
  290. {
  291. // Remove the binding
  292. // ==================
  293. m_apBindings.RemoveAt(i, &pOldBinding);
  294. AdjustSingleAsync();
  295. break;
  296. }
  297. } // for
  298. } // m_cs
  299. // Deactivate the filter if necessary
  300. // ==================================
  301. AdjustActivation();
  302. } // update
  303. if(pOldBinding)
  304. {
  305. pOldBinding->Release();
  306. return S_OK;
  307. }
  308. else
  309. {
  310. // Not found
  311. // =========
  312. return S_FALSE;
  313. }
  314. }
  315. HRESULT CEventFilter::Unbind(bool bShuttingDown)
  316. {
  317. // Unbind the binding array from the filter
  318. // ========================================
  319. CBinding** apBindings = NULL;
  320. int nNumBindings = 0;
  321. {
  322. CInUpdate iu(this);
  323. {
  324. CInCritSec ics(&m_cs);
  325. nNumBindings = m_apBindings.GetSize();
  326. apBindings = m_apBindings.UnbindPtr();
  327. if ( NULL == apBindings )
  328. {
  329. return WBEM_S_FALSE;
  330. }
  331. m_bSingleAsync = false;
  332. }
  333. if(!bShuttingDown)
  334. AdjustActivation();
  335. }
  336. // Instruct all the consumers that are bound to us to unbind
  337. // =========================================================
  338. HRESULT hres = S_OK;
  339. for(int i = 0; i < nNumBindings; i++)
  340. {
  341. HRESULT hr = apBindings[i]->GetConsumer()->EnsureNotReferences(this);
  342. if ( FAILED( hr ) )
  343. {
  344. hres = hr;
  345. }
  346. apBindings[i]->Release();
  347. }
  348. delete [] apBindings;
  349. return hres;
  350. }
  351. // This function is only called at construction --- no locks are needed
  352. HRESULT CEventFilter::SetGuardQuery(LPCWSTR wszQuery, LPCWSTR wszNamespace)
  353. {
  354. if(wszQuery)
  355. m_wsGuardQuery = wszQuery;
  356. else
  357. m_wsGuardQuery.Empty();
  358. if(wszNamespace)
  359. m_wsGuardNamespace = wszNamespace;
  360. else
  361. m_wsGuardNamespace.Empty();
  362. return WBEM_S_NO_ERROR;
  363. }
  364. bool CEventFilter::IsGuarded()
  365. {
  366. return (m_wsGuardQuery.Length() != 0);
  367. }
  368. bool CEventFilter::IsGuardActive()
  369. {
  370. return (m_pGuardingSink != NULL);
  371. }
  372. HRESULT CEventFilter::ActivateGuard()
  373. {
  374. HRESULT hres;
  375. //
  376. // Check if the guard is already active
  377. //
  378. if(IsGuardActive())
  379. return WBEM_S_FALSE;
  380. //
  381. // Create the guarding sink --- the one that receives notifications
  382. // of the guard going up or down
  383. //
  384. CFilterGuardingSink* pSink = new CFilterGuardingSink(this);
  385. if(pSink == NULL)
  386. return WBEM_E_OUT_OF_MEMORY;
  387. pSink->AddRef();
  388. CReleaseMe rm1(pSink);
  389. //
  390. // Issue the monitor for the guarding query. It is up to the monitoring
  391. // subsystem to optimize similar monitors
  392. //
  393. CEssNamespace* pNamespace = NULL;
  394. if(m_wsGuardNamespace.Length() > 0)
  395. {
  396. hres = m_pNamespace->GetEss()->GetNamespaceObject( m_wsGuardNamespace,
  397. TRUE,
  398. &pNamespace );
  399. if(FAILED(hres))
  400. {
  401. ERRORTRACE((LOG_ESS, "Unable to connect to namespace '%S' of "
  402. "guarding monitor '%S' for "
  403. "event filter '%S': 0x%X. The filter will remain inactive\n",
  404. (LPCWSTR)m_wsGuardNamespace, (LPCWSTR)m_wsGuardQuery,
  405. (LPCWSTR)(WString)GetKey(), hres));
  406. SetGuardStatus(false);
  407. return hres;
  408. }
  409. }
  410. else
  411. {
  412. pNamespace = m_pNamespace;
  413. pNamespace->AddRef();
  414. }
  415. CTemplateReleaseMe<CEssNamespace> rm2(pNamespace);
  416. hres = pNamespace->InternalRegisterNotificationSink(L"WQL",
  417. m_wsGuardQuery,
  418. WBEM_FLAG_MONITOR, WMIMSG_FLAG_QOS_SYNCHRONOUS,
  419. GetCurrentEssContext(), pSink, false, NULL );
  420. if(FAILED(hres))
  421. {
  422. ERRORTRACE((LOG_ESS, "Unable to issue guarding monitor '%S' for "
  423. "event filter '%S': 0x%X. The filter will remain inactive\n",
  424. (LPCWSTR)m_wsGuardQuery, (LPCWSTR)(WString)GetKey(),
  425. hres));
  426. SetGuardStatus(false);
  427. return hres;
  428. }
  429. //
  430. // Store the sink AddRef'ed in the filter object. This creates a
  431. // circular reference count, but that's OK, since the sink is released
  432. // during filter deactivation and shutdown
  433. //
  434. m_pGuardingSink = pSink;
  435. m_pGuardingSink->AddRef();
  436. return S_OK;
  437. }
  438. HRESULT CEventFilter::DeactivateGuard()
  439. {
  440. HRESULT hres;
  441. if(!IsGuardActive())
  442. return WBEM_S_FALSE;
  443. //
  444. // Cancel the monitor
  445. //
  446. hres = m_pNamespace->InternalRemoveNotificationSink(m_pGuardingSink);
  447. if(FAILED(hres))
  448. {
  449. ERRORTRACE((LOG_ESS, "Unable to stop guarding monitor '%S' for "
  450. "event filter '%S': 0x%X\n",
  451. (LPCWSTR)m_wsGuardQuery, (LPCWSTR)(WString)GetKey(),
  452. hres));
  453. }
  454. m_pGuardingSink->Release();
  455. m_pGuardingSink = NULL;
  456. return S_OK;
  457. }
  458. CEventFilter::CFilterGuardingSink::CFilterGuardingSink(CEventFilter* pFilter)
  459. : m_pFilter(pFilter)
  460. {
  461. m_pFilter->AddRef();
  462. }
  463. CEventFilter::CFilterGuardingSink::~CFilterGuardingSink()
  464. {
  465. if(m_pFilter)
  466. m_pFilter->Release();
  467. }
  468. STDMETHODIMP CEventFilter::CFilterGuardingSink::Indicate(long lNumObjects,
  469. IWbemClassObject** apEvents)
  470. {
  471. HRESULT hres;
  472. //
  473. // Get current state from the filter
  474. //
  475. bool bEnable;
  476. bool bError;
  477. m_pFilter->GetGuardStatus(&bEnable, &bError);
  478. bool bOldEnable = bEnable;
  479. bool bOldError = bError;
  480. //
  481. // Traverse the entire list computing the end result --- whether the
  482. // guard should be true or false
  483. //
  484. for(long i = 0; i < lNumObjects; i++)
  485. {
  486. _IWmiObject* pObj = NULL;
  487. hres = apEvents[i]->QueryInterface(IID__IWmiObject, (void**)&pObj);
  488. if(FAILED(hres))
  489. return hres;
  490. CReleaseMe rm1(pObj);
  491. //
  492. // Determine the class and process accordingly
  493. //
  494. WCHAR wszClassName[256];
  495. BOOL bIsNull;
  496. DWORD dwSizeUsed;
  497. hres = pObj->ReadProp(L"__CLASS", 0, 256 * sizeof(WCHAR), NULL, NULL,
  498. &bIsNull, &dwSizeUsed, wszClassName);
  499. if(FAILED(hres))
  500. return hres;
  501. if(bIsNull)
  502. return WBEM_E_INVALID_CLASS;
  503. if(!wbem_wcsicmp(wszClassName, ASSERT_EVENT_CLASS))
  504. {
  505. if(!bError)
  506. bEnable = true;
  507. }
  508. else if(!wbem_wcsicmp(wszClassName, RETRACT_EVENT_CLASS))
  509. {
  510. if(!bError)
  511. bEnable = !IsCountZero(pObj);
  512. }
  513. else if(!wbem_wcsicmp(wszClassName, GOINGUP_EVENT_CLASS))
  514. {
  515. bEnable = !IsCountZero(pObj);
  516. bError = false;
  517. }
  518. else if(!wbem_wcsicmp(wszClassName, MONITORERROR_EVENT_CLASS) ||
  519. !wbem_wcsicmp(wszClassName, GOINGDOWN_EVENT_CLASS))
  520. {
  521. bError = true;
  522. }
  523. }
  524. if(bError != bOldError || bOldEnable != bEnable)
  525. {
  526. CEssThreadObject Obj(NULL);
  527. SetConstructedEssThreadObject(&Obj);
  528. //
  529. // Set the guard state back
  530. //
  531. m_pFilter->SetGuardStatus(bEnable, bError);
  532. m_pFilter->AdjustActivation();
  533. m_pFilter->m_pNamespace->FirePostponedOperations();
  534. ClearCurrentEssThreadObject();
  535. }
  536. return S_OK;
  537. }
  538. bool CEventFilter::CFilterGuardingSink::IsCountZero(_IWmiObject* pObj)
  539. {
  540. HRESULT hres;
  541. //
  542. // Get the count
  543. //
  544. DWORD dwCurrentCount;
  545. BOOL bIsNull;
  546. DWORD dwSize;
  547. hres = pObj->ReadProp(MONITORCOUNT_EVENT_PROPNAME, 0, sizeof(DWORD), NULL,
  548. NULL, &bIsNull, &dwSize, &dwCurrentCount);
  549. if(FAILED(hres) || bIsNull)
  550. {
  551. // internal error
  552. return true;
  553. }
  554. return (dwCurrentCount == 0);
  555. }
  556. void CEventFilter::SetInactive()
  557. {
  558. m_eState = e_Inactive;
  559. }
  560. BOOL CEventFilter::IsActive()
  561. {
  562. return (m_eState == e_Active);
  563. }
  564. HRESULT CEventFilter::GetFilterError()
  565. {
  566. return m_hresFilterError;
  567. }
  568. HRESULT CEventFilter::GetEventNamespace(LPWSTR* pwszNamespace)
  569. {
  570. *pwszNamespace = NULL;
  571. return S_OK;
  572. }
  573. // assumes in m_cs
  574. void CEventFilter::AdjustSingleAsync()
  575. {
  576. if(m_apBindings.GetSize() > 1)
  577. m_bSingleAsync = false;
  578. else if(m_apBindings.GetSize() == 0)
  579. m_bSingleAsync = false;
  580. else if(m_apBindings[0]->IsSynch())
  581. m_bSingleAsync = false;
  582. else
  583. m_bSingleAsync = true;
  584. }
  585. bool CEventFilter::IsBound()
  586. {
  587. return (m_apBindings.GetSize() != 0);
  588. }
  589. // Requires: in m_csChangeBindings
  590. HRESULT CEventFilter::AdjustActivation()
  591. {
  592. // Invalid filters cannot be activated or deactivated
  593. // ==================================================
  594. if(m_eValidity == e_PermanentlyInvalid)
  595. return S_FALSE;
  596. //
  597. // Check if we need to activate or deactivate our guarding mechanism
  598. //
  599. if(IsBound() && IsGuarded() && !IsGuardActive())
  600. {
  601. // The default guard status is false --- the monitor is sure to tell
  602. // us if it has anything
  603. SetGuardStatus(false);
  604. ActivateGuard();
  605. }
  606. else if(IsGuardActive() && (!IsBound() || !IsGuarded()))
  607. {
  608. DeactivateGuard();
  609. }
  610. HRESULT hres = S_FALSE;
  611. if(!IsBound() || m_bDeactivatedByGuard)
  612. {
  613. //
  614. // Even if this filter is not active, it may be subscribed for
  615. // activation events if it is temporarily invalid (and that's the only
  616. // reason it is not active).
  617. //
  618. m_pNamespace->UnregisterFilterFromAllClassChanges(this);
  619. if(m_eState == e_Active)
  620. {
  621. hres = m_pNamespace->DeactivateFilter(this);
  622. if(FAILED(hres)) return hres;
  623. m_eState = e_Inactive;
  624. }
  625. return WBEM_S_NO_ERROR;
  626. }
  627. else if(m_eState == e_Inactive && IsBound() && !m_bDeactivatedByGuard)
  628. {
  629. //
  630. // Even though this filter is not active, it may be subscribed for
  631. // activation events if it is temporarily invalid (and that's the only
  632. // reason it is not active).
  633. //
  634. m_pNamespace->UnregisterFilterFromAllClassChanges(this);
  635. hres = m_pNamespace->ActivateFilter(this);
  636. if(FAILED(hres)) return hres;
  637. m_eState = e_Active;
  638. return WBEM_S_NO_ERROR;
  639. }
  640. else
  641. {
  642. return S_FALSE;
  643. }
  644. }
  645. void CEventFilter::MarkAsPermanentlyInvalid(HRESULT hres)
  646. {
  647. m_eValidity = e_PermanentlyInvalid;
  648. m_hresFilterError = hres;
  649. }
  650. void CEventFilter::MarkAsTemporarilyInvalid(HRESULT hres)
  651. {
  652. m_eValidity = e_TemporarilyInvalid;
  653. m_hresFilterError = hres;
  654. }
  655. void CEventFilter::MarkAsValid()
  656. {
  657. m_eValidity = e_Valid;
  658. m_bHasBeenValid = true;
  659. m_hresFilterError = WBEM_S_NO_ERROR;
  660. }
  661. void CEventFilter::MarkReconstructOnHit(bool bReconstruct)
  662. {
  663. //
  664. // Reconstruction is not really needed, since dummer nodes are used for
  665. // this
  666. //
  667. m_bReconstructOnHit = bReconstruct;
  668. }
  669. void CEventFilter::GetGuardStatus(bool *pbEnable, bool *pbError)
  670. {
  671. *pbError = m_bGuardError;
  672. *pbEnable = !m_bDeactivatedByGuard;
  673. }
  674. void CEventFilter::SetGuardStatus(bool bEnable, bool bError)
  675. {
  676. // Activation adjustment is handled by the caller
  677. m_bGuardError = bError;
  678. m_bDeactivatedByGuard = (bError || !bEnable);
  679. }
  680. HRESULT CEventFilter::CheckEventAccessToFilter( IServerSecurity* pProvCtx )
  681. {
  682. HRESULT hr = WBEM_S_NO_ERROR;
  683. const PSECURITY_DESCRIPTOR pEventAccessSD = GetEventAccessSD();
  684. if ( pEventAccessSD == NULL )
  685. {
  686. //
  687. // filter allows all events
  688. //
  689. return WBEM_S_NO_ERROR;
  690. }
  691. //
  692. // check that the event provider's calling context has access to filter
  693. //
  694. if ( pProvCtx != NULL )
  695. {
  696. hr = pProvCtx->ImpersonateClient();
  697. if ( SUCCEEDED(hr) )
  698. {
  699. HANDLE hToken;
  700. if ( OpenThreadToken( GetCurrentThread(),
  701. TOKEN_QUERY,
  702. TRUE,
  703. &hToken ) )
  704. {
  705. GENERIC_MAPPING map;
  706. ZeroMemory( &map, sizeof(GENERIC_MAPPING) );
  707. PRIVILEGE_SET ps;
  708. DWORD dwPrivLength = sizeof(ps);
  709. BOOL bStatus;
  710. DWORD dwGranted;
  711. if ( ::AccessCheck( PSECURITY_DESCRIPTOR(pEventAccessSD),
  712. hToken,
  713. WBEM_RIGHT_PUBLISH,
  714. &map,
  715. &ps,
  716. &dwPrivLength,
  717. &dwGranted,
  718. &bStatus ) )
  719. {
  720. hr = bStatus ? WBEM_S_NO_ERROR : WBEM_E_ACCESS_DENIED;
  721. }
  722. else
  723. {
  724. hr = HRESULT_FROM_WIN32( GetLastError() );
  725. }
  726. CloseHandle( hToken );
  727. }
  728. else
  729. {
  730. hr = HRESULT_FROM_WIN32( GetLastError() );
  731. }
  732. pProvCtx->RevertToSelf();
  733. }
  734. }
  735. return hr;
  736. }
  737. HRESULT CEventFilter::CheckFilterAccessToEvent( PSECURITY_DESCRIPTOR pEventSD )
  738. {
  739. HRESULT hr;
  740. if ( pEventSD == NULL )
  741. {
  742. //
  743. // event provider allows all filters access
  744. //
  745. return WBEM_S_NO_ERROR;
  746. }
  747. if( !m_bCheckSDs )
  748. {
  749. //
  750. // This filter was unconditionally allowed by all its event providers!
  751. //
  752. return WBEM_S_NO_ERROR;
  753. }
  754. //
  755. // Get the token for this filter
  756. //
  757. if( m_pToken == NULL && FAILED(m_hresTokenError) )
  758. {
  759. //
  760. // Check how long it's been since we last attempted to get the token --
  761. // don't want to do that too often.
  762. //
  763. if(m_dwLastTokenAttempt == 0 ||
  764. m_dwLastTokenAttempt <
  765. GetTickCount() - MIN_TIMEOUT_BETWEEN_TOKEN_ATTEMPTS )
  766. {
  767. //
  768. // Get the filter to find a token, however it does that
  769. //
  770. m_hresTokenError = ObtainToken( &m_pToken );
  771. if( FAILED(m_hresTokenError) )
  772. {
  773. m_dwLastTokenAttempt = GetTickCount();
  774. }
  775. }
  776. }
  777. if ( m_hresTokenError == WBEM_S_NO_ERROR )
  778. {
  779. _DBG_ASSERT( m_pToken != NULL );
  780. //
  781. // Check security for real
  782. //
  783. DWORD dwGranted;
  784. hr = m_pToken->AccessCheck( WBEM_RIGHT_SUBSCRIBE,
  785. (const BYTE*)pEventSD,
  786. &dwGranted );
  787. if( SUCCEEDED(hr) )
  788. {
  789. if(dwGranted & WBEM_RIGHT_SUBSCRIBE)
  790. {
  791. hr = WBEM_S_NO_ERROR;
  792. }
  793. else
  794. {
  795. hr = WBEM_E_ACCESS_DENIED;
  796. }
  797. }
  798. }
  799. else
  800. {
  801. hr = m_hresTokenError;
  802. }
  803. return hr;
  804. }
  805. HRESULT CEventFilter::AccessCheck( CEventContext* pContext, IWbemEvent* pEvent)
  806. {
  807. HRESULT hr;
  808. //
  809. // With polling, there will be a null context. we don't do an access
  810. // check in that case.
  811. //
  812. if ( pContext == NULL )
  813. {
  814. return WBEM_S_NO_ERROR;
  815. }
  816. PSECURITY_DESCRIPTOR pEventSD = (PSECURITY_DESCRIPTOR)pContext->GetSD();
  817. //
  818. // check that the filter allows access to the event provider and owner.
  819. // owner and provider can be different when the provider is signaling
  820. // events on behalf of some other identity.
  821. //
  822. CWbemPtr<IServerSecurity> pProvCtx = NULL;
  823. CoGetCallContext( IID_IServerSecurity, (void**)&pProvCtx );
  824. //
  825. // NOTE: With cross namespace events, the two parts of the access check
  826. // are split up between the namespaces. The FilterAccessToEvent is
  827. // performed in the event's namespace with the temp subscription's
  828. // AccessCheck. This is possible because the owner sid is propagated
  829. // over with the temp subscription. The EventAccessToFilter is performed
  830. // in the subscription namespace. This is possible because the call
  831. // context and the SD of the event ( containing the event owner sid )
  832. // is propagated with the event. Both functions are called in
  833. // both namespaces, but the unnecessary calls turn out to be no-ops.
  834. //
  835. hr = CheckEventAccessToFilter( pProvCtx );
  836. if ( SUCCEEDED(hr) )
  837. {
  838. //
  839. // check that the event provider allows access to the filter.
  840. //
  841. hr = CheckFilterAccessToEvent( pEventSD );
  842. }
  843. return hr;
  844. }
  845. HRESULT CEventFilter::Deliver( long lNumEvents,
  846. IWbemEvent** apEvents,
  847. CEventContext* pContext )
  848. {
  849. int i;
  850. if( m_lSecurityChecksRemaining > 0 )
  851. {
  852. return WBEM_S_FALSE;
  853. }
  854. CBinding* pBinding = NULL;
  855. {
  856. CInCritSec ics(&m_cs);
  857. if(m_bSingleAsync)
  858. {
  859. //
  860. // Thought we could deliver (call Indicate on the binding) right
  861. // here, since single async ensures that no delivery will occur on
  862. // this thread. But no --- an error may be raised, and that event
  863. // will be delivered on this thread, so we must exit the critsec
  864. // before calling
  865. //
  866. pBinding = m_apBindings[0];
  867. pBinding->AddRef();
  868. }
  869. }
  870. if( pBinding )
  871. {
  872. CReleaseMe rm1(pBinding);
  873. return pBinding->Indicate( lNumEvents, apEvents, pContext );
  874. }
  875. // Make referenced copies of all the bindings to deliver over
  876. // ==========================================================
  877. // CANNOT USE SCOPING DUE TO CTempArray --- it uses _alloca
  878. m_cs.Enter();
  879. CTempArray<CBinding*> apBindings;
  880. int nSize = m_apBindings.GetSize();
  881. if(!INIT_TEMP_ARRAY(apBindings, nSize))
  882. {
  883. m_cs.Leave();
  884. return WBEM_E_OUT_OF_MEMORY;
  885. }
  886. {
  887. for(i = 0; i < nSize; i++)
  888. {
  889. CBinding* pBindingInner = m_apBindings[i];
  890. pBindingInner->AddRef();
  891. apBindings[i] = pBindingInner;
  892. }
  893. }
  894. m_cs.Leave();
  895. // Deliver and release the bindings
  896. // ================================
  897. HRESULT hresGlobal = S_OK;
  898. for(i = 0; i < nSize; i++)
  899. {
  900. CBinding* pBindingInner = apBindings[i];
  901. HRESULT hres = pBindingInner->Indicate( lNumEvents, apEvents, pContext );
  902. pBindingInner->Release();
  903. if(FAILED(hres))
  904. hresGlobal = hres;
  905. }
  906. return hresGlobal;
  907. }
  908. HRESULT CEventFilter::LockForUpdate()
  909. {
  910. // Don't need to do anything since the namespace is locked!
  911. /*
  912. m_csChangeBindings.Enter();
  913. AddRef();
  914. */
  915. return S_OK;
  916. }
  917. HRESULT CEventFilter::UnlockForUpdate()
  918. {
  919. /*
  920. m_csChangeBindings.Leave();
  921. Release();
  922. */
  923. return S_OK;
  924. }
  925. HRESULT CEventFilter::CEventForwardingSink::Indicate(long lNumEvents,
  926. IWbemEvent** apEvents,
  927. CEventContext* pContext)
  928. {
  929. return m_pOwner->Deliver(lNumEvents, apEvents, pContext);
  930. }
  931. void CEventFilter::IncrementRemainingSecurityChecks()
  932. {
  933. InterlockedIncrement(&m_lSecurityChecksRemaining);
  934. }
  935. void CEventFilter::DecrementRemainingSecurityChecks(HRESULT hresProvider)
  936. {
  937. //
  938. // The provider could have said;
  939. // S_OK: this subscription is fine, send all events through or
  940. // S_SUBJECT_TO_SDS: check event security descriptors before sending
  941. // So, if all the providers gave us a blank check, we won't check security
  942. // descriptors, but if any did, we will check them all.
  943. //
  944. if(hresProvider == WBEM_S_SUBJECT_TO_SDS)
  945. {
  946. m_bCheckSDs = true;
  947. }
  948. else if(hresProvider != WBEM_S_NO_ERROR)
  949. {
  950. ERRORTRACE((LOG_ESS, "Invalid return code from provider security test: "
  951. "0x%X\n", hresProvider));
  952. return;
  953. }
  954. InterlockedDecrement(&m_lSecurityChecksRemaining);
  955. }
  956. HRESULT CEventFilter::SetActualClassChangeSink( IWbemObjectSink* pSink,
  957. IWbemObjectSink** ppOldSink )
  958. {
  959. HRESULT hr;
  960. if ( m_pActualClassChangeSink != NULL )
  961. {
  962. m_pActualClassChangeSink->AddRef();
  963. *ppOldSink = m_pActualClassChangeSink;
  964. hr = WBEM_S_NO_ERROR;
  965. }
  966. else
  967. {
  968. *ppOldSink = NULL;
  969. hr = WBEM_S_FALSE;
  970. }
  971. m_pActualClassChangeSink = pSink;
  972. return hr;
  973. }
  974. HRESULT CEventFilter::Reactivate()
  975. {
  976. HRESULT hres;
  977. //
  978. // This is called when a class or something like that changes from
  979. // from underneath us.
  980. // What we need to do is lock the namespace, deactivate this filter, then
  981. // activate it again
  982. //
  983. CInUpdate iu(m_pNamespace);
  984. DEBUGTRACE((LOG_ESS, "Attempting to reactivate filter '%S' in namespace "
  985. "'%S'\n", (LPCWSTR)(WString)GetKey(),
  986. m_pNamespace->GetName()));
  987. // Invalid filters cannot be activated or deactivated
  988. // ==================================================
  989. if(m_eValidity == e_PermanentlyInvalid)
  990. {
  991. DEBUGTRACE((LOG_ESS, "Not reactivate filter '%S' in namespace "
  992. "'%S': permanently invalid\n",
  993. (LPCWSTR)(WString)GetKey(), m_pNamespace->GetName()));
  994. return S_FALSE;
  995. }
  996. if(m_eState == e_Active)
  997. {
  998. DEBUGTRACE((LOG_ESS, "Deactivating filter '%S' in namespace "
  999. "'%S' prior to reactivation\n",
  1000. (LPCWSTR)(WString)GetKey(), m_pNamespace->GetName()));
  1001. hres = m_pNamespace->DeactivateFilter(this);
  1002. if(FAILED(hres))
  1003. {
  1004. ERRORTRACE((LOG_ESS, "Deactivating filter '%S' in namespace "
  1005. "'%S' prior to reactivation failed: 0x%X\n",
  1006. (LPCWSTR)(WString)GetKey(), m_pNamespace->GetName(),
  1007. hres));
  1008. return hres;
  1009. }
  1010. m_eState = e_Inactive;
  1011. }
  1012. hres = AdjustActivation();
  1013. DEBUGTRACE((LOG_ESS, "Reactivating filter '%S' in namespace "
  1014. "'%S' returned 0x%X\n",
  1015. (LPCWSTR)(WString)GetKey(), m_pNamespace->GetName(),
  1016. hres));
  1017. return hres;
  1018. }
  1019. STDMETHODIMP CEventFilter::CClassChangeSink::Indicate( long lNumEvents,
  1020. IWbemEvent** apEvents )
  1021. {
  1022. HRESULT hr;
  1023. hr = m_pOuter->Reactivate();
  1024. if ( SUCCEEDED(hr) )
  1025. {
  1026. hr = m_pOuter->m_pNamespace->FirePostponedOperations();
  1027. }
  1028. else
  1029. {
  1030. m_pOuter->m_pNamespace->FirePostponedOperations();
  1031. }
  1032. if ( FAILED(hr) )
  1033. {
  1034. ERRORTRACE((LOG_ESS, "Error encountered when reactivating filter '%S' "
  1035. "due to a class change. Namespace is '%S', HRES=0x%x\n",
  1036. (LPCWSTR)(WString)m_pOuter->GetKey(),
  1037. m_pOuter->m_pNamespace->GetName(),
  1038. hr ));
  1039. }
  1040. return hr;
  1041. }
  1042. //***************************** Binding ***************************************
  1043. CBinding::CBinding()
  1044. : m_pConsumer(NULL), m_pFilter(NULL), m_dwQoS( WMIMSG_FLAG_QOS_EXPRESS ),
  1045. m_bSlowDown(false), m_bSecure(false), m_bDisabledForSecurity(false)
  1046. {
  1047. InterlockedIncrement( &g_lNumBindings );
  1048. }
  1049. CBinding::CBinding(ADDREF CEventConsumer* pConsumer,
  1050. ADDREF CEventFilter* pFilter)
  1051. : m_pConsumer(NULL), m_pFilter(NULL), m_dwQoS( WMIMSG_FLAG_QOS_EXPRESS ),
  1052. m_bSlowDown(false), m_bSecure(false)
  1053. {
  1054. InterlockedIncrement( &g_lNumBindings );
  1055. SetEndpoints(pConsumer, pFilter, NULL);
  1056. }
  1057. HRESULT CBinding::SetEndpoints(ADDREF CEventConsumer* pConsumer,
  1058. ADDREF CEventFilter* pFilter,
  1059. READONLY PSID pBinderSid)
  1060. {
  1061. m_pConsumer = pConsumer;
  1062. m_pConsumer->AddRef();
  1063. m_pFilter = pFilter;
  1064. m_pFilter->AddRef();
  1065. // Make sure that the owner of this binding is the same as the
  1066. // owners of the endpoints
  1067. // ==================================================================
  1068. if(pBinderSid && (!EqualSid(pBinderSid, pConsumer->GetOwner()) ||
  1069. !EqualSid(pBinderSid, pFilter->GetOwner())))
  1070. {
  1071. DisableForSecurity();
  1072. }
  1073. return WBEM_S_NO_ERROR;
  1074. }
  1075. void CBinding::DisableForSecurity()
  1076. {
  1077. ERRORTRACE((LOG_ESS, "An event binding is disabled because its creator is "
  1078. "not the same security principal as the creators of the endpoints. "
  1079. "The binding and the endpoints must be created by the same user!\n"));
  1080. m_bDisabledForSecurity = true;
  1081. }
  1082. CBinding::~CBinding()
  1083. {
  1084. InterlockedDecrement( &g_lNumBindings );
  1085. if(m_pConsumer)
  1086. m_pConsumer->Release();
  1087. if(m_pFilter)
  1088. m_pFilter->Release();
  1089. }
  1090. DWORD CBinding::GetQoS() NOCS
  1091. {
  1092. return m_dwQoS;
  1093. }
  1094. bool CBinding::IsSynch() NOCS
  1095. {
  1096. return m_dwQoS == WMIMSG_FLAG_QOS_SYNCHRONOUS;
  1097. }
  1098. bool CBinding::IsSecure() NOCS
  1099. {
  1100. return m_bSecure;
  1101. }
  1102. bool CBinding::ShouldSlowDown() NOCS
  1103. {
  1104. return m_bSlowDown;
  1105. }
  1106. HRESULT CBinding::Indicate(long lNumEvents, IWbemEvent** apEvents,
  1107. CEventContext* pContext)
  1108. {
  1109. // Check if this binding is active
  1110. // ===============================
  1111. if(m_bDisabledForSecurity)
  1112. return WBEM_S_FALSE;
  1113. // It is: deliver
  1114. // ==============
  1115. return m_pConsumer->ConsumeFromBinding(this, lNumEvents, apEvents,
  1116. pContext);
  1117. }
  1118. //************************* Consumer watch instruction ************************
  1119. CWbemInterval CConsumerWatchInstruction::mstatic_Interval;
  1120. CConsumerWatchInstruction::CConsumerWatchInstruction(CBindingTable* pTable)
  1121. : CBasicUnloadInstruction(mstatic_Interval),
  1122. m_pTableRef(pTable->m_pTableRef)
  1123. {
  1124. if(m_pTableRef)
  1125. m_pTableRef->AddRef();
  1126. }
  1127. CConsumerWatchInstruction::~CConsumerWatchInstruction()
  1128. {
  1129. if(m_pTableRef)
  1130. m_pTableRef->Release();
  1131. }
  1132. void CConsumerWatchInstruction::staticInitialize(IWbemServices* pRoot)
  1133. {
  1134. mstatic_Interval = CBasicUnloadInstruction::staticRead(pRoot, GetCurrentEssContext(),
  1135. L"__EventSinkCacheControl=@");
  1136. }
  1137. HRESULT CConsumerWatchInstruction::Fire(long, CWbemTime)
  1138. {
  1139. if(!m_bTerminate)
  1140. {
  1141. CEssThreadObject Obj(NULL);
  1142. SetConstructedEssThreadObject(&Obj);
  1143. CEssNamespace* pNamespace = NULL;
  1144. if(m_pTableRef)
  1145. {
  1146. m_pTableRef->GetNamespace(&pNamespace);
  1147. m_pTableRef->UnloadUnusedConsumers(m_Interval);
  1148. }
  1149. Terminate();
  1150. if( pNamespace )
  1151. {
  1152. pNamespace->FirePostponedOperations();
  1153. pNamespace->Release();
  1154. }
  1155. ClearCurrentEssThreadObject();
  1156. }
  1157. return WBEM_S_NO_ERROR; // no point worrying the timer
  1158. }
  1159. //*************************** Binding Table ************************************
  1160. class CConsumersToRelease
  1161. {
  1162. CEventConsumer** m_apConsumers;
  1163. int m_nNumConsumers;
  1164. public:
  1165. CConsumersToRelease(CEventConsumer** apConsumers, int nNumConsumers)
  1166. : m_apConsumers(apConsumers), m_nNumConsumers(nNumConsumers)
  1167. {
  1168. }
  1169. ~CConsumersToRelease()
  1170. {
  1171. for(int i = 0; i < m_nNumConsumers; i++)
  1172. {
  1173. m_apConsumers[i]->Shutdown();
  1174. m_apConsumers[i]->Release();
  1175. }
  1176. delete [] m_apConsumers;
  1177. }
  1178. static DWORD Delete(void* p)
  1179. {
  1180. delete (CConsumersToRelease*)p;
  1181. return 0;
  1182. }
  1183. };
  1184. CBindingTable::CBindingTable(CEssNamespace* pNamespace)
  1185. : m_pNamespace(pNamespace), m_pInstruction(NULL),
  1186. m_bUnloadInstruction(FALSE), m_lNumPermConsumers(0),
  1187. m_pTableRef(NULL)
  1188. {
  1189. m_pTableRef = new CBindingTableRef(this);
  1190. if(m_pTableRef)
  1191. m_pTableRef->AddRef();
  1192. }
  1193. void CBindingTable::Clear( bool bSkipClean )
  1194. {
  1195. //
  1196. // Ensure that no more unloading instructions can make it in
  1197. //
  1198. if(m_pTableRef)
  1199. {
  1200. m_pTableRef->Disconnect();
  1201. m_pTableRef->Release();
  1202. m_pTableRef = NULL;
  1203. }
  1204. // Unbind filter and consumer arrays from the table
  1205. // ================================================
  1206. CEventFilter** apFilters;
  1207. int nNumFilters;
  1208. CEventConsumer** apConsumers;
  1209. int nNumConsumers;
  1210. {
  1211. CInCritSec ics(&m_cs);
  1212. nNumFilters = m_apFilters.GetSize();
  1213. apFilters = m_apFilters.UnbindPtr();
  1214. nNumConsumers = m_apConsumers.GetSize();
  1215. apConsumers = m_apConsumers.UnbindPtr();
  1216. }
  1217. int i;
  1218. // Unbind and release all filters
  1219. // ==============================
  1220. if ( apFilters )
  1221. {
  1222. for(i = 0; i < nNumFilters; i++)
  1223. {
  1224. if (!apFilters[i]->IsInternal())
  1225. {
  1226. g_quotas.DecrementQuotaIndex(
  1227. apFilters[i]->GetOwner() ? ESSQ_PERM_SUBSCRIPTIONS :
  1228. ESSQ_TEMP_SUBSCRIPTIONS,
  1229. apFilters[i],
  1230. 1 );
  1231. }
  1232. apFilters[i]->Unbind(bSkipClean); // shutting down
  1233. apFilters[i]->Release();
  1234. }
  1235. delete [] apFilters;
  1236. }
  1237. //
  1238. // unbind all consumers, but postpone their release.
  1239. //
  1240. if ( apConsumers )
  1241. {
  1242. for(i = 0; i < nNumConsumers; i++)
  1243. {
  1244. apConsumers[i]->Unbind(); // shutting down
  1245. }
  1246. //
  1247. // Release all consumers (unbound by virtue of filter unbinding), but do
  1248. // so on a separate thread
  1249. //
  1250. CConsumersToRelease* pToRelease =
  1251. new CConsumersToRelease(apConsumers, nNumConsumers);
  1252. DWORD dwId;
  1253. HANDLE hThread = CreateThread(NULL, 0,
  1254. (LPTHREAD_START_ROUTINE)CConsumersToRelease::Delete, pToRelease, 0,
  1255. &dwId);
  1256. if(hThread == NULL)
  1257. {
  1258. ERRORTRACE((LOG_ESS, "Unable to launch consumer deleting thread: %d\n",
  1259. GetLastError()));
  1260. }
  1261. else
  1262. {
  1263. //
  1264. // Wait for 8 seconds --- David's magic constant
  1265. //
  1266. DWORD dwRes = WaitForSingleObject(hThread, 8000);
  1267. CloseHandle(hThread);
  1268. if(dwRes != WAIT_OBJECT_0)
  1269. {
  1270. ERRORTRACE((LOG_ESS, "Consumer deleting thread failed to finish in "
  1271. "time in namespace %S. Some consumers may not receive their "
  1272. "Release calls until DCOM times out\n",
  1273. m_pNamespace->GetName()));
  1274. }
  1275. }
  1276. }
  1277. }
  1278. HRESULT CBindingTable::AddEventFilter(CEventFilter* pFilter)
  1279. {
  1280. HRESULT hr;
  1281. if (pFilter->IsInternal() ||
  1282. SUCCEEDED(hr = g_quotas.IncrementQuotaIndex(
  1283. pFilter->GetOwner() ? ESSQ_PERM_SUBSCRIPTIONS : ESSQ_TEMP_SUBSCRIPTIONS,
  1284. pFilter,
  1285. 1)))
  1286. {
  1287. CInCritSec ics(&m_cs);
  1288. if (m_apFilters.Add(pFilter) >= 0)
  1289. hr = S_OK;
  1290. else
  1291. hr = WBEM_E_OUT_OF_MEMORY;
  1292. }
  1293. return hr;
  1294. }
  1295. HRESULT CBindingTable::AddEventConsumer(CEventConsumer* pConsumer)
  1296. {
  1297. CInCritSec ics(&m_cs);
  1298. if(m_apConsumers.Add(pConsumer) < 0)
  1299. return WBEM_E_OUT_OF_MEMORY;
  1300. if(pConsumer->IsPermanent())
  1301. {
  1302. if(m_lNumPermConsumers++ == 0)
  1303. m_pNamespace->SetActive();
  1304. }
  1305. return S_OK;
  1306. }
  1307. HRESULT CBindingTable::FindEventFilter(LPCWSTR wszKey,
  1308. RELEASE_ME CEventFilter** ppFilter)
  1309. {
  1310. CInCritSec ics(&m_cs);
  1311. if(m_apFilters.Find(wszKey, ppFilter))
  1312. return S_OK;
  1313. else
  1314. return WBEM_E_NOT_FOUND;
  1315. }
  1316. HRESULT CBindingTable::FindEventConsumer(LPCWSTR wszKey,
  1317. RELEASE_ME CEventConsumer** ppConsumer)
  1318. {
  1319. CInCritSec ics(&m_cs);
  1320. if(m_apConsumers.Find(wszKey, ppConsumer))
  1321. return S_OK;
  1322. else
  1323. return WBEM_E_NOT_FOUND;
  1324. }
  1325. HRESULT CBindingTable::RemoveEventFilter(LPCWSTR wszKey)
  1326. {
  1327. // Find it and remove it from the table
  1328. // ====================================
  1329. CEventFilter* pFilter = NULL;
  1330. HRESULT hres;
  1331. {
  1332. CInCritSec ics(&m_cs);
  1333. if(!m_apFilters.Remove(wszKey, &pFilter))
  1334. return WBEM_E_NOT_FOUND;
  1335. }
  1336. if(pFilter == NULL)
  1337. return WBEM_E_CRITICAL_ERROR;
  1338. // Remove 1 from our quota count.
  1339. if (!pFilter->IsInternal())
  1340. {
  1341. g_quotas.DecrementQuotaIndex(
  1342. pFilter->GetOwner() ? ESSQ_PERM_SUBSCRIPTIONS : ESSQ_TEMP_SUBSCRIPTIONS,
  1343. pFilter,
  1344. 1);
  1345. }
  1346. // Unbind it, thus deactivating
  1347. // ============================
  1348. hres = pFilter->Unbind();
  1349. pFilter->Release();
  1350. return hres;
  1351. }
  1352. void CBindingTable::MarkRemoval(CEventConsumer* pConsumer)
  1353. {
  1354. if(pConsumer && pConsumer->IsPermanent())
  1355. {
  1356. if(--m_lNumPermConsumers == 0)
  1357. m_pNamespace->SetInactive();
  1358. }
  1359. }
  1360. HRESULT CBindingTable::RemoveEventConsumer(LPCWSTR wszKey)
  1361. {
  1362. // Find it and remove it from the table
  1363. // ====================================
  1364. CEventConsumer* pConsumer = NULL;
  1365. HRESULT hres;
  1366. {
  1367. CInCritSec ics(&m_cs);
  1368. if(!m_apConsumers.Remove(wszKey, &pConsumer))
  1369. return WBEM_E_NOT_FOUND;
  1370. MarkRemoval(pConsumer);
  1371. }
  1372. if(pConsumer == NULL)
  1373. return WBEM_E_CRITICAL_ERROR;
  1374. hres = pConsumer->Unbind();
  1375. pConsumer->Release();
  1376. return hres;
  1377. }
  1378. HRESULT CBindingTable::Bind(LPCWSTR wszFilterKey, LPCWSTR wszConsumerKey,
  1379. CBinding* pBinding, PSID pBinderSid)
  1380. {
  1381. // Find them both and get ref-counted pointers
  1382. // ===========================================
  1383. CEventFilter* pFilter;
  1384. CEventConsumer* pConsumer;
  1385. HRESULT hres;
  1386. {
  1387. CInCritSec ics(&m_cs);
  1388. hres = FindEventFilter(wszFilterKey, &pFilter);
  1389. if(FAILED(hres)) return hres;
  1390. hres = FindEventConsumer(wszConsumerKey, &pConsumer);
  1391. if(FAILED(hres))
  1392. {
  1393. pFilter->Release();
  1394. return hres;
  1395. }
  1396. }
  1397. // Fully construct the binding --- will check security
  1398. // ===================================================
  1399. hres = pBinding->SetEndpoints(pConsumer, pFilter, pBinderSid);
  1400. if(FAILED(hres))
  1401. return hres;
  1402. // Make them reference each other
  1403. // ==============================
  1404. HRESULT hresGlobal = S_OK;
  1405. hres = pFilter->EnsureReferences(pConsumer, pBinding);
  1406. if(FAILED(hres))
  1407. hresGlobal = hres;
  1408. hres = pConsumer->EnsureReferences(pFilter, pBinding);
  1409. if(FAILED(hres))
  1410. hresGlobal = hres;
  1411. // Cleanup
  1412. // =======
  1413. pConsumer->Release();
  1414. pFilter->Release();
  1415. return hresGlobal;
  1416. }
  1417. HRESULT CBindingTable::Unbind(LPCWSTR wszFilterKey, LPCWSTR wszConsumerKey)
  1418. {
  1419. // Find them both and get ref-counted pointers
  1420. // ===========================================
  1421. CEventFilter* pFilter;
  1422. CEventConsumer* pConsumer;
  1423. HRESULT hres;
  1424. {
  1425. CInCritSec ics(&m_cs);
  1426. hres = FindEventFilter(wszFilterKey, &pFilter);
  1427. if(FAILED(hres)) return hres;
  1428. hres = FindEventConsumer(wszConsumerKey, &pConsumer);
  1429. if(FAILED(hres))
  1430. {
  1431. pFilter->Release();
  1432. return hres;
  1433. }
  1434. }
  1435. // Remove respective references
  1436. // ============================
  1437. HRESULT hresGlobal = S_OK;
  1438. hres = pFilter->EnsureNotReferences(pConsumer);
  1439. if(FAILED(hres))
  1440. hresGlobal = hres;
  1441. pConsumer->EnsureNotReferences(pFilter);
  1442. if(FAILED(hres))
  1443. hresGlobal = hres;
  1444. pFilter->Release();
  1445. pConsumer->Release();
  1446. return hresGlobal;
  1447. }
  1448. BOOL CBindingTable::DoesHavePermanentConsumers()
  1449. {
  1450. return (m_lNumPermConsumers != 0);
  1451. }
  1452. HRESULT CBindingTable::ResetProviderRecords(LPCWSTR wszProviderRef)
  1453. {
  1454. // Make a copy of the list of consumers, AddRefed
  1455. // ==============================================
  1456. CRefedPointerArray<CEventConsumer> apConsumers;
  1457. if(!GetConsumers(apConsumers))
  1458. return WBEM_E_OUT_OF_MEMORY;
  1459. // Go through all the consumers and see if they reference this record
  1460. // ==================================================================
  1461. for(int i = 0; i < apConsumers.GetSize(); i++)
  1462. {
  1463. apConsumers[i]->ResetProviderRecord(wszProviderRef);
  1464. }
  1465. return S_OK;
  1466. }
  1467. //*******************************************************************************
  1468. //
  1469. // EnsureConsumerWatchInstruction / UnloadUnusedConsumers synchronization
  1470. //
  1471. // Usage:
  1472. //
  1473. // ECWI is called when a consumer is loaded. It is called after the consumer
  1474. // record has been updated. Post-condition: UnloadUnusedConsumers must be
  1475. // called at least once after this function starts executing.
  1476. //
  1477. // UUC is called by the CConsumerWatchTimerInstruction::Fire on timer. The
  1478. // instruction then self-destructs. Post-condition: idle consumers
  1479. // unloaded; if any are still active, another UUC will occur in the future;
  1480. // If none are active for a while, no UUC will occur in the future,
  1481. // until ECWI is called.
  1482. //
  1483. // Primitives:
  1484. //
  1485. // CS m_cs: atomic, data access
  1486. //
  1487. // BOOL m_bUnloadInstruction: Can only be accessed in m_cs. Semantics:
  1488. // TRUE if an instruction is either scheduled or will be scheduled
  1489. // shortly; this putative instruction, when fired, is guaranteed to
  1490. // examine any consumer in the table at the time of he check.
  1491. //
  1492. // Algorithm:
  1493. //
  1494. // ECWI checks m_bUnloadInstructiion (in m_cs) and if TRUE does nothing, as the
  1495. // m_bUnloadInstruction == TRUE guarantee above assures that UUC will be
  1496. // called. If it is FALSE, ECWI sets it to TRUE, then schedules an
  1497. // instruction (outside of m_cs). The setting of m_bUnloadInstruction to
  1498. // TRUE is correct, since an instruction will be scheduled shortly. Thus,
  1499. // ECWI post-condition is satisfied, assuming primitive semantics above.
  1500. //
  1501. // UUC, in m_cs, sets m_bUnloadInstriction to FALSE and makes a copy of the
  1502. // consumer list. Outside of m_cs, it iterates over the copy and unloads
  1503. // consumers as required. Then, if any are active, it calls ECWI. This
  1504. // guarantees that another UUC will be called. If a consumer was active
  1505. // before the entry into m_cs, we call ECWI. If a consumer became active
  1506. // after we entered into m_cs, it will call ECWI after we have reset
  1507. // m_bUnloadInstruction, causing another instruction to be scheduled. This
  1508. // proves our post-condition assuming primitive semantics above.
  1509. //
  1510. // Proof of primitives:
  1511. //
  1512. // m_bUnloadInstruction becomes TRUE only in ECWI. When it does, ECWI is
  1513. // guaranteed to schedule a new instruction, causing a call to UUC. So, the
  1514. // semantics holds in the beginning. It can become invalid if UUC fires and is
  1515. // not rescheduled. But UUC resets m_bUnloadInstruction to FALSE, thus making
  1516. // semantics valid vacuously.
  1517. //
  1518. // Now, we need to show that any consumer in the table at the time when
  1519. // m_bUnloadInstruction == TRUE will be examined by the scheduled UUC. Well,
  1520. // the latest scheduled (or about to be scheduled) UUC, cannot have exited
  1521. // its m_cs stint yet, for otherwise m_bUnloadInstruction would be FALSE.
  1522. // Therefore, it hasn't entered it yet, and therefore hasn't made a copy yet.
  1523. //
  1524. //******************************************************************************
  1525. HRESULT CBindingTable::EnsureConsumerWatchInstruction()
  1526. {
  1527. // Check if it is already there
  1528. // ============================
  1529. BOOL bMustSchedule = FALSE;
  1530. {
  1531. CInCritSec ics(&m_cs);
  1532. if(!m_bUnloadInstruction)
  1533. {
  1534. // Not there. Mark as there, preventing others from scheduling
  1535. // more.
  1536. // ============================================================
  1537. m_bUnloadInstruction = TRUE;
  1538. bMustSchedule = TRUE;
  1539. }
  1540. }
  1541. if(bMustSchedule)
  1542. {
  1543. CConsumerWatchInstruction* pInst = new CConsumerWatchInstruction(this);
  1544. if(pInst == NULL)
  1545. {
  1546. CInCritSec ics(&m_cs);
  1547. m_bUnloadInstruction = FALSE;
  1548. return WBEM_E_OUT_OF_MEMORY;
  1549. }
  1550. pInst->AddRef();
  1551. // Set it in the generator
  1552. // =======================
  1553. HRESULT hres = m_pNamespace->GetTimerGenerator().Set(pInst);
  1554. if(FAILED(hres))
  1555. {
  1556. CInCritSec ics(&m_cs);
  1557. m_bUnloadInstruction = FALSE;
  1558. return hres;
  1559. }
  1560. pInst->Release();
  1561. return S_OK;
  1562. }
  1563. else
  1564. {
  1565. return S_FALSE;
  1566. }
  1567. }
  1568. HRESULT CBindingTable::UnloadUnusedConsumers(CWbemInterval Interval)
  1569. {
  1570. // Mark unload instruction as empty and copy consumer records
  1571. // ==========================================================
  1572. CRefedPointerArray<CEventConsumer> apConsumers;
  1573. {
  1574. CInCritSec ics(&m_cs);
  1575. m_bUnloadInstruction = FALSE;
  1576. if(!GetConsumers(apConsumers))
  1577. return WBEM_E_OUT_OF_MEMORY;
  1578. }
  1579. // Go through the consumers and unload them if needed
  1580. // ==================================================
  1581. BOOL bUnloaded = FALSE;
  1582. BOOL bActive = FALSE;
  1583. for(int i = 0; i < apConsumers.GetSize(); i++)
  1584. {
  1585. if(apConsumers[i]->UnloadIfUnusedFor(Interval))
  1586. bUnloaded = TRUE;
  1587. else if(!apConsumers[i]->IsFullyUnloaded())
  1588. bActive = TRUE;
  1589. }
  1590. // Schedule DLL unloading if any COM objects were unloaded
  1591. // =======================================================
  1592. if(bUnloaded)
  1593. m_pNamespace->GetTimerGenerator().ScheduleFreeUnusedLibraries();
  1594. // Schedule the new instruction if needed
  1595. // ======================================
  1596. if(bActive)
  1597. return EnsureConsumerWatchInstruction();
  1598. return S_OK;
  1599. }
  1600. BOOL CBindingTable::GetConsumers(
  1601. CRefedPointerArray<CEventConsumer>& apConsumers)
  1602. {
  1603. CInCritSec ics(&m_cs);
  1604. TConsumerIterator it;
  1605. for(it = m_apConsumers.Begin(); it != m_apConsumers.End(); it++)
  1606. {
  1607. if(apConsumers.Add(*it) < 0)
  1608. return FALSE;
  1609. }
  1610. return TRUE;
  1611. }
  1612. BOOL CBindingTable::GetEventFilters( CRefedPointerArray< CEventFilter > & apEventFilters )
  1613. {
  1614. CInCritSec ics( &m_cs );
  1615. TFilterIterator it;
  1616. for( it = m_apFilters.Begin( ); it != m_apFilters.End( ); ++it )
  1617. {
  1618. if( apEventFilters.Add( *it ) < 0 )
  1619. {
  1620. return FALSE;
  1621. }
  1622. }
  1623. return TRUE;
  1624. }
  1625. HRESULT CBindingTable::RemoveConsumersStartingWith(LPCWSTR wszPrefix)
  1626. {
  1627. CRefedPointerArray<CEventConsumer> apToRelease;
  1628. int nLen = wcslen(wszPrefix);
  1629. {
  1630. CInCritSec ics(&m_cs);
  1631. TConsumerIterator it = m_apConsumers.Begin();
  1632. while(it != m_apConsumers.End())
  1633. {
  1634. if(!wcsncmp((WString)(*it)->GetKey(), wszPrefix, nLen))
  1635. {
  1636. // Found it --- move to the "to be released" list
  1637. // ==============================================
  1638. CEventConsumer* pConsumer;
  1639. it = m_apConsumers.Remove(it, &pConsumer);
  1640. MarkRemoval(pConsumer);
  1641. apToRelease.Add(pConsumer);
  1642. pConsumer->Release();
  1643. }
  1644. else
  1645. {
  1646. it++;
  1647. }
  1648. }
  1649. }
  1650. // Unbind all the consumers we have left. Release will happen on destruct
  1651. // =======================================================================
  1652. for(int i = 0; i < apToRelease.GetSize(); i++)
  1653. {
  1654. apToRelease[i]->Unbind();
  1655. }
  1656. return WBEM_S_NO_ERROR;
  1657. }
  1658. HRESULT CBindingTable::RemoveConsumerWithFilters(LPCWSTR wszConsumerKey)
  1659. {
  1660. HRESULT hres;
  1661. CRefedPointerSmallArray<CEventFilter> apFilters;
  1662. {
  1663. CInCritSec ics(&m_cs);
  1664. // Find the consumer in question
  1665. // =============================
  1666. CEventConsumer* pConsumer = NULL;
  1667. hres = FindEventConsumer(wszConsumerKey, &pConsumer);
  1668. if(FAILED(hres))
  1669. return hres;
  1670. CReleaseMe rm1(pConsumer);
  1671. // Make addrefed copies of all its associated filters
  1672. // ==================================================
  1673. hres = pConsumer->GetAssociatedFilters(apFilters);
  1674. if(FAILED(hres))
  1675. return hres;
  1676. }
  1677. // Remove the consumer
  1678. // ===================
  1679. RemoveEventConsumer(wszConsumerKey);
  1680. // Remove every one of its filters
  1681. // ===============================
  1682. for(int i = 0; i < apFilters.GetSize(); i++)
  1683. {
  1684. RemoveEventFilter((WString)apFilters[i]->GetKey());
  1685. }
  1686. return S_OK;
  1687. }
  1688. HRESULT CBindingTable::ReactivateAllFilters()
  1689. {
  1690. // Retrieve a copy of all the filters
  1691. // ==================================
  1692. CRefedPointerArray<CEventFilter> apFilters;
  1693. {
  1694. CInCritSec ics(&m_cs);
  1695. TFilterIterator it;
  1696. for(it = m_apFilters.Begin(); it != m_apFilters.End(); it++)
  1697. {
  1698. if(apFilters.Add(*it) < 0)
  1699. return WBEM_E_OUT_OF_MEMORY;
  1700. }
  1701. }
  1702. // Reactivate them all
  1703. // ===================
  1704. for(int i = 0; i < apFilters.GetSize(); i++)
  1705. {
  1706. CEventFilter* pFilter = apFilters[i];
  1707. pFilter->SetInactive();
  1708. pFilter->AdjustActivation();
  1709. }
  1710. return WBEM_S_NO_ERROR;
  1711. }
  1712. void CBindingTable::Park()
  1713. {
  1714. //
  1715. // Tell each filter to "park" itself
  1716. //
  1717. CInCritSec ics(&m_cs);
  1718. TFilterIterator it;
  1719. for(it = m_apFilters.Begin(); it != m_apFilters.End(); it++)
  1720. {
  1721. (*it)->Park();
  1722. }
  1723. }
  1724. void CBindingTable::DumpStatistics(FILE* f, long lFlags)
  1725. {
  1726. fprintf(f, "%d consumers (%d permanent), %d filters\n",
  1727. m_apConsumers.GetSize(), m_lNumPermConsumers,
  1728. m_apFilters.GetSize());
  1729. }
  1730. CBindingTableRef::~CBindingTableRef()
  1731. {
  1732. }
  1733. CBindingTableRef::CBindingTableRef(CBindingTable* pTable)
  1734. : m_pTable(pTable), m_lRef(0)
  1735. {
  1736. }
  1737. void CBindingTableRef::AddRef()
  1738. {
  1739. InterlockedIncrement(&m_lRef);
  1740. }
  1741. void CBindingTableRef::Release()
  1742. {
  1743. if(InterlockedDecrement(&m_lRef) == 0)
  1744. delete this;
  1745. }
  1746. void CBindingTableRef::Disconnect()
  1747. {
  1748. CInCritSec ics(&m_cs);
  1749. m_pTable = NULL;
  1750. }
  1751. HRESULT CBindingTableRef::UnloadUnusedConsumers(CWbemInterval Interval)
  1752. {
  1753. CInCritSec ics(&m_cs);
  1754. if(m_pTable)
  1755. return m_pTable->UnloadUnusedConsumers(Interval);
  1756. else
  1757. return WBEM_S_FALSE;
  1758. }
  1759. HRESULT CBindingTableRef::GetNamespace(RELEASE_ME CEssNamespace** ppNamespace)
  1760. {
  1761. CInCritSec ics(&m_cs);
  1762. if(m_pTable)
  1763. {
  1764. *ppNamespace = m_pTable->m_pNamespace;
  1765. if(*ppNamespace)
  1766. (*ppNamespace)->AddRef();
  1767. }
  1768. else
  1769. {
  1770. *ppNamespace = NULL;
  1771. }
  1772. return WBEM_S_NO_ERROR;
  1773. }