//*************************************************************************** // // 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 #include "oahelp.inl" //#include // 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; }