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.
2275 lines
100 KiB
2275 lines
100 KiB
//***************************************************************************
|
|
//
|
|
// 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;
|
|
}
|