|
|
//***************************************************************************
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// PerfAcc.CPP
//
// Windows NT Performance Data Access helper functions
//
// bobw 8-Jub-98 Created for use with NT Perf counters
//
//***************************************************************************
//
#include "wpheader.h"
#include <stdlib.h>
#include "oahelp.inl"
//#include <malloc.h>
// NOTE: Consider reading this from the registry
LONG lExtCounterTestLevel = EXT_TEST_ALL;
LPCWSTR cszFirstCounter = L"First Counter"; LPCWSTR cszLastCounter = L"Last Counter";
//
//
// precompiled security descriptor
// System and NetworkService has full access
//
// since this is RELATIVE, it will work on both IA32 and IA64
//
DWORD g_PrecSD[] = { 0x80040001 , 0x00000044 , 0x00000050 , 0x00000000 , 0x00000014 , 0x00300002 , 0x00000002 , 0x00140000 , 0x001f0001 , 0x00000101 , 0x05000000 , 0x00000012 , 0x00140000 , 0x001f0001 , 0x00000101 , 0x05000000 , 0x00000014 , 0x00000101 , 0x05000000 , 0x00000014 , 0x00000101 , 0x05000000 , 0x00000014 };
DWORD g_SizeSD = 0;
DWORD g_RuntimeSD[(sizeof(ACL)+sizeof(ACCESS_ALLOWED_ACE)+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+4*(sizeof(SID)+SID_MAX_SUB_AUTHORITIES*sizeof(DWORD)))/sizeof(DWORD)];
typedef BOOLEAN ( * fnRtlValidRelativeSecurityDescriptor)( IN PSECURITY_DESCRIPTOR SecurityDescriptorInput, IN ULONG SecurityDescriptorLength, IN SECURITY_INFORMATION RequiredInformation );
fnRtlValidRelativeSecurityDescriptor RtlValidRelativeSecurityDescriptor;
//
// Build a SD with owner == This
// group == This
// DACL
// ACE[0] MUTEX_ALL_ACCESS Owner
// ACE[1] MUTEX_ALL_ACCESS System
///////////////////////////////////////////////////////////////////
BOOL CreateSD( ) { TOKEN_USER * pToken_User = NULL; SECURITY_DESCRIPTOR_RELATIVE * pLocalSD = NULL; PACL pDacl = NULL;
//
// Using GetProcAddress so that nt.h does not have to be included.
// Since WBEM and NT don't get along this function would need to
// be in a separate file.
//
if (! RtlValidRelativeSecurityDescriptor) { HMODULE hModule = GetModuleHandleW(L"ntdll.dll"); if (hModule) { RtlValidRelativeSecurityDescriptor = (fnRtlValidRelativeSecurityDescriptor)GetProcAddress(hModule,"RtlValidRelativeSecurityDescriptor"); if (! RtlValidRelativeSecurityDescriptor) { return FALSE; } } }
HANDLE hToken; BOOL bRet; bRet = OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken); if (bRet) { DWORD dwSize = sizeof(TOKEN_USER)+sizeof(SID)+(SID_MAX_SUB_AUTHORITIES*sizeof(DWORD)); pToken_User = (TOKEN_USER *)ALLOCMEM( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize); if( NULL == pToken_User ){ bRet = FALSE; goto cleanup; } bRet = GetTokenInformation(hToken,TokenUser,pToken_User,dwSize,&dwSize); if (bRet) { SID SystemSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID }; PSID pSIDUser = pToken_User->User.Sid; dwSize = GetLengthSid(pSIDUser); DWORD dwSids = 2; // Owner and System
DWORD ACLLength = (ULONG) sizeof(ACL) + (dwSids * ((ULONG) sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) + dwSize + sizeof(SystemSid);
DWORD dwSizeSD = sizeof(SECURITY_DESCRIPTOR_RELATIVE) + dwSize + dwSize + ACLLength; pLocalSD = (SECURITY_DESCRIPTOR_RELATIVE *)ALLOCMEM(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSizeSD); if( NULL == pLocalSD ){ bRet = FALSE; goto cleanup; } memset(pLocalSD,0,sizeof(SECURITY_DESCRIPTOR_RELATIVE)); pLocalSD->Revision = SECURITY_DESCRIPTOR_REVISION; pLocalSD->Control = SE_DACL_PRESENT|SE_SELF_RELATIVE; //SetSecurityDescriptorOwner(pLocalSD,pSIDUser,FALSE);
memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE),pSIDUser,dwSize); pLocalSD->Owner = (DWORD)sizeof(SECURITY_DESCRIPTOR_RELATIVE); //SetSecurityDescriptorGroup(pLocalSD,pSIDUser,FALSE);
memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize,pSIDUser,dwSize); pLocalSD->Group = (DWORD)(sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize);
pDacl = (PACL)ALLOCMEM(GetProcessHeap(), HEAP_ZERO_MEMORY, ACLLength); if( NULL == pDacl ){ bRet = FALSE; goto cleanup; }
bRet = InitializeAcl( pDacl, ACLLength, ACL_REVISION); if (bRet) { bRet = AddAccessAllowedAceEx (pDacl,ACL_REVISION,0,MUTEX_ALL_ACCESS,&SystemSid); if (bRet) { bRet = AddAccessAllowedAceEx (pDacl,ACL_REVISION,0,MUTEX_ALL_ACCESS,pSIDUser); if (bRet) { //bRet = SetSecurityDescriptorDacl(pLocalSD,TRUE,pDacl,FALSE);
memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize+dwSize,pDacl,ACLLength); pLocalSD->Dacl = (DWORD)(sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize+dwSize);
if (RtlValidRelativeSecurityDescriptor(pLocalSD, dwSizeSD, OWNER_SECURITY_INFORMATION| GROUP_SECURITY_INFORMATION| DACL_SECURITY_INFORMATION)) { g_SizeSD = dwSizeSD; memcpy(g_RuntimeSD,pLocalSD,dwSizeSD); } else { bRet = FALSE; } } } } } CloseHandle(hToken); }
cleanup: if( NULL != pToken_User ){ FREEMEM(GetProcessHeap(), 0, pToken_User ); } if( NULL != pLocalSD ){ FREEMEM(GetProcessHeap(), 0, pLocalSD ); } if( NULL != pDacl ){ FREEMEM(GetProcessHeap(), 0, pDacl ); }
return bRet; };
//***************************************************************************
//
// HANDLE CreateMutexAsProcess(LPCWSTR pwszName)
//
// This function will create a mutex using the process' security context
//
//***************************************************************************
//
HANDLE CreateMutexAsProcess(LPCWSTR pwszName) { BOOL bImpersonating = FALSE;
HANDLE hThreadToken = NULL;
// Determine if we are impersonating
bImpersonating = OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &hThreadToken); if(bImpersonating) { // Determine if we are impersonating
bImpersonating = RevertToSelf(); }
// Create the mutex as using the process token.
HANDLE hRet = OpenMutexW(MUTEX_ALL_ACCESS,FALSE,pwszName); if (NULL == hRet) { SECURITY_ATTRIBUTES sa; if (0 == g_SizeSD) { if (CreateSD()) { sa.nLength = g_SizeSD; sa.lpSecurityDescriptor = (LPVOID)g_RuntimeSD; sa.bInheritHandle = FALSE; } else { sa.nLength = sizeof(g_PrecSD); sa.lpSecurityDescriptor = (LPVOID)g_PrecSD; sa.bInheritHandle = FALSE; } } else { sa.nLength = g_SizeSD; sa.lpSecurityDescriptor = (LPVOID)g_RuntimeSD; sa.bInheritHandle = FALSE; }
hRet = CreateMutexW(&sa, FALSE, pwszName); }
// If code was oringinally impersonating, resume impersonation
if(bImpersonating){ BOOL bRes = SetThreadToken(NULL, hThreadToken); }
if(hThreadToken) CloseHandle(hThreadToken);
return hRet; }
//***************************************************************************
//
// CPerfDataLibrary ::CPerfDataLibrary
//
// This object is used to abstract the perf data library
//
//***************************************************************************
//
CPerfDataLibrary::CPerfDataLibrary (void) { pLibInfo = NULL; memset ((LPVOID)szQueryString, 0, sizeof(szQueryString)); dwRefCount = 0; // number of classes referencing this object
}
CPerfDataLibrary::~CPerfDataLibrary (void) { // all libraries should be closed before this is
// destructed
assert (dwRefCount == 0); assert (pLibInfo == NULL); }
//***************************************************************************
//
// CPerfObjectAccess::CPerfObjectAccess
//
// This object is used to abstract a data object within a perf library
//
//***************************************************************************
//
CPerfObjectAccess::CPerfObjectAccess () { m_hObjectHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0x10000, 0); if (m_hObjectHeap == NULL) { // then just use the process heap
m_hObjectHeap = GetProcessHeap(); }
m_aLibraries.Empty(); lEventLogLevel = LOG_UNDEFINED; hEventLog = NULL; }
CPerfObjectAccess::~CPerfObjectAccess () { int nNumLibraries; int nIdx;
CPerfDataLibrary *pThisLibrary;
// close any lingering libraries
nNumLibraries = m_aLibraries.Size(); for (nIdx = 0; nIdx < nNumLibraries; nIdx++) { pThisLibrary = (CPerfDataLibrary *)m_aLibraries[nIdx]; CloseLibrary (pThisLibrary); FREEMEM(m_hObjectHeap, 0, pThisLibrary->pLibInfo); pThisLibrary->pLibInfo = NULL; delete pThisLibrary; } m_aLibraries.Empty();
if ((m_hObjectHeap != NULL) && (m_hObjectHeap != GetProcessHeap())) { HeapDestroy (m_hObjectHeap); } }
//***************************************************************************
//
// CPerfObjectAccess::CloseLibrary (CPerfDataLibrary *pLib)
//
// removes a reference to the library that contains this object and closes
// the library when the last reference is removed
//
//***************************************************************************
//
DWORD CPerfObjectAccess::CloseLibrary (CPerfDataLibrary *pLib) { pExtObject pInfo; LONG lStatus;
assert (pLib != NULL); assert (pLib->pLibInfo != NULL); pInfo = pLib->pLibInfo;
assert (pLib->dwRefCount > 0); if (pLib->dwRefCount > 0) { pLib->dwRefCount--;
if (pLib->dwRefCount == 0) { // if there's a close proc to call, then
// call close procedure to close anything that may have
// been allocated by the library
if (pInfo->hMutex != NULL){ lStatus = WaitForSingleObject ( pInfo->hMutex, pInfo->dwOpenTimeout);
if ( lStatus != WAIT_TIMEOUT ){ if( pInfo->CloseProc != NULL ){ __try{ lStatus = (*pInfo->CloseProc) (); } __except (EXCEPTION_EXECUTE_HANDLER) { lStatus = ERROR_INVALID_FUNCTION; } } ReleaseMutex(pInfo->hMutex); } else { pInfo->dwLockoutCount++; } } else { lStatus = ERROR_LOCK_FAILED; }
// then close everything
if (pInfo->hMutex != NULL) { CloseHandle (pInfo->hMutex); pInfo->hMutex = NULL; } if (pInfo->hLibrary != NULL) { FreeLibrary (pInfo->hLibrary); pInfo->hLibrary = NULL; } if (pInfo->hPerfKey != NULL) { RegCloseKey (pInfo->hPerfKey); pInfo->hPerfKey = NULL; } } } return pLib->dwRefCount; // returns remaining references
}
//***************************************************************************
//
// CPerfObjectAccess::OpenExtObjectLibrary (pExtObject pObj)
//
// OpenExtObjectLibrary
//
// Opens the specified library and looks up the functions used by
// the performance library. If the library is successfully
// loaded and opened then the open procedure is called to initialize
// the object.
//
// This function expects locked and exclusive access to the object while
// it is opening. This must be provided by the calling function.
//
// Arguments:
//
// pObj -- pointer to the object information structure of the
// perf object to close
//
//***************************************************************************
//
DWORD CPerfObjectAccess::OpenExtObjectLibrary (pExtObject pObj) { DWORD Status = ERROR_SUCCESS; DWORD dwOpenEvent = 0; DWORD dwType; DWORD dwSize; DWORD dwValue;
// variables used for event logging
DWORD dwDataIndex; WORD wStringIndex; DWORD dwRawDataDwords[8]; LPWSTR szMessageArray[8];
UINT nErrorMode;
// check to see if the library has already been opened
if (pObj->hLibrary == NULL) { // library isn't loaded yet, so
// check to see if this function is enabled
dwType = 0; dwSize = sizeof (dwValue); dwValue = 0; Status = RegQueryValueExW ( pObj->hPerfKey, cszDisablePerformanceCounters, NULL, &dwType, (LPBYTE)&dwValue, &dwSize);
if ((Status == ERROR_SUCCESS) && (dwType == REG_DWORD) && (dwValue == 1)) { // then DON'T Load this library
Status = ERROR_SERVICE_DISABLED; } else { Status = ERROR_SUCCESS; // go ahead and load it
nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS); // then load library & look up functions
pObj->hLibrary = LoadLibraryExW (pObj->szLibraryName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (pObj->hLibrary != NULL) { const size_t cchSize = 512; WCHAR buffer[cchSize]; // lookup function names
pObj->OpenProc = (OPENPROC)GetProcAddress( pObj->hLibrary, pObj->szOpenProcName); if (pObj->OpenProc == NULL) { if (lEventLogLevel >= LOG_USER) { Status = GetLastError(); // load data for eventlog message
dwDataIndex = wStringIndex = 0; dwRawDataDwords[dwDataIndex++] = (DWORD)Status; szMessageArray[wStringIndex++] = ConvertProcName(pObj->szOpenProcName, buffer, cchSize); szMessageArray[wStringIndex++] = pObj->szLibraryName; szMessageArray[wStringIndex++] = pObj->szServiceName;
ReportEventW (hEventLog, EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_OPEN_PROC_NOT_FOUND, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
} }
if (Status == ERROR_SUCCESS) { if (pObj->dwFlags & PERF_EO_QUERY_FUNC) { pObj->QueryProc = (QUERYPROC)GetProcAddress ( pObj->hLibrary, pObj->szCollectProcName); pObj->CollectProc = (COLLECTPROC)pObj->QueryProc; } else { pObj->CollectProc = (COLLECTPROC)GetProcAddress ( pObj->hLibrary, pObj->szCollectProcName); pObj->QueryProc = (QUERYPROC)pObj->CollectProc; }
if (pObj->CollectProc == NULL) { if (lEventLogLevel >= LOG_USER) { Status = GetLastError(); // load data for eventlog message
dwDataIndex = wStringIndex = 0; dwRawDataDwords[dwDataIndex++] = (DWORD)Status; szMessageArray[wStringIndex++] = ConvertProcName(pObj->szCollectProcName, buffer, cchSize ); szMessageArray[wStringIndex++] = pObj->szLibraryName; szMessageArray[wStringIndex++] = pObj->szServiceName;
ReportEventW (hEventLog, EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_COLLECT_PROC_NOT_FOUND, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
} } }
if (Status == ERROR_SUCCESS) { pObj->CloseProc = (CLOSEPROC)GetProcAddress ( pObj->hLibrary, pObj->szCloseProcName);
if (pObj->CloseProc == NULL) { if (lEventLogLevel >= LOG_USER) { Status = GetLastError(); // load data for eventlog message
dwDataIndex = wStringIndex = 0; dwRawDataDwords[dwDataIndex++] = (DWORD)Status; szMessageArray[wStringIndex++] = ConvertProcName(pObj->szCloseProcName, buffer, cchSize); szMessageArray[wStringIndex++] = pObj->szLibraryName; szMessageArray[wStringIndex++] = pObj->szServiceName;
ReportEventW (hEventLog, EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_CLOSE_PROC_NOT_FOUND, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
} } }
if (Status == ERROR_SUCCESS) { __try {
// call open procedure to initialize DLL
if (pObj->hMutex != NULL) { Status = WaitForSingleObject ( pObj->hMutex, pObj->dwOpenTimeout);
if (Status != WAIT_TIMEOUT){ if( pObj->OpenProc != NULL ) { Status = (*pObj->OpenProc)(pObj->szLinkageString); } ReleaseMutex(pObj->hMutex); } else { pObj->dwLockoutCount++; } } else { Status = ERROR_LOCK_FAILED; }
// check the result.
if (Status != ERROR_SUCCESS) { dwOpenEvent = WBEMPERF_OPEN_PROC_FAILURE; } else { InterlockedIncrement((LONG *)&pObj->dwOpenCount); } } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); dwOpenEvent = WBEMPERF_OPEN_PROC_EXCEPTION; }
if (Status != ERROR_SUCCESS) { // load data for eventlog message
dwDataIndex = wStringIndex = 0; dwRawDataDwords[dwDataIndex++] = (DWORD)Status; szMessageArray[wStringIndex++] = pObj->szServiceName; szMessageArray[wStringIndex++] = pObj->szLibraryName;
ReportEventW (hEventLog, (WORD)EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
dwOpenEvent, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
} }
if (Status != ERROR_SUCCESS) { // clear fields
pObj->OpenProc = NULL; pObj->CollectProc = NULL; pObj->QueryProc = NULL; pObj->CloseProc = NULL; if (pObj->hLibrary != NULL) { FreeLibrary (pObj->hLibrary); pObj->hLibrary = NULL; } } else { pObj->llLastUsedTime = GetTimeAsLongLong(); } } else { Status = GetLastError(); } SetErrorMode (nErrorMode); } } else { // else already open so bump the ref count
pObj->llLastUsedTime = GetTimeAsLongLong(); }
if( ERROR_SUCCESS != Status ){ if( ERROR_ACCESS_DENIED == Status ){ InterlockedExchange( (LONG*)&(pObj->ADThreadId), GetCurrentThreadId() ); }else{ InterlockedIncrement( (LONG*)&(pObj->dwOpenFail) ); } }else{ InterlockedExchange( (LONG*)&(pObj->dwOpenFail), 0 ); InterlockedExchange( (LONG*)&(pObj->ADThreadId), 0 ); } return Status; }
//***************************************************************************
//
// CPerfObjectAccess::AddLibrary (
// IWbemClassObject *pClass,
// IWbemQualifierSet *pClassQualifiers,
// LPCWSTR szRegistryKey,
// DWORD dwPerfIndex)
//
// Adds the library referenced by the class object to the list of
// libraries to call
//
//***************************************************************************
//
DWORD CPerfObjectAccess::AddLibrary ( IWbemClassObject *pClass, IWbemQualifierSet *pClassQualifiers, LPCWSTR szRegistryKey, DWORD dwPerfIndex) { CPerfDataLibrary *pLibEntry = NULL; LONG Status = ERROR_SUCCESS; HKEY hServicesKey = NULL; HKEY hPerfKey = NULL; LPWSTR szServiceName = NULL;
HKEY hKeyLinkage;
BOOL bUseQueryFn = FALSE;
pExtObject pReturnObject = NULL;
DWORD dwType = 0; DWORD dwSize = 0; DWORD dwFlags = 0; DWORD dwKeep; DWORD dwObjectArray[MAX_PERF_OBJECTS_IN_QUERY_FUNCTION]; DWORD dwObjIndex = 0; DWORD dwMemBlockSize = sizeof(ExtObject); DWORD dwLinkageStringLen = 0; DWORD dwFirstCounter = 2; DWORD dwLastCounter = 1846;
const size_t cchSize = WBEMPERF_STRING_SIZE; size_t StorageSizeA = cchSize * 3 * sizeof(CHAR); size_t StorageSizeW = cchSize * 9 * sizeof(WCHAR); LPSTR szStorageA = NULL; LPWSTR szStorageW = NULL; LPSTR szOpenProcName; LPSTR szCollectProcName; LPSTR szCloseProcName; LPWSTR szLibraryString; LPWSTR szLibraryExpPath; LPWSTR mszObjectList; LPWSTR szLinkageKeyPath; LPWSTR szLinkageString;
DWORD dwOpenTimeout = 0; DWORD dwCollectTimeout = 0;
LPWSTR szThisObject; LPWSTR szThisChar;
LPSTR pNextStringA; LPWSTR pNextStringW;
LPWSTR szServicePath; LPWSTR szMutexName; WCHAR szPID[32];
szStorageW = (LPWSTR)ALLOCMEM(m_hObjectHeap, HEAP_ZERO_MEMORY, StorageSizeW ); szStorageA = (LPSTR)ALLOCMEM(m_hObjectHeap, HEAP_ZERO_MEMORY, StorageSizeA );
if( NULL == szStorageA || NULL == szStorageW ){ Status = ERROR_OUTOFMEMORY; goto cleanup; }else{ pNextStringA = szStorageA; pNextStringW = szStorageW;
szOpenProcName = pNextStringA; pNextStringA += cchSize; szCollectProcName = pNextStringA; pNextStringA += cchSize; szCloseProcName = pNextStringA;
szLibraryString = pNextStringW; pNextStringW += cchSize; szLibraryExpPath = pNextStringW; pNextStringW += cchSize; mszObjectList = pNextStringW; pNextStringW += cchSize; szLinkageKeyPath = pNextStringW; pNextStringW += cchSize; szLinkageString = pNextStringW; pNextStringW += cchSize; szServicePath = pNextStringW; pNextStringW += cchSize; szMutexName = pNextStringW; }
assert(pClass != NULL); assert(pClassQualifiers != NULL);
UNREFERENCED_PARAMETER(pClassQualifiers); UNREFERENCED_PARAMETER(pClass);
pLibEntry = new CPerfDataLibrary; if ((pLibEntry != NULL) && (szRegistryKey != NULL)) {
StringCchCopyW(szServicePath, cchSize, cszHklmServicesKey);
Status = RegOpenKeyExW (HKEY_LOCAL_MACHINE, szServicePath, 0, KEY_READ, &hServicesKey);
if (Status == ERROR_SUCCESS) { StringCchCopyW(szServicePath, cchSize, szRegistryKey); StringCchCatW(szServicePath, cchSize, cszPerformance); Status = RegOpenKeyExW (hServicesKey, szServicePath, 0, KEY_READ, &hPerfKey);
if (Status == ERROR_SUCCESS) { szServiceName = (LPWSTR)szRegistryKey;
// read the performance DLL name
dwType = 0; dwSize = cchSize * sizeof(WCHAR);
Status = RegQueryValueExW (hPerfKey, cszDLLValue, NULL, &dwType, (LPBYTE)szLibraryString, &dwSize); } }
if (Status == ERROR_SUCCESS) { if (dwType == REG_EXPAND_SZ) { // expand any environment vars
dwSize = ExpandEnvironmentStringsW( szLibraryString, szLibraryExpPath, cchSize);
if ((dwSize > WBEMPERF_STRING_SIZE) || (dwSize == 0)) { Status = ERROR_INVALID_DLL; } else { dwSize += 1; dwSize *= sizeof(WCHAR); dwMemBlockSize += DWORD_MULTIPLE(dwSize); } } else if (dwType == REG_SZ) { // look for dll and save full file Path
dwSize = SearchPathW ( NULL, // use standard system search path
szLibraryString, NULL, WBEMPERF_STRING_SIZE, szLibraryExpPath, NULL);
if ((dwSize > WBEMPERF_STRING_SIZE) || (dwSize == 0)) { Status = ERROR_INVALID_DLL; } else { dwSize += 1; dwSize *= sizeof(WCHAR); dwMemBlockSize += DWORD_MULTIPLE(dwSize); } } else { Status = ERROR_INVALID_DLL; }
if (Status == ERROR_SUCCESS) { // we have the DLL name so get the procedure names
dwType = 0; dwSize = cchSize * sizeof(CHAR);
Status = RegQueryValueExA (hPerfKey, caszOpenValue, NULL, &dwType, (LPBYTE)szOpenProcName, &dwSize); }
if (Status == ERROR_SUCCESS) { // add in size of previous string
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
// we have the procedure name so get the timeout value
dwType = 0; dwSize = cchSize * sizeof(WCHAR); Status = RegQueryValueExW (hPerfKey, cszOpenTimeout, NULL, &dwType, (LPBYTE)&dwOpenTimeout, &dwSize);
// if error, then apply default
if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) { dwOpenTimeout = dwExtCtrOpenProcWaitMs; Status = ERROR_SUCCESS; }
}
if (Status == ERROR_SUCCESS) { // add in size of previous string
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
// we have the procedure name so get the timeout value
dwType = 0; dwSize = sizeof(dwFirstCounter); Status = RegQueryValueExW (hPerfKey, cszFirstCounter, NULL, & dwType, (LPBYTE) & dwFirstCounter, & dwSize);
// if error, then apply default
if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) { dwFirstCounter = 2; // assume this is for system base counters
Status = ERROR_SUCCESS; }
}
if (Status == ERROR_SUCCESS) { // add in size of previous string
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
// we have the procedure name so get the timeout value
dwType = 0; dwSize = sizeof(dwLastCounter); Status = RegQueryValueExW (hPerfKey, cszLastCounter, NULL, & dwType, (LPBYTE) & dwLastCounter, & dwSize);
// if error, then apply default
if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) { dwLastCounter = 1846; // assume this is for system base counters
Status = ERROR_SUCCESS; }
}
if (Status == ERROR_SUCCESS) { // get next string
dwType = 0; dwSize = cchSize * sizeof(CHAR); Status = RegQueryValueExA (hPerfKey, caszCloseValue, NULL, &dwType, (LPBYTE)szCloseProcName, &dwSize); }
if (Status == ERROR_SUCCESS) { // add in size of previous string
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
// try to look up the query function which is the
// preferred interface if it's not found, then
// try the collect function name. If that's not found,
// then bail
dwType = 0; dwSize = cchSize * sizeof(CHAR); Status = RegQueryValueExA (hPerfKey, caszQueryValue, NULL, &dwType, (LPBYTE)szCollectProcName, &dwSize);
if (Status == ERROR_SUCCESS) { // add in size of the Query Function Name
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize); // get next string
bUseQueryFn = TRUE; // the query function can support a static object list
// so look it up
} else { // the QueryFunction wasn't found so look up the
// Collect Function name instead
dwType = 0; dwSize = cchSize * sizeof(CHAR); Status = RegQueryValueExA (hPerfKey, caszCollectValue, NULL, &dwType, (LPBYTE)szCollectProcName, &dwSize);
if (Status == ERROR_SUCCESS) { // add in size of Collect Function Name
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize); } }
if (Status == ERROR_SUCCESS) { // we have the procedure name so get the timeout value
dwType = 0; dwSize = sizeof(dwCollectTimeout); Status = RegQueryValueExW (hPerfKey, cszCollectTimeout, NULL, &dwType, (LPBYTE)&dwCollectTimeout, &dwSize);
// if error, then apply default
if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) { dwCollectTimeout = dwExtCtrOpenProcWaitMs; Status = ERROR_SUCCESS; }
} // get the list of supported objects if provided by the registry
dwType = 0; dwSize = cchSize * sizeof(WCHAR); Status = RegQueryValueExW (hPerfKey, cszObjListValue, NULL, &dwType, (LPBYTE)mszObjectList, &dwSize);
if (Status == ERROR_SUCCESS) { if (dwType != REG_MULTI_SZ) { size_t cch; // convert space delimited list to msz
for (szThisChar = mszObjectList, cch = 0; *szThisChar != 0 && cch < cchSize; szThisChar++, cch++) { if (*szThisChar == L' ') *szThisChar = L'\0'; } ++szThisChar; *szThisChar = 0; // add MSZ term Null
} for (szThisObject = mszObjectList, dwObjIndex = 0; (*szThisObject != 0) && (dwObjIndex < MAX_PERF_OBJECTS_IN_QUERY_FUNCTION); szThisObject += lstrlenW(szThisObject) + 1) { dwObjectArray[dwObjIndex] = wcstoul(szThisObject, NULL, 10); dwObjIndex++; } if (*szThisObject != 0) { DWORD dwDataIndex = 0; WORD wStringIndex = 0; DWORD dwRawDataDwords[8]; LPWSTR szMessageArray[8]; dwRawDataDwords[dwDataIndex++] = (DWORD) ERROR_SUCCESS; szMessageArray[wStringIndex++] = (LPWSTR) cszObjListValue; szMessageArray[wStringIndex++] = szLibraryString; szMessageArray[wStringIndex++] = szServicePath;
ReportEventW(hEventLog, EVENTLOG_WARNING_TYPE, 0, (DWORD) WBEMPERF_TOO_MANY_OBJECT_IDS, NULL, wStringIndex, dwDataIndex * sizeof(DWORD), (LPCWSTR *) szMessageArray, (LPVOID) & dwRawDataDwords[0]); } } else { // reset status since not having this is
// not a showstopper
Status = ERROR_SUCCESS; }
if (Status == ERROR_SUCCESS) { dwType = 0; dwKeep = 0; dwSize = sizeof(dwKeep); Status = RegQueryValueExW (hPerfKey, cszKeepResident, NULL, &dwType, (LPBYTE)&dwKeep, &dwSize);
if ((Status == ERROR_SUCCESS) && (dwType == REG_DWORD)) { if (dwKeep == 1) { dwFlags |= PERF_EO_KEEP_RESIDENT; } else { // no change.
} } else { // not fatal, just use the defaults.
Status = ERROR_SUCCESS; }
} } }
if (Status == ERROR_SUCCESS) {
StringCchCopyW( szLinkageKeyPath, cchSize, szServiceName); StringCchCatW( szLinkageKeyPath, cchSize, cszLinkageKey);
Status = RegOpenKeyExW ( hServicesKey, szLinkageKeyPath, 0L, KEY_READ, &hKeyLinkage);
if (Status == ERROR_SUCCESS) { // look up export value string
dwSize = sizeof(szLinkageString); dwType = 0; Status = RegQueryValueExW ( hKeyLinkage, cszExportValue, NULL, &dwType, (LPBYTE)&szLinkageString, &dwSize);
if ((Status != ERROR_SUCCESS) || ((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))) { // clear buffer
dwLinkageStringLen = 0;
// not finding a linkage key is not fatal so correct
// status
Status = ERROR_SUCCESS; } else { // add size of linkage string to buffer
// the size value includes the Term. NULL
dwLinkageStringLen = dwSize; dwMemBlockSize += DWORD_MULTIPLE(dwSize); }
RegCloseKey (hKeyLinkage); } else { // not finding a linkage key is not fatal so correct
// status
Status = ERROR_SUCCESS; } }
if (Status == ERROR_SUCCESS) { size_t cbDestSize; // add in size of service name
dwSize = lstrlenW (szServiceName); dwSize += 1; dwSize *= sizeof(WCHAR); dwMemBlockSize += DWORD_MULTIPLE(dwSize); cbDestSize = dwMemBlockSize - sizeof(pExtObject); // allocate and initialize a new ext. object block
pReturnObject = (pExtObject)ALLOCMEM(m_hObjectHeap, HEAP_ZERO_MEMORY, dwMemBlockSize);
if (pReturnObject != NULL) { // copy values to new buffer (all others are NULL)
pNextStringA = (LPSTR)&pReturnObject[1];
// copy Open Procedure Name
pReturnObject->szOpenProcName = pNextStringA; StringCbCopyA( pNextStringA, cbDestSize, szOpenProcName );
pNextStringA += lstrlenA (pNextStringA) + 1; pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA); cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringA - (PUCHAR)pReturnObject); pReturnObject->dwOpenTimeout = dwOpenTimeout;
// copy collect function or query function, depending
pReturnObject->szCollectProcName = pNextStringA; StringCbCopyA(pNextStringA, cbDestSize, szCollectProcName);
pNextStringA += lstrlenA (pNextStringA) + 1; pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA); cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringA - (PUCHAR)pReturnObject);
pReturnObject->dwCollectTimeout = dwCollectTimeout;
// copy Close Procedure Name
pReturnObject->szCloseProcName = pNextStringA; StringCbCopyA(pNextStringA, cbDestSize, szCloseProcName);
pNextStringA += lstrlenA (pNextStringA) + 1; pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA); cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringA - (PUCHAR)pReturnObject);
// copy Library path
pNextStringW = (LPWSTR)pNextStringA; pReturnObject->szLibraryName = pNextStringW; StringCbCopyW(pNextStringW, cbDestSize, szLibraryExpPath);
pNextStringW += lstrlenW (pNextStringW) + 1; pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW); cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringW - (PUCHAR)pReturnObject);
// copy Linkage String if there is one
if (*szLinkageString != 0) { pReturnObject->szLinkageString = pNextStringW; if( cbDestSize > dwLinkageStringLen ){ memcpy (pNextStringW, szLinkageString, dwLinkageStringLen);
// length includes extra NULL char and is in BYTES
pNextStringW += (dwLinkageStringLen / sizeof (WCHAR)); pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW); cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringW - (PUCHAR)pReturnObject); } }
// copy Service name
pReturnObject->szServiceName = pNextStringW; StringCbCopyW(pNextStringW, cbDestSize, szServiceName);
pNextStringW += lstrlenW (pNextStringW) + 1; pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW); cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringW - (PUCHAR)pReturnObject);
// load flags
if (bUseQueryFn) { dwFlags |= PERF_EO_QUERY_FUNC; } pReturnObject->dwFlags = dwFlags;
pReturnObject->hPerfKey = hPerfKey; hPerfKey = NULL;
// load Object array
if (dwObjIndex > 0) { pReturnObject->dwNumObjects = dwObjIndex; memcpy (pReturnObject->dwObjList, dwObjectArray, (dwObjIndex * sizeof(dwObjectArray[0]))); } pReturnObject->dwFirstCounter = dwFirstCounter; pReturnObject->dwLastCounter = dwLastCounter; pReturnObject->llLastUsedTime = 0;
// create Mutex name
StringCchCopyW(szMutexName, cchSize, szRegistryKey); StringCchCatW( szMutexName, cchSize, (LPCWSTR)L"_Perf_Library_Lock_PID_"); _ultow ((ULONG)GetCurrentProcessId(), szPID, 16); StringCchCatW( szMutexName, cchSize, szPID);
// pReturnObject->hMutex = CreateMutexW (NULL, FALSE, szMutexName);
pReturnObject->hMutex = CreateMutexAsProcess(szMutexName); } else { Status = ERROR_OUTOFMEMORY; } }
if (Status != ERROR_SUCCESS) { SetLastError (Status); if (pReturnObject != NULL) { // release the new block
hPerfKey = pReturnObject->hPerfKey; FREEMEM (m_hObjectHeap, 0, pReturnObject); } } else { if (pReturnObject != NULL) { Status = OpenExtObjectLibrary (pReturnObject); if (Status == ERROR_SUCCESS) { if (dwPerfIndex != 0) { // initialize the perf index string
_ultow (dwPerfIndex, pLibEntry->szQueryString, 10); } else { StringCchCopyW(pLibEntry->szQueryString, MAX_PERF_OBJECTS_IN_QUERY_FUNCTION * 10, cszGlobal); } // save the pointer to the initialize structure
pLibEntry->pLibInfo = pReturnObject; m_aLibraries.Add(pLibEntry); pLibEntry->dwRefCount++; assert(pLibEntry->dwRefCount == 1); } else { // release the new block
hPerfKey = pReturnObject->hPerfKey; FREEMEM (m_hObjectHeap, 0, pReturnObject); } } }
if (hServicesKey != NULL) RegCloseKey (hServicesKey); } else { // gets here if pLibEntry == NULL and/or szRegistryKey == NULL
if (pLibEntry == NULL) { Status = ERROR_OUTOFMEMORY; } if (szRegistryKey == NULL) { Status = ERROR_INVALID_PARAMETER; } } if ((Status != ERROR_SUCCESS) && (pLibEntry != NULL)) delete pLibEntry;
cleanup: if( hPerfKey != NULL ){ RegCloseKey( hPerfKey ); } FREEMEM (m_hObjectHeap, 0, szStorageA ); FREEMEM (m_hObjectHeap, 0, szStorageW );
return Status; }
//***************************************************************************
//
// CPerfObjectAccess::AddClass (IWbemClassObject *pClass, BOOL bCatalogQuery)
//
// Adds the specified WBEM performance object class and any required library
// entries to the access object.
//
//***************************************************************************
//
DWORD CPerfObjectAccess::AddClass (IWbemClassObject *pClass, BOOL bCatalogQuery) { CPerfDataLibrary *pLibEntry = NULL; CPerfDataLibrary *pThisLibEntry = NULL; DWORD dwIndex, dwEnd; LPWSTR szRegistryKey = NULL; IWbemQualifierSet *pClassQualifiers = NULL; VARIANT vRegistryKey; HRESULT hRes; DWORD dwReturn = ERROR_SUCCESS; DWORD dwPerfIndex = 0;
CBSTR cbPerfIndex(cszPerfIndex); CBSTR cbRegistryKey(cszRegistryKey); if( NULL == (BSTR)cbPerfIndex || NULL == (BSTR)cbRegistryKey ){ return ERROR_OUTOFMEMORY; }
VariantInit (&vRegistryKey); // get the Qualifier Set for this class
hRes = pClass->GetQualifierSet(&pClassQualifiers); if( NULL == pClassQualifiers ){ return hRes; } // now get the library and procedure names
hRes = pClassQualifiers->Get( cbRegistryKey, 0, &vRegistryKey, 0); if ((hRes == 0) && (vRegistryKey.vt == VT_BSTR)) { szRegistryKey = Macro_CloneLPWSTR(V_BSTR(&vRegistryKey)); if (szRegistryKey == NULL) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; } else { // now also get the perf index
if (bCatalogQuery) { // then insert 0 for the perf index to indicate a "GLOBAL"
// query
dwPerfIndex = 0; } else { VariantClear (&vRegistryKey); hRes = pClassQualifiers->Get( cbPerfIndex, 0, &vRegistryKey, 0); if (hRes == 0) { dwPerfIndex = (DWORD)V_UI4(&vRegistryKey); } else { // unable to find NtPerfLibrary entry
dwReturn = ERROR_FILE_NOT_FOUND; } } } } else { // unable to find NtPerfLibrary entry
dwReturn = ERROR_FILE_NOT_FOUND; }
if (pClassQualifiers != NULL) pClassQualifiers->Release();
if (dwReturn == ERROR_SUCCESS) { // find matching library in the array
dwEnd = m_aLibraries.Size(); if (dwEnd > 0) { // walk down the list of libraries
for (dwIndex = 0; dwIndex < dwEnd; dwIndex++) { // see if this library entry is good enough to keep
// The library is assumed to be a match if the
// lib. name and all proc's are the same.
pThisLibEntry = (CPerfDataLibrary *)m_aLibraries[dwIndex]; assert (pThisLibEntry != NULL); // it should have been removed!
// make sure it's complete
assert (pThisLibEntry->pLibInfo->szServiceName != NULL);
if (lstrcmpiW (szRegistryKey, pThisLibEntry->pLibInfo->szServiceName) == 0) { pLibEntry = pThisLibEntry; break; } else { // wrong library
// so continue
} } }
if (pLibEntry == NULL) { // add this class & it's library to the list
dwReturn = AddLibrary (pClass, pClassQualifiers, szRegistryKey, dwPerfIndex); } else { WCHAR wszNewIndex[WBEMPERF_STRING_SIZE]; pLibEntry->dwRefCount++; _ultow (dwPerfIndex, wszNewIndex, 10); if (!IsNumberInUnicodeList (dwPerfIndex, pLibEntry->szQueryString)) { // then add it to the list
StringCchCatW(pLibEntry->szQueryString, MAX_PERF_OBJECTS_IN_QUERY_FUNCTION*10, cszSpace); StringCchCatW(pLibEntry->szQueryString, MAX_PERF_OBJECTS_IN_QUERY_FUNCTION*10, wszNewIndex); } } }
if (szRegistryKey != NULL) delete szRegistryKey; VariantClear(&vRegistryKey);
return dwReturn; }
//***************************************************************************
//
// CPerfObjectAccess::CollectData (LPBYTE pBuffer,
// LPDWORD pdwBufferSize, LPWSTR pszItemList)
//
// Collects data from the perf objects and libraries added to the access
// object
//
// Inputs:
//
// pBuffer - pointer to start of data block
// where data is being collected
//
// pdwBufferSize - pointer to size of data buffer
//
// pszItemList - string to pass to ext DLL
//
// Outputs:
//
// *lppDataDefinition - set to location for next Type
// Definition if successful
//
// Returns:
//
// 0 if successful, else Win 32 error code of failure
//
//
//***************************************************************************
//
DWORD CPerfObjectAccess::CollectData (LPBYTE pBuffer, LPDWORD pdwBufferSize, LPWSTR pszItemList) { LPWSTR lpValueName = NULL; LPBYTE lpData = pBuffer; LPDWORD lpcbData = pdwBufferSize; LPVOID lpDataDefinition = NULL;
DWORD Win32Error=ERROR_SUCCESS; // Failure code
DWORD BytesLeft; DWORD NumObjectTypes;
LPVOID lpExtDataBuffer = NULL; LPVOID lpCallBuffer = NULL; LPVOID lpLowGuardPage = NULL; LPVOID lpHiGuardPage = NULL; LPVOID lpEndPointer = NULL; LPVOID lpBufferBefore = NULL; LPVOID lpBufferAfter = NULL; LPDWORD lpCheckPointer; LARGE_INTEGER liStartTime, liEndTime, liWaitTime;
pExtObject pThisExtObj = NULL;
BOOL bGuardPageOK; BOOL bBufferOK; BOOL bException; BOOL bUseSafeBuffer; BOOL bUnlockObjData = FALSE;
LPWSTR szMessageArray[8]; DWORD dwRawDataDwords[8]; // raw data buffer
DWORD dwDataIndex; WORD wStringIndex; LONG lReturnValue = ERROR_SUCCESS;
LONG lInstIndex; PERF_OBJECT_TYPE *pObject, *pNextObject; PERF_INSTANCE_DEFINITION *pInstance; PERF_DATA_BLOCK *pPerfData; BOOL bForeignDataBuffer; BOOL bCheckThisService;
DWORD dwItemsInList = 0;
DWORD dwIndex, dwEntry;
CPerfDataLibrary *pThisLib;
liStartTime.QuadPart = 0; liEndTime.QuadPart = 0;
if (lExtCounterTestLevel < EXT_TEST_NOMEMALLOC) { bUseSafeBuffer = TRUE; } else { bUseSafeBuffer = FALSE; }
if (lReturnValue == ERROR_SUCCESS) {
if (*pdwBufferSize > (sizeof(PERF_DATA_BLOCK) *2)) { MonBuildPerfDataBlock( (PERF_DATA_BLOCK *)pBuffer, &lpDataDefinition, 0,0); dwItemsInList = m_aLibraries.Size(); } else { lReturnValue = ERROR_MORE_DATA; dwItemsInList = 0; }
if (dwItemsInList > 0) { for (dwEntry = 0; dwEntry < dwItemsInList; dwEntry++) { pThisLib = (CPerfDataLibrary *)m_aLibraries[dwEntry]; assert (pThisLib != NULL);
bCheckThisService = FALSE; pThisExtObj = pThisLib->pLibInfo; if (pszItemList == NULL) { // use the one for this library
lpValueName = pThisLib->szQueryString; } else { // use the one passed by the caller
lpValueName = pszItemList; } if (lpValueName == NULL) { lpValueName = (LPWSTR) cszGlobal; }
// convert timeout value
liWaitTime.QuadPart = MakeTimeOutValue (pThisExtObj->dwCollectTimeout);
// initialize values to pass to the extensible counter function
NumObjectTypes = 0; BytesLeft = (DWORD) (*lpcbData - ((LPBYTE)lpDataDefinition - lpData)); bException = FALSE;
if (lstrcmpiW(lpValueName, cszGlobal) == 0 || lstrcmpiW(lpValueName, cszCostly) == 0) { bCheckThisService = TRUE; } else { LPWSTR szThisChar; LPWSTR szThisObject = NULL; DWORD dwThisObject; DWORD dwIndex;
for (szThisChar = lpValueName; * szThisChar != L'\0'; szThisChar ++) { if (* szThisChar == L' ') { if (szThisObject == NULL) { continue; } else { * szThisChar = L'\0'; dwThisObject = wcstoul(szThisObject, NULL, 0); szThisObject = NULL; * szThisChar = L' ';
for (dwIndex = 0; dwIndex < pThisExtObj->dwNumObjects; dwIndex ++) { if (pThisExtObj->dwObjList[dwIndex] == dwThisObject) { bCheckThisService = TRUE; break; } }
if (! bCheckThisService) { if (dwThisObject >= pThisExtObj->dwFirstCounter && dwThisObject <= pThisExtObj->dwLastCounter) { bCheckThisService = TRUE; } } if (bCheckThisService) break; } } else if (szThisObject == NULL) { szThisObject = szThisChar; } } if (! bCheckThisService && szThisObject != NULL) { dwThisObject = wcstoul(szThisObject, NULL, 0); szThisObject = NULL;
for (dwIndex = 0; dwIndex < pThisExtObj->dwNumObjects; dwIndex ++) { if (pThisExtObj->dwObjList[dwIndex] == dwThisObject) { bCheckThisService = TRUE; break; } }
if (! bCheckThisService) { if (dwThisObject >= pThisExtObj->dwFirstCounter && dwThisObject <= pThisExtObj->dwLastCounter) { bCheckThisService = TRUE; } } } }
if (! bCheckThisService) continue;
if (pThisExtObj->hLibrary == NULL) { // lock library object
if (pThisExtObj->hMutex != NULL) { Win32Error = WaitForSingleObject ( pThisExtObj->hMutex, pThisExtObj->dwCollectTimeout); if (Win32Error != WAIT_TIMEOUT) { Win32Error = ERROR_INVALID_ACCESS; // if necessary, open the library
if (pThisExtObj->hLibrary == NULL) { // make sure the library is open
if( pThisExtObj->dwOpenFail == 0 && GetCurrentThreadId() != pThisExtObj->ADThreadId ){ Win32Error = OpenExtObjectLibrary(pThisExtObj); } } ReleaseMutex (pThisExtObj->hMutex);
if( ERROR_SUCCESS != Win32Error ){ // assume error has been posted
continue; } } else { pThisExtObj->dwLockoutCount++; } } else { Win32Error = ERROR_LOCK_FAILED; } } else { // library should be ready to use
}
// allocate a local block of memory to pass to the
// extensible counter function.
if (bUseSafeBuffer) { lpExtDataBuffer = ALLOCMEM (m_hObjectHeap, HEAP_ZERO_MEMORY, BytesLeft + (2*GUARD_PAGE_SIZE)); } else { lpExtDataBuffer = lpCallBuffer = lpDataDefinition; }
if (lpExtDataBuffer != NULL) {
if (bUseSafeBuffer) { // set buffer pointers
lpLowGuardPage = lpExtDataBuffer; lpCallBuffer = (LPBYTE)lpExtDataBuffer + GUARD_PAGE_SIZE; lpHiGuardPage = (LPBYTE)lpCallBuffer + BytesLeft; lpEndPointer = (LPBYTE)lpHiGuardPage + GUARD_PAGE_SIZE; lpBufferBefore = lpCallBuffer; lpBufferAfter = NULL;
// initialize GuardPage Data
memset (lpLowGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE); memset (lpHiGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE); }
__try { //
// Collect data from extesible objects
//
bUnlockObjData = FALSE; if (pThisExtObj->hMutex != NULL) { Win32Error = WaitForSingleObject ( pThisExtObj->hMutex, pThisExtObj->dwCollectTimeout); if ( Win32Error != WAIT_TIMEOUT ){ if( pThisExtObj->CollectProc != NULL) { bUnlockObjData = TRUE;
QueryPerformanceCounter (&liStartTime);
Win32Error = (*pThisExtObj->CollectProc) ( lpValueName, &lpCallBuffer, &BytesLeft, &NumObjectTypes);
QueryPerformanceCounter (&liEndTime);
pThisExtObj->llLastUsedTime = GetTimeAsLongLong(); } ReleaseMutex (pThisExtObj->hMutex); bUnlockObjData = FALSE; } else { pThisExtObj->dwLockoutCount++; } } else { Win32Error = ERROR_LOCK_FAILED; }
if ((Win32Error == ERROR_SUCCESS) && (BytesLeft > 0)) { // increment perf counters
InterlockedIncrement ((LONG *)&pThisExtObj->dwCollectCount); pThisExtObj->llElapsedTime += liEndTime.QuadPart - liStartTime.QuadPart;
if (bUseSafeBuffer) { // a data buffer was returned and
// the function returned OK so see how things
// turned out...
//
lpBufferAfter = lpCallBuffer; //
// check for buffer corruption here
//
bBufferOK = TRUE; // assume it's ok until a check fails
//
if (lExtCounterTestLevel <= EXT_TEST_BASIC) { //
// check 1: bytes left should be the same as
// new data buffer ptr - orig data buffer ptr
//
if (BytesLeft != (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore)) { if (lEventLogLevel >= LOG_DEBUG) { // issue WARNING, that bytes left param is incorrect
// load data for eventlog message
// since this error is correctable (though with
// some risk) this won't be reported at LOG_USER
// level
dwDataIndex = wStringIndex = 0; dwRawDataDwords[dwDataIndex++] = BytesLeft; dwRawDataDwords[dwDataIndex++] = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore); szMessageArray[wStringIndex++] = pThisExtObj->szServiceName; szMessageArray[wStringIndex++] = pThisExtObj->szLibraryName; ReportEventW (hEventLog, EVENTLOG_WARNING_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_BUFFER_POINTER_MISMATCH, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
} // we'll keep the buffer, since the returned bytes left
// value is ignored anyway, in order to make the
// rest of this function work, we'll fix it here
BytesLeft = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore); } //
// check 2: buffer after ptr should be < hi Guard page ptr
//
if (((LPBYTE)lpBufferAfter >= (LPBYTE)lpHiGuardPage) && bBufferOK) { // see if they exceeded the allocated memory
if ((LPBYTE)lpBufferAfter >= (LPBYTE)lpEndPointer) { // this is very serious since they've probably trashed
// the heap by overwriting the heap sig. block
// issue ERROR, buffer overrun
if (lEventLogLevel >= LOG_USER) { // load data for eventlog message
dwDataIndex = wStringIndex = 0; dwRawDataDwords[dwDataIndex++] = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage); szMessageArray[wStringIndex++] = pThisExtObj->szLibraryName; szMessageArray[wStringIndex++] = pThisExtObj->szServiceName; ReportEventW (hEventLog, EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_HEAP_ERROR, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
} } else { // issue ERROR, buffer overrun
if (lEventLogLevel >= LOG_USER) { // load data for eventlog message
dwDataIndex = wStringIndex = 0; dwRawDataDwords[dwDataIndex++] = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage); szMessageArray[wStringIndex++] = pThisExtObj->szLibraryName; szMessageArray[wStringIndex++] = pThisExtObj->szServiceName; ReportEventW (hEventLog, EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_BUFFER_OVERFLOW, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
} } bBufferOK = FALSE; // since the DLL overran the buffer, the buffer
// must be too small (no comments about the DLL
// will be made here) so the status will be
// changed to ERROR_MORE_DATA and the function
// will return.
Win32Error = ERROR_MORE_DATA; } //
// check 3: check lo guard page for corruption
//
if (bBufferOK) { bGuardPageOK = TRUE; for (lpCheckPointer = (LPDWORD)lpLowGuardPage; lpCheckPointer < (LPDWORD)lpBufferBefore; lpCheckPointer++) { if (*lpCheckPointer != GUARD_PAGE_DWORD) { bGuardPageOK = FALSE; break; } } if (!bGuardPageOK) { // issue ERROR, Lo Guard Page corrupted
if (lEventLogLevel >= LOG_USER) { // load data for eventlog message
dwDataIndex = wStringIndex = 0; szMessageArray[wStringIndex++] = pThisExtObj->szLibraryName; szMessageArray[wStringIndex++] = pThisExtObj->szServiceName; ReportEventW (hEventLog, EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_GUARD_PAGE_VIOLATION, // event
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
} bBufferOK = FALSE; } } //
// check 4: check hi guard page for corruption
//
if (bBufferOK) { bGuardPageOK = TRUE; for (lpCheckPointer = (LPDWORD)lpHiGuardPage; lpCheckPointer < (LPDWORD)lpEndPointer; lpCheckPointer++) { if (*lpCheckPointer != GUARD_PAGE_DWORD) { bGuardPageOK = FALSE; break; } } if (!bGuardPageOK) { // issue ERROR, Hi Guard Page corrupted
if (lEventLogLevel >= LOG_USER) { // load data for eventlog message
dwDataIndex = wStringIndex = 0; szMessageArray[wStringIndex++] = pThisExtObj->szLibraryName; szMessageArray[wStringIndex++] = pThisExtObj->szServiceName; ReportEventW (hEventLog, EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_GUARD_PAGE_VIOLATION, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
bBufferOK = FALSE; } } //
if ((lExtCounterTestLevel <= EXT_TEST_ALL) && bBufferOK) { //
// Internal consistency checks
//
//
// Check 5: Check object length field values
//
// first test to see if this is a foreign
// computer data block or not
//
pPerfData = (PERF_DATA_BLOCK *)lpBufferBefore; if ((pPerfData->Signature[0] == (WCHAR)'P') && (pPerfData->Signature[1] == (WCHAR)'E') && (pPerfData->Signature[2] == (WCHAR)'R') && (pPerfData->Signature[3] == (WCHAR)'F')) { // if this is a foreign computer data block, then the
// first object is after the header
pObject = (PERF_OBJECT_TYPE *) ( (LPBYTE)pPerfData + pPerfData->HeaderLength); bForeignDataBuffer = TRUE; } else { // otherwise, if this is just a buffer from
// an extensible counter, the object starts
// at the beginning of the buffer
pObject = (PERF_OBJECT_TYPE *)lpBufferBefore; bForeignDataBuffer = FALSE; } // go to where the pointers say the end of the
// buffer is and then see if it's where it
// should be
for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) { pObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject + pObject->TotalByteLength); } if ((LPBYTE)pObject != (LPBYTE)lpCallBuffer) { // then a length field is incorrect. This is FATAL
// since it can corrupt the rest of the buffer
// and render the buffer unusable.
if (lEventLogLevel >= LOG_USER) { // load data for eventlog message
dwDataIndex = wStringIndex = 0; dwRawDataDwords[dwDataIndex++] = NumObjectTypes; szMessageArray[wStringIndex++] = pThisExtObj->szLibraryName; szMessageArray[wStringIndex++] = pThisExtObj->szServiceName; ReportEventW (hEventLog, EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_INCORRECT_OBJECT_LENGTH, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
} bBufferOK = FALSE; } //
// Test 6: Test instance field size values
//
if (bBufferOK) { // set object pointer
if (bForeignDataBuffer) { pObject = (PERF_OBJECT_TYPE *) ( (LPBYTE)pPerfData + pPerfData->HeaderLength); } else { // otherwise, if this is just a buffer from
// an extensible counter, the object starts
// at the beginning of the buffer
pObject = (PERF_OBJECT_TYPE *)lpBufferBefore; }
for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) { pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject + pObject->TotalByteLength);
if (pObject->NumInstances != PERF_NO_INSTANCES) { pInstance = (PERF_INSTANCE_DEFINITION *) ((LPBYTE)pObject + pObject->DefinitionLength); lInstIndex = 0; while (lInstIndex < pObject->NumInstances) { PERF_COUNTER_BLOCK *pCounterBlock;
pCounterBlock = (PERF_COUNTER_BLOCK *) ((PCHAR) pInstance + pInstance->ByteLength);
pInstance = (PERF_INSTANCE_DEFINITION *) ((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
lInstIndex++; } if ((LPBYTE)pInstance > (LPBYTE)pNextObject) { bBufferOK = FALSE; } }
if (!bBufferOK) { break; } else { pObject = pNextObject; } }
if (!bBufferOK) { if (lEventLogLevel >= LOG_USER) { // load data for eventlog message
dwDataIndex = wStringIndex = 0; dwRawDataDwords[dwDataIndex++] = pObject->ObjectNameTitleIndex; szMessageArray[wStringIndex++] = pThisExtObj->szLibraryName; szMessageArray[wStringIndex++] = pThisExtObj->szServiceName; ReportEventW (hEventLog, EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_INCORRECT_INSTANCE_LENGTH, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
} } } } } //
// if all the tests pass,then copy the data to the
// original buffer and update the pointers
if (bBufferOK) { RtlMoveMemory (lpDataDefinition, lpBufferBefore, BytesLeft); // returned buffer size
} else { NumObjectTypes = 0; // since this buffer was tossed
BytesLeft = 0; // reset the size value since the buffer wasn't used
} } else { // function already copied data to caller's buffer
// so no further action is necessary
} lpDataDefinition = (LPVOID)((LPBYTE)(lpDataDefinition) + BytesLeft); // update data pointer
} else { if (Win32Error != ERROR_SUCCESS) { InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount); } if (bUnlockObjData) { ReleaseMutex (pThisExtObj->hMutex); }
NumObjectTypes = 0; // clear counter
}// end if function returned successfully
} __except (EXCEPTION_EXECUTE_HANDLER) { Win32Error = GetExceptionCode(); InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount); bException = TRUE; if (bUnlockObjData) { ReleaseMutex (pThisExtObj->hMutex); bUnlockObjData = FALSE; } } if (bUseSafeBuffer) { FREEMEM (m_hObjectHeap, 0, lpExtDataBuffer); } } else { // unable to allocate memory so set error value
Win32Error = ERROR_OUTOFMEMORY; } // end if temp buffer allocated successfully
//
// Update the count of the number of object types
//
((PPERF_DATA_BLOCK) lpData)->NumObjectTypes += NumObjectTypes;
if ( Win32Error != ERROR_SUCCESS) { if (bException || !((Win32Error == ERROR_MORE_DATA) || (Win32Error == WAIT_TIMEOUT))) { // inform on exceptions & illegal error status only
if (lEventLogLevel >= LOG_USER) { // load data for eventlog message
dwDataIndex = wStringIndex = 0; dwRawDataDwords[dwDataIndex++] = Win32Error; szMessageArray[wStringIndex++] = pThisExtObj->szServiceName; szMessageArray[wStringIndex++] = pThisExtObj->szLibraryName; ReportEventW (hEventLog, EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_COLLECT_PROC_EXCEPTION, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
} else { // don't report
} } // the ext. dll is only supposed to return:
// ERROR_SUCCESS even if it encountered a problem, OR
// ERROR_MODE_DATA if the buffer was too small.
// if it's ERROR_MORE_DATA, then break and return the
// error now, since it'll just be returned again and again.
if (Win32Error == ERROR_MORE_DATA) { lReturnValue = Win32Error; break; } } } // end for each object
} // else an error occurred so unable to call functions
((PPERF_DATA_BLOCK) lpData)->TotalByteLength = (DWORD) ((LPBYTE)lpDataDefinition - (LPBYTE)lpData); }
return lReturnValue; }
//***************************************************************************
//
// CPerfObjectAccess::RemoveClass(IWbemClassObject *pClass)
//
// removes the class from the access object
//
//***************************************************************************
//
DWORD CPerfObjectAccess::RemoveClass(IWbemClassObject *pClass) { CPerfDataLibrary *pLibEntry = NULL; CPerfDataLibrary *pThisLibEntry = NULL; DWORD dwIndex = 0; DWORD dwEnd; LPWSTR szRegistryKey = NULL; IWbemQualifierSet *pClassQualifiers = NULL; VARIANT vRegistryKey; HRESULT hRes; DWORD dwReturn = ERROR_SUCCESS; DWORD dwPerfIndex; CBSTR cbPerfIndex(cszPerfIndex); CBSTR cbRegistryKey(cszRegistryKey); if( NULL == (BSTR)cbPerfIndex || NULL == (BSTR)cbRegistryKey ){ return ERROR_OUTOFMEMORY; }
VariantInit (&vRegistryKey); // get the Qualifier Set for this class
hRes = pClass->GetQualifierSet(&pClassQualifiers); if( hRes == 0){ // now get the library and procedure names
hRes = pClassQualifiers->Get( cbRegistryKey, 0, &vRegistryKey, 0); if ((hRes == 0) && (vRegistryKey.vt == VT_BSTR)) { szRegistryKey = Macro_CloneLPWSTR(V_BSTR(&vRegistryKey)); if (szRegistryKey == NULL) { dwReturn = ERROR_NOT_ENOUGH_MEMORY; } else { // now also get the perf index
VariantClear (&vRegistryKey); hRes = pClassQualifiers->Get( cbPerfIndex, 0, &vRegistryKey, 0); if (hRes == 0) { dwPerfIndex = (DWORD)V_UI4(&vRegistryKey); } else { // unable to find NtPerfLibrary entry
dwReturn = ERROR_FILE_NOT_FOUND; } } } else { // unable to find NtPerfLibrary entry
dwReturn = ERROR_FILE_NOT_FOUND; }
if (pClassQualifiers != NULL) pClassQualifiers->Release();
if (dwReturn == ERROR_SUCCESS) { // find matching library in the array
dwEnd = m_aLibraries.Size(); if (dwEnd > 0) { // walk down the list of libraries
for (dwIndex = 0; dwIndex < dwEnd; dwIndex++) { // see if this library entry is good enough to keep
// The library is assumed to be a match if the
// lib. name and all proc's are the same.
pThisLibEntry = (CPerfDataLibrary *)m_aLibraries[dwIndex]; assert (pThisLibEntry != NULL); // it should have been removed!
// make sure it's complete
assert (pThisLibEntry->pLibInfo->szServiceName != NULL);
if (lstrcmpiW (szRegistryKey, pThisLibEntry->pLibInfo->szServiceName) == 0) { pLibEntry = pThisLibEntry; break; } else { // wrong library
// so continue
} } }
if (pLibEntry != NULL) { // close this class & it's library
dwReturn = CloseLibrary(pLibEntry); if (dwReturn == 0) { // then no one wants it
FREEMEM(m_hObjectHeap, 0, pLibEntry->pLibInfo); pLibEntry->pLibInfo = NULL; m_aLibraries.RemoveAt(dwIndex); m_aLibraries.Compress(); delete pLibEntry; } dwReturn = ERROR_SUCCESS; } else { dwReturn = ERROR_FILE_NOT_FOUND; } }
if (szRegistryKey != NULL) delete szRegistryKey; VariantClear(&vRegistryKey); } return dwReturn; }
BOOL CPerfObjectAccess::CheckClassExist(LPWSTR wszClassName, IWbemClassObject * pClass) { BOOL bExist = TRUE; HRESULT hRes = S_OK; IWbemQualifierSet * pClassQualifiers = NULL; SYSTEMTIME LocalTime; VARIANT vRegistry; LPWSTR szRegistry = NULL; LPWSTR szKey = NULL; DWORD dwKey; DWORD dwType; DWORD dwSize; DWORD Status; HKEY hKey = NULL;
ZeroMemory(& LocalTime, sizeof(SYSTEMTIME)); GetLocalTime(& LocalTime);
hRes = pClass->GetQualifierSet(& pClassQualifiers); if (hRes != S_OK || pClassQualifiers == NULL) { bExist = FALSE; goto Cleanup; }
hRes = pClassQualifiers->Get(CBSTR(cszRegistryKey), 0, & vRegistry, 0); if (hRes != S_OK || vRegistry.vt != VT_BSTR) { bExist = FALSE; goto Cleanup; }
dwKey = lstrlenW(V_BSTR(& vRegistry)) + 1; szRegistry = (LPWSTR) ALLOCMEM(m_hObjectHeap, HEAP_ZERO_MEMORY, sizeof(WCHAR) * dwKey); if (szRegistry != NULL) { StringCchCopyW(szRegistry, dwKey, V_BSTR(& vRegistry)); VariantClear(& vRegistry); } else { VariantClear(& vRegistry); goto Cleanup; }
dwKey = lstrlenW(cszHklmServicesKey) + 1 + lstrlenW(szRegistry) + lstrlenW(cszPerformance) + 1; szKey = (LPWSTR) ALLOCMEM(m_hObjectHeap, HEAP_ZERO_MEMORY, dwKey * sizeof(WCHAR)); if (szKey == NULL) { goto Cleanup; } StringCchPrintfW(szKey, dwKey, L"%ws\\%ws%ws", cszHklmServicesKey, szRegistry, cszPerformance);
Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, & hKey); if (Status != ERROR_SUCCESS || hKey == NULL || hKey == INVALID_HANDLE_VALUE) { bExist = FALSE; goto Cleanup; }
dwType = 0; dwSize = sizeof(dwKey); Status = RegQueryValueExW(hKey, cszFirstCounter, NULL, & dwType, (LPBYTE) & dwKey, & dwSize); if (Status != ERROR_SUCCESS || dwType != REG_DWORD) { bExist = FALSE; goto Cleanup; }
dwType = 0; dwSize = sizeof(dwKey); Status = RegQueryValueExW(hKey, cszLastCounter, NULL, & dwType, (LPBYTE) & dwKey, & dwSize); if (Status != ERROR_SUCCESS || dwType != REG_DWORD) { bExist = FALSE; goto Cleanup; }
Cleanup: if (pClassQualifiers != NULL) pClassQualifiers->Release(); if (szRegistry != NULL) FREEMEM(m_hObjectHeap, 0, szRegistry); if (szKey != NULL) FREEMEM(m_hObjectHeap, 0, szKey); if (hKey != NULL && hKey != INVALID_HANDLE_VALUE) RegCloseKey(hKey); return bExist; }
|