//****************************************************************************** // // BINDING.H // // Copyright (C) 1996-1999 Microsoft Corporation // //****************************************************************************** #ifndef __WMI_ESS_BINDING__H_ #define __WMI_ESS_BINDING__H_ #include #include "evtools.h" #include "evsink.h" #include #include #include #include #include "qsink.h" class CEventConsumer; class CEventFilter; class CEssNamespace; //****************************************************************************** // // Immutable after initialization // //****************************************************************************** class CBinding : public CEventSink { protected: long m_lRef; CEventConsumer* m_pConsumer; // immutable after init CEventFilter* m_pFilter; // immutable after init DWORD m_dwQoS; // immutable after init bool m_bSecure; // immutable after init bool m_bSlowDown; // immutable after init bool m_bDisabledForSecurity; public: CBinding(); CBinding(ADDREF CEventConsumer* pConsumer, ADDREF CEventFilter* pFilter); virtual ~CBinding(); HRESULT SetEndpoints(ADDREF CEventConsumer* pConsumer, ADDREF CEventFilter* pFilter, PSID pBinderSid); void DisableForSecurity(); INTERNAL CEventConsumer* GetConsumer() NOCS {return m_pConsumer;} INTERNAL CEventFilter* GetFilter() NOCS {return m_pFilter;} DWORD GetQoS() NOCS; bool IsSynch() NOCS; bool IsSecure() NOCS; bool ShouldSlowDown() NOCS; HRESULT Indicate( long lNumEvents, IWbemEvent** apEvents, CEventContext* pContext); }; class CEventConsumer : public CQueueingEventSink { protected: CRefedPointerSmallArray m_apBindings; CInternalString m_isKey; PBYTE m_pOwnerSid; public: CEventConsumer(CEssNamespace* pNamespace); virtual ~CEventConsumer(); inline const CInternalString& GetKey() const {return m_isKey;} inline const PSID GetOwner() {return m_pOwnerSid;} virtual BOOL IsPermanent() const {return FALSE;} virtual BOOL UnloadIfUnusedFor(CWbemInterval Interval) {return FALSE;} virtual BOOL IsFullyUnloaded() {return TRUE;} virtual HRESULT ResetProviderRecord(LPCWSTR wszProviderRef) {return S_FALSE;} virtual HRESULT Shutdown(bool bQuiet = false) {return S_OK;} virtual HRESULT Validate(IWbemClassObject* pLogicalConsumer) {return S_OK;} HRESULT EnsureReferences(CEventFilter* pFilter, CBinding* pBinding); HRESULT EnsureNotReferences(CEventFilter* pFilter); HRESULT Unbind(); HRESULT ConsumeFromBinding(CBinding* pBinding, long lNumEvents, IWbemEvent** apEvents, CEventContext* pContext); HRESULT GetAssociatedFilters( CRefedPointerSmallArray& apFilters); virtual HRESULT ActuallyDeliver(long lNumEvents, IWbemEvent** apEvents, BOOL bSecure, CEventContext* pContext) = 0; virtual HRESULT ReportEventDrop(IWbemEvent* pEvent); }; //***************************************************************************** // // m_cs controls access to data members. No critical sections may be acquired // while holding m_cs. // // m_csChangeBindings controls activation/deactivation requests on this filter. // As long as an activation/deactivation request is proceeding, no other // such request can get underway. This ensures that the activation state // state of the filter always matches the state of its bindings. At the // same time, the filter can filter events while such a request executes, // since m_cs is not held. Only m_cs can be acquired while holding // m_csActivation // //***************************************************************************** class CEventFilter : public CEventSink, public CUpdateLockable { protected: CEssNamespace* m_pNamespace; // immutable after init CRefedPointerSmallArray m_apBindings; // changes CCritSec m_cs; // CCritSec m_csChangeBindings; // don't need since the namespace is locked bool m_bSingleAsync; CInternalString m_isKey; PBYTE m_pOwnerSid; long m_lSecurityChecksRemaining; long m_lSubjectToSDSCount; bool m_bCheckSDs; HRESULT m_hresFilterError; bool m_bHasBeenValid; IWbemToken* m_pToken; HRESULT m_hresTokenError; DWORD m_dwLastTokenAttempt; bool m_bReconstructOnHit; HRESULT m_hresPollingError; enum { e_Inactive, e_Active } m_eState; //changes enum { e_Unknown, e_PermanentlyInvalid, e_TemporarilyInvalid, e_Valid } m_eValidity; friend class CEventForwardingSink; class CEventForwardingSink : public CAbstractEventSink { protected: CEventFilter* m_pOwner; public: CEventForwardingSink(CEventFilter* pOwner) : m_pOwner(pOwner){} ULONG STDMETHODCALLTYPE AddRef() {return m_pOwner->AddRef();} ULONG STDMETHODCALLTYPE Release() {return m_pOwner->Release();} HRESULT Indicate(long lNumEvents, IWbemEvent** apEvents, CEventContext* pContext); } m_ForwardingSink; // immutable class CClassChangeSink : public CEmbeddedObjectSink { public: CClassChangeSink(CEventFilter* pOwner) : CEmbeddedObjectSink(pOwner){} STDMETHOD(Indicate)(long lNumEvents, IWbemEvent** apEvents); } m_ClassChangeSink; // immutable CWbemPtr m_pActualClassChangeSink; friend CEventForwardingSink; public: CEventFilter(CEssNamespace* pEssNamespace); virtual ~CEventFilter(); virtual bool IsInternal() { return false; } //************** // Acquire CSs //************** HRESULT EnsureReferences(CEventConsumer* pConsumer, CBinding* pBinding); HRESULT EnsureNotReferences(CEventConsumer* pConsumer); HRESULT Unbind(bool bShuttingDown = false); bool IsBound(); virtual BOOL DoesNeedType(int nType) const = 0; HRESULT Indicate(long lNumEvents, IWbemEvent** apEvents, CEventContext* pContext) = 0; virtual HRESULT LockForUpdate(); virtual HRESULT UnlockForUpdate(); //******************* // Do not acquire CSs //******************* virtual HRESULT GetCoveringQuery(DELETE_ME LPWSTR& wszQueryLanguage, DELETE_ME LPWSTR& wszQuery, BOOL& bExact, DELETE_ME QL_LEVEL_1_RPN_EXPRESSION** ppExp) = 0; virtual HRESULT GetEventNamespace(DELETE_ME LPWSTR* pwszNamespace); virtual DWORD GetForceFlags() {return 0;} virtual bool DoesAllowInvalid() {return ((GetForceFlags() & WBEM_FLAG_STRONG_VALIDATION) == 0);} bool HasBeenValid() {return m_bHasBeenValid;} inline const CInternalString& GetKey() {return m_isKey;} inline const PSID GetOwner() { return m_pOwnerSid; } virtual CAbstractEventSink* GetNonFilteringSink() = 0; virtual HRESULT GetReady(LPCWSTR wszQuery, QL_LEVEL_1_RPN_EXPRESSION* pExp) = 0; virtual HRESULT GetReadyToFilter() = 0; virtual BOOL IsPermanent() = 0; virtual HRESULT SetThreadSecurity( IUnknown** ppNewContext ) = 0; virtual HRESULT ObtainToken(IWbemToken** ppToken) = 0; virtual void Park(){} virtual const PSECURITY_DESCRIPTOR GetEventAccessSD() { return NULL; } void MarkAsPermanentlyInvalid(HRESULT hres); void MarkAsTemporarilyInvalid(HRESULT hres); void MarkAsValid(); void SetInactive(); BOOL IsActive(); HRESULT GetFilterError(); void MarkReconstructOnHit(bool bReconstruct = true); void SetPollingError(HRESULT hres) {m_hresPollingError = hres;} HRESULT GetPollingError() {return m_hresPollingError;} void IncrementRemainingSecurityChecks(); void DecrementRemainingSecurityChecks(HRESULT hresProvider); INTERNAL IWbemObjectSink* GetClassChangeSink() {return &m_ClassChangeSink;} // // this so the caller can wrap the class change sink however they want and // store the resultant sink with the filter object. // HRESULT SetActualClassChangeSink( IWbemObjectSink* pSink, IWbemObjectSink** ppOldSink ); HRESULT Reactivate(); protected: HRESULT Deliver(long lNumEvents, IWbemEvent** apEvents, CEventContext* pContext); HRESULT AdjustActivation(); void AdjustSingleAsync(); BOOL DoesNeedDeactivation(); HRESULT AccessCheck( CEventContext* pEventContext, IWbemEvent* pEvent ); HRESULT CheckEventAccessToFilter( IServerSecurity* pProvCtx ); HRESULT CheckFilterAccessToEvent( PSECURITY_DESCRIPTOR pEventSD ); friend class CBindingTable; }; class CConsumerWatchInstruction : public CBasicUnloadInstruction { protected: class CBindingTableRef* m_pTableRef; static CWbemInterval mstatic_Interval; public: CConsumerWatchInstruction(CBindingTable* pTable); ~CConsumerWatchInstruction(); HRESULT Fire(long, CWbemTime); static void staticInitialize(IWbemServices* pRoot); }; //****************************************************************************** // // This class is a comparer (as required by the sorted array template) that // compares an object with CInternalString* GetKey() method (e.g. filter or // consumer) to another such object or an LPCWSTR // //****************************************************************************** template class CInternalStringComparer { public: int Compare(TObject* p1, TObject* p2) const { return p1->GetKey().Compare(p2->GetKey()); } int Compare(const CInternalString& isKey, TObject* p) const { return - p->GetKey().Compare(isKey); } int Compare(LPCWSTR wszKey, TObject* p) const { return - p->GetKey().Compare(wszKey); } int Compare(const CInternalString& isKey1, const CInternalString& isKey2) const { return isKey1.Compare(isKey2); } const CInternalString& Extract(TObject* p) const { return p->GetKey(); } }; template class CSortedRefedKeyedPointerArray : public CRefedPointerSortedTree > { typedef CRefedPointerSortedTree > TParent; public: inline bool Find(LPCWSTR wszKey, TObject** ppObj) { CInternalString is(wszKey); if (is.IsEmpty()) return false; return TParent::Find(is, ppObj); } inline bool Remove(LPCWSTR wszKey, TObject** ppObj) { CInternalString is(wszKey); if (is.IsEmpty()) return false; return TParent::Remove(is, ppObj); } inline typename TParent::TIterator Remove(typename TParent::TIterator it, TObject** ppObj) { return TParent::Remove(it, ppObj); } }; /* template class CSortedRefedKeyedPointerArray : public CRefedPointerSortedArray > { }; */ class CBindingTableRef { protected: long m_lRef; CBindingTable* m_pTable; CCritSec m_cs; protected: virtual ~CBindingTableRef(); public: CBindingTableRef(CBindingTable* pTable); void AddRef(); void Release(); void Disconnect(); HRESULT UnloadUnusedConsumers(CWbemInterval Interval); HRESULT GetNamespace(RELEASE_ME CEssNamespace** ppNamespace); }; class CBindingTable { protected: CEssNamespace* m_pNamespace; CCritSec m_cs; CSortedRefedKeyedPointerArray m_apFilters; typedef CSortedRefedKeyedPointerArray::TIterator TFilterIterator; CSortedRefedKeyedPointerArray m_apConsumers; typedef CSortedRefedKeyedPointerArray::TIterator TConsumerIterator; long m_lNumPermConsumers; CConsumerWatchInstruction* m_pInstruction; BOOL m_bUnloadInstruction; CBindingTableRef* m_pTableRef; public: //**************************************************** // all members should be assumed to acquire random CSs //**************************************************** CBindingTable(CEssNamespace* pNamespace); void Clear( bool bSkipClean ); ~CBindingTable() { Clear(true); } HRESULT AddEventFilter(CEventFilter* pFilter); HRESULT AddEventConsumer(CEventConsumer* pConsumer); HRESULT FindEventFilter(LPCWSTR wszKey, RELEASE_ME CEventFilter** ppFilter); HRESULT FindEventConsumer(LPCWSTR wszKey, RELEASE_ME CEventConsumer** ppConsumer); HRESULT RemoveEventFilter(LPCWSTR wszKey); HRESULT RemoveEventConsumer(LPCWSTR wszKey); HRESULT Bind(LPCWSTR wszFilterKey, LPCWSTR wszConsumerKey, CBinding* pBinding, PSID pBinderSid); HRESULT Unbind(LPCWSTR wszFilterKey, LPCWSTR wszConsumerKey); BOOL DoesHavePermanentConsumers(); HRESULT ListActiveNamespaces(CWStringArray& wsNamespaces); HRESULT ResetProviderRecords(LPCWSTR wszProvider); HRESULT RemoveConsumerWithFilters(LPCWSTR wszConsumerKey); HRESULT ReactivateAllFilters(); HRESULT RemoveConsumersStartingWith(LPCWSTR wszPrefix); HRESULT EnsureConsumerWatchInstruction(); void Park(); void DumpStatistics(FILE* f, long lFlags); BOOL GetEventFilters( CRefedPointerArray< CEventFilter > & apEventFilters ); protected: void MarkRemoval(CEventConsumer* pConsumer); HRESULT UnloadUnusedConsumers(CWbemInterval Interval); BOOL GetConsumers(CRefedPointerArray& apConsumers); friend CConsumerWatchInstruction; friend CBindingTableRef; }; #endif