windows-nt/Source/XPSP1/NT/admin/wmi/wbem/providers/wdmprovider/wmievent.cpp

802 lines
22 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/////////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
//
/////////////////////////////////////////////////////////////////////////////////////
#include "precomp.h"
#include <aclapi.h>
#include <groupsforuser.h>
#include <sql_1.h>
#include <flexq.h>
static CFlexArray g_apRequests; // Shared between all CWMIEvent instances to provide a master event list
extern CCriticalSection * g_pEventCs;
extern CCriticalSection * g_pListCs;
////////////////////////////////////////////////////////////////////////////////////////////////
class CFlexQueueEx : public CFlexQueue
{
public:
void ResetQueue()
{
delete [] m_ppData;
m_ppData = NULL;
m_nSize = m_nHeadIndex = m_nTailIndex = 0;
}
};
CFlexQueueEx Q;
////////////////////////////////////////////////////////////////////////////////////////////////
void WINAPI EventCallbackRoutine(PWNODE_HEADER WnodeHeader, ULONG_PTR Context)
{
PWNODE_HEADER * pEventHeader = NULL;
{
CAutoBlock block (g_pListCs);
// Create a queue
pEventHeader = new PWNODE_HEADER;
if( pEventHeader )
{
*pEventHeader = WnodeHeader;
Q.Enqueue(pEventHeader);
}
}
while( TRUE )
{
//scope the use of the critsec...
{
CAutoBlock block( g_pListCs );
if( Q.GetQueueSize() == 0 )
{
Q.ResetQueue();
break;
}
pEventHeader = (PWNODE_HEADER *) Q.Dequeue();
if (pEventHeader == 0)
break;
}
CWMIEvent * p = (CWMIEvent* ) Context;
p->WMIEventCallback(*pEventHeader);
}
}
/////////////////////////////////////////////////////////////////////
void CWMIEvent::SetEventHandler(IWbemObjectSink __RPC_FAR * pHandler)
{
CAutoBlock Block(g_pEventCs);
if( m_pEventHandler )
{
m_pEventHandler->Release();
}
m_pEventHandler = pHandler;
if( m_pEventHandler )
{
m_pEventHandler->AddRef();
}
}
/////////////////////////////////////////////////////////////////////
void CWMIEvent::SetEventServices(IWbemServices __RPC_FAR * pServices)
{
CAutoBlock Block(g_pEventCs);
if( m_pEventServices )
{
m_pEventServices->Release();
}
m_pEventServices = pServices;
if( m_pEventServices )
{
m_pEventServices->AddRef();
}
}
/////////////////////////////////////////////////////////////////////
void CWMIEvent::SetEventContext(IWbemContext __RPC_FAR * pCtx)
{
CAutoBlock Block(g_pEventCs);
if( m_pEventCtx )
{
m_pEventCtx->Release();
}
m_pEventCtx = pCtx;
if( m_pEventCtx )
{
m_pEventCtx->AddRef();
}
}
////////////////////////////////////////////////////////////////////////
CWMIEvent::CWMIEvent(int nType)
{
m_nType = nType;
m_lRef = 0;
m_pEventHandler = NULL;
m_pEventServices = NULL;
m_pEventCtx = NULL;
if( m_nType != INTERNAL_EVENT )
{
InterlockedIncrement(&g_cObj);
}
m_fReadyForInternalEvents = FALSE;
}
////////////////////////////////////////////////////////////////////////
CWMIEvent::~CWMIEvent()
{
SAFE_RELEASE_PTR( m_pEventHandler );
SAFE_RELEASE_PTR( m_pEventServices );
SAFE_RELEASE_PTR( m_pEventCtx );
if( m_nType != INTERNAL_EVENT )
{
InterlockedDecrement(&g_cObj);
}
}
void CWMIEvent::ReleaseAllPointers()
{
IWbemObjectSink * pHandler = NULL;
IWbemServices * pServices = NULL;
IWbemContext * pCtx = NULL;
{
CAutoBlock Block(g_pEventCs);
pHandler = m_pEventHandler;
pServices = m_pEventServices;
pCtx = m_pEventCtx;
m_pEventCtx = NULL;
m_pEventServices = NULL;
m_pEventHandler = NULL;
}
SAFE_RELEASE_PTR( pHandler );
SAFE_RELEASE_PTR( pServices );
SAFE_RELEASE_PTR( pCtx );
}
////////////////////////////////////////////////////////////////////////
HRESULT CWMIEvent::DeleteAllLeftOverEvents()
{
HRESULT hr = WBEM_E_FAILED;
RevertToSelf();
CWMIStandardShell WMI;
if( SUCCEEDED(WMI.Initialize(NULL,FALSE,&m_HandleMap,TRUE,WMIGUID_NOTIFICATION|WMIGUID_QUERY,m_pEventServices,m_pEventHandler,m_pEventCtx)))
{
CAutoBlock Block(g_pEventCs);
// =====================================================
// Remove all requests with this Id
// =====================================================
for( int i = 0; i < g_apRequests.Size(); i++ )
{
WMIEventRequest* pReq = (WMIEventRequest*) g_apRequests[i];
ULONG_PTR uRc =(ULONG_PTR)this;
//===============================================
// Cancel the Event registration, if it fails...
// so what,we are leaving anyway, so delete all
//===============================================
WMI.CancelWMIEventRegistration(pReq->gGuid,uRc);
delete pReq;
}
g_apRequests.Empty();
hr = S_OK;
}
return hr;
}
////////////////////////////////////////////////////////////////////////
BOOL CWMIEvent::RegisterForInternalEvents( )
{
BOOL fRc = FALSE;
if( m_fReadyForInternalEvents )
{
if( SUCCEEDED(RegisterForRequestedEvent(BINARY_MOF_ID,RUNTIME_BINARY_MOFS_ADDED,MOF_ADDED)))
{
if( SUCCEEDED(RegisterForRequestedEvent(BINARY_MOF_ID,RUNTIME_BINARY_MOFS_DELETED,MOF_DELETED)))
{
fRc = TRUE;
}
}
}
return fRc;
}
////////////////////////////////////////////////////////////////////////
HRESULT CWMIEvent::RemoveWMIEvent(DWORD dwId)
{
HRESULT hr = S_OK;
if( m_nType == WMIEVENT )
{
hr = CheckImpersonationLevelAndVerifyInternalEvents(FALSE);
}
else
{
RevertToSelf();
}
if( SUCCEEDED(hr))
{
CWMIStandardShell WMI;
if( SUCCEEDED(WMI.Initialize(NULL,FALSE,&m_HandleMap,TRUE,WMIGUID_NOTIFICATION|WMIGUID_QUERY,m_pEventServices,m_pEventHandler,m_pEventCtx)))
{
CAutoBlock Block(g_pEventCs);
// ================================
// Remove all requests with this Id
// ================================
int nSize = g_apRequests.Size();
int i = 0;
while( i < nSize )
{
WMIEventRequest* pReq = (WMIEventRequest*) g_apRequests[i];
if(pReq->dwId == dwId)
{
// Inform WMI we don't want this anymore as
// long as there are no more these guids in
// the list, there might be more than one
// event consumer registered.
// =========================================
if( NoMoreEventConsumersRegistered( pReq->gGuid ) == 1)
{
ULONG_PTR uRc =(ULONG_PTR)this;
WMI.CancelWMIEventRegistration(pReq->gGuid,uRc);
}
g_apRequests.RemoveAt(i);
delete pReq;
nSize = g_apRequests.Size();
}
else
{
i++;
}
}
}
}
CheckImpersonationLevelAndVerifyInternalEvents(FALSE);
return WBEM_S_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////
HRESULT CWMIEvent::DeleteBinaryMofResourceEvent()
{
CAutoBlock Block(g_pEventCs);
RevertToSelf();
CWMIStandardShell WMI;
if( SUCCEEDED(WMI.Initialize(NULL,FALSE,&m_HandleMap,TRUE,WMIGUID_NOTIFICATION|WMIGUID_QUERY,m_pEventServices,m_pEventHandler,m_pEventCtx)))
{
// Remove all requests with this Id
// ================================
int nSize = g_apRequests.Size();
int i = 0;
while( i < nSize ){
WMIEventRequest* pReq = (WMIEventRequest*) g_apRequests[i];
if( ( IsBinaryMofResourceEvent(WMI_RESOURCE_MOF_ADDED_GUID,pReq->gGuid)) ||
( IsBinaryMofResourceEvent(WMI_RESOURCE_MOF_REMOVED_GUID,pReq->gGuid))){
ULONG_PTR uRc =(ULONG_PTR)this;
WMI.CancelWMIEventRegistration(pReq->gGuid,uRc);
g_apRequests.RemoveAt(i);
delete pReq;
nSize = g_apRequests.Size();
}
else{
i++;
}
}
CheckImpersonationLevelAndVerifyInternalEvents(FALSE);
}
return WBEM_S_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////
int CWMIEvent::NoMoreEventConsumersRegistered(GUID gGuid)
{
CAutoBlock Block(g_pEventCs);
int nTotalNumberOfRegisteredEventConsumers = 0;
WMIEventRequest * pEvent;
for(int i = 0; i < g_apRequests.Size(); i++)
{
pEvent = (WMIEventRequest *) g_apRequests.GetAt(i);
if( pEvent->gGuid == gGuid)
{
nTotalNumberOfRegisteredEventConsumers++;
}
}
return nTotalNumberOfRegisteredEventConsumers;
}
////////////////////////////////////////////////////////////////////////
BOOL CWMIEvent::IsGuidInListIfSoGetCorrectContext(GUID gGuid, WMIEventRequest *& pEvent )
{
CAutoBlock Block(g_pEventCs);
for( int i = 0; i < g_apRequests.Size(); i++ )
{
pEvent = (WMIEventRequest *) g_apRequests.GetAt(i);
if( pEvent->gGuid == gGuid){
return TRUE;
}
}
pEvent = NULL;
return FALSE;
}
////////////////////////////////////////////////////////////////////////
BOOL CWMIEvent::IsGuidInList(WCHAR * wcsGuid, WMIEventRequest *& pEvent)
{
CAutoBlock Block(g_pEventCs);
BOOL fRc = FALSE;
int Size = g_apRequests.Size();
for(int i =0 ; i < Size; i++ ){
pEvent = (WMIEventRequest *) g_apRequests.GetAt(i);
if( (_wcsicmp(pEvent->wcsGuid,wcsGuid)) == 0 ){
fRc = TRUE;
break;
}
}
return fRc;
}
////////////////////////////////////////////////////////////////////////
HRESULT CWMIEvent::RegisterForRequestedEvent( DWORD dwId, WCHAR * wcsClass, WORD wType)
{
BOOL fRegistered = FALSE;
CWMIStandardShell WMI;
HRESULT hr = WBEM_E_ACCESS_DENIED;
BOOL fInternalEvent = TRUE;
if( wType == STANDARD_EVENT )
{
fInternalEvent = FALSE;
}
if( SUCCEEDED(WMI.Initialize(wcsClass, fInternalEvent, &m_HandleMap,TRUE,WMIGUID_NOTIFICATION|WMIGUID_QUERY,m_pEventServices,m_pEventHandler,m_pEventCtx)))
{
if( m_nType == WMIEVENT ){
hr = CheckImpersonationLevelAndVerifyInternalEvents(FALSE);
}
else
{
RevertToSelf();
hr = S_OK;
}
if( SUCCEEDED(hr) )
{
WCHAR wcsGuid[128];
hr = WMI.SetGuidForEvent( wType,wcsGuid );
if( SUCCEEDED(hr)){
WMIEventRequest * pAlreadyRegisteredEvent;
//===========================================================
// Keep a record of this guy, see if it is already registered
// if it is/isn't we call WDM with different flags
//===========================================================
fRegistered = IsGuidInList( wcsGuid, pAlreadyRegisteredEvent );
//===========================================================
// Register for the requested event
//===========================================================
ULONG_PTR uRc =(ULONG_PTR)this;
CLSID Guid;
hr = WMI.RegisterWMIEvent(wcsGuid,uRc,Guid,fRegistered);
if( SUCCEEDED(hr) && !fRegistered)
{
//=======================================================
// If we succeeded, then add it to our list of events we
// are watching
//=======================================================
WMIEventRequest * pEvent = new WMIEventRequest;
pEvent->gGuid = Guid;
pEvent->dwId = dwId;
pEvent->fHardCoded = wType;
wcscpy( pEvent->wcsGuid,wcsGuid);
pEvent->SetClassName(wcsClass);
pEvent->AddPtrs(m_pEventHandler,m_pEventServices,m_pEventCtx);
g_apRequests.Add(pEvent);
}
}
}
CheckImpersonationLevelAndVerifyInternalEvents(FALSE);
}
return hr;
}
////////////////////////////////////////////////////////////////////////
CWMIEventProvider::CWMIEventProvider(int nType) : CWMIEvent(nType)
{
m_hResyncEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
ERRORTRACE((THISPROVIDER,"Event Provider constructed\n"));
}
////////////////////////////////////////////////////////////////////////
CWMIEventProvider::~CWMIEventProvider()
{
ERRORTRACE((THISPROVIDER,"Event Provider denstructed\n"));
}
////////////////////////////////////////////////////////////////////////
STDMETHODIMP CWMIEventProvider::QueryInterface(REFIID riid, void** ppv)
{
HRESULT hr = E_NOINTERFACE;
*ppv = NULL;
if(riid == IID_IUnknown)
{
*ppv = this;
}
else
if(riid == IID_IWbemEventProvider)
{
*ppv = (IWbemEventProvider*)this;
}
else if(riid == IID_IWbemEventProviderQuerySink)
{
*ppv = (IWbemEventProviderQuerySink*)this;
}
else if (IsEqualIID(riid, IID_IWbemProviderInit))
{
*ppv = (IWbemProviderInit *) this ;
}
else if (IsEqualIID(riid, IID_IWbemEventProviderSecurity))
{
*ppv = (IWbemEventProviderSecurity *) this ;
}
if( *ppv)
{
AddRef();
hr = S_OK;
}
return hr;
}
////////////////////////////////////////////////////////////////////////
ULONG STDMETHODCALLTYPE CWMIEventProvider::AddRef()
{
return InterlockedIncrement(&m_lRef);
}
////////////////////////////////////////////////////////////////////////
ULONG STDMETHODCALLTYPE CWMIEventProvider::Release()
{
long lRef = InterlockedDecrement(&m_lRef);
if(lRef == 0){
//**********************************************
// reference count is zero, delete this object.
// and do all of the cleanup for this user,
//**********************************************
delete this ;
}
return lRef;
}
/////////////////////////////////////////////////////////////////////
STDMETHODIMP CWMIEventProvider::Initialize(LPWSTR wszUser, long lFlags,
LPWSTR wszNamespace,
LPWSTR wszLocale,
IWbemServices* pNamespace,
IWbemContext* pCtx,
IWbemProviderInitSink* pSink)
{
IWbemClassObject * pWMIClass = NULL;
HRESULT hres = pNamespace->GetObject(WMI_EVENT_CLASS, 0, NULL, &pWMIClass, NULL);
CAutoBlock Block(g_pEventCs);
// ptr initialization routines
SetEventServices(pNamespace);
SetEventContext(pCtx);
pSink->SetStatus(hres, 0);
SAFE_RELEASE_PTR(pWMIClass);
return hres;
}
////////////////////////////////////////////////////////////////////////
STDMETHODIMP CWMIEventProvider::ProvideEvents(IWbemObjectSink __RPC_FAR *pSink,long lFlags)
{
CAutoBlock Block(g_pEventCs);
SetEventHandler(pSink);
// ===============================================================================
// Make sure any request added before this was called gets the updated handler
// PROVIDING it isn't the binary mof guid
// ===============================================================================
for(int i = 0; i < g_apRequests.Size(); i++)
{
WMIEventRequest* pReq = (WMIEventRequest*) g_apRequests[i];
if(!pReq->pHandler)
{
if( IsBinaryMofResourceEvent(WMI_RESOURCE_MOF_ADDED_GUID,pReq->gGuid))
{
}
else
{
if( !pReq->pHandler )
{
pReq->pHandler = pSink;
}
}
}
}
return S_OK;
}
////////////////////////////////////////////////////////////////////////
STDMETHODIMP CWMIEventProvider::NewQuery( DWORD dwId, WBEM_WSTR wszLanguage, WBEM_WSTR wszQuery)
{
HRESULT hRes = WBEM_S_NO_ERROR;
if (_wcsicmp(wszLanguage, L"WQL") != 0)
{
hRes = WBEM_E_INVALID_QUERY_TYPE;
}
if( hRes == WBEM_S_NO_ERROR )
{
// Parse the query
// Construct the lex source
// ========================
CTextLexSource Source(wszQuery);
// Use the lex source to set up for parser
// =======================================
SQL1_Parser QueryParser(&Source);
SQL_LEVEL_1_RPN_EXPRESSION * pParse;
int ParseRetValue = QueryParser.Parse(&pParse);
if( SQL1_Parser::SUCCESS != ParseRetValue) {
hRes = WBEM_E_INVALID_QUERY;
}
else{
//Set the class
if( pParse ){
hRes = RegisterForRequestedEvent(dwId,pParse->bsClassName,STANDARD_EVENT);
delete pParse;
}
}
}
return hRes;
}
////////////////////////////////////////////////////////////////////////
STDMETHODIMP CWMIEventProvider::CancelQuery(DWORD dwId)
{
return RemoveWMIEvent(dwId);
}
////////////////////////////////////////////////////////////////////////
STDMETHODIMP CWMIEventProvider::AccessCheck(WBEM_CWSTR wszLanguage,
WBEM_CWSTR wszQuery,
long lSidLength,
const BYTE* aSid)
{
HRESULT hr = WBEM_E_ACCESS_DENIED;
//=======================================================
// Check platform
//=======================================================
if(!IsNT())
return WBEM_S_FALSE;
//=======================================================
// Check query language
//=======================================================
if (_wcsicmp(wszLanguage, L"WQL") != 0) {
return WBEM_E_INVALID_QUERY_TYPE;
}
//=======================================================
// If the PSid is NULL, then check impersonation level
// as usual - based on the thread
//=======================================================
PSID pSid = (PSID)aSid;
HANDLE hToken = NULL;
if(pSid == NULL){
//=================================================
// if this is the INTERNAL_EVENT class, then we
// do not want the local events set up again.
//=================================================
BOOL VerifyLocalEventsAreSetup = TRUE;
if( m_nType == INTERNAL_EVENT ){
VerifyLocalEventsAreSetup = FALSE;
}
hr = CheckImpersonationLevelAndVerifyInternalEvents(VerifyLocalEventsAreSetup);
}
else{
//=======================================================
// Parse the query
//=======================================================
CTextLexSource Source(wszQuery);
//=======================================================
// Use the lex source to set up for parser
//=======================================================
SQL1_Parser QueryParser(&Source);
SQL_LEVEL_1_RPN_EXPRESSION * pParse;
int ParseRetValue = QueryParser.Parse(&pParse);
if( SQL1_Parser::SUCCESS != ParseRetValue) {
return WBEM_E_INVALID_QUERY;
}
else{
if( pParse ){
CWMIStandardShell WMI;
if( SUCCEEDED(WMI.Initialize(pParse->bsClassName,FALSE,&m_HandleMap,TRUE,WMIGUID_NOTIFICATION|WMIGUID_QUERY,m_pEventServices,m_pEventHandler,m_pEventCtx)))
{
CLSID * pGuid;
pGuid = WMI.GuidPtr();
if(pGuid != NULL)
{
//========================================
// Get the ACL
//========================================
PACL pDacl;
PSECURITY_DESCRIPTOR psd = NULL;
SE_OBJECT_TYPE ObjectType = SE_WMIGUID_OBJECT;
hr = WBEM_E_ACCESS_DENIED;
WCHAR * GuidName = NULL;
hr = UuidToString(pGuid, &GuidName);
if (hr == RPC_S_OK)
{
hr = S_OK;
DWORD dwRc = GetNamedSecurityInfo(GuidName,ObjectType,DACL_SECURITY_INFORMATION,NULL,NULL,&pDacl, NULL, &psd );
if( dwRc != ERROR_SUCCESS )
{
ERRORTRACE((THISPROVIDER, "GetNamedSecurityInfo returned %ld.\n", dwRc ));
hr = WBEM_E_ACCESS_DENIED;
}
}
if( GuidName )
{
RpcStringFree(&GuidName);
}
if(SUCCEEDED(hr))
{
//====================================
// This is our own ACL walker
//====================================
DWORD dwAccessMask;
NTSTATUS st = GetAccessMask((PSID)pSid, pDacl, &dwAccessMask);
if(st)
{
ERRORTRACE((THISPROVIDER, "WDM event provider unable "
"to retrieve access mask for the creator of "
"registration %S: NT status %d.\n"
"Registration disabled\n", wszQuery,st));
return WBEM_E_FAILED;
}
if((dwAccessMask & WMIGUID_QUERY) == 0)
{
hr = WBEM_E_ACCESS_DENIED;
}
else
{
hr = S_OK;
m_nType = PERMANENT_EVENT;
}
}
if( psd != NULL)
{
AccFree( psd );
}
}
delete pParse;
}
}
}
}
return hr;
}
////////////////////////////////////////////////////////////////////////
void CWMIEvent::WMIEventCallback(PWNODE_HEADER WnodeHeader)
{
LPGUID EventGuid = &WnodeHeader->Guid;
ERRORTRACE((THISPROVIDER,"Received Event\n"));
//=======================================================
// We only support WNODE_FLAG_ALL_DATA and
// WNODE_FLAG_SINGLE_INSTANCE
//
// Parse thru whatever it is and send it off to HMOM
//=======================================================
if( WnodeHeader )
{
HRESULT hr;
WMIEventRequest * pEvent;
//===========================================================
// Make sure it is an event we want
//===========================================================
if( IsGuidInListIfSoGetCorrectContext( *EventGuid,pEvent))
{
CWMIStandardShell WMI;
//=======================================================
// See if a binary mof event is being added or deleted
//=======================================================
WORD wBinaryMofType = 0;
BOOL fInternalEvent = FALSE;
if( IsBinaryMofResourceEvent(WMI_RESOURCE_MOF_ADDED_GUID,WnodeHeader->Guid))
{
fInternalEvent = TRUE;
wBinaryMofType = MOF_ADDED;
}
else if( IsBinaryMofResourceEvent(WMI_RESOURCE_MOF_REMOVED_GUID,WnodeHeader->Guid))
{
fInternalEvent = TRUE;
wBinaryMofType = MOF_DELETED;
}
if( SUCCEEDED(WMI.Initialize(pEvent->pwcsClass,fInternalEvent,&m_HandleMap,TRUE,WMIGUID_QUERY|WMIGUID_NOTIFICATION,pEvent->pServices,pEvent->pHandler,pEvent->pCtx)))
{
//=======================================================
// If it was, then process it, otherwise go on... :)
//=======================================================
WMI.ProcessEvent(wBinaryMofType,WnodeHeader);
}
}
}
}