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.

1522 lines
51 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. sxsstorage.c
  5. Abstract:
  6. Side-by-side activation support for Windows/NT
  7. Implementation of the assembly storage map.
  8. Author:
  9. Michael Grier (MGrier) 6/13/2000
  10. Revision History:
  11. Xiaoyu Wu(xiaoyuw) 7/01/2000 .local directory
  12. Xiaoyu Wu(xiaoyuw) 8/04/2000 private assembly
  13. Jay Krell (a-JayK) October 2000 the little bit of system default context that wasn't already done
  14. --*/
  15. #pragma warning(disable:4214) // bit field types other than int
  16. #pragma warning(disable:4201) // nameless struct/union
  17. #pragma warning(disable:4115) // named type definition in parentheses
  18. #pragma warning(disable:4127) // condition expression is constant
  19. #include <ntos.h>
  20. #include <ntrtl.h>
  21. #include <nturtl.h>
  22. #include <sxstypes.h>
  23. #include "sxsp.h"
  24. #define IS_PATH_SEPARATOR(_wch) (((_wch) == L'\\') || ((_wch) == L'/'))
  25. #define LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX L".Local"
  26. #if DBG
  27. PCUNICODE_STRING RtlpGetImagePathName(VOID);
  28. #define RtlpGetCurrentProcessId() (HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess))
  29. #define RtlpGetCurrentThreadId() (HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread))
  30. #endif
  31. #if DBG
  32. PCUNICODE_STRING RtlpGetImagePathName(VOID)
  33. {
  34. PPEB Peb = NtCurrentPeb();
  35. return (Peb->ProcessParameters != NULL) ? &Peb->ProcessParameters->ImagePathName : NULL;
  36. }
  37. static VOID
  38. DbgPrintFunctionEntry(
  39. CONST CHAR* Function
  40. )
  41. {
  42. DbgPrintEx(
  43. DPFLTR_SXS_ID,
  44. DPFLTR_TRACE_LEVEL,
  45. "SXS: [pid:0x%x, tid:0x%x, %wZ] enter %s%d()\n",
  46. RtlpGetCurrentProcessId(),
  47. RtlpGetCurrentThreadId(),
  48. RtlpGetImagePathName(),
  49. Function,
  50. (int)sizeof(PVOID) * 8
  51. );
  52. }
  53. static VOID
  54. DbgPrintFunctionExit(
  55. CONST CHAR* Function,
  56. NTSTATUS Status
  57. )
  58. {
  59. DbgPrintEx(
  60. DPFLTR_SXS_ID,
  61. NT_SUCCESS(Status) ? DPFLTR_TRACE_LEVEL : DPFLTR_ERROR_LEVEL,
  62. "SXS: [0x%x.%x] %s%d() exiting with status 0x%lx\n",
  63. RtlpGetCurrentProcessId(),
  64. RtlpGetCurrentThreadId(),
  65. Function,
  66. (int)sizeof(PVOID) * 8,
  67. Status
  68. );
  69. }
  70. #else
  71. #define DbgPrintFunctionEntry(function) /* nothing */
  72. #define DbgPrintFunctionExit(function, status) /* nothing */
  73. #endif // DBG
  74. // Because we write to the peb, we must not be in 64bit code for a 32bit process,
  75. // unless we know we are early enough in CreateProcess, which is not the case
  76. // in this file. Also don't call the 32bit version of this in a 64bit process.
  77. #if DBG
  78. #define ASSERT_OK_TO_WRITE_PEB() \
  79. { \
  80. PVOID Peb32 = NULL; \
  81. NTSTATUS Status; \
  82. \
  83. Status = \
  84. NtQueryInformationProcess( \
  85. NtCurrentProcess(), \
  86. ProcessWow64Information, \
  87. &Peb32, \
  88. sizeof(Peb32), \
  89. NULL); \
  90. /* The other Peb must be The Peb or the other Peb must not exist. */ \
  91. ASSERT(Peb32 == NtCurrentPeb() || Peb32 == NULL); \
  92. }
  93. #else
  94. #define ASSERT_OK_TO_WRITE_PEB() /* nothing */
  95. #endif
  96. NTSTATUS
  97. RtlpInitializeAssemblyStorageMap(
  98. PASSEMBLY_STORAGE_MAP Map,
  99. ULONG EntryCount,
  100. PASSEMBLY_STORAGE_MAP_ENTRY *EntryArray
  101. )
  102. {
  103. NTSTATUS Status = STATUS_SUCCESS;
  104. ULONG i;
  105. ULONG Flags = 0;
  106. #if DBG
  107. DbgPrintFunctionEntry(__FUNCTION__);
  108. DbgPrintEx(
  109. DPFLTR_SXS_ID,
  110. DPFLTR_TRACE_LEVEL,
  111. "%s(Map:%p, EntryCount:0x%lx)\n",
  112. __FUNCTION__,
  113. Map,
  114. EntryCount
  115. );
  116. ASSERT_OK_TO_WRITE_PEB();
  117. #endif // DBG
  118. if ((Map == NULL) ||
  119. (EntryCount == 0)) {
  120. DbgPrintEx(
  121. DPFLTR_SXS_ID,
  122. DPFLTR_ERROR_LEVEL,
  123. "SXS: %s() bad parameters:\n"
  124. "SXS: Map : 0x%lx\n"
  125. "SXS: EntryCount : 0x%lx\n"
  126. __FUNCTION__,
  127. Map,
  128. EntryCount
  129. );
  130. Status = STATUS_INVALID_PARAMETER;
  131. goto Exit;
  132. }
  133. if (EntryArray == NULL) {
  134. EntryArray = (PASSEMBLY_STORAGE_MAP_ENTRY *) RtlAllocateHeap(RtlProcessHeap(), 0, EntryCount * sizeof(PASSEMBLY_STORAGE_MAP_ENTRY));
  135. if (EntryArray == NULL) {
  136. Status = STATUS_NO_MEMORY;
  137. goto Exit;
  138. }
  139. Flags |= ASSEMBLY_STORAGE_MAP_ASSEMBLY_ARRAY_IS_HEAP_ALLOCATED;
  140. }
  141. for (i=0; i<EntryCount; i++)
  142. EntryArray[i] = NULL;
  143. Map->Flags = Flags;
  144. Map->AssemblyCount = EntryCount;
  145. Map->AssemblyArray = EntryArray;
  146. Status = STATUS_SUCCESS;
  147. Exit:
  148. #if DBG
  149. DbgPrintFunctionExit(__FUNCTION__, Status);
  150. DbgPrintEx(
  151. DPFLTR_SXS_ID,
  152. NT_SUCCESS(Status) ? DPFLTR_TRACE_LEVEL : DPFLTR_ERROR_LEVEL,
  153. "%s(Map:%p, EntryCount:0x%lx) : (Map:%p, Status:0x%lx)\n",
  154. __FUNCTION__,
  155. Map,
  156. EntryCount,
  157. Map,
  158. Status
  159. );
  160. #endif
  161. return Status;
  162. }
  163. VOID
  164. RtlpUninitializeAssemblyStorageMap(
  165. PASSEMBLY_STORAGE_MAP Map
  166. )
  167. {
  168. DbgPrintFunctionEntry(__FUNCTION__);
  169. #if DBG
  170. DbgPrintEx(
  171. DPFLTR_SXS_ID,
  172. DPFLTR_TRACE_LEVEL,
  173. "%s(Map:%p)\n",
  174. __FUNCTION__,
  175. Map
  176. );
  177. #endif
  178. if (Map != NULL) {
  179. ULONG i;
  180. for (i=0; i<Map->AssemblyCount; i++) {
  181. PASSEMBLY_STORAGE_MAP_ENTRY Entry = Map->AssemblyArray[i];
  182. if (Entry != NULL) {
  183. Entry->DosPath.Length = 0;
  184. Entry->DosPath.MaximumLength = 0;
  185. Entry->DosPath.Buffer = NULL;
  186. if (Entry->Handle != NULL) {
  187. RTL_SOFT_VERIFY(NT_SUCCESS(NtClose(Entry->Handle)));
  188. Entry->Handle = NULL;
  189. }
  190. Map->AssemblyArray[i] = NULL;
  191. RtlFreeHeap(RtlProcessHeap(), 0, Entry);
  192. }
  193. }
  194. if (Map->Flags & ASSEMBLY_STORAGE_MAP_ASSEMBLY_ARRAY_IS_HEAP_ALLOCATED) {
  195. RtlFreeHeap(RtlProcessHeap(), 0, Map->AssemblyArray);
  196. }
  197. Map->AssemblyArray = NULL;
  198. Map->AssemblyCount = 0;
  199. Map->Flags = 0;
  200. }
  201. }
  202. NTSTATUS
  203. RtlpInsertAssemblyStorageMapEntry(
  204. PASSEMBLY_STORAGE_MAP Map,
  205. ULONG AssemblyRosterIndex,
  206. PCUNICODE_STRING StorageLocation,
  207. HANDLE* OpenDirectoryHandle
  208. )
  209. {
  210. PASSEMBLY_STORAGE_MAP_ENTRY Entry = NULL;
  211. NTSTATUS Status = STATUS_SUCCESS;
  212. ASSERT(Map != NULL);
  213. ASSERT(AssemblyRosterIndex >= 1);
  214. ASSERT((Map != NULL) && (AssemblyRosterIndex < Map->AssemblyCount));
  215. ASSERT(StorageLocation != NULL);
  216. ASSERT((StorageLocation != NULL) && (StorageLocation->Length >= sizeof(WCHAR)));
  217. ASSERT((StorageLocation != NULL) && (StorageLocation->Buffer != NULL));
  218. DbgPrintFunctionEntry(__FUNCTION__);
  219. if ((Map == NULL) ||
  220. (AssemblyRosterIndex < 1) ||
  221. (AssemblyRosterIndex > Map->AssemblyCount) ||
  222. (StorageLocation == NULL) ||
  223. (StorageLocation->Length < sizeof(WCHAR)) ||
  224. (StorageLocation->Buffer == NULL) ||
  225. (OpenDirectoryHandle == NULL)) {
  226. DbgPrintEx(
  227. DPFLTR_SXS_ID,
  228. DPFLTR_ERROR_LEVEL,
  229. "SXS: %s() bad parameters\n"
  230. "SXS: Map : %p\n"
  231. "SXS: AssemblyRosterIndex : 0x%lx\n"
  232. "SXS: Map->AssemblyCount : 0x%lx\n"
  233. "SXS: StorageLocation : %p\n"
  234. "SXS: StorageLocation->Length: 0x%x\n"
  235. "SXS: StorageLocation->Buffer: %p\n"
  236. "SXS: OpenDirectoryHandle : %p\n",
  237. __FUNCTION__,
  238. Map,
  239. AssemblyRosterIndex,
  240. Map ? Map->AssemblyCount : 0,
  241. StorageLocation,
  242. (StorageLocation != NULL) ? StorageLocation->Length : 0,
  243. (StorageLocation != NULL) ? StorageLocation->Buffer : NULL,
  244. OpenDirectoryHandle
  245. );
  246. Status = STATUS_INVALID_PARAMETER;
  247. goto Exit;
  248. }
  249. if ((StorageLocation->Length + sizeof(WCHAR)) > UNICODE_STRING_MAX_BYTES) {
  250. Status = STATUS_NAME_TOO_LONG;
  251. goto Exit;
  252. }
  253. Entry = (PASSEMBLY_STORAGE_MAP_ENTRY) RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(ASSEMBLY_STORAGE_MAP_ENTRY) + StorageLocation->Length + sizeof(WCHAR));
  254. if (Entry == NULL) {
  255. Status = STATUS_NO_MEMORY;
  256. goto Exit;
  257. }
  258. Entry->Flags = 0;
  259. Entry->DosPath.Length = StorageLocation->Length;
  260. Entry->DosPath.Buffer = (PWSTR) (Entry + 1);
  261. Entry->DosPath.MaximumLength = (USHORT) (StorageLocation->Length + sizeof(WCHAR));
  262. RtlCopyMemory(
  263. Entry->DosPath.Buffer,
  264. StorageLocation->Buffer,
  265. StorageLocation->Length);
  266. Entry->DosPath.Buffer[Entry->DosPath.Length / sizeof(WCHAR)] = L'\0';
  267. Entry->Handle = *OpenDirectoryHandle;
  268. // Ok, we're all set. Let's try the big interlocked switcheroo
  269. if (InterlockedCompareExchangePointer(
  270. (PVOID *) &Map->AssemblyArray[AssemblyRosterIndex],
  271. (PVOID) Entry,
  272. (PVOID) NULL) == NULL) {
  273. // If we're the first ones in, avoid cleaning up in the exit path.
  274. Entry = NULL;
  275. *OpenDirectoryHandle = NULL;
  276. }
  277. Status = STATUS_SUCCESS;
  278. Exit:
  279. DbgPrintFunctionExit(__FUNCTION__, Status);
  280. if (Entry != NULL) {
  281. RtlFreeHeap(RtlProcessHeap(), 0, Entry);
  282. }
  283. return Status;
  284. }
  285. NTSTATUS
  286. RtlpResolveAssemblyStorageMapEntry(
  287. PASSEMBLY_STORAGE_MAP Map,
  288. PCACTIVATION_CONTEXT_DATA Data,
  289. ULONG AssemblyRosterIndex,
  290. PASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_ROUTINE Callback,
  291. PVOID CallbackContext
  292. )
  293. {
  294. NTSTATUS Status = STATUS_SUCCESS;
  295. ASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_DATA CallbackData;
  296. PVOID ResolutionContext;
  297. BOOLEAN ResolutionContextValid = FALSE;
  298. UNICODE_STRING AssemblyDirectory;
  299. PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRoster;
  300. PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY AssemblyRosterEntry;
  301. PCACTIVATION_CONTEXT_DATA_ASSEMBLY_INFORMATION AssemblyInformation;
  302. PVOID AssemblyInformationSectionBase;
  303. UNICODE_STRING ResolvedPath;
  304. WCHAR ResolvedPathBuffer[DOS_MAX_PATH_LENGTH];
  305. UNICODE_STRING ResolvedDynamicPath;
  306. PUNICODE_STRING ResolvedPathUsed;
  307. HANDLE OpenDirectoryHandle = NULL;
  308. WCHAR QueryPathBuffer[DOS_MAX_PATH_LENGTH];
  309. UNICODE_STRING FileName;
  310. RTL_RELATIVE_NAME RelativeName;
  311. OBJECT_ATTRIBUTES Obja;
  312. IO_STATUS_BLOCK IoStatusBlock;
  313. SIZE_T RootCount, CurrentRootIndex;
  314. PWSTR FreeBuffer = NULL;
  315. DbgPrintFunctionEntry(__FUNCTION__);
  316. ResolvedPath.Length = 0;
  317. ResolvedPath.MaximumLength = sizeof(ResolvedPathBuffer);
  318. ResolvedPath.Buffer = ResolvedPathBuffer;
  319. ResolvedDynamicPath.Length = 0;
  320. ResolvedDynamicPath.MaximumLength = 0;
  321. ResolvedDynamicPath.Buffer = NULL;
  322. FileName.Length = 0;
  323. FileName.MaximumLength = 0;
  324. FileName.Buffer = NULL;
  325. ResolutionContext = NULL;
  326. // First, let's validate parameters...
  327. if ((Map == NULL) ||
  328. (Data == NULL) ||
  329. (AssemblyRosterIndex < 1) ||
  330. (AssemblyRosterIndex > Map->AssemblyCount)) {
  331. DbgPrintEx(
  332. DPFLTR_SXS_ID,
  333. DPFLTR_ERROR_LEVEL,
  334. "SXS: %s() bad parameters\n"
  335. "SXS: Map : %p\n"
  336. "SXS: Data : %p\n"
  337. "SXS: AssemblyRosterIndex: 0x%lx\n"
  338. "SXS: Map->AssemblyCount : 0x%lx\n",
  339. __FUNCTION__,
  340. Map,
  341. Data,
  342. AssemblyRosterIndex,
  343. (Map != NULL) ? Map->AssemblyCount : 0
  344. );
  345. Status = STATUS_INVALID_PARAMETER;
  346. goto Exit;
  347. }
  348. // Is it already resolved?
  349. if (Map->AssemblyArray[AssemblyRosterIndex] != NULL)
  350. goto Exit;
  351. AssemblyRoster = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) Data) + Data->AssemblyRosterOffset);
  352. AssemblyRosterEntry = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY) (((ULONG_PTR) Data) + AssemblyRoster->FirstEntryOffset + (AssemblyRosterIndex * sizeof(ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY)));
  353. AssemblyInformation = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_INFORMATION) (((ULONG_PTR) Data) + AssemblyRosterEntry->AssemblyInformationOffset);
  354. AssemblyInformationSectionBase = (PVOID) (((ULONG_PTR) Data) + AssemblyRoster->AssemblyInformationSectionOffset);
  355. if (AssemblyInformation->AssemblyDirectoryNameLength > UNICODE_STRING_MAX_BYTES) {
  356. DbgPrintEx(
  357. DPFLTR_SXS_ID,
  358. DPFLTR_ERROR_LEVEL,
  359. "SXS: Assembly directory name stored in assembly information too long (%lu bytes) - ACTIVATION_CONTEXT_DATA at %p\n", AssemblyInformation->AssemblyDirectoryNameLength, Data);
  360. Status = STATUS_NAME_TOO_LONG;
  361. goto Exit;
  362. }
  363. // The root assembly may just be in the raw filesystem, in which case we want to resolve the path to be the
  364. // directory containing the application.
  365. if (AssemblyInformation->Flags & ACTIVATION_CONTEXT_DATA_ASSEMBLY_INFORMATION_PRIVATE_ASSEMBLY)
  366. {
  367. WCHAR * p = NULL;
  368. WCHAR * pManifestPath = NULL;
  369. USHORT ManifestPathLength;
  370. //now, we have AssemblyInformation in hand, get the manifest path
  371. ResolvedPathUsed = &ResolvedPath;
  372. pManifestPath = (PWSTR)((ULONG_PTR)AssemblyInformationSectionBase + AssemblyInformation->ManifestPathOffset);
  373. if ( !pManifestPath) {
  374. Status = STATUS_INTERNAL_ERROR;
  375. goto Exit;
  376. }
  377. p = wcsrchr(pManifestPath, L'\\');
  378. if (!p) {
  379. Status = STATUS_INTERNAL_ERROR;
  380. goto Exit;
  381. }
  382. ManifestPathLength = (USHORT)((p - pManifestPath + 1) * sizeof(WCHAR)); // additional 1 WCHAR for "\"
  383. ManifestPathLength += sizeof(WCHAR); // for trailing NULL
  384. if (ManifestPathLength > sizeof(ResolvedPathBuffer)) {
  385. if (ManifestPathLength > UNICODE_STRING_MAX_BYTES) {
  386. Status = STATUS_NAME_TOO_LONG;
  387. goto Exit;
  388. }
  389. ResolvedDynamicPath.MaximumLength = (USHORT) (ManifestPathLength);
  390. ResolvedDynamicPath.Buffer = (RtlAllocateStringRoutine)(ResolvedDynamicPath.MaximumLength);
  391. if (ResolvedDynamicPath.Buffer == NULL) {
  392. Status = STATUS_NO_MEMORY;
  393. goto Exit;
  394. }
  395. ResolvedPathUsed = &ResolvedDynamicPath;
  396. }
  397. RtlCopyMemory(
  398. ResolvedPathUsed->Buffer,
  399. (PVOID)(pManifestPath),
  400. ManifestPathLength-sizeof(WCHAR));
  401. ResolvedPathUsed->Buffer[ManifestPathLength / sizeof(WCHAR) - 1] = L'\0';
  402. ResolvedPathUsed->Length = (USHORT)ManifestPathLength-sizeof(WCHAR);
  403. } else if ((AssemblyInformation->Flags & ACTIVATION_CONTEXT_DATA_ASSEMBLY_INFORMATION_ROOT_ASSEMBLY) &&
  404. (AssemblyInformation->AssemblyDirectoryNameLength == 0)) {
  405. // Get the image directory for the process
  406. PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NtCurrentPeb()->ProcessParameters;
  407. // We don't need to image name, just the length up to the last slash.
  408. PWSTR pszCursor;
  409. USHORT cbOriginalLength;
  410. USHORT cbLeft;
  411. USHORT cbIncludingSlash;
  412. ASSERT(ProcessParameters != NULL);
  413. if (ProcessParameters == NULL) {
  414. Status = STATUS_INTERNAL_ERROR;
  415. goto Exit;
  416. }
  417. // We don't need to image name, just the length up to the last slash.
  418. pszCursor = ProcessParameters->ImagePathName.Buffer;
  419. cbOriginalLength = ProcessParameters->ImagePathName.Length;
  420. cbLeft = cbOriginalLength;
  421. cbIncludingSlash = 0;
  422. while (cbLeft != 0) {
  423. const WCHAR wch = *pszCursor++;
  424. cbLeft -= sizeof(WCHAR);
  425. if (IS_PATH_SEPARATOR(wch)) {
  426. cbIncludingSlash = cbOriginalLength - cbLeft;
  427. }
  428. }
  429. ResolvedPathUsed = &ResolvedPath;
  430. if ((cbIncludingSlash + sizeof(WCHAR)) > sizeof(ResolvedPathBuffer)) {
  431. if ((cbIncludingSlash + sizeof(WCHAR)) > UNICODE_STRING_MAX_BYTES) {
  432. Status = STATUS_NAME_TOO_LONG;
  433. goto Exit;
  434. }
  435. ResolvedDynamicPath.MaximumLength = (USHORT) (cbIncludingSlash + sizeof(WCHAR));
  436. ResolvedDynamicPath.Buffer = (RtlAllocateStringRoutine)(ResolvedDynamicPath.MaximumLength);
  437. if (ResolvedDynamicPath.Buffer == NULL) {
  438. Status = STATUS_NO_MEMORY;
  439. goto Exit;
  440. }
  441. ResolvedPathUsed = &ResolvedDynamicPath;
  442. }
  443. RtlCopyMemory(
  444. ResolvedPathUsed->Buffer,
  445. ProcessParameters->ImagePathName.Buffer,
  446. cbIncludingSlash);
  447. ResolvedPathUsed->Buffer[cbIncludingSlash / sizeof(WCHAR)] = L'\0';
  448. ResolvedPathUsed->Length = cbIncludingSlash;
  449. } else {
  450. // If the resolution is not to the root assembly path, we need to make our callbacks.
  451. ResolvedPathUsed = NULL;
  452. AssemblyDirectory.Length = (USHORT) AssemblyInformation->AssemblyDirectoryNameLength;
  453. AssemblyDirectory.MaximumLength = AssemblyDirectory.Length;
  454. AssemblyDirectory.Buffer = (PWSTR) (((ULONG_PTR) AssemblyInformationSectionBase) + AssemblyInformation->AssemblyDirectoryNameOffset);
  455. // Get ready to fire the resolution beginning event...
  456. CallbackData.ResolutionBeginning.Data = Data;
  457. CallbackData.ResolutionBeginning.AssemblyRosterIndex = AssemblyRosterIndex;
  458. CallbackData.ResolutionBeginning.ResolutionContext = NULL;
  459. CallbackData.ResolutionBeginning.Root.Length = 0;
  460. CallbackData.ResolutionBeginning.Root.MaximumLength = sizeof(QueryPathBuffer);
  461. CallbackData.ResolutionBeginning.Root.Buffer = QueryPathBuffer;
  462. CallbackData.ResolutionBeginning.KnownRoot = FALSE;
  463. CallbackData.ResolutionBeginning.CancelResolution = FALSE;
  464. CallbackData.ResolutionBeginning.RootCount = 0;
  465. (*Callback)(
  466. ASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_REASON_RESOLUTION_BEGINNING,
  467. &CallbackData,
  468. CallbackContext);
  469. if (CallbackData.ResolutionBeginning.CancelResolution) {
  470. Status = STATUS_CANCELLED;
  471. goto Exit;
  472. }
  473. // If that was enough, then register it and we're outta here...
  474. if (CallbackData.ResolutionBeginning.KnownRoot) {
  475. DbgPrintEx(
  476. DPFLTR_SXS_ID,
  477. DPFLTR_TRACE_LEVEL,
  478. "SXS: Storage resolution callback said that this is a well known storage root\n");
  479. // See if it's there...
  480. Status = RtlpProbeAssemblyStorageRootForAssembly(
  481. 0,
  482. &CallbackData.ResolutionBeginning.Root,
  483. &AssemblyDirectory,
  484. &ResolvedPath,
  485. &ResolvedDynamicPath,
  486. &ResolvedPathUsed,
  487. &OpenDirectoryHandle);
  488. if (!NT_SUCCESS(Status)) {
  489. DbgPrintEx(
  490. DPFLTR_SXS_ID,
  491. DPFLTR_ERROR_LEVEL,
  492. "SXS: Attempt to probe known root of assembly storage (\"%wZ\") failed; Status = 0x%08lx\n", &CallbackData.ResolutionBeginning.Root, Status);
  493. goto Exit;
  494. }
  495. Status = RtlpInsertAssemblyStorageMapEntry(
  496. Map,
  497. AssemblyRosterIndex,
  498. &CallbackData.ResolutionBeginning.Root,
  499. &OpenDirectoryHandle);
  500. if (!NT_SUCCESS(Status)) {
  501. DbgPrintEx(
  502. DPFLTR_SXS_ID,
  503. DPFLTR_ERROR_LEVEL,
  504. "SXS: Attempt to insert well known storage root into assembly storage map assembly roster index %lu failed; Status = 0x%08lx\n", AssemblyRosterIndex, Status);
  505. goto Exit;
  506. }
  507. Status = STATUS_SUCCESS;
  508. goto Exit;
  509. }
  510. // Otherwise, begin the grind...
  511. ResolutionContext = CallbackData.ResolutionBeginning.ResolutionContext;
  512. RootCount = CallbackData.ResolutionBeginning.RootCount;
  513. DbgPrintEx(
  514. DPFLTR_SXS_ID,
  515. DPFLTR_TRACE_LEVEL,
  516. "SXS: Assembly storage resolution trying %Id roots (-1 is ok)\n", (SSIZE_T/*from SIZE_T*/)RootCount);
  517. ResolutionContextValid = TRUE;
  518. for (CurrentRootIndex = 0; CurrentRootIndex < RootCount; CurrentRootIndex++) {
  519. CallbackData.GetRoot.ResolutionContext = ResolutionContext;
  520. CallbackData.GetRoot.RootIndex = CurrentRootIndex;
  521. CallbackData.GetRoot.Root.Length = 0;
  522. CallbackData.GetRoot.Root.MaximumLength = sizeof(QueryPathBuffer);
  523. CallbackData.GetRoot.Root.Buffer = QueryPathBuffer;
  524. CallbackData.GetRoot.CancelResolution = FALSE;
  525. CallbackData.GetRoot.NoMoreEntries = FALSE;
  526. (*Callback)(
  527. ASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_REASON_GET_ROOT,
  528. &CallbackData,
  529. CallbackContext);
  530. if (CallbackData.GetRoot.CancelResolution) {
  531. DbgPrintEx(
  532. DPFLTR_SXS_ID,
  533. DPFLTR_TRACE_LEVEL,
  534. "SXS: Callback routine cancelled storage root resolution on root number %Iu\n", CurrentRootIndex);
  535. Status = STATUS_CANCELLED;
  536. goto Exit;
  537. }
  538. if (CallbackData.GetRoot.NoMoreEntries) {
  539. if (CallbackData.GetRoot.Root.Length == 0) {
  540. DbgPrintEx(
  541. DPFLTR_SXS_ID,
  542. DPFLTR_TRACE_LEVEL,
  543. "SXS: Storage resolution finished because callback indicated no more entries on root number %Iu\n", CurrentRootIndex);
  544. // we're done...
  545. RootCount = CurrentRootIndex;
  546. break;
  547. }
  548. DbgPrintEx(
  549. DPFLTR_SXS_ID,
  550. DPFLTR_TRACE_LEVEL,
  551. "SXS: Storage resolution callback has indicated that this is the last root to process: number %Iu\n", CurrentRootIndex);
  552. RootCount = CurrentRootIndex + 1;
  553. }
  554. // Allow the caller to skip this index.
  555. if (CallbackData.GetRoot.Root.Length == 0) {
  556. DbgPrintEx(
  557. DPFLTR_SXS_ID,
  558. DPFLTR_TRACE_LEVEL,
  559. "SXS: Storage resolution for root number %lu returned blank root; skipping probing logic and moving to next.\n", CurrentRootIndex);
  560. continue;
  561. }
  562. if (OpenDirectoryHandle != NULL) {
  563. RTL_SOFT_VERIFY(NT_SUCCESS(NtClose(OpenDirectoryHandle)));
  564. OpenDirectoryHandle = NULL;
  565. }
  566. DbgPrintEx(
  567. DPFLTR_SXS_ID,
  568. DPFLTR_TRACE_LEVEL,
  569. "SXS: Assembly storage map probing root %wZ for assembly directory %wZ\n", &CallbackData.GetRoot.Root, &AssemblyDirectory);
  570. // See if it's there...
  571. Status = RtlpProbeAssemblyStorageRootForAssembly(
  572. 0,
  573. &CallbackData.GetRoot.Root,
  574. &AssemblyDirectory,
  575. &ResolvedPath,
  576. &ResolvedDynamicPath,
  577. &ResolvedPathUsed,
  578. &OpenDirectoryHandle);
  579. // If we got it, leave the loop.
  580. if (NT_SUCCESS(Status)) {
  581. DbgPrintEx(
  582. DPFLTR_SXS_ID,
  583. DPFLTR_TRACE_LEVEL,
  584. "SXS: Found good storage root for %wZ at index %Iu\n", &AssemblyDirectory, CurrentRootIndex);
  585. break;
  586. }
  587. if (Status != STATUS_SXS_ASSEMBLY_NOT_FOUND) {
  588. DbgPrintEx(
  589. DPFLTR_SXS_ID,
  590. DPFLTR_ERROR_LEVEL,
  591. "SXS: Attempt to probe assembly storage root %wZ for assembly directory %wZ failed with status = 0x%08lx\n", &CallbackData.GetRoot.Root, &AssemblyDirectory, Status);
  592. goto Exit;
  593. }
  594. }
  595. if (CurrentRootIndex == RootCount) {
  596. DbgPrintEx(
  597. DPFLTR_SXS_ID,
  598. DPFLTR_ERROR_LEVEL,
  599. "SXS: Unable to resolve storage root for assembly directory %wZ in %Iu tries\n", &AssemblyDirectory, CurrentRootIndex);
  600. Status = STATUS_SXS_ASSEMBLY_NOT_FOUND;
  601. goto Exit;
  602. }
  603. }
  604. //
  605. // sometimes at this point probing has simultaneously opened the directory,
  606. // sometimes it has not.
  607. //
  608. if (OpenDirectoryHandle == NULL) {
  609. //create Handle for this directory
  610. if (!RtlDosPathNameToNtPathName_U(
  611. ResolvedPathUsed->Buffer,
  612. &FileName,
  613. NULL,
  614. &RelativeName
  615. ))
  616. {
  617. DbgPrintEx(
  618. DPFLTR_SXS_ID,
  619. DPFLTR_ERROR_LEVEL,
  620. "SXS: Attempt to translate DOS path name \"%S\" to NT format failed\n", ResolvedPathUsed->Buffer);
  621. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  622. goto Exit;
  623. }
  624. FreeBuffer = FileName.Buffer;
  625. if (RelativeName.RelativeName.Length != 0)
  626. {
  627. FileName = *((PUNICODE_STRING) &RelativeName.RelativeName);
  628. } else
  629. {
  630. RelativeName.ContainingDirectory = NULL;
  631. }
  632. InitializeObjectAttributes(
  633. &Obja,
  634. &FileName,
  635. OBJ_CASE_INSENSITIVE,
  636. RelativeName.ContainingDirectory,
  637. NULL
  638. );
  639. // Open the directory to prevent deletion, just like set current working directory does...
  640. Status = NtOpenFile(
  641. &OpenDirectoryHandle,
  642. FILE_TRAVERSE | SYNCHRONIZE,
  643. &Obja,
  644. &IoStatusBlock,
  645. FILE_SHARE_READ | FILE_SHARE_WRITE,
  646. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
  647. );
  648. if (!NT_SUCCESS(Status))
  649. {
  650. //
  651. // Don't map this to like SXS_blah_NOT_FOUND, because
  652. // probing says this is definitely where we expect to get stuff.
  653. //
  654. DbgPrintEx(
  655. DPFLTR_SXS_ID,
  656. DPFLTR_ERROR_LEVEL,
  657. "SXS: Unable to open assembly directory under storage root \"%S\"; Status = 0x%08lx\n", ResolvedPathUsed->Buffer, Status);
  658. goto Exit;
  659. } else
  660. {
  661. DbgPrintEx(
  662. DPFLTR_SXS_ID,
  663. DPFLTR_TRACE_LEVEL,
  664. "SXS: It is resolved!!!, GOOD");
  665. }
  666. }
  667. // Hey, we made it. Add us to the list!
  668. Status = RtlpInsertAssemblyStorageMapEntry(
  669. Map,
  670. AssemblyRosterIndex,
  671. ResolvedPathUsed,
  672. &OpenDirectoryHandle);
  673. if (!NT_SUCCESS(Status)) {
  674. DbgPrintEx(
  675. DPFLTR_SXS_ID,
  676. DPFLTR_ERROR_LEVEL,
  677. "SXS: Storage resolution failed to insert entry to storage map; Status = 0x%08lx\n", Status);
  678. goto Exit;
  679. }
  680. Status = STATUS_SUCCESS;
  681. Exit:
  682. DbgPrintFunctionExit(__FUNCTION__, Status);
  683. // Let the caller run down their context...
  684. if (ResolutionContextValid) {
  685. CallbackData.ResolutionEnding.ResolutionContext = ResolutionContext;
  686. (*Callback)(
  687. ASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_REASON_RESOLUTION_ENDING,
  688. &CallbackData,
  689. CallbackContext);
  690. }
  691. if (ResolvedDynamicPath.Buffer != NULL) {
  692. (RtlFreeStringRoutine)(ResolvedDynamicPath.Buffer);
  693. }
  694. //
  695. // RtlpInsertAssemblyStorageMapEntry gives ownership to the storage map, and
  696. // NULLs out our local, when successful.
  697. //
  698. if (OpenDirectoryHandle != NULL) {
  699. RTL_SOFT_VERIFY(NT_SUCCESS(NtClose(OpenDirectoryHandle)));
  700. }
  701. if (FreeBuffer != NULL) {
  702. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  703. }
  704. return Status;
  705. }
  706. NTSTATUS
  707. RtlpProbeAssemblyStorageRootForAssembly(
  708. ULONG Flags,
  709. PCUNICODE_STRING Root,
  710. PCUNICODE_STRING AssemblyDirectory,
  711. PUNICODE_STRING PreAllocatedString,
  712. PUNICODE_STRING DynamicString,
  713. PUNICODE_STRING *StringUsed,
  714. HANDLE *OpenDirectoryHandle
  715. )
  716. {
  717. NTSTATUS Status = STATUS_SUCCESS;
  718. WCHAR Buffer[DOS_MAX_PATH_LENGTH];
  719. UNICODE_STRING String = {0};
  720. SIZE_T TotalLength;
  721. BOOLEAN SeparatorNeededAfterRoot = FALSE;
  722. PWSTR Cursor;
  723. OBJECT_ATTRIBUTES Obja;
  724. IO_STATUS_BLOCK IoStatusBlock;
  725. UNICODE_STRING FileName = {0};
  726. RTL_RELATIVE_NAME RelativeName;
  727. PWSTR FreeBuffer = NULL;
  728. HANDLE TempDirectoryHandle = NULL;
  729. BOOLEAN fExistDir;
  730. FILE_BASIC_INFORMATION BasicInfo;
  731. DbgPrintFunctionEntry(__FUNCTION__);
  732. if (StringUsed != NULL)
  733. *StringUsed = NULL;
  734. if (OpenDirectoryHandle != NULL)
  735. *OpenDirectoryHandle = NULL;
  736. if ((Flags != 0) ||
  737. (Root == NULL) ||
  738. (AssemblyDirectory == NULL) ||
  739. (PreAllocatedString == NULL) ||
  740. (DynamicString == NULL) ||
  741. (StringUsed == NULL) ||
  742. (OpenDirectoryHandle == NULL)) {
  743. DbgPrintEx(
  744. DPFLTR_SXS_ID,
  745. DPFLTR_ERROR_LEVEL,
  746. "SXS: %s() bad parameters\n"
  747. "SXS: Flags: 0x%lx\n"
  748. // %p is good enough because the checks are only against NULL
  749. "SXS: Root: %p\n"
  750. "SXS: AssemblyDirectory: %p\n"
  751. "SXS: PreAllocatedString: %p\n"
  752. "SXS: DynamicString: %p\n"
  753. "SXS: StringUsed: %p\n"
  754. "SXS: OpenDirectoryHandle: %p\n",
  755. __FUNCTION__,
  756. Flags,
  757. Root,
  758. AssemblyDirectory,
  759. PreAllocatedString,
  760. DynamicString,
  761. StringUsed,
  762. OpenDirectoryHandle
  763. );
  764. Status = STATUS_INVALID_PARAMETER;
  765. goto Exit;
  766. }
  767. TotalLength = Root->Length;
  768. if (Root->Length != 0) {
  769. if (!IS_PATH_SEPARATOR(Root->Buffer[(Root->Length / sizeof(WCHAR)) - 1])) {
  770. SeparatorNeededAfterRoot = TRUE;
  771. TotalLength += sizeof(WCHAR);
  772. }
  773. }
  774. TotalLength += AssemblyDirectory->Length;
  775. // And space for the trailing slash
  776. TotalLength += sizeof(WCHAR);
  777. // And space for a trailing null character because the path functions want one
  778. TotalLength += sizeof(WCHAR);
  779. //
  780. // We do not add in space for the trailing slash so as to not cause a dynamic
  781. // allocation until necessary in the boundary condition. If the name of the
  782. // directory we're probing fits fine in the stack-allocated buffer, we'll do
  783. // the heap allocation if the probe succeeds. Otherwise we'll not bother.
  784. //
  785. // Maybe the relative complexity of the extra "+ sizeof(WCHAR)"s that are
  786. // around aren't worth it, but extra unnecessary heap allocations are my
  787. // hot button.
  788. //
  789. // Check to see if the string, plus a trailing slash that we don't write until
  790. // the end of this function plus the trailing null accounted for above
  791. // fits into a UNICODE_STRING. If not, bail out.
  792. if (TotalLength > UNICODE_STRING_MAX_BYTES) {
  793. DbgPrintEx(
  794. DPFLTR_SXS_ID,
  795. DPFLTR_ERROR_LEVEL,
  796. "SXS: Assembly storage resolution failing probe because combined path length does not fit in an UNICODE_STRING.\n");
  797. Status = STATUS_NAME_TOO_LONG;
  798. goto Exit;
  799. }
  800. if (TotalLength > sizeof(Buffer)) {
  801. String.MaximumLength = (USHORT) TotalLength;
  802. String.Buffer = (RtlAllocateStringRoutine)(String.MaximumLength);
  803. if (String.Buffer == NULL) {
  804. DbgPrintEx(
  805. DPFLTR_SXS_ID,
  806. DPFLTR_ERROR_LEVEL,
  807. "SXS: Assembly storage resolution failing probe because attempt to allocate %u bytes failed.\n", String.MaximumLength);
  808. Status = STATUS_NO_MEMORY;
  809. goto Exit;
  810. }
  811. } else {
  812. String.Buffer = Buffer;
  813. String.MaximumLength = sizeof(Buffer);
  814. }
  815. RtlCopyMemory(
  816. String.Buffer,
  817. Root->Buffer,
  818. Root->Length);
  819. Cursor = (PWSTR) (((ULONG_PTR) String.Buffer) + Root->Length);
  820. if (SeparatorNeededAfterRoot) {
  821. *Cursor++ = L'\\';
  822. }
  823. RtlCopyMemory(
  824. Cursor,
  825. AssemblyDirectory->Buffer,
  826. AssemblyDirectory->Length);
  827. Cursor = (PWSTR) (((ULONG_PTR) Cursor) + AssemblyDirectory->Length);
  828. *Cursor = L'\0';
  829. String.Length =
  830. Root->Length +
  831. (SeparatorNeededAfterRoot ? sizeof(WCHAR) : 0) +
  832. AssemblyDirectory->Length;
  833. if (!RtlDosPathNameToNtPathName_U(
  834. String.Buffer,
  835. &FileName,
  836. NULL,
  837. &RelativeName
  838. )) {
  839. DbgPrintEx(
  840. DPFLTR_SXS_ID,
  841. DPFLTR_ERROR_LEVEL,
  842. "SXS: Attempt to translate DOS path name \"%S\" to NT format failed\n", String.Buffer);
  843. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  844. goto Exit;
  845. }
  846. FreeBuffer = FileName.Buffer;
  847. if (RelativeName.RelativeName.Length != 0) {
  848. FileName = *((PUNICODE_STRING) &RelativeName.RelativeName);
  849. } else {
  850. RelativeName.ContainingDirectory = NULL;
  851. }
  852. InitializeObjectAttributes(
  853. &Obja,
  854. &FileName,
  855. OBJ_CASE_INSENSITIVE,
  856. RelativeName.ContainingDirectory,
  857. NULL
  858. );
  859. // check the existence of directories
  860. Status = NtQueryAttributesFile(
  861. &Obja,
  862. &BasicInfo
  863. );
  864. fExistDir = FALSE;
  865. if ( !NT_SUCCESS(Status) ) {
  866. if ( (Status == STATUS_SHARING_VIOLATION) || (Status == STATUS_ACCESS_DENIED) )
  867. fExistDir = TRUE;
  868. else
  869. fExistDir = FALSE;
  870. }
  871. else
  872. fExistDir = TRUE;
  873. if (! fExistDir) {
  874. if (( Status == STATUS_NO_SUCH_FILE) || Status == STATUS_OBJECT_NAME_NOT_FOUND || Status == STATUS_OBJECT_PATH_NOT_FOUND)
  875. Status = STATUS_SXS_ASSEMBLY_NOT_FOUND;
  876. else
  877. DbgPrintEx(
  878. DPFLTR_SXS_ID,
  879. DPFLTR_ERROR_LEVEL,
  880. "SXS: Unable to open assembly directory under storage root \"%S\"; Status = 0x%08lx\n", String.Buffer, Status);
  881. goto Exit;
  882. }
  883. // Open the directory to prevent deletion, just like set current working directory does...
  884. Status = NtOpenFile(
  885. &TempDirectoryHandle,
  886. FILE_TRAVERSE | SYNCHRONIZE,
  887. &Obja,
  888. &IoStatusBlock,
  889. FILE_SHARE_READ | FILE_SHARE_WRITE,
  890. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
  891. );
  892. if (!NT_SUCCESS(Status)) {
  893. // If we failed, remap no such file to STATUS_SXS_ASSEMBLY_NOT_FOUND.
  894. if (Status == STATUS_NO_SUCH_FILE) {
  895. Status = STATUS_SXS_ASSEMBLY_NOT_FOUND;
  896. } else {
  897. DbgPrintEx(
  898. DPFLTR_SXS_ID,
  899. DPFLTR_ERROR_LEVEL,
  900. "SXS: Unable to open assembly directory under storage root \"%S\"; Status = 0x%08lx\n", String.Buffer, Status);
  901. }
  902. goto Exit;
  903. }
  904. // Hey, we found it!
  905. // add a slash to the path on the way out and we're done!
  906. if (TotalLength <= PreAllocatedString->MaximumLength) {
  907. // The caller's static string is big enough; just use it.
  908. RtlCopyMemory(
  909. PreAllocatedString->Buffer,
  910. String.Buffer,
  911. String.Length);
  912. *StringUsed = PreAllocatedString;
  913. } else {
  914. // If we already have a dynamic string, just give them our pointer.
  915. if (String.Buffer != Buffer) {
  916. DynamicString->Buffer = String.Buffer;
  917. String.Buffer = NULL;
  918. } else {
  919. // Otherwise we do our first allocation on the way out...
  920. DynamicString->Buffer = (RtlAllocateStringRoutine)(TotalLength);
  921. if (DynamicString->Buffer == NULL) {
  922. Status = STATUS_NO_MEMORY;
  923. goto Exit;
  924. }
  925. RtlCopyMemory(
  926. DynamicString->Buffer,
  927. String.Buffer,
  928. String.Length);
  929. }
  930. DynamicString->MaximumLength = (USHORT) TotalLength;
  931. *StringUsed = DynamicString;
  932. }
  933. Cursor = (PWSTR) (((ULONG_PTR) (*StringUsed)->Buffer) + String.Length);
  934. *Cursor++ = L'\\';
  935. *Cursor++ = L'\0';
  936. (*StringUsed)->Length = (USHORT) (String.Length + sizeof(WCHAR)); // aka "TotalLength - sizeof(WCHAR)" but this seemed cleaner
  937. *OpenDirectoryHandle = TempDirectoryHandle;
  938. TempDirectoryHandle = NULL;
  939. Status = STATUS_SUCCESS;
  940. Exit:
  941. DbgPrintFunctionExit(__FUNCTION__, Status);
  942. if (FreeBuffer != NULL) {
  943. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  944. }
  945. if ((String.Buffer != NULL) && (String.Buffer != Buffer)) {
  946. (RtlFreeStringRoutine)(String.Buffer);
  947. }
  948. if (TempDirectoryHandle != NULL) {
  949. RTL_SOFT_VERIFY(NT_SUCCESS(NtClose(TempDirectoryHandle)));
  950. }
  951. return Status;
  952. }
  953. #if 0 /* dead code */
  954. NTSTATUS
  955. NTAPI
  956. RtlResolveAssemblyStorageMapEntry(
  957. IN ULONG Flags,
  958. IN PACTIVATION_CONTEXT ActivationContext,
  959. IN ULONG AssemblyRosterIndex,
  960. IN PASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_ROUTINE Callback,
  961. IN PVOID CallbackContext
  962. )
  963. {
  964. NTSTATUS Status = STATUS_SUCCESS;
  965. PCACTIVATION_CONTEXT_DATA ActivationContextData = NULL;
  966. PASSEMBLY_STORAGE_MAP Map = NULL;
  967. PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRosterHeader = NULL;
  968. PPEB Peb = NtCurrentPeb();
  969. DbgPrintFunctionEntry(__FUNCTION__);
  970. ASSERT_OK_TO_WRITE_PEB();
  971. RTLP_DISALLOW_THE_EMPTY_ACTIVATION_CONTEXT(ActivationContext);
  972. Status = RtlpGetActivationContextDataStorageMapAndRosterHeader(
  973. 0,
  974. Peb,
  975. ActivationContext,
  976. &ActivationContextData,
  977. &Map,
  978. &AssemblyRosterHeader);
  979. if (!NT_SUCCESS(Status))
  980. goto Exit;
  981. if (ActivationContextData == NULL) {
  982. ASSERT(ActivationContext == NULL);
  983. DbgPrintEx(
  984. DPFLTR_SXS_ID,
  985. DPFLTR_ERROR_LEVEL,
  986. "SXS: RtlResolveAssemblyStorageMapEntry() asked to resolve an assembly storage entry when no activation context data is available.\n");
  987. Status = STATUS_INVALID_PARAMETER;
  988. goto Exit;
  989. }
  990. if (AssemblyRosterIndex >= AssemblyRosterHeader->EntryCount) {
  991. DbgPrintEx(
  992. DPFLTR_SXS_ID,
  993. DPFLTR_ERROR_LEVEL,
  994. "SXS: %s() bad parameters: AssemblyRosterIndex 0x%lx >= AssemblyRosterHeader->EntryCount 0x%lx\n",
  995. __FUNCTION__,
  996. AssemblyRosterIndex,
  997. AssemblyRosterHeader->EntryCount
  998. );
  999. Status = STATUS_INVALID_PARAMETER;
  1000. goto Exit;
  1001. }
  1002. Status = RtlpResolveAssemblyStorageMapEntry(Map, ActivationContextData, AssemblyRosterIndex, Callback, CallbackContext);
  1003. if (!NT_SUCCESS(Status))
  1004. goto Exit;
  1005. Status = STATUS_SUCCESS;
  1006. Exit:
  1007. DbgPrintFunctionExit(__FUNCTION__, Status);
  1008. return Status;
  1009. }
  1010. #endif /* dead code */
  1011. NTSTATUS
  1012. NTAPI
  1013. RtlGetAssemblyStorageRoot(
  1014. IN ULONG Flags,
  1015. IN PACTIVATION_CONTEXT ActivationContext,
  1016. IN ULONG AssemblyRosterIndex,
  1017. OUT PCUNICODE_STRING *AssemblyStorageRoot,
  1018. IN PASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_ROUTINE Callback,
  1019. IN PVOID CallbackContext
  1020. )
  1021. {
  1022. NTSTATUS Status = STATUS_SUCCESS;
  1023. PCACTIVATION_CONTEXT_DATA ActivationContextData = NULL;
  1024. PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRosterHeader = NULL;
  1025. PASSEMBLY_STORAGE_MAP AssemblyStorageMap = NULL;
  1026. const PPEB Peb = NtCurrentPeb();
  1027. DbgPrintFunctionEntry(__FUNCTION__);
  1028. ASSERT_OK_TO_WRITE_PEB();
  1029. RTLP_DISALLOW_THE_EMPTY_ACTIVATION_CONTEXT(ActivationContext);
  1030. if (AssemblyStorageRoot != NULL) {
  1031. *AssemblyStorageRoot = NULL;
  1032. }
  1033. if ((Flags & ~(RTL_GET_ASSEMBLY_STORAGE_ROOT_FLAG_ACTIVATION_CONTEXT_USE_PROCESS_DEFAULT
  1034. | RTL_GET_ASSEMBLY_STORAGE_ROOT_FLAG_ACTIVATION_CONTEXT_USE_SYSTEM_DEFAULT))
  1035. ||
  1036. (AssemblyRosterIndex < 1) ||
  1037. (AssemblyStorageRoot == NULL) ||
  1038. (Callback == NULL)) {
  1039. DbgPrintEx(
  1040. DPFLTR_SXS_ID,
  1041. DPFLTR_ERROR_LEVEL,
  1042. "SXS: %s() bad parameters:\n"
  1043. "SXS: Flags : 0x%lx\n"
  1044. "SXS: AssemblyRosterIndex: 0x%lx\n"
  1045. "SXS: AssemblyStorageRoot: %p\n"
  1046. "SXS: Callback : %p\n",
  1047. __FUNCTION__,
  1048. Flags,
  1049. AssemblyRosterIndex,
  1050. AssemblyStorageRoot,
  1051. Callback
  1052. );
  1053. Status = STATUS_INVALID_PARAMETER;
  1054. goto Exit;
  1055. }
  1056. // Simple implementation: just resolve it and if it resolves OK, return the string in the
  1057. // storage map.
  1058. Status =
  1059. RtlpGetActivationContextDataStorageMapAndRosterHeader(
  1060. ((Flags & RTL_GET_ASSEMBLY_STORAGE_ROOT_FLAG_ACTIVATION_CONTEXT_USE_PROCESS_DEFAULT)
  1061. ? RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_PROCESS_DEFAULT
  1062. : 0)
  1063. | ((Flags & RTL_GET_ASSEMBLY_STORAGE_ROOT_FLAG_ACTIVATION_CONTEXT_USE_SYSTEM_DEFAULT)
  1064. ? RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_SYSTEM_DEFAULT
  1065. : 0),
  1066. Peb,
  1067. ActivationContext,
  1068. &ActivationContextData,
  1069. &AssemblyStorageMap,
  1070. &AssemblyRosterHeader
  1071. );
  1072. if (!NT_SUCCESS(Status)) {
  1073. DbgPrintEx(
  1074. DPFLTR_SXS_ID,
  1075. DPFLTR_ERROR_LEVEL,
  1076. "SXS: RtlGetAssemblyStorageRoot() unable to get activation context data, storage map and assembly roster header. Status = 0x%08lx\n", Status);
  1077. goto Exit;
  1078. }
  1079. // It's possible that there wasn't anything...
  1080. if (ActivationContextData != NULL) {
  1081. ASSERT(AssemblyRosterHeader != NULL);
  1082. ASSERT(AssemblyStorageMap != NULL);
  1083. if ((AssemblyRosterHeader == NULL) || (AssemblyStorageMap == NULL)) {
  1084. Status = STATUS_INTERNAL_ERROR;
  1085. goto Exit;
  1086. }
  1087. if (AssemblyRosterIndex >= AssemblyRosterHeader->EntryCount) {
  1088. DbgPrintEx(
  1089. DPFLTR_SXS_ID,
  1090. DPFLTR_ERROR_LEVEL,
  1091. "SXS: %s() bad parameters AssemblyRosterIndex 0x%lx "
  1092. ">= AssemblyRosterHeader->EntryCount: 0x%lx\n",
  1093. __FUNCTION__,
  1094. AssemblyRosterIndex,
  1095. AssemblyRosterHeader->EntryCount
  1096. );
  1097. Status = STATUS_INVALID_PARAMETER;
  1098. goto Exit;
  1099. }
  1100. Status = RtlpResolveAssemblyStorageMapEntry(AssemblyStorageMap, ActivationContextData, AssemblyRosterIndex, Callback, CallbackContext);
  1101. if (!NT_SUCCESS(Status)) {
  1102. DbgPrintEx(
  1103. DPFLTR_SXS_ID,
  1104. DPFLTR_ERROR_LEVEL,
  1105. "SXS: RtlGetAssemblyStorageRoot() unable to resolve storage map entry. Status = 0x%08lx\n", Status);
  1106. goto Exit;
  1107. }
  1108. // I guess we're done!
  1109. ASSERT(AssemblyStorageMap->AssemblyArray[AssemblyRosterIndex] != NULL);
  1110. if (AssemblyStorageMap->AssemblyArray[AssemblyRosterIndex] == NULL) {
  1111. Status = STATUS_INTERNAL_ERROR;
  1112. goto Exit;
  1113. }
  1114. *AssemblyStorageRoot = &AssemblyStorageMap->AssemblyArray[AssemblyRosterIndex]->DosPath;
  1115. }
  1116. Status = STATUS_SUCCESS;
  1117. Exit:
  1118. DbgPrintFunctionExit(__FUNCTION__, Status);
  1119. return Status;
  1120. }
  1121. NTSTATUS
  1122. RtlpGetActivationContextDataStorageMapAndRosterHeader(
  1123. ULONG Flags,
  1124. PPEB Peb,
  1125. PACTIVATION_CONTEXT ActivationContext,
  1126. PCACTIVATION_CONTEXT_DATA *ActivationContextData,
  1127. PASSEMBLY_STORAGE_MAP *AssemblyStorageMap,
  1128. PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER *AssemblyRosterHeader
  1129. )
  1130. {
  1131. NTSTATUS Status = STATUS_SUCCESS;
  1132. PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER TempAssemblyRosterHeader = NULL;
  1133. PCACTIVATION_CONTEXT_DATA* TempActivationContextData = NULL;
  1134. PASSEMBLY_STORAGE_MAP* TempAssemblyStorageMap = NULL;
  1135. WCHAR LocalAssemblyDirectoryBuffer[DOS_MAX_PATH_LENGTH];
  1136. UNICODE_STRING LocalAssemblyDirectory = {0};
  1137. DbgPrintFunctionEntry(__FUNCTION__);
  1138. LocalAssemblyDirectoryBuffer[0] = 0;
  1139. LocalAssemblyDirectory.Length = 0;
  1140. LocalAssemblyDirectory.MaximumLength = sizeof(WCHAR);
  1141. LocalAssemblyDirectory.Buffer = LocalAssemblyDirectoryBuffer;
  1142. ASSERT(Peb != NULL);
  1143. RTLP_DISALLOW_THE_EMPTY_ACTIVATION_CONTEXT(ActivationContext);
  1144. if (ActivationContextData != NULL) {
  1145. *ActivationContextData = NULL;
  1146. }
  1147. if (AssemblyStorageMap != NULL) {
  1148. *AssemblyStorageMap = NULL;
  1149. }
  1150. if (AssemblyRosterHeader != NULL) {
  1151. *AssemblyRosterHeader = NULL;
  1152. }
  1153. if (
  1154. (Flags & ~(RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_PROCESS_DEFAULT
  1155. | RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_SYSTEM_DEFAULT))
  1156. ||
  1157. (Peb == NULL) ||
  1158. (ActivationContextData == NULL) ||
  1159. (AssemblyStorageMap == NULL)) {
  1160. DbgPrintEx(
  1161. DPFLTR_SXS_ID,
  1162. DPFLTR_ERROR_LEVEL,
  1163. "SXS: %s() bad parameters:\n"
  1164. "SXS: Flags : 0x%lx\n"
  1165. "SXS: Peb : %p\n"
  1166. "SXS: ActivationContextData: %p\n"
  1167. "SXS: AssemblyStorageMap : %p\n"
  1168. __FUNCTION__,
  1169. Flags,
  1170. Peb,
  1171. ActivationContextData,
  1172. AssemblyStorageMap
  1173. );
  1174. Status = STATUS_INVALID_PARAMETER;
  1175. goto Exit;
  1176. }
  1177. if (ActivationContext == ACTCTX_PROCESS_DEFAULT
  1178. || ActivationContext == ACTCTX_SYSTEM_DEFAULT
  1179. || (Flags & (
  1180. RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_PROCESS_DEFAULT
  1181. | RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_SYSTEM_DEFAULT))) {
  1182. //
  1183. // NOTE the ambiguity here. Maybe we'll clean this up.
  1184. //
  1185. // The flags override.
  1186. // ActivationContext == ACTCTX_PROCESS_DEFAULT could still be system default.
  1187. //
  1188. if (ActivationContext == ACTCTX_SYSTEM_DEFAULT
  1189. || (Flags & RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_SYSTEM_DEFAULT)
  1190. ) {
  1191. TempActivationContextData = (PACTIVATION_CONTEXT_DATA*)(&Peb->SystemDefaultActivationContextData);
  1192. TempAssemblyStorageMap = (PASSEMBLY_STORAGE_MAP*)(&Peb->SystemAssemblyStorageMap);
  1193. if (*TempActivationContextData != NULL) {
  1194. TempAssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) *TempActivationContextData) + (*TempActivationContextData)->AssemblyRosterOffset);
  1195. }
  1196. }
  1197. else if (ActivationContext == ACTCTX_PROCESS_DEFAULT || (Flags & RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_PROCESS_DEFAULT)) {
  1198. TempActivationContextData = (PACTIVATION_CONTEXT_DATA*)(&Peb->ActivationContextData);
  1199. TempAssemblyStorageMap = (PASSEMBLY_STORAGE_MAP*)(&Peb->ProcessAssemblyStorageMap);
  1200. if (*TempActivationContextData != NULL) {
  1201. TempAssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) *TempActivationContextData) + (*TempActivationContextData)->AssemblyRosterOffset);
  1202. if (*TempAssemblyStorageMap == NULL) {
  1203. UNICODE_STRING ImagePathName;
  1204. // Capture the image path name so that we don't overrun allocated buffers because someone's
  1205. // randomly tweaking the RTL_USER_PROCESS_PARAMETERS.
  1206. ImagePathName = Peb->ProcessParameters->ImagePathName;
  1207. // The process default local assembly directory is the image name plus ".local".
  1208. // The process default private assembly directory is the image path.
  1209. if ((ImagePathName.Length + sizeof(LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX)) > sizeof(LocalAssemblyDirectoryBuffer)) {
  1210. if ((ImagePathName.Length + sizeof(LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX)) > UNICODE_STRING_MAX_BYTES) {
  1211. Status = STATUS_NAME_TOO_LONG;
  1212. goto Exit;
  1213. }
  1214. LocalAssemblyDirectory.MaximumLength = (USHORT) (ImagePathName.Length + sizeof(LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX));
  1215. LocalAssemblyDirectory.Buffer = (RtlAllocateStringRoutine)(LocalAssemblyDirectory.MaximumLength);
  1216. if (LocalAssemblyDirectory.Buffer == NULL) {
  1217. Status = STATUS_NO_MEMORY;
  1218. goto Exit;
  1219. }
  1220. } else {
  1221. LocalAssemblyDirectory.MaximumLength = sizeof(LocalAssemblyDirectoryBuffer);
  1222. LocalAssemblyDirectory.Buffer = LocalAssemblyDirectoryBuffer;
  1223. }
  1224. RtlCopyMemory(
  1225. LocalAssemblyDirectory.Buffer,
  1226. ImagePathName.Buffer,
  1227. ImagePathName.Length);
  1228. RtlCopyMemory(
  1229. &LocalAssemblyDirectory.Buffer[ImagePathName.Length / sizeof(WCHAR)],
  1230. LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX,
  1231. sizeof(LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX));
  1232. LocalAssemblyDirectory.Length = ImagePathName.Length + sizeof(LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX) - sizeof(WCHAR);
  1233. if (!NT_SUCCESS(Status))
  1234. goto Exit;
  1235. }
  1236. }
  1237. }
  1238. if (*TempActivationContextData != NULL) {
  1239. if (*TempAssemblyStorageMap == NULL) {
  1240. PASSEMBLY_STORAGE_MAP Map = (PASSEMBLY_STORAGE_MAP) RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(ASSEMBLY_STORAGE_MAP) + (TempAssemblyRosterHeader->EntryCount * sizeof(PASSEMBLY_STORAGE_MAP_ENTRY)));
  1241. if (Map == NULL) {
  1242. Status = STATUS_NO_MEMORY;
  1243. goto Exit;
  1244. }
  1245. Status = RtlpInitializeAssemblyStorageMap(Map, TempAssemblyRosterHeader->EntryCount, (PASSEMBLY_STORAGE_MAP_ENTRY *) (Map + 1));
  1246. if (!NT_SUCCESS(Status)) {
  1247. RtlFreeHeap(RtlProcessHeap(), 0, Map);
  1248. goto Exit;
  1249. }
  1250. if (InterlockedCompareExchangePointer(TempAssemblyStorageMap, Map, NULL) != NULL) {
  1251. // We were not the first ones in. Free ours and use the one allocated.
  1252. RtlpUninitializeAssemblyStorageMap(Map);
  1253. RtlFreeHeap(RtlProcessHeap(), 0, Map);
  1254. }
  1255. }
  1256. } else {
  1257. ASSERT(*TempAssemblyStorageMap == NULL);
  1258. }
  1259. *AssemblyStorageMap = (PASSEMBLY_STORAGE_MAP) *TempAssemblyStorageMap;
  1260. } else {
  1261. TempActivationContextData = (PACTIVATION_CONTEXT_DATA*)(&ActivationContext->ActivationContextData);
  1262. ASSERT(*TempActivationContextData != NULL);
  1263. if (*TempActivationContextData == NULL) {
  1264. Status = STATUS_INTERNAL_ERROR;
  1265. goto Exit;
  1266. }
  1267. TempAssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) *TempActivationContextData) + (*TempActivationContextData)->AssemblyRosterOffset);
  1268. *AssemblyStorageMap = &ActivationContext->StorageMap;
  1269. }
  1270. if (ActivationContextData != NULL)
  1271. *ActivationContextData = *TempActivationContextData;
  1272. if (AssemblyRosterHeader != NULL)
  1273. *AssemblyRosterHeader = TempAssemblyRosterHeader;
  1274. Status = STATUS_SUCCESS;
  1275. Exit:
  1276. DbgPrintFunctionExit(__FUNCTION__, Status);
  1277. if ((LocalAssemblyDirectory.Buffer != NULL) &&
  1278. (LocalAssemblyDirectory.Buffer != LocalAssemblyDirectoryBuffer)) {
  1279. RtlFreeUnicodeString(&LocalAssemblyDirectory);
  1280. }
  1281. return Status;
  1282. }