/*++ Copyright (C) 1997-1999 Microsoft Corporation 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 #include "oahelp.inl" #define __WBEMSECURITY 1 //*************************************************************************** // // 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 { 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. // // The current user. // Reserved. // The namespace for which we are being activated. // The locale under which we are to be running. // An active pointer back into the current namespace // from which we can retrieve schema objects. // The user's context object. We simply reuse this // during any reentrant operations into CIMOM. // 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: // A pointer to the relevant namespace. This // should not be AddRef'ed or retained past the // execution of this method. // The class name for which instances are required. // Reserved. // The user-supplied context (used during callbacks // into CIMOM). // 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); #ifdef __WBEMSECURITY 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; } #else hReturn = S_OK; #endif 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 } #ifdef __WBEMSECURITY // Revert if we successfuly impersonated the user if ( fRevert ) { CoRevertToSelf(); } #endif return hReturn; } //*************************************************************************** // // CNt5PerfProvider::CreateRefresher // // Called whenever a new refresher is needed by the client. // // Parameters: // A pointer to the relevant namespace. Not used. // Not used. // 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); #ifdef __WBEMSECURITY 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; } #else hReturn = S_OK; #endif 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; } } } #ifdef __WBEMSECURITY // Revert if we successfuly impersonated the user if ( fRevert ) { CoRevertToSelf(); } #endif return hReturn; } //*************************************************************************** // // CNt5PerfProvider::CreateRefresherObject // // Called whenever a user wants to include an object in a refresher. // // Parameters: // A pointer to the relevant namespace in CIMOM. // A pointer to a copy of the object which is to be // added. This object itself cannot be used, as // it not owned locally. // The refresher to which to add the object. // Not used. // Not used here. // A pointer to the internal object which was added // to the refresher. // 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; UNREFERENCED_PARAMETER(lFlags); 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(CBSTR(cszClassName), 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 (hReturn == NO_ERROR) { pNewCopy->Release(); // We don't need the IWbemClassObject interface any more // We now have an IWbemObjectAccess pointer for the refreshable // object in . // ============================================================ } } } 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 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 hReturn = GetLastError(); } } } } } VariantClear(&v); return hReturn; } //*************************************************************************** // // CNt5PerfProvider::CreateRefreshableObject // // Called whenever a user wants to include an object in a refresher. // // Parameters: // A pointer to the relevant namespace in CIMOM. // A pointer to a copy of the object which is to be // added. This object itself cannot be used, as // it not owned locally. // The refresher to which to add the object. // Not used. // Not used here. // A pointer to the internal object which was added // to the refresher. // 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; #ifdef __WBEMSECURITY 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; } #else hReturn = S_OK; #endif if (hReturn == S_OK) { hReturn = CreateRefresherObject( pNamespace, pTemplate, pRefresher, lFlags, pContext, NULL, NULL, ppRefreshable, plId); } #ifdef __WBEMSECURITY // Revert if we successfuly impersonated the user if ( fRevert ) { CoRevertToSelf(); } #endif return hReturn; } //*************************************************************************** // // CNt5PerfProvider::StopRefreshing // // Called whenever a user wants to remove an object from a refresher. // // Parameters: // The refresher object from which we are to // remove the perf object. // The ID of the object. // 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); #ifdef __WBEMSECURITY 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; } #else hReturn = S_OK; #endif if (hReturn == S_OK) { pRef = (CNt5Refresher *) pRefresher; bRes = pRef->RemoveObject(lId); if (bRes == FALSE) { hReturn = WBEM_E_FAILED; } else { hReturn = WBEM_NO_ERROR; } } #ifdef __WBEMSECURITY // Revert if we successfuly impersonated the user if ( fRevert ) { CoRevertToSelf(); } #endif 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; #ifdef __WBEMSECURITY 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; } #else hReturn = S_OK; #endif if (hReturn == S_OK) { hReturn = CreateRefresherObject( pNamespace, NULL, pRefresher, lFlags, pContext, wszClass, pHiPerfEnum, NULL, plId); } #ifdef __WBEMSECURITY // Revert if we successfuly impersonated the user if ( fRevert ) { CoRevertToSelf(); } #endif 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. // // 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; 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 ) { ReleaseMutex( m_hClassMapMutex ); return FALSE; } } for (i = 0; i < nNumElements; i++) { pTracer = (CClassMapInfo *) m_aCache[i]; if (_wcsicmp(pClsMap->m_pszClassName, pTracer->m_pszClassName) < 0) { m_aCache.InsertAt(i, pClsMap); break; } } if (i == nNumElements) { // If here, add it to the end. // =========================== m_aCache.Add(pClsMap); } // make sure the library is in the list dwResult = m_PerfObject.AddClass (pClsMap->m_pClassDef, TRUE); 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 (m_hClassMapMutex != 0) { if (WAIT_OBJECT_0 == WaitForSingleObject(m_hClassMapMutex, cdwClassMapTimeout)) { u = m_aCache.Size() - 1; 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; } } 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; 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(CBSTR(wszClass), 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(CBSTR(cszProvider), 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); } else { // unable to add this to the cache delete pMapInfo; //pClsDef->Release(); // this was not AddRef'd so no need to Release } } else { // inable to create new class bReturn = FALSE; } } else { // unable to read provider qualifier so bail // as this isn't a dynamic provider pClsDef->Release(); } } else { SetLastError ((DWORD)WBEM_E_INVALID_PROVIDER_REGISTRATION); } VariantClear(&v); } else { // unable to get qualifiers pClsDef->Release(); } } else { // Unable to retrieve the class definition } } 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; }