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.

1909 lines
50 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 <vector>
  17. #include "Quota.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. return hres;
  134. }
  135. HRESULT CEventConsumer::ConsumeFromBinding(CBinding* pBinding,
  136. long lNumEvents, IWbemEvent** apEvents,
  137. CEventContext* pContext)
  138. {
  139. DWORD dwQoS = pBinding->GetQoS();
  140. if( dwQoS == WMIMSG_FLAG_QOS_SYNCHRONOUS )
  141. {
  142. // Synchronous delivery --- call the ultimate client
  143. // =================================================
  144. IUnknown* pOldSec = NULL;
  145. HRESULT hr;
  146. if(!pBinding->IsSecure())
  147. {
  148. hr = CoSwitchCallContext(NULL, &pOldSec);
  149. if ( FAILED( hr ) )
  150. {
  151. return hr;
  152. }
  153. }
  154. HRESULT hres = ActuallyDeliver( lNumEvents,
  155. apEvents,
  156. pBinding->IsSecure(),
  157. pContext );
  158. if(!pBinding->IsSecure())
  159. {
  160. IUnknown* pGarb = NULL;
  161. hr = CoSwitchCallContext(pOldSec, &pGarb);
  162. if ( FAILED( hr ) && SUCCEEDED ( hres ) )
  163. {
  164. return hr;
  165. }
  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_lSubjectToSDSCount(0), m_hresPollingError(S_OK),
  213. m_hresFilterError(WBEM_E_CRITICAL_ERROR), m_bCheckSDs(true),
  214. m_bHasBeenValid(false), m_dwLastTokenAttempt(0), m_pToken(NULL),
  215. m_bReconstructOnHit(false), m_hresTokenError(WBEM_E_CRITICAL_ERROR)
  216. {
  217. InterlockedIncrement( &g_lNumFilters );
  218. m_pNamespace->AddRef();
  219. }
  220. CEventFilter::~CEventFilter()
  221. {
  222. InterlockedDecrement( &g_lNumFilters );
  223. delete [] m_pOwnerSid;
  224. if(m_pNamespace)
  225. m_pNamespace->Release();
  226. if(m_pToken)
  227. m_pToken->Release();
  228. }
  229. HRESULT CEventFilter::EnsureReferences(CEventConsumer* pConsumer,
  230. CBinding* pBinding)
  231. {
  232. CBinding* pOldBinding = NULL;
  233. {
  234. CInUpdate iu(this);
  235. // Actually change the bindings
  236. // ============================
  237. {
  238. CInCritSec ics(&m_cs);
  239. for(int i = 0; i < m_apBindings.GetSize(); i++)
  240. {
  241. if(m_apBindings[i]->GetConsumer() == pConsumer)
  242. {
  243. // Replace the binding
  244. // ===================
  245. // binding cannot change synchronicity --- in such cases,
  246. // it is first removed, and then re-added. Therefore,
  247. // no m_bSingleAsync adjustment is needed
  248. m_apBindings.SetAt(i, pBinding, &pOldBinding);
  249. break;
  250. }
  251. }
  252. if(pOldBinding == NULL)
  253. {
  254. // Add it to the list
  255. // ==================
  256. if(m_apBindings.Add(pBinding) < 0)
  257. return WBEM_E_OUT_OF_MEMORY;
  258. AdjustSingleAsync();
  259. }
  260. }
  261. // Activate if needed
  262. // ==================
  263. AdjustActivation();
  264. }
  265. if(pOldBinding)
  266. {
  267. // Found
  268. // =====
  269. pOldBinding->Release();
  270. return S_FALSE;
  271. }
  272. else
  273. {
  274. return S_OK;
  275. }
  276. }
  277. HRESULT CEventFilter::EnsureNotReferences(CEventConsumer* pConsumer)
  278. {
  279. CBinding* pOldBinding = NULL;
  280. {
  281. CInUpdate iu(this);
  282. // Make the actual change
  283. // ======================
  284. {
  285. CInCritSec ics(&m_cs);
  286. for(int i = 0; i < m_apBindings.GetSize(); i++)
  287. {
  288. if(m_apBindings[i]->GetConsumer() == pConsumer)
  289. {
  290. // Remove the binding
  291. // ==================
  292. m_apBindings.RemoveAt(i, &pOldBinding);
  293. AdjustSingleAsync();
  294. break;
  295. }
  296. } // for
  297. } // m_cs
  298. // Deactivate the filter if necessary
  299. // ==================================
  300. AdjustActivation();
  301. } // update
  302. if(pOldBinding)
  303. {
  304. pOldBinding->Release();
  305. return S_OK;
  306. }
  307. else
  308. {
  309. // Not found
  310. // =========
  311. return S_FALSE;
  312. }
  313. }
  314. HRESULT CEventFilter::Unbind(bool bShuttingDown)
  315. {
  316. // Unbind the binding array from the filter
  317. // ========================================
  318. std::vector< CWbemPtr < CBinding >,wbem_allocator< CWbemPtr<CBinding> > > apBindings;
  319. int nNumBindings = 0;
  320. {
  321. CInUpdate iu(this);
  322. {
  323. CInCritSec ics(&m_cs);
  324. nNumBindings = m_apBindings.GetSize();
  325. apBindings.insert(apBindings.begin(),nNumBindings,CWbemPtr<CBinding>()); // may throw
  326. CBinding ** ppBindTmp = m_apBindings.UnbindPtr(); //needed to set size to zero
  327. CVectorDeleteMe<CBinding *> dm(ppBindTmp);
  328. if ( NULL == ppBindTmp)
  329. {
  330. return WBEM_S_FALSE;
  331. }
  332. for (int Idx=0;Idx<nNumBindings;Idx++)
  333. {
  334. apBindings[Idx].Attach(ppBindTmp[Idx]); // does not AddRef
  335. }
  336. m_bSingleAsync = false;
  337. }
  338. if(!bShuttingDown)
  339. AdjustActivation(); // throws
  340. }
  341. // Instruct all the consumers that are bound to us to unbind
  342. // =========================================================
  343. HRESULT hres = S_OK;
  344. for(int i = 0; i < nNumBindings; i++)
  345. {
  346. HRESULT hr = apBindings[i]->GetConsumer()->EnsureNotReferences(this);
  347. if ( FAILED( hr ) )
  348. {
  349. hres = hr;
  350. }
  351. apBindings[i].Release(); // performs the "final" release
  352. }
  353. return hres;
  354. }
  355. void CEventFilter::SetInactive()
  356. {
  357. m_eState = e_Inactive;
  358. }
  359. BOOL CEventFilter::IsActive()
  360. {
  361. return (m_eState == e_Active);
  362. }
  363. HRESULT CEventFilter::GetFilterError()
  364. {
  365. return m_hresFilterError;
  366. }
  367. HRESULT CEventFilter::GetEventNamespace(LPWSTR* pwszNamespace)
  368. {
  369. *pwszNamespace = NULL;
  370. return S_OK;
  371. }
  372. // assumes in m_cs
  373. void CEventFilter::AdjustSingleAsync()
  374. {
  375. if(m_apBindings.GetSize() > 1)
  376. m_bSingleAsync = false;
  377. else if(m_apBindings.GetSize() == 0)
  378. m_bSingleAsync = false;
  379. else if(m_apBindings[0]->IsSynch())
  380. m_bSingleAsync = false;
  381. else
  382. m_bSingleAsync = true;
  383. }
  384. bool CEventFilter::IsBound()
  385. {
  386. return (m_apBindings.GetSize() != 0);
  387. }
  388. // Requires: in m_csChangeBindings
  389. HRESULT CEventFilter::AdjustActivation()
  390. {
  391. // Invalid filters cannot be activated or deactivated
  392. // ==================================================
  393. if(m_eValidity == e_PermanentlyInvalid)
  394. return S_FALSE;
  395. HRESULT hres = S_FALSE;
  396. if(!IsBound() )
  397. {
  398. //
  399. // Even if this filter is not active, it may be subscribed for
  400. // activation events if it is temporarily invalid (and that's the only
  401. // reason it is not active).
  402. //
  403. m_pNamespace->UnregisterFilterFromAllClassChanges(this);
  404. if(m_eState == e_Active)
  405. {
  406. hres = m_pNamespace->DeactivateFilter(this);
  407. if(FAILED(hres)) return hres;
  408. m_eState = e_Inactive;
  409. }
  410. return WBEM_S_NO_ERROR;
  411. }
  412. else if(m_eState == e_Inactive && IsBound() )
  413. {
  414. //
  415. // Even though this filter is not active, it may be subscribed for
  416. // activation events if it is temporarily invalid (and that's the only
  417. // reason it is not active).
  418. //
  419. m_pNamespace->UnregisterFilterFromAllClassChanges(this);
  420. hres = m_pNamespace->ActivateFilter(this);
  421. if(FAILED(hres)) return hres;
  422. m_eState = e_Active;
  423. return WBEM_S_NO_ERROR;
  424. }
  425. else
  426. {
  427. return S_FALSE;
  428. }
  429. }
  430. void CEventFilter::MarkAsPermanentlyInvalid(HRESULT hres)
  431. {
  432. m_eValidity = e_PermanentlyInvalid;
  433. m_hresFilterError = hres;
  434. }
  435. void CEventFilter::MarkAsTemporarilyInvalid(HRESULT hres)
  436. {
  437. m_eValidity = e_TemporarilyInvalid;
  438. m_hresFilterError = hres;
  439. }
  440. void CEventFilter::MarkAsValid()
  441. {
  442. m_eValidity = e_Valid;
  443. m_bHasBeenValid = true;
  444. m_hresFilterError = WBEM_S_NO_ERROR;
  445. }
  446. void CEventFilter::MarkReconstructOnHit(bool bReconstruct)
  447. {
  448. //
  449. // Reconstruction is not really needed, since dummer nodes are used for
  450. // this
  451. //
  452. m_bReconstructOnHit = bReconstruct;
  453. }
  454. HRESULT CEventFilter::CheckEventAccessToFilter( IServerSecurity* pProvCtx )
  455. {
  456. HRESULT hr = WBEM_S_NO_ERROR;
  457. const PSECURITY_DESCRIPTOR pEventAccessSD = GetEventAccessSD();
  458. if ( pEventAccessSD == NULL )
  459. {
  460. //
  461. // filter allows all events
  462. //
  463. return WBEM_S_NO_ERROR;
  464. }
  465. //
  466. // check that the event provider's calling context has access to filter
  467. //
  468. if ( pProvCtx != NULL )
  469. {
  470. hr = pProvCtx->ImpersonateClient();
  471. if ( SUCCEEDED(hr) )
  472. {
  473. HANDLE hToken;
  474. if ( OpenThreadToken( GetCurrentThread(),
  475. TOKEN_QUERY,
  476. TRUE,
  477. &hToken ) )
  478. {
  479. GENERIC_MAPPING map;
  480. ZeroMemory( &map, sizeof(GENERIC_MAPPING) );
  481. PRIVILEGE_SET ps;
  482. DWORD dwPrivLength = sizeof(ps);
  483. BOOL bStatus;
  484. DWORD dwGranted;
  485. if ( ::AccessCheck( PSECURITY_DESCRIPTOR(pEventAccessSD),
  486. hToken,
  487. WBEM_RIGHT_PUBLISH,
  488. &map,
  489. &ps,
  490. &dwPrivLength,
  491. &dwGranted,
  492. &bStatus ) )
  493. {
  494. hr = bStatus ? WBEM_S_NO_ERROR : WBEM_E_ACCESS_DENIED;
  495. }
  496. else
  497. {
  498. hr = HRESULT_FROM_WIN32( GetLastError() );
  499. }
  500. CloseHandle( hToken );
  501. }
  502. else
  503. {
  504. hr = HRESULT_FROM_WIN32( GetLastError() );
  505. }
  506. pProvCtx->RevertToSelf();
  507. }
  508. }
  509. return hr;
  510. }
  511. HRESULT CEventFilter::CheckFilterAccessToEvent( PSECURITY_DESCRIPTOR pEventSD )
  512. {
  513. HRESULT hr;
  514. if ( pEventSD == NULL )
  515. {
  516. //
  517. // event provider allows all filters access
  518. //
  519. return WBEM_S_NO_ERROR;
  520. }
  521. if( !m_bCheckSDs )
  522. {
  523. //
  524. // This filter was unconditionally allowed by all its event providers!
  525. //
  526. return WBEM_S_NO_ERROR;
  527. }
  528. //
  529. // Get the token for this filter
  530. //
  531. if( m_pToken == NULL && FAILED(m_hresTokenError) )
  532. {
  533. //
  534. // Check how long it's been since we last attempted to get the token --
  535. // don't want to do that too often.
  536. //
  537. if(m_dwLastTokenAttempt == 0 ||
  538. m_dwLastTokenAttempt <
  539. GetTickCount() - MIN_TIMEOUT_BETWEEN_TOKEN_ATTEMPTS )
  540. {
  541. //
  542. // Get the filter to find a token, however it does that
  543. //
  544. m_hresTokenError = ObtainToken( &m_pToken );
  545. if( FAILED(m_hresTokenError) )
  546. {
  547. m_dwLastTokenAttempt = GetTickCount();
  548. }
  549. }
  550. }
  551. if ( m_hresTokenError == WBEM_S_NO_ERROR )
  552. {
  553. _DBG_ASSERT( m_pToken != NULL );
  554. //
  555. // Check security for real
  556. //
  557. DWORD dwGranted;
  558. hr = m_pToken->AccessCheck( WBEM_RIGHT_SUBSCRIBE,
  559. (const BYTE*)pEventSD,
  560. &dwGranted );
  561. if( SUCCEEDED(hr) )
  562. {
  563. if(dwGranted & WBEM_RIGHT_SUBSCRIBE)
  564. {
  565. hr = WBEM_S_NO_ERROR;
  566. }
  567. else
  568. {
  569. hr = WBEM_E_ACCESS_DENIED;
  570. }
  571. }
  572. }
  573. else
  574. {
  575. hr = m_hresTokenError;
  576. }
  577. return hr;
  578. }
  579. HRESULT CEventFilter::AccessCheck( CEventContext* pContext, IWbemEvent* pEvent)
  580. {
  581. HRESULT hr;
  582. //
  583. // With polling, there will be a null context. we don't do an access
  584. // check in that case.
  585. //
  586. if ( pContext == NULL )
  587. {
  588. return WBEM_S_NO_ERROR;
  589. }
  590. PSECURITY_DESCRIPTOR pEventSD = (PSECURITY_DESCRIPTOR)pContext->GetSD();
  591. //
  592. // check that the filter allows access to the event provider and owner.
  593. // owner and provider can be different when the provider is signaling
  594. // events on behalf of some other identity.
  595. //
  596. CWbemPtr<IServerSecurity> pProvCtx = NULL;
  597. CoGetCallContext( IID_IServerSecurity, (void**)&pProvCtx );
  598. //
  599. // NOTE: With cross namespace events, the two parts of the access check
  600. // are split up between the namespaces. The FilterAccessToEvent is
  601. // performed in the event's namespace with the temp subscription's
  602. // AccessCheck. This is possible because the owner sid is propagated
  603. // over with the temp subscription. The EventAccessToFilter is performed
  604. // in the subscription namespace. This is possible because the call
  605. // context and the SD of the event ( containing the event owner sid )
  606. // is propagated with the event. Both functions are called in
  607. // both namespaces, but the unnecessary calls turn out to be no-ops.
  608. //
  609. hr = CheckEventAccessToFilter( pProvCtx );
  610. if ( SUCCEEDED(hr) )
  611. {
  612. //
  613. // check that the event provider allows access to the filter.
  614. //
  615. hr = CheckFilterAccessToEvent( pEventSD );
  616. }
  617. return hr;
  618. }
  619. HRESULT CEventFilter::Deliver( long lNumEvents,
  620. IWbemEvent** apEvents,
  621. CEventContext* pContext )
  622. {
  623. int i;
  624. if( m_lSecurityChecksRemaining > 0 )
  625. {
  626. return WBEM_S_FALSE;
  627. }
  628. CBinding* pBinding = NULL;
  629. {
  630. CInCritSec ics(&m_cs);
  631. if(m_bSingleAsync)
  632. {
  633. //
  634. // Thought we could deliver (call Indicate on the binding) right
  635. // here, since single async ensures that no delivery will occur on
  636. // this thread. But no --- an error may be raised, and that event
  637. // will be delivered on this thread, so we must exit the critsec
  638. // before calling
  639. //
  640. pBinding = m_apBindings[0];
  641. pBinding->AddRef();
  642. }
  643. }
  644. if( pBinding )
  645. {
  646. CReleaseMe rm1(pBinding);
  647. return pBinding->Indicate( lNumEvents, apEvents, pContext );
  648. }
  649. // Make referenced copies of all the bindings to deliver over
  650. // ==========================================================
  651. // CANNOT USE SCOPING DUE TO CTempArray --- it uses _alloca
  652. m_cs.Enter();
  653. CTempArray<CBinding*> apBindings;
  654. int nSize = m_apBindings.GetSize();
  655. if(!INIT_TEMP_ARRAY(apBindings, nSize))
  656. {
  657. m_cs.Leave();
  658. return WBEM_E_OUT_OF_MEMORY;
  659. }
  660. {
  661. for(i = 0; i < nSize; i++)
  662. {
  663. CBinding* pBindingInner = m_apBindings[i];
  664. pBindingInner->AddRef();
  665. apBindings[i] = pBindingInner;
  666. }
  667. }
  668. m_cs.Leave();
  669. // Deliver and release the bindings
  670. // ================================
  671. HRESULT hresGlobal = S_OK;
  672. for(i = 0; i < nSize; i++)
  673. {
  674. CBinding* pBindingInner = apBindings[i];
  675. HRESULT hres = pBindingInner->Indicate( lNumEvents, apEvents, pContext );
  676. pBindingInner->Release();
  677. if(FAILED(hres))
  678. hresGlobal = hres;
  679. }
  680. return hresGlobal;
  681. }
  682. HRESULT CEventFilter::LockForUpdate()
  683. {
  684. // Don't need to do anything since the namespace is locked!
  685. /*
  686. m_csChangeBindings.Enter();
  687. AddRef();
  688. */
  689. return S_OK;
  690. }
  691. HRESULT CEventFilter::UnlockForUpdate()
  692. {
  693. /*
  694. m_csChangeBindings.Leave();
  695. Release();
  696. */
  697. return S_OK;
  698. }
  699. HRESULT CEventFilter::CEventForwardingSink::Indicate(long lNumEvents,
  700. IWbemEvent** apEvents,
  701. CEventContext* pContext)
  702. {
  703. return m_pOwner->Deliver(lNumEvents, apEvents, pContext);
  704. }
  705. void CEventFilter::IncrementRemainingSecurityChecks()
  706. {
  707. InterlockedIncrement(&m_lSecurityChecksRemaining);
  708. InterlockedIncrement(&m_lSubjectToSDSCount);
  709. }
  710. void CEventFilter::DecrementRemainingSecurityChecks(HRESULT hresProvider)
  711. {
  712. //
  713. // The provider could have said;
  714. // S_OK: this subscription is fine, send all events through or
  715. // S_SUBJECT_TO_SDS: check event security descriptors before sending
  716. // So, if all the providers gave us a blank check, we won't check security
  717. // descriptors, but if any did, we will check them all.
  718. //
  719. if(hresProvider != WBEM_S_SUBJECT_TO_SDS)
  720. {
  721. if(hresProvider != WBEM_S_NO_ERROR)
  722. {
  723. ERRORTRACE((LOG_ESS, "Invalid return code from provider security test: "
  724. "0x%X\n", hresProvider));
  725. return;
  726. }
  727. InterlockedDecrement(&m_lSubjectToSDSCount);
  728. }
  729. InterlockedDecrement(&m_lSecurityChecksRemaining);
  730. if ( 0 == m_lSubjectToSDSCount && 0 == m_lSecurityChecksRemaining )
  731. {
  732. m_bCheckSDs = false;
  733. }
  734. else
  735. {
  736. InterlockedExchange( &m_lSubjectToSDSCount, 0 );
  737. }
  738. }
  739. HRESULT CEventFilter::SetActualClassChangeSink( IWbemObjectSink* pSink,
  740. IWbemObjectSink** ppOldSink )
  741. {
  742. HRESULT hr;
  743. if ( m_pActualClassChangeSink != NULL )
  744. {
  745. m_pActualClassChangeSink->AddRef();
  746. *ppOldSink = m_pActualClassChangeSink;
  747. hr = WBEM_S_NO_ERROR;
  748. }
  749. else
  750. {
  751. *ppOldSink = NULL;
  752. hr = WBEM_S_FALSE;
  753. }
  754. m_pActualClassChangeSink = pSink;
  755. return hr;
  756. }
  757. HRESULT CEventFilter::Reactivate()
  758. {
  759. HRESULT hres;
  760. //
  761. // This is called when a class or something like that changes from
  762. // from underneath us.
  763. // What we need to do is lock the namespace, deactivate this filter, then
  764. // activate it again
  765. //
  766. CInUpdate iu(m_pNamespace);
  767. DEBUGTRACE((LOG_ESS, "Attempting to reactivate filter '%S' in namespace "
  768. "'%S'\n", (LPCWSTR)(WString)GetKey(),
  769. m_pNamespace->GetName()));
  770. // Invalid filters cannot be activated or deactivated
  771. // ==================================================
  772. if(m_eValidity == e_PermanentlyInvalid)
  773. {
  774. DEBUGTRACE((LOG_ESS, "Not reactivate filter '%S' in namespace "
  775. "'%S': permanently invalid\n",
  776. (LPCWSTR)(WString)GetKey(), m_pNamespace->GetName()));
  777. return S_FALSE;
  778. }
  779. if(m_eState == e_Active)
  780. {
  781. DEBUGTRACE((LOG_ESS, "Deactivating filter '%S' in namespace "
  782. "'%S' prior to reactivation\n",
  783. (LPCWSTR)(WString)GetKey(), m_pNamespace->GetName()));
  784. hres = m_pNamespace->DeactivateFilter(this);
  785. if(FAILED(hres))
  786. {
  787. ERRORTRACE((LOG_ESS, "Deactivating filter '%S' in namespace "
  788. "'%S' prior to reactivation failed: 0x%X\n",
  789. (LPCWSTR)(WString)GetKey(), m_pNamespace->GetName(),
  790. hres));
  791. return hres;
  792. }
  793. m_eState = e_Inactive;
  794. }
  795. hres = AdjustActivation();
  796. DEBUGTRACE((LOG_ESS, "Reactivating filter '%S' in namespace "
  797. "'%S' returned 0x%X\n",
  798. (LPCWSTR)(WString)GetKey(), m_pNamespace->GetName(),
  799. hres));
  800. return hres;
  801. }
  802. STDMETHODIMP CEventFilter::CClassChangeSink::Indicate( long lNumEvents,
  803. IWbemEvent** apEvents )
  804. {
  805. HRESULT hr;
  806. hr = m_pOuter->Reactivate();
  807. if ( SUCCEEDED(hr) )
  808. {
  809. hr = m_pOuter->m_pNamespace->FirePostponedOperations();
  810. }
  811. else
  812. {
  813. m_pOuter->m_pNamespace->FirePostponedOperations();
  814. }
  815. if ( FAILED(hr) )
  816. {
  817. ERRORTRACE((LOG_ESS, "Error encountered when reactivating filter '%S' "
  818. "due to a class change. Namespace is '%S', HRES=0x%x\n",
  819. (LPCWSTR)(WString)m_pOuter->GetKey(),
  820. m_pOuter->m_pNamespace->GetName(),
  821. hr ));
  822. }
  823. return hr;
  824. }
  825. //***************************** Binding ***************************************
  826. CBinding::CBinding()
  827. : m_pConsumer(NULL), m_pFilter(NULL), m_dwQoS( WMIMSG_FLAG_QOS_EXPRESS ),
  828. m_bSlowDown(false), m_bSecure(false), m_bDisabledForSecurity(false)
  829. {
  830. InterlockedIncrement( &g_lNumBindings );
  831. }
  832. CBinding::CBinding(ADDREF CEventConsumer* pConsumer,
  833. ADDREF CEventFilter* pFilter)
  834. : m_pConsumer(NULL), m_pFilter(NULL), m_dwQoS( WMIMSG_FLAG_QOS_EXPRESS ),
  835. m_bSlowDown(false), m_bSecure(false)
  836. {
  837. InterlockedIncrement( &g_lNumBindings );
  838. SetEndpoints(pConsumer, pFilter, NULL);
  839. }
  840. HRESULT CBinding::SetEndpoints(ADDREF CEventConsumer* pConsumer,
  841. ADDREF CEventFilter* pFilter,
  842. READONLY PSID pBinderSid)
  843. {
  844. m_pConsumer = pConsumer;
  845. m_pConsumer->AddRef();
  846. m_pFilter = pFilter;
  847. m_pFilter->AddRef();
  848. // Make sure that the owner of this binding is the same as the
  849. // owners of the endpoints
  850. // ==================================================================
  851. if(pBinderSid && (!EqualSid(pBinderSid, pConsumer->GetOwner()) ||
  852. !EqualSid(pBinderSid, pFilter->GetOwner())))
  853. {
  854. DisableForSecurity();
  855. }
  856. return WBEM_S_NO_ERROR;
  857. }
  858. void CBinding::DisableForSecurity()
  859. {
  860. ERRORTRACE((LOG_ESS, "An event binding is disabled because its creator is "
  861. "not the same security principal as the creators of the endpoints. "
  862. "The binding and the endpoints must be created by the same user!\n"));
  863. m_bDisabledForSecurity = true;
  864. }
  865. CBinding::~CBinding()
  866. {
  867. InterlockedDecrement( &g_lNumBindings );
  868. if(m_pConsumer)
  869. m_pConsumer->Release();
  870. if(m_pFilter)
  871. m_pFilter->Release();
  872. }
  873. DWORD CBinding::GetQoS() NOCS
  874. {
  875. return m_dwQoS;
  876. }
  877. bool CBinding::IsSynch() NOCS
  878. {
  879. return m_dwQoS == WMIMSG_FLAG_QOS_SYNCHRONOUS;
  880. }
  881. bool CBinding::IsSecure() NOCS
  882. {
  883. return m_bSecure;
  884. }
  885. bool CBinding::ShouldSlowDown() NOCS
  886. {
  887. return m_bSlowDown;
  888. }
  889. HRESULT CBinding::Indicate(long lNumEvents, IWbemEvent** apEvents,
  890. CEventContext* pContext)
  891. {
  892. // Check if this binding is active
  893. // ===============================
  894. if(m_bDisabledForSecurity)
  895. return WBEM_S_FALSE;
  896. // It is: deliver
  897. // ==============
  898. return m_pConsumer->ConsumeFromBinding(this, lNumEvents, apEvents,
  899. pContext);
  900. }
  901. //************************* Consumer watch instruction ************************
  902. CWbemInterval CConsumerWatchInstruction::mstatic_Interval;
  903. CConsumerWatchInstruction::CConsumerWatchInstruction(CBindingTable* pTable)
  904. : CBasicUnloadInstruction(mstatic_Interval),
  905. m_pTableRef(pTable->m_pTableRef)
  906. {
  907. if(m_pTableRef)
  908. m_pTableRef->AddRef();
  909. }
  910. CConsumerWatchInstruction::~CConsumerWatchInstruction()
  911. {
  912. if(m_pTableRef)
  913. m_pTableRef->Release();
  914. }
  915. void CConsumerWatchInstruction::staticInitialize(IWbemServices* pRoot)
  916. {
  917. mstatic_Interval = CBasicUnloadInstruction::staticRead(pRoot, GetCurrentEssContext(),
  918. L"__EventSinkCacheControl=@");
  919. }
  920. HRESULT CConsumerWatchInstruction::Fire(long, CWbemTime)
  921. {
  922. if(!m_bTerminate)
  923. {
  924. CEssThreadObject Obj(NULL);
  925. SetConstructedEssThreadObject(&Obj);
  926. CEssNamespace* pNamespace = NULL;
  927. if(m_pTableRef)
  928. {
  929. m_pTableRef->GetNamespace(&pNamespace);
  930. m_pTableRef->UnloadUnusedConsumers(m_Interval);
  931. }
  932. Terminate();
  933. if( pNamespace )
  934. {
  935. pNamespace->FirePostponedOperations();
  936. pNamespace->Release();
  937. }
  938. ClearCurrentEssThreadObject();
  939. }
  940. return WBEM_S_NO_ERROR; // no point worrying the timer
  941. }
  942. //*************************** Binding Table ************************************
  943. class CConsumersToRelease
  944. {
  945. CEventConsumer** m_apConsumers;
  946. int m_nNumConsumers;
  947. public:
  948. CConsumersToRelease(CEventConsumer** apConsumers, int nNumConsumers)
  949. : m_apConsumers(apConsumers), m_nNumConsumers(nNumConsumers)
  950. {
  951. }
  952. ~CConsumersToRelease()
  953. {
  954. for(int i = 0; i < m_nNumConsumers; i++)
  955. {
  956. m_apConsumers[i]->Shutdown();
  957. m_apConsumers[i]->Release();
  958. }
  959. delete [] m_apConsumers;
  960. }
  961. static DWORD Delete(void* p)
  962. {
  963. delete (CConsumersToRelease*)p;
  964. return 0;
  965. }
  966. };
  967. CBindingTable::CBindingTable(CEssNamespace* pNamespace)
  968. : m_pNamespace(pNamespace), m_pInstruction(NULL),
  969. m_bUnloadInstruction(FALSE), m_lNumPermConsumers(0),
  970. m_pTableRef(NULL)
  971. {
  972. m_pTableRef = new CBindingTableRef(this);
  973. if(m_pTableRef)
  974. m_pTableRef->AddRef();
  975. }
  976. void CBindingTable::Clear( bool bSkipClean )
  977. {
  978. //
  979. // Ensure that no more unloading instructions can make it in
  980. //
  981. if(m_pTableRef)
  982. {
  983. m_pTableRef->Disconnect();
  984. m_pTableRef->Release();
  985. m_pTableRef = NULL;
  986. }
  987. // Unbind filter and consumer arrays from the table
  988. // ================================================
  989. CEventFilter** apFilters;
  990. int nNumFilters;
  991. CEventConsumer** apConsumers;
  992. int nNumConsumers;
  993. {
  994. CInCritSec ics(&m_cs);
  995. nNumFilters = m_apFilters.GetSize();
  996. apFilters = m_apFilters.UnbindPtr();
  997. nNumConsumers = m_apConsumers.GetSize();
  998. apConsumers = m_apConsumers.UnbindPtr();
  999. }
  1000. int i;
  1001. // Unbind and release all filters
  1002. // ==============================
  1003. if ( apFilters )
  1004. {
  1005. for(i = 0; i < nNumFilters; i++)
  1006. {
  1007. if (!apFilters[i]->IsInternal())
  1008. {
  1009. g_quotas.DecrementQuotaIndex(
  1010. apFilters[i]->GetOwner() ? ESSQ_PERM_SUBSCRIPTIONS :
  1011. ESSQ_TEMP_SUBSCRIPTIONS,
  1012. apFilters[i],
  1013. 1 );
  1014. }
  1015. apFilters[i]->Unbind(bSkipClean); // shutting down
  1016. apFilters[i]->Release();
  1017. }
  1018. delete [] apFilters;
  1019. }
  1020. //
  1021. // unbind all consumers, but postpone their release.
  1022. //
  1023. if ( apConsumers )
  1024. {
  1025. for(i = 0; i < nNumConsumers; i++)
  1026. {
  1027. apConsumers[i]->Unbind(); // shutting down
  1028. }
  1029. //
  1030. // Release all consumers (unbound by virtue of filter unbinding), but do
  1031. // so on a separate thread
  1032. //
  1033. CConsumersToRelease* pToRelease =
  1034. new CConsumersToRelease(apConsumers, nNumConsumers);
  1035. DWORD dwId;
  1036. HANDLE hThread = CreateThread(NULL, 0,
  1037. (LPTHREAD_START_ROUTINE)CConsumersToRelease::Delete, pToRelease, 0,
  1038. &dwId);
  1039. if(hThread == NULL)
  1040. {
  1041. ERRORTRACE((LOG_ESS, "Unable to launch consumer deleting thread: %d\n",
  1042. GetLastError()));
  1043. }
  1044. else
  1045. {
  1046. DWORD dwRes = WaitForSingleObject(hThread, INFINITE );
  1047. _DBG_ASSERT( WAIT_OBJECT_0 == dwRes );
  1048. CloseHandle(hThread);
  1049. }
  1050. }
  1051. }
  1052. HRESULT CBindingTable::AddEventFilter(CEventFilter* pFilter)
  1053. {
  1054. HRESULT hr;
  1055. if (pFilter->IsInternal() ||
  1056. SUCCEEDED(hr = g_quotas.IncrementQuotaIndex(
  1057. pFilter->GetOwner() ? ESSQ_PERM_SUBSCRIPTIONS : ESSQ_TEMP_SUBSCRIPTIONS,
  1058. pFilter,
  1059. 1)))
  1060. {
  1061. CInCritSec ics(&m_cs);
  1062. if (m_apFilters.Add(pFilter) >= 0)
  1063. hr = S_OK;
  1064. else
  1065. hr = WBEM_E_OUT_OF_MEMORY;
  1066. }
  1067. return hr;
  1068. }
  1069. HRESULT CBindingTable::AddEventConsumer(CEventConsumer* pConsumer)
  1070. {
  1071. CInCritSec ics(&m_cs);
  1072. if(m_apConsumers.Add(pConsumer) < 0)
  1073. return WBEM_E_OUT_OF_MEMORY;
  1074. if(pConsumer->IsPermanent())
  1075. {
  1076. if(m_lNumPermConsumers++ == 0)
  1077. m_pNamespace->SetActive();
  1078. }
  1079. return S_OK;
  1080. }
  1081. HRESULT CBindingTable::FindEventFilter(LPCWSTR wszKey,
  1082. RELEASE_ME CEventFilter** ppFilter)
  1083. {
  1084. CInCritSec ics(&m_cs);
  1085. if(m_apFilters.Find(wszKey, ppFilter))
  1086. return S_OK;
  1087. else
  1088. return WBEM_E_NOT_FOUND;
  1089. }
  1090. HRESULT CBindingTable::FindEventConsumer(LPCWSTR wszKey,
  1091. RELEASE_ME CEventConsumer** ppConsumer)
  1092. {
  1093. CInCritSec ics(&m_cs);
  1094. if(m_apConsumers.Find(wszKey, ppConsumer))
  1095. return S_OK;
  1096. else
  1097. return WBEM_E_NOT_FOUND;
  1098. }
  1099. HRESULT CBindingTable::RemoveEventFilter(LPCWSTR wszKey)
  1100. {
  1101. // Find it and remove it from the table
  1102. // ====================================
  1103. CEventFilter* pFilter = NULL;
  1104. HRESULT hres;
  1105. {
  1106. CInCritSec ics(&m_cs);
  1107. if(!m_apFilters.Remove(wszKey, &pFilter))
  1108. return WBEM_E_NOT_FOUND;
  1109. }
  1110. if(pFilter == NULL)
  1111. return WBEM_E_CRITICAL_ERROR;
  1112. // Remove 1 from our quota count.
  1113. if (!pFilter->IsInternal())
  1114. {
  1115. g_quotas.DecrementQuotaIndex(
  1116. pFilter->GetOwner() ? ESSQ_PERM_SUBSCRIPTIONS : ESSQ_TEMP_SUBSCRIPTIONS,
  1117. pFilter,
  1118. 1);
  1119. }
  1120. // Unbind it, thus deactivating
  1121. // ============================
  1122. hres = pFilter->Unbind();
  1123. pFilter->Release();
  1124. return hres;
  1125. }
  1126. void CBindingTable::MarkRemoval(CEventConsumer* pConsumer)
  1127. {
  1128. if(pConsumer && pConsumer->IsPermanent())
  1129. {
  1130. if(--m_lNumPermConsumers == 0)
  1131. m_pNamespace->SetInactive();
  1132. }
  1133. }
  1134. HRESULT CBindingTable::RemoveEventConsumer(LPCWSTR wszKey)
  1135. {
  1136. // Find it and remove it from the table
  1137. // ====================================
  1138. CEventConsumer* pConsumer = NULL;
  1139. HRESULT hres;
  1140. {
  1141. CInCritSec ics(&m_cs);
  1142. if(!m_apConsumers.Remove(wszKey, &pConsumer))
  1143. return WBEM_E_NOT_FOUND;
  1144. MarkRemoval(pConsumer);
  1145. }
  1146. if(pConsumer == NULL)
  1147. return WBEM_E_CRITICAL_ERROR;
  1148. hres = pConsumer->Unbind();
  1149. pConsumer->Release();
  1150. return hres;
  1151. }
  1152. HRESULT CBindingTable::Bind(LPCWSTR wszFilterKey, LPCWSTR wszConsumerKey,
  1153. CBinding* pBinding, PSID pBinderSid)
  1154. {
  1155. // Find them both and get ref-counted pointers
  1156. // ===========================================
  1157. CEventFilter* pFilter;
  1158. CEventConsumer* pConsumer;
  1159. HRESULT hres;
  1160. {
  1161. CInCritSec ics(&m_cs);
  1162. hres = FindEventFilter(wszFilterKey, &pFilter);
  1163. if(FAILED(hres)) return hres;
  1164. hres = FindEventConsumer(wszConsumerKey, &pConsumer);
  1165. if(FAILED(hres))
  1166. {
  1167. pFilter->Release();
  1168. return hres;
  1169. }
  1170. }
  1171. // Fully construct the binding --- will check security
  1172. // ===================================================
  1173. hres = pBinding->SetEndpoints(pConsumer, pFilter, pBinderSid);
  1174. if(FAILED(hres))
  1175. return hres;
  1176. // Make them reference each other
  1177. // ==============================
  1178. HRESULT hresGlobal = S_OK;
  1179. hres = pFilter->EnsureReferences(pConsumer, pBinding);
  1180. if(FAILED(hres))
  1181. hresGlobal = hres;
  1182. hres = pConsumer->EnsureReferences(pFilter, pBinding);
  1183. if(FAILED(hres))
  1184. hresGlobal = hres;
  1185. // Cleanup
  1186. // =======
  1187. pConsumer->Release();
  1188. pFilter->Release();
  1189. return hresGlobal;
  1190. }
  1191. HRESULT CBindingTable::Unbind(LPCWSTR wszFilterKey, LPCWSTR wszConsumerKey)
  1192. {
  1193. // Find them both and get ref-counted pointers
  1194. // ===========================================
  1195. CEventFilter* pFilter;
  1196. CEventConsumer* pConsumer;
  1197. HRESULT hres;
  1198. {
  1199. CInCritSec ics(&m_cs);
  1200. hres = FindEventFilter(wszFilterKey, &pFilter);
  1201. if(FAILED(hres)) return hres;
  1202. hres = FindEventConsumer(wszConsumerKey, &pConsumer);
  1203. if(FAILED(hres))
  1204. {
  1205. pFilter->Release();
  1206. return hres;
  1207. }
  1208. }
  1209. // Remove respective references
  1210. // ============================
  1211. HRESULT hresGlobal = S_OK;
  1212. hres = pFilter->EnsureNotReferences(pConsumer);
  1213. if(FAILED(hres))
  1214. hresGlobal = hres;
  1215. pConsumer->EnsureNotReferences(pFilter);
  1216. if(FAILED(hres))
  1217. hresGlobal = hres;
  1218. pFilter->Release();
  1219. pConsumer->Release();
  1220. return hresGlobal;
  1221. }
  1222. BOOL CBindingTable::DoesHavePermanentConsumers()
  1223. {
  1224. return (m_lNumPermConsumers != 0);
  1225. }
  1226. HRESULT CBindingTable::ResetProviderRecords(LPCWSTR wszProviderRef)
  1227. {
  1228. // Make a copy of the list of consumers, AddRefed
  1229. // ==============================================
  1230. CRefedPointerArray<CEventConsumer> apConsumers;
  1231. if(!GetConsumers(apConsumers))
  1232. return WBEM_E_OUT_OF_MEMORY;
  1233. // Go through all the consumers and see if they reference this record
  1234. // ==================================================================
  1235. for(int i = 0; i < apConsumers.GetSize(); i++)
  1236. {
  1237. apConsumers[i]->ResetProviderRecord(wszProviderRef);
  1238. }
  1239. return S_OK;
  1240. }
  1241. //*******************************************************************************
  1242. //
  1243. // EnsureConsumerWatchInstruction / UnloadUnusedConsumers synchronization
  1244. //
  1245. // Usage:
  1246. //
  1247. // ECWI is called when a consumer is loaded. It is called after the consumer
  1248. // record has been updated. Post-condition: UnloadUnusedConsumers must be
  1249. // called at least once after this function starts executing.
  1250. //
  1251. // UUC is called by the CConsumerWatchTimerInstruction::Fire on timer. The
  1252. // instruction then self-destructs. Post-condition: idle consumers
  1253. // unloaded; if any are still active, another UUC will occur in the future;
  1254. // If none are active for a while, no UUC will occur in the future,
  1255. // until ECWI is called.
  1256. //
  1257. // Primitives:
  1258. //
  1259. // CS m_cs: atomic, data access
  1260. //
  1261. // BOOL m_bUnloadInstruction: Can only be accessed in m_cs. Semantics:
  1262. // TRUE if an instruction is either scheduled or will be scheduled
  1263. // shortly; this putative instruction, when fired, is guaranteed to
  1264. // examine any consumer in the table at the time of he check.
  1265. //
  1266. // Algorithm:
  1267. //
  1268. // ECWI checks m_bUnloadInstructiion (in m_cs) and if TRUE does nothing, as the
  1269. // m_bUnloadInstruction == TRUE guarantee above assures that UUC will be
  1270. // called. If it is FALSE, ECWI sets it to TRUE, then schedules an
  1271. // instruction (outside of m_cs). The setting of m_bUnloadInstruction to
  1272. // TRUE is correct, since an instruction will be scheduled shortly. Thus,
  1273. // ECWI post-condition is satisfied, assuming primitive semantics above.
  1274. //
  1275. // UUC, in m_cs, sets m_bUnloadInstriction to FALSE and makes a copy of the
  1276. // consumer list. Outside of m_cs, it iterates over the copy and unloads
  1277. // consumers as required. Then, if any are active, it calls ECWI. This
  1278. // guarantees that another UUC will be called. If a consumer was active
  1279. // before the entry into m_cs, we call ECWI. If a consumer became active
  1280. // after we entered into m_cs, it will call ECWI after we have reset
  1281. // m_bUnloadInstruction, causing another instruction to be scheduled. This
  1282. // proves our post-condition assuming primitive semantics above.
  1283. //
  1284. // Proof of primitives:
  1285. //
  1286. // m_bUnloadInstruction becomes TRUE only in ECWI. When it does, ECWI is
  1287. // guaranteed to schedule a new instruction, causing a call to UUC. So, the
  1288. // semantics holds in the beginning. It can become invalid if UUC fires and is
  1289. // not rescheduled. But UUC resets m_bUnloadInstruction to FALSE, thus making
  1290. // semantics valid vacuously.
  1291. //
  1292. // Now, we need to show that any consumer in the table at the time when
  1293. // m_bUnloadInstruction == TRUE will be examined by the scheduled UUC. Well,
  1294. // the latest scheduled (or about to be scheduled) UUC, cannot have exited
  1295. // its m_cs stint yet, for otherwise m_bUnloadInstruction would be FALSE.
  1296. // Therefore, it hasn't entered it yet, and therefore hasn't made a copy yet.
  1297. //
  1298. //******************************************************************************
  1299. HRESULT CBindingTable::EnsureConsumerWatchInstruction()
  1300. {
  1301. // Check if it is already there
  1302. // ============================
  1303. BOOL bMustSchedule = FALSE;
  1304. {
  1305. CInCritSec ics(&m_cs);
  1306. if(!m_bUnloadInstruction)
  1307. {
  1308. // Not there. Mark as there, preventing others from scheduling
  1309. // more.
  1310. // ============================================================
  1311. m_bUnloadInstruction = TRUE;
  1312. bMustSchedule = TRUE;
  1313. }
  1314. }
  1315. if(bMustSchedule)
  1316. {
  1317. CConsumerWatchInstruction* pInst = new CConsumerWatchInstruction(this);
  1318. if(pInst == NULL)
  1319. {
  1320. CInCritSec ics(&m_cs);
  1321. m_bUnloadInstruction = FALSE;
  1322. return WBEM_E_OUT_OF_MEMORY;
  1323. }
  1324. pInst->AddRef();
  1325. // Set it in the generator
  1326. // =======================
  1327. HRESULT hres = m_pNamespace->GetTimerGenerator().Set(pInst);
  1328. if(FAILED(hres))
  1329. {
  1330. CInCritSec ics(&m_cs);
  1331. m_bUnloadInstruction = FALSE;
  1332. return hres;
  1333. }
  1334. pInst->Release();
  1335. return S_OK;
  1336. }
  1337. else
  1338. {
  1339. return S_FALSE;
  1340. }
  1341. }
  1342. HRESULT CBindingTable::UnloadUnusedConsumers(CWbemInterval Interval)
  1343. {
  1344. // Mark unload instruction as empty and copy consumer records
  1345. // ==========================================================
  1346. CRefedPointerArray<CEventConsumer> apConsumers;
  1347. {
  1348. CInCritSec ics(&m_cs);
  1349. m_bUnloadInstruction = FALSE;
  1350. if(!GetConsumers(apConsumers))
  1351. return WBEM_E_OUT_OF_MEMORY;
  1352. }
  1353. // Go through the consumers and unload them if needed
  1354. // ==================================================
  1355. BOOL bUnloaded = FALSE;
  1356. BOOL bActive = FALSE;
  1357. for(int i = 0; i < apConsumers.GetSize(); i++)
  1358. {
  1359. if(apConsumers[i]->UnloadIfUnusedFor(Interval))
  1360. bUnloaded = TRUE;
  1361. else if(!apConsumers[i]->IsFullyUnloaded())
  1362. bActive = TRUE;
  1363. }
  1364. // Schedule DLL unloading if any COM objects were unloaded
  1365. // =======================================================
  1366. if(bUnloaded)
  1367. m_pNamespace->GetTimerGenerator().ScheduleFreeUnusedLibraries();
  1368. // Schedule the new instruction if needed
  1369. // ======================================
  1370. if(bActive)
  1371. return EnsureConsumerWatchInstruction();
  1372. return S_OK;
  1373. }
  1374. BOOL CBindingTable::GetConsumers(
  1375. CRefedPointerArray<CEventConsumer>& apConsumers)
  1376. {
  1377. CInCritSec ics(&m_cs);
  1378. TConsumerIterator it;
  1379. for(it = m_apConsumers.Begin(); it != m_apConsumers.End(); it++)
  1380. {
  1381. if(apConsumers.Add(*it) < 0)
  1382. return FALSE;
  1383. }
  1384. return TRUE;
  1385. }
  1386. BOOL CBindingTable::GetEventFilters( CRefedPointerArray< CEventFilter > & apEventFilters )
  1387. {
  1388. CInCritSec ics( &m_cs );
  1389. TFilterIterator it;
  1390. for( it = m_apFilters.Begin( ); it != m_apFilters.End( ); ++it )
  1391. {
  1392. if( apEventFilters.Add( *it ) < 0 )
  1393. {
  1394. return FALSE;
  1395. }
  1396. }
  1397. return TRUE;
  1398. }
  1399. HRESULT CBindingTable::RemoveConsumersStartingWith(LPCWSTR wszPrefix)
  1400. {
  1401. CRefedPointerArray<CEventConsumer> apToRelease;
  1402. int nLen = wcslen(wszPrefix);
  1403. {
  1404. CInCritSec ics(&m_cs);
  1405. TConsumerIterator it = m_apConsumers.Begin();
  1406. while(it != m_apConsumers.End())
  1407. {
  1408. if(!wcsncmp((WString)(*it)->GetKey(), wszPrefix, nLen))
  1409. {
  1410. // Found it --- move to the "to be released" list
  1411. // ==============================================
  1412. CEventConsumer* pConsumer;
  1413. it = m_apConsumers.Remove(it, &pConsumer);
  1414. MarkRemoval(pConsumer);
  1415. apToRelease.Add(pConsumer);
  1416. pConsumer->Release();
  1417. }
  1418. else
  1419. {
  1420. it++;
  1421. }
  1422. }
  1423. }
  1424. // Unbind all the consumers we have left. Release will happen on destruct
  1425. // =======================================================================
  1426. for(int i = 0; i < apToRelease.GetSize(); i++)
  1427. {
  1428. apToRelease[i]->Unbind();
  1429. }
  1430. return WBEM_S_NO_ERROR;
  1431. }
  1432. HRESULT CBindingTable::RemoveConsumerWithFilters(LPCWSTR wszConsumerKey)
  1433. {
  1434. HRESULT hres;
  1435. CRefedPointerSmallArray<CEventFilter> apFilters;
  1436. {
  1437. CInCritSec ics(&m_cs);
  1438. // Find the consumer in question
  1439. // =============================
  1440. CEventConsumer* pConsumer = NULL;
  1441. hres = FindEventConsumer(wszConsumerKey, &pConsumer);
  1442. if(FAILED(hres))
  1443. return hres;
  1444. CReleaseMe rm1(pConsumer);
  1445. // Make addrefed copies of all its associated filters
  1446. // ==================================================
  1447. hres = pConsumer->GetAssociatedFilters(apFilters);
  1448. if(FAILED(hres))
  1449. return hres;
  1450. }
  1451. // Remove the consumer
  1452. // ===================
  1453. RemoveEventConsumer(wszConsumerKey);
  1454. // Remove every one of its filters
  1455. // ===============================
  1456. for(int i = 0; i < apFilters.GetSize(); i++)
  1457. {
  1458. RemoveEventFilter((WString)apFilters[i]->GetKey());
  1459. }
  1460. return S_OK;
  1461. }
  1462. HRESULT CBindingTable::ReactivateAllFilters()
  1463. {
  1464. // Retrieve a copy of all the filters
  1465. // ==================================
  1466. CRefedPointerArray<CEventFilter> apFilters;
  1467. {
  1468. CInCritSec ics(&m_cs);
  1469. TFilterIterator it;
  1470. for(it = m_apFilters.Begin(); it != m_apFilters.End(); it++)
  1471. {
  1472. if(apFilters.Add(*it) < 0)
  1473. return WBEM_E_OUT_OF_MEMORY;
  1474. }
  1475. }
  1476. // Reactivate them all
  1477. // ===================
  1478. for(int i = 0; i < apFilters.GetSize(); i++)
  1479. {
  1480. CEventFilter* pFilter = apFilters[i];
  1481. pFilter->SetInactive();
  1482. pFilter->AdjustActivation();
  1483. }
  1484. return WBEM_S_NO_ERROR;
  1485. }
  1486. void CBindingTable::Park()
  1487. {
  1488. //
  1489. // Tell each filter to "park" itself
  1490. //
  1491. CInCritSec ics(&m_cs);
  1492. TFilterIterator it;
  1493. for(it = m_apFilters.Begin(); it != m_apFilters.End(); it++)
  1494. {
  1495. (*it)->Park();
  1496. }
  1497. }
  1498. void CBindingTable::DumpStatistics(FILE* f, long lFlags)
  1499. {
  1500. fprintf(f, "%d consumers (%d permanent), %d filters\n",
  1501. m_apConsumers.GetSize(), m_lNumPermConsumers,
  1502. m_apFilters.GetSize());
  1503. }
  1504. CBindingTableRef::~CBindingTableRef()
  1505. {
  1506. }
  1507. CBindingTableRef::CBindingTableRef(CBindingTable* pTable)
  1508. : m_pTable(pTable), m_lRef(0)
  1509. {
  1510. }
  1511. void CBindingTableRef::AddRef()
  1512. {
  1513. InterlockedIncrement(&m_lRef);
  1514. }
  1515. void CBindingTableRef::Release()
  1516. {
  1517. if(InterlockedDecrement(&m_lRef) == 0)
  1518. delete this;
  1519. }
  1520. void CBindingTableRef::Disconnect()
  1521. {
  1522. CInCritSec ics(&m_cs);
  1523. m_pTable = NULL;
  1524. }
  1525. HRESULT CBindingTableRef::UnloadUnusedConsumers(CWbemInterval Interval)
  1526. {
  1527. CInCritSec ics(&m_cs);
  1528. if(m_pTable)
  1529. return m_pTable->UnloadUnusedConsumers(Interval);
  1530. else
  1531. return WBEM_S_FALSE;
  1532. }
  1533. HRESULT CBindingTableRef::GetNamespace(RELEASE_ME CEssNamespace** ppNamespace)
  1534. {
  1535. CInCritSec ics(&m_cs);
  1536. if(m_pTable)
  1537. {
  1538. *ppNamespace = m_pTable->m_pNamespace;
  1539. if(*ppNamespace)
  1540. (*ppNamespace)->AddRef();
  1541. }
  1542. else
  1543. {
  1544. *ppNamespace = NULL;
  1545. }
  1546. return WBEM_S_NO_ERROR;
  1547. }