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.

374 lines
13 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. sxsstorage.c
  5. Abstract:
  6. User-mode side by side storage map default resolution support.
  7. Private functions that support the default probing/finding
  8. where assemblies are stored.
  9. Author:
  10. Michael J. Grier (mgrier) 6/30/2000
  11. Revision History:
  12. --*/
  13. #if defined(__cplusplus)
  14. extern "C" {
  15. #endif
  16. #pragma warning(disable:4201) // nameless struct/union
  17. #include "nt.h"
  18. #include "ntrtl.h"
  19. #include "nturtl.h"
  20. #include "string.h"
  21. #include "ctype.h"
  22. #include "sxstypes.h"
  23. #include "ntdllp.h"
  24. VOID
  25. NTAPI
  26. RtlpAssemblyStorageMapResolutionDefaultCallback(
  27. ULONG Reason,
  28. PASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_DATA Data,
  29. PVOID Context
  30. )
  31. {
  32. NTSTATUS Status;
  33. NTSTATUS *StatusOut = (NTSTATUS *) Context;
  34. switch (Reason) {
  35. case ASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_REASON_RESOLUTION_BEGINNING: {
  36. static const WCHAR NameStringBuffer[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\SideBySide\\AssemblyStorageRoots";
  37. static const UNICODE_STRING NameString = { sizeof(NameStringBuffer) - sizeof(WCHAR), sizeof(NameStringBuffer), (PWSTR) NameStringBuffer };
  38. OBJECT_ATTRIBUTES Obja;
  39. HANDLE KeyHandle = NULL;
  40. InitializeObjectAttributes(
  41. &Obja,
  42. (PUNICODE_STRING) &NameString,
  43. OBJ_CASE_INSENSITIVE,
  44. NULL,
  45. NULL);
  46. Status = NtOpenKey(&KeyHandle, KEY_ENUMERATE_SUB_KEYS, &Obja);
  47. if (!NT_SUCCESS(Status)) {
  48. // If the key is not found, we handle the system assembly installation area and privatized
  49. // assemblies differently anyways, so let things continue. We'll just stop when we
  50. // try to use the registry stuff.
  51. if ((Status != STATUS_OBJECT_NAME_NOT_FOUND) &&
  52. (Status != STATUS_TOO_LATE)) {
  53. DbgPrintEx(
  54. DPFLTR_SXS_ID,
  55. DPFLTR_ERROR_LEVEL,
  56. "SXS: Unable to open registry key %wZ Status = 0x%08lx\n", &NameString, Status);
  57. Data->ResolutionBeginning.CancelResolution = TRUE;
  58. if (StatusOut != NULL)
  59. *StatusOut = Status;
  60. break;
  61. }
  62. RTL_SOFT_ASSERT(KeyHandle == NULL);
  63. }
  64. Data->ResolutionBeginning.ResolutionContext = (PVOID) KeyHandle;
  65. Data->ResolutionBeginning.RootCount = ((SIZE_T) -1);
  66. break;
  67. }
  68. case ASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_REASON_GET_ROOT: {
  69. DbgPrintEx(
  70. DPFLTR_SXS_ID,
  71. DPFLTR_TRACE_LEVEL,
  72. "SXS: Getting assembly storage root #%Iu\n", Data->GetRoot.RootIndex);
  73. if (Data->GetRoot.RootIndex == 0) {
  74. // privatized assembly
  75. static const WCHAR DllRedirectionLocal[] = L".Local\\";
  76. USHORT cbFullImageNameLength;
  77. LPWSTR pFullImageName = NULL;
  78. SIZE_T TotalLength;
  79. PVOID Cursor = NULL;
  80. // get ImageName and Lenght from PEB
  81. cbFullImageNameLength = NtCurrentPeb()->ProcessParameters->ImagePathName.Length; // w/o trailing NULL
  82. TotalLength = cbFullImageNameLength + sizeof(DllRedirectionLocal); // containing a trailing NULL
  83. if (TotalLength > UNICODE_STRING_MAX_BYTES) {
  84. Data->GetRoot.CancelResolution = TRUE;
  85. if (StatusOut != NULL)
  86. *StatusOut = STATUS_NAME_TOO_LONG;
  87. break;
  88. }
  89. if ( TotalLength > Data->GetRoot.Root.MaximumLength) {
  90. Data->GetRoot.CancelResolution = TRUE;
  91. if (StatusOut != NULL)
  92. *StatusOut = STATUS_BUFFER_TOO_SMALL;
  93. break;
  94. }
  95. // point to ImageName
  96. pFullImageName = (PWSTR)NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer;
  97. if (!(NtCurrentPeb()->ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED))
  98. pFullImageName = (PWSTR)((PCHAR)pFullImageName + (ULONG_PTR)(NtCurrentPeb()->ProcessParameters));
  99. Cursor = Data->GetRoot.Root.Buffer;
  100. RtlCopyMemory(Cursor, pFullImageName, cbFullImageNameLength);
  101. Cursor = (PVOID) (((ULONG_PTR) Cursor) + cbFullImageNameLength);
  102. RtlCopyMemory(Cursor, DllRedirectionLocal, sizeof(DllRedirectionLocal));//with a trailing "/" and NULL
  103. Data->GetRoot.Root.Length = (USHORT)TotalLength - sizeof(WCHAR);
  104. if ( ! RtlDoesFileExists_U(Data->GetRoot.Root.Buffer)) // no bother to return a wrong path
  105. Data->GetRoot.Root.Length = 0 ;
  106. } else if (Data->GetRoot.RootIndex == 1) {
  107. static const UNICODE_STRING WinSxS = RTL_CONSTANT_STRING(L"\\WinSxS\\");
  108. UNICODE_STRING SystemRoot;
  109. RtlInitUnicodeString(&SystemRoot, USER_SHARED_DATA->NtSystemRoot);
  110. Data->GetRoot.Root.Length = 0;
  111. if ((SystemRoot.Length + WinSxS.Length) > Data->GetRoot.Root.MaximumLength) {
  112. Data->GetRoot.CancelResolution = TRUE;
  113. if (StatusOut != NULL)
  114. *StatusOut = STATUS_BUFFER_TOO_SMALL;
  115. break;
  116. }
  117. RtlCopyMemory(Data->GetRoot.Root.Buffer, SystemRoot.Buffer, SystemRoot.Length);
  118. RtlCopyMemory(((PUCHAR)Data->GetRoot.Root.Buffer) + SystemRoot.Length, WinSxS.Buffer, WinSxS.Length);
  119. Data->GetRoot.Root.Length = SystemRoot.Length + WinSxS.Length;
  120. } else if (Data->GetRoot.RootIndex <= MAXULONG) {
  121. // Return the appropriate root
  122. struct {
  123. KEY_BASIC_INFORMATION kbi;
  124. WCHAR KeyNameBuffer[DOS_MAX_PATH_LENGTH]; // arbitrary biggish size
  125. } KeyData;
  126. HANDLE KeyHandle = (HANDLE) Data->GetRoot.ResolutionContext;
  127. ULONG ResultLength = 0;
  128. ULONG SubKeyIndex = (ULONG) (Data->GetRoot.RootIndex - 2); // minus two because we use index 0 for privatized assembly probing and 1 for %SystemRoot%\winsxs
  129. UNICODE_STRING SubKeyName;
  130. // If the registry key could not be opened in the first place, we're done.
  131. if (KeyHandle == NULL) {
  132. Data->GetRoot.NoMoreEntries = TRUE;
  133. break;
  134. }
  135. Status = NtEnumerateKey(
  136. KeyHandle,
  137. SubKeyIndex,
  138. KeyBasicInformation,
  139. &KeyData,
  140. sizeof(KeyData),
  141. &ResultLength);
  142. if (!NT_SUCCESS(Status)) {
  143. // If this is the end of the subkeys, tell our caller to stop the iterations.
  144. if (Status == STATUS_NO_MORE_ENTRIES) {
  145. Data->GetRoot.NoMoreEntries = TRUE;
  146. break;
  147. }
  148. DbgPrintEx(
  149. DPFLTR_SXS_ID,
  150. DPFLTR_ERROR_LEVEL,
  151. "SXS: Unable to enumerate assembly storage subkey #%lu Status = 0x%08lx\n", SubKeyIndex, Status);
  152. // Otherwise, cancel the searching and propogate the error status.
  153. Data->GetRoot.CancelResolution = TRUE;
  154. if (StatusOut != NULL)
  155. *StatusOut = Status;
  156. break;
  157. }
  158. if (KeyData.kbi.NameLength > UNICODE_STRING_MAX_BYTES) {
  159. Data->GetRoot.CancelResolution = TRUE;
  160. if (StatusOut != NULL)
  161. *StatusOut = STATUS_NAME_TOO_LONG;
  162. break;
  163. }
  164. SubKeyName.Length = (USHORT) KeyData.kbi.NameLength;
  165. SubKeyName.MaximumLength = SubKeyName.Length;
  166. SubKeyName.Buffer = KeyData.kbi.Name;
  167. Status = RtlpGetAssemblyStorageMapRootLocation(
  168. KeyHandle,
  169. &SubKeyName,
  170. &Data->GetRoot.Root);
  171. if (!NT_SUCCESS(Status)) {
  172. DbgPrintEx(
  173. DPFLTR_SXS_ID,
  174. DPFLTR_ERROR_LEVEL,
  175. "SXS: Attempt to get storage location from subkey %wZ failed; Status = 0x%08lx\n", &SubKeyName, Status);
  176. Data->GetRoot.CancelResolution = TRUE;
  177. if (StatusOut != NULL)
  178. *StatusOut = Status;
  179. break;
  180. }
  181. } else {
  182. Data->GetRoot.NoMoreEntries = TRUE;
  183. break;
  184. }
  185. break;
  186. }
  187. case ASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_REASON_RESOLUTION_SUCCESSFUL:
  188. // nothing to do...
  189. break;
  190. case ASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_REASON_RESOLUTION_ENDING: {
  191. // close the registry key, if it was opened.
  192. if (Data->ResolutionEnding.ResolutionContext != NULL) {
  193. RTL_SOFT_VERIFY(NT_SUCCESS(NtClose((HANDLE) Data->ResolutionEnding.ResolutionContext)));
  194. }
  195. break;
  196. }
  197. }
  198. }
  199. NTSTATUS
  200. RtlpGetAssemblyStorageMapRootLocation(
  201. HANDLE KeyHandle,
  202. PCUNICODE_STRING SubKeyName,
  203. PUNICODE_STRING Root
  204. )
  205. {
  206. NTSTATUS Status = STATUS_SUCCESS;
  207. OBJECT_ATTRIBUTES Obja;
  208. HANDLE SubKeyHandle = NULL;
  209. ULONG ResultLength = 0;
  210. struct {
  211. KEY_VALUE_PARTIAL_INFORMATION kvpi;
  212. WCHAR Buffer[DOS_MAX_PATH_LENGTH];
  213. } ValueData;
  214. static const WCHAR ValueNameBuffer[] = L"Location";
  215. static const UNICODE_STRING ValueName = { sizeof(ValueNameBuffer) - sizeof(WCHAR), sizeof(ValueNameBuffer), (PWSTR) ValueNameBuffer };
  216. ASSERT(KeyHandle != NULL);
  217. ASSERT(SubKeyName != NULL);
  218. ASSERT(Root != NULL);
  219. if ((KeyHandle == NULL) ||
  220. (SubKeyName == NULL) ||
  221. (Root == NULL)) {
  222. Status = STATUS_INVALID_PARAMETER;
  223. goto Exit;
  224. }
  225. InitializeObjectAttributes(
  226. &Obja,
  227. (PUNICODE_STRING) &SubKeyName,
  228. OBJ_CASE_INSENSITIVE,
  229. KeyHandle,
  230. NULL);
  231. Status = NtOpenKey(&SubKeyHandle, KEY_QUERY_VALUE, &Obja);
  232. if (!NT_SUCCESS(Status)) {
  233. DbgPrintEx(
  234. DPFLTR_SXS_ID,
  235. DPFLTR_ERROR_LEVEL,
  236. "SXS: Unable to open storage root subkey %wZ; Status = 0x%08lx\n", &SubKeyName, Status);
  237. goto Exit;
  238. }
  239. Status = NtQueryValueKey(
  240. SubKeyHandle,
  241. (PUNICODE_STRING) &ValueName,
  242. KeyValuePartialInformation,
  243. &ValueData,
  244. sizeof(ValueData),
  245. &ResultLength);
  246. if (!NT_SUCCESS(Status)) {
  247. DbgPrintEx(
  248. DPFLTR_SXS_ID,
  249. DPFLTR_ERROR_LEVEL,
  250. "SXS: Unabel to query location from storage root subkey %wZ; Status = 0x%08lx\n", &SubKeyName, Status);
  251. goto Exit;
  252. }
  253. if (ValueData.kvpi.Type != REG_SZ) {
  254. DbgPrintEx(
  255. DPFLTR_SXS_ID,
  256. DPFLTR_ERROR_LEVEL,
  257. "SXS: Assembly storage root location value type is not REG_SZ\n");
  258. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  259. goto Exit;
  260. }
  261. if ((ValueData.kvpi.DataLength % 2) != 0) {
  262. // Hmmm... a unicode string with an odd size??
  263. DbgPrintEx(
  264. DPFLTR_SXS_ID,
  265. DPFLTR_ERROR_LEVEL,
  266. "SXS: Assembly storage root location value has non-even size\n");
  267. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  268. goto Exit;
  269. }
  270. if (ValueData.kvpi.DataLength > Root->MaximumLength) {
  271. // The buffer isn't big enough. Let's allocate one that is.
  272. if (ValueData.kvpi.DataLength > UNICODE_STRING_MAX_BYTES) {
  273. DbgPrintEx(
  274. DPFLTR_SXS_ID,
  275. DPFLTR_ERROR_LEVEL,
  276. "SXS: Assembly storage root location for %wZ does not fit in a UNICODE STRING\n", &SubKeyName);
  277. Status = STATUS_NAME_TOO_LONG;
  278. goto Exit;
  279. }
  280. Root->MaximumLength = (USHORT) ValueData.kvpi.DataLength;
  281. Root->Buffer = (PWSTR)(RtlAllocateStringRoutine)(Root->MaximumLength);
  282. if (Root->Buffer == NULL) {
  283. Status = STATUS_NO_MEMORY;
  284. goto Exit;
  285. }
  286. }
  287. RtlCopyMemory(
  288. Root->Buffer,
  289. ValueData.kvpi.Data,
  290. ValueData.kvpi.DataLength);
  291. // We checked the length earlier; either it was less than or equal to a value that's
  292. // already stored in a USHORT or we explicitly compared against UNICODE_STRING_MAX_BYTES.
  293. Root->Length = (USHORT) ValueData.kvpi.DataLength;
  294. Status = STATUS_SUCCESS;
  295. Exit:
  296. if (SubKeyHandle != NULL) {
  297. RTL_SOFT_VERIFY(NT_SUCCESS(NtClose(SubKeyHandle)));
  298. }
  299. return Status;
  300. }
  301. #if defined(__cplusplus)
  302. } /* extern "C" */
  303. #endif