You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4391 lines
121 KiB
4391 lines
121 KiB
|
|
//=============================================================================
|
|
//
|
|
// Copyright (c) 1996-1999, Microsoft Corporation, All rights reserved
|
|
//
|
|
// NSREP.CPP
|
|
//
|
|
// See nsrep.h for documentation
|
|
//
|
|
// History:
|
|
//
|
|
//=============================================================================
|
|
|
|
#include "precomp.h"
|
|
#include <stdio.h>
|
|
#include "ess.h"
|
|
#include "esssink.h"
|
|
#include "permbind.h"
|
|
#include "aggreg.h"
|
|
#include "persistcfg.h"
|
|
#include "WinMgmtR.h"
|
|
#include <ql.h>
|
|
#include <cominit.h>
|
|
#include <genutils.h>
|
|
#include "NCEvents.h" // For the non-COM event stuff
|
|
#include <tempbind.h>
|
|
#include <wbemutil.h>
|
|
#include <sddl.h>
|
|
#include <helper.h>
|
|
|
|
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<IWbemObjectSink> m_pSink;
|
|
CWbemPtr<CEssNamespace> 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<IWbemObjectSink> m_pSink;
|
|
CWbemPtr<CEssNamespace> 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<CEssNamespace> 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<WCHAR> 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<BYTE> 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<BYTE> 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<HRESULT(*)(void),CoRevertToSelf> 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<CPermanentBinding> 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<CCoreEventProvider> 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<WCHAR> vdm2(&wszConsumerKey);
|
|
wszConsumerKey = CTempConsumer::ComputeKeyFromSink(pSink);
|
|
if ( NULL == wszConsumerKey )
|
|
{
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
bool bInterNamespace = pOwnerSid != NULL;
|
|
|
|
LPWSTR wszFilterKey = NULL;
|
|
CVectorDeleteMe<WCHAR> 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<WCHAR> vdm0(wszConsumerKey);
|
|
CInUpdate iu(this);
|
|
|
|
// Find the consumer in question
|
|
CEventConsumer *pConsumer = NULL;
|
|
|
|
if (SUCCEEDED(m_Bindings.FindEventConsumer(wszConsumerKey, &pConsumer)))
|
|
{
|
|
CRefedPointerSmallArray<CEventFilter>
|
|
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<WCHAR> vdm1(wszQueryLanguage);
|
|
CVectorDeleteMe<WCHAR> 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<WCHAR> 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<CEssNamespace> 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<WCHAR> vdm1(wszQueryLanguage);
|
|
CVectorDeleteMe<WCHAR> 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<WCHAR> vdm1(wszQueryLanguage);
|
|
CVectorDeleteMe<WCHAR> 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<WCHAR> vdm1(wszQueryLanguage);
|
|
CVectorDeleteMe<WCHAR> vdm2(wszQuery);
|
|
CDeleteMe<QL_LEVEL_1_RPN_EXPRESSION> 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<CEssNamespace> 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<WCHAR> 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<CEssInternalOperationSink> 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<IWbemObjectSink> 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<WCHAR> 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<IWbemObjectSink> 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<CEssNamespace> 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<WCHAR> 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<CCoreEventProvider> 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<IWbemClassObject> 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<IWbemClassObject> 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<IWbemClassObject> 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;
|
|
}
|