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.

1531 lines
53 KiB

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