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.

364 lines
13 KiB

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