Leaked source code of windows server 2003
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

  1. //***************************************************************************
  2. //
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. //
  5. // PerfAcc.CPP
  6. //
  7. // Windows NT Performance Data Access helper functions
  8. //
  9. // bobw 8-Jub-98 Created for use with NT Perf counters
  10. //
  11. //***************************************************************************
  12. //
  13. #include "wpheader.h"
  14. #include <stdlib.h>
  15. #include "oahelp.inl"
  16. //#include <malloc.h>
  17. // NOTE: Consider reading this from the registry
  18. LONG lExtCounterTestLevel = EXT_TEST_ALL;
  19. LPCWSTR cszFirstCounter = L"First Counter";
  20. LPCWSTR cszLastCounter = L"Last Counter";
  21. //
  22. //
  23. // precompiled security descriptor
  24. // System and NetworkService has full access
  25. //
  26. // since this is RELATIVE, it will work on both IA32 and IA64
  27. //
  28. DWORD g_PrecSD[] = {
  29. 0x80040001 , 0x00000044 , 0x00000050 , 0x00000000 ,
  30. 0x00000014 , 0x00300002 , 0x00000002 , 0x00140000 ,
  31. 0x001f0001 , 0x00000101 , 0x05000000 , 0x00000012 ,
  32. 0x00140000 , 0x001f0001 , 0x00000101 , 0x05000000 ,
  33. 0x00000014 , 0x00000101 , 0x05000000 , 0x00000014 ,
  34. 0x00000101 , 0x05000000 , 0x00000014
  35. };
  36. DWORD g_SizeSD = 0;
  37. DWORD g_RuntimeSD[(sizeof(ACL)+sizeof(ACCESS_ALLOWED_ACE)+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+4*(sizeof(SID)+SID_MAX_SUB_AUTHORITIES*sizeof(DWORD)))/sizeof(DWORD)];
  38. typedef
  39. BOOLEAN ( * fnRtlValidRelativeSecurityDescriptor)(
  40. IN PSECURITY_DESCRIPTOR SecurityDescriptorInput,
  41. IN ULONG SecurityDescriptorLength,
  42. IN SECURITY_INFORMATION RequiredInformation
  43. );
  44. fnRtlValidRelativeSecurityDescriptor RtlValidRelativeSecurityDescriptor;
  45. //
  46. // Build a SD with owner == This
  47. // group == This
  48. // DACL
  49. // ACE[0] MUTEX_ALL_ACCESS Owner
  50. // ACE[1] MUTEX_ALL_ACCESS System
  51. ///////////////////////////////////////////////////////////////////
  52. BOOL
  53. CreateSD( )
  54. {
  55. TOKEN_USER * pToken_User = NULL;
  56. SECURITY_DESCRIPTOR_RELATIVE * pLocalSD = NULL;
  57. PACL pDacl = NULL;
  58. //
  59. // Using GetProcAddress so that nt.h does not have to be included.
  60. // Since WBEM and NT don't get along this function would need to
  61. // be in a separate file.
  62. //
  63. if (! RtlValidRelativeSecurityDescriptor)
  64. {
  65. HMODULE hModule = GetModuleHandleW(L"ntdll.dll");
  66. if (hModule)
  67. {
  68. RtlValidRelativeSecurityDescriptor = (fnRtlValidRelativeSecurityDescriptor)GetProcAddress(hModule,"RtlValidRelativeSecurityDescriptor");
  69. if (! RtlValidRelativeSecurityDescriptor)
  70. {
  71. return FALSE;
  72. }
  73. }
  74. }
  75. HANDLE hToken;
  76. BOOL bRet;
  77. bRet = OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken);
  78. if (bRet)
  79. {
  80. DWORD dwSize = sizeof(TOKEN_USER)+sizeof(SID)+(SID_MAX_SUB_AUTHORITIES*sizeof(DWORD));
  81. pToken_User = (TOKEN_USER *)ALLOCMEM( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
  82. if( NULL == pToken_User ){
  83. bRet = FALSE;
  84. goto cleanup;
  85. }
  86. bRet = GetTokenInformation(hToken,TokenUser,pToken_User,dwSize,&dwSize);
  87. if (bRet)
  88. {
  89. SID SystemSid = { SID_REVISION,
  90. 1,
  91. SECURITY_NT_AUTHORITY,
  92. SECURITY_LOCAL_SYSTEM_RID
  93. };
  94. PSID pSIDUser = pToken_User->User.Sid;
  95. dwSize = GetLengthSid(pSIDUser);
  96. DWORD dwSids = 2; // Owner and System
  97. DWORD ACLLength = (ULONG) sizeof(ACL) +
  98. (dwSids * ((ULONG) sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) + dwSize + sizeof(SystemSid);
  99. DWORD dwSizeSD = sizeof(SECURITY_DESCRIPTOR_RELATIVE) + dwSize + dwSize + ACLLength;
  100. pLocalSD = (SECURITY_DESCRIPTOR_RELATIVE *)ALLOCMEM(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSizeSD);
  101. if( NULL == pLocalSD ){
  102. bRet = FALSE;
  103. goto cleanup;
  104. }
  105. memset(pLocalSD,0,sizeof(SECURITY_DESCRIPTOR_RELATIVE));
  106. pLocalSD->Revision = SECURITY_DESCRIPTOR_REVISION;
  107. pLocalSD->Control = SE_DACL_PRESENT|SE_SELF_RELATIVE;
  108. //SetSecurityDescriptorOwner(pLocalSD,pSIDUser,FALSE);
  109. memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE),pSIDUser,dwSize);
  110. pLocalSD->Owner = (DWORD)sizeof(SECURITY_DESCRIPTOR_RELATIVE);
  111. //SetSecurityDescriptorGroup(pLocalSD,pSIDUser,FALSE);
  112. memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize,pSIDUser,dwSize);
  113. pLocalSD->Group = (DWORD)(sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize);
  114. pDacl = (PACL)ALLOCMEM(GetProcessHeap(), HEAP_ZERO_MEMORY, ACLLength);
  115. if( NULL == pDacl ){
  116. bRet = FALSE;
  117. goto cleanup;
  118. }
  119. bRet = InitializeAcl( pDacl,
  120. ACLLength,
  121. ACL_REVISION);
  122. if (bRet)
  123. {
  124. bRet = AddAccessAllowedAceEx (pDacl,ACL_REVISION,0,MUTEX_ALL_ACCESS,&SystemSid);
  125. if (bRet)
  126. {
  127. bRet = AddAccessAllowedAceEx (pDacl,ACL_REVISION,0,MUTEX_ALL_ACCESS,pSIDUser);
  128. if (bRet)
  129. {
  130. //bRet = SetSecurityDescriptorDacl(pLocalSD,TRUE,pDacl,FALSE);
  131. memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize+dwSize,pDacl,ACLLength);
  132. pLocalSD->Dacl = (DWORD)(sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize+dwSize);
  133. if (RtlValidRelativeSecurityDescriptor(pLocalSD,
  134. dwSizeSD,
  135. OWNER_SECURITY_INFORMATION|
  136. GROUP_SECURITY_INFORMATION|
  137. DACL_SECURITY_INFORMATION))
  138. {
  139. g_SizeSD = dwSizeSD;
  140. memcpy(g_RuntimeSD,pLocalSD,dwSizeSD);
  141. }
  142. else
  143. {
  144. bRet = FALSE;
  145. }
  146. }
  147. }
  148. }
  149. }
  150. CloseHandle(hToken);
  151. }
  152. cleanup:
  153. if( NULL != pToken_User ){
  154. FREEMEM(GetProcessHeap(), 0, pToken_User );
  155. }
  156. if( NULL != pLocalSD ){
  157. FREEMEM(GetProcessHeap(), 0, pLocalSD );
  158. }
  159. if( NULL != pDacl ){
  160. FREEMEM(GetProcessHeap(), 0, pDacl );
  161. }
  162. return bRet;
  163. };
  164. //***************************************************************************
  165. //
  166. // HANDLE CreateMutexAsProcess(LPCWSTR pwszName)
  167. //
  168. // This function will create a mutex using the process' security context
  169. //
  170. //***************************************************************************
  171. //
  172. HANDLE CreateMutexAsProcess(LPCWSTR pwszName)
  173. {
  174. BOOL bImpersonating = FALSE;
  175. HANDLE hThreadToken = NULL;
  176. // Determine if we are impersonating
  177. bImpersonating = OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE,
  178. &hThreadToken);
  179. if(bImpersonating)
  180. {
  181. // Determine if we are impersonating
  182. bImpersonating = RevertToSelf();
  183. }
  184. // Create the mutex as using the process token.
  185. HANDLE hRet = OpenMutexW(MUTEX_ALL_ACCESS,FALSE,pwszName);
  186. if (NULL == hRet)
  187. {
  188. SECURITY_ATTRIBUTES sa;
  189. if (0 == g_SizeSD)
  190. {
  191. if (CreateSD())
  192. {
  193. sa.nLength = g_SizeSD;
  194. sa.lpSecurityDescriptor = (LPVOID)g_RuntimeSD;
  195. sa.bInheritHandle = FALSE;
  196. }
  197. else
  198. {
  199. sa.nLength = sizeof(g_PrecSD);
  200. sa.lpSecurityDescriptor = (LPVOID)g_PrecSD;
  201. sa.bInheritHandle = FALSE;
  202. }
  203. }
  204. else
  205. {
  206. sa.nLength = g_SizeSD;
  207. sa.lpSecurityDescriptor = (LPVOID)g_RuntimeSD;
  208. sa.bInheritHandle = FALSE;
  209. }
  210. hRet = CreateMutexW(&sa, FALSE, pwszName);
  211. }
  212. // If code was oringinally impersonating, resume impersonation
  213. if(bImpersonating){
  214. BOOL bRes = SetThreadToken(NULL, hThreadToken);
  215. }
  216. if(hThreadToken)
  217. CloseHandle(hThreadToken);
  218. return hRet;
  219. }
  220. //***************************************************************************
  221. //
  222. // CPerfDataLibrary ::CPerfDataLibrary
  223. //
  224. // This object is used to abstract the perf data library
  225. //
  226. //***************************************************************************
  227. //
  228. CPerfDataLibrary::CPerfDataLibrary (void)
  229. {
  230. pLibInfo = NULL;
  231. memset ((LPVOID)szQueryString, 0, sizeof(szQueryString));
  232. dwRefCount = 0; // number of classes referencing this object
  233. }
  234. CPerfDataLibrary::~CPerfDataLibrary (void)
  235. {
  236. // all libraries should be closed before this is
  237. // destructed
  238. assert (dwRefCount == 0);
  239. assert (pLibInfo == NULL);
  240. }
  241. //***************************************************************************
  242. //
  243. // CPerfObjectAccess::CPerfObjectAccess
  244. //
  245. // This object is used to abstract a data object within a perf library
  246. //
  247. //***************************************************************************
  248. //
  249. CPerfObjectAccess::CPerfObjectAccess ()
  250. {
  251. m_hObjectHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0x10000, 0);
  252. if (m_hObjectHeap == NULL) {
  253. // then just use the process heap
  254. m_hObjectHeap = GetProcessHeap();
  255. }
  256. m_aLibraries.Empty();
  257. lEventLogLevel = LOG_UNDEFINED;
  258. hEventLog = NULL;
  259. }
  260. CPerfObjectAccess::~CPerfObjectAccess ()
  261. {
  262. int nNumLibraries;
  263. int nIdx;
  264. CPerfDataLibrary *pThisLibrary;
  265. // close any lingering libraries
  266. nNumLibraries = m_aLibraries.Size();
  267. for (nIdx = 0; nIdx < nNumLibraries; nIdx++) {
  268. pThisLibrary = (CPerfDataLibrary *)m_aLibraries[nIdx];
  269. CloseLibrary (pThisLibrary);
  270. FREEMEM(m_hObjectHeap, 0, pThisLibrary->pLibInfo);
  271. pThisLibrary->pLibInfo = NULL;
  272. delete pThisLibrary;
  273. }
  274. m_aLibraries.Empty();
  275. if ((m_hObjectHeap != NULL) && (m_hObjectHeap != GetProcessHeap())) {
  276. HeapDestroy (m_hObjectHeap);
  277. }
  278. }
  279. //***************************************************************************
  280. //
  281. // CPerfObjectAccess::CloseLibrary (CPerfDataLibrary *pLib)
  282. //
  283. // removes a reference to the library that contains this object and closes
  284. // the library when the last reference is removed
  285. //
  286. //***************************************************************************
  287. //
  288. DWORD
  289. CPerfObjectAccess::CloseLibrary (CPerfDataLibrary *pLib)
  290. {
  291. pExtObject pInfo;
  292. LONG lStatus;
  293. assert (pLib != NULL);
  294. assert (pLib->pLibInfo != NULL);
  295. pInfo = pLib->pLibInfo;
  296. assert (pLib->dwRefCount > 0);
  297. if (pLib->dwRefCount > 0) {
  298. pLib->dwRefCount--;
  299. if (pLib->dwRefCount == 0) {
  300. // if there's a close proc to call, then
  301. // call close procedure to close anything that may have
  302. // been allocated by the library
  303. if (pInfo->hMutex != NULL){
  304. lStatus = WaitForSingleObject (
  305. pInfo->hMutex,
  306. pInfo->dwOpenTimeout);
  307. if ( lStatus != WAIT_TIMEOUT ){
  308. if( pInfo->CloseProc != NULL ){
  309. __try{
  310. lStatus = (*pInfo->CloseProc) ();
  311. } __except (EXCEPTION_EXECUTE_HANDLER) {
  312. lStatus = ERROR_INVALID_FUNCTION;
  313. }
  314. }
  315. ReleaseMutex(pInfo->hMutex);
  316. } else {
  317. pInfo->dwLockoutCount++;
  318. }
  319. } else {
  320. lStatus = ERROR_LOCK_FAILED;
  321. }
  322. // then close everything
  323. if (pInfo->hMutex != NULL) {
  324. CloseHandle (pInfo->hMutex);
  325. pInfo->hMutex = NULL;
  326. }
  327. if (pInfo->hLibrary != NULL) {
  328. FreeLibrary (pInfo->hLibrary);
  329. pInfo->hLibrary = NULL;
  330. }
  331. if (pInfo->hPerfKey != NULL) {
  332. RegCloseKey (pInfo->hPerfKey);
  333. pInfo->hPerfKey = NULL;
  334. }
  335. }
  336. }
  337. return pLib->dwRefCount; // returns remaining references
  338. }
  339. //***************************************************************************
  340. //
  341. // CPerfObjectAccess::OpenExtObjectLibrary (pExtObject pObj)
  342. //
  343. // OpenExtObjectLibrary
  344. //
  345. // Opens the specified library and looks up the functions used by
  346. // the performance library. If the library is successfully
  347. // loaded and opened then the open procedure is called to initialize
  348. // the object.
  349. //
  350. // This function expects locked and exclusive access to the object while
  351. // it is opening. This must be provided by the calling function.
  352. //
  353. // Arguments:
  354. //
  355. // pObj -- pointer to the object information structure of the
  356. // perf object to close
  357. //
  358. //***************************************************************************
  359. //
  360. DWORD
  361. CPerfObjectAccess::OpenExtObjectLibrary (pExtObject pObj)
  362. {
  363. DWORD Status = ERROR_SUCCESS;
  364. DWORD dwOpenEvent = 0;
  365. DWORD dwType;
  366. DWORD dwSize;
  367. DWORD dwValue;
  368. // variables used for event logging
  369. DWORD dwDataIndex;
  370. WORD wStringIndex;
  371. DWORD dwRawDataDwords[8];
  372. LPWSTR szMessageArray[8];
  373. UINT nErrorMode;
  374. // check to see if the library has already been opened
  375. if (pObj->hLibrary == NULL) {
  376. // library isn't loaded yet, so
  377. // check to see if this function is enabled
  378. dwType = 0;
  379. dwSize = sizeof (dwValue);
  380. dwValue = 0;
  381. Status = RegQueryValueExW (
  382. pObj->hPerfKey,
  383. cszDisablePerformanceCounters,
  384. NULL,
  385. &dwType,
  386. (LPBYTE)&dwValue,
  387. &dwSize);
  388. if ((Status == ERROR_SUCCESS) &&
  389. (dwType == REG_DWORD) &&
  390. (dwValue == 1)) {
  391. // then DON'T Load this library
  392. Status = ERROR_SERVICE_DISABLED;
  393. } else {
  394. Status = ERROR_SUCCESS;
  395. // go ahead and load it
  396. nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS);
  397. // then load library & look up functions
  398. pObj->hLibrary = LoadLibraryExW (pObj->szLibraryName,
  399. NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  400. if (pObj->hLibrary != NULL) {
  401. const size_t cchSize = 512;
  402. WCHAR buffer[cchSize];
  403. // lookup function names
  404. pObj->OpenProc = (OPENPROC)GetProcAddress(
  405. pObj->hLibrary, pObj->szOpenProcName);
  406. if (pObj->OpenProc == NULL) {
  407. if (lEventLogLevel >= LOG_USER) {
  408. Status = GetLastError();
  409. // load data for eventlog message
  410. dwDataIndex = wStringIndex = 0;
  411. dwRawDataDwords[dwDataIndex++] =
  412. (DWORD)Status;
  413. szMessageArray[wStringIndex++] =
  414. ConvertProcName(pObj->szOpenProcName, buffer, cchSize);
  415. szMessageArray[wStringIndex++] =
  416. pObj->szLibraryName;
  417. szMessageArray[wStringIndex++] =
  418. pObj->szServiceName;
  419. ReportEventW (hEventLog,
  420. EVENTLOG_ERROR_TYPE, // error type
  421. 0, // category (not used)
  422. (DWORD)WBEMPERF_OPEN_PROC_NOT_FOUND, // event,
  423. NULL, // SID (not used),
  424. wStringIndex, // number of strings
  425. dwDataIndex*sizeof(DWORD), // sizeof raw data
  426. (LPCWSTR *)szMessageArray, // message text array
  427. (LPVOID)&dwRawDataDwords[0]); // raw data
  428. }
  429. }
  430. if (Status == ERROR_SUCCESS) {
  431. if (pObj->dwFlags & PERF_EO_QUERY_FUNC) {
  432. pObj->QueryProc = (QUERYPROC)GetProcAddress (
  433. pObj->hLibrary, pObj->szCollectProcName);
  434. pObj->CollectProc = (COLLECTPROC)pObj->QueryProc;
  435. } else {
  436. pObj->CollectProc = (COLLECTPROC)GetProcAddress (
  437. pObj->hLibrary, pObj->szCollectProcName);
  438. pObj->QueryProc = (QUERYPROC)pObj->CollectProc;
  439. }
  440. if (pObj->CollectProc == NULL) {
  441. if (lEventLogLevel >= LOG_USER) {
  442. Status = GetLastError();
  443. // load data for eventlog message
  444. dwDataIndex = wStringIndex = 0;
  445. dwRawDataDwords[dwDataIndex++] =
  446. (DWORD)Status;
  447. szMessageArray[wStringIndex++] =
  448. ConvertProcName(pObj->szCollectProcName, buffer, cchSize );
  449. szMessageArray[wStringIndex++] =
  450. pObj->szLibraryName;
  451. szMessageArray[wStringIndex++] =
  452. pObj->szServiceName;
  453. ReportEventW (hEventLog,
  454. EVENTLOG_ERROR_TYPE, // error type
  455. 0, // category (not used)
  456. (DWORD)WBEMPERF_COLLECT_PROC_NOT_FOUND, // event,
  457. NULL, // SID (not used),
  458. wStringIndex, // number of strings
  459. dwDataIndex*sizeof(DWORD), // sizeof raw data
  460. (LPCWSTR *)szMessageArray, // message text array
  461. (LPVOID)&dwRawDataDwords[0]); // raw data
  462. }
  463. }
  464. }
  465. if (Status == ERROR_SUCCESS) {
  466. pObj->CloseProc = (CLOSEPROC)GetProcAddress (
  467. pObj->hLibrary, pObj->szCloseProcName);
  468. if (pObj->CloseProc == NULL) {
  469. if (lEventLogLevel >= LOG_USER) {
  470. Status = GetLastError();
  471. // load data for eventlog message
  472. dwDataIndex = wStringIndex = 0;
  473. dwRawDataDwords[dwDataIndex++] =
  474. (DWORD)Status;
  475. szMessageArray[wStringIndex++] =
  476. ConvertProcName(pObj->szCloseProcName, buffer, cchSize);
  477. szMessageArray[wStringIndex++] =
  478. pObj->szLibraryName;
  479. szMessageArray[wStringIndex++] =
  480. pObj->szServiceName;
  481. ReportEventW (hEventLog,
  482. EVENTLOG_ERROR_TYPE, // error type
  483. 0, // category (not used)
  484. (DWORD)WBEMPERF_CLOSE_PROC_NOT_FOUND, // event,
  485. NULL, // SID (not used),
  486. wStringIndex, // number of strings
  487. dwDataIndex*sizeof(DWORD), // sizeof raw data
  488. (LPCWSTR *)szMessageArray, // message text array
  489. (LPVOID)&dwRawDataDwords[0]); // raw data
  490. }
  491. }
  492. }
  493. if (Status == ERROR_SUCCESS) {
  494. __try {
  495. // call open procedure to initialize DLL
  496. if (pObj->hMutex != NULL) {
  497. Status = WaitForSingleObject (
  498. pObj->hMutex,
  499. pObj->dwOpenTimeout);
  500. if (Status != WAIT_TIMEOUT){
  501. if( pObj->OpenProc != NULL ) {
  502. Status = (*pObj->OpenProc)(pObj->szLinkageString);
  503. }
  504. ReleaseMutex(pObj->hMutex);
  505. }
  506. else {
  507. pObj->dwLockoutCount++;
  508. }
  509. } else {
  510. Status = ERROR_LOCK_FAILED;
  511. }
  512. // check the result.
  513. if (Status != ERROR_SUCCESS) {
  514. dwOpenEvent = WBEMPERF_OPEN_PROC_FAILURE;
  515. } else {
  516. InterlockedIncrement((LONG *)&pObj->dwOpenCount);
  517. }
  518. } __except (EXCEPTION_EXECUTE_HANDLER) {
  519. Status = GetExceptionCode();
  520. dwOpenEvent = WBEMPERF_OPEN_PROC_EXCEPTION;
  521. }
  522. if (Status != ERROR_SUCCESS) {
  523. // load data for eventlog message
  524. dwDataIndex = wStringIndex = 0;
  525. dwRawDataDwords[dwDataIndex++] =
  526. (DWORD)Status;
  527. szMessageArray[wStringIndex++] =
  528. pObj->szServiceName;
  529. szMessageArray[wStringIndex++] =
  530. pObj->szLibraryName;
  531. ReportEventW (hEventLog,
  532. (WORD)EVENTLOG_ERROR_TYPE, // error type
  533. 0, // category (not used)
  534. dwOpenEvent, // event,
  535. NULL, // SID (not used),
  536. wStringIndex, // number of strings
  537. dwDataIndex*sizeof(DWORD), // sizeof raw data
  538. (LPCWSTR *)szMessageArray, // message text array
  539. (LPVOID)&dwRawDataDwords[0]); // raw data
  540. }
  541. }
  542. if (Status != ERROR_SUCCESS) {
  543. // clear fields
  544. pObj->OpenProc = NULL;
  545. pObj->CollectProc = NULL;
  546. pObj->QueryProc = NULL;
  547. pObj->CloseProc = NULL;
  548. if (pObj->hLibrary != NULL) {
  549. FreeLibrary (pObj->hLibrary);
  550. pObj->hLibrary = NULL;
  551. }
  552. } else {
  553. pObj->llLastUsedTime = GetTimeAsLongLong();
  554. }
  555. } else {
  556. Status = GetLastError();
  557. }
  558. SetErrorMode (nErrorMode);
  559. }
  560. } else {
  561. // else already open so bump the ref count
  562. pObj->llLastUsedTime = GetTimeAsLongLong();
  563. }
  564. if( ERROR_SUCCESS != Status ){
  565. if( ERROR_ACCESS_DENIED == Status ){
  566. InterlockedExchange( (LONG*)&(pObj->ADThreadId),
  567. GetCurrentThreadId() );
  568. }else{
  569. InterlockedIncrement( (LONG*)&(pObj->dwOpenFail) );
  570. }
  571. }else{
  572. InterlockedExchange( (LONG*)&(pObj->dwOpenFail), 0 );
  573. InterlockedExchange( (LONG*)&(pObj->ADThreadId), 0 );
  574. }
  575. return Status;
  576. }
  577. //***************************************************************************
  578. //
  579. // CPerfObjectAccess::AddLibrary (
  580. // IWbemClassObject *pClass,
  581. // IWbemQualifierSet *pClassQualifiers,
  582. // LPCWSTR szRegistryKey,
  583. // DWORD dwPerfIndex)
  584. //
  585. // Adds the library referenced by the class object to the list of
  586. // libraries to call
  587. //
  588. //***************************************************************************
  589. //
  590. DWORD
  591. CPerfObjectAccess::AddLibrary (
  592. IWbemClassObject *pClass,
  593. IWbemQualifierSet *pClassQualifiers,
  594. LPCWSTR szRegistryKey,
  595. DWORD dwPerfIndex)
  596. {
  597. CPerfDataLibrary *pLibEntry = NULL;
  598. LONG Status = ERROR_SUCCESS;
  599. HKEY hServicesKey = NULL;
  600. HKEY hPerfKey = NULL;
  601. LPWSTR szServiceName = NULL;
  602. HKEY hKeyLinkage;
  603. BOOL bUseQueryFn = FALSE;
  604. pExtObject pReturnObject = NULL;
  605. DWORD dwType = 0;
  606. DWORD dwSize = 0;
  607. DWORD dwFlags = 0;
  608. DWORD dwKeep;
  609. DWORD dwObjectArray[MAX_PERF_OBJECTS_IN_QUERY_FUNCTION];
  610. DWORD dwObjIndex = 0;
  611. DWORD dwMemBlockSize = sizeof(ExtObject);
  612. DWORD dwLinkageStringLen = 0;
  613. DWORD dwFirstCounter = 2;
  614. DWORD dwLastCounter = 1846;
  615. const size_t cchSize = WBEMPERF_STRING_SIZE;
  616. size_t StorageSizeA = cchSize * 3 * sizeof(CHAR);
  617. size_t StorageSizeW = cchSize * 9 * sizeof(WCHAR);
  618. LPSTR szStorageA = NULL;
  619. LPWSTR szStorageW = NULL;
  620. LPSTR szOpenProcName;
  621. LPSTR szCollectProcName;
  622. LPSTR szCloseProcName;
  623. LPWSTR szLibraryString;
  624. LPWSTR szLibraryExpPath;
  625. LPWSTR mszObjectList;
  626. LPWSTR szLinkageKeyPath;
  627. LPWSTR szLinkageString;
  628. DWORD dwOpenTimeout = 0;
  629. DWORD dwCollectTimeout = 0;
  630. LPWSTR szThisObject;
  631. LPWSTR szThisChar;
  632. LPSTR pNextStringA;
  633. LPWSTR pNextStringW;
  634. LPWSTR szServicePath;
  635. LPWSTR szMutexName;
  636. WCHAR szPID[32];
  637. szStorageW = (LPWSTR)ALLOCMEM(m_hObjectHeap, HEAP_ZERO_MEMORY, StorageSizeW );
  638. szStorageA = (LPSTR)ALLOCMEM(m_hObjectHeap, HEAP_ZERO_MEMORY, StorageSizeA );
  639. if( NULL == szStorageA || NULL == szStorageW ){
  640. Status = ERROR_OUTOFMEMORY;
  641. goto cleanup;
  642. }else{
  643. pNextStringA = szStorageA;
  644. pNextStringW = szStorageW;
  645. szOpenProcName = pNextStringA;
  646. pNextStringA += cchSize;
  647. szCollectProcName = pNextStringA;
  648. pNextStringA += cchSize;
  649. szCloseProcName = pNextStringA;
  650. szLibraryString = pNextStringW;
  651. pNextStringW += cchSize;
  652. szLibraryExpPath = pNextStringW;
  653. pNextStringW += cchSize;
  654. mszObjectList = pNextStringW;
  655. pNextStringW += cchSize;
  656. szLinkageKeyPath = pNextStringW;
  657. pNextStringW += cchSize;
  658. szLinkageString = pNextStringW;
  659. pNextStringW += cchSize;
  660. szServicePath = pNextStringW;
  661. pNextStringW += cchSize;
  662. szMutexName = pNextStringW;
  663. }
  664. assert(pClass != NULL);
  665. assert(pClassQualifiers != NULL);
  666. UNREFERENCED_PARAMETER(pClassQualifiers);
  667. UNREFERENCED_PARAMETER(pClass);
  668. pLibEntry = new CPerfDataLibrary;
  669. if ((pLibEntry != NULL) && (szRegistryKey != NULL)) {
  670. StringCchCopyW(szServicePath, cchSize, cszHklmServicesKey);
  671. Status = RegOpenKeyExW (HKEY_LOCAL_MACHINE, szServicePath,
  672. 0, KEY_READ, &hServicesKey);
  673. if (Status == ERROR_SUCCESS) {
  674. StringCchCopyW(szServicePath, cchSize, szRegistryKey);
  675. StringCchCatW(szServicePath, cchSize, cszPerformance);
  676. Status = RegOpenKeyExW (hServicesKey, szServicePath,
  677. 0, KEY_READ, &hPerfKey);
  678. if (Status == ERROR_SUCCESS) {
  679. szServiceName = (LPWSTR)szRegistryKey;
  680. // read the performance DLL name
  681. dwType = 0;
  682. dwSize = cchSize * sizeof(WCHAR);
  683. Status = RegQueryValueExW (hPerfKey,
  684. cszDLLValue,
  685. NULL,
  686. &dwType,
  687. (LPBYTE)szLibraryString,
  688. &dwSize);
  689. }
  690. }
  691. if (Status == ERROR_SUCCESS) {
  692. if (dwType == REG_EXPAND_SZ) {
  693. // expand any environment vars
  694. dwSize = ExpandEnvironmentStringsW(
  695. szLibraryString,
  696. szLibraryExpPath,
  697. cchSize);
  698. if ((dwSize > WBEMPERF_STRING_SIZE) || (dwSize == 0)) {
  699. Status = ERROR_INVALID_DLL;
  700. } else {
  701. dwSize += 1;
  702. dwSize *= sizeof(WCHAR);
  703. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  704. }
  705. } else if (dwType == REG_SZ) {
  706. // look for dll and save full file Path
  707. dwSize = SearchPathW (
  708. NULL, // use standard system search path
  709. szLibraryString,
  710. NULL,
  711. WBEMPERF_STRING_SIZE,
  712. szLibraryExpPath,
  713. NULL);
  714. if ((dwSize > WBEMPERF_STRING_SIZE) || (dwSize == 0)) {
  715. Status = ERROR_INVALID_DLL;
  716. } else {
  717. dwSize += 1;
  718. dwSize *= sizeof(WCHAR);
  719. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  720. }
  721. } else {
  722. Status = ERROR_INVALID_DLL;
  723. }
  724. if (Status == ERROR_SUCCESS) {
  725. // we have the DLL name so get the procedure names
  726. dwType = 0;
  727. dwSize = cchSize * sizeof(CHAR);
  728. Status = RegQueryValueExA (hPerfKey,
  729. caszOpenValue,
  730. NULL,
  731. &dwType,
  732. (LPBYTE)szOpenProcName,
  733. &dwSize);
  734. }
  735. if (Status == ERROR_SUCCESS) {
  736. // add in size of previous string
  737. // the size value includes the Term. NULL
  738. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  739. // we have the procedure name so get the timeout value
  740. dwType = 0;
  741. dwSize = cchSize * sizeof(WCHAR);
  742. Status = RegQueryValueExW (hPerfKey,
  743. cszOpenTimeout,
  744. NULL,
  745. &dwType,
  746. (LPBYTE)&dwOpenTimeout,
  747. &dwSize);
  748. // if error, then apply default
  749. if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
  750. dwOpenTimeout = dwExtCtrOpenProcWaitMs;
  751. Status = ERROR_SUCCESS;
  752. }
  753. }
  754. if (Status == ERROR_SUCCESS) {
  755. // add in size of previous string
  756. // the size value includes the Term. NULL
  757. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  758. // we have the procedure name so get the timeout value
  759. dwType = 0;
  760. dwSize = sizeof(dwFirstCounter);
  761. Status = RegQueryValueExW (hPerfKey,
  762. cszFirstCounter,
  763. NULL,
  764. & dwType,
  765. (LPBYTE) & dwFirstCounter,
  766. & dwSize);
  767. // if error, then apply default
  768. if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
  769. dwFirstCounter = 2; // assume this is for system base counters
  770. Status = ERROR_SUCCESS;
  771. }
  772. }
  773. if (Status == ERROR_SUCCESS) {
  774. // add in size of previous string
  775. // the size value includes the Term. NULL
  776. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  777. // we have the procedure name so get the timeout value
  778. dwType = 0;
  779. dwSize = sizeof(dwLastCounter);
  780. Status = RegQueryValueExW (hPerfKey,
  781. cszLastCounter,
  782. NULL,
  783. & dwType,
  784. (LPBYTE) & dwLastCounter,
  785. & dwSize);
  786. // if error, then apply default
  787. if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
  788. dwLastCounter = 1846; // assume this is for system base counters
  789. Status = ERROR_SUCCESS;
  790. }
  791. }
  792. if (Status == ERROR_SUCCESS) {
  793. // get next string
  794. dwType = 0;
  795. dwSize = cchSize * sizeof(CHAR);
  796. Status = RegQueryValueExA (hPerfKey,
  797. caszCloseValue,
  798. NULL,
  799. &dwType,
  800. (LPBYTE)szCloseProcName,
  801. &dwSize);
  802. }
  803. if (Status == ERROR_SUCCESS) {
  804. // add in size of previous string
  805. // the size value includes the Term. NULL
  806. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  807. // try to look up the query function which is the
  808. // preferred interface if it's not found, then
  809. // try the collect function name. If that's not found,
  810. // then bail
  811. dwType = 0;
  812. dwSize = cchSize * sizeof(CHAR);
  813. Status = RegQueryValueExA (hPerfKey,
  814. caszQueryValue,
  815. NULL,
  816. &dwType,
  817. (LPBYTE)szCollectProcName,
  818. &dwSize);
  819. if (Status == ERROR_SUCCESS) {
  820. // add in size of the Query Function Name
  821. // the size value includes the Term. NULL
  822. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  823. // get next string
  824. bUseQueryFn = TRUE;
  825. // the query function can support a static object list
  826. // so look it up
  827. } else {
  828. // the QueryFunction wasn't found so look up the
  829. // Collect Function name instead
  830. dwType = 0;
  831. dwSize = cchSize * sizeof(CHAR);
  832. Status = RegQueryValueExA (hPerfKey,
  833. caszCollectValue,
  834. NULL,
  835. &dwType,
  836. (LPBYTE)szCollectProcName,
  837. &dwSize);
  838. if (Status == ERROR_SUCCESS) {
  839. // add in size of Collect Function Name
  840. // the size value includes the Term. NULL
  841. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  842. }
  843. }
  844. if (Status == ERROR_SUCCESS) {
  845. // we have the procedure name so get the timeout value
  846. dwType = 0;
  847. dwSize = sizeof(dwCollectTimeout);
  848. Status = RegQueryValueExW (hPerfKey,
  849. cszCollectTimeout,
  850. NULL,
  851. &dwType,
  852. (LPBYTE)&dwCollectTimeout,
  853. &dwSize);
  854. // if error, then apply default
  855. if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
  856. dwCollectTimeout = dwExtCtrOpenProcWaitMs;
  857. Status = ERROR_SUCCESS;
  858. }
  859. }
  860. // get the list of supported objects if provided by the registry
  861. dwType = 0;
  862. dwSize = cchSize * sizeof(WCHAR);
  863. Status = RegQueryValueExW (hPerfKey,
  864. cszObjListValue,
  865. NULL,
  866. &dwType,
  867. (LPBYTE)mszObjectList,
  868. &dwSize);
  869. if (Status == ERROR_SUCCESS) {
  870. if (dwType != REG_MULTI_SZ) {
  871. size_t cch;
  872. // convert space delimited list to msz
  873. for (szThisChar = mszObjectList, cch = 0;
  874. *szThisChar != 0 && cch < cchSize;
  875. szThisChar++, cch++) {
  876. if (*szThisChar == L' ') *szThisChar = L'\0';
  877. }
  878. ++szThisChar;
  879. *szThisChar = 0; // add MSZ term Null
  880. }
  881. for (szThisObject = mszObjectList, dwObjIndex = 0;
  882. (*szThisObject != 0) && (dwObjIndex < MAX_PERF_OBJECTS_IN_QUERY_FUNCTION);
  883. szThisObject += lstrlenW(szThisObject) + 1) {
  884. dwObjectArray[dwObjIndex] = wcstoul(szThisObject, NULL, 10);
  885. dwObjIndex++;
  886. }
  887. if (*szThisObject != 0) {
  888. DWORD dwDataIndex = 0;
  889. WORD wStringIndex = 0;
  890. DWORD dwRawDataDwords[8];
  891. LPWSTR szMessageArray[8];
  892. dwRawDataDwords[dwDataIndex++] = (DWORD) ERROR_SUCCESS;
  893. szMessageArray[wStringIndex++] = (LPWSTR) cszObjListValue;
  894. szMessageArray[wStringIndex++] = szLibraryString;
  895. szMessageArray[wStringIndex++] = szServicePath;
  896. ReportEventW(hEventLog,
  897. EVENTLOG_WARNING_TYPE,
  898. 0,
  899. (DWORD) WBEMPERF_TOO_MANY_OBJECT_IDS,
  900. NULL,
  901. wStringIndex,
  902. dwDataIndex * sizeof(DWORD),
  903. (LPCWSTR *) szMessageArray,
  904. (LPVOID) & dwRawDataDwords[0]);
  905. }
  906. } else {
  907. // reset status since not having this is
  908. // not a showstopper
  909. Status = ERROR_SUCCESS;
  910. }
  911. if (Status == ERROR_SUCCESS) {
  912. dwType = 0;
  913. dwKeep = 0;
  914. dwSize = sizeof(dwKeep);
  915. Status = RegQueryValueExW (hPerfKey,
  916. cszKeepResident,
  917. NULL,
  918. &dwType,
  919. (LPBYTE)&dwKeep,
  920. &dwSize);
  921. if ((Status == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
  922. if (dwKeep == 1) {
  923. dwFlags |= PERF_EO_KEEP_RESIDENT;
  924. } else {
  925. // no change.
  926. }
  927. } else {
  928. // not fatal, just use the defaults.
  929. Status = ERROR_SUCCESS;
  930. }
  931. }
  932. }
  933. }
  934. if (Status == ERROR_SUCCESS) {
  935. StringCchCopyW( szLinkageKeyPath, cchSize, szServiceName);
  936. StringCchCatW( szLinkageKeyPath, cchSize, cszLinkageKey);
  937. Status = RegOpenKeyExW (
  938. hServicesKey,
  939. szLinkageKeyPath,
  940. 0L,
  941. KEY_READ,
  942. &hKeyLinkage);
  943. if (Status == ERROR_SUCCESS) {
  944. // look up export value string
  945. dwSize = sizeof(szLinkageString);
  946. dwType = 0;
  947. Status = RegQueryValueExW (
  948. hKeyLinkage,
  949. cszExportValue,
  950. NULL,
  951. &dwType,
  952. (LPBYTE)&szLinkageString,
  953. &dwSize);
  954. if ((Status != ERROR_SUCCESS) ||
  955. ((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))) {
  956. // clear buffer
  957. dwLinkageStringLen = 0;
  958. // not finding a linkage key is not fatal so correct
  959. // status
  960. Status = ERROR_SUCCESS;
  961. } else {
  962. // add size of linkage string to buffer
  963. // the size value includes the Term. NULL
  964. dwLinkageStringLen = dwSize;
  965. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  966. }
  967. RegCloseKey (hKeyLinkage);
  968. } else {
  969. // not finding a linkage key is not fatal so correct
  970. // status
  971. Status = ERROR_SUCCESS;
  972. }
  973. }
  974. if (Status == ERROR_SUCCESS) {
  975. size_t cbDestSize;
  976. // add in size of service name
  977. dwSize = lstrlenW (szServiceName);
  978. dwSize += 1;
  979. dwSize *= sizeof(WCHAR);
  980. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  981. cbDestSize = dwMemBlockSize - sizeof(pExtObject);
  982. // allocate and initialize a new ext. object block
  983. pReturnObject = (pExtObject)ALLOCMEM(m_hObjectHeap,
  984. HEAP_ZERO_MEMORY, dwMemBlockSize);
  985. if (pReturnObject != NULL) {
  986. // copy values to new buffer (all others are NULL)
  987. pNextStringA = (LPSTR)&pReturnObject[1];
  988. // copy Open Procedure Name
  989. pReturnObject->szOpenProcName = pNextStringA;
  990. StringCbCopyA( pNextStringA, cbDestSize, szOpenProcName );
  991. pNextStringA += lstrlenA (pNextStringA) + 1;
  992. pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
  993. cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringA - (PUCHAR)pReturnObject);
  994. pReturnObject->dwOpenTimeout = dwOpenTimeout;
  995. // copy collect function or query function, depending
  996. pReturnObject->szCollectProcName = pNextStringA;
  997. StringCbCopyA(pNextStringA, cbDestSize, szCollectProcName);
  998. pNextStringA += lstrlenA (pNextStringA) + 1;
  999. pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
  1000. cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringA - (PUCHAR)pReturnObject);
  1001. pReturnObject->dwCollectTimeout = dwCollectTimeout;
  1002. // copy Close Procedure Name
  1003. pReturnObject->szCloseProcName = pNextStringA;
  1004. StringCbCopyA(pNextStringA, cbDestSize, szCloseProcName);
  1005. pNextStringA += lstrlenA (pNextStringA) + 1;
  1006. pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
  1007. cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringA - (PUCHAR)pReturnObject);
  1008. // copy Library path
  1009. pNextStringW = (LPWSTR)pNextStringA;
  1010. pReturnObject->szLibraryName = pNextStringW;
  1011. StringCbCopyW(pNextStringW, cbDestSize, szLibraryExpPath);
  1012. pNextStringW += lstrlenW (pNextStringW) + 1;
  1013. pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
  1014. cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringW - (PUCHAR)pReturnObject);
  1015. // copy Linkage String if there is one
  1016. if (*szLinkageString != 0) {
  1017. pReturnObject->szLinkageString = pNextStringW;
  1018. if( cbDestSize > dwLinkageStringLen ){
  1019. memcpy (pNextStringW, szLinkageString, dwLinkageStringLen);
  1020. // length includes extra NULL char and is in BYTES
  1021. pNextStringW += (dwLinkageStringLen / sizeof (WCHAR));
  1022. pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
  1023. cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringW - (PUCHAR)pReturnObject);
  1024. }
  1025. }
  1026. // copy Service name
  1027. pReturnObject->szServiceName = pNextStringW;
  1028. StringCbCopyW(pNextStringW, cbDestSize, szServiceName);
  1029. pNextStringW += lstrlenW (pNextStringW) + 1;
  1030. pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
  1031. cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringW - (PUCHAR)pReturnObject);
  1032. // load flags
  1033. if (bUseQueryFn) {
  1034. dwFlags |= PERF_EO_QUERY_FUNC;
  1035. }
  1036. pReturnObject->dwFlags = dwFlags;
  1037. pReturnObject->hPerfKey = hPerfKey;
  1038. hPerfKey = NULL;
  1039. // load Object array
  1040. if (dwObjIndex > 0) {
  1041. pReturnObject->dwNumObjects = dwObjIndex;
  1042. memcpy (pReturnObject->dwObjList,
  1043. dwObjectArray, (dwObjIndex * sizeof(dwObjectArray[0])));
  1044. }
  1045. pReturnObject->dwFirstCounter = dwFirstCounter;
  1046. pReturnObject->dwLastCounter = dwLastCounter;
  1047. pReturnObject->llLastUsedTime = 0;
  1048. // create Mutex name
  1049. StringCchCopyW(szMutexName, cchSize, szRegistryKey);
  1050. StringCchCatW( szMutexName, cchSize, (LPCWSTR)L"_Perf_Library_Lock_PID_");
  1051. _ultow ((ULONG)GetCurrentProcessId(), szPID, 16);
  1052. StringCchCatW( szMutexName, cchSize, szPID);
  1053. // pReturnObject->hMutex = CreateMutexW (NULL, FALSE, szMutexName);
  1054. pReturnObject->hMutex = CreateMutexAsProcess(szMutexName);
  1055. } else {
  1056. Status = ERROR_OUTOFMEMORY;
  1057. }
  1058. }
  1059. if (Status != ERROR_SUCCESS) {
  1060. SetLastError (Status);
  1061. if (pReturnObject != NULL) {
  1062. // release the new block
  1063. hPerfKey = pReturnObject->hPerfKey;
  1064. FREEMEM (m_hObjectHeap, 0, pReturnObject);
  1065. }
  1066. } else {
  1067. if (pReturnObject != NULL) {
  1068. Status = OpenExtObjectLibrary (pReturnObject);
  1069. if (Status == ERROR_SUCCESS) {
  1070. if (dwPerfIndex != 0) {
  1071. // initialize the perf index string
  1072. _ultow (dwPerfIndex, pLibEntry->szQueryString, 10);
  1073. } else {
  1074. StringCchCopyW(pLibEntry->szQueryString,
  1075. MAX_PERF_OBJECTS_IN_QUERY_FUNCTION * 10, cszGlobal);
  1076. }
  1077. // save the pointer to the initialize structure
  1078. pLibEntry->pLibInfo = pReturnObject;
  1079. m_aLibraries.Add(pLibEntry);
  1080. pLibEntry->dwRefCount++;
  1081. assert(pLibEntry->dwRefCount == 1);
  1082. } else {
  1083. // release the new block
  1084. hPerfKey = pReturnObject->hPerfKey;
  1085. FREEMEM (m_hObjectHeap, 0, pReturnObject);
  1086. }
  1087. }
  1088. }
  1089. if (hServicesKey != NULL) RegCloseKey (hServicesKey);
  1090. } else { // gets here if pLibEntry == NULL and/or szRegistryKey == NULL
  1091. if (pLibEntry == NULL) {
  1092. Status = ERROR_OUTOFMEMORY;
  1093. }
  1094. if (szRegistryKey == NULL) {
  1095. Status = ERROR_INVALID_PARAMETER;
  1096. }
  1097. }
  1098. if ((Status != ERROR_SUCCESS) && (pLibEntry != NULL))
  1099. delete pLibEntry;
  1100. cleanup:
  1101. if( hPerfKey != NULL ){
  1102. RegCloseKey( hPerfKey );
  1103. }
  1104. FREEMEM (m_hObjectHeap, 0, szStorageA );
  1105. FREEMEM (m_hObjectHeap, 0, szStorageW );
  1106. return Status;
  1107. }
  1108. //***************************************************************************
  1109. //
  1110. // CPerfObjectAccess::AddClass (IWbemClassObject *pClass, BOOL bCatalogQuery)
  1111. //
  1112. // Adds the specified WBEM performance object class and any required library
  1113. // entries to the access object.
  1114. //
  1115. //***************************************************************************
  1116. //
  1117. DWORD
  1118. CPerfObjectAccess::AddClass (IWbemClassObject *pClass, BOOL bCatalogQuery)
  1119. {
  1120. CPerfDataLibrary *pLibEntry = NULL;
  1121. CPerfDataLibrary *pThisLibEntry = NULL;
  1122. DWORD dwIndex, dwEnd;
  1123. LPWSTR szRegistryKey = NULL;
  1124. IWbemQualifierSet *pClassQualifiers = NULL;
  1125. VARIANT vRegistryKey;
  1126. HRESULT hRes;
  1127. DWORD dwReturn = ERROR_SUCCESS;
  1128. DWORD dwPerfIndex = 0;
  1129. CBSTR cbPerfIndex(cszPerfIndex);
  1130. CBSTR cbRegistryKey(cszRegistryKey);
  1131. if( NULL == (BSTR)cbPerfIndex ||
  1132. NULL == (BSTR)cbRegistryKey ){
  1133. return ERROR_OUTOFMEMORY;
  1134. }
  1135. VariantInit (&vRegistryKey);
  1136. // get the Qualifier Set for this class
  1137. hRes = pClass->GetQualifierSet(&pClassQualifiers);
  1138. if( NULL == pClassQualifiers ){
  1139. return hRes;
  1140. }
  1141. // now get the library and procedure names
  1142. hRes = pClassQualifiers->Get( cbRegistryKey, 0, &vRegistryKey, 0);
  1143. if ((hRes == 0) && (vRegistryKey.vt == VT_BSTR)) {
  1144. szRegistryKey = Macro_CloneLPWSTR(V_BSTR(&vRegistryKey));
  1145. if (szRegistryKey == NULL) {
  1146. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  1147. }
  1148. else {
  1149. // now also get the perf index
  1150. if (bCatalogQuery) {
  1151. // then insert 0 for the perf index to indicate a "GLOBAL"
  1152. // query
  1153. dwPerfIndex = 0;
  1154. } else {
  1155. VariantClear (&vRegistryKey);
  1156. hRes = pClassQualifiers->Get( cbPerfIndex, 0, &vRegistryKey, 0);
  1157. if (hRes == 0) {
  1158. dwPerfIndex = (DWORD)V_UI4(&vRegistryKey);
  1159. } else {
  1160. // unable to find NtPerfLibrary entry
  1161. dwReturn = ERROR_FILE_NOT_FOUND;
  1162. }
  1163. }
  1164. }
  1165. } else {
  1166. // unable to find NtPerfLibrary entry
  1167. dwReturn = ERROR_FILE_NOT_FOUND;
  1168. }
  1169. if (pClassQualifiers != NULL) pClassQualifiers->Release();
  1170. if (dwReturn == ERROR_SUCCESS) {
  1171. // find matching library in the array
  1172. dwEnd = m_aLibraries.Size();
  1173. if (dwEnd > 0) {
  1174. // walk down the list of libraries
  1175. for (dwIndex = 0; dwIndex < dwEnd; dwIndex++) {
  1176. // see if this library entry is good enough to keep
  1177. // The library is assumed to be a match if the
  1178. // lib. name and all proc's are the same.
  1179. pThisLibEntry = (CPerfDataLibrary *)m_aLibraries[dwIndex];
  1180. assert (pThisLibEntry != NULL); // it should have been removed!
  1181. // make sure it's complete
  1182. assert (pThisLibEntry->pLibInfo->szServiceName != NULL);
  1183. if (lstrcmpiW (szRegistryKey, pThisLibEntry->pLibInfo->szServiceName) == 0) {
  1184. pLibEntry = pThisLibEntry;
  1185. break;
  1186. } else {
  1187. // wrong library
  1188. // so continue
  1189. }
  1190. }
  1191. }
  1192. if (pLibEntry == NULL) {
  1193. // add this class & it's library to the list
  1194. dwReturn = AddLibrary (pClass, pClassQualifiers, szRegistryKey, dwPerfIndex);
  1195. } else {
  1196. WCHAR wszNewIndex[WBEMPERF_STRING_SIZE];
  1197. pLibEntry->dwRefCount++;
  1198. _ultow (dwPerfIndex, wszNewIndex, 10);
  1199. if (!IsNumberInUnicodeList (dwPerfIndex, pLibEntry->szQueryString)) {
  1200. // then add it to the list
  1201. StringCchCatW(pLibEntry->szQueryString,
  1202. MAX_PERF_OBJECTS_IN_QUERY_FUNCTION*10, cszSpace);
  1203. StringCchCatW(pLibEntry->szQueryString,
  1204. MAX_PERF_OBJECTS_IN_QUERY_FUNCTION*10, wszNewIndex);
  1205. }
  1206. }
  1207. }
  1208. if (szRegistryKey != NULL) delete szRegistryKey;
  1209. VariantClear(&vRegistryKey);
  1210. return dwReturn;
  1211. }
  1212. //***************************************************************************
  1213. //
  1214. // CPerfObjectAccess::CollectData (LPBYTE pBuffer,
  1215. // LPDWORD pdwBufferSize, LPWSTR pszItemList)
  1216. //
  1217. // Collects data from the perf objects and libraries added to the access
  1218. // object
  1219. //
  1220. // Inputs:
  1221. //
  1222. // pBuffer - pointer to start of data block
  1223. // where data is being collected
  1224. //
  1225. // pdwBufferSize - pointer to size of data buffer
  1226. //
  1227. // pszItemList - string to pass to ext DLL
  1228. //
  1229. // Outputs:
  1230. //
  1231. // *lppDataDefinition - set to location for next Type
  1232. // Definition if successful
  1233. //
  1234. // Returns:
  1235. //
  1236. // 0 if successful, else Win 32 error code of failure
  1237. //
  1238. //
  1239. //***************************************************************************
  1240. //
  1241. DWORD
  1242. CPerfObjectAccess::CollectData (LPBYTE pBuffer, LPDWORD pdwBufferSize, LPWSTR pszItemList)
  1243. {
  1244. LPWSTR lpValueName = NULL;
  1245. LPBYTE lpData = pBuffer;
  1246. LPDWORD lpcbData = pdwBufferSize;
  1247. LPVOID lpDataDefinition = NULL;
  1248. DWORD Win32Error=ERROR_SUCCESS; // Failure code
  1249. DWORD BytesLeft;
  1250. DWORD NumObjectTypes;
  1251. LPVOID lpExtDataBuffer = NULL;
  1252. LPVOID lpCallBuffer = NULL;
  1253. LPVOID lpLowGuardPage = NULL;
  1254. LPVOID lpHiGuardPage = NULL;
  1255. LPVOID lpEndPointer = NULL;
  1256. LPVOID lpBufferBefore = NULL;
  1257. LPVOID lpBufferAfter = NULL;
  1258. LPDWORD lpCheckPointer;
  1259. LARGE_INTEGER liStartTime, liEndTime, liWaitTime;
  1260. pExtObject pThisExtObj = NULL;
  1261. BOOL bGuardPageOK;
  1262. BOOL bBufferOK;
  1263. BOOL bException;
  1264. BOOL bUseSafeBuffer;
  1265. BOOL bUnlockObjData = FALSE;
  1266. LPWSTR szMessageArray[8];
  1267. DWORD dwRawDataDwords[8]; // raw data buffer
  1268. DWORD dwDataIndex;
  1269. WORD wStringIndex;
  1270. LONG lReturnValue = ERROR_SUCCESS;
  1271. LONG lInstIndex;
  1272. PERF_OBJECT_TYPE *pObject, *pNextObject;
  1273. PERF_INSTANCE_DEFINITION *pInstance;
  1274. PERF_DATA_BLOCK *pPerfData;
  1275. BOOL bForeignDataBuffer;
  1276. BOOL bCheckThisService;
  1277. DWORD dwItemsInList = 0;
  1278. DWORD dwIndex, dwEntry;
  1279. CPerfDataLibrary *pThisLib;
  1280. liStartTime.QuadPart = 0;
  1281. liEndTime.QuadPart = 0;
  1282. if (lExtCounterTestLevel < EXT_TEST_NOMEMALLOC) {
  1283. bUseSafeBuffer = TRUE;
  1284. } else {
  1285. bUseSafeBuffer = FALSE;
  1286. }
  1287. if (lReturnValue == ERROR_SUCCESS) {
  1288. if (*pdwBufferSize > (sizeof(PERF_DATA_BLOCK) *2)) {
  1289. MonBuildPerfDataBlock(
  1290. (PERF_DATA_BLOCK *)pBuffer,
  1291. &lpDataDefinition,
  1292. 0,0);
  1293. dwItemsInList = m_aLibraries.Size();
  1294. } else {
  1295. lReturnValue = ERROR_MORE_DATA;
  1296. dwItemsInList = 0;
  1297. }
  1298. if (dwItemsInList > 0) {
  1299. for (dwEntry = 0; dwEntry < dwItemsInList; dwEntry++) {
  1300. pThisLib = (CPerfDataLibrary *)m_aLibraries[dwEntry];
  1301. assert (pThisLib != NULL);
  1302. bCheckThisService = FALSE;
  1303. pThisExtObj = pThisLib->pLibInfo;
  1304. if (pszItemList == NULL) {
  1305. // use the one for this library
  1306. lpValueName = pThisLib->szQueryString;
  1307. } else {
  1308. // use the one passed by the caller
  1309. lpValueName = pszItemList;
  1310. }
  1311. if (lpValueName == NULL) {
  1312. lpValueName = (LPWSTR) cszGlobal;
  1313. }
  1314. // convert timeout value
  1315. liWaitTime.QuadPart = MakeTimeOutValue (pThisExtObj->dwCollectTimeout);
  1316. // initialize values to pass to the extensible counter function
  1317. NumObjectTypes = 0;
  1318. BytesLeft = (DWORD) (*lpcbData - ((LPBYTE)lpDataDefinition - lpData));
  1319. bException = FALSE;
  1320. if (lstrcmpiW(lpValueName, cszGlobal) == 0 || lstrcmpiW(lpValueName, cszCostly) == 0) {
  1321. bCheckThisService = TRUE;
  1322. }
  1323. else {
  1324. LPWSTR szThisChar;
  1325. LPWSTR szThisObject = NULL;
  1326. DWORD dwThisObject;
  1327. DWORD dwIndex;
  1328. for (szThisChar = lpValueName; * szThisChar != L'\0'; szThisChar ++) {
  1329. if (* szThisChar == L' ') {
  1330. if (szThisObject == NULL) {
  1331. continue;
  1332. }
  1333. else {
  1334. * szThisChar = L'\0';
  1335. dwThisObject = wcstoul(szThisObject, NULL, 0);
  1336. szThisObject = NULL;
  1337. * szThisChar = L' ';
  1338. for (dwIndex = 0; dwIndex < pThisExtObj->dwNumObjects; dwIndex ++) {
  1339. if (pThisExtObj->dwObjList[dwIndex] == dwThisObject) {
  1340. bCheckThisService = TRUE;
  1341. break;
  1342. }
  1343. }
  1344. if (! bCheckThisService) {
  1345. if (dwThisObject >= pThisExtObj->dwFirstCounter
  1346. && dwThisObject <= pThisExtObj->dwLastCounter) {
  1347. bCheckThisService = TRUE;
  1348. }
  1349. }
  1350. if (bCheckThisService) break;
  1351. }
  1352. }
  1353. else if (szThisObject == NULL) {
  1354. szThisObject = szThisChar;
  1355. }
  1356. }
  1357. if (! bCheckThisService && szThisObject != NULL) {
  1358. dwThisObject = wcstoul(szThisObject, NULL, 0);
  1359. szThisObject = NULL;
  1360. for (dwIndex = 0; dwIndex < pThisExtObj->dwNumObjects; dwIndex ++) {
  1361. if (pThisExtObj->dwObjList[dwIndex] == dwThisObject) {
  1362. bCheckThisService = TRUE;
  1363. break;
  1364. }
  1365. }
  1366. if (! bCheckThisService) {
  1367. if (dwThisObject >= pThisExtObj->dwFirstCounter
  1368. && dwThisObject <= pThisExtObj->dwLastCounter) {
  1369. bCheckThisService = TRUE;
  1370. }
  1371. }
  1372. }
  1373. }
  1374. if (! bCheckThisService) continue;
  1375. if (pThisExtObj->hLibrary == NULL) {
  1376. // lock library object
  1377. if (pThisExtObj->hMutex != NULL) {
  1378. Win32Error = WaitForSingleObject (
  1379. pThisExtObj->hMutex,
  1380. pThisExtObj->dwCollectTimeout);
  1381. if (Win32Error != WAIT_TIMEOUT) {
  1382. Win32Error = ERROR_INVALID_ACCESS;
  1383. // if necessary, open the library
  1384. if (pThisExtObj->hLibrary == NULL) {
  1385. // make sure the library is open
  1386. if( pThisExtObj->dwOpenFail == 0 &&
  1387. GetCurrentThreadId() != pThisExtObj->ADThreadId ){
  1388. Win32Error = OpenExtObjectLibrary(pThisExtObj);
  1389. }
  1390. }
  1391. ReleaseMutex (pThisExtObj->hMutex);
  1392. if( ERROR_SUCCESS != Win32Error ){
  1393. // assume error has been posted
  1394. continue;
  1395. }
  1396. } else {
  1397. pThisExtObj->dwLockoutCount++;
  1398. }
  1399. } else {
  1400. Win32Error = ERROR_LOCK_FAILED;
  1401. }
  1402. } else {
  1403. // library should be ready to use
  1404. }
  1405. // allocate a local block of memory to pass to the
  1406. // extensible counter function.
  1407. if (bUseSafeBuffer) {
  1408. lpExtDataBuffer = ALLOCMEM (m_hObjectHeap,
  1409. HEAP_ZERO_MEMORY, BytesLeft + (2*GUARD_PAGE_SIZE));
  1410. } else {
  1411. lpExtDataBuffer =
  1412. lpCallBuffer = lpDataDefinition;
  1413. }
  1414. if (lpExtDataBuffer != NULL) {
  1415. if (bUseSafeBuffer) {
  1416. // set buffer pointers
  1417. lpLowGuardPage = lpExtDataBuffer;
  1418. lpCallBuffer = (LPBYTE)lpExtDataBuffer + GUARD_PAGE_SIZE;
  1419. lpHiGuardPage = (LPBYTE)lpCallBuffer + BytesLeft;
  1420. lpEndPointer = (LPBYTE)lpHiGuardPage + GUARD_PAGE_SIZE;
  1421. lpBufferBefore = lpCallBuffer;
  1422. lpBufferAfter = NULL;
  1423. // initialize GuardPage Data
  1424. memset (lpLowGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
  1425. memset (lpHiGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
  1426. }
  1427. __try {
  1428. //
  1429. // Collect data from extesible objects
  1430. //
  1431. bUnlockObjData = FALSE;
  1432. if (pThisExtObj->hMutex != NULL) {
  1433. Win32Error = WaitForSingleObject (
  1434. pThisExtObj->hMutex,
  1435. pThisExtObj->dwCollectTimeout);
  1436. if ( Win32Error != WAIT_TIMEOUT ){
  1437. if( pThisExtObj->CollectProc != NULL) {
  1438. bUnlockObjData = TRUE;
  1439. QueryPerformanceCounter (&liStartTime);
  1440. Win32Error = (*pThisExtObj->CollectProc) (
  1441. lpValueName,
  1442. &lpCallBuffer,
  1443. &BytesLeft,
  1444. &NumObjectTypes);
  1445. QueryPerformanceCounter (&liEndTime);
  1446. pThisExtObj->llLastUsedTime = GetTimeAsLongLong();
  1447. }
  1448. ReleaseMutex (pThisExtObj->hMutex);
  1449. bUnlockObjData = FALSE;
  1450. } else {
  1451. pThisExtObj->dwLockoutCount++;
  1452. }
  1453. } else {
  1454. Win32Error = ERROR_LOCK_FAILED;
  1455. }
  1456. if ((Win32Error == ERROR_SUCCESS) && (BytesLeft > 0)) {
  1457. // increment perf counters
  1458. InterlockedIncrement ((LONG *)&pThisExtObj->dwCollectCount);
  1459. pThisExtObj->llElapsedTime +=
  1460. liEndTime.QuadPart - liStartTime.QuadPart;
  1461. if (bUseSafeBuffer) {
  1462. // a data buffer was returned and
  1463. // the function returned OK so see how things
  1464. // turned out...
  1465. //
  1466. lpBufferAfter = lpCallBuffer;
  1467. //
  1468. // check for buffer corruption here
  1469. //
  1470. bBufferOK = TRUE; // assume it's ok until a check fails
  1471. //
  1472. if (lExtCounterTestLevel <= EXT_TEST_BASIC) {
  1473. //
  1474. // check 1: bytes left should be the same as
  1475. // new data buffer ptr - orig data buffer ptr
  1476. //
  1477. if (BytesLeft != (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore)) {
  1478. if (lEventLogLevel >= LOG_DEBUG) {
  1479. // issue WARNING, that bytes left param is incorrect
  1480. // load data for eventlog message
  1481. // since this error is correctable (though with
  1482. // some risk) this won't be reported at LOG_USER
  1483. // level
  1484. dwDataIndex = wStringIndex = 0;
  1485. dwRawDataDwords[dwDataIndex++] = BytesLeft;
  1486. dwRawDataDwords[dwDataIndex++] =
  1487. (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
  1488. szMessageArray[wStringIndex++] =
  1489. pThisExtObj->szServiceName;
  1490. szMessageArray[wStringIndex++] =
  1491. pThisExtObj->szLibraryName;
  1492. ReportEventW (hEventLog,
  1493. EVENTLOG_WARNING_TYPE, // error type
  1494. 0, // category (not used)
  1495. (DWORD)WBEMPERF_BUFFER_POINTER_MISMATCH, // event,
  1496. NULL, // SID (not used),
  1497. wStringIndex, // number of strings
  1498. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1499. (LPCWSTR *)szMessageArray, // message text array
  1500. (LPVOID)&dwRawDataDwords[0]); // raw data
  1501. }
  1502. // we'll keep the buffer, since the returned bytes left
  1503. // value is ignored anyway, in order to make the
  1504. // rest of this function work, we'll fix it here
  1505. BytesLeft = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
  1506. }
  1507. //
  1508. // check 2: buffer after ptr should be < hi Guard page ptr
  1509. //
  1510. if (((LPBYTE)lpBufferAfter >= (LPBYTE)lpHiGuardPage) && bBufferOK) {
  1511. // see if they exceeded the allocated memory
  1512. if ((LPBYTE)lpBufferAfter >= (LPBYTE)lpEndPointer) {
  1513. // this is very serious since they've probably trashed
  1514. // the heap by overwriting the heap sig. block
  1515. // issue ERROR, buffer overrun
  1516. if (lEventLogLevel >= LOG_USER) {
  1517. // load data for eventlog message
  1518. dwDataIndex = wStringIndex = 0;
  1519. dwRawDataDwords[dwDataIndex++] =
  1520. (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage);
  1521. szMessageArray[wStringIndex++] =
  1522. pThisExtObj->szLibraryName;
  1523. szMessageArray[wStringIndex++] =
  1524. pThisExtObj->szServiceName;
  1525. ReportEventW (hEventLog,
  1526. EVENTLOG_ERROR_TYPE, // error type
  1527. 0, // category (not used)
  1528. (DWORD)WBEMPERF_HEAP_ERROR, // event,
  1529. NULL, // SID (not used),
  1530. wStringIndex, // number of strings
  1531. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1532. (LPCWSTR *)szMessageArray, // message text array
  1533. (LPVOID)&dwRawDataDwords[0]); // raw data
  1534. }
  1535. } else {
  1536. // issue ERROR, buffer overrun
  1537. if (lEventLogLevel >= LOG_USER) {
  1538. // load data for eventlog message
  1539. dwDataIndex = wStringIndex = 0;
  1540. dwRawDataDwords[dwDataIndex++] =
  1541. (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage);
  1542. szMessageArray[wStringIndex++] =
  1543. pThisExtObj->szLibraryName;
  1544. szMessageArray[wStringIndex++] =
  1545. pThisExtObj->szServiceName;
  1546. ReportEventW (hEventLog,
  1547. EVENTLOG_ERROR_TYPE, // error type
  1548. 0, // category (not used)
  1549. (DWORD)WBEMPERF_BUFFER_OVERFLOW, // event,
  1550. NULL, // SID (not used),
  1551. wStringIndex, // number of strings
  1552. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1553. (LPCWSTR *)szMessageArray, // message text array
  1554. (LPVOID)&dwRawDataDwords[0]); // raw data
  1555. }
  1556. }
  1557. bBufferOK = FALSE;
  1558. // since the DLL overran the buffer, the buffer
  1559. // must be too small (no comments about the DLL
  1560. // will be made here) so the status will be
  1561. // changed to ERROR_MORE_DATA and the function
  1562. // will return.
  1563. Win32Error = ERROR_MORE_DATA;
  1564. }
  1565. //
  1566. // check 3: check lo guard page for corruption
  1567. //
  1568. if (bBufferOK) {
  1569. bGuardPageOK = TRUE;
  1570. for (lpCheckPointer = (LPDWORD)lpLowGuardPage;
  1571. lpCheckPointer < (LPDWORD)lpBufferBefore;
  1572. lpCheckPointer++) {
  1573. if (*lpCheckPointer != GUARD_PAGE_DWORD) {
  1574. bGuardPageOK = FALSE;
  1575. break;
  1576. }
  1577. }
  1578. if (!bGuardPageOK) {
  1579. // issue ERROR, Lo Guard Page corrupted
  1580. if (lEventLogLevel >= LOG_USER) {
  1581. // load data for eventlog message
  1582. dwDataIndex = wStringIndex = 0;
  1583. szMessageArray[wStringIndex++] =
  1584. pThisExtObj->szLibraryName;
  1585. szMessageArray[wStringIndex++] =
  1586. pThisExtObj->szServiceName;
  1587. ReportEventW (hEventLog,
  1588. EVENTLOG_ERROR_TYPE, // error type
  1589. 0, // category (not used)
  1590. (DWORD)WBEMPERF_GUARD_PAGE_VIOLATION, // event
  1591. NULL, // SID (not used),
  1592. wStringIndex, // number of strings
  1593. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1594. (LPCWSTR *)szMessageArray, // message text array
  1595. (LPVOID)&dwRawDataDwords[0]); // raw data
  1596. }
  1597. bBufferOK = FALSE;
  1598. }
  1599. }
  1600. //
  1601. // check 4: check hi guard page for corruption
  1602. //
  1603. if (bBufferOK) {
  1604. bGuardPageOK = TRUE;
  1605. for (lpCheckPointer = (LPDWORD)lpHiGuardPage;
  1606. lpCheckPointer < (LPDWORD)lpEndPointer;
  1607. lpCheckPointer++) {
  1608. if (*lpCheckPointer != GUARD_PAGE_DWORD) {
  1609. bGuardPageOK = FALSE;
  1610. break;
  1611. }
  1612. }
  1613. if (!bGuardPageOK) {
  1614. // issue ERROR, Hi Guard Page corrupted
  1615. if (lEventLogLevel >= LOG_USER) {
  1616. // load data for eventlog message
  1617. dwDataIndex = wStringIndex = 0;
  1618. szMessageArray[wStringIndex++] =
  1619. pThisExtObj->szLibraryName;
  1620. szMessageArray[wStringIndex++] =
  1621. pThisExtObj->szServiceName;
  1622. ReportEventW (hEventLog,
  1623. EVENTLOG_ERROR_TYPE, // error type
  1624. 0, // category (not used)
  1625. (DWORD)WBEMPERF_GUARD_PAGE_VIOLATION, // event,
  1626. NULL, // SID (not used),
  1627. wStringIndex, // number of strings
  1628. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1629. (LPCWSTR *)szMessageArray, // message text array
  1630. (LPVOID)&dwRawDataDwords[0]); // raw data
  1631. }
  1632. bBufferOK = FALSE;
  1633. }
  1634. }
  1635. //
  1636. if ((lExtCounterTestLevel <= EXT_TEST_ALL) && bBufferOK) {
  1637. //
  1638. // Internal consistency checks
  1639. //
  1640. //
  1641. // Check 5: Check object length field values
  1642. //
  1643. // first test to see if this is a foreign
  1644. // computer data block or not
  1645. //
  1646. pPerfData = (PERF_DATA_BLOCK *)lpBufferBefore;
  1647. if ((pPerfData->Signature[0] == (WCHAR)'P') &&
  1648. (pPerfData->Signature[1] == (WCHAR)'E') &&
  1649. (pPerfData->Signature[2] == (WCHAR)'R') &&
  1650. (pPerfData->Signature[3] == (WCHAR)'F')) {
  1651. // if this is a foreign computer data block, then the
  1652. // first object is after the header
  1653. pObject = (PERF_OBJECT_TYPE *) (
  1654. (LPBYTE)pPerfData + pPerfData->HeaderLength);
  1655. bForeignDataBuffer = TRUE;
  1656. } else {
  1657. // otherwise, if this is just a buffer from
  1658. // an extensible counter, the object starts
  1659. // at the beginning of the buffer
  1660. pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
  1661. bForeignDataBuffer = FALSE;
  1662. }
  1663. // go to where the pointers say the end of the
  1664. // buffer is and then see if it's where it
  1665. // should be
  1666. for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
  1667. pObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  1668. pObject->TotalByteLength);
  1669. }
  1670. if ((LPBYTE)pObject != (LPBYTE)lpCallBuffer) {
  1671. // then a length field is incorrect. This is FATAL
  1672. // since it can corrupt the rest of the buffer
  1673. // and render the buffer unusable.
  1674. if (lEventLogLevel >= LOG_USER) {
  1675. // load data for eventlog message
  1676. dwDataIndex = wStringIndex = 0;
  1677. dwRawDataDwords[dwDataIndex++] = NumObjectTypes;
  1678. szMessageArray[wStringIndex++] =
  1679. pThisExtObj->szLibraryName;
  1680. szMessageArray[wStringIndex++] =
  1681. pThisExtObj->szServiceName;
  1682. ReportEventW (hEventLog,
  1683. EVENTLOG_ERROR_TYPE, // error type
  1684. 0, // category (not used)
  1685. (DWORD)WBEMPERF_INCORRECT_OBJECT_LENGTH, // event,
  1686. NULL, // SID (not used),
  1687. wStringIndex, // number of strings
  1688. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1689. (LPCWSTR *)szMessageArray, // message text array
  1690. (LPVOID)&dwRawDataDwords[0]); // raw data
  1691. }
  1692. bBufferOK = FALSE;
  1693. }
  1694. //
  1695. // Test 6: Test instance field size values
  1696. //
  1697. if (bBufferOK) {
  1698. // set object pointer
  1699. if (bForeignDataBuffer) {
  1700. pObject = (PERF_OBJECT_TYPE *) (
  1701. (LPBYTE)pPerfData + pPerfData->HeaderLength);
  1702. } else {
  1703. // otherwise, if this is just a buffer from
  1704. // an extensible counter, the object starts
  1705. // at the beginning of the buffer
  1706. pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
  1707. }
  1708. for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
  1709. pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  1710. pObject->TotalByteLength);
  1711. if (pObject->NumInstances != PERF_NO_INSTANCES) {
  1712. pInstance = (PERF_INSTANCE_DEFINITION *)
  1713. ((LPBYTE)pObject + pObject->DefinitionLength);
  1714. lInstIndex = 0;
  1715. while (lInstIndex < pObject->NumInstances) {
  1716. PERF_COUNTER_BLOCK *pCounterBlock;
  1717. pCounterBlock = (PERF_COUNTER_BLOCK *)
  1718. ((PCHAR) pInstance + pInstance->ByteLength);
  1719. pInstance = (PERF_INSTANCE_DEFINITION *)
  1720. ((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
  1721. lInstIndex++;
  1722. }
  1723. if ((LPBYTE)pInstance > (LPBYTE)pNextObject) {
  1724. bBufferOK = FALSE;
  1725. }
  1726. }
  1727. if (!bBufferOK) {
  1728. break;
  1729. } else {
  1730. pObject = pNextObject;
  1731. }
  1732. }
  1733. if (!bBufferOK) {
  1734. if (lEventLogLevel >= LOG_USER) {
  1735. // load data for eventlog message
  1736. dwDataIndex = wStringIndex = 0;
  1737. dwRawDataDwords[dwDataIndex++] = pObject->ObjectNameTitleIndex;
  1738. szMessageArray[wStringIndex++] =
  1739. pThisExtObj->szLibraryName;
  1740. szMessageArray[wStringIndex++] =
  1741. pThisExtObj->szServiceName;
  1742. ReportEventW (hEventLog,
  1743. EVENTLOG_ERROR_TYPE, // error type
  1744. 0, // category (not used)
  1745. (DWORD)WBEMPERF_INCORRECT_INSTANCE_LENGTH, // event,
  1746. NULL, // SID (not used),
  1747. wStringIndex, // number of strings
  1748. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1749. (LPCWSTR *)szMessageArray, // message text array
  1750. (LPVOID)&dwRawDataDwords[0]); // raw data
  1751. }
  1752. }
  1753. }
  1754. }
  1755. }
  1756. //
  1757. // if all the tests pass,then copy the data to the
  1758. // original buffer and update the pointers
  1759. if (bBufferOK) {
  1760. RtlMoveMemory (lpDataDefinition,
  1761. lpBufferBefore,
  1762. BytesLeft); // returned buffer size
  1763. } else {
  1764. NumObjectTypes = 0; // since this buffer was tossed
  1765. BytesLeft = 0; // reset the size value since the buffer wasn't used
  1766. }
  1767. } else {
  1768. // function already copied data to caller's buffer
  1769. // so no further action is necessary
  1770. }
  1771. lpDataDefinition = (LPVOID)((LPBYTE)(lpDataDefinition) + BytesLeft); // update data pointer
  1772. } else {
  1773. if (Win32Error != ERROR_SUCCESS) {
  1774. InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
  1775. }
  1776. if (bUnlockObjData) {
  1777. ReleaseMutex (pThisExtObj->hMutex);
  1778. }
  1779. NumObjectTypes = 0; // clear counter
  1780. }// end if function returned successfully
  1781. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1782. Win32Error = GetExceptionCode();
  1783. InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
  1784. bException = TRUE;
  1785. if (bUnlockObjData) {
  1786. ReleaseMutex (pThisExtObj->hMutex);
  1787. bUnlockObjData = FALSE;
  1788. }
  1789. }
  1790. if (bUseSafeBuffer) {
  1791. FREEMEM (m_hObjectHeap, 0, lpExtDataBuffer);
  1792. }
  1793. } else {
  1794. // unable to allocate memory so set error value
  1795. Win32Error = ERROR_OUTOFMEMORY;
  1796. } // end if temp buffer allocated successfully
  1797. //
  1798. // Update the count of the number of object types
  1799. //
  1800. ((PPERF_DATA_BLOCK) lpData)->NumObjectTypes += NumObjectTypes;
  1801. if ( Win32Error != ERROR_SUCCESS) {
  1802. if (bException ||
  1803. !((Win32Error == ERROR_MORE_DATA) ||
  1804. (Win32Error == WAIT_TIMEOUT))) {
  1805. // inform on exceptions & illegal error status only
  1806. if (lEventLogLevel >= LOG_USER) {
  1807. // load data for eventlog message
  1808. dwDataIndex = wStringIndex = 0;
  1809. dwRawDataDwords[dwDataIndex++] = Win32Error;
  1810. szMessageArray[wStringIndex++] =
  1811. pThisExtObj->szServiceName;
  1812. szMessageArray[wStringIndex++] =
  1813. pThisExtObj->szLibraryName;
  1814. ReportEventW (hEventLog,
  1815. EVENTLOG_ERROR_TYPE, // error type
  1816. 0, // category (not used)
  1817. (DWORD)WBEMPERF_COLLECT_PROC_EXCEPTION, // event,
  1818. NULL, // SID (not used),
  1819. wStringIndex, // number of strings
  1820. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1821. (LPCWSTR *)szMessageArray, // message text array
  1822. (LPVOID)&dwRawDataDwords[0]); // raw data
  1823. } else {
  1824. // don't report
  1825. }
  1826. }
  1827. // the ext. dll is only supposed to return:
  1828. // ERROR_SUCCESS even if it encountered a problem, OR
  1829. // ERROR_MODE_DATA if the buffer was too small.
  1830. // if it's ERROR_MORE_DATA, then break and return the
  1831. // error now, since it'll just be returned again and again.
  1832. if (Win32Error == ERROR_MORE_DATA) {
  1833. lReturnValue = Win32Error;
  1834. break;
  1835. }
  1836. }
  1837. } // end for each object
  1838. } // else an error occurred so unable to call functions
  1839. ((PPERF_DATA_BLOCK) lpData)->TotalByteLength = (DWORD)
  1840. ((LPBYTE)lpDataDefinition - (LPBYTE)lpData);
  1841. }
  1842. return lReturnValue;
  1843. }
  1844. //***************************************************************************
  1845. //
  1846. // CPerfObjectAccess::RemoveClass(IWbemClassObject *pClass)
  1847. //
  1848. // removes the class from the access object
  1849. //
  1850. //***************************************************************************
  1851. //
  1852. DWORD
  1853. CPerfObjectAccess::RemoveClass(IWbemClassObject *pClass)
  1854. {
  1855. CPerfDataLibrary *pLibEntry = NULL;
  1856. CPerfDataLibrary *pThisLibEntry = NULL;
  1857. DWORD dwIndex = 0;
  1858. DWORD dwEnd;
  1859. LPWSTR szRegistryKey = NULL;
  1860. IWbemQualifierSet *pClassQualifiers = NULL;
  1861. VARIANT vRegistryKey;
  1862. HRESULT hRes;
  1863. DWORD dwReturn = ERROR_SUCCESS;
  1864. DWORD dwPerfIndex;
  1865. CBSTR cbPerfIndex(cszPerfIndex);
  1866. CBSTR cbRegistryKey(cszRegistryKey);
  1867. if( NULL == (BSTR)cbPerfIndex ||
  1868. NULL == (BSTR)cbRegistryKey ){
  1869. return ERROR_OUTOFMEMORY;
  1870. }
  1871. VariantInit (&vRegistryKey);
  1872. // get the Qualifier Set for this class
  1873. hRes = pClass->GetQualifierSet(&pClassQualifiers);
  1874. if( hRes == 0){
  1875. // now get the library and procedure names
  1876. hRes = pClassQualifiers->Get( cbRegistryKey, 0, &vRegistryKey, 0);
  1877. if ((hRes == 0) && (vRegistryKey.vt == VT_BSTR)) {
  1878. szRegistryKey = Macro_CloneLPWSTR(V_BSTR(&vRegistryKey));
  1879. if (szRegistryKey == NULL) {
  1880. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  1881. }
  1882. else {
  1883. // now also get the perf index
  1884. VariantClear (&vRegistryKey);
  1885. hRes = pClassQualifiers->Get( cbPerfIndex, 0, &vRegistryKey, 0);
  1886. if (hRes == 0) {
  1887. dwPerfIndex = (DWORD)V_UI4(&vRegistryKey);
  1888. } else {
  1889. // unable to find NtPerfLibrary entry
  1890. dwReturn = ERROR_FILE_NOT_FOUND;
  1891. }
  1892. }
  1893. } else {
  1894. // unable to find NtPerfLibrary entry
  1895. dwReturn = ERROR_FILE_NOT_FOUND;
  1896. }
  1897. if (pClassQualifiers != NULL) pClassQualifiers->Release();
  1898. if (dwReturn == ERROR_SUCCESS) {
  1899. // find matching library in the array
  1900. dwEnd = m_aLibraries.Size();
  1901. if (dwEnd > 0) {
  1902. // walk down the list of libraries
  1903. for (dwIndex = 0; dwIndex < dwEnd; dwIndex++) {
  1904. // see if this library entry is good enough to keep
  1905. // The library is assumed to be a match if the
  1906. // lib. name and all proc's are the same.
  1907. pThisLibEntry = (CPerfDataLibrary *)m_aLibraries[dwIndex];
  1908. assert (pThisLibEntry != NULL); // it should have been removed!
  1909. // make sure it's complete
  1910. assert (pThisLibEntry->pLibInfo->szServiceName != NULL);
  1911. if (lstrcmpiW (szRegistryKey, pThisLibEntry->pLibInfo->szServiceName) == 0) {
  1912. pLibEntry = pThisLibEntry;
  1913. break;
  1914. } else {
  1915. // wrong library
  1916. // so continue
  1917. }
  1918. }
  1919. }
  1920. if (pLibEntry != NULL) {
  1921. // close this class & it's library
  1922. dwReturn = CloseLibrary(pLibEntry);
  1923. if (dwReturn == 0) {
  1924. // then no one wants it
  1925. FREEMEM(m_hObjectHeap, 0, pLibEntry->pLibInfo);
  1926. pLibEntry->pLibInfo = NULL;
  1927. m_aLibraries.RemoveAt(dwIndex);
  1928. m_aLibraries.Compress();
  1929. delete pLibEntry;
  1930. }
  1931. dwReturn = ERROR_SUCCESS;
  1932. } else {
  1933. dwReturn = ERROR_FILE_NOT_FOUND;
  1934. }
  1935. }
  1936. if (szRegistryKey != NULL) delete szRegistryKey;
  1937. VariantClear(&vRegistryKey);
  1938. }
  1939. return dwReturn;
  1940. }
  1941. BOOL
  1942. CPerfObjectAccess::CheckClassExist(LPWSTR wszClassName, IWbemClassObject * pClass)
  1943. {
  1944. BOOL bExist = TRUE;
  1945. HRESULT hRes = S_OK;
  1946. IWbemQualifierSet * pClassQualifiers = NULL;
  1947. SYSTEMTIME LocalTime;
  1948. VARIANT vRegistry;
  1949. LPWSTR szRegistry = NULL;
  1950. LPWSTR szKey = NULL;
  1951. DWORD dwKey;
  1952. DWORD dwType;
  1953. DWORD dwSize;
  1954. DWORD Status;
  1955. HKEY hKey = NULL;
  1956. ZeroMemory(& LocalTime, sizeof(SYSTEMTIME));
  1957. GetLocalTime(& LocalTime);
  1958. hRes = pClass->GetQualifierSet(& pClassQualifiers);
  1959. if (hRes != S_OK || pClassQualifiers == NULL) {
  1960. bExist = FALSE;
  1961. goto Cleanup;
  1962. }
  1963. hRes = pClassQualifiers->Get(CBSTR(cszRegistryKey), 0, & vRegistry, 0);
  1964. if (hRes != S_OK || vRegistry.vt != VT_BSTR) {
  1965. bExist = FALSE;
  1966. goto Cleanup;
  1967. }
  1968. dwKey = lstrlenW(V_BSTR(& vRegistry)) + 1;
  1969. szRegistry = (LPWSTR) ALLOCMEM(m_hObjectHeap, HEAP_ZERO_MEMORY, sizeof(WCHAR) * dwKey);
  1970. if (szRegistry != NULL) {
  1971. StringCchCopyW(szRegistry, dwKey, V_BSTR(& vRegistry));
  1972. VariantClear(& vRegistry);
  1973. }
  1974. else {
  1975. VariantClear(& vRegistry);
  1976. goto Cleanup;
  1977. }
  1978. dwKey = lstrlenW(cszHklmServicesKey) + 1 + lstrlenW(szRegistry) + lstrlenW(cszPerformance) + 1;
  1979. szKey = (LPWSTR) ALLOCMEM(m_hObjectHeap, HEAP_ZERO_MEMORY, dwKey * sizeof(WCHAR));
  1980. if (szKey == NULL) {
  1981. goto Cleanup;
  1982. }
  1983. StringCchPrintfW(szKey, dwKey, L"%ws\\%ws%ws", cszHklmServicesKey, szRegistry, cszPerformance);
  1984. Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, & hKey);
  1985. if (Status != ERROR_SUCCESS || hKey == NULL || hKey == INVALID_HANDLE_VALUE) {
  1986. bExist = FALSE;
  1987. goto Cleanup;
  1988. }
  1989. dwType = 0;
  1990. dwSize = sizeof(dwKey);
  1991. Status = RegQueryValueExW(hKey, cszFirstCounter, NULL, & dwType, (LPBYTE) & dwKey, & dwSize);
  1992. if (Status != ERROR_SUCCESS || dwType != REG_DWORD) {
  1993. bExist = FALSE;
  1994. goto Cleanup;
  1995. }
  1996. dwType = 0;
  1997. dwSize = sizeof(dwKey);
  1998. Status = RegQueryValueExW(hKey, cszLastCounter, NULL, & dwType, (LPBYTE) & dwKey, & dwSize);
  1999. if (Status != ERROR_SUCCESS || dwType != REG_DWORD) {
  2000. bExist = FALSE;
  2001. goto Cleanup;
  2002. }
  2003. Cleanup:
  2004. if (pClassQualifiers != NULL) pClassQualifiers->Release();
  2005. if (szRegistry != NULL) FREEMEM(m_hObjectHeap, 0, szRegistry);
  2006. if (szKey != NULL) FREEMEM(m_hObjectHeap, 0, szKey);
  2007. if (hKey != NULL && hKey != INVALID_HANDLE_VALUE) RegCloseKey(hKey);
  2008. return bExist;
  2009. }