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.
1075 lines
35 KiB
1075 lines
35 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
ntperf.cpp
|
|
|
|
Abstract:
|
|
|
|
Mapped NT5 Perf counter provider
|
|
|
|
History:
|
|
|
|
raymcc 02-Dec-97 Created.
|
|
raymcc 20-Feb-98 Updated to use new initializer.
|
|
bobw 8-Jun-98 tuned up
|
|
|
|
--*/
|
|
|
|
#include "wpheader.h"
|
|
#include <stdio.h>
|
|
#include "oahelp.inl"
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider constructor
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
CNt5PerfProvider::CNt5PerfProvider(enumCLSID OriginClsid)
|
|
{
|
|
m_lRef = 0;
|
|
m_OriginClsid = OriginClsid;
|
|
m_hClassMapMutex = CreateMutex(NULL, FALSE, NULL);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider destructor
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
CNt5PerfProvider::~CNt5PerfProvider()
|
|
{
|
|
int i;
|
|
CClassMapInfo *pClassElem;
|
|
|
|
assert (m_lRef == 0);
|
|
|
|
for (i = 0; i < m_aCache.Size(); i++) {
|
|
pClassElem = (CClassMapInfo *) m_aCache[i];
|
|
m_PerfObject.RemoveClass (pClassElem->m_pClassDef);
|
|
delete pClassElem;
|
|
}
|
|
m_aCache.Empty(); // reset the buffer pointers
|
|
|
|
if (m_hClassMapMutex != 0)
|
|
CloseHandle(m_hClassMapMutex);
|
|
|
|
// RegCloseKey(HKEY_PERFORMANCE_DATA); // causes more problems than it solves
|
|
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::AddRef
|
|
//
|
|
// Standard COM AddRef().
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
ULONG CNt5PerfProvider::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_lRef);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::Release
|
|
//
|
|
// Standard COM Release().
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
ULONG CNt5PerfProvider::Release()
|
|
{
|
|
long lRef = InterlockedDecrement(&m_lRef);
|
|
if(lRef == 0) {
|
|
delete this;
|
|
}
|
|
return lRef;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::QueryInterface
|
|
//
|
|
// Standard COM QueryInterface(). We have to support two interfaces,
|
|
// the IWbemHiPerfProvider interface itself to provide the objects and
|
|
// the IWbemProviderInit interface to initialize the provider.
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
HRESULT CNt5PerfProvider::QueryInterface(REFIID riid, void** ppv)
|
|
{
|
|
HRESULT hReturn;
|
|
|
|
if (riid == IID_IUnknown || riid == IID_IWbemHiPerfProvider) {
|
|
*ppv = (IWbemHiPerfProvider*) this;
|
|
AddRef();
|
|
hReturn = S_OK;
|
|
} else if (riid == IID_IWbemProviderInit) {
|
|
*ppv = (IWbemProviderInit *) this;
|
|
AddRef();
|
|
hReturn = S_OK;
|
|
} else {
|
|
*ppv = NULL;
|
|
hReturn = E_NOINTERFACE;
|
|
}
|
|
return hReturn;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::Initialize
|
|
//
|
|
// Called once during startup. Indicates to the provider which
|
|
// namespace it is being invoked for and which User. It also supplies
|
|
// a back pointer to CIMOM so that class definitions can be retrieved.
|
|
//
|
|
// We perform any one-time initialization in this routine. The
|
|
// final call to Release() is for any cleanup.
|
|
//
|
|
// <wszUser> The current user.
|
|
// <lFlags> Reserved.
|
|
// <wszNamespace> The namespace for which we are being activated.
|
|
// <wszLocale> The locale under which we are to be running.
|
|
// <pNamespace> An active pointer back into the current namespace
|
|
// from which we can retrieve schema objects.
|
|
// <pCtx> The user's context object. We simply reuse this
|
|
// during any reentrant operations into CIMOM.
|
|
// <pInitSink> The sink to which we indicate our readiness.
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
HRESULT CNt5PerfProvider::Initialize(
|
|
/* [unique][in] */ LPWSTR wszUser,
|
|
/* [in] */ LONG lFlags,
|
|
/* [in] */ LPWSTR wszNamespace,
|
|
/* [unique][in] */ LPWSTR wszLocale,
|
|
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
|
|
/* [in] */ IWbemContext __RPC_FAR *pCtx,
|
|
/* [in] */ IWbemProviderInitSink __RPC_FAR *pInitSink
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(wszUser);
|
|
UNREFERENCED_PARAMETER(lFlags);
|
|
UNREFERENCED_PARAMETER(wszNamespace);
|
|
UNREFERENCED_PARAMETER(wszLocale);
|
|
UNREFERENCED_PARAMETER(pNamespace);
|
|
UNREFERENCED_PARAMETER(pCtx);
|
|
|
|
pInitSink->SetStatus(0, WBEM_S_INITIALIZED);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::QueryInstances
|
|
//
|
|
// Called whenever a complete, fresh list of instances for a given
|
|
// class is required. The objects are constructed and sent back to the
|
|
// caller through the sink. The sink can be used in-line as here, or
|
|
// the call can return and a separate thread could be used to deliver
|
|
// the instances to the sink.
|
|
//
|
|
// Parameters:
|
|
// <pNamespace> A pointer to the relevant namespace. This
|
|
// should not be AddRef'ed or retained past the
|
|
// execution of this method.
|
|
// <wszClass> The class name for which instances are required.
|
|
// <lFlags> Reserved.
|
|
// <pCtx> The user-supplied context (used during callbacks
|
|
// into CIMOM).
|
|
// <pSink> The sink to which to deliver the objects. The objects
|
|
// can be delivered synchronously through the duration
|
|
// of this call or asynchronously (assuming we
|
|
// had a separate thread). A IWbemObjectSink::SetStatus
|
|
// call is required at the end of the sequence.
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
HRESULT CNt5PerfProvider::QueryInstances(
|
|
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
|
|
/* [string][in] */ WCHAR __RPC_FAR *wszClass,
|
|
/* [in] */ long lFlags,
|
|
/* [in] */ IWbemContext __RPC_FAR *pCtx,
|
|
/* [in] */ IWbemObjectSink __RPC_FAR *pSink
|
|
)
|
|
{
|
|
HRESULT hReturn;
|
|
BOOL bRes ;
|
|
CClassMapInfo *pClsMap = NULL;
|
|
|
|
UNREFERENCED_PARAMETER(lFlags);
|
|
|
|
hReturn = CoImpersonateClient(); // make sure we're legit.
|
|
|
|
BOOL fRevert = SUCCEEDED( hReturn );
|
|
|
|
// The following error appears to occur when we are in-proc and there is no
|
|
// proxy/stub, so we are effectively impersonating already
|
|
|
|
if ( RPC_E_CALL_COMPLETE == hReturn ) {
|
|
hReturn = S_OK;
|
|
}
|
|
|
|
if (S_OK == hReturn) {
|
|
hReturn = CheckImpersonationLevel();
|
|
}
|
|
// Check Registry security here.
|
|
if ((hReturn != S_OK) || (!HasPermission())) {
|
|
// if Impersonation level is incorrect or
|
|
// the caller doesn't have permission to read
|
|
// from the registry, then they cannot continue
|
|
hReturn = WBEM_E_ACCESS_DENIED;
|
|
}
|
|
|
|
if (hReturn == S_OK) {
|
|
|
|
if (pNamespace == 0 || wszClass == 0 || pSink == 0) {
|
|
hReturn = WBEM_E_INVALID_PARAMETER;
|
|
} else {
|
|
|
|
// Ensure the class is in our cache and mapped.
|
|
// ============================================
|
|
bRes = MapClass(pNamespace, wszClass, pCtx);
|
|
|
|
if (bRes == FALSE) {
|
|
// Class is not one of ours.
|
|
hReturn = WBEM_E_INVALID_CLASS;
|
|
} else {
|
|
pClsMap = FindClassMap(wszClass);
|
|
if (pClsMap == NULL) {
|
|
hReturn = WBEM_E_INVALID_CLASS;
|
|
}
|
|
}
|
|
|
|
if (hReturn == NO_ERROR) {
|
|
// Refresh the instances.
|
|
// ======================
|
|
|
|
PerfHelper::QueryInstances(&m_PerfObject, pClsMap, pSink);
|
|
|
|
// Tell CIMOM we are finished.
|
|
// ===========================
|
|
|
|
pSink->SetStatus(0, WBEM_NO_ERROR, 0, 0);
|
|
hReturn = NO_ERROR;
|
|
}
|
|
}
|
|
} else {
|
|
// return error
|
|
}
|
|
|
|
// Revert if we successfuly impersonated the user
|
|
if ( fRevert )
|
|
{
|
|
CoRevertToSelf();
|
|
}
|
|
|
|
return hReturn;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::CreateRefresher
|
|
//
|
|
// Called whenever a new refresher is needed by the client.
|
|
//
|
|
// Parameters:
|
|
// <pNamespace> A pointer to the relevant namespace. Not used.
|
|
// <lFlags> Not used.
|
|
// <ppRefresher> Receives the requested refresher.
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
HRESULT CNt5PerfProvider::CreateRefresher(
|
|
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
|
|
/* [in] */ long lFlags,
|
|
/* [out] */ IWbemRefresher __RPC_FAR *__RPC_FAR *ppRefresher
|
|
)
|
|
{
|
|
HRESULT hReturn;
|
|
CNt5Refresher *pNewRefresher;
|
|
|
|
UNREFERENCED_PARAMETER(lFlags);
|
|
|
|
hReturn = CoImpersonateClient(); // make sure we're legit.
|
|
|
|
BOOL fRevert = SUCCEEDED( hReturn );
|
|
|
|
// The following error appears to occur when we are in-proc and there is no
|
|
// proxy/stub, so we are effectively impersonating already
|
|
|
|
if ( RPC_E_CALL_COMPLETE == hReturn ) {
|
|
hReturn = S_OK;
|
|
}
|
|
|
|
if (S_OK == hReturn) {
|
|
hReturn = CheckImpersonationLevel();
|
|
}
|
|
// Check Registry security here.
|
|
if ((hReturn != S_OK) || (!HasPermission())) {
|
|
// if Impersonation level is incorrect or
|
|
// the caller doesn't have permission to read
|
|
// from the registry, then they cannot continue
|
|
hReturn = WBEM_E_ACCESS_DENIED;
|
|
}
|
|
|
|
if (hReturn == S_OK) {
|
|
|
|
if (pNamespace == 0 || ppRefresher == 0) {
|
|
hReturn = WBEM_E_INVALID_PARAMETER;
|
|
} else {
|
|
// Construct a new empty refresher.
|
|
// ================================
|
|
pNewRefresher = new CNt5Refresher (this);
|
|
|
|
if (pNewRefresher != NULL) {
|
|
// Follow COM rules and AddRef() the thing before sending it back.
|
|
// ===============================================================
|
|
pNewRefresher->AddRef();
|
|
*ppRefresher = pNewRefresher;
|
|
|
|
hReturn = NO_ERROR;
|
|
} else {
|
|
hReturn = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Revert if we successfuly impersonated the user
|
|
if ( fRevert )
|
|
{
|
|
CoRevertToSelf();
|
|
}
|
|
|
|
return hReturn;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::CreateRefresherObject
|
|
//
|
|
// Called whenever a user wants to include an object in a refresher.
|
|
//
|
|
// Parameters:
|
|
// <pNamespace> A pointer to the relevant namespace in CIMOM.
|
|
// <pTemplate> A pointer to a copy of the object which is to be
|
|
// added. This object itself cannot be used, as
|
|
// it not owned locally.
|
|
// <pRefresher> The refresher to which to add the object.
|
|
// <lFlags> Not used.
|
|
// <pContext> Not used here.
|
|
// <ppRefreshable> A pointer to the internal object which was added
|
|
// to the refresher.
|
|
// <plId> The Object Id (for identification during removal).
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
HRESULT CNt5PerfProvider::CreateRefresherObject(
|
|
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
|
|
/* [in] */ IWbemObjectAccess __RPC_FAR *pTemplate,
|
|
/* [in] */ IWbemRefresher __RPC_FAR *pRefresher,
|
|
/* [in] */ long lFlags,
|
|
/* [in] */ IWbemContext __RPC_FAR *pContext,
|
|
/* [string][in] */ LPCWSTR wszClass,
|
|
/* [in] */ IWbemHiPerfEnum __RPC_FAR *pHiPerfEnum,
|
|
/* [out] */ IWbemObjectAccess __RPC_FAR *__RPC_FAR *ppRefreshable,
|
|
/* [out] */ long __RPC_FAR *plId
|
|
)
|
|
{
|
|
IWbemClassObject *pOriginal = 0;
|
|
IWbemClassObject *pNewCopy = 0;
|
|
IWbemObjectAccess *pNewAccess = 0;
|
|
CNt5Refresher *pRef = 0;
|
|
CClassMapInfo *pClsMap;
|
|
VARIANT v;
|
|
BOOL bRes;
|
|
HRESULT hReturn = NO_ERROR;
|
|
CBSTR cbClassName(cszClassName);
|
|
|
|
UNREFERENCED_PARAMETER(lFlags);
|
|
|
|
if( NULL == (BSTR)cbClassName ){
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if (ppRefreshable != NULL) {
|
|
// Initialize the argument
|
|
*ppRefreshable = 0;
|
|
}
|
|
|
|
// init the variant
|
|
VariantInit(&v);
|
|
|
|
if (pTemplate != NULL) {
|
|
// Make a copy of the template object.
|
|
// ===================================
|
|
hReturn = pTemplate->QueryInterface(IID_IWbemClassObject, (LPVOID *) &pOriginal);
|
|
if (hReturn == NO_ERROR) {
|
|
hReturn = pOriginal->Clone(&pNewCopy);
|
|
|
|
// Get the class name of the object.
|
|
// =================================
|
|
if (hReturn == NO_ERROR) {
|
|
hReturn = pOriginal->Get( cbClassName, 0, &v, 0, 0);
|
|
if ((hReturn == NO_ERROR) && (v.vt != VT_BSTR)) {
|
|
hReturn = WBEM_E_INVALID_CLASS;
|
|
}
|
|
}
|
|
|
|
// We are now done with the original object
|
|
// ========================================
|
|
pOriginal->Release();
|
|
}
|
|
|
|
if (hReturn == NO_ERROR) {
|
|
// We now get the IWbemObjectAccess form of the cloned object
|
|
// and release the unused interface.
|
|
// ==========================================================
|
|
hReturn = pNewCopy->QueryInterface(IID_IWbemObjectAccess, (LPVOID *) &pNewAccess);
|
|
}
|
|
|
|
if( NULL != pNewCopy ){
|
|
pNewCopy->Release();
|
|
}
|
|
|
|
} else {
|
|
// copy the class name passed in
|
|
v.vt = VT_BSTR;
|
|
v.bstrVal = SysAllocString(wszClass);
|
|
}
|
|
|
|
if (hReturn == NO_ERROR) {
|
|
// cast refresher pointer to our refresher object
|
|
pRef = (CNt5Refresher *) pRefresher;
|
|
|
|
// Map the class info for this instance.
|
|
// =====================================
|
|
bRes = MapClass(pNamespace, V_BSTR(&v), pContext);
|
|
if (bRes == FALSE) {
|
|
// Class is not one of ours.
|
|
if (pNewAccess != NULL) pNewAccess->Release();
|
|
hReturn = WBEM_E_INVALID_CLASS;
|
|
} else {
|
|
pClsMap = FindClassMap(V_BSTR(&v));
|
|
if (pClsMap == 0) {
|
|
if (pNewAccess != NULL) pNewAccess->Release();
|
|
hReturn = WBEM_E_INVALID_CLASS;
|
|
} else {
|
|
// Add the object to the refresher.
|
|
if (pHiPerfEnum != NULL) {
|
|
// then this is an Enum object so add it
|
|
bRes = pRef->AddEnum (
|
|
pHiPerfEnum,
|
|
pClsMap,
|
|
plId);
|
|
if (bRes) {
|
|
// Return new ID to caller
|
|
// ==========================
|
|
hReturn = NO_ERROR;
|
|
} else {
|
|
// unable to add enumerator
|
|
pNewAccess->Release();
|
|
hReturn = GetLastError();
|
|
}
|
|
} else {
|
|
// This method will AddRef() the object before returning.
|
|
// ======================================================
|
|
bRes = pRef->AddObject(
|
|
&pNewAccess,
|
|
pClsMap,
|
|
plId);
|
|
if (bRes) {
|
|
// Return object to the user.
|
|
// ==========================
|
|
*ppRefreshable = pNewAccess;
|
|
hReturn = NO_ERROR;
|
|
} else {
|
|
// unable to add object
|
|
pNewAccess->Release();
|
|
hReturn = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VariantClear(&v);
|
|
|
|
return hReturn;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::CreateRefreshableObject
|
|
//
|
|
// Called whenever a user wants to include an object in a refresher.
|
|
//
|
|
// Parameters:
|
|
// <pNamespace> A pointer to the relevant namespace in CIMOM.
|
|
// <pTemplate> A pointer to a copy of the object which is to be
|
|
// added. This object itself cannot be used, as
|
|
// it not owned locally.
|
|
// <pRefresher> The refresher to which to add the object.
|
|
// <lFlags> Not used.
|
|
// <pContext> Not used here.
|
|
// <ppRefreshable> A pointer to the internal object which was added
|
|
// to the refresher.
|
|
// <plId> The Object Id (for identification during removal).
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
HRESULT CNt5PerfProvider::CreateRefreshableObject(
|
|
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
|
|
/* [in] */ IWbemObjectAccess __RPC_FAR *pTemplate,
|
|
/* [in] */ IWbemRefresher __RPC_FAR *pRefresher,
|
|
/* [in] */ long lFlags,
|
|
/* [in] */ IWbemContext __RPC_FAR *pContext,
|
|
/* [out] */ IWbemObjectAccess __RPC_FAR *__RPC_FAR *ppRefreshable,
|
|
/* [out] */ long __RPC_FAR *plId
|
|
)
|
|
{
|
|
|
|
|
|
HRESULT hReturn = NO_ERROR;
|
|
|
|
hReturn = CoImpersonateClient(); // make sure we're legit.
|
|
|
|
BOOL fRevert = SUCCEEDED( hReturn );
|
|
|
|
// The following error appears to occur when we are in-proc and there is no
|
|
// proxy/stub, so we are effectively impersonating already
|
|
|
|
if ( RPC_E_CALL_COMPLETE == hReturn ) {
|
|
hReturn = S_OK;
|
|
}
|
|
|
|
if (S_OK == hReturn) {
|
|
hReturn = CheckImpersonationLevel();
|
|
}
|
|
// Check Registry security here.
|
|
if ((hReturn != S_OK) || (!HasPermission())) {
|
|
// if Impersonation level is incorrect or
|
|
// the caller doesn't have permission to read
|
|
// from the registry, then they cannot continue
|
|
hReturn = WBEM_E_ACCESS_DENIED;
|
|
}
|
|
|
|
if (hReturn == S_OK) {
|
|
|
|
hReturn = CreateRefresherObject(
|
|
pNamespace,
|
|
pTemplate,
|
|
pRefresher,
|
|
lFlags,
|
|
pContext,
|
|
NULL,
|
|
NULL,
|
|
ppRefreshable,
|
|
plId);
|
|
}
|
|
|
|
// Revert if we successfuly impersonated the user
|
|
if ( fRevert )
|
|
{
|
|
CoRevertToSelf();
|
|
}
|
|
|
|
return hReturn;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::StopRefreshing
|
|
//
|
|
// Called whenever a user wants to remove an object from a refresher.
|
|
//
|
|
// Parameters:
|
|
// <pRefresher> The refresher object from which we are to
|
|
// remove the perf object.
|
|
// <lId> The ID of the object.
|
|
// <lFlags> Not used.
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
HRESULT CNt5PerfProvider::StopRefreshing(
|
|
/* [in] */ IWbemRefresher __RPC_FAR *pRefresher,
|
|
/* [in] */ long lId,
|
|
/* [in] */ long lFlags
|
|
)
|
|
{
|
|
CNt5Refresher *pRef;
|
|
BOOL bRes ;
|
|
HRESULT hReturn;
|
|
|
|
UNREFERENCED_PARAMETER(lFlags);
|
|
|
|
hReturn = CoImpersonateClient(); // make sure we're legit.
|
|
|
|
BOOL fRevert = SUCCEEDED( hReturn );
|
|
|
|
// The following error appears to occur when we are in-proc and there is no
|
|
// proxy/stub, so we are effectively impersonating already
|
|
|
|
if ( RPC_E_CALL_COMPLETE == hReturn ) {
|
|
hReturn = S_OK;
|
|
}
|
|
|
|
if (S_OK == hReturn) {
|
|
hReturn = CheckImpersonationLevel();
|
|
}
|
|
// Check Registry security here.
|
|
if ((hReturn != S_OK) || (!HasPermission())) {
|
|
// if Impersonation level is incorrect or
|
|
// the caller doesn't have permission to read
|
|
// from the registry, then they cannot continue
|
|
hReturn = WBEM_E_ACCESS_DENIED;
|
|
}
|
|
|
|
if (hReturn == S_OK) {
|
|
|
|
pRef = (CNt5Refresher *) pRefresher;
|
|
|
|
bRes = pRef->RemoveObject(lId);
|
|
if (bRes == FALSE) {
|
|
hReturn = WBEM_E_FAILED;
|
|
} else {
|
|
hReturn = WBEM_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
// Revert if we successfuly impersonated the user
|
|
if ( fRevert )
|
|
{
|
|
CoRevertToSelf();
|
|
}
|
|
|
|
return hReturn;
|
|
}
|
|
|
|
HRESULT CNt5PerfProvider::CreateRefreshableEnum(
|
|
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
|
|
/* [string][in] */ LPCWSTR wszClass,
|
|
/* [in] */ IWbemRefresher __RPC_FAR *pRefresher,
|
|
/* [in] */ long lFlags,
|
|
/* [in] */ IWbemContext __RPC_FAR *pContext,
|
|
/* [in] */ IWbemHiPerfEnum __RPC_FAR *pHiPerfEnum,
|
|
/* [out] */ long __RPC_FAR *plId)
|
|
{
|
|
HRESULT hReturn;
|
|
|
|
hReturn = CoImpersonateClient(); // make sure we're legit.
|
|
|
|
BOOL fRevert = SUCCEEDED( hReturn );
|
|
|
|
// The following error appears to occur when we are in-proc and there is no
|
|
// proxy/stub, so we are effectively impersonating already
|
|
|
|
if ( RPC_E_CALL_COMPLETE == hReturn ) {
|
|
hReturn = S_OK;
|
|
}
|
|
|
|
if (S_OK == hReturn) {
|
|
hReturn = CheckImpersonationLevel();
|
|
}
|
|
// Check Registry security here.
|
|
if ((hReturn != S_OK) || (!HasPermission())) {
|
|
// if Impersonation level is incorrect or
|
|
// the caller doesn't have permission to read
|
|
// from the registry, then they cannot continue
|
|
hReturn = WBEM_E_ACCESS_DENIED;
|
|
}
|
|
|
|
if (hReturn == S_OK) {
|
|
|
|
hReturn = CreateRefresherObject(
|
|
pNamespace,
|
|
NULL,
|
|
pRefresher,
|
|
lFlags,
|
|
pContext,
|
|
wszClass,
|
|
pHiPerfEnum,
|
|
NULL,
|
|
plId);
|
|
}
|
|
|
|
// Revert if we successfuly impersonated the user
|
|
if ( fRevert )
|
|
{
|
|
CoRevertToSelf();
|
|
}
|
|
|
|
return hReturn;
|
|
}
|
|
|
|
HRESULT CNt5PerfProvider::GetObjects(
|
|
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
|
|
/* [in] */ long lNumObjects,
|
|
/* [size_is][in] */ IWbemObjectAccess __RPC_FAR *__RPC_FAR *apObj,
|
|
/* [in] */ long lFlags,
|
|
/* [in] */ IWbemContext __RPC_FAR *pContext)
|
|
{
|
|
DBG_UNREFERENCED_PARAMETER(pNamespace);
|
|
DBG_UNREFERENCED_PARAMETER(lNumObjects);
|
|
DBG_UNREFERENCED_PARAMETER(apObj);
|
|
DBG_UNREFERENCED_PARAMETER(lFlags);
|
|
DBG_UNREFERENCED_PARAMETER(pContext);
|
|
|
|
return WBEM_E_METHOD_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::MapClass
|
|
//
|
|
// Adds the class map to an internal cache.
|
|
//
|
|
// <pClsMap> The pointer to the map info to add. This pointer
|
|
// is acquired by this function and should not be
|
|
// deleted by the caller.
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
BOOL CNt5PerfProvider::AddClassMap(
|
|
IN CClassMapInfo *pClsMap
|
|
)
|
|
{
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
int i;
|
|
CClassMapInfo *pTracer;
|
|
int nNumElements;
|
|
BOOL bInCache = FALSE;
|
|
|
|
if (m_hClassMapMutex != 0) {
|
|
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hClassMapMutex, cdwClassMapTimeout)) {
|
|
nNumElements = m_aCache.Size();
|
|
|
|
// Because of a problem in which perflibs seem to ignore supported methods of updating
|
|
// the perflib names database (lodctr/unlodctr), do a quick initial traversal to ensure
|
|
// that we don't have any duplicate object indices, since this can cause real problems
|
|
// during adding and refreshing, since incorrect indexes can be returned.
|
|
|
|
for (i = 0; i < nNumElements; i++) {
|
|
pTracer = (CClassMapInfo *) m_aCache[i];
|
|
|
|
// We've got a problem -- we cannot add this class
|
|
if (pClsMap->m_dwObjectId == pTracer->m_dwObjectId )
|
|
{
|
|
if (m_PerfObject.CheckClassExist(pTracer->m_pszClassName, pTracer->m_pClassDef)) {
|
|
ReleaseMutex(m_hClassMapMutex);
|
|
return FALSE;
|
|
}
|
|
else {
|
|
m_PerfObject.RemoveClass(pTracer->m_pClassDef);
|
|
m_aCache.RemoveAt(i);
|
|
delete pTracer;
|
|
|
|
nNumElements = m_aCache.Size();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < nNumElements; i++) {
|
|
pTracer = (CClassMapInfo *) m_aCache[i];
|
|
if (_wcsicmp(pClsMap->m_pszClassName, pTracer->m_pszClassName) < 0) {
|
|
if( CFlexArray::no_error == m_aCache.InsertAt(i, pClsMap) ){
|
|
bInCache = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == nNumElements) {
|
|
// If here, add it to the end.
|
|
// ===========================
|
|
if( CFlexArray::no_error == m_aCache.Add(pClsMap) ){
|
|
bInCache = TRUE;
|
|
}
|
|
}
|
|
|
|
// make sure the library is in the list
|
|
if( bInCache ){
|
|
dwResult = m_PerfObject.AddClass (pClsMap->m_pClassDef, TRUE);
|
|
if( ERROR_SUCCESS != dwResult ){
|
|
m_aCache.Remove( pClsMap );
|
|
}
|
|
}else{
|
|
dwResult = ERROR_INVALID_BLOCK;
|
|
}
|
|
|
|
ReleaseMutex(m_hClassMapMutex);
|
|
} else {
|
|
dwResult = ERROR_LOCK_FAILED;
|
|
}
|
|
}
|
|
|
|
return (dwResult == ERROR_SUCCESS);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::FindClassMap
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
CClassMapInfo *CNt5PerfProvider::FindClassMap(
|
|
LPWSTR pszClassName
|
|
)
|
|
{
|
|
int l = 0;
|
|
int u;
|
|
int m;
|
|
CClassMapInfo *pClsMap;
|
|
CClassMapInfo *pClsMapReturn = NULL;
|
|
|
|
// Binary search the cache.
|
|
// ========================
|
|
if( NULL == pszClassName ){
|
|
return NULL;
|
|
}
|
|
|
|
if (m_hClassMapMutex != 0) {
|
|
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hClassMapMutex, cdwClassMapTimeout)) {
|
|
|
|
u = m_aCache.Size() - 1;
|
|
__try{
|
|
while (l <= u) {
|
|
m = (l + u) / 2;
|
|
|
|
pClsMap = (CClassMapInfo *) m_aCache[m];
|
|
|
|
if (pClsMap != NULL) {
|
|
if (_wcsicmp(pszClassName, pClsMap->m_pszClassName) < 0) {
|
|
u = m - 1;
|
|
} else if (_wcsicmp(pszClassName, pClsMap->m_pszClassName) > 0) {
|
|
l = m + 1;
|
|
} else { // Hit!
|
|
pClsMapReturn = pClsMap;
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
pClsMapReturn = NULL;
|
|
}
|
|
|
|
ReleaseMutex(m_hClassMapMutex);
|
|
}
|
|
}
|
|
return pClsMapReturn;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::MapClass
|
|
//
|
|
// Retrieves the requested class and places it in the cache.
|
|
//
|
|
// Parameters:
|
|
// pNs The namespace which contains the class definition.
|
|
// wsClass The class name.
|
|
// pCtx The inbound context object. Only used for reentrant
|
|
// calls.
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
BOOL CNt5PerfProvider::MapClass(
|
|
IN IWbemServices *pNs,
|
|
IN WCHAR *wszClass,
|
|
IN IWbemContext *pCtx
|
|
)
|
|
{
|
|
HRESULT hRes = 0;
|
|
BOOL bReturn = FALSE;
|
|
IWbemClassObject *pClsDef = 0;
|
|
IWbemQualifierSet *pQSet = 0;
|
|
VARIANT v;
|
|
CClassMapInfo *pMapInfo = 0;
|
|
CBSTR cbClass(wszClass);
|
|
CBSTR cbProvider(cszProvider);
|
|
|
|
if( NULL == (BSTR)cbClass ||
|
|
NULL == (BSTR)cbProvider ){
|
|
return FALSE;
|
|
}
|
|
|
|
if (m_hClassMapMutex != 0) {
|
|
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hClassMapMutex, cdwClassMapTimeout)) {
|
|
// See if the class is already in the cache.
|
|
// =========================================
|
|
if (FindClassMap(wszClass) != 0) {
|
|
// already loaded so quit now
|
|
bReturn = TRUE;
|
|
} else {
|
|
// Get the class definition from CIMOM.
|
|
// ====================================
|
|
hRes = pNs->GetObject( cbClass, 0, pCtx, &pClsDef, 0);
|
|
if (hRes == NO_ERROR) {
|
|
// Verify the class is one of ours by checking
|
|
// the "provider" qualifier to ensure it matches
|
|
// the name that we we have for this component.
|
|
// =============================================
|
|
hRes = pClsDef->GetQualifierSet(&pQSet);
|
|
if (hRes == NO_ERROR) {
|
|
VariantInit(&v);
|
|
hRes = pQSet->Get( cbProvider, 0, &v, 0);
|
|
pQSet->Release();
|
|
|
|
if ((hRes == NO_ERROR) && (v.vt == VT_BSTR)) {
|
|
if (_wcsicmp(V_BSTR(&v), cszProviderName) == 0) {
|
|
// Get the property handles and mappings to the perf counter ids
|
|
// by calling the Map() method of CClassMapInfo.
|
|
// ==============================================================
|
|
pMapInfo = new CClassMapInfo;
|
|
if (pMapInfo != NULL) {
|
|
if (pMapInfo->Map(pClsDef)) {
|
|
// Add it to the cache.
|
|
// ====================
|
|
bReturn = AddClassMap(pMapInfo);
|
|
if( !bReturn ){
|
|
delete pMapInfo;
|
|
}
|
|
} else {
|
|
// unable to add this to the cache
|
|
delete pMapInfo;
|
|
pMapInfo = NULL;
|
|
}
|
|
} else {
|
|
// inable to create new class
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
} else {
|
|
SetLastError ((DWORD)WBEM_E_INVALID_PROVIDER_REGISTRATION);
|
|
}
|
|
VariantClear(&v);
|
|
}
|
|
|
|
}
|
|
if( pMapInfo == NULL && pClsDef != NULL ){
|
|
pClsDef->Release();
|
|
}
|
|
}
|
|
ReleaseMutex(m_hClassMapMutex);
|
|
}
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::HasPermission
|
|
//
|
|
// tests to see if the caller has permission to access the functions
|
|
//
|
|
// Parameters:
|
|
// void N/A
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
BOOL CNt5PerfProvider::HasPermission (void)
|
|
{
|
|
DWORD dwStatus;
|
|
HKEY hKeyTest;
|
|
BOOL bReturn;
|
|
|
|
dwStatus = RegOpenKeyExW (
|
|
HKEY_LOCAL_MACHINE,
|
|
(LPCWSTR)L"Software\\Microsoft\\Windows NT\\CurrentVersion\\WbemPerf",
|
|
0, KEY_READ, &hKeyTest);
|
|
|
|
if ((dwStatus == ERROR_SUCCESS) || (dwStatus == ERROR_FILE_NOT_FOUND)) {
|
|
bReturn = TRUE;
|
|
if (dwStatus == ERROR_SUCCESS) RegCloseKey (hKeyTest);
|
|
} else {
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CNt5PerfProvider::CheckImpersonationLevel
|
|
//
|
|
// tests caller's security impersonation level for correct access
|
|
//
|
|
// Only call here if CoImpersonate worked.
|
|
//
|
|
// Parameters:
|
|
// void N/A
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
HRESULT CNt5PerfProvider::CheckImpersonationLevel (void)
|
|
{
|
|
HRESULT hr = WBEM_E_ACCESS_DENIED;
|
|
BOOL bReturn;
|
|
|
|
// Now, let's check the impersonation level. First, get the thread token
|
|
HANDLE hThreadTok;
|
|
DWORD dwImp, dwBytesReturned;
|
|
|
|
bReturn = OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&hThreadTok);
|
|
|
|
if (!bReturn) {
|
|
|
|
// If the CoImpersonate works, but the OpenThreadToken fails, we are running under the
|
|
// process token (either local system, or if we are running with /exe, the rights of
|
|
// the logged in user). In either case, impersonation rights don't apply. We have the
|
|
// full rights of that user.
|
|
|
|
hr = WBEM_S_NO_ERROR;
|
|
|
|
} else {
|
|
// We really do have a thread token, so let's retrieve its level
|
|
|
|
bReturn = GetTokenInformation(
|
|
hThreadTok,
|
|
TokenImpersonationLevel,
|
|
&dwImp,
|
|
sizeof(DWORD),
|
|
&dwBytesReturned);
|
|
|
|
if (bReturn) {
|
|
// Is the impersonation level Impersonate?
|
|
if ((dwImp == SecurityImpersonation) || (dwImp == SecurityDelegation)) {
|
|
hr = WBEM_S_NO_ERROR;
|
|
} else {
|
|
hr = WBEM_E_ACCESS_DENIED;
|
|
}
|
|
} else {
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
|
|
// Done with this handle
|
|
CloseHandle(hThreadTok);
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|