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.

1430 lines
56 KiB

  1. /*++ BUILD Version: 0001 // Increment this if a change has global effects
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. extinit.c
  5. Abstract:
  6. This file implements all the initialization library routines operating on
  7. extensible performance libraries.
  8. Author:
  9. JeePang
  10. Revision History:
  11. 09/27/2000 - JeePang - Moved from perflib.c
  12. --*/
  13. #define UNICODE
  14. //
  15. // Include files
  16. //
  17. #pragma warning(disable:4306)
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <ntregapi.h>
  22. #include <ntprfctr.h>
  23. #include <windows.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <winperf.h>
  27. #include <rpc.h>
  28. #include <strsafe.h>
  29. #include "regrpc.h"
  30. #include "ntconreg.h"
  31. #include "prflbmsg.h" // event log messages
  32. #include "perflib.h"
  33. #pragma warning(default:4306)
  34. //
  35. // used for error logging control
  36. #define DEFAULT_ERROR_LIMIT 1000
  37. DWORD dwExtCtrOpenProcWaitMs = OPEN_PROC_WAIT_TIME;
  38. LONG lExtCounterTestLevel = EXT_TEST_UNDEFINED;
  39. // precompiled security descriptor
  40. // System and NetworkService has full access
  41. //
  42. // since this is RELATIVE, it will work on both IA32 and IA64
  43. //
  44. DWORD g_PrecSD[] = {
  45. 0x80040001, 0x00000044, 0x00000050, 0x00000000,
  46. 0x00000014, 0x00300002, 0x00000002, 0x00140000,
  47. 0x001f0001, 0x00000101, 0x05000000, 0x00000012,
  48. 0x00140000, 0x001f0001, 0x00000101, 0x05000000,
  49. 0x00000014, 0x00000101, 0x05000000, 0x00000014,
  50. 0x00000101, 0x05000000, 0x00000014 };
  51. DWORD g_SizeSD = 0;
  52. DWORD g_RuntimeSD[ (sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
  53. + sizeof(SECURITY_DESCRIPTOR_RELATIVE)
  54. + 4 * (sizeof(SID) + SID_MAX_SUB_AUTHORITIES * sizeof(DWORD)))
  55. / sizeof(DWORD)];
  56. BOOL
  57. PerflibCreateSD()
  58. {
  59. BOOL bRet = FALSE;
  60. HANDLE hToken = NULL;
  61. TOKEN_USER * pToken_User;
  62. bRet = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, & hToken);
  63. if (bRet) {
  64. DWORD dwSize = sizeof(TOKEN_USER) + sizeof(SID)
  65. + (SID_MAX_SUB_AUTHORITIES * sizeof(DWORD));
  66. try {
  67. pToken_User = (TOKEN_USER *) _alloca(dwSize);
  68. } except (EXCEPTION_EXECUTE_HANDLER) {
  69. pToken_User = NULL;
  70. bRet = FALSE;
  71. }
  72. if (bRet) {
  73. bRet = GetTokenInformation(
  74. hToken, TokenUser, pToken_User, dwSize, & dwSize);
  75. }
  76. if (bRet) {
  77. SID SystemSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY,
  78. SECURITY_LOCAL_SYSTEM_RID };
  79. PSID pSIDUser = pToken_User->User.Sid;
  80. DWORD dwSids;
  81. DWORD ACLLength;
  82. DWORD dwSizeSD;
  83. SECURITY_DESCRIPTOR_RELATIVE * pLocalSD = NULL;
  84. PACL pDacl = NULL;
  85. dwSize = GetLengthSid(pSIDUser);
  86. dwSids = 2;
  87. ACLLength = (ULONG) sizeof(ACL)
  88. + (dwSids * ( (ULONG) sizeof(ACCESS_ALLOWED_ACE)
  89. - sizeof(ULONG)))
  90. + dwSize
  91. + sizeof(SystemSid);
  92. dwSizeSD = sizeof(SECURITY_DESCRIPTOR_RELATIVE)
  93. + dwSize + dwSize + ACLLength;
  94. pLocalSD = (SECURITY_DESCRIPTOR_RELATIVE *) ALLOCMEM(dwSizeSD);
  95. if (pLocalSD == NULL) {
  96. CloseHandle(hToken);
  97. return FALSE;
  98. }
  99. pLocalSD->Revision = SECURITY_DESCRIPTOR_REVISION;
  100. pLocalSD->Control = SE_DACL_PRESENT|SE_SELF_RELATIVE;
  101. memcpy((BYTE *) pLocalSD + sizeof(SECURITY_DESCRIPTOR_RELATIVE),
  102. pSIDUser,
  103. dwSize);
  104. pLocalSD->Owner = (DWORD) sizeof(SECURITY_DESCRIPTOR_RELATIVE);
  105. memcpy((BYTE *) pLocalSD + sizeof(SECURITY_DESCRIPTOR_RELATIVE)
  106. + dwSize,
  107. pSIDUser,
  108. dwSize);
  109. pLocalSD->Group = (DWORD) ( sizeof(SECURITY_DESCRIPTOR_RELATIVE)
  110. + dwSize);
  111. pDacl = (PACL) ALLOCMEM(ACLLength);
  112. if (pDacl == NULL) {
  113. FREEMEM(pLocalSD);
  114. CloseHandle(hToken);
  115. return FALSE;
  116. }
  117. bRet = InitializeAcl(pDacl, ACLLength, ACL_REVISION);
  118. if (bRet) {
  119. bRet = AddAccessAllowedAceEx(pDacl,
  120. ACL_REVISION,
  121. 0,
  122. MUTEX_ALL_ACCESS,
  123. & SystemSid);
  124. if (bRet) {
  125. bRet = AddAccessAllowedAceEx(pDacl,
  126. ACL_REVISION,
  127. 0,
  128. MUTEX_ALL_ACCESS,
  129. pSIDUser);
  130. if (bRet) {
  131. memcpy((BYTE *) pLocalSD
  132. + sizeof(SECURITY_DESCRIPTOR_RELATIVE)
  133. + dwSize
  134. + dwSize,
  135. pDacl,
  136. ACLLength);
  137. pLocalSD->Dacl = (DWORD)
  138. ( sizeof(SECURITY_DESCRIPTOR_RELATIVE)
  139. + dwSize + dwSize);
  140. if (RtlValidRelativeSecurityDescriptor(
  141. pLocalSD,
  142. dwSizeSD,
  143. OWNER_SECURITY_INFORMATION
  144. | GROUP_SECURITY_INFORMATION
  145. | DACL_SECURITY_INFORMATION)) {
  146. g_SizeSD = dwSizeSD;
  147. memcpy(g_RuntimeSD, pLocalSD, dwSizeSD);
  148. }
  149. else {
  150. bRet = FALSE;
  151. }
  152. }
  153. }
  154. }
  155. if (pLocalSD) {
  156. FREEMEM(pLocalSD);
  157. }
  158. if (pDacl) {
  159. FREEMEM(pDacl);
  160. }
  161. }
  162. CloseHandle(hToken);
  163. }
  164. return bRet;
  165. }
  166. PEXT_OBJECT
  167. AllocateAndInitializeExtObject (
  168. HKEY hServicesKey,
  169. HKEY hPerfKey,
  170. PUNICODE_STRING usServiceName
  171. )
  172. /*++
  173. AllocateAndInitializeExtObject
  174. allocates and initializes an extensible object information entry
  175. for use by the performance library.
  176. a pointer to the initialized block is returned if all goes well,
  177. otherwise no memory is allocated and a null pointer is returned.
  178. The calling function must close the open handles and free this
  179. memory block when it is no longer needed.
  180. Arguments:
  181. hServicesKey -- open registry handle to the
  182. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services hey
  183. hPerfKey -- the open registry key to the Performance sub-key under
  184. the selected service
  185. szServiceName -- The name of the service
  186. --*/
  187. {
  188. LONG Status;
  189. HKEY hKeyLinkage;
  190. BOOL bUseQueryFn = FALSE;
  191. PEXT_OBJECT pReturnObject = NULL;
  192. DWORD dwType;
  193. DWORD dwSize;
  194. DWORD dwFlags = 0;
  195. DWORD dwKeep;
  196. DWORD dwObjectArray[MAX_PERF_OBJECTS_IN_QUERY_FUNCTION];
  197. DWORD dwObjIndex = 0;
  198. SIZE_T dwMemBlockSize = sizeof(EXT_OBJECT);
  199. DWORD dwLinkageStringLen = 0;
  200. DWORD dwErrorLimit;
  201. PCHAR szOpenProcName;
  202. PCHAR szCollectProcName;
  203. PCHAR szCloseProcName;
  204. PWCHAR szLibraryString;
  205. PWCHAR szLibraryExpPath;
  206. PWCHAR mszObjectList;
  207. PWCHAR szLinkageKeyPath;
  208. LPWSTR szLinkageString = NULL; // max path wasn't enough for some paths
  209. SIZE_T OpenProcLen, CollectProcLen, CloseProcLen;
  210. SIZE_T LibStringLen, LibExpPathLen, ObjListLen;
  211. SIZE_T LinkageKeyLen;
  212. DLL_VALIDATION_DATA DllVD;
  213. FILETIME LocalftLastGoodDllFileDate;
  214. DWORD dwOpenTimeout;
  215. DWORD dwCollectTimeout;
  216. LPWSTR szThisObject;
  217. LPWSTR szThisChar;
  218. LPSTR pNextStringA;
  219. LPWSTR pNextStringW;
  220. WCHAR szMutexName[MAX_NAME_PATH+40];
  221. WCHAR szPID[32];
  222. WORD wStringIndex;
  223. LPWSTR szMessageArray[2];
  224. BOOL bDisable = FALSE;
  225. LPWSTR szServiceName;
  226. PCHAR pBuffer = NULL; // Buffer to store all registry value strings
  227. PWCHAR swzTail;
  228. PCHAR szTail;
  229. DWORD hErr;
  230. size_t nCharsLeft;
  231. DWORD MAX_STR, MAX_WSTR; // Make this global if we want this dynamic
  232. // read the performance DLL name
  233. MAX_STR = MAX_NAME_PATH;
  234. MAX_WSTR = MAX_STR * sizeof(WCHAR);
  235. szServiceName = (LPWSTR) usServiceName->Buffer;
  236. dwSize = (3 * MAX_STR) + (4 * MAX_WSTR);
  237. pBuffer = ALLOCMEM(dwSize);
  238. //
  239. // Assumes that the allocated heap is zeroed.
  240. //
  241. if (pBuffer == NULL) {
  242. return NULL;
  243. }
  244. szLibraryString = (PWCHAR) pBuffer;
  245. szLibraryExpPath = (PWCHAR) ((PCHAR) szLibraryString + MAX_WSTR);
  246. szOpenProcName = (PCHAR) szLibraryExpPath + MAX_WSTR;
  247. szCollectProcName = szOpenProcName + MAX_STR;
  248. szCloseProcName = szCollectProcName + MAX_STR;
  249. mszObjectList = (PWCHAR) (szCloseProcName + MAX_STR);
  250. szLinkageKeyPath = (PWCHAR) ((PCHAR) mszObjectList + MAX_WSTR);
  251. dwType = 0;
  252. LocalftLastGoodDllFileDate.dwLowDateTime = 0;
  253. LocalftLastGoodDllFileDate.dwHighDateTime = 0;
  254. memset (&DllVD, 0, sizeof(DllVD));
  255. dwErrorLimit = DEFAULT_ERROR_LIMIT;
  256. dwCollectTimeout = dwExtCtrOpenProcWaitMs;
  257. dwOpenTimeout = dwExtCtrOpenProcWaitMs;
  258. dwSize = MAX_WSTR;
  259. Status = PrivateRegQueryValueExW (hPerfKey,
  260. DLLValue,
  261. NULL,
  262. &dwType,
  263. (LPBYTE)szLibraryString,
  264. &dwSize);
  265. if (Status == ERROR_SUCCESS) {
  266. LibStringLen = QWORD_MULTIPLE(dwSize + 1);
  267. szLibraryExpPath = (PWCHAR) ((PCHAR) szLibraryString + LibStringLen);
  268. LibExpPathLen = 8;
  269. if (dwType == REG_EXPAND_SZ) {
  270. // expand any environment vars
  271. dwSize = ExpandEnvironmentStringsW(
  272. szLibraryString,
  273. szLibraryExpPath,
  274. MAX_STR);
  275. if ((dwSize > MAX_STR) || (dwSize == 0)) {
  276. Status = ERROR_INVALID_DLL;
  277. } else {
  278. dwSize += 1;
  279. dwSize *= sizeof(WCHAR);
  280. LibExpPathLen = QWORD_MULTIPLE(dwSize);
  281. dwMemBlockSize += LibExpPathLen;
  282. }
  283. } else if (dwType == REG_SZ) {
  284. // look for dll and save full file Path
  285. dwSize = SearchPathW (
  286. NULL, // use standard system search path
  287. szLibraryString,
  288. NULL,
  289. MAX_STR,
  290. szLibraryExpPath,
  291. NULL);
  292. if ((dwSize > MAX_STR) || (dwSize == 0)) {
  293. Status = ERROR_INVALID_DLL;
  294. } else {
  295. dwSize += 1;
  296. dwSize *= sizeof(WCHAR);
  297. LibExpPathLen = QWORD_MULTIPLE(dwSize);
  298. dwMemBlockSize += LibExpPathLen;
  299. }
  300. } else {
  301. Status = ERROR_INVALID_DLL;
  302. TRACE((WINPERF_DBG_TRACE_FATAL),
  303. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
  304. }
  305. szOpenProcName = (PCHAR) szLibraryExpPath + LibExpPathLen;
  306. OpenProcLen = 8;
  307. LibStringLen = 8;
  308. LibExpPathLen = 8;
  309. LinkageKeyLen = 8;
  310. if (Status == ERROR_SUCCESS) {
  311. // we have the DLL name so get the procedure names
  312. dwType = 0;
  313. dwSize = MAX_STR;
  314. Status = PrivateRegQueryValueExA (hPerfKey,
  315. OpenValue,
  316. NULL,
  317. &dwType,
  318. (LPBYTE)szOpenProcName,
  319. &dwSize);
  320. if ((Status != ERROR_SUCCESS) || (szOpenProcName[0] == 0)) {
  321. if (szServiceName != NULL) {
  322. TRACE((WINPERF_DBG_TRACE_FATAL),
  323. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT,
  324. ARG_TYPE_WSTR, Status,
  325. szServiceName, usServiceName->MaximumLength, NULL));
  326. }
  327. else {
  328. TRACE((WINPERF_DBG_TRACE_FATAL),
  329. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
  330. }
  331. // DebugPrint((1, "No open procedure for %ws %d\n",
  332. // szServiceName, Status));
  333. bDisable = TRUE;
  334. if (THROTTLE_PERFLIB(PERFLIB_PROC_NAME_NOT_FOUND)) {
  335. wStringIndex = 0;
  336. szMessageArray[wStringIndex++] = (LPWSTR) L"Open";
  337. szMessageArray[wStringIndex++] = szServiceName;
  338. ReportEvent(hEventLog,
  339. EVENTLOG_ERROR_TYPE,
  340. 0,
  341. (DWORD)PERFLIB_PROC_NAME_NOT_FOUND,
  342. NULL,
  343. wStringIndex,
  344. 0,
  345. szMessageArray,
  346. NULL);
  347. }
  348. OpenProcLen = 8; // 8 byte alignment
  349. }
  350. else {
  351. DebugPrint((2, "Found %s for %ws\n",
  352. szOpenProcName, szServiceName));
  353. OpenProcLen = QWORD_MULTIPLE(dwSize + 1); // 8 byte alignment
  354. szOpenProcName[dwSize] = 0; // add a NULL always to be safe
  355. }
  356. }
  357. #ifdef DBG
  358. else {
  359. DebugPrint((1, "Invalid DLL found for %ws\n",
  360. szServiceName));
  361. }
  362. #endif
  363. if (Status == ERROR_SUCCESS) {
  364. // add in size of previous string
  365. // the size value includes the Term. NULL
  366. dwMemBlockSize += OpenProcLen;
  367. // we have the procedure name so get the timeout value
  368. dwType = 0;
  369. dwSize = sizeof(dwOpenTimeout);
  370. Status = PrivateRegQueryValueExW (hPerfKey,
  371. OpenTimeout,
  372. NULL,
  373. &dwType,
  374. (LPBYTE)&dwOpenTimeout,
  375. &dwSize);
  376. // if error, then apply default
  377. if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
  378. dwOpenTimeout = dwExtCtrOpenProcWaitMs;
  379. Status = ERROR_SUCCESS;
  380. }
  381. }
  382. szCloseProcName = szOpenProcName + OpenProcLen;
  383. CloseProcLen = 8;
  384. if (Status == ERROR_SUCCESS) {
  385. // get next string
  386. dwType = 0;
  387. dwSize = MAX_STR;
  388. Status = PrivateRegQueryValueExA (hPerfKey,
  389. CloseValue,
  390. NULL,
  391. &dwType,
  392. (LPBYTE)szCloseProcName,
  393. &dwSize);
  394. if ((Status != ERROR_SUCCESS) || (szCloseProcName[0] == 0)) {
  395. if (szServiceName != NULL) {
  396. TRACE((WINPERF_DBG_TRACE_FATAL),
  397. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT,
  398. ARG_TYPE_WSTR, Status,
  399. szServiceName, usServiceName->MaximumLength, NULL));
  400. }
  401. else {
  402. TRACE((WINPERF_DBG_TRACE_FATAL),
  403. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
  404. }
  405. // DebugPrint((1, "No close procedure for %ws\n",
  406. // szServiceName));
  407. if (THROTTLE_PERFLIB(PERFLIB_PROC_NAME_NOT_FOUND)) {
  408. wStringIndex = 0;
  409. szMessageArray[wStringIndex++] = (LPWSTR) L"Close";
  410. szMessageArray[wStringIndex++] = szServiceName;
  411. ReportEvent(hEventLog,
  412. EVENTLOG_ERROR_TYPE,
  413. 0,
  414. (DWORD)PERFLIB_PROC_NAME_NOT_FOUND,
  415. NULL,
  416. wStringIndex,
  417. 0,
  418. szMessageArray,
  419. NULL);
  420. }
  421. bDisable = TRUE;
  422. }
  423. else {
  424. DebugPrint((2, "Found %s for %ws\n",
  425. szCloseProcName, szServiceName));
  426. CloseProcLen = QWORD_MULTIPLE(dwSize + 1);
  427. }
  428. }
  429. // Initialize defaults first
  430. szCollectProcName = szCloseProcName + CloseProcLen;
  431. CollectProcLen = 8;
  432. mszObjectList = (PWCHAR) ((PCHAR) szCollectProcName + CollectProcLen);
  433. if (Status == ERROR_SUCCESS) {
  434. // add in size of previous string
  435. // the size value includes the Term. NULL
  436. dwMemBlockSize += CloseProcLen;
  437. // try to look up the query function which is the
  438. // preferred interface if it's not found, then
  439. // try the collect function name. If that's not found,
  440. // then bail
  441. dwType = 0;
  442. dwSize = MAX_STR;
  443. Status = PrivateRegQueryValueExA (hPerfKey,
  444. QueryValue,
  445. NULL,
  446. &dwType,
  447. (LPBYTE)szCollectProcName,
  448. &dwSize);
  449. if (Status == ERROR_SUCCESS) {
  450. // add in size of the Query Function Name
  451. // the size value includes the Term. NULL
  452. CollectProcLen = QWORD_MULTIPLE(dwSize + 1);
  453. dwMemBlockSize += CollectProcLen;
  454. // get next string
  455. bUseQueryFn = TRUE;
  456. // the query function can support a static object list
  457. // so look it up
  458. } else {
  459. // the QueryFunction wasn't found so look up the
  460. // Collect Function name instead
  461. dwType = 0;
  462. dwSize = MAX_STR;
  463. Status = PrivateRegQueryValueExA (hPerfKey,
  464. CollectValue,
  465. NULL,
  466. &dwType,
  467. (LPBYTE)szCollectProcName,
  468. &dwSize);
  469. if (Status == ERROR_SUCCESS) {
  470. // add in size of Collect Function Name
  471. // the size value includes the Term. NULL
  472. CollectProcLen = QWORD_MULTIPLE(dwSize+1);
  473. dwMemBlockSize += CollectProcLen;
  474. }
  475. }
  476. if ((Status != ERROR_SUCCESS) || (szCollectProcName[0] == 0)) {
  477. if (szServiceName != NULL) {
  478. TRACE((WINPERF_DBG_TRACE_FATAL),
  479. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT,
  480. ARG_TYPE_WSTR, Status,
  481. szServiceName, usServiceName->MaximumLength, NULL));
  482. }
  483. else {
  484. TRACE((WINPERF_DBG_TRACE_FATAL),
  485. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
  486. }
  487. // DebugPrint((1, "No collect procedure for %ws\n",
  488. // szServiceName));
  489. bDisable = TRUE;
  490. if (THROTTLE_PERFLIB(PERFLIB_PROC_NAME_NOT_FOUND)) {
  491. wStringIndex = 0;
  492. szMessageArray[wStringIndex++] = (LPWSTR) L"Collect";
  493. szMessageArray[wStringIndex++] = szServiceName;
  494. ReportEvent(hEventLog,
  495. EVENTLOG_ERROR_TYPE,
  496. 0,
  497. (DWORD)PERFLIB_PROC_NAME_NOT_FOUND,
  498. NULL,
  499. wStringIndex,
  500. 0,
  501. szMessageArray,
  502. NULL);
  503. }
  504. }
  505. #ifdef DBG
  506. else {
  507. DebugPrint((2, "Found %s for %ws\n",
  508. szCollectProcName, szServiceName));
  509. }
  510. #endif
  511. if (Status == ERROR_SUCCESS) {
  512. // we have the procedure name so get the timeout value
  513. dwType = 0;
  514. dwSize = sizeof(dwCollectTimeout);
  515. Status = PrivateRegQueryValueExW (hPerfKey,
  516. CollectTimeout,
  517. NULL,
  518. &dwType,
  519. (LPBYTE)&dwCollectTimeout,
  520. &dwSize);
  521. // if error, then apply default
  522. if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
  523. dwCollectTimeout = dwExtCtrOpenProcWaitMs;
  524. Status = ERROR_SUCCESS;
  525. }
  526. }
  527. // get the list of supported objects if provided by the registry
  528. mszObjectList = (PWCHAR) ((PCHAR) szCollectProcName + CollectProcLen);
  529. ObjListLen = 8;
  530. dwType = 0;
  531. dwSize = MAX_WSTR;
  532. Status = PrivateRegQueryValueExW (hPerfKey,
  533. ObjListValue,
  534. NULL,
  535. &dwType,
  536. (LPBYTE)mszObjectList,
  537. &dwSize);
  538. if (Status == ERROR_SUCCESS) {
  539. ObjListLen = QWORD_MULTIPLE(dwSize + 1);
  540. if (dwType == REG_SZ) {
  541. szThisObject = NULL;
  542. for (szThisChar = mszObjectList; * szThisChar != L'\0'; szThisChar ++) {
  543. if (* szThisChar == L' ') {
  544. if (szThisObject == NULL) {
  545. // Extra space, skip.
  546. continue;
  547. }
  548. else {
  549. if (dwObjIndex < MAX_PERF_OBJECTS_IN_QUERY_FUNCTION) {
  550. * szThisChar = L'\0';
  551. dwObjectArray[dwObjIndex] = wcstoul(szThisObject, NULL, 10);
  552. dwObjIndex ++;
  553. * szThisChar = L' ';
  554. szThisObject = NULL;
  555. }
  556. }
  557. }
  558. else if (szThisObject == NULL) {
  559. szThisObject = szThisChar;
  560. }
  561. }
  562. if ((szThisObject != NULL) && (dwObjIndex < MAX_PERF_OBJECTS_IN_QUERY_FUNCTION)) {
  563. if ((szThisObject != szThisChar) && (*szThisChar == L'\0')) {
  564. dwObjectArray[dwObjIndex] = wcstoul(szThisObject, NULL, 10);
  565. dwObjIndex ++;
  566. szThisObject = NULL;
  567. }
  568. }
  569. }
  570. else if (dwType == REG_MULTI_SZ) {
  571. for (szThisObject = mszObjectList, dwObjIndex = 0;
  572. (* szThisObject != L'\0') && (dwObjIndex < MAX_PERF_OBJECTS_IN_QUERY_FUNCTION);
  573. szThisObject += lstrlenW(szThisObject) + 1) {
  574. dwObjectArray[dwObjIndex] = wcstoul(szThisObject, NULL, 10);
  575. dwObjIndex ++;
  576. }
  577. }
  578. else {
  579. // skip unknown ObjectList value.
  580. szThisObject = NULL;
  581. }
  582. if (szThisObject != NULL && * szThisObject != L'\0') {
  583. TRACE((WINPERF_DBG_TRACE_FATAL),
  584. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, 0, NULL));
  585. if (THROTTLE_PERFLIB(PERFLIB_TOO_MANY_OBJECTS)) {
  586. ReportEvent (hEventLog,
  587. EVENTLOG_ERROR_TYPE, // error type
  588. 0, // category (not used
  589. (DWORD)PERFLIB_TOO_MANY_OBJECTS, // event,
  590. NULL, // SID (not used),
  591. 0, // number of strings
  592. 0, // sizeof raw data
  593. NULL, // message text array
  594. NULL); // raw data
  595. }
  596. }
  597. } else {
  598. // reset status since not having this is
  599. // not a showstopper
  600. Status = ERROR_SUCCESS;
  601. }
  602. szLinkageKeyPath = (PWCHAR) ((PCHAR) mszObjectList + ObjListLen);
  603. if (Status == ERROR_SUCCESS) {
  604. dwType = 0;
  605. dwKeep = 0;
  606. dwSize = sizeof(dwKeep);
  607. Status = PrivateRegQueryValueExW (hPerfKey,
  608. KeepResident,
  609. NULL,
  610. &dwType,
  611. (LPBYTE)&dwKeep,
  612. &dwSize);
  613. if ((Status == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
  614. if (dwKeep == 1) {
  615. dwFlags |= PERF_EO_KEEP_RESIDENT;
  616. } else {
  617. // no change.
  618. }
  619. } else {
  620. // not fatal, just use the defaults.
  621. Status = ERROR_SUCCESS;
  622. }
  623. }
  624. if (Status == ERROR_SUCCESS) {
  625. dwType = REG_DWORD;
  626. dwSize = sizeof(DWORD);
  627. PrivateRegQueryValueExW(
  628. hPerfKey,
  629. cszFailureLimit,
  630. NULL,
  631. &dwType,
  632. (LPBYTE)&dwErrorLimit,
  633. &dwSize);
  634. }
  635. }
  636. }
  637. else {
  638. if (szServiceName != NULL) {
  639. TRACE((WINPERF_DBG_TRACE_FATAL),
  640. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT,
  641. ARG_TYPE_WSTR, Status,
  642. szServiceName, WSTRSIZE(szServiceName), NULL));
  643. }
  644. else {
  645. TRACE((WINPERF_DBG_TRACE_FATAL),
  646. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
  647. }
  648. // DebugPrint((1, "Cannot key for %ws. Error=%d\n",
  649. // szServiceName, Status));
  650. }
  651. if (Status == ERROR_SUCCESS) {
  652. // get Library validation time
  653. dwType = 0;
  654. dwSize = sizeof(DllVD);
  655. Status = PrivateRegQueryValueExW (hPerfKey,
  656. cszLibraryValidationData,
  657. NULL,
  658. &dwType,
  659. (LPBYTE)&DllVD,
  660. &dwSize);
  661. if ((Status != ERROR_SUCCESS) ||
  662. (dwType != REG_BINARY) ||
  663. (dwSize != sizeof (DllVD))){
  664. // then set this entry to be 0
  665. TRACE((WINPERF_DBG_TRACE_INFO),
  666. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status,
  667. &dwType, sizeof(dwType), &dwSize, sizeof(dwSize), NULL));
  668. memset (&DllVD, 0, sizeof(DllVD));
  669. // and clear the error
  670. Status = ERROR_SUCCESS;
  671. }
  672. }
  673. if (Status == ERROR_SUCCESS) {
  674. // get the file timestamp of the last successfully accessed file
  675. dwType = 0;
  676. dwSize = sizeof(LocalftLastGoodDllFileDate);
  677. memset (&LocalftLastGoodDllFileDate, 0, sizeof(LocalftLastGoodDllFileDate));
  678. Status = PrivateRegQueryValueExW (hPerfKey,
  679. cszSuccessfulFileData,
  680. NULL,
  681. &dwType,
  682. (LPBYTE)&LocalftLastGoodDllFileDate,
  683. &dwSize);
  684. if ((Status != ERROR_SUCCESS) ||
  685. (dwType != REG_BINARY) ||
  686. (dwSize != sizeof (LocalftLastGoodDllFileDate))) {
  687. // then set this entry to be Invalid
  688. memset (&LocalftLastGoodDllFileDate, 0xFF, sizeof(LocalftLastGoodDllFileDate));
  689. // and clear the error
  690. TRACE((WINPERF_DBG_TRACE_INFO),
  691. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status,
  692. &dwType, sizeof(dwType), &dwSize, sizeof(dwSize), NULL));
  693. Status = ERROR_SUCCESS;
  694. }
  695. }
  696. if (Status == ERROR_SUCCESS) {
  697. hErr = StringCchCopyEx(szLinkageKeyPath, MAX_STR, szServiceName,
  698. &swzTail, &nCharsLeft, STRSAFE_NULL_ON_FAILURE);
  699. if (SUCCEEDED(hErr)) {
  700. hErr = StringCchCopy(swzTail, nCharsLeft, LinkageKey);
  701. }
  702. hKeyLinkage = INVALID_HANDLE_VALUE;
  703. Status = HRESULT_CODE(hErr);
  704. if (SUCCEEDED(hErr)) {
  705. Status = RegOpenKeyExW (
  706. hServicesKey,
  707. szLinkageKeyPath,
  708. 0L,
  709. KEY_READ,
  710. &hKeyLinkage);
  711. }
  712. if ((Status == ERROR_SUCCESS) && (hKeyLinkage != INVALID_HANDLE_VALUE)) {
  713. // look up export value string
  714. dwSize = 0;
  715. dwType = 0;
  716. Status = PrivateRegQueryValueExW (
  717. hKeyLinkage,
  718. ExportValue,
  719. NULL,
  720. &dwType,
  721. NULL,
  722. &dwSize);
  723. // get size of string
  724. if (((Status != ERROR_SUCCESS) && (Status != ERROR_MORE_DATA)) ||
  725. ((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))) {
  726. dwLinkageStringLen = 0;
  727. szLinkageString = NULL;
  728. // not finding a linkage key is not fatal so correct
  729. // status
  730. Status = ERROR_SUCCESS;
  731. } else {
  732. // allocate buffer
  733. szLinkageString = (LPWSTR)ALLOCMEM(dwSize + sizeof(UNICODE_NULL));
  734. if (szLinkageString != NULL) {
  735. // read string into buffer
  736. dwType = 0;
  737. Status = PrivateRegQueryValueExW (
  738. hKeyLinkage,
  739. ExportValue,
  740. NULL,
  741. &dwType,
  742. (LPBYTE)szLinkageString,
  743. &dwSize);
  744. if ((Status != ERROR_SUCCESS) ||
  745. ((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))) {
  746. // clear & release buffer
  747. FREEMEM (szLinkageString);
  748. szLinkageString = NULL;
  749. dwLinkageStringLen = 0;
  750. // not finding a linkage key is not fatal so correct
  751. // status
  752. Status = ERROR_SUCCESS;
  753. } else {
  754. // add size of linkage string to buffer
  755. // the size value includes the Term. NULL
  756. dwLinkageStringLen = dwSize + 1;
  757. dwMemBlockSize += QWORD_MULTIPLE(dwLinkageStringLen);
  758. }
  759. } else {
  760. // clear & release buffer
  761. dwLinkageStringLen = 0;
  762. Status = ERROR_OUTOFMEMORY;
  763. TRACE((WINPERF_DBG_TRACE_FATAL),
  764. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status,
  765. &dwSize, sizeof(dwSize), NULL));
  766. }
  767. }
  768. RegCloseKey (hKeyLinkage);
  769. } else {
  770. // not finding a linkage key is not fatal so correct
  771. // status
  772. // clear & release buffer
  773. szLinkageString = NULL;
  774. dwLinkageStringLen = 0;
  775. Status = ERROR_SUCCESS;
  776. }
  777. }
  778. if (Status == ERROR_SUCCESS) {
  779. // add in size of service name
  780. SIZE_T nDestSize;
  781. dwSize = usServiceName->MaximumLength;
  782. dwMemBlockSize += QWORD_MULTIPLE(dwSize);
  783. // allocate and initialize a new ext. object block
  784. pReturnObject = ALLOCMEM (dwMemBlockSize);
  785. if (pReturnObject != NULL) {
  786. // copy values to new buffer (all others are NULL)
  787. pNextStringA = (LPSTR)&pReturnObject[1];
  788. nDestSize = dwMemBlockSize - sizeof(EXT_OBJECT);
  789. // copy Open Procedure Name
  790. pReturnObject->szOpenProcName = pNextStringA;
  791. hErr = StringCbCopyExA(pNextStringA, nDestSize, szOpenProcName,
  792. &szTail, &nCharsLeft, STRSAFE_NULL_ON_FAILURE);
  793. if (FAILED(hErr)) {
  794. Status = HRESULT_CODE(hErr);
  795. goto AddFailed;
  796. }
  797. pNextStringA = ALIGN_ON_QWORD(szTail + 1); // skip pass the NULL
  798. nDestSize = nCharsLeft - (pNextStringA - szTail);
  799. pReturnObject->dwOpenTimeout = dwOpenTimeout;
  800. // copy collect function or query function
  801. pReturnObject->szCollectProcName = pNextStringA;
  802. hErr = StringCbCopyExA(pNextStringA, nDestSize, szCollectProcName,
  803. &szTail, &nCharsLeft, STRSAFE_NULL_ON_FAILURE);
  804. if (FAILED(hErr)) {
  805. Status = HRESULT_CODE(hErr);
  806. goto AddFailed;
  807. }
  808. pNextStringA = ALIGN_ON_QWORD(szTail + 1);
  809. nDestSize = nCharsLeft - (pNextStringA - szTail);
  810. pReturnObject->dwCollectTimeout = dwCollectTimeout;
  811. // copy Close Procedure Name
  812. pReturnObject->szCloseProcName = pNextStringA;
  813. hErr = StringCbCopyExA(pNextStringA, nDestSize, szCloseProcName,
  814. &szTail, &nCharsLeft, STRSAFE_NULL_ON_FAILURE);
  815. if (FAILED(hErr)) {
  816. Status = HRESULT_CODE(hErr);
  817. goto AddFailed;
  818. }
  819. pNextStringA = ALIGN_ON_QWORD(szTail + 1);
  820. nDestSize = nCharsLeft - (pNextStringA - szTail);
  821. // copy Library path
  822. pNextStringW = (LPWSTR)pNextStringA;
  823. pReturnObject->szLibraryName = pNextStringW;
  824. hErr = StringCchCopyExW(pNextStringW, nDestSize/sizeof(WCHAR),
  825. szLibraryExpPath, (PWCHAR *) &szTail, &nCharsLeft, STRSAFE_NULL_ON_FAILURE);
  826. if (FAILED(hErr)) {
  827. Status = HRESULT_CODE(hErr);
  828. goto AddFailed;
  829. }
  830. pNextStringW = (PWCHAR) ALIGN_ON_QWORD(szTail + sizeof(UNICODE_STRING));
  831. nDestSize = (nCharsLeft * sizeof(WCHAR)) - ((PCHAR) pNextStringW - szTail);
  832. // copy Linkage String if there is one
  833. if (szLinkageString != NULL) {
  834. pReturnObject->szLinkageString = pNextStringW;
  835. memcpy (pNextStringW, szLinkageString, dwLinkageStringLen);
  836. // length includes extra NULL char and is in BYTES
  837. pNextStringW += (dwLinkageStringLen / sizeof (WCHAR));
  838. pNextStringW = ALIGN_ON_QWORD(pNextStringW); // not necessary!
  839. // release the buffer now that it's been copied
  840. FREEMEM (szLinkageString);
  841. szLinkageString = NULL;
  842. nDestSize -= QWORD_MULTIPLE(dwLinkageStringLen);
  843. }
  844. // copy Service name
  845. pReturnObject->szServiceName = pNextStringW;
  846. hErr = StringCchCopyExW(pNextStringW, nDestSize/sizeof(WCHAR),
  847. szServiceName, (PWCHAR *) &szTail, &nCharsLeft, STRSAFE_NULL_ON_FAILURE);
  848. if (FAILED(hErr)) {
  849. Status = HRESULT_CODE(hErr);
  850. goto AddFailed;
  851. }
  852. pNextStringW = (PWCHAR) ALIGN_ON_QWORD(szTail + sizeof(UNICODE_STRING));
  853. nDestSize = (nCharsLeft * sizeof(WCHAR)) - ((PCHAR) pNextStringW - szTail);
  854. // load flags
  855. if (bUseQueryFn) {
  856. dwFlags |= PERF_EO_QUERY_FUNC;
  857. }
  858. pReturnObject->dwFlags = dwFlags;
  859. pReturnObject->hPerfKey = hPerfKey;
  860. pReturnObject->LibData = DllVD; // validation data
  861. pReturnObject->ftLastGoodDllFileDate = LocalftLastGoodDllFileDate;
  862. // the default test level is "all tests"
  863. // if the file and timestamp work out OK, this can
  864. // be reset to the system test level
  865. pReturnObject->dwValidationLevel = EXT_TEST_ALL;
  866. // load Object array
  867. if (dwObjIndex > 0) {
  868. pReturnObject->dwNumObjects = dwObjIndex;
  869. memcpy (pReturnObject->dwObjList,
  870. dwObjectArray, (dwObjIndex * sizeof(dwObjectArray[0])));
  871. }
  872. pReturnObject->llLastUsedTime = 0;
  873. // create Mutex name
  874. hErr = StringCchCopyEx(szMutexName, MAX_STR, szServiceName,
  875. &swzTail, &nCharsLeft, STRSAFE_NULL_ON_FAILURE);
  876. if (SUCCEEDED(hErr)) {
  877. hErr = StringCchCopyEx(swzTail, nCharsLeft,
  878. (LPCWSTR)L"_Perf_Library_Lock_PID_",
  879. &swzTail, &nCharsLeft, STRSAFE_NULL_ON_FAILURE);
  880. }
  881. if (FAILED(hErr)) { // should not happen
  882. Status = HRESULT_CODE(hErr);
  883. }
  884. //
  885. // 16 chars for ULONG is plenty, so assume _ultow cannot fail
  886. //
  887. _ultow ((ULONG)GetCurrentProcessId(), szPID, 16);
  888. hErr = StringCchCopy(swzTail, nCharsLeft, szPID);
  889. if (FAILED(hErr)) { // Should not happen
  890. szPID[0] = 0;
  891. }
  892. {
  893. SECURITY_ATTRIBUTES sa;
  894. BOOL bImpersonating = FALSE;
  895. HANDLE hThreadToken = NULL;
  896. bImpersonating = OpenThreadToken(GetCurrentThread(),
  897. TOKEN_IMPERSONATE,
  898. TRUE,
  899. & hThreadToken);
  900. if (bImpersonating) {
  901. bImpersonating = RevertToSelf();
  902. }
  903. if (g_SizeSD == 0) {
  904. if (PerflibCreateSD()) {
  905. sa.nLength = g_SizeSD;
  906. sa.lpSecurityDescriptor = (LPVOID) g_RuntimeSD;
  907. sa.bInheritHandle = FALSE;
  908. }
  909. else {
  910. sa.nLength = sizeof(g_PrecSD);
  911. sa.lpSecurityDescriptor = (LPVOID) g_PrecSD;
  912. sa.bInheritHandle = FALSE;
  913. }
  914. }
  915. else {
  916. sa.nLength = g_SizeSD;
  917. sa.lpSecurityDescriptor = (LPVOID) g_RuntimeSD;
  918. sa.bInheritHandle = FALSE;
  919. }
  920. pReturnObject->hMutex = CreateMutexW(& sa, FALSE, szMutexName);
  921. if (bImpersonating) {
  922. BOOL bRet;
  923. bRet = SetThreadToken(NULL, hThreadToken);
  924. if (!bRet)
  925. Status = GetLastError();
  926. }
  927. if (hThreadToken) CloseHandle(hThreadToken);
  928. }
  929. pReturnObject->dwErrorLimit = dwErrorLimit;
  930. if ( pReturnObject->hMutex != NULL
  931. && GetLastError() == ERROR_ALREADY_EXISTS) {
  932. Status = ERROR_SUCCESS;
  933. }
  934. else {
  935. Status = GetLastError();
  936. }
  937. } else {
  938. Status = ERROR_OUTOFMEMORY;
  939. TRACE((WINPERF_DBG_TRACE_FATAL),
  940. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, (ULONG)dwMemBlockSize, NULL));
  941. }
  942. }
  943. AddFailed :
  944. if ((Status == ERROR_SUCCESS) && (lpPerflibSectionAddr != NULL)) {
  945. PPERFDATA_SECTION_HEADER pHead;
  946. DWORD dwEntry;
  947. PPERFDATA_SECTION_RECORD pEntry;
  948. // init perf data section
  949. pHead = (PPERFDATA_SECTION_HEADER)lpPerflibSectionAddr;
  950. pEntry = (PPERFDATA_SECTION_RECORD)lpPerflibSectionAddr;
  951. // get the entry first
  952. // the "0" entry is the header
  953. if (pHead->dwEntriesInUse < pHead->dwMaxEntries) {
  954. dwEntry = ++pHead->dwEntriesInUse;
  955. pReturnObject->pPerfSectionEntry = &pEntry[dwEntry];
  956. lstrcpynW (pReturnObject->pPerfSectionEntry->szServiceName,
  957. pReturnObject->szServiceName, PDSR_SERVICE_NAME_LEN);
  958. } else {
  959. // the list is full so bump the missing entry count
  960. pHead->dwMissingEntries++;
  961. pReturnObject->pPerfSectionEntry = NULL;
  962. }
  963. }
  964. if (Status != ERROR_SUCCESS) {
  965. SetLastError (Status);
  966. TRACE((WINPERF_DBG_TRACE_FATAL),
  967. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
  968. if (bDisable) {
  969. DisableLibrary(hPerfKey, szServiceName, PERFLIB_DISABLE_ALL);
  970. }
  971. if (pReturnObject) {
  972. FREEMEM(pReturnObject);
  973. pReturnObject = NULL;
  974. }
  975. if (szLinkageString) {
  976. FREEMEM(szLinkageString);
  977. }
  978. }
  979. if (pReturnObject) {
  980. InitializeListHead((PLIST_ENTRY)&pReturnObject->ErrorLog);
  981. DebugPrint((3, "Initialize list %X\n", pReturnObject->ErrorLog));
  982. }
  983. if (pBuffer) {
  984. FREEMEM(pBuffer);
  985. }
  986. return pReturnObject;
  987. }
  988. void
  989. OpenExtensibleObjects (
  990. )
  991. /*++
  992. Routine Description:
  993. This routine will search the Configuration Registry for modules
  994. which will return data at data collection time. If any are found,
  995. and successfully opened, data structures are allocated to hold
  996. handles to them.
  997. The global data access in this section is protected by the
  998. hGlobalDataMutex acquired by the calling function.
  999. Arguments:
  1000. None.
  1001. successful open.
  1002. Return Value:
  1003. None.
  1004. --*/
  1005. {
  1006. DWORD dwIndex; // index for enumerating services
  1007. ULONG KeyBufferLength; // length of buffer for reading key data
  1008. ULONG ValueBufferLength; // length of buffer for reading value data
  1009. ULONG ResultLength; // length of data returned by Query call
  1010. HANDLE hPerfKey; // Root of queries for performance info
  1011. HANDLE hServicesKey; // Root of services
  1012. REGSAM samDesired; // access needed to query
  1013. NTSTATUS Status; // generally used for Nt call result status
  1014. ANSI_STRING AnsiValueData; // Ansi version of returned strings
  1015. UNICODE_STRING ServiceName; // name of service returned by enumeration
  1016. UNICODE_STRING PathName; // path name to services
  1017. UNICODE_STRING PerformanceName; // name of key holding performance data
  1018. UNICODE_STRING ValueDataName; // result of query of value is this name
  1019. OBJECT_ATTRIBUTES ObjectAttributes; // general use for opening keys
  1020. PKEY_BASIC_INFORMATION KeyInformation; // data from query key goes here
  1021. LPTSTR szMessageArray[8];
  1022. DWORD dwRawDataDwords[8]; // raw data buffer
  1023. DWORD dwDataIndex;
  1024. WORD wStringIndex;
  1025. DWORD dwDefaultValue;
  1026. HKEY hPerflibKey = NULL;
  1027. PEXT_OBJECT pLastObject = NULL;
  1028. PEXT_OBJECT pThisObject = NULL;
  1029. // Initialize do failure can deallocate if allocated
  1030. ServiceName.Buffer = NULL;
  1031. KeyInformation = NULL;
  1032. ValueDataName.Buffer = NULL;
  1033. AnsiValueData.Buffer = NULL;
  1034. hServicesKey = NULL;
  1035. dwIndex = 0;
  1036. RtlInitUnicodeString(&PathName, ExtPath);
  1037. RtlInitUnicodeString(&PerformanceName, PerfSubKey);
  1038. try {
  1039. // get current event log level
  1040. dwDefaultValue = LOG_USER;
  1041. Status = GetPerflibKeyValue (
  1042. EventLogLevel,
  1043. REG_DWORD,
  1044. sizeof(DWORD),
  1045. (LPVOID)&lEventLogLevel,
  1046. sizeof(DWORD),
  1047. (LPVOID)&dwDefaultValue,
  1048. &hPerflibKey);
  1049. dwDefaultValue = EXT_TEST_ALL;
  1050. Status = GetPerflibKeyValue (
  1051. ExtCounterTestLevel,
  1052. REG_DWORD,
  1053. sizeof(DWORD),
  1054. (LPVOID)&lExtCounterTestLevel,
  1055. sizeof(DWORD),
  1056. (LPVOID)&dwDefaultValue,
  1057. &hPerflibKey);
  1058. dwDefaultValue = OPEN_PROC_WAIT_TIME;
  1059. Status = GetPerflibKeyValue (
  1060. OpenProcedureWaitTime,
  1061. REG_DWORD,
  1062. sizeof(DWORD),
  1063. (LPVOID)&dwExtCtrOpenProcWaitMs,
  1064. sizeof(DWORD),
  1065. (LPVOID)&dwDefaultValue,
  1066. &hPerflibKey);
  1067. dwDefaultValue = PERFLIB_TIMING_THREAD_TIMEOUT;
  1068. Status = GetPerflibKeyValue (
  1069. LibraryUnloadTime,
  1070. REG_DWORD,
  1071. sizeof(DWORD),
  1072. (LPVOID)&dwThreadAndLibraryTimeout,
  1073. sizeof(DWORD),
  1074. (LPVOID)&dwDefaultValue,
  1075. &hPerflibKey);
  1076. if (hPerflibKey != NULL) {
  1077. NtClose(hPerflibKey);
  1078. }
  1079. // register as an event log source if not already done.
  1080. if (hEventLog == NULL) {
  1081. hEventLog = RegisterEventSource (NULL, (LPCWSTR)TEXT("Perflib"));
  1082. }
  1083. if (ExtensibleObjects == NULL) {
  1084. // create a list of the known performance data objects
  1085. ServiceName.Length = 0; // Initial to mean empty string
  1086. ServiceName.MaximumLength = (WORD)(MAX_KEY_NAME_LENGTH +
  1087. PerformanceName.MaximumLength +
  1088. sizeof(UNICODE_NULL));
  1089. ServiceName.Buffer = ALLOCMEM(ServiceName.MaximumLength);
  1090. InitializeObjectAttributes(&ObjectAttributes,
  1091. &PathName,
  1092. OBJ_CASE_INSENSITIVE,
  1093. NULL,
  1094. NULL);
  1095. samDesired = KEY_READ;
  1096. Status = NtOpenKey(&hServicesKey,
  1097. samDesired,
  1098. &ObjectAttributes);
  1099. KeyBufferLength = sizeof(KEY_BASIC_INFORMATION) + MAX_KEY_NAME_LENGTH;
  1100. KeyInformation = ALLOCMEM(KeyBufferLength);
  1101. ValueBufferLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
  1102. MAX_VALUE_NAME_LENGTH +
  1103. MAX_VALUE_DATA_LENGTH;
  1104. ValueDataName.MaximumLength = MAX_VALUE_DATA_LENGTH;
  1105. ValueDataName.Buffer = ALLOCMEM(ValueDataName.MaximumLength);
  1106. AnsiValueData.MaximumLength = MAX_VALUE_DATA_LENGTH/sizeof(WCHAR);
  1107. AnsiValueData.Buffer = ALLOCMEM(AnsiValueData.MaximumLength);
  1108. //
  1109. // Check for successful NtOpenKey and allocation of dynamic buffers
  1110. //
  1111. if ( NT_SUCCESS(Status) &&
  1112. ServiceName.Buffer != NULL &&
  1113. KeyInformation != NULL &&
  1114. ValueDataName.Buffer != NULL &&
  1115. AnsiValueData.Buffer != NULL ) {
  1116. dwIndex = 0;
  1117. // wait longer than the thread to give the timing thread
  1118. // a chance to finish on it's own. This is really just a
  1119. // failsafe step.
  1120. while (NT_SUCCESS(Status)) {
  1121. Status = NtEnumerateKey(hServicesKey,
  1122. dwIndex,
  1123. KeyBasicInformation,
  1124. KeyInformation,
  1125. KeyBufferLength,
  1126. &ResultLength);
  1127. dwIndex++; // next time, get the next key
  1128. if( !NT_SUCCESS(Status) ) {
  1129. // This is the normal exit: Status should be
  1130. // STATUS_NO_MORE_VALUES
  1131. break;
  1132. }
  1133. // Concatenate Service name with "\\Performance" to form Subkey
  1134. if ( ServiceName.MaximumLength >=
  1135. (USHORT)( KeyInformation->NameLength + sizeof(UNICODE_NULL) ) ) {
  1136. ServiceName.Length = (USHORT) KeyInformation->NameLength;
  1137. RtlMoveMemory(ServiceName.Buffer,
  1138. KeyInformation->Name,
  1139. ServiceName.Length);
  1140. // remember ServiceName terminator
  1141. dwDataIndex = ServiceName.Length/sizeof(WCHAR);
  1142. ServiceName.Buffer[dwDataIndex] = 0; // null term
  1143. // zero terminate the buffer if space allows
  1144. RtlAppendUnicodeStringToString(&ServiceName,
  1145. &PerformanceName);
  1146. // Open Service\Performance Subkey
  1147. InitializeObjectAttributes(&ObjectAttributes,
  1148. &ServiceName,
  1149. OBJ_CASE_INSENSITIVE,
  1150. hServicesKey,
  1151. NULL);
  1152. samDesired = KEY_WRITE | KEY_READ; // to be able to disable perf DLL's
  1153. Status = NtOpenKey(&hPerfKey,
  1154. samDesired,
  1155. &ObjectAttributes);
  1156. if(! NT_SUCCESS(Status) ) {
  1157. samDesired = KEY_READ; // try read only access
  1158. Status = NtOpenKey(&hPerfKey,
  1159. samDesired,
  1160. &ObjectAttributes);
  1161. }
  1162. if( NT_SUCCESS(Status) ) {
  1163. // this has a performance key so read the info
  1164. // and add the entry to the list
  1165. ServiceName.Buffer[dwDataIndex] = 0; // Put back terminator
  1166. pThisObject = AllocateAndInitializeExtObject (
  1167. hServicesKey, hPerfKey, &ServiceName);
  1168. if (pThisObject != NULL) {
  1169. if (ExtensibleObjects == NULL) {
  1170. // set head pointer
  1171. pLastObject =
  1172. ExtensibleObjects = pThisObject;
  1173. NumExtensibleObjects = 1;
  1174. } else {
  1175. pLastObject->pNext = pThisObject;
  1176. pLastObject = pThisObject;
  1177. NumExtensibleObjects++;
  1178. }
  1179. } else {
  1180. TRACE((WINPERF_DBG_TRACE_FATAL),
  1181. (&PerflibGuid, __LINE__, PERF_OPEN_EXT_OBJS, ARG_TYPE_WSTR, 0,
  1182. ServiceName.Buffer, ServiceName.MaximumLength, NULL));
  1183. // the object wasn't initialized so toss
  1184. // the perf subkey handle.
  1185. // otherwise keep it open for later
  1186. // use and it will be closed when
  1187. // this extensible object is closed
  1188. NtClose (hPerfKey);
  1189. }
  1190. } else {
  1191. TRACE((WINPERF_DBG_TRACE_FATAL),
  1192. (&PerflibGuid, __LINE__, PERF_OPEN_EXT_OBJS, ARG_TYPE_WSTR, Status,
  1193. ServiceName.Buffer, ServiceName.MaximumLength, NULL));
  1194. // unable to open the performance subkey
  1195. if ((Status != STATUS_OBJECT_NAME_NOT_FOUND) &&
  1196. THROTTLE_PERFLIB(PERFLIB_NO_PERFORMANCE_SUBKEY) &&
  1197. (lEventLogLevel >= LOG_DEBUG)) {
  1198. // an error other than OBJECT_NOT_FOUND should be
  1199. // displayed if error logging is enabled
  1200. // if DEBUG level is selected, then write all
  1201. // non-success status returns to the event log
  1202. //
  1203. dwDataIndex = wStringIndex = 0;
  1204. dwRawDataDwords[dwDataIndex++] = PerfpDosError(Status);
  1205. if (lEventLogLevel >= LOG_DEBUG) {
  1206. // if this is DEBUG mode, then log
  1207. // the NT status as well.
  1208. dwRawDataDwords[dwDataIndex++] =
  1209. (DWORD)Status;
  1210. }
  1211. szMessageArray[wStringIndex++] =
  1212. ServiceName.Buffer;
  1213. ReportEvent (hEventLog,
  1214. EVENTLOG_WARNING_TYPE, // error type
  1215. 0, // category (not used)
  1216. (DWORD)PERFLIB_NO_PERFORMANCE_SUBKEY, // event,
  1217. NULL, // SID (not used),
  1218. wStringIndex, // number of strings
  1219. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1220. szMessageArray, // message text array
  1221. (LPVOID)&dwRawDataDwords[0]); // raw data
  1222. }
  1223. }
  1224. }
  1225. Status = STATUS_SUCCESS; // allow loop to continue
  1226. }
  1227. }
  1228. }
  1229. } finally {
  1230. if (hServicesKey != NULL) {
  1231. NtClose(hServicesKey);
  1232. }
  1233. if ( ServiceName.Buffer ) {
  1234. FREEMEM(ServiceName.Buffer);
  1235. }
  1236. if ( KeyInformation ) {
  1237. FREEMEM(KeyInformation);
  1238. }
  1239. if ( ValueDataName.Buffer ) {
  1240. FREEMEM(ValueDataName.Buffer);
  1241. }
  1242. if ( AnsiValueData.Buffer ) {
  1243. FREEMEM(AnsiValueData.Buffer);
  1244. }
  1245. }
  1246. }