//============================================================================= // // Copyright (c) 1996-1999, Microsoft Corporation, All rights reserved // // NSREP.CPP // // See nsrep.h for documentation // // History: // //============================================================================= #include "precomp.h" #include #include "ess.h" #include "esssink.h" #include "permbind.h" #include "aggreg.h" #include "persistcfg.h" #include "WinMgmtR.h" #include #include #include #include "NCEvents.h" // For the non-COM event stuff #include #include #include #include long g_lNumNamespaces = 0; long g_lNumInternalTempSubscriptions = 0; long g_lNumTempSubscriptions = 0; #define ENSURE_INITIALIZED \ hres = EnsureInitPending(); \ if ( FAILED(hres) ) \ return hres; \ hres = WaitForInitialization(); \ if ( FAILED(hres) ) \ return hres; \ CInUpdate iu(this); \ if ( m_eState == e_Shutdown ) \ return WBEM_E_SHUTTING_DOWN; // The use of this pointer to initialize parent class is valid in this context #pragma warning(disable : 4355) class CEnumSink : public CObjectSink { protected: CEssNamespace* m_pNamespace; HANDLE m_hEvent; CEssThreadObject* m_pThreadObj; public: CEnumSink(CEssNamespace* pNamespace) : m_pNamespace(pNamespace), m_hEvent(CreateEvent(NULL, FALSE, FALSE, NULL)), m_pThreadObj(GetCurrentEssThreadObject()) {} ~CEnumSink(){SetEvent(m_hEvent);} void ReleaseAndWait() { HANDLE h = m_hEvent; Release(); WaitForSingleObject(h, INFINITE); CloseHandle(h); } virtual HRESULT Process(IWbemClassObject* pObj) = 0; STDMETHOD(Indicate)(long lNumObjects, IWbemClassObject** apObjects) { SetConstructedEssThreadObject(m_pThreadObj); for(int i = 0; i < lNumObjects; i++) Process(apObjects[i]); return S_OK; } STDMETHOD(SetStatus)(long, HRESULT, BSTR, IWbemClassObject*) { return S_OK; } }; class CFilterEnumSink : public CEnumSink { public: CFilterEnumSink(CEssNamespace* pNamespace) : CEnumSink(pNamespace){} virtual HRESULT Process(IWbemClassObject* pObj) { return m_pNamespace->AddEventFilter(pObj, TRUE); } }; class CConsumerEnumSink : public CEnumSink { public: CConsumerEnumSink(CEssNamespace* pNamespace) : CEnumSink(pNamespace){} virtual HRESULT Process(IWbemClassObject* pObj) { return m_pNamespace->AddEventConsumer(pObj, 0, TRUE); } }; class CBindingEnumSink : public CEnumSink { public: CBindingEnumSink(CEssNamespace* pNamespace) : CEnumSink(pNamespace){} virtual HRESULT Process(IWbemClassObject* pObj) { return m_pNamespace->AddBinding(pObj); } }; class CPostponedReleaseRequest : public CPostponedRequest { protected: IUnknown* m_pUnk; public: CPostponedReleaseRequest(IUnknown* pToRelease) : m_pUnk(pToRelease) { try { if(m_pUnk) m_pUnk->AddRef(); } catch(...) { } } HRESULT Execute(CEssNamespace* pNamespace) { try { if(m_pUnk) m_pUnk->Release(); } catch(...) { } return WBEM_S_NO_ERROR; } ~CPostponedReleaseRequest() { try { if(m_pUnk) m_pUnk->Release(); } catch(...) { } } }; class CPostponedRegisterNotificationSinkRequest : public CPostponedRequest { protected: WString m_wsQuery; WString m_wsQueryLanguage; DWORD m_lFlags; DWORD m_dwQosFlags; CWbemPtr m_pSink; CWbemPtr m_pNamespace; CNtSid m_OwnerSid; public: HRESULT SetRegistration( CEssNamespace* pNamespace, LPCWSTR wszQueryLanguage, LPCWSTR wszQuery, long lFlags, DWORD dwQosFlags, IWbemObjectSink* pSink, PSID pOwnerSid ) { m_pSink = pSink; m_lFlags = lFlags; m_dwQosFlags = dwQosFlags; m_pNamespace = pNamespace; try { m_wsQuery = wszQuery; m_wsQueryLanguage = wszQueryLanguage; m_OwnerSid = CNtSid(pOwnerSid); } catch( CX_MemoryException ) { return WBEM_E_OUT_OF_MEMORY; } return WBEM_S_NO_ERROR; } HRESULT Execute( CEssNamespace* pNamespace ) { HRESULT hr; // // we must set up a new thread object and then restore the // old one where we're done. Reason for this is that we don't // want our call into the other namespace to affect the postponed // list of this one. // CEssThreadObject* pOldThreadObject = GetCurrentEssThreadObject(); SetCurrentEssThreadObject(NULL); if ( GetCurrentEssThreadObject() != NULL ) { { CInUpdate iu( m_pNamespace ); if ( !m_pNamespace->IsShutdown() ) { hr = m_pNamespace->InternalRegisterNotificationSink( m_wsQueryLanguage, m_wsQuery, m_lFlags, WMIMSG_QOS_FLAG(m_dwQosFlags), NULL, m_pSink, TRUE, m_OwnerSid.GetPtr() ); } else { hr = WBEM_E_SHUTTING_DOWN; } } if ( SUCCEEDED(hr) ) { hr = m_pNamespace->FirePostponedOperations(); } else { m_pNamespace->FirePostponedOperations(); } delete GetCurrentEssThreadObject(); } else { hr = WBEM_E_OUT_OF_MEMORY; } SetConstructedEssThreadObject( pOldThreadObject ); return hr; } }; class CPostponedRemoveNotificationSinkRequest : public CPostponedRequest { protected: CWbemPtr m_pSink; CWbemPtr m_pNamespace; public: CPostponedRemoveNotificationSinkRequest( CEssNamespace* pNamespace, IWbemObjectSink* pSink ) : m_pSink( pSink ), m_pNamespace( pNamespace ) { } HRESULT Execute( CEssNamespace* pNamespace ) { HRESULT hr; // // we must set up a new thread object and then restore the // old one where we're done. Reason for this is that we don't // want our call into the other namespace to affect the postponed // list of this one. // CEssThreadObject* pOldThreadObject = GetCurrentEssThreadObject(); SetCurrentEssThreadObject(NULL); if ( GetCurrentEssThreadObject() != NULL ) { { CInUpdate iu( m_pNamespace ); if ( !m_pNamespace->IsShutdown() ) { hr = m_pNamespace->InternalRemoveNotificationSink(m_pSink); } else { hr = WBEM_E_SHUTTING_DOWN; } } if ( SUCCEEDED(hr) ) { hr = m_pNamespace->FirePostponedOperations(); } else { m_pNamespace->FirePostponedOperations(); } delete GetCurrentEssThreadObject(); } else { hr = WBEM_E_OUT_OF_MEMORY; } SetConstructedEssThreadObject( pOldThreadObject ); return hr; } }; class CFirePostponed : public CExecRequest { protected: CEssNamespace* m_pNamespace; CEssThreadObject* m_pThreadObj; public: CFirePostponed(CEssNamespace* pNamespace, CEssThreadObject* pThreadObj) : m_pNamespace(pNamespace), m_pThreadObj(pThreadObj) { m_pNamespace->AddRef(); } ~CFirePostponed() { m_pNamespace->Release(); delete m_pThreadObj; } HRESULT Execute() { SetConstructedEssThreadObject(m_pThreadObj); m_pNamespace->FirePostponedOperations(); ClearCurrentEssThreadObject(); return WBEM_S_NO_ERROR; } }; //****************************************************************************** // public // // See ess.h for documentation // //****************************************************************************** CEssNamespace::CEssNamespace(CEss* pEss) : m_ClassDeletionSink(this), m_bInResync(FALSE), m_Bindings(this), m_hInitComplete(INVALID_HANDLE_VALUE), m_EventProviderCache(this), m_Poller(this), m_ConsumerProviderCache(this), m_hresInit(WBEM_E_CRITICAL_ERROR), m_ClassCache(this), m_eState(e_Quiet), m_pCoreEventProvider(NULL), m_pEss(pEss), m_wszName(NULL), m_pCoreSvc(NULL), m_pFullSvc(NULL), m_lRef(0), m_pInternalCoreSvc(NULL), m_pInternalFullSvc(NULL), m_pProviderFactory(NULL), m_bStage1Complete(FALSE), m_pAdminOnlySD(NULL), m_cAdminOnlySD(0) { PSID pRawSid; SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY; g_lNumNamespaces++; if(AllocateAndInitializeSid( &id, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,0,&pRawSid)) { m_sidAdministrators = CNtSid(pRawSid); // We're done with this FreeSid( pRawSid ); } } ULONG CEssNamespace::AddRef() { return InterlockedIncrement(&m_lRef); } ULONG CEssNamespace::Release() { long lRef = InterlockedDecrement(&m_lRef); if(lRef == 0) delete this; return lRef; } // // this function is intended to be called in the same control path as // the one which constructs the namespace object. Any initialization that // cannot be defferred is done here. // HRESULT CEssNamespace::PreInitialize( LPCWSTR wszName ) { HRESULT hres; m_wszName = new WCHAR[wcslen(wszName)+1]; if(m_wszName == NULL) { hres = WBEM_E_OUT_OF_MEMORY; return hres; } StringCchCopyW( m_wszName, wcslen(wszName)+1, wszName ); // // create the event that will be used to signal any threads waiting // for initialization to finish. // m_hInitComplete = CreateEvent( NULL, TRUE, FALSE, NULL ); if ( NULL == m_hInitComplete ) { return WBEM_E_CRITICAL_ERROR; } // // create admin only SD for raising core events that are AdminOnly. // static LPCWSTR wszAdminOnlyString = L"O:BAG:BAD:(A;;0x40;;;BA)"; if ( !ConvertStringSecurityDescriptorToSecurityDescriptorW( wszAdminOnlyString, SDDL_REVISION_1, &m_pAdminOnlySD, &m_cAdminOnlySD ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } // // Obtain repository only service. This is used for acessing all // static ess objects. // hres = m_pEss->GetNamespacePointer( m_wszName, TRUE, &m_pCoreSvc ); if(FAILED(hres)) { return WBEM_E_INVALID_NAMESPACE; // not there anymore! } hres = m_pCoreSvc->QueryInterface( IID_IWbemInternalServices, (void**)&m_pInternalCoreSvc ); if(FAILED(hres)) { return WBEM_E_CRITICAL_ERROR; } // // Obtain full service. This is used accessing class objects // ( which may involve accessing class providers. // hres = m_pEss->GetNamespacePointer( m_wszName, FALSE, &m_pFullSvc ); if(FAILED(hres)) { return WBEM_E_INVALID_NAMESPACE; // not there anymore! } hres = m_pFullSvc->QueryInterface( IID_IWbemInternalServices, (void**)&m_pInternalFullSvc ); if(FAILED(hres)) { return WBEM_E_CRITICAL_ERROR; } // // Get provider factory // hres = m_pEss->GetProviderFactory( m_wszName, m_pFullSvc, &m_pProviderFactory); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "No provider factory in %S: 0x%X\n", m_wszName, hres)); } // // we want to ensure that core stays loaded between the PreInitialize() // call and the Initialize() call. This is only ever an issue when the // Initialize() call is defferred. Reason to ensure this is because we // must keep core loaded when we have permanent subscriptions. If we // haven't initialized yet, then we don't know if we have any. AddRef() // core here and will then decrement in Initialize() to ensure this. // IncrementObjectCount(); // // Namespace always starts out in the Quiet state. Caller must make // a MarkAsInitPendingIfQuiet() call if they are going to schedule // initialization. // return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::EnsureInitPending() { { CInCritSec ics(&m_csLevel1); if ( m_eState != e_Quiet ) { return WBEM_S_FALSE; } } CWbemPtr pNamespace; return m_pEss->GetNamespaceObject( m_wszName, TRUE, &pNamespace ); } BOOL CEssNamespace::MarkAsInitPendingIfQuiet() { CInCritSec ics( &m_csLevel1 ); if ( m_eState != e_Quiet ) { return FALSE; } m_eState = e_InitializePending; return TRUE; }; HRESULT CEssNamespace::Initialize() { HRESULT hres; DEBUGTRACE((LOG_ESS,"Initializing namespace %S\n", m_wszName )); // // need to modify level2 members. Grab namespace lock. // { CInUpdate iu(this); { CInCritSec ics( &m_csLevel1 ); if ( m_eState == e_Shutdown ) { return WBEM_E_SHUTTING_DOWN; } _DBG_ASSERT( m_eState == e_InitializePending ); } // // Load and process subscription objects // hres = PerformSubscriptionInitialization(); } // // execute postponed operations outside of namespace lock. // if some of them fail to execute, it doesn't mean that the namespace // can't be initialized. just log the error. // HRESULT hres2 = FirePostponedOperations(); if ( FAILED(hres2) ) { ERRORTRACE((LOG_ESS,"Failed to execute postponed operations when " "performing initialization in namespace %S. HR=0x%x\n", m_wszName, hres2)); } return hres; } HRESULT CEssNamespace::CompleteInitialization() { HRESULT hres; DEBUGTRACE((LOG_ESS,"Completing Initialization for namespace %S\n", m_wszName)); // // need to modify level2 members. Grab namespace lock. // { CInUpdate iu(this); // // stage 1 of initialization really isn't complete until we grab the // lock to perform stage 2. // m_bStage1Complete = TRUE; { CInCritSec ics( &m_csLevel1 ); if ( m_eState == e_Shutdown ) { return WBEM_E_SHUTTING_DOWN; } _DBG_ASSERT( m_eState == e_InitializePending ); } // // load and process all objects that deal with event providers. // hres = PerformProviderInitialization(); } // // execute postponed operations outside of namespace lock. // if some of them fail to execute, it doesn't mean that the namespace // can't be initialized. just log the error. // HRESULT hres2 = FirePostponedOperations(); if ( FAILED(hres2) ) { ERRORTRACE((LOG_ESS,"Failed to execute postponed operations when " "completing initialization in namespace %S. HR=0x%x\n", m_wszName, hres2)); } return hres; } void CEssNamespace::MarkAsInitialized( HRESULT hres ) { // // we need to grab the level1 critsec here because we're going to be // modifying the state of the namespace and because we're going to be // using the defferred events list. // CInCritSec ics( &m_csLevel1 ); if ( m_eState == e_Shutdown ) { return; } _DBG_ASSERT( m_eState == e_InitializePending ); // // transition to Initialized. // if ( SUCCEEDED(hres) && m_pCoreEventProvider != NULL ) { // // while holding level1, handle any deferred events // for( int i=0; i < m_aDeferredEvents.GetSize(); i++ ) { // // iterate through 1 by 1 because later we may propagate // context for each event here. // HRESULT hr; CEventContext Context; hr = m_pCoreEventProvider->Fire( *m_aDeferredEvents[i], &Context ); if ( FAILED(hr) ) { ERRORTRACE((LOG_ESS,"Could not fire deferred event in " "namespace '%S'. HR=0x%x\n", m_wszName, hr )); } delete m_aDeferredEvents[i]; } if ( m_aDeferredEvents.GetSize() > 0 ) { DEBUGTRACE((LOG_ESS,"Fired %d deferred events after init " "complete in namespace '%S'.\n", m_aDeferredEvents.GetSize(),m_wszName)); } m_aDeferredEvents.RemoveAll(); } // // release the ref we were holding to keep core loaded between PreInit() // and now. // DecrementObjectCount(); m_eState = e_Initialized; m_hresInit = hres; SetEvent( m_hInitComplete ); } HRESULT CEssNamespace::WaitForInitialization() { IWbemContext *pContext = GetCurrentEssContext( ); VARIANT vValue; HRESULT hres; do { if ( NULL == pContext ) { break; } hres = pContext->GetValue( L"__ReentranceTestProp", 0, &vValue ); if ( WBEM_E_NOT_FOUND == hres ) { break; } if ( FAILED( hres ) ) { return hres; } if ( VARIANT_TRUE == V_BOOL( &vValue ) ) { return S_OK; } } while( FALSE ); // // The level1 or level2 locks cannot be held when calling this function. // The reason for this is because we may be we waiting on the initialize // event. // CInCritSec ics(&m_csLevel1); if ( m_eState == e_Shutdown ) { return WBEM_E_SHUTTING_DOWN; } if ( m_eState == e_Initialized ) { return m_hresInit; } _DBG_ASSERT( m_eState == e_InitializePending ); _DBG_ASSERT( m_hInitComplete != INVALID_HANDLE_VALUE ) // // wait for initialization to complete. // LeaveCriticalSection( &m_csLevel1 ); m_pEss->TriggerDeferredInitialization(); DWORD dwRes = WaitForSingleObject( m_hInitComplete, 20*60*1000 ); EnterCriticalSection( &m_csLevel1 ); if ( dwRes != WAIT_OBJECT_0 ) { return WBEM_E_CRITICAL_ERROR; } return m_hresInit; } BOOL CEssNamespace::DoesThreadOwnNamespaceLock() { return m_csLevel2.GetLockCount() != -1 && m_csLevel2.GetOwningThreadId() == GetCurrentThreadId(); } void CEssNamespace::LogOp( LPCWSTR wszOp, IWbemClassObject* pObj ) { if ( LoggingLevelEnabled(2) ) { _DBG_ASSERT(pObj!=NULL); BSTR bstrText; if ( SUCCEEDED(pObj->GetObjectText( 0, &bstrText )) ) { DEBUGTRACE((LOG_ESS,"%S in namespace %S. Object is %S\n", wszOp, m_wszName, bstrText )); SysFreeString( bstrText ); } } } CQueueingEventSink* CEssNamespace::GetQueueingEventSink( LPCWSTR wszSinkName ) { HRESULT hr; // // TODO: For now there is a 1 to 1 mapping between a sink and a consumer. // ( consumer inherits from queueing sink ). This will not always be // the case. Here, the sink name is really the standard path to the cons. // CEventConsumer* pCons; hr = m_Bindings.FindEventConsumer( wszSinkName, &pCons ); if ( FAILED(hr) ) { return NULL; } return pCons; } //****************************************************************************** // public // // See ess.h for documentation // //****************************************************************************** BOOL CEssNamespace::IsNeededOnStartup() { return m_Bindings.DoesHavePermanentConsumers(); } void CEssNamespace::SetActive() { // // Inform ESS of our newely active status so that it can make sure // we are reloaded the next time around // m_pEss->SetNamespaceActive(m_wszName); } void CEssNamespace::SetInactive() { // // Inform ESS of our newely inactive status so that it does not have to // reload us the next time around // m_pEss->SetNamespaceInactive(m_wszName); } // // This is a quick and dirty shutdown of the namespace that is used when the // process is shutting down. // HRESULT CEssNamespace::Park() { { CInUpdate iu(this); m_Bindings.Clear( false ); } FirePostponedOperations(); return S_OK; } // // This is the slow and clean shutdown that is used when the namespace is // purged. // HRESULT CEssNamespace::Shutdown() { { // // we want to wait until all update operations have completed, then // we'll mark the namespace as shutdown. // CInUpdate iu(this); // // we will also be modifying the level1 members too so need level1 // lock. // CInCritSec ics(&m_csLevel1); m_eState = e_Shutdown; } // // at this point all new calls into the namespace will be rejected. // // // wake up any threads waiting for Initialization. // SetEvent( m_hInitComplete ); InternalRemoveNotificationSink(&m_ClassDeletionSink); m_EventProviderCache.Shutdown(); m_Bindings.Clear( false ); m_Poller.Clear(); m_ConsumerProviderCache.Clear(); FirePostponedOperations(); return WBEM_S_NO_ERROR; } CEssNamespace::~CEssNamespace() { // // Do not call shutdown here. Shutdown() is an operation that incurrs // postponed operations and triggering them to fire here is not usually // expected by the caller. If the caller wants to call shutdown on their // own then they are welcome to do so. // g_lNumNamespaces--; delete [] m_wszName; if(m_pCoreSvc) m_pCoreSvc->Release(); if(m_pFullSvc) m_pFullSvc->Release(); if(m_pInternalCoreSvc) m_pInternalCoreSvc->Release(); if(m_pInternalFullSvc) m_pInternalFullSvc->Release(); if(m_pProviderFactory) m_pProviderFactory->Release(); if(m_pCoreEventProvider) m_pCoreEventProvider->Release(); if ( m_hInitComplete != INVALID_HANDLE_VALUE ) CloseHandle( m_hInitComplete ); for( int i=0; i < m_aDeferredEvents.GetSize(); i++ ) delete m_aDeferredEvents[i]; if ( m_pAdminOnlySD != NULL ) LocalFree( m_pAdminOnlySD ); } HRESULT CEssNamespace::GetNamespacePointer( RELEASE_ME IWbemServices** ppNamespace) { // // This function returns the full svc pointer for use outside this class. // We want to ensure that we don't use the full service ptr until we've // completed stage 1 initialization. Reason is that we don't want to // load class providers until the second stage of initialization. // _DBG_ASSERT( m_bStage1Complete ); if(m_pFullSvc == NULL) return WBEM_E_CRITICAL_ERROR; *ppNamespace = m_pFullSvc; (*ppNamespace)->AddRef(); return S_OK; } HRESULT CEssNamespace::ActOnSystemEvent(CEventRepresentation& Event, long lFlags) { HRESULT hres; // This macro will execute its parameter if updates are allowed at this time on // this thread, and schedule it otherwise (in the case of an event provider // calling back #define PERFORM_IF_ALLOWED(OP) OP // Check the type // ============== if(Event.IsInstanceEvent()) { // Instance creation, deletion or modification event. Check class // ============================================================== if(!wbem_wcsicmp(CLASS_OF(Event), EVENT_FILTER_CLASS)) { return PERFORM_IF_ALLOWED(ReloadEventFilter(OBJECT_OF(Event))); } else if(!wbem_wcsicmp(CLASS_OF(Event), BINDING_CLASS)) { return PERFORM_IF_ALLOWED(ReloadBinding(OBJECT_OF(Event))); } else if(!wbem_wcsicmp(CLASS_OF(Event), EVENT_PROVIDER_REGISTRATION_CLASS)) { return PERFORM_IF_ALLOWED( ReloadEventProviderRegistration(OBJECT_OF(Event))); } else if(!wbem_wcsicmp(CLASS_OF(Event), CONSUMER_PROVIDER_REGISTRATION_CLASS)) { return PERFORM_IF_ALLOWED( ReloadConsumerProviderRegistration(OBJECT_OF(Event))); } else if(OBJECT_OF(Event)->InheritsFrom(PROVIDER_CLASS) == S_OK) { return PERFORM_IF_ALLOWED(ReloadProvider(OBJECT_OF(Event))); } else if(OBJECT_OF(Event)->InheritsFrom(CONSUMER_CLASS) == S_OK) { return PERFORM_IF_ALLOWED(ReloadEventConsumer(OBJECT_OF(Event), lFlags)); } else if(OBJECT_OF(Event)->InheritsFrom(TIMER_BASE_CLASS) == S_OK) { return PERFORM_IF_ALLOWED(ReloadTimerInstruction(OBJECT_OF(Event))); } else { return WBEM_S_FALSE; } } else if(Event.type == e_EventTypeClassDeletion) { // // For now --- only for deletions. Force-mode modifications are not // properly handled at the moment. // return PERFORM_IF_ALLOWED( HandleClassChange(CLASS_OF(Event), OBJECT_OF(Event))); } else if(Event.type == e_EventTypeClassCreation) { return PERFORM_IF_ALLOWED( HandleClassCreation(CLASS_OF(Event), OBJECT_OF(Event))); } else if(Event.type == e_EventTypeNamespaceDeletion) { // Construct full namespace name (ours + child) // ============================================= DWORD cLen = wcslen(m_wszName) + wcslen(Event.wsz2) + 2; LPWSTR wszFullName = new WCHAR[cLen]; if(wszFullName == NULL) return WBEM_E_OUT_OF_MEMORY; CVectorDeleteMe vdm( wszFullName ); StringCchPrintfW( wszFullName, cLen, L"%s\\%s", m_wszName, Event.wsz2); // Get the main object to purge that namespace // =========================================== return m_pEss->PurgeNamespace(wszFullName); } else { // Not of interest // =============== return WBEM_S_FALSE; } } HRESULT CEssNamespace::ValidateSystemEvent(CEventRepresentation& Event) { HRESULT hr; // Check the type // ============== if(Event.IsInstanceEvent()) { IWbemClassObject* pPrevObj = NULL; IWbemClassObject* pObj = NULL; if(Event.type == e_EventTypeInstanceCreation) pObj = OBJECT_OF(Event); else if(Event.type == e_EventTypeInstanceDeletion) pPrevObj = OBJECT_OF(Event); else if(Event.type == e_EventTypeInstanceModification) { pObj = OBJECT_OF(Event); pPrevObj = OTHER_OBJECT_OF(Event); } // Instance creation, deletion or modification event. Check class // ============================================================== if(!wbem_wcsicmp(CLASS_OF(Event), EVENT_FILTER_CLASS)) { hr = CheckEventFilter(pPrevObj, pObj); } else if(!wbem_wcsicmp(CLASS_OF(Event), BINDING_CLASS)) { hr = CheckBinding(pPrevObj, pObj); } else if(!wbem_wcsicmp(CLASS_OF(Event), EVENT_PROVIDER_REGISTRATION_CLASS)) { hr = CheckEventProviderRegistration(OBJECT_OF(Event)); } else if(OBJECT_OF(Event)->InheritsFrom(CONSUMER_CLASS) == S_OK) { hr = CheckEventConsumer(pPrevObj, pObj); } else if(OBJECT_OF(Event)->InheritsFrom(TIMER_BASE_CLASS) == S_OK) { hr = CheckTimerInstruction(pObj); } else { hr = WBEM_S_FALSE; } // // even some of the validation routines use postponed operations. // FirePostponedOperations(); } else { // Not of interest // =============== hr = WBEM_S_FALSE; } return hr; } HRESULT CEssNamespace::CheckEventConsumer(IWbemClassObject* pPrevConsumerObj, IWbemClassObject* pConsumerObj) { HRESULT hres; ENSURE_INITIALIZED hres = CheckSecurity(pPrevConsumerObj, pConsumerObj); return hres; } PSID CEssNamespace::GetSidFromObject(IWbemClassObject* pObj) { HRESULT hres; VARIANT vSid; VariantInit(&vSid); CClearMe cm1(&vSid); hres = pObj->Get(OWNER_SID_PROPNAME, 0, &vSid, NULL, NULL); if(FAILED(hres) || V_VT(&vSid) != (VT_UI1 | VT_ARRAY)) { return NULL; } // Construct an actual PSID from the SAFEARRAY // =========================================== PSID pOriginal = NULL; hres = SafeArrayAccessData(V_ARRAY(&vSid), (void**)&pOriginal); if(FAILED(hres)) { return NULL; } CUnaccessMe uam(V_ARRAY(&vSid)); long cOriginal; if ( FAILED(SafeArrayGetUBound( V_ARRAY(&vSid), 1, &cOriginal ) )) { return NULL; } cOriginal++; // SafeArrayGetUBound() is -1 based // // validate SID. // DWORD dwSidLength = GetLengthSid(pOriginal); if ( dwSidLength > cOriginal || !IsValidSid(pOriginal) ) { return NULL; } // Make a copy and return it // ========================= PSID pCopy = (PSID)new BYTE[dwSidLength]; if(pCopy == NULL) return NULL; if(!CopySid(dwSidLength, pCopy, pOriginal)) { delete [] (BYTE*)pCopy; return NULL; } return pCopy; } HRESULT CEssNamespace::CheckSecurity(IWbemClassObject* pPrevObj, IWbemClassObject* pObj) { HRESULT hres; if(!IsNT()) return WBEM_S_NO_ERROR; // Retrieve the SID of the calling user // ==================================== hres = CoImpersonateClient(); if(FAILED(hres)) return hres; CNtSid Sid; hres = RetrieveSidFromCall(Sid); CoRevertToSelf(); if(FAILED(hres)) return hres; // If modifying an existing object, check override security // ======================================================== if(pPrevObj) { hres = CheckOverwriteSecurity(pPrevObj, Sid); if(FAILED(hres)) return hres; } // If creating a new version of an object, ensure Sid correctness // ============================================================== if(pObj) { hres = EnsureSessionSid(pObj, Sid); if(FAILED(hres)) return hres; } return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::CheckSidForPrivilege( PSID sid ) { HRESULT hres; // // we must check that it will be possible to even perform access checks // for this SID. If the SID is a domain account, then we need to see // if this machine even has permission in the domain to enumerate the // groups for this user ( necessary for performing access checks later // on. ) If not, then we should fail now during subscription creation // vs later on when performing the access checks. // IWbemToken* pTok; hres = GetToken( sid, &pTok ); if ( FAILED(hres) ) { if ( hres == HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ) ) return WBEMESS_E_AUTHZ_NOT_PRIVILEGED; return hres; } pTok->Release(); return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::EnsureSessionSid(IWbemClassObject* pObj, CNtSid& Sid) { HRESULT hres; PSID pOldSid = GetSidFromObject(pObj); if( pOldSid == NULL ) { // // No SID --- just put owner SID in there // hres = PutSidInObject(pObj, Sid); if ( SUCCEEDED(hres) ) hres = CheckSidForPrivilege( Sid.GetPtr() ); return hres; } CVectorDeleteMe vdm((BYTE*)pOldSid); // // Check for the special case of administrators --- they get to use the // Administrators SID instead of their own for off-line operations. // hres = IsCallerAdministrator(); if(FAILED(hres) && hres != WBEM_E_ACCESS_DENIED) return hres; BOOL bAdmin = hres == WBEM_S_NO_ERROR; if ( EqualSid(pOldSid, Sid.GetPtr()) || ( bAdmin && EqualSid(pOldSid, GetAdministratorsSid().GetPtr()) ) ) { // // the existing SID is o.k. // return CheckSidForPrivilege( pOldSid ); } if ( !bAdmin ) { CNtSid OldSid(pOldSid); WCHAR achSid[130], achOldSid[130]; DWORD cSid = 130, cOldSid = 130; if ( Sid.GetTextSid( achSid, &cSid ) && OldSid.GetTextSid( achOldSid, &cOldSid ) ) { ERRORTRACE((LOG_ESS, "ERROR : " "User %S has tried to put an incompatible SID " "%S in a subscription instance. " "Using User SID instead.\n", achSid, achOldSid )); } } // // Invalid SID found --- replace with owner SID // hres = PutSidInObject( pObj, Sid ); if ( SUCCEEDED(hres) ) hres = CheckSidForPrivilege( Sid.GetPtr() ); return hres; } HRESULT CEssNamespace::PutSidInObject(IWbemClassObject* pObj, CNtSid& Sid) { HRESULT hres; // // Clear it first // VARIANT vSid; VariantInit(&vSid); V_VT(&vSid) = VT_NULL; CClearMe cm1(&vSid); hres = pObj->Put(OWNER_SID_PROPNAME, 0, &vSid, 0); if(FAILED(hres)) return hres; // // Construct a safearray for it // V_VT(&vSid) = VT_ARRAY | VT_UI1; SAFEARRAYBOUND sab; sab.cElements = Sid.GetSize(); sab.lLbound = 0; V_ARRAY(&vSid) = SafeArrayCreate(VT_UI1, 1, &sab); if(V_ARRAY(&vSid) == NULL) return WBEM_E_OUT_OF_MEMORY; // Copy the SID in there // ===================== BYTE* abSid = NULL; hres = SafeArrayAccessData(V_ARRAY(&vSid), (void**)&abSid); if(FAILED(hres)) return WBEM_E_OUT_OF_MEMORY; CUnaccessMe uam(V_ARRAY(&vSid)); if(!CopySid(Sid.GetSize(), (PSID)abSid, Sid.GetPtr())) return WBEM_E_OUT_OF_MEMORY; // Put it into the consumer // ======================== hres = pObj->Put(OWNER_SID_PROPNAME, 0, &vSid, 0); return hres; } HRESULT CEssNamespace::CheckOverwriteSecurity(IWbemClassObject* pPrevObj, CNtSid& ActingSid) { HRESULT hres; if(!IsNT()) return WBEM_S_NO_ERROR; // Retrieve owner SID from the old object // ====================================== PSID pOwnerSid = GetSidFromObject(pPrevObj); if(pOwnerSid == NULL) return WBEM_E_OUT_OF_MEMORY; CVectorDeleteMe vdm((BYTE*)pOwnerSid); // Compare the owner sid with the acting SID. If same, allow access // ================================================================= if(EqualSid(pOwnerSid, ActingSid.GetPtr())) return WBEM_S_NO_ERROR; // Not the same --- still hope that the acting SID is an Admin // =========================================================== hres = IsCallerAdministrator(); if(FAILED(hres)) return hres; // // OK --- an admin can overwrite // return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::IsCallerAdministrator() { HRESULT hres; hres = CoImpersonateClient(); if(FAILED(hres)) return hres; OnDelete0 RevertMe; HANDLE hToken; if(!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken)) return WBEM_E_FAILED; CCloseMe ccm(hToken); if(CNtSecurity::IsUserInGroup(hToken, GetAdministratorsSid())) return WBEM_S_NO_ERROR; return WBEM_E_ACCESS_DENIED; } HRESULT CEssNamespace::CheckEventFilter(IWbemClassObject* pOldFilterObj, IWbemClassObject* pFilterObj) { HRESULT hres; ENSURE_INITIALIZED // Check security // ============== hres = CheckSecurity(pOldFilterObj, pFilterObj); if(FAILED(hres)) return hres; // Check everything else // ===================== return CPermanentFilter::CheckValidity(pFilterObj); } HRESULT CEssNamespace::ReloadEventFilter(IWbemClassObject* pFilterObjTemplate) { HRESULT hres; LogOp( L"ReloadEventFilter", pFilterObjTemplate ); ENSURE_INITIALIZED // Start by deleting this event filter from our records, if there // ============================================================== hres = RemoveEventFilter(pFilterObjTemplate); if(FAILED(hres)) return hres; // Determine the current state of this filter in the database // ========================================================== IWbemClassObject* pFilterObj = NULL; hres = GetCurrentState(pFilterObjTemplate, &pFilterObj); if(FAILED(hres)) return hres; if(pFilterObj == NULL) { // The filter has been deleted --- no further action is needed // =========================================================== return S_OK; } CReleaseMe rm1(pFilterObj); // Now create it if necessary // ========================== hres = AddEventFilter(pFilterObj); if(FAILED(hres)) return hres; return hres; } //****************************************************************************** // // Starting with the namespace locked and the filter deleted from the records, // AddEventFilter updates the records to the state of this filter in the // database. // //****************************************************************************** HRESULT CEssNamespace::AddEventFilter(IWbemClassObject* pFilterObj, BOOL bInRestart) { HRESULT hres; // Construct the new filter // ======================== CPermanentFilter* pFilter = new CPermanentFilter(this); if(pFilter == NULL) return WBEM_E_OUT_OF_MEMORY; pFilter->AddRef(); CReleaseMe rm2(pFilter); // Initialize it // ============= hres = pFilter->Initialize(pFilterObj); if(FAILED(hres)) return hres; // Add it to the table // =================== hres = m_Bindings.AddEventFilter(pFilter); if(FAILED(hres)) return hres; if(!bInRestart) { // Process all the bindings that this filter might have // ==================================================== hres = AssertBindings(pFilterObj); if(FAILED(hres)) return hres; } return hres; } //****************************************************************************** // // Starting with the namespace locked, RemoveEventFilter updates the records // to remove all mention of this filter. Note: this is *not* the function to be // called in response to the database instance-deletion event, as the filter // could have been recreated in the interim. // //****************************************************************************** HRESULT CEssNamespace::RemoveEventFilter(IWbemClassObject* pFilterObj) { HRESULT hres; // Calculate the key for this filter // ================================= BSTR strKey = CPermanentFilter::ComputeKeyFromObj(pFilterObj); if(strKey == NULL) return WBEM_E_OUT_OF_MEMORY; CSysFreeMe sfm1(strKey); // Remove it from the table, thus deactivating it // ============================================== hres = m_Bindings.RemoveEventFilter(strKey); if(hres == WBEM_E_NOT_FOUND) return S_FALSE; return hres; } //***************************************************************************** // // Called in response to an instance operation event related to an event // consumer object. // //***************************************************************************** HRESULT CEssNamespace::ReloadEventConsumer( IWbemClassObject* pConsumerObjTemplate, long lFlags) { HRESULT hres; LogOp( L"ReloadConsumer", pConsumerObjTemplate ); ENSURE_INITIALIZED // Start by deleting this event consumer from our records, if there // ================================================================ hres = RemoveEventConsumer(pConsumerObjTemplate); if(FAILED(hres)) return hres; // Determine the current state of this Consumer in the database // ============================================================ IWbemClassObject* pConsumerObj = NULL; hres = GetCurrentState(pConsumerObjTemplate, &pConsumerObj); if(FAILED(hres)) return hres; if(pConsumerObj == NULL) { // The Consumer has been deleted --- no further action is needed // ============================================================= return S_OK; } CReleaseMe rm1(pConsumerObj); // Now create it if necessary // ========================== hres = AddEventConsumer(pConsumerObjTemplate, lFlags, FALSE); return hres; } //****************************************************************************** // // Starting with the namespace locked and the consumer deleted from the records // AddEventConsumer updates the records to the state of this consumer in the // database. // //****************************************************************************** HRESULT CEssNamespace::AddEventConsumer(IWbemClassObject* pConsumerObj, long lFlags, BOOL bInRestart) { HRESULT hres; // Construct the new Consumer // ========================== CPermanentConsumer* pConsumer = new CPermanentConsumer(this); if(pConsumer == NULL) return WBEM_E_OUT_OF_MEMORY; pConsumer->AddRef(); CReleaseMe rm2(pConsumer); // Initialize it // ============= hres = pConsumer->Initialize(pConsumerObj); if(FAILED(hres)) return hres; // // Validate if required // if(lFlags & WBEM_FLAG_STRONG_VALIDATION) { hres = pConsumer->Validate(pConsumerObj); if(FAILED(hres)) { return hres; } } // Add it to the table // =================== hres = m_Bindings.AddEventConsumer(pConsumer); if(FAILED(hres)) return hres; if(!bInRestart) { // Process all the bindings that this consumer might have // ====================================================== hres = AssertBindings(pConsumerObj); if(FAILED(hres)) return hres; } return hres; } //****************************************************************************** // // Starting with the namespace locked, RemoveEventConsumer updates the records // to remove all mention of this consumer. // //****************************************************************************** HRESULT CEssNamespace::RemoveEventConsumer(IWbemClassObject* pConsumerObj) { HRESULT hres; // Calculate the key for this filter // ================================= BSTR strKey = CPermanentConsumer::ComputeKeyFromObj(this, pConsumerObj); if(strKey == NULL) return WBEM_E_OUT_OF_MEMORY; CSysFreeMe sfm1(strKey); // Remove it from the table // ======================== hres = m_Bindings.RemoveEventConsumer(strKey); if(hres == WBEM_E_NOT_FOUND) return S_FALSE; return hres; } HRESULT CEssNamespace::CheckBinding(IWbemClassObject* pPrevBindingObj, IWbemClassObject* pBindingObj) { HRESULT hres; ENSURE_INITIALIZED // // Check security // hres = CheckSecurity(pPrevBindingObj, pBindingObj); if(FAILED(hres)) return hres; // // Construct a fake binding to test correctness // CPermanentBinding* pBinding = new CPermanentBinding; if(pBinding == NULL) return WBEM_E_OUT_OF_MEMORY; pBinding->AddRef(); CTemplateReleaseMe trm(pBinding); hres = pBinding->Initialize(pBindingObj); if(FAILED(hres)) return hres; return S_OK; } //****************************************************************************** // // Called in response to an instance operation event related to a binding // instance. // //****************************************************************************** HRESULT CEssNamespace::ReloadBinding(IWbemClassObject* pBindingObjTemplate) { HRESULT hres; LogOp( L"ReloadBinding", pBindingObjTemplate ); ENSURE_INITIALIZED // Retrieve consumer and provider keys from the binding // ==================================================== BSTR strPrelimConsumerKey = NULL; BSTR strFilterKey = NULL; hres = CPermanentBinding::ComputeKeysFromObject(pBindingObjTemplate, &strPrelimConsumerKey, &strFilterKey); if(FAILED(hres)) return hres; CSysFreeMe sfm1(strPrelimConsumerKey); CSysFreeMe sfm2(strFilterKey); // Get real paths from these possibly abbreviated ones // =================================================== BSTR strConsumerKey = NULL; hres = m_pInternalCoreSvc->GetNormalizedPath( strPrelimConsumerKey, &strConsumerKey); if(FAILED(hres)) return hres; CSysFreeMe sfm3(strConsumerKey); // Start by deleting this binding from our records, if there // ========================================================= hres = RemoveBinding(strFilterKey, strConsumerKey); if(FAILED(hres) && hres != WBEM_E_NOT_FOUND) return hres; // Determine the current state of this binding in the database // ============================================================ IWbemClassObject* pBindingObj = NULL; hres = GetCurrentState(pBindingObjTemplate, &pBindingObj); if(FAILED(hres)) return hres; if(pBindingObj == NULL) { // The Binding has been deleted --- no further action is needed // ============================================================= return S_OK; } CReleaseMe rm1(pBindingObj); // Now create it if necessary // ========================== hres = AddBinding(strFilterKey, strConsumerKey, pBindingObjTemplate); return hres; } HRESULT CEssNamespace::AddBinding(IWbemClassObject* pBindingObj) { HRESULT hres; // Retrieve consumer and provider keys from the binding // ==================================================== BSTR strPrelimConsumerKey = NULL; BSTR strFilterKey = NULL; hres = CPermanentBinding::ComputeKeysFromObject(pBindingObj, &strPrelimConsumerKey, &strFilterKey); if(FAILED(hres)) return hres; CSysFreeMe sfm1(strPrelimConsumerKey); CSysFreeMe sfm2(strFilterKey); // Get real paths from these possibly abbreviated ones // =================================================== BSTR strConsumerKey = NULL; hres = m_pInternalCoreSvc->GetNormalizedPath( strPrelimConsumerKey, &strConsumerKey ); if(FAILED(hres)) return hres; CSysFreeMe sfm3(strConsumerKey); return AddBinding(strFilterKey, strConsumerKey, pBindingObj); } HRESULT CEssNamespace::AddBinding(LPCWSTR wszFilterKey, LPCWSTR wszConsumerKey, IWbemClassObject* pBindingObj) { HRESULT hres; // Create a new binding // ==================== CPermanentBinding* pBinding = new CPermanentBinding; if(pBinding == NULL) return WBEM_E_OUT_OF_MEMORY; pBinding->AddRef(); CReleaseMe rm1(pBinding); // Initialize it with the information we have // ========================================== hres = pBinding->Initialize(pBindingObj); if(FAILED(hres)) return hres; // Extract its creator's SID // ======================== PSID pSid = CPermanentBinding::GetSidFromObject(pBindingObj); if ( pSid == NULL ) { return WBEM_E_OUT_OF_MEMORY; } hres = m_Bindings.Bind( wszFilterKey, wszConsumerKey, pBinding, pSid ); delete [] pSid; return hres; } HRESULT CEssNamespace::RemoveBinding(LPCWSTR wszFilterKey, LPCWSTR wszConsumerKey) { HRESULT hres; hres = m_Bindings.Unbind(wszFilterKey, wszConsumerKey); if(hres == WBEM_E_NOT_FOUND) return S_FALSE; return hres; } //****************************************************************************** // // Reads all the bindings referencing a given objects from the database and // asserts them. // //****************************************************************************** class CAssertBindingsSink : public CObjectSink { protected: CEssNamespace* m_pNamespace; public: CAssertBindingsSink(CEssNamespace* pNamespace) : m_pNamespace(pNamespace) { AddRef(); } STDMETHOD(Indicate)(long lNumObjects, IWbemClassObject** apObjects) { for(long i = 0; i < lNumObjects; i++) { m_pNamespace->AddBinding(apObjects[i]); } return S_OK; } }; HRESULT CEssNamespace::AssertBindings(IWbemClassObject* pEndpoint) { // Get the relative path of the endpoint // ===================================== VARIANT vRelPath; VariantInit(&vRelPath); CClearMe cm1(&vRelPath); HRESULT hres = pEndpoint->Get(L"__RELPATH", 0, &vRelPath, NULL, NULL); if(FAILED(hres)) return hres; if(V_VT(&vRelPath) != VT_BSTR) return WBEM_E_INVALID_OBJECT; BSTR strRelPath = V_BSTR(&vRelPath); // Issue the query // =============== DWORD cLen = 200 + wcslen(strRelPath); BSTR strQuery = SysAllocStringLen(NULL, cLen); if(strQuery == NULL) return WBEM_E_OUT_OF_MEMORY; CSysFreeMe sfm1(strQuery); StringCchPrintfW( strQuery, cLen, L"references of {%s} where " L"ResultClass = __FilterToConsumerBinding", strRelPath); CAssertBindingsSink Sink(this); hres = ExecQuery(strQuery, 0, &Sink); return hres; } HRESULT CEssNamespace::ReloadTimerInstruction( IWbemClassObject* pInstObjTemplate) { HRESULT hres; LogOp( L"ReloadTimerInstruction", pInstObjTemplate ); ENSURE_INITIALIZED hres = RemoveTimerInstruction(pInstObjTemplate); if(FAILED(hres)) return hres; // Get the current version from the namespace // ========================================== IWbemClassObject* pInstObj = NULL; hres = GetCurrentState(pInstObjTemplate, &pInstObj); if(FAILED(hres)) return hres; if(pInstObj == NULL) { // The instruction has been deleted --- no further action is needed // ================================================================ return S_OK; } CReleaseMe rm1(pInstObj); // Add it to the generator // ======================= hres = AddTimerInstruction(pInstObj); if(FAILED(hres)) return hres; return hres; } HRESULT CEssNamespace::AddTimerInstruction(IWbemClassObject* pInstObj) { return m_pEss->GetTimerGenerator(). LoadTimerEventObject(m_wszName, pInstObj); } //****************************************************************************** // public // // See ess.h for documentation // //****************************************************************************** HRESULT CEssNamespace::RemoveTimerInstruction(IWbemClassObject* pOldObject) { HRESULT hres; VARIANT vID; VariantInit(&vID); hres = pOldObject->Get(TIMER_ID_PROPNAME, 0, &vID, NULL, NULL); if(FAILED(hres)) return hres; if ( V_VT(&vID) != VT_BSTR ) { VariantClear(&vID); return WBEM_E_INVALID_OBJECT; } m_pEss->GetTimerGenerator().Remove(m_wszName, V_BSTR(&vID)); VariantClear(&vID); return S_OK; } //****************************************************************************** // public // // See ess.h for documentation // //****************************************************************************** HRESULT CEssNamespace::SignalEvent( READ_ONLY CEventRepresentation& Event, long lFlags, BOOL bAdminOnly ) { HRESULT hres; // // we cannot hold any turns in an exec line or hold the namespace lock // when calling this function. This is because this function will // aquire the proxy lock. // CPostponedList* pList; _DBG_ASSERT( !DoesThreadOwnNamespaceLock() ); _DBG_ASSERT( !(pList=GetCurrentPostponedList()) || !pList->IsHoldingTurns() ); // BUGBUG: need to propagate security context to this function ? CWbemPtr pCoreEventProvider; { // // we need to figure out if we need to deffer the event or signal it. // we deffer events when we are in the init pending or init state. // CInCritSec ics( &m_csLevel1 ); if ( m_eState == e_Initialized ) { pCoreEventProvider = m_pCoreEventProvider; } else if ( m_eState == e_InitializePending ) { // // Copy and add to defferred list. // CEventRepresentation* pEvRep = Event.MakePermanentCopy(); if ( pEvRep == NULL ) { return WBEM_E_OUT_OF_MEMORY; } if ( m_aDeferredEvents.Add( pEvRep ) < 0 ) { delete pEvRep; return WBEM_E_OUT_OF_MEMORY; } } } if ( pCoreEventProvider != NULL ) { CEventContext Context; if ( bAdminOnly ) Context.SetSD( m_cAdminOnlySD, PBYTE(m_pAdminOnlySD), FALSE ); hres = pCoreEventProvider->Fire( Event, &Context ); if(FAILED(hres)) { return hres; } } return WBEM_S_NO_ERROR; } //****************************************************************************** // public // // See ess.h for documentation // //****************************************************************************** HRESULT CEssNamespace::ProcessEvent(READ_ONLY CEventRepresentation& Event, long lFlags) { // Ignore internal operations // ========================== if(Event.wsz2 != NULL && (!wbem_wcsicmp(Event.wsz2, L"__TimerNextFiring") || !wbem_wcsicmp(Event.wsz2, L"__ListOfEventActiveNamespaces"))) { return WBEM_S_NO_ERROR; } HRESULT hres, hresReturn = WBEM_S_NO_ERROR; // Analyze it for system changes // ============================= hres = ActOnSystemEvent(Event, lFlags); if(FAILED(hres)) { // // Check if this operation needs to be failed if invalid // if( lFlags & WBEM_FLAG_STRONG_VALIDATION ) { hresReturn = hres; } else { ERRORTRACE((LOG_ESS, "Event subsystem was unable to perform the " "necessary operations to accomodate a change to the system " "state.\nThe state of the database may not reflect the state " "of the event subsystem (%X)\n", hres)); } } // Fire postponed operations // ========================= hres = FirePostponedOperations(); if(FAILED(hres)) { ERRORTRACE((LOG_ESS,"Event subsystem was unable to perform the (post) " "necessary operations to accomodate a change to the system state.\n" "The state of the database may not reflect the state of the event " "subsystem (%X)\n", hres)); } // Deliver it to consumers // ======================= hres = SignalEvent( Event, lFlags ); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Event subsystem was unable to deliver a " "repository intrinsic event to some consumers (%X)\n", hres)); } return hresReturn; } HRESULT CEssNamespace::ProcessQueryObjectSinkEvent( READ_ONLY CEventRepresentation& Event ) { HRESULT hres; hres = EnsureInitPending(); if ( FAILED(hres) ) return hres; hres = WaitForInitialization(); if ( FAILED(hres) ) return hres; if ( m_eState == e_Shutdown ) return WBEM_E_SHUTTING_DOWN; CRefedPointerArray< CEventFilter > apEventFilters; hres = S_FALSE; if ( m_Bindings.GetEventFilters( apEventFilters ) ) { if ( apEventFilters.GetSize( ) > 0 ) { // // Convert to real event // IWbemClassObject* pEvent; HRESULT hr = Event.MakeWbemObject( this, &pEvent ); if( FAILED( hr ) ) { return hr; } CReleaseMe rm1( pEvent ); ULONG cEventSD; PBYTE pEventSD = (PBYTE)GetSD( pEvent, &cEventSD ); CEventContext Context; if ( pEventSD != NULL ) { if ( FALSE == Context.SetSD( cEventSD, pEventSD, TRUE ) ) { return WBEM_E_OUT_OF_MEMORY; } if ( !IsValidSecurityDescriptor( (PSECURITY_DESCRIPTOR)Context.GetSD() ) ) { return WBEM_E_INVALID_OBJECT; } } // // Fire all matching filters // for( int i = 0; i < apEventFilters.GetSize( ); ++i ) { CEventFilter* pEventFilter = apEventFilters[i]; hr = pEventFilter->Indicate( 1, &pEvent, &Context ); if ( FAILED( hr ) ) { return hr; } // // Return S_FALSE if all of the Indicates returns S_FALSE // if ( S_FALSE != hr ) { hres = S_OK; } } } } else { return E_FAIL; } return hres; } HRESULT CEssNamespace::RegisterNotificationSink( WBEM_CWSTR wszQueryLanguage, WBEM_CWSTR wszQuery, long lFlags, WMIMSG_QOS_FLAG lQosFlags, IWbemContext* pContext, IWbemObjectSink* pSink ) { HRESULT hres; // // Report the MSFT_WmiRegisterNotificationSink event. // FIRE_NCEVENT( g_hNCEvents[MSFT_WmiRegisterNotificationSink], WMI_SENDCOMMIT_SET_NOT_REQUIRED, // Data follows... (LPCWSTR) m_wszName, wszQueryLanguage, wszQuery, (DWORD64) pSink); DEBUGTRACE((LOG_ESS,"Registering notification sink with query %S in " "namespace %S.\n", wszQuery, m_wszName )); { ENSURE_INITIALIZED hres = InternalRegisterNotificationSink( wszQueryLanguage, wszQuery, lFlags, lQosFlags, pContext, pSink, FALSE, NULL ); } if(FAILED(hres)) { // Clean up and return FirePostponedOperations(); return hres; } // Filter and consumer are in place --- fire external operations // ============================================================= hres = FirePostponedOperations(); if(FAILED(hres)) { { CInUpdate iu(this); if ( m_eState == e_Shutdown ) return WBEM_E_SHUTTING_DOWN; InternalRemoveNotificationSink( pSink ); } // // need to make sure that we fire postponed here too. Remember that // we cannot hold the namespace lock when firing postponed ops. // FirePostponedOperations(); } else { InterlockedIncrement(&g_lNumTempSubscriptions); } return hres; } HRESULT CEssNamespace::InternalRegisterNotificationSink( WBEM_CWSTR wszQueryLanguage, WBEM_CWSTR wszQuery, long lFlags, WMIMSG_QOS_FLAG lQosFlags, IWbemContext* pContext, IWbemObjectSink* pSink, bool bInternal, PSID pOwnerSid ) { HRESULT hres; if(wbem_wcsicmp(wszQueryLanguage, L"WQL")) return WBEM_E_INVALID_QUERY_TYPE; LPWSTR wszConsumerKey = NULL; CVectorDeleteMe vdm2(&wszConsumerKey); wszConsumerKey = CTempConsumer::ComputeKeyFromSink(pSink); if ( NULL == wszConsumerKey ) { return WBEM_E_OUT_OF_MEMORY; } bool bInterNamespace = pOwnerSid != NULL; LPWSTR wszFilterKey = NULL; CVectorDeleteMe vdm1(&wszFilterKey); { // Create a new temporary filter and add it to the binding table // ============================================================= CTempFilter* pFilter = new CTempFilter(this); if(pFilter == NULL) return WBEM_E_OUT_OF_MEMORY; hres = pFilter->Initialize( wszQueryLanguage, wszQuery, lFlags, pOwnerSid, bInternal, pContext, pSink ); if(FAILED(hres)) { delete pFilter; return hres; } hres = m_Bindings.AddEventFilter(pFilter); if(FAILED(hres)) { delete pFilter; return hres; } wszFilterKey = pFilter->GetKey().CreateLPWSTRCopy(); if(wszFilterKey == NULL) return WBEM_E_OUT_OF_MEMORY; // Check if this sink has already been used by looking for it in the // binding table // ================================================================= CTempConsumer* pConsumer = NULL; if(FAILED(m_Bindings.FindEventConsumer(wszConsumerKey, NULL))) { // Create a new temporary consumer and add it to the table // ======================================================= pConsumer = _new CTempConsumer(this); if(pConsumer == NULL) return WBEM_E_OUT_OF_MEMORY; hres = pConsumer->Initialize( bInterNamespace, pSink); if(FAILED(hres)) return hres; hres = m_Bindings.AddEventConsumer(pConsumer); if(FAILED(hres)) { // Undo filter creation // ==================== m_Bindings.RemoveEventFilter(wszFilterKey); return hres; } } // Bind them together // ================== CBinding* pBinding = new CTempBinding( lFlags, lQosFlags, bInterNamespace ); if(pBinding == NULL) return WBEM_E_OUT_OF_MEMORY; pBinding->AddRef(); CReleaseMe rm1(pBinding); // // SPAGETTI WARNING: From this point on, we must flush the postponed // operation cache, or we may leak memory. But not before all the // CReleaseMe calls have fired. // hres = m_Bindings.Bind(wszFilterKey, wszConsumerKey, pBinding, NULL); // Check that the filter is active --- otherwise activatioin must have // failed. // =================================================================== if(SUCCEEDED(hres) && !pFilter->IsActive()) hres = pFilter->GetFilterError(); if(FAILED(hres)) { // // The core will deliver the SetStatus call to the consumer based // on the return code from the ESS. Since we are failing, we should // not call SetStatus ourselves. // if(pConsumer) pConsumer->Shutdown(true); // quiet m_Bindings.RemoveEventFilter(wszFilterKey); m_Bindings.RemoveEventConsumer(wszConsumerKey); } else { InterlockedIncrement(&g_lNumInternalTempSubscriptions); } } return hres; } HRESULT CEssNamespace::RemoveNotificationSink( IWbemObjectSink* pSink ) { // Fire a MSFT_WmiCancelNotificationSink if necessary. if (IS_NCEVENT_ACTIVE(MSFT_WmiCancelNotificationSink)) { LPWSTR wszConsumerKey = CTempConsumer::ComputeKeyFromSink(pSink); if (wszConsumerKey != NULL) { CVectorDeleteMe vdm0(wszConsumerKey); CInUpdate iu(this); // Find the consumer in question CEventConsumer *pConsumer = NULL; if (SUCCEEDED(m_Bindings.FindEventConsumer(wszConsumerKey, &pConsumer))) { CRefedPointerSmallArray apFilters; CReleaseMe rm1(pConsumer); // Make addrefed copies of all its associated filters if (SUCCEEDED(pConsumer->GetAssociatedFilters(apFilters)) && apFilters.GetSize()) { int nFilters = apFilters.GetSize(); LPWSTR wszQuery = NULL, wszQueryLanguage = NULL; BOOL bExact; apFilters[0]-> GetCoveringQuery(wszQueryLanguage, wszQuery, bExact, NULL); CVectorDeleteMe vdm1(wszQueryLanguage); CVectorDeleteMe vdm2(wszQuery); // // Report the MSFT_WmiRegisterNotificationSink event. // FIRE_NCEVENT( g_hNCEvents[MSFT_WmiCancelNotificationSink], WMI_SENDCOMMIT_SET_NOT_REQUIRED, // Data follows... (LPCWSTR) m_wszName, wszQueryLanguage, wszQuery, (DWORD64) pSink); } } } } HRESULT hres; { CInUpdate iu( this ); if ( m_eState == e_Shutdown ) { return WBEM_E_SHUTTING_DOWN; } hres = InternalRemoveNotificationSink( pSink ); } FirePostponedOperations(); if ( SUCCEEDED(hres) ) { InterlockedDecrement( &g_lNumTempSubscriptions ); } return hres; } HRESULT CEssNamespace::InternalRemoveNotificationSink(IWbemObjectSink* pSink) { HRESULT hres; LPWSTR wszKey = CTempConsumer::ComputeKeyFromSink(pSink); if(wszKey == NULL) return WBEM_E_OUT_OF_MEMORY; CVectorDeleteMe vdm1(wszKey); // Find the consumer container // =========================== hres = m_Bindings.RemoveConsumerWithFilters(wszKey); if(FAILED(hres)) return hres; else InterlockedDecrement( &g_lNumInternalTempSubscriptions ); return hres; } void CEssNamespace::FireNCFilterEvent(DWORD dwIndex, CEventFilter *pFilter) { if (IS_NCEVENT_ACTIVE(dwIndex)) { LPWSTR wszQuery = NULL; LPWSTR wszQueryLanguage = NULL; BOOL bExact; CWbemPtr pNamespace; GetFilterEventNamespace(pFilter, &pNamespace); // I'll assume we should use the current namespace if it's null. if (!pNamespace) pNamespace = this; pFilter->GetCoveringQuery(wszQueryLanguage, wszQuery, bExact, NULL); CVectorDeleteMe vdm1(wszQueryLanguage); CVectorDeleteMe vdm2(wszQuery); // // Report the event. // FIRE_NCEVENT( g_hNCEvents[dwIndex], WMI_SENDCOMMIT_SET_NOT_REQUIRED, // Data follows... pNamespace ? (LPCWSTR) pNamespace->GetName() : NULL, (LPCWSTR) (WString) pFilter->GetKey(), wszQueryLanguage, wszQuery); } } //***************************************************************************** // // Called by the filter when it notices that it has consumers. The filter is // guaranteed to be either valid or temporarily invalid and not active. It is // guaranteed that no more than 1 activation/deactivation can occur on the // same filter at the same time. // //***************************************************************************** HRESULT CEssNamespace::ActivateFilter(READ_ONLY CEventFilter* pFilter) { HRESULT hres, hresAttempt; hresAttempt = AttemptToActivateFilter(pFilter); if(FAILED(hresAttempt)) { pFilter->MarkAsTemporarilyInvalid(hresAttempt); // // We need to log an event about our inability to activate the filter // unless we shall report this failure to the caller. We can only // report this to the caller if the filter is being created (not // reactivated), and the caller is not using a force-mode // if(pFilter->DoesAllowInvalid() || pFilter->HasBeenValid()) { LPWSTR wszQuery = NULL; LPWSTR wszQueryLanguage = NULL; BOOL bExact; hres = pFilter->GetCoveringQuery( wszQueryLanguage, wszQuery, bExact, NULL); if(FAILED(hres)) return hres; CVectorDeleteMe vdm1(wszQueryLanguage); CVectorDeleteMe vdm2(wszQuery); // // Don't change this one: could be Nova customer dependencies // m_pEss->GetEventLog().Report( EVENTLOG_ERROR_TYPE, WBEM_MC_CANNOT_ACTIVATE_FILTER, m_wszName, wszQuery, (CHex)hresAttempt ); ERRORTRACE((LOG_ESS, "Could not activate filter %S in namespace " "%S. HR=0x%x\n", wszQuery, m_wszName, hresAttempt )); } } else { // // Report the MSFT_WmiFilterActivated event. // FireNCFilterEvent(MSFT_WmiFilterActivated, pFilter); pFilter->MarkAsValid(); } return hresAttempt; } //****************************************************************************** // // Worker for ActivateFilter --- does all the work but does not mark the filter // status // //****************************************************************************** HRESULT CEssNamespace::AttemptToActivateFilter(READ_ONLY CEventFilter* pFilter) { HRESULT hres = WBEM_S_NO_ERROR; // // Get the query information from the filter // LPWSTR wszQueryLanguage = NULL; LPWSTR wszQuery = NULL; BOOL bExact; QL_LEVEL_1_RPN_EXPRESSION* pExp = NULL; hres = pFilter->GetCoveringQuery(wszQueryLanguage, wszQuery, bExact, &pExp); if(FAILED(hres)) { WMIESS_REPORT((WMIESS_CANNOT_GET_FILTER_QUERY, m_wszName, pFilter)); return hres; } CVectorDeleteMe vdm1(wszQueryLanguage); CVectorDeleteMe vdm2(wszQuery); CDeleteMe dm1(pExp); if(!bExact) { // // We don't support inexact filter, nor do we have any now // return WBEM_E_NOT_SUPPORTED; } // // Check if the events are supposed to come from this namespace or some // other one. Cross-namespace filters are all we are interested in the // initialize phase, since we're going to reprocess normal filters // after loading provider registrations ( In CompleteInitialization() ) // CEssNamespace* pOtherNamespace = NULL; hres = GetFilterEventNamespace(pFilter, &pOtherNamespace); if(FAILED(hres)) return hres; if( pOtherNamespace ) { CTemplateReleaseMe rm0(pOtherNamespace); if ( m_bInResync ) { // // we don't need to do anything in the other namespace during // resync of this one, so no work to do here. Actually, since // resync doesn't do a deactivate, the registration is still there // so be careful of double registration if removing this check. // return WBEM_S_FALSE; } DEBUGTRACE((LOG_ESS,"Activating cross-namespace filter %p with query " "%S in namespace %S from namespace %S.\n", pFilter, wszQuery, pOtherNamespace->GetName(), m_wszName )); // // Register this notification sink with the other namespace, as // if it were a temporary consumer. Make the registration // synchronous, as whatever asynchronicity we need will be // provided by the ultimate consumer handling. This needs to be a // postponed operation though, else we could have a deadlock // scenario if at the same time cross namespace subscriptions // were registered in both namespaces. // // // BUGBUG: security propagation // CPostponedRegisterNotificationSinkRequest* pReq; pReq = new CPostponedRegisterNotificationSinkRequest; if ( pReq == NULL ) { return WBEM_E_OUT_OF_MEMORY; } hres = pReq->SetRegistration( pOtherNamespace, wszQueryLanguage, wszQuery, pFilter->GetForceFlags(), WMIMSG_FLAG_QOS_SYNCHRONOUS, pFilter->GetNonFilteringSink(), pFilter->GetOwner() ); if(FAILED(hres)) { return hres; } CPostponedList* pList = GetCurrentPostponedList(); _DBG_ASSERT( pList != NULL ); hres = pList->AddRequest( this, pReq ); if ( FAILED(hres) ) { return hres; } return WBEM_S_NO_ERROR; } else if ( m_bStage1Complete ) { // // Filter is being activated in this namespace. We must avoid // processing filters before we're fully initialized. This can // happen when one namespace is initializing its cross namespace // subscription to one that is still initializing. We do not process // filters before we're initialized because (1) we are not allowed to // access class providers during stage1 init and (2) we're going to // resync everything anyways during stage2 init. // DEBUGTRACE((LOG_ESS,"Activating filter %p with query %S " "in namespace %S.\n", pFilter, wszQuery, m_wszName )); // Retrieve its non-filtering sink // =============================== CAbstractEventSink* pNonFilter = pFilter->GetNonFilteringSink(); if(pNonFilter == NULL) return WBEM_E_OUT_OF_MEMORY; // // Register for class modification events of relevance for this filter // hres = RegisterFilterForAllClassChanges(pFilter, pExp); if(FAILED(hres)) { ERRORTRACE((LOG_ESS,"Unable to register for class changes related " "to filter %S in namespace %S: 0x%x\n", wszQuery, GetName(), hres)); return hres; } // // Prepare filter for action // hres = pFilter->GetReady(wszQuery, pExp); if( SUCCEEDED(hres) ) { // // Register it in the core tables // hres = m_EventProviderCache.LoadProvidersForQuery(wszQuery, pExp, pNonFilter); if(SUCCEEDED(hres)) { hres = m_Poller.ActivateFilter(pFilter, wszQuery, pExp); if(FAILED(hres)) { // Need to deactivate providers // ============================ m_EventProviderCache.ReleaseProvidersForQuery( pNonFilter); } } } } if(FAILED(hres)) { // // Keep this filter registered for its class change events, as one of // them could make it valid! // } return hres; } //***************************************************************************** // // Retrieves the namespace pointer for the event namespace for this filter. // If current, returns NULL. // //***************************************************************************** HRESULT CEssNamespace::GetFilterEventNamespace(CEventFilter* pFilter, RELEASE_ME CEssNamespace** ppNamespace) { HRESULT hres; *ppNamespace = NULL; LPWSTR wszNamespace = NULL; hres = pFilter->GetEventNamespace(&wszNamespace); if(FAILED(hres)) { WMIESS_REPORT((WMIESS_INVALID_FILTER_NAMESPACE, m_wszName, pFilter, wszNamespace)); return hres; } CVectorDeleteMe vdm0(wszNamespace); if(wszNamespace && wbem_wcsicmp(wszNamespace, m_wszName)) { // // Different namespace: Find it in the list. // hres = m_pEss->GetNamespaceObject( wszNamespace, TRUE, ppNamespace ); if(FAILED(hres)) { WMIESS_REPORT((WMIESS_CANNOT_OPEN_FILTER_NAMESPACE, m_wszName, pFilter, wszNamespace)); return hres; } // // Check if we got back our current namespace --- could happen if the // spelling is different, etc // if(*ppNamespace == this) { (*ppNamespace)->Release(); *ppNamespace = NULL; } return S_OK; } else { // Same namespace *ppNamespace = NULL; return S_OK; } } HRESULT CEssNamespace::RegisterFilterForAllClassChanges(CEventFilter* pFilter, QL_LEVEL_1_RPN_EXPRESSION* pExpr) { HRESULT hres; // // Do nothing for class operation filters. They simply serve as their own // "class change" filters // if(!wbem_wcsicmp(pExpr->bsClassName, L"__ClassOperationEvent") || !wbem_wcsicmp(pExpr->bsClassName, L"__ClassCreationEvent") || !wbem_wcsicmp(pExpr->bsClassName, L"__ClassDeletionEvent") || !wbem_wcsicmp(pExpr->bsClassName, L"__ClassModificationEvent")) { pFilter->MarkReconstructOnHit(); return WBEM_S_NO_ERROR; } // // get the sink for class change notifications. // IWbemObjectSink* pClassChangeSink = pFilter->GetClassChangeSink(); // NOREF _DBG_ASSERT( pClassChangeSink != NULL ); // // since the class change sink will be modifying internal namespace // structures, we must wrap with an internal operations sink. This is so // the thread that performs the indicate will be guaranteed to have a // valid thread object associated with it. // CWbemPtr pInternalOpSink; pInternalOpSink = new CEssInternalOperationSink( pClassChangeSink ); if ( pInternalOpSink == NULL ) { return WBEM_E_OUT_OF_MEMORY; } // // store the new sink with the filter because we need it later to unreg // CWbemPtr pOldInternalOpSink; hres = pFilter->SetActualClassChangeSink( pInternalOpSink, &pOldInternalOpSink ); if ( FAILED(hres) ) { return hres; } _DBG_ASSERT( pOldInternalOpSink == NULL ); return RegisterSinkForAllClassChanges( pInternalOpSink, pExpr ); } HRESULT CEssNamespace::RegisterSinkForAllClassChanges(IWbemObjectSink* pSink, QL_LEVEL_1_RPN_EXPRESSION* pExpr) { HRESULT hres; // // First of all, the class we are looking for is of interest // hres = RegisterSinkForClassChanges(pSink, pExpr->bsClassName); if(FAILED(hres)) return hres; // // Now, iterate over all the tokens looking for ISAs. We need those classes // too. // for(int i = 0; i < pExpr->nNumTokens; i++) { QL_LEVEL_1_TOKEN* pToken = pExpr->pArrayOfTokens + i; if(pToken->nTokenType == QL1_OP_EXPRESSION && (pToken->nOperator == QL1_OPERATOR_ISA || pToken->nOperator == QL1_OPERATOR_ISNOTA) && V_VT(&pToken->vConstValue) == VT_BSTR) { hres = RegisterSinkForClassChanges(pSink, V_BSTR(&pToken->vConstValue)); if(FAILED(hres)) { UnregisterSinkFromAllClassChanges(pSink); return hres; } } } // Somehow need to keep this filter subscribed to various events until all // the classes show up return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::RegisterSinkForClassChanges(IWbemObjectSink* pSink, LPCWSTR wszClassName) { // // Do not register for changes to system classes --- they do not change! // if(wszClassName[0] == L'_') { return WBEM_S_NO_ERROR; } // // Just issue the appropriate query against the namespace. The filter // will know what to do when called // DWORD cLen = wcslen(wszClassName) + 100; LPWSTR wszQuery = new WCHAR[cLen]; if ( wszQuery == NULL ) { return WBEM_E_OUT_OF_MEMORY; } StringCchPrintfW( wszQuery, cLen, L"select * from __ClassOperationEvent where " L"TargetClass isa \"%s\"", wszClassName ); CVectorDeleteMe vdm( wszQuery ); return InternalRegisterNotificationSink(L"WQL", wszQuery, 0, WMIMSG_FLAG_QOS_SYNCHRONOUS, GetCurrentEssContext(), pSink, true, NULL ); } HRESULT CEssNamespace::RegisterProviderForClassChanges( LPCWSTR wszClassName, LPCWSTR wszProvName ) { try { CInCritSec ics(&m_csLevel1); m_mapProviderInterestClasses[wszClassName].insert( wszProvName ); } catch(CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } return S_OK; } HRESULT CEssNamespace::UnregisterFilterFromAllClassChanges( CEventFilter* pFilter) { HRESULT hres; // // unbind the filter from the actual class change sink and use it to unreg // CWbemPtr pActualClassChangeSink; hres = pFilter->SetActualClassChangeSink( NULL, &pActualClassChangeSink ); if ( FAILED(hres) ) { return hres; } if ( pActualClassChangeSink != NULL ) { hres = UnregisterSinkFromAllClassChanges( pActualClassChangeSink ); } return hres; } HRESULT CEssNamespace::UnregisterSinkFromAllClassChanges( IWbemObjectSink* pSink) { return InternalRemoveNotificationSink(pSink); } HRESULT CEssNamespace::DeactivateFilter( READ_ONLY CEventFilter* pFilter ) { HRESULT hres; DEBUGTRACE((LOG_ESS,"Deactivating filter %p\n", pFilter )); HRESULT hresGlobal = WBEM_S_NO_ERROR; // // Check if the events are supposed to come from this namespace or some // other one. // CEssNamespace* pOtherNamespace = NULL; hres = GetFilterEventNamespace(pFilter, &pOtherNamespace); if(FAILED(hres)) return hres; if( pOtherNamespace ) { CTemplateReleaseMe rm0(pOtherNamespace); // // Unregister this notification sink with the other namespace, // as if it were a temporary consumer. This needs to be a // postponed operation though, else we could have a deadlock // scenario if at the same time cross namespace subscriptions // were registered in both namespaces. // CPostponedRemoveNotificationSinkRequest* pReq; pReq = new CPostponedRemoveNotificationSinkRequest( pOtherNamespace, pFilter->GetNonFilteringSink() ); if ( pReq == NULL ) { return WBEM_E_OUT_OF_MEMORY; } CPostponedList* pList = GetCurrentPostponedList(); _DBG_ASSERT( pList != NULL ); hres = pList->AddRequest( this, pReq ); if ( FAILED(hres) ) { delete pReq; return hres; } return WBEM_S_NO_ERROR; } else { // // Current namespace --- unregister for real // // Retrieve its non-filtering sink // =============================== CAbstractEventSink* pNonFilter = pFilter->GetNonFilteringSink(); if(pNonFilter == NULL) return WBEM_E_OUT_OF_MEMORY; // // Report the MSFT_WmiFilterDeactivated event. // FireNCFilterEvent(MSFT_WmiFilterDeactivated, pFilter); // // Unregister it from class change notifications // hres = UnregisterFilterFromAllClassChanges(pFilter); if(FAILED(hres)) hresGlobal = hres; // Deactivate in providers, poller, and static search // ================================================== hres = m_EventProviderCache.ReleaseProvidersForQuery(pNonFilter); if(FAILED(hres)) hresGlobal = hres; hres = m_Poller.DeactivateFilter(pFilter); if(FAILED(hres)) hresGlobal = hres; pFilter->SetInactive(); return hres; } } HRESULT CEssNamespace::HandleClassCreation( LPCWSTR wszClassName, IWbemClassObject* pClass) { // // Check if this is a class that a provider is waiting for. // ProviderSet setProviders; { CInCritSec ics( &m_csLevel1 ); ClassToProviderMap::iterator it; it = m_mapProviderInterestClasses.find( wszClassName ); if ( it != m_mapProviderInterestClasses.end() ) { // // copy the interested provider list. // setProviders = it->second; // // remove the entry from the map. // m_mapProviderInterestClasses.erase( it ); } } if ( setProviders.size() > 0 ) { // // reload interested providers. // DEBUGTRACE((LOG_ESS,"Reloading some providers in namespace %S due to " "creation of %S class\n", m_wszName, wszClassName )); ProviderSet::iterator itProv; for( itProv=setProviders.begin(); itProv!=setProviders.end(); itProv++) { ReloadProvider( 0, *itProv ); } } return S_OK; } //***************************************************************************** // // Updates internal structures to reflect a change to this class. Assumes that // the namespace is already locked. // Very few errors are reported from this function, since class changes cannot // be vetoed. // //***************************************************************************** HRESULT CEssNamespace::HandleClassChange(LPCWSTR wszClassName, IWbemClassObject* pClass) { // Check if the class in question is an event consumer class // ========================================================= if(pClass->InheritsFrom(CONSUMER_CLASS) == S_OK) { CInUpdate iu(this); if ( IsShutdown() ) return WBEM_E_SHUTTING_DOWN; HandleConsumerClassDeletion(wszClassName); } return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::HandleConsumerClassDeletion(LPCWSTR wszClassName) { // There are two varieties: non-singleton and singleton // ==================================================== DWORD cLen = wcslen(wszClassName) + 2; LPWSTR wszPrefix = new WCHAR[cLen]; if(wszPrefix == NULL) return WBEM_E_OUT_OF_MEMORY; CVectorDeleteMe vdm( wszPrefix ); StringCchPrintfW(wszPrefix, cLen, L"%s.", wszClassName); m_Bindings.RemoveConsumersStartingWith(wszPrefix); StringCchPrintfW(wszPrefix, cLen, L"%s=", wszClassName); m_Bindings.RemoveConsumersStartingWith(wszPrefix); return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::ReloadProvider( long lFlags, LPCWSTR wszProvider ) { HRESULT hres; WString wsRelpath; // // we only have to do this for event providers. Check to see if // we know about this try to see if we even have any event providers to reload ... // try { wsRelpath = L"__Win32Provider.Name='"; wsRelpath += wszProvider; wsRelpath += L"'"; } catch( CX_MemoryException ) { return WBEM_E_OUT_OF_MEMORY; } CWbemPtr<_IWmiObject> pObj; hres = GetInstance( wsRelpath, &pObj ); if ( SUCCEEDED(hres) ) { { ENSURE_INITIALIZED CInResync ir(this); // // note : in case of reloading event provider due to notification // from provss, we only need to handle event providers since // consumer providers already have a reloading mechanism. // m_EventProviderCache.RemoveProvider(pObj); hres = AddProvider( pObj ); ir.Commit(); } if ( SUCCEEDED(hres) ) { hres = FirePostponedOperations(); } else { FirePostponedOperations(); } } return hres; } HRESULT CEssNamespace::ReloadProvider(IWbemClassObject* pProvObjTemplate) { HRESULT hres; LogOp( L"ReloadProvider", pProvObjTemplate ); ENSURE_INITIALIZED CInResync ir(this); // Start by deleting this provider from our records, if there // ========================================================== hres = RemoveProvider(pProvObjTemplate); if(FAILED(hres)) return hres; // Determine the current state of this provider in the database // ============================================================ IWbemClassObject* pProvObj = NULL; hres = GetCurrentState(pProvObjTemplate, &pProvObj); if(FAILED(hres)) return hres; if(pProvObj == NULL) { // The provider has been deleted --- no further action is needed // ============================================================= return S_OK; } CReleaseMe rm1(pProvObj); // Now create it if necessary // ========================== hres = AddProvider(pProvObj); if(FAILED(hres)) return hres; ir.Commit(); return hres; } HRESULT CEssNamespace::ReloadEventProviderRegistration( IWbemClassObject* pProvRegObjTemplate) { HRESULT hres; LogOp( L"ReloadEventProviderRegistration", pProvRegObjTemplate ); ENSURE_INITIALIZED CInResync ir(this); // Start by deleting this provider from our records, if there // ========================================================== hres = RemoveEventProviderRegistration(pProvRegObjTemplate); if(FAILED(hres)) return hres; // Determine the current state of this registration in the database // ================================================================ IWbemClassObject* pProvRegObj = NULL; hres = GetCurrentState(pProvRegObjTemplate, &pProvRegObj); if(FAILED(hres)) return hres; if(pProvRegObj == NULL) { // The registration has been deleted --- no further action is needed // ================================================================= return S_OK; } CReleaseMe rm1(pProvRegObj); // Now create it if necessary // ========================== hres = AddEventProviderRegistration(pProvRegObj); if(FAILED(hres)) return hres; ir.Commit(); return hres; } HRESULT CEssNamespace::ReloadConsumerProviderRegistration( IWbemClassObject* pProvRegObjTemplate) { CInUpdate iu(this); // Reset consumer provider info in all the consumers using this consumer // provider. That's all we need to do --- they will simply pick up the new // data on next delivery. We don't even need to get the current version, // since all we need is the key // ======================================================================== return RemoveConsumerProviderRegistration(pProvRegObjTemplate); } //***************************************************************************** // // Assumes that the namespace is locked and PrepareForResync has been called // Adds this provider to the records. Expects ReactivateAllFilters and // CommitResync to be called later // //***************************************************************************** HRESULT CEssNamespace::AddProvider(READ_ONLY IWbemClassObject* pProv) { HRESULT hres; hres = m_EventProviderCache.AddProvider(pProv); return hres; } HRESULT CEssNamespace::CheckEventProviderRegistration(IWbemClassObject* pReg) { HRESULT hres; ENSURE_INITIALIZED hres = m_EventProviderCache.CheckProviderRegistration(pReg); return hres; } HRESULT CEssNamespace::CheckTimerInstruction(IWbemClassObject* pInst) { HRESULT hres; ENSURE_INITIALIZED hres = GetTimerGenerator().CheckTimerInstruction(pInst); return hres; } //***************************************************************************** // // Assumes that the namespace is locked and PrepareForResync has been called // Adds this event provider registration to the records. Expects // ReactivateAllFilters and CommitResync to be called later // //***************************************************************************** HRESULT CEssNamespace::AddEventProviderRegistration( IWbemClassObject* pReg) { HRESULT hres; hres = m_EventProviderCache.AddProviderRegistration(pReg); return hres; } //***************************************************************************** // // Assumes that the namespace is locked and PrepareForResync has been called // Removes this provider from the records. Expects ReactivateAllFilters and // CommitResync to be called later // //***************************************************************************** HRESULT CEssNamespace::RemoveProvider(READ_ONLY IWbemClassObject* pProv) { HRESULT hres; // Handle event consumer providers // =============================== IWbemClassObject* pConsProvReg; hres = m_ConsumerProviderCache. GetConsumerProviderRegFromProviderReg(pProv, &pConsProvReg); if(SUCCEEDED(hres)) { RemoveConsumerProviderRegistration(pConsProvReg); pConsProvReg->Release(); } // Handle event providers // ====================== hres = m_EventProviderCache.RemoveProvider(pProv); return hres; } //***************************************************************************** // // Assumes that the namespace is locked and PrepareForResync has been called // Adds this event provider registration to the records. Expects // ReactivateAllFilters and CommitResync to be called later // //***************************************************************************** HRESULT CEssNamespace::RemoveEventProviderRegistration( READ_ONLY IWbemClassObject* pReg) { HRESULT hres; hres = m_EventProviderCache.RemoveProviderRegistration(pReg); return hres; } DWORD CEssNamespace::GetProvidedEventMask(IWbemClassObject* pClass) { return m_EventProviderCache.GetProvidedEventMask(pClass); } //***************************************************************************** // // This function is called before a major update to the records. Without any // calls to external components, it "deactivates" all the filters, in a sense // that when all of them are "reactivated", the system will arrive in a // consistent state (usage counts, etc). CommitResync will then perform any // necessary activations/deactivations based on the new state // //***************************************************************************** HRESULT CEssNamespace::PrepareForResync() { m_bInResync = TRUE; // Ask the poller to "virtually" stop all polling instructions, without // actually stopping them physically // ==================================================================== m_Poller.VirtuallyStopPolling(); // Ask provider cache to "virtually" release all its providers, without // actually releasing them physically // ==================================================================== m_EventProviderCache.VirtuallyReleaseProviders(); // Ask core search to mark all filters so that it would know which ones are // gone after the resync // ======================================================================== DEBUGTRACE((LOG_ESS,"Prepared resync in namespace %S\n", m_wszName )); return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::ReactivateAllFilters() { DEBUGTRACE((LOG_ESS,"Reactivating all filters in namespace %S\n", m_wszName )); return m_Bindings.ReactivateAllFilters(); } HRESULT CEssNamespace::CommitResync() { m_bInResync = FALSE; // Tell provider cache to perform all the loadings and unloadings it // needs to perform based on the new data // ================================================================= m_EventProviderCache.CommitProviderUsage(); // Tell the poller to cancel unnecessary instructions // ================================================== m_Poller.CancelUnnecessaryPolling(); DEBUGTRACE((LOG_ESS,"Committed resync in namespace %S\n", m_wszName )); return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::RemoveConsumerProviderRegistration( IWbemClassObject* pReg) { // Get the name of the consumer provider being deleteed // ==================================================== BSTR strProvRef = CConsumerProviderCache::GetProviderRefFromRecord(pReg); if(strProvRef == NULL) { ERRORTRACE((LOG_ESS, "Invalid consumer provider record is being deleted" "\n")); return WBEM_S_FALSE; } CSysFreeMe sfm1(strProvRef); // Reset it in all the consumers // ============================= m_Bindings.ResetProviderRecords(strProvRef); // Remove it from the cache // ======================== m_ConsumerProviderCache.RemoveConsumerProvider(strProvRef); return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::ScheduleDelivery(CQueueingEventSink* pDest) { return m_pEss->EnqueueDeliver(pDest); } HRESULT CEssNamespace::DecorateObject(IWbemClassObject* pObj) { return m_pEss->DecorateObject(pObj, m_wszName); } HRESULT CEssNamespace::EnsureConsumerWatchInstruction() { return m_Bindings.EnsureConsumerWatchInstruction(); } HRESULT CEssNamespace::AddSleepCharge(DWORD dwSleep) { return m_pEss->AddSleepCharge(dwSleep); } HRESULT CEssNamespace::AddCache() { return m_pEss->AddCache(); } HRESULT CEssNamespace::RemoveCache() { return m_pEss->RemoveCache(); } HRESULT CEssNamespace::AddToCache(DWORD dwAdd, DWORD dwMemberTotal, DWORD* pdwSleep) { return m_pEss->AddToCache(dwAdd, dwMemberTotal, pdwSleep); } HRESULT CEssNamespace::RemoveFromCache(DWORD dwRemove) { return m_pEss->RemoveFromCache(dwRemove); } HRESULT CEssNamespace::PerformSubscriptionInitialization() { HRESULT hres; DWORD dwRead; // // must use repository only svc ptr here, else we can deadlock when // class providers try to call back in. // // Enumerator all EventFilters // =========================== CFilterEnumSink* pFilterSink = new CFilterEnumSink(this); if ( NULL == pFilterSink ) { return WBEM_E_OUT_OF_MEMORY; } pFilterSink->AddRef(); m_pInternalCoreSvc->InternalCreateInstanceEnum( EVENT_FILTER_CLASS, 0, pFilterSink); pFilterSink->ReleaseAndWait(); // Enumerator all consumers // ======================== CConsumerEnumSink* pConsumerSink = new CConsumerEnumSink(this); if ( NULL == pConsumerSink ) { return WBEM_E_OUT_OF_MEMORY; } pConsumerSink->AddRef(); m_pInternalCoreSvc->InternalCreateInstanceEnum( CONSUMER_CLASS, 0, pConsumerSink); pConsumerSink->ReleaseAndWait(); // Enumerator all bindings // ======================= CBindingEnumSink* pBindingSink = new CBindingEnumSink(this); if ( NULL == pBindingSink ) { return WBEM_E_OUT_OF_MEMORY; } pBindingSink->AddRef(); m_pInternalCoreSvc->InternalCreateInstanceEnum( BINDING_CLASS, 0, pBindingSink); pBindingSink->ReleaseAndWait(); return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::PerformProviderInitialization() { HRESULT hres; DWORD dwRead; // // make sure that we resync all subscriptions after we've processed // provider objs // CInResync ir( this ); // // Enumerate all the providers // IEnumWbemClassObject* penumProvs; hres = m_pCoreSvc->CreateInstanceEnum( CWbemBSTR( PROVIDER_CLASS ), WBEM_FLAG_DEEP, GetCurrentEssContext(), &penumProvs ); if ( SUCCEEDED(hres) ) { CReleaseMe rm1(penumProvs); // Add them all to ESS // =================== IWbemClassObject* pProvObj; while((hres=penumProvs->Next(INFINITE, 1, &pProvObj, &dwRead)) == S_OK) { hres = AddProvider(pProvObj); pProvObj->Release(); if(FAILED(hres)) { // Already logged. } } } if ( FAILED(hres) ) { ERRORTRACE((LOG_ESS, "Error 0x%X occurred enumerating event providers " "in namespace %S. Some event providers may not be active\n", hres, m_wszName)); } // // Enumerate all the provider registrations // IEnumWbemClassObject* penumRegs; hres = m_pCoreSvc->CreateInstanceEnum( CWbemBSTR( EVENT_PROVIDER_REGISTRATION_CLASS ), WBEM_FLAG_DEEP, GetCurrentEssContext(), &penumRegs); if ( SUCCEEDED(hres) ) { CReleaseMe rm2(penumRegs); // Add them all to ESS // =================== IWbemClassObject* pRegObj; while((hres = penumRegs->Next(INFINITE, 1, &pRegObj, &dwRead)) == S_OK) { hres = AddEventProviderRegistration(pRegObj); pRegObj->Release(); if(FAILED(hres)) { // Already logged } } } if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Error 0x%X occurred enumerating event providers " "registrations in namespace %S. " "Some event providers may not be active\n", hres, m_wszName)); } // // Create and initialize the core provider. // CWbemPtr pCoreEventProvider = new CCoreEventProvider; if ( pCoreEventProvider != NULL ) { hres = pCoreEventProvider->SetNamespace(this); if ( SUCCEEDED(hres) ) { LPCWSTR awszQuery[5] = { L"select * from __InstanceOperationEvent", L"select * from __ClassOperationEvent", L"select * from __NamespaceOperationEvent", L"select * from __SystemEvent", L"select * from __TimerEvent" }; hres = m_EventProviderCache.AddSystemProvider(pCoreEventProvider, L"$Core", 5, awszQuery ); } } else { hres = WBEM_E_OUT_OF_MEMORY; } if ( SUCCEEDED(hres) ) { pCoreEventProvider->AddRef(); m_pCoreEventProvider = pCoreEventProvider; } else { ERRORTRACE((LOG_ESS, "Core event provider cannot initialize due " "to critical errors. HR=0x%x\n", hres)); } // Initialize timer generator // ========================== hres = InitializeTimerGenerator(); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Error 0x%X occurred initializing the timer " "in namespace %S. Some timer instructions may not be active\n", hres, m_wszName)); } ir.Commit(); return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::InitializeTimerGenerator() { return m_pEss->InitializeTimerGenerator( m_wszName, m_pCoreSvc ); } HRESULT CEssNamespace::ScheduleFirePostponed() { // // Save and detach the current thread object --- we need to pass it to the // other thread, as well as make sure than nobody else fires our postponed // operations! // CEssThreadObject* pThreadObj = GetCurrentEssThreadObject(); ClearCurrentEssThreadObject(); SetCurrentEssThreadObject(NULL); if ( GetCurrentEssThreadObject() == NULL ) { SetConstructedEssThreadObject( pThreadObj ); return WBEM_E_OUT_OF_MEMORY; } CFirePostponed* pReq = new CFirePostponed(this, pThreadObj); if(pReq == NULL) { SetConstructedEssThreadObject( pThreadObj ); return WBEM_E_OUT_OF_MEMORY; } HRESULT hr = m_pEss->Enqueue(pReq); if (FAILED(hr)) delete pReq; return hr; } HRESULT CEssNamespace::FirePostponedOperations() { IWbemContext *pContext = GetCurrentEssContext( ); VARIANT vValue; HRESULT hr; do { if ( NULL == pContext ) { break; } hr = pContext->GetValue( L"__ReentranceTestProp", 0, &vValue ); if ( WBEM_E_NOT_FOUND == hr ) { break; } if ( FAILED( hr ) ) { return hr; } if ( VARIANT_TRUE == V_BOOL( &vValue ) ) { // // Reentrance // hr = pContext->DeleteValue( L"__ReentranceTestProp", 0 ); if ( FAILED( hr ) ) { return hr; } ScheduleFirePostponed( ); return S_OK; } } while( FALSE ); HRESULT hrReturn = WBEM_S_NO_ERROR; // // Update lock cannot be held when calling this function and there // are operations to execute. // _DBG_ASSERT( !DoesThreadOwnNamespaceLock() ); // // execute both primary and event postponed ops until empty. // CPostponedList* pList = GetCurrentPostponedList(); CPostponedList* pEventList = GetCurrentPostponedEventList(); do { // // execute the primary postponed ops. // if( pList != NULL ) { hr = pList->Execute(this, CPostponedList::e_ReturnOneError); if ( SUCCEEDED(hrReturn) ) { hrReturn = hr; } } // // now execute postponed events // if ( pEventList != NULL ) { hr = pEventList->Execute(this, CPostponedList::e_ReturnOneError); if ( SUCCEEDED(hrReturn) ) { hrReturn = hr; } } } while( pList != NULL && !pList->IsEmpty() ); return hrReturn; } HRESULT CEssNamespace::PostponeRelease(IUnknown* pUnk) { CPostponedList* pList = GetCurrentPostponedList(); if(pList == NULL) { // // Just execute it // pUnk->Release(); return WBEM_S_NO_ERROR; } CPostponedReleaseRequest* pReq = new CPostponedReleaseRequest(pUnk); if(pReq == NULL) return WBEM_E_OUT_OF_MEMORY; // // this is a namespace agnostic postponed request, so specify null. // return pList->AddRequest( NULL, pReq ); } HRESULT CEssNamespace::GetProviderNamespacePointer(IWbemServices** ppServices) { IWbemServices* pServices = NULL; HRESULT hres = m_pEss->GetNamespacePointer(m_wszName, FALSE, &pServices); if(FAILED(hres)) return hres; *ppServices = pServices; return WBEM_S_NO_ERROR; } void CEssNamespace::IncrementObjectCount() { m_pEss->IncrementObjectCount(); } void CEssNamespace::DecrementObjectCount() { m_pEss->DecrementObjectCount(); } HRESULT CEssNamespace::LockForUpdate() { m_csLevel2.Enter(); return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::UnlockForUpdate() { m_ClassCache.Clear(); m_csLevel2.Leave(); return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::GetCurrentState( IWbemClassObject* pTemplate, IWbemClassObject** ppObj) { HRESULT hres; *ppObj = NULL; // Retrieve the path // ================= VARIANT vPath; hres = pTemplate->Get(L"__RELPATH", 0, &vPath, NULL, NULL); if(FAILED(hres)) return hres; CClearMe cm1(&vPath); if(V_VT(&vPath) != VT_BSTR) return WBEM_E_INVALID_OBJECT; // Get it from the namespace // ========================= _IWmiObject* pObj; hres = GetInstance( V_BSTR(&vPath), &pObj ); if( hres == WBEM_E_NOT_FOUND ) return WBEM_S_FALSE; *ppObj = pObj; return hres; } CWinMgmtTimerGenerator& CEssNamespace::GetTimerGenerator() { return m_pEss->GetTimerGenerator(); } HRESULT CEssNamespace::RaiseErrorEvent(IWbemEvent* pEvent, BOOL bAdminOnly ) { CEventRepresentation Event; Event.type = e_EventTypeSystem; Event.nObjects = 1; Event.apObjects = &pEvent; HRESULT hres; hres = SignalEvent( Event, 0, bAdminOnly ); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Event subsystem was unable to deliver an " "error event to some consumers (%X)\n", hres)); } return S_OK; } HRESULT CEssNamespace::GetClassFromCore( LPCWSTR wszClassName, _IWmiObject** ppClass ) { HRESULT hres; CWbemPtr pClass; *ppClass = NULL; // // want to ensure that we don't use the full service ptr until we've // completed stage 1 initialization. Reason is that we don't want to // load class providers until the second stage of initialization. // _DBG_ASSERT( m_bStage1Complete ); // // must use full service because will need to support dynamic classes. // hres = m_pInternalFullSvc->InternalGetClass( wszClassName, &pClass ); if ( FAILED(hres) ) { return hres; } return pClass->QueryInterface( IID__IWmiObject, (void**)ppClass ); } HRESULT CEssNamespace::GetInstance( LPCWSTR wszPath, _IWmiObject** ppInstance ) { HRESULT hres; CWbemPtr pInstance; *ppInstance = NULL; hres = m_pInternalCoreSvc->InternalGetInstance( wszPath, &pInstance ); if ( FAILED(hres) ) { return hres; } return pInstance->QueryInterface( IID__IWmiObject, (void**)ppInstance ); } HRESULT CEssNamespace::GetDbInstance( LPCWSTR wszDbKey, _IWmiObject** ppInstance) { HRESULT hres; CWbemPtr pInstance; *ppInstance = NULL; hres = m_pInternalCoreSvc->GetDbInstance( wszDbKey, &pInstance ); if ( FAILED(hres) ) { return hres; } return pInstance->QueryInterface( IID__IWmiObject, (void**)ppInstance ); } HRESULT CEssNamespace::CreateInstanceEnum(LPCWSTR wszClass, long lFlags, IWbemObjectSink* pSink) { return m_pInternalCoreSvc->InternalCreateInstanceEnum(wszClass, lFlags, pSink); } HRESULT CEssNamespace::ExecQuery(LPCWSTR wszQuery, long lFlags, IWbemObjectSink* pSink) { return m_pInternalCoreSvc->InternalExecQuery(L"WQL", wszQuery, lFlags, pSink); } HRESULT CEssNamespace::GetToken(PSID pSid, IWbemToken** ppToken) { return m_pEss->GetToken(pSid, ppToken); } void CEssNamespace::DumpStatistics(FILE* f, long lFlags) { CInUpdate iu(this); fprintf(f, "------- Namespace '%S' ----------\n", m_wszName); m_Bindings.DumpStatistics(f, lFlags); m_ConsumerProviderCache.DumpStatistics(f, lFlags); m_EventProviderCache.DumpStatistics(f, lFlags); m_Poller.DumpStatistics(f, lFlags); } HRESULT CEssMetaData::GetClass( LPCWSTR wszName, IWbemContext* pContext, _IWmiObject** ppClass) { return m_pNamespace->m_ClassCache.GetClass(wszName, pContext, ppClass); } STDMETHODIMP CEssNamespace::CConsumerClassDeletionSink::Indicate( long lNumObjects, IWbemClassObject** apObjects) { HRESULT hres; for(long i = 0; i < lNumObjects; i++) { _IWmiObject* pEvent = NULL; apObjects[i]->QueryInterface(IID__IWmiObject, (void**)&pEvent); CReleaseMe rm1(pEvent); // // Get the class name of the class being deleted // VARIANT vObj; hres = pEvent->Get(L"TargetClass", 0, &vObj, NULL, NULL); if(SUCCEEDED(hres)) { CClearMe cm1(&vObj); IWbemClassObject* pClass; V_UNKNOWN(&vObj)->QueryInterface(IID_IWbemClassObject, (void**)&pClass); CReleaseMe rm2(pClass); VARIANT vClass; hres = pClass->Get(L"__CLASS", 0, &vClass, NULL, NULL); if(SUCCEEDED(hres)) { CClearMe cm(&vClass); m_pOuter->HandleConsumerClassDeletion(V_BSTR(&vClass)); } } } return WBEM_S_NO_ERROR; } HRESULT CEssNamespace::LoadEventProvider(LPCWSTR wszProviderName, IWbemEventProvider** ppProv) { HRESULT hres; *ppProv = NULL; // // Get provider pointer from the provider subsystem // if(m_pProviderFactory == NULL) return WBEM_E_CRITICAL_ERROR; WmiInternalContext t_InternalContext ; ZeroMemory ( & t_InternalContext , sizeof ( t_InternalContext ) ) ; hres = m_pProviderFactory->GetProvider( t_InternalContext , 0, // lFlags GetCurrentEssContext(), 0, NULL, NULL, 0, wszProviderName, IID_IWbemEventProvider, (LPVOID *) ppProv ); return hres; } HRESULT CEssNamespace::LoadConsumerProvider(LPCWSTR wszProviderName, IUnknown** ppProv) { HRESULT hres; *ppProv = NULL; // // Get provider pointer from the provider subsystem // if(m_pProviderFactory == NULL) return WBEM_E_CRITICAL_ERROR; WmiInternalContext t_InternalContext ; ZeroMemory ( & t_InternalContext , sizeof ( t_InternalContext ) ) ; hres = m_pProviderFactory->GetProvider( t_InternalContext , 0, // lFlags GetCurrentEssContext(), 0, NULL, NULL, 0, wszProviderName, IID_IUnknown, (LPVOID *) ppProv ); return hres; }