2025-11-28 00:35:46 +09:00

519 lines
12 KiB
C++

// **************************************************************************
// Copyright (c) Microsoft Corporation, All Rights Reserved
//
// File: EVPROV.cpp
//
// Description:
// Sample event provider.
//
// History:
//
// **************************************************************************
#ifndef _WIN32_DCOM
#define _WIN32_DCOM
#endif
#include <windows.h>
#include <stdio.h>
#include <objbase.h>
#include <wbemidl.h>
#include "oahelp.inl"
#include "evprov.h"
#include <strsafe.h>
#include <sddl.h>
#define MASK_CLIENT_ACCESS_BIND 1
static GENERIC_MAPPING s_ClientAccessMapping = {
0,
0,
STANDARD_RIGHTS_REQUIRED | MASK_CLIENT_ACCESS_BIND,
STANDARD_RIGHTS_REQUIRED | MASK_CLIENT_ACCESS_BIND
};
//***************************************************************************
//
//***************************************************************************
// ok
CMyEventProvider::CMyEventProvider()
{
m_pNs = 0;
m_pSink = 0;
m_cRef = 0;
m_pEventClassDef = 0;
m_eStatus = Pending;
m_hThread = 0;
}
//***************************************************************************
//
//***************************************************************************
// ok
CMyEventProvider::~CMyEventProvider()
{
if (m_hThread)
CloseHandle(m_hThread);
if (m_pNs)
m_pNs->Release();
if (m_pSink)
m_pSink->Release();
if (m_pEventClassDef)
m_pEventClassDef->Release();
}
//***************************************************************************
//
//***************************************************************************
// ok
STDMETHODIMP CMyEventProvider::QueryInterface(REFIID riid, LPVOID * ppv)
{
*ppv = 0;
if (IID_IUnknown==riid || IID_IWbemEventProvider==riid)
{
*ppv = (IWbemEventProvider *) this;
AddRef();
return NOERROR;
}
if (IID_IWbemProviderInit==riid)
{
*ppv = (IWbemProviderInit *) this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
//***************************************************************************
//
//***************************************************************************
// ok
ULONG CMyEventProvider::AddRef()
{
return ++m_cRef;
}
//***************************************************************************
//
//***************************************************************************
// ok
ULONG CMyEventProvider::Release()
{
if (0 != --m_cRef)
return m_cRef;
// If here, we are shutting down.
// ==============================
m_eStatus = PendingStop;
return 0;
}
//***************************************************************************
//
//***************************************************************************
// ok
HRESULT CMyEventProvider::ProvideEvents(
/* [in] */ IWbemObjectSink __RPC_FAR *pSink,
/* [in] */ long lFlags
)
{
// Copy the sink.
// ==============
m_pSink = pSink;
m_pSink->AddRef();
// Create the event thread.
// ========================
DWORD dwTID;
m_hThread = CreateThread(
0,
0,
CMyEventProvider::EventThread,
this,
0,
&dwTID
);
// Wait for provider to be 'ready'.
// ================================
while (m_eStatus != Running)
Sleep(100);
return WBEM_NO_ERROR;
}
//***************************************************************************
//
// This particular provider, being in a DLL operates via its own thread.
//
// In practice, such a provider would probably be implemented within a
// separate EXE.
//
//***************************************************************************
// ok
DWORD WINAPI CMyEventProvider::EventThread(LPVOID pArg)
{
// Make transition to the per-instance method.
// ===========================================
((CMyEventProvider *)pArg)->InstanceThread();
return 0;
}
//***************************************************************************
//
// Events are generated from here
//
//***************************************************************************
// ok
void CMyEventProvider::InstanceThread()
{
int nIteration = 0;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
m_eStatus = Running;
while (m_eStatus == Running)
{
Sleep(2000); // Provide an event every two seconds
// Generate a new event object.
// ============================
IWbemClassObject *pEvt = 0;
HRESULT hRes = m_pEventClassDef->SpawnInstance(0, &pEvt);
if (hRes != 0)
continue; // Failed
// Generate some values to put in the event.
// =========================================
wchar_t Buf[128];
StringCbPrintfW(Buf, sizeof(Buf), L"Test Event <%d>", nIteration);
CVARIANT vName(Buf);
hRes = pEvt->Put(CBSTR(L"Name"), 0, vName, 0);
if (FAILED(hRes))
{
// If here, delivery failed. This could be due to an out of memory condition.
// Do something to report it.
}
CVARIANT vCount((LONG) nIteration);
hRes = pEvt->Put(CBSTR(L"Value"), 0, vCount, 0);
if (FAILED(hRes))
{
// If here, delivery failed. This could be due to an out of memory condition.
// Do something to report it.
}
// Deliver the event to CIMOM.
// ============================
hRes = m_pSink->Indicate(1, &pEvt);
if (FAILED(hRes))
{
// If here, delivery failed. Do something to report it.
}
pEvt->Release();
nIteration++;
}
// When we get to here, we are no longer interested in the
// provider and Release() has long since returned.
m_eStatus = Stopped;
delete this;
}
//***************************************************************************
//
//***************************************************************************
// Inherited from IWbemProviderInit
// ================================
HRESULT CMyEventProvider::Initialize(
/* [in] */ LPWSTR pszUser,
/* [in] */ LONG lFlags,
/* [in] */ LPWSTR pszNamespace,
/* [in] */ LPWSTR pszLocale,
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
/* [in] */ IWbemContext __RPC_FAR *pCtx,
/* [in] */ IWbemProviderInitSink __RPC_FAR *pInitSink
)
{
// We don't care about most of the incoming parameters in this
// simple sample. However, we will save the namespace pointer
// and get our event class definition.
// ===========================================================
if(! pNamespace)
{
pInitSink->SetStatus(WBEM_E_FAILED , 0);
return WBEM_NO_ERROR;
}
m_pNs = pNamespace;
m_pNs->AddRef();
// Grab the class definition for the event.
// ======================================
IWbemClassObject *pObj = 0;
HRESULT hRes = m_pNs->GetObject(
CBSTR(EVENTCLASS),
0,
pCtx,
&pObj,
0
);
if (hRes != 0)
{
pInitSink->SetStatus(WBEM_E_FAILED , 0);
return WBEM_NO_ERROR;
}
m_pEventClassDef = pObj;
// Tell CIMOM that we're up and running.
// =====================================
pInitSink->SetStatus(WBEM_S_INITIALIZED,0);
return WBEM_NO_ERROR;
}
// ================================
// Inherited from IWbemEventProviderSecurity. This sample does not analyze the query and
// applies the same policy to all queries.
// ================================
HRESULT CMyEventProvider::AccessCheck(
WBEM_CWSTR wszQueryLanguage,
WBEM_CWSTR wszQuery,
long lSidLength,
const BYTE* pSid)
{
HRESULT hr = WBEM_S_NO_ERROR;
//this is a temporary subscription, and therefore we have the thread token
//Grant access for built-in admins, local system, local admins, local service and network service.
PSECURITY_DESCRIPTOR secDescriptor = NULL;
BOOL bRes = ConvertStringSecurityDescriptorToSecurityDescriptor //this function is only available on Windows 2000 and above
( "O:BAG:BAD:(A;;0x10000001;;;BA)(A;;0x10000001;;;SY)(A;;0x10000001;;;LA)(A;;0x10000001;;;SY)(A;;0x10000001;;;S-1-5-20)(A;;0x10000001;;;S-1-5-19)",
SDDL_REVISION_1,
(PSECURITY_DESCRIPTOR *) &secDescriptor,
NULL);
if (! bRes)
{
return WBEM_E_ACCESS_DENIED;
}
if (pSid == NULL)
{
hr = CoImpersonateClient () ;
if ( FAILED ( hr ) )
{
LocalFree(secDescriptor);
return WBEM_E_ACCESS_DENIED ;
}
// perform an access check.
hr = CheckAccess((SECURITY_DESCRIPTOR *)secDescriptor,
MASK_CLIENT_ACCESS_BIND,
&s_ClientAccessMapping);
LocalFree(secDescriptor);
// Revert before we perform any operations
CoRevertToSelf () ;
if (FAILED(hr))
return WBEM_E_ACCESS_DENIED;
else
return WBEM_S_NO_ERROR;
}
else
{
//check against the SID passed to us. This op
// Call GetSecurityDescriptorDacl() to obtain the DACL for secDescriptor.
// Then, retrieve the access mask corresponding to permissions granted
// by DACL to account denoted in pSid. Please refer to Security SDK samples
// and documentation for more details.
LocalFree(secDescriptor);
if(0) //pSID is not privileged enough to receive events from this proviuder
return WBEM_E_ACCESS_DENIED;
else
return WBEM_S_NO_ERROR;
}
return WBEM_S_NO_ERROR;
}
/******************************************************************************
*
* Name: CheckAccess
*
* Description: Allow provider to evaluate permissions against a security descriptor
*
* This method should be called by WMI providers in scenarios where
* they cannot or should not impersonate the client. This happens in two scenarios:
* a) when the providers access resources that are not protected by ACL's
* b) when the client connects at the impersonation level of RPC_C_IMP_LEVEL_IDENTIFY
*
*****************************************************************************/
HRESULT CMyEventProvider::CheckAccess (SECURITY_DESCRIPTOR *a_SecurityDescriptor ,
DWORD a_Access ,
GENERIC_MAPPING *a_Mapping)
{
HRESULT t_Result = S_OK ;
HANDLE t_Token = NULL ;
BOOL t_Status = OpenThreadToken (
GetCurrentThread () ,
TOKEN_QUERY ,
TRUE ,
& t_Token
) ;
DWORD t_LastError = GetLastError () ;
if ( ! t_Status)
{
//the thread token should always be available
if ( t_LastError ==E_ACCESSDENIED)
return WBEM_E_ACCESS_DENIED ;
else
return WBEM_E_FAILED ;
}
DWORD t_Access = 0 ;
BOOL t_AccessStatus = FALSE ;
PRIVILEGE_SET *t_PrivilegeSet = NULL ;
DWORD t_PrivilegeSetSize = 0 ;
MapGenericMask (
& a_Access ,
a_Mapping
) ;
t_Status = ::AccessCheck (
a_SecurityDescriptor ,
t_Token,
a_Access ,
a_Mapping ,
NULL ,
& t_PrivilegeSetSize ,
& t_Access ,
& t_AccessStatus
) ;
if (!t_Status || !t_AccessStatus )
{
DWORD t_LastError = GetLastError () ;
if ( t_LastError == ERROR_INSUFFICIENT_BUFFER )
{
t_PrivilegeSet = ( PRIVILEGE_SET * ) new BYTE [ t_PrivilegeSetSize ] ;
if ( t_PrivilegeSet )
{
t_Status = ::AccessCheck (
a_SecurityDescriptor ,
t_Token,
a_Access ,
a_Mapping ,
t_PrivilegeSet ,
& t_PrivilegeSetSize ,
& t_Access ,
& t_AccessStatus
) ;
if ( !t_Status || !t_AccessStatus )
{
t_Result = WBEM_E_ACCESS_DENIED ;
}
delete [] ( BYTE * ) t_PrivilegeSet ;
}
else
{
t_Result = WBEM_E_OUT_OF_MEMORY ;
}
}
else
{
t_Result = WBEM_E_ACCESS_DENIED;
}
}
CloseHandle ( t_Token ) ;
return t_Result ;
}