Source code of Windows XP (NT5)
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.

375 lines
11 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. ntbase.c
  5. Abstract:
  6. This module implements low level primitives. They should never be
  7. called by anything other than this module.
  8. Author:
  9. dmunsil created sometime in 1999
  10. Revision History:
  11. several people contributed (vadimb, clupu, ...)
  12. --*/
  13. #include "sdbp.h"
  14. #define SDB_MEMORY_POOL_TAG 'abdS'
  15. #if defined(KERNEL_MODE) && defined(ALLOC_DATA_PRAGMA)
  16. #pragma data_seg()
  17. #endif // KERNEL_MODE && ALLOC_DATA_PRAGMA
  18. #if defined(KERNEL_MODE) && defined(ALLOC_PRAGMA)
  19. #pragma alloc_text(PAGE, SdbAlloc)
  20. #pragma alloc_text(PAGE, SdbFree)
  21. #pragma alloc_text(PAGE, SdbpOpenFile)
  22. #pragma alloc_text(PAGE, SdbpQueryAppCompatFlagsByExeID)
  23. #pragma alloc_text(PAGE, SdbGetEntryFlags)
  24. #pragma alloc_text(PAGE, SdbpGetFileSize)
  25. #endif // KERNEL_MODE && ALLOC_PRAGMA
  26. //
  27. // Memory functions
  28. //
  29. void*
  30. SdbAlloc(
  31. IN size_t size // size in bytes to allocate
  32. )
  33. /*++
  34. Return: The pointer allocated.
  35. Desc: Just a wrapper for allocation -- perhaps useful if we move this
  36. code to a non-NTDLL location and need to call differently.
  37. --*/
  38. {
  39. #ifdef BOUNDS_CHECKER_DETECTION
  40. return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
  41. #else
  42. #ifdef KERNEL_MODE
  43. LPVOID lpv; // return zero-initialized memory pool.
  44. lpv = ExAllocatePoolWithTag(PagedPool, size, SDB_MEMORY_POOL_TAG);
  45. if (lpv != NULL) {
  46. RtlZeroMemory(lpv, size);
  47. }
  48. return lpv;
  49. #else
  50. return RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, size);
  51. #endif // KERNEL_MODE
  52. #endif // BOUNDS_CHECKER_DETECTION
  53. }
  54. void
  55. SdbFree(
  56. IN void* pWhat // ptr allocated with SdbAlloc that should be freed.
  57. )
  58. /*++
  59. Return: The pointer allocated.
  60. Desc: Just a wrapper for deallocation -- perhaps useful if we move this
  61. code to a non-NTDLL location and need to call differently.
  62. --*/
  63. {
  64. #ifdef BOUNDS_CHECKER_DETECTION
  65. HeapFree(GetProcessHeap(), 0, pWhat);
  66. #else
  67. #ifdef KERNEL_MODE
  68. ExFreePoolWithTag(pWhat, SDB_MEMORY_POOL_TAG);
  69. #else
  70. RtlFreeHeap(RtlProcessHeap(), 0, pWhat);
  71. #endif // KERNEL_MODE
  72. #endif // BOUNDS_CHECKER_DETECTION
  73. }
  74. HANDLE
  75. SdbpOpenFile(
  76. IN LPCWSTR szPath, // full path of file to open
  77. IN PATH_TYPE eType // DOS_PATH for standard paths, NT_PATH for nt
  78. // internal paths
  79. )
  80. /*++
  81. Return: A handle to the opened file or INVALID_HANDLE_VALUE on failure.
  82. Desc: Just a wrapper for opening an existing file for READ -- perhaps
  83. useful if we move this code to a non-NTDLL location and need to
  84. call differently. Also makes the code more readable by wrapping
  85. all the strange NTDLL goo in one place.
  86. Takes as parameters the path to open, and the kind of path.
  87. NT_PATH is the type used internally in NTDLL, and DOS_PATH is
  88. the type most users know, that begins with a drive letter.
  89. --*/
  90. {
  91. OBJECT_ATTRIBUTES ObjectAttributes;
  92. IO_STATUS_BLOCK IoStatusBlock;
  93. UNICODE_STRING UnicodeString;
  94. NTSTATUS status;
  95. HANDLE hFile = INVALID_HANDLE_VALUE;
  96. #ifndef KERNEL_MODE
  97. RTL_RELATIVE_NAME RelativeName;
  98. #endif // KERNEL_MODE
  99. RtlInitUnicodeString(&UnicodeString, szPath);
  100. #ifndef KERNEL_MODE
  101. if (eType == DOS_PATH) {
  102. if (!RtlDosPathNameToNtPathName_U(szPath,
  103. &UnicodeString,
  104. NULL,
  105. &RelativeName)) {
  106. DBGPRINT((sdlError,
  107. "SdbpOpenFile",
  108. "RtlDosPathNameToNtPathName_U failed, path \"%s\"\n",
  109. szPath));
  110. return INVALID_HANDLE_VALUE;
  111. }
  112. }
  113. #endif // KERNEL_MODE
  114. InitializeObjectAttributes(&ObjectAttributes,
  115. &UnicodeString,
  116. OBJ_CASE_INSENSITIVE,
  117. NULL,
  118. NULL);
  119. status = NtCreateFile(&hFile,
  120. GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  121. &ObjectAttributes,
  122. &IoStatusBlock,
  123. 0,
  124. FILE_ATTRIBUTE_NORMAL,
  125. FILE_SHARE_READ,
  126. FILE_OPEN,
  127. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  128. NULL,
  129. 0);
  130. #ifndef KERNEL_MODE
  131. if (eType == DOS_PATH) {
  132. RtlFreeUnicodeString(&UnicodeString);
  133. }
  134. #endif // KERNEL_MODE
  135. if (!NT_SUCCESS(status)) {
  136. DBGPRINT((sdlInfo, "SdbpOpenFile", "NtCreateFile failed status 0x%x\n", status));
  137. return INVALID_HANDLE_VALUE;
  138. }
  139. return hFile;
  140. }
  141. void
  142. SdbpQueryAppCompatFlagsByExeID(
  143. IN LPCWSTR pwszKeyPath, // NT registry key path.
  144. IN PUNICODE_STRING pustrExeID, // a GUID in string format that identifies the
  145. // EXE entry in the database.
  146. OUT LPDWORD lpdwFlags // this will contain the flags for the EXE
  147. // entry checked.
  148. )
  149. /*++
  150. Return: STATUS_SUCCESS or a failure NTSTATUS code.
  151. Desc: Given an EXE id it returns flags from the registry associated with
  152. that exe..
  153. --*/
  154. {
  155. UNICODE_STRING ustrKey;
  156. NTSTATUS Status;
  157. OBJECT_ATTRIBUTES ObjectAttributes;
  158. HANDLE KeyHandle;
  159. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  160. ULONG KeyValueBuffer[256];
  161. ULONG KeyValueLength;
  162. *lpdwFlags = 0;
  163. RtlInitUnicodeString(&ustrKey, pwszKeyPath);
  164. InitializeObjectAttributes(&ObjectAttributes,
  165. &ustrKey,
  166. OBJ_CASE_INSENSITIVE,
  167. NULL,
  168. NULL);
  169. Status = NtOpenKey(&KeyHandle,
  170. GENERIC_READ|SdbpGetWow64Flag(),
  171. &ObjectAttributes);
  172. if (!NT_SUCCESS(Status)) {
  173. DBGPRINT((sdlInfo,
  174. "SdbpQueryAppCompatFlagsByExeID",
  175. "Failed to open Key \"%s\" Status 0x%x\n",
  176. pwszKeyPath,
  177. Status));
  178. return;
  179. }
  180. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
  181. Status = NtQueryValueKey(KeyHandle,
  182. pustrExeID,
  183. KeyValuePartialInformation,
  184. KeyValueInformation,
  185. sizeof(KeyValueBuffer),
  186. &KeyValueLength);
  187. NtClose(KeyHandle);
  188. if (!NT_SUCCESS(Status)) {
  189. DBGPRINT((sdlInfo,
  190. "SdbpQueryAppCompatFlagsByExeID",
  191. "Failed to read value info from Key \"%s\" Status 0x%x\n",
  192. pwszKeyPath,
  193. Status));
  194. return;
  195. }
  196. //
  197. // Check for the value type.
  198. //
  199. if (KeyValueInformation->Type != REG_DWORD) {
  200. DBGPRINT((sdlError,
  201. "SdbpQueryAppCompatFlagsByExeID",
  202. "Unexpected value type 0x%x for Key \"%s\".\n",
  203. KeyValueInformation->Type,
  204. pwszKeyPath));
  205. return;
  206. }
  207. *lpdwFlags = *(DWORD*)(&KeyValueInformation->Data[0]);
  208. }
  209. BOOL
  210. SdbGetEntryFlags(
  211. IN GUID* pGuid, // pointer to the GUID that identifies an EXE entry in
  212. // the database
  213. OUT LPDWORD lpdwFlags // this will contain the "disable" flags for that entry
  214. )
  215. /*++
  216. Return: TRUE on success, FALSE on failure.
  217. Desc: Given an EXE id it returns flags from the registry associated with
  218. that exe..
  219. --*/
  220. {
  221. BOOL bSuccess = FALSE;
  222. NTSTATUS Status;
  223. UNICODE_STRING ustrExeID;
  224. DWORD dwFlagsUser = 0; // flags from HKEY_CURRENT_USER
  225. DWORD dwFlagsMachine = 0; // flags from HKEY_LOCAL_MACHINE
  226. UNICODE_STRING userKeyPath = { 0 };
  227. *lpdwFlags = 0;
  228. //
  229. // Convert the GUID to string.
  230. //
  231. Status = GUID_TO_UNICODE_STRING(pGuid, &ustrExeID);
  232. if (!NT_SUCCESS(Status)) {
  233. DBGPRINT((sdlError,
  234. "SdbGetEntryFlags",
  235. "Failed to convert EXE id to string. status 0x%x.\n",
  236. Status));
  237. return TRUE;
  238. }
  239. //
  240. // Query the flags in the LOCAL_MACHINE subtree.
  241. //
  242. SdbpQueryAppCompatFlagsByExeID(APPCOMPAT_KEY_PATH_MACHINE, &ustrExeID, &dwFlagsMachine);
  243. //
  244. // Set the flags here so that if any call from now on fails we at least have
  245. // the per machine settings.
  246. //
  247. *lpdwFlags = dwFlagsMachine;
  248. //
  249. // We do not query CURRENT_USER subtree in kernel-mode
  250. //
  251. #ifndef KERNEL_MODE
  252. if (!SdbpBuildUserKeyPath(APPCOMPAT_KEY_PATH_NT, &userKeyPath)) {
  253. DBGPRINT((sdlError,
  254. "SdbGetEntryFlags",
  255. "Failed to format current user key path for \"%s\"\n",
  256. APPCOMPAT_KEY_PATH_NT));
  257. FREE_GUID_STRING(&ustrExeID);
  258. return TRUE;
  259. }
  260. SdbpQueryAppCompatFlagsByExeID(userKeyPath.Buffer, &ustrExeID, &dwFlagsUser);
  261. *lpdwFlags |= dwFlagsUser;
  262. SdbFree(userKeyPath.Buffer);
  263. #endif // KERNEL_MODE
  264. //
  265. // Free the buffer allocated by RtlStringFromGUID
  266. //
  267. FREE_GUID_STRING(&ustrExeID);
  268. return TRUE;
  269. }
  270. DWORD
  271. SdbpGetFileSize(
  272. IN HANDLE hFile // file to check the size of
  273. )
  274. /*++
  275. Return: The size of the file or 0 on failure.
  276. Desc: Gets the lower DWORD of the size of a file -- only
  277. works accurately with files smaller than 2GB.
  278. In general, since we're only interested in matching, we're
  279. fine just matching the least significant DWORD of the file size.
  280. --*/
  281. {
  282. FILE_STANDARD_INFORMATION FileStandardInformationBlock;
  283. IO_STATUS_BLOCK IoStatusBlock;
  284. HRESULT status;
  285. status = NtQueryInformationFile(hFile,
  286. &IoStatusBlock,
  287. &FileStandardInformationBlock,
  288. sizeof(FileStandardInformationBlock),
  289. FileStandardInformation);
  290. if (!NT_SUCCESS(status)) {
  291. DBGPRINT((sdlError, "SdbpGetFileSize", "Unsuccessful. Status: 0x%x.\n", status));
  292. return 0;
  293. }
  294. return FileStandardInformationBlock.EndOfFile.LowPart;
  295. }