windows-nt/Source/XPSP1/NT/base/ntdll/sxsstoragemap.c

1523 lines
51 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
sxsstorage.c
Abstract:
Side-by-side activation support for Windows/NT
Implementation of the assembly storage map.
Author:
Michael Grier (MGrier) 6/13/2000
Revision History:
Xiaoyu Wu(xiaoyuw) 7/01/2000 .local directory
Xiaoyu Wu(xiaoyuw) 8/04/2000 private assembly
Jay Krell (a-JayK) October 2000 the little bit of system default context that wasn't already done
--*/
#pragma warning(disable:4214) // bit field types other than int
#pragma warning(disable:4201) // nameless struct/union
#pragma warning(disable:4115) // named type definition in parentheses
#pragma warning(disable:4127) // condition expression is constant
#include <ntos.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <sxstypes.h>
#include "sxsp.h"
#define IS_PATH_SEPARATOR(_wch) (((_wch) == L'\\') || ((_wch) == L'/'))
#define LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX L".Local"
#if DBG
PCUNICODE_STRING RtlpGetImagePathName(VOID);
#define RtlpGetCurrentProcessId() (HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess))
#define RtlpGetCurrentThreadId() (HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread))
#endif
#if DBG
PCUNICODE_STRING RtlpGetImagePathName(VOID)
{
PPEB Peb = NtCurrentPeb();
return (Peb->ProcessParameters != NULL) ? &Peb->ProcessParameters->ImagePathName : NULL;
}
static VOID
DbgPrintFunctionEntry(
CONST CHAR* Function
)
{
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"SXS: [pid:0x%x, tid:0x%x, %wZ] enter %s%d()\n",
RtlpGetCurrentProcessId(),
RtlpGetCurrentThreadId(),
RtlpGetImagePathName(),
Function,
(int)sizeof(PVOID) * 8
);
}
static VOID
DbgPrintFunctionExit(
CONST CHAR* Function,
NTSTATUS Status
)
{
DbgPrintEx(
DPFLTR_SXS_ID,
NT_SUCCESS(Status) ? DPFLTR_TRACE_LEVEL : DPFLTR_ERROR_LEVEL,
"SXS: [0x%x.%x] %s%d() exiting with status 0x%lx\n",
RtlpGetCurrentProcessId(),
RtlpGetCurrentThreadId(),
Function,
(int)sizeof(PVOID) * 8,
Status
);
}
#else
#define DbgPrintFunctionEntry(function) /* nothing */
#define DbgPrintFunctionExit(function, status) /* nothing */
#endif // DBG
// Because we write to the peb, we must not be in 64bit code for a 32bit process,
// unless we know we are early enough in CreateProcess, which is not the case
// in this file. Also don't call the 32bit version of this in a 64bit process.
#if DBG
#define ASSERT_OK_TO_WRITE_PEB() \
{ \
PVOID Peb32 = NULL; \
NTSTATUS Status; \
\
Status = \
NtQueryInformationProcess( \
NtCurrentProcess(), \
ProcessWow64Information, \
&Peb32, \
sizeof(Peb32), \
NULL); \
/* The other Peb must be The Peb or the other Peb must not exist. */ \
ASSERT(Peb32 == NtCurrentPeb() || Peb32 == NULL); \
}
#else
#define ASSERT_OK_TO_WRITE_PEB() /* nothing */
#endif
NTSTATUS
RtlpInitializeAssemblyStorageMap(
PASSEMBLY_STORAGE_MAP Map,
ULONG EntryCount,
PASSEMBLY_STORAGE_MAP_ENTRY *EntryArray
)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG i;
ULONG Flags = 0;
#if DBG
DbgPrintFunctionEntry(__FUNCTION__);
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"%s(Map:%p, EntryCount:0x%lx)\n",
__FUNCTION__,
Map,
EntryCount
);
ASSERT_OK_TO_WRITE_PEB();
#endif // DBG
if ((Map == NULL) ||
(EntryCount == 0)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: %s() bad parameters:\n"
"SXS: Map : 0x%lx\n"
"SXS: EntryCount : 0x%lx\n"
__FUNCTION__,
Map,
EntryCount
);
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
if (EntryArray == NULL) {
EntryArray = (PASSEMBLY_STORAGE_MAP_ENTRY *) RtlAllocateHeap(RtlProcessHeap(), 0, EntryCount * sizeof(PASSEMBLY_STORAGE_MAP_ENTRY));
if (EntryArray == NULL) {
Status = STATUS_NO_MEMORY;
goto Exit;
}
Flags |= ASSEMBLY_STORAGE_MAP_ASSEMBLY_ARRAY_IS_HEAP_ALLOCATED;
}
for (i=0; i<EntryCount; i++)
EntryArray[i] = NULL;
Map->Flags = Flags;
Map->AssemblyCount = EntryCount;
Map->AssemblyArray = EntryArray;
Status = STATUS_SUCCESS;
Exit:
#if DBG
DbgPrintFunctionExit(__FUNCTION__, Status);
DbgPrintEx(
DPFLTR_SXS_ID,
NT_SUCCESS(Status) ? DPFLTR_TRACE_LEVEL : DPFLTR_ERROR_LEVEL,
"%s(Map:%p, EntryCount:0x%lx) : (Map:%p, Status:0x%lx)\n",
__FUNCTION__,
Map,
EntryCount,
Map,
Status
);
#endif
return Status;
}
VOID
RtlpUninitializeAssemblyStorageMap(
PASSEMBLY_STORAGE_MAP Map
)
{
DbgPrintFunctionEntry(__FUNCTION__);
#if DBG
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"%s(Map:%p)\n",
__FUNCTION__,
Map
);
#endif
if (Map != NULL) {
ULONG i;
for (i=0; i<Map->AssemblyCount; i++) {
PASSEMBLY_STORAGE_MAP_ENTRY Entry = Map->AssemblyArray[i];
if (Entry != NULL) {
Entry->DosPath.Length = 0;
Entry->DosPath.MaximumLength = 0;
Entry->DosPath.Buffer = NULL;
if (Entry->Handle != NULL) {
RTL_SOFT_VERIFY(NT_SUCCESS(NtClose(Entry->Handle)));
Entry->Handle = NULL;
}
Map->AssemblyArray[i] = NULL;
RtlFreeHeap(RtlProcessHeap(), 0, Entry);
}
}
if (Map->Flags & ASSEMBLY_STORAGE_MAP_ASSEMBLY_ARRAY_IS_HEAP_ALLOCATED) {
RtlFreeHeap(RtlProcessHeap(), 0, Map->AssemblyArray);
}
Map->AssemblyArray = NULL;
Map->AssemblyCount = 0;
Map->Flags = 0;
}
}
NTSTATUS
RtlpInsertAssemblyStorageMapEntry(
PASSEMBLY_STORAGE_MAP Map,
ULONG AssemblyRosterIndex,
PCUNICODE_STRING StorageLocation,
HANDLE* OpenDirectoryHandle
)
{
PASSEMBLY_STORAGE_MAP_ENTRY Entry = NULL;
NTSTATUS Status = STATUS_SUCCESS;
ASSERT(Map != NULL);
ASSERT(AssemblyRosterIndex >= 1);
ASSERT((Map != NULL) && (AssemblyRosterIndex < Map->AssemblyCount));
ASSERT(StorageLocation != NULL);
ASSERT((StorageLocation != NULL) && (StorageLocation->Length >= sizeof(WCHAR)));
ASSERT((StorageLocation != NULL) && (StorageLocation->Buffer != NULL));
DbgPrintFunctionEntry(__FUNCTION__);
if ((Map == NULL) ||
(AssemblyRosterIndex < 1) ||
(AssemblyRosterIndex > Map->AssemblyCount) ||
(StorageLocation == NULL) ||
(StorageLocation->Length < sizeof(WCHAR)) ||
(StorageLocation->Buffer == NULL) ||
(OpenDirectoryHandle == NULL)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: %s() bad parameters\n"
"SXS: Map : %p\n"
"SXS: AssemblyRosterIndex : 0x%lx\n"
"SXS: Map->AssemblyCount : 0x%lx\n"
"SXS: StorageLocation : %p\n"
"SXS: StorageLocation->Length: 0x%x\n"
"SXS: StorageLocation->Buffer: %p\n"
"SXS: OpenDirectoryHandle : %p\n",
__FUNCTION__,
Map,
AssemblyRosterIndex,
Map ? Map->AssemblyCount : 0,
StorageLocation,
(StorageLocation != NULL) ? StorageLocation->Length : 0,
(StorageLocation != NULL) ? StorageLocation->Buffer : NULL,
OpenDirectoryHandle
);
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
if ((StorageLocation->Length + sizeof(WCHAR)) > UNICODE_STRING_MAX_BYTES) {
Status = STATUS_NAME_TOO_LONG;
goto Exit;
}
Entry = (PASSEMBLY_STORAGE_MAP_ENTRY) RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(ASSEMBLY_STORAGE_MAP_ENTRY) + StorageLocation->Length + sizeof(WCHAR));
if (Entry == NULL) {
Status = STATUS_NO_MEMORY;
goto Exit;
}
Entry->Flags = 0;
Entry->DosPath.Length = StorageLocation->Length;
Entry->DosPath.Buffer = (PWSTR) (Entry + 1);
Entry->DosPath.MaximumLength = (USHORT) (StorageLocation->Length + sizeof(WCHAR));
RtlCopyMemory(
Entry->DosPath.Buffer,
StorageLocation->Buffer,
StorageLocation->Length);
Entry->DosPath.Buffer[Entry->DosPath.Length / sizeof(WCHAR)] = L'\0';
Entry->Handle = *OpenDirectoryHandle;
// Ok, we're all set. Let's try the big interlocked switcheroo
if (InterlockedCompareExchangePointer(
(PVOID *) &Map->AssemblyArray[AssemblyRosterIndex],
(PVOID) Entry,
(PVOID) NULL) == NULL) {
// If we're the first ones in, avoid cleaning up in the exit path.
Entry = NULL;
*OpenDirectoryHandle = NULL;
}
Status = STATUS_SUCCESS;
Exit:
DbgPrintFunctionExit(__FUNCTION__, Status);
if (Entry != NULL) {
RtlFreeHeap(RtlProcessHeap(), 0, Entry);
}
return Status;
}
NTSTATUS
RtlpResolveAssemblyStorageMapEntry(
PASSEMBLY_STORAGE_MAP Map,
PCACTIVATION_CONTEXT_DATA Data,
ULONG AssemblyRosterIndex,
PASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_ROUTINE Callback,
PVOID CallbackContext
)
{
NTSTATUS Status = STATUS_SUCCESS;
ASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_DATA CallbackData;
PVOID ResolutionContext;
BOOLEAN ResolutionContextValid = FALSE;
UNICODE_STRING AssemblyDirectory;
PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRoster;
PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY AssemblyRosterEntry;
PCACTIVATION_CONTEXT_DATA_ASSEMBLY_INFORMATION AssemblyInformation;
PVOID AssemblyInformationSectionBase;
UNICODE_STRING ResolvedPath;
WCHAR ResolvedPathBuffer[DOS_MAX_PATH_LENGTH];
UNICODE_STRING ResolvedDynamicPath;
PUNICODE_STRING ResolvedPathUsed;
HANDLE OpenDirectoryHandle = NULL;
WCHAR QueryPathBuffer[DOS_MAX_PATH_LENGTH];
UNICODE_STRING FileName;
RTL_RELATIVE_NAME RelativeName;
OBJECT_ATTRIBUTES Obja;
IO_STATUS_BLOCK IoStatusBlock;
SIZE_T RootCount, CurrentRootIndex;
PWSTR FreeBuffer = NULL;
DbgPrintFunctionEntry(__FUNCTION__);
ResolvedPath.Length = 0;
ResolvedPath.MaximumLength = sizeof(ResolvedPathBuffer);
ResolvedPath.Buffer = ResolvedPathBuffer;
ResolvedDynamicPath.Length = 0;
ResolvedDynamicPath.MaximumLength = 0;
ResolvedDynamicPath.Buffer = NULL;
FileName.Length = 0;
FileName.MaximumLength = 0;
FileName.Buffer = NULL;
ResolutionContext = NULL;
// First, let's validate parameters...
if ((Map == NULL) ||
(Data == NULL) ||
(AssemblyRosterIndex < 1) ||
(AssemblyRosterIndex > Map->AssemblyCount)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: %s() bad parameters\n"
"SXS: Map : %p\n"
"SXS: Data : %p\n"
"SXS: AssemblyRosterIndex: 0x%lx\n"
"SXS: Map->AssemblyCount : 0x%lx\n",
__FUNCTION__,
Map,
Data,
AssemblyRosterIndex,
(Map != NULL) ? Map->AssemblyCount : 0
);
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
// Is it already resolved?
if (Map->AssemblyArray[AssemblyRosterIndex] != NULL)
goto Exit;
AssemblyRoster = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) Data) + Data->AssemblyRosterOffset);
AssemblyRosterEntry = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY) (((ULONG_PTR) Data) + AssemblyRoster->FirstEntryOffset + (AssemblyRosterIndex * sizeof(ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY)));
AssemblyInformation = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_INFORMATION) (((ULONG_PTR) Data) + AssemblyRosterEntry->AssemblyInformationOffset);
AssemblyInformationSectionBase = (PVOID) (((ULONG_PTR) Data) + AssemblyRoster->AssemblyInformationSectionOffset);
if (AssemblyInformation->AssemblyDirectoryNameLength > UNICODE_STRING_MAX_BYTES) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: Assembly directory name stored in assembly information too long (%lu bytes) - ACTIVATION_CONTEXT_DATA at %p\n", AssemblyInformation->AssemblyDirectoryNameLength, Data);
Status = STATUS_NAME_TOO_LONG;
goto Exit;
}
// The root assembly may just be in the raw filesystem, in which case we want to resolve the path to be the
// directory containing the application.
if (AssemblyInformation->Flags & ACTIVATION_CONTEXT_DATA_ASSEMBLY_INFORMATION_PRIVATE_ASSEMBLY)
{
WCHAR * p = NULL;
WCHAR * pManifestPath = NULL;
USHORT ManifestPathLength;
//now, we have AssemblyInformation in hand, get the manifest path
ResolvedPathUsed = &ResolvedPath;
pManifestPath = (PWSTR)((ULONG_PTR)AssemblyInformationSectionBase + AssemblyInformation->ManifestPathOffset);
if ( !pManifestPath) {
Status = STATUS_INTERNAL_ERROR;
goto Exit;
}
p = wcsrchr(pManifestPath, L'\\');
if (!p) {
Status = STATUS_INTERNAL_ERROR;
goto Exit;
}
ManifestPathLength = (USHORT)((p - pManifestPath + 1) * sizeof(WCHAR)); // additional 1 WCHAR for "\"
ManifestPathLength += sizeof(WCHAR); // for trailing NULL
if (ManifestPathLength > sizeof(ResolvedPathBuffer)) {
if (ManifestPathLength > UNICODE_STRING_MAX_BYTES) {
Status = STATUS_NAME_TOO_LONG;
goto Exit;
}
ResolvedDynamicPath.MaximumLength = (USHORT) (ManifestPathLength);
ResolvedDynamicPath.Buffer = (RtlAllocateStringRoutine)(ResolvedDynamicPath.MaximumLength);
if (ResolvedDynamicPath.Buffer == NULL) {
Status = STATUS_NO_MEMORY;
goto Exit;
}
ResolvedPathUsed = &ResolvedDynamicPath;
}
RtlCopyMemory(
ResolvedPathUsed->Buffer,
(PVOID)(pManifestPath),
ManifestPathLength-sizeof(WCHAR));
ResolvedPathUsed->Buffer[ManifestPathLength / sizeof(WCHAR) - 1] = L'\0';
ResolvedPathUsed->Length = (USHORT)ManifestPathLength-sizeof(WCHAR);
} else if ((AssemblyInformation->Flags & ACTIVATION_CONTEXT_DATA_ASSEMBLY_INFORMATION_ROOT_ASSEMBLY) &&
(AssemblyInformation->AssemblyDirectoryNameLength == 0)) {
// Get the image directory for the process
PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NtCurrentPeb()->ProcessParameters;
// We don't need to image name, just the length up to the last slash.
PWSTR pszCursor;
USHORT cbOriginalLength;
USHORT cbLeft;
USHORT cbIncludingSlash;
ASSERT(ProcessParameters != NULL);
if (ProcessParameters == NULL) {
Status = STATUS_INTERNAL_ERROR;
goto Exit;
}
// We don't need to image name, just the length up to the last slash.
pszCursor = ProcessParameters->ImagePathName.Buffer;
cbOriginalLength = ProcessParameters->ImagePathName.Length;
cbLeft = cbOriginalLength;
cbIncludingSlash = 0;
while (cbLeft != 0) {
const WCHAR wch = *pszCursor++;
cbLeft -= sizeof(WCHAR);
if (IS_PATH_SEPARATOR(wch)) {
cbIncludingSlash = cbOriginalLength - cbLeft;
}
}
ResolvedPathUsed = &ResolvedPath;
if ((cbIncludingSlash + sizeof(WCHAR)) > sizeof(ResolvedPathBuffer)) {
if ((cbIncludingSlash + sizeof(WCHAR)) > UNICODE_STRING_MAX_BYTES) {
Status = STATUS_NAME_TOO_LONG;
goto Exit;
}
ResolvedDynamicPath.MaximumLength = (USHORT) (cbIncludingSlash + sizeof(WCHAR));
ResolvedDynamicPath.Buffer = (RtlAllocateStringRoutine)(ResolvedDynamicPath.MaximumLength);
if (ResolvedDynamicPath.Buffer == NULL) {
Status = STATUS_NO_MEMORY;
goto Exit;
}
ResolvedPathUsed = &ResolvedDynamicPath;
}
RtlCopyMemory(
ResolvedPathUsed->Buffer,
ProcessParameters->ImagePathName.Buffer,
cbIncludingSlash);
ResolvedPathUsed->Buffer[cbIncludingSlash / sizeof(WCHAR)] = L'\0';
ResolvedPathUsed->Length = cbIncludingSlash;
} else {
// If the resolution is not to the root assembly path, we need to make our callbacks.
ResolvedPathUsed = NULL;
AssemblyDirectory.Length = (USHORT) AssemblyInformation->AssemblyDirectoryNameLength;
AssemblyDirectory.MaximumLength = AssemblyDirectory.Length;
AssemblyDirectory.Buffer = (PWSTR) (((ULONG_PTR) AssemblyInformationSectionBase) + AssemblyInformation->AssemblyDirectoryNameOffset);
// Get ready to fire the resolution beginning event...
CallbackData.ResolutionBeginning.Data = Data;
CallbackData.ResolutionBeginning.AssemblyRosterIndex = AssemblyRosterIndex;
CallbackData.ResolutionBeginning.ResolutionContext = NULL;
CallbackData.ResolutionBeginning.Root.Length = 0;
CallbackData.ResolutionBeginning.Root.MaximumLength = sizeof(QueryPathBuffer);
CallbackData.ResolutionBeginning.Root.Buffer = QueryPathBuffer;
CallbackData.ResolutionBeginning.KnownRoot = FALSE;
CallbackData.ResolutionBeginning.CancelResolution = FALSE;
CallbackData.ResolutionBeginning.RootCount = 0;
(*Callback)(
ASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_REASON_RESOLUTION_BEGINNING,
&CallbackData,
CallbackContext);
if (CallbackData.ResolutionBeginning.CancelResolution) {
Status = STATUS_CANCELLED;
goto Exit;
}
// If that was enough, then register it and we're outta here...
if (CallbackData.ResolutionBeginning.KnownRoot) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"SXS: Storage resolution callback said that this is a well known storage root\n");
// See if it's there...
Status = RtlpProbeAssemblyStorageRootForAssembly(
0,
&CallbackData.ResolutionBeginning.Root,
&AssemblyDirectory,
&ResolvedPath,
&ResolvedDynamicPath,
&ResolvedPathUsed,
&OpenDirectoryHandle);
if (!NT_SUCCESS(Status)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: Attempt to probe known root of assembly storage (\"%wZ\") failed; Status = 0x%08lx\n", &CallbackData.ResolutionBeginning.Root, Status);
goto Exit;
}
Status = RtlpInsertAssemblyStorageMapEntry(
Map,
AssemblyRosterIndex,
&CallbackData.ResolutionBeginning.Root,
&OpenDirectoryHandle);
if (!NT_SUCCESS(Status)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: Attempt to insert well known storage root into assembly storage map assembly roster index %lu failed; Status = 0x%08lx\n", AssemblyRosterIndex, Status);
goto Exit;
}
Status = STATUS_SUCCESS;
goto Exit;
}
// Otherwise, begin the grind...
ResolutionContext = CallbackData.ResolutionBeginning.ResolutionContext;
RootCount = CallbackData.ResolutionBeginning.RootCount;
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"SXS: Assembly storage resolution trying %Id roots (-1 is ok)\n", (SSIZE_T/*from SIZE_T*/)RootCount);
ResolutionContextValid = TRUE;
for (CurrentRootIndex = 0; CurrentRootIndex < RootCount; CurrentRootIndex++) {
CallbackData.GetRoot.ResolutionContext = ResolutionContext;
CallbackData.GetRoot.RootIndex = CurrentRootIndex;
CallbackData.GetRoot.Root.Length = 0;
CallbackData.GetRoot.Root.MaximumLength = sizeof(QueryPathBuffer);
CallbackData.GetRoot.Root.Buffer = QueryPathBuffer;
CallbackData.GetRoot.CancelResolution = FALSE;
CallbackData.GetRoot.NoMoreEntries = FALSE;
(*Callback)(
ASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_REASON_GET_ROOT,
&CallbackData,
CallbackContext);
if (CallbackData.GetRoot.CancelResolution) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"SXS: Callback routine cancelled storage root resolution on root number %Iu\n", CurrentRootIndex);
Status = STATUS_CANCELLED;
goto Exit;
}
if (CallbackData.GetRoot.NoMoreEntries) {
if (CallbackData.GetRoot.Root.Length == 0) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"SXS: Storage resolution finished because callback indicated no more entries on root number %Iu\n", CurrentRootIndex);
// we're done...
RootCount = CurrentRootIndex;
break;
}
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"SXS: Storage resolution callback has indicated that this is the last root to process: number %Iu\n", CurrentRootIndex);
RootCount = CurrentRootIndex + 1;
}
// Allow the caller to skip this index.
if (CallbackData.GetRoot.Root.Length == 0) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"SXS: Storage resolution for root number %lu returned blank root; skipping probing logic and moving to next.\n", CurrentRootIndex);
continue;
}
if (OpenDirectoryHandle != NULL) {
RTL_SOFT_VERIFY(NT_SUCCESS(NtClose(OpenDirectoryHandle)));
OpenDirectoryHandle = NULL;
}
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"SXS: Assembly storage map probing root %wZ for assembly directory %wZ\n", &CallbackData.GetRoot.Root, &AssemblyDirectory);
// See if it's there...
Status = RtlpProbeAssemblyStorageRootForAssembly(
0,
&CallbackData.GetRoot.Root,
&AssemblyDirectory,
&ResolvedPath,
&ResolvedDynamicPath,
&ResolvedPathUsed,
&OpenDirectoryHandle);
// If we got it, leave the loop.
if (NT_SUCCESS(Status)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"SXS: Found good storage root for %wZ at index %Iu\n", &AssemblyDirectory, CurrentRootIndex);
break;
}
if (Status != STATUS_SXS_ASSEMBLY_NOT_FOUND) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: Attempt to probe assembly storage root %wZ for assembly directory %wZ failed with status = 0x%08lx\n", &CallbackData.GetRoot.Root, &AssemblyDirectory, Status);
goto Exit;
}
}
if (CurrentRootIndex == RootCount) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: Unable to resolve storage root for assembly directory %wZ in %Iu tries\n", &AssemblyDirectory, CurrentRootIndex);
Status = STATUS_SXS_ASSEMBLY_NOT_FOUND;
goto Exit;
}
}
//
// sometimes at this point probing has simultaneously opened the directory,
// sometimes it has not.
//
if (OpenDirectoryHandle == NULL) {
//create Handle for this directory
if (!RtlDosPathNameToNtPathName_U(
ResolvedPathUsed->Buffer,
&FileName,
NULL,
&RelativeName
))
{
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: Attempt to translate DOS path name \"%S\" to NT format failed\n", ResolvedPathUsed->Buffer);
Status = STATUS_OBJECT_PATH_NOT_FOUND;
goto Exit;
}
FreeBuffer = FileName.Buffer;
if (RelativeName.RelativeName.Length != 0)
{
FileName = *((PUNICODE_STRING) &RelativeName.RelativeName);
} else
{
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
// Open the directory to prevent deletion, just like set current working directory does...
Status = NtOpenFile(
&OpenDirectoryHandle,
FILE_TRAVERSE | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
);
if (!NT_SUCCESS(Status))
{
//
// Don't map this to like SXS_blah_NOT_FOUND, because
// probing says this is definitely where we expect to get stuff.
//
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: Unable to open assembly directory under storage root \"%S\"; Status = 0x%08lx\n", ResolvedPathUsed->Buffer, Status);
goto Exit;
} else
{
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_TRACE_LEVEL,
"SXS: It is resolved!!!, GOOD");
}
}
// Hey, we made it. Add us to the list!
Status = RtlpInsertAssemblyStorageMapEntry(
Map,
AssemblyRosterIndex,
ResolvedPathUsed,
&OpenDirectoryHandle);
if (!NT_SUCCESS(Status)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: Storage resolution failed to insert entry to storage map; Status = 0x%08lx\n", Status);
goto Exit;
}
Status = STATUS_SUCCESS;
Exit:
DbgPrintFunctionExit(__FUNCTION__, Status);
// Let the caller run down their context...
if (ResolutionContextValid) {
CallbackData.ResolutionEnding.ResolutionContext = ResolutionContext;
(*Callback)(
ASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_REASON_RESOLUTION_ENDING,
&CallbackData,
CallbackContext);
}
if (ResolvedDynamicPath.Buffer != NULL) {
(RtlFreeStringRoutine)(ResolvedDynamicPath.Buffer);
}
//
// RtlpInsertAssemblyStorageMapEntry gives ownership to the storage map, and
// NULLs out our local, when successful.
//
if (OpenDirectoryHandle != NULL) {
RTL_SOFT_VERIFY(NT_SUCCESS(NtClose(OpenDirectoryHandle)));
}
if (FreeBuffer != NULL) {
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
}
return Status;
}
NTSTATUS
RtlpProbeAssemblyStorageRootForAssembly(
ULONG Flags,
PCUNICODE_STRING Root,
PCUNICODE_STRING AssemblyDirectory,
PUNICODE_STRING PreAllocatedString,
PUNICODE_STRING DynamicString,
PUNICODE_STRING *StringUsed,
HANDLE *OpenDirectoryHandle
)
{
NTSTATUS Status = STATUS_SUCCESS;
WCHAR Buffer[DOS_MAX_PATH_LENGTH];
UNICODE_STRING String = {0};
SIZE_T TotalLength;
BOOLEAN SeparatorNeededAfterRoot = FALSE;
PWSTR Cursor;
OBJECT_ATTRIBUTES Obja;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING FileName = {0};
RTL_RELATIVE_NAME RelativeName;
PWSTR FreeBuffer = NULL;
HANDLE TempDirectoryHandle = NULL;
BOOLEAN fExistDir;
FILE_BASIC_INFORMATION BasicInfo;
DbgPrintFunctionEntry(__FUNCTION__);
if (StringUsed != NULL)
*StringUsed = NULL;
if (OpenDirectoryHandle != NULL)
*OpenDirectoryHandle = NULL;
if ((Flags != 0) ||
(Root == NULL) ||
(AssemblyDirectory == NULL) ||
(PreAllocatedString == NULL) ||
(DynamicString == NULL) ||
(StringUsed == NULL) ||
(OpenDirectoryHandle == NULL)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: %s() bad parameters\n"
"SXS: Flags: 0x%lx\n"
// %p is good enough because the checks are only against NULL
"SXS: Root: %p\n"
"SXS: AssemblyDirectory: %p\n"
"SXS: PreAllocatedString: %p\n"
"SXS: DynamicString: %p\n"
"SXS: StringUsed: %p\n"
"SXS: OpenDirectoryHandle: %p\n",
__FUNCTION__,
Flags,
Root,
AssemblyDirectory,
PreAllocatedString,
DynamicString,
StringUsed,
OpenDirectoryHandle
);
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
TotalLength = Root->Length;
if (Root->Length != 0) {
if (!IS_PATH_SEPARATOR(Root->Buffer[(Root->Length / sizeof(WCHAR)) - 1])) {
SeparatorNeededAfterRoot = TRUE;
TotalLength += sizeof(WCHAR);
}
}
TotalLength += AssemblyDirectory->Length;
// And space for the trailing slash
TotalLength += sizeof(WCHAR);
// And space for a trailing null character because the path functions want one
TotalLength += sizeof(WCHAR);
//
// We do not add in space for the trailing slash so as to not cause a dynamic
// allocation until necessary in the boundary condition. If the name of the
// directory we're probing fits fine in the stack-allocated buffer, we'll do
// the heap allocation if the probe succeeds. Otherwise we'll not bother.
//
// Maybe the relative complexity of the extra "+ sizeof(WCHAR)"s that are
// around aren't worth it, but extra unnecessary heap allocations are my
// hot button.
//
// Check to see if the string, plus a trailing slash that we don't write until
// the end of this function plus the trailing null accounted for above
// fits into a UNICODE_STRING. If not, bail out.
if (TotalLength > UNICODE_STRING_MAX_BYTES) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: Assembly storage resolution failing probe because combined path length does not fit in an UNICODE_STRING.\n");
Status = STATUS_NAME_TOO_LONG;
goto Exit;
}
if (TotalLength > sizeof(Buffer)) {
String.MaximumLength = (USHORT) TotalLength;
String.Buffer = (RtlAllocateStringRoutine)(String.MaximumLength);
if (String.Buffer == NULL) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: Assembly storage resolution failing probe because attempt to allocate %u bytes failed.\n", String.MaximumLength);
Status = STATUS_NO_MEMORY;
goto Exit;
}
} else {
String.Buffer = Buffer;
String.MaximumLength = sizeof(Buffer);
}
RtlCopyMemory(
String.Buffer,
Root->Buffer,
Root->Length);
Cursor = (PWSTR) (((ULONG_PTR) String.Buffer) + Root->Length);
if (SeparatorNeededAfterRoot) {
*Cursor++ = L'\\';
}
RtlCopyMemory(
Cursor,
AssemblyDirectory->Buffer,
AssemblyDirectory->Length);
Cursor = (PWSTR) (((ULONG_PTR) Cursor) + AssemblyDirectory->Length);
*Cursor = L'\0';
String.Length =
Root->Length +
(SeparatorNeededAfterRoot ? sizeof(WCHAR) : 0) +
AssemblyDirectory->Length;
if (!RtlDosPathNameToNtPathName_U(
String.Buffer,
&FileName,
NULL,
&RelativeName
)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: Attempt to translate DOS path name \"%S\" to NT format failed\n", String.Buffer);
Status = STATUS_OBJECT_PATH_NOT_FOUND;
goto Exit;
}
FreeBuffer = FileName.Buffer;
if (RelativeName.RelativeName.Length != 0) {
FileName = *((PUNICODE_STRING) &RelativeName.RelativeName);
} else {
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
// check the existence of directories
Status = NtQueryAttributesFile(
&Obja,
&BasicInfo
);
fExistDir = FALSE;
if ( !NT_SUCCESS(Status) ) {
if ( (Status == STATUS_SHARING_VIOLATION) || (Status == STATUS_ACCESS_DENIED) )
fExistDir = TRUE;
else
fExistDir = FALSE;
}
else
fExistDir = TRUE;
if (! fExistDir) {
if (( Status == STATUS_NO_SUCH_FILE) || Status == STATUS_OBJECT_NAME_NOT_FOUND || Status == STATUS_OBJECT_PATH_NOT_FOUND)
Status = STATUS_SXS_ASSEMBLY_NOT_FOUND;
else
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: Unable to open assembly directory under storage root \"%S\"; Status = 0x%08lx\n", String.Buffer, Status);
goto Exit;
}
// Open the directory to prevent deletion, just like set current working directory does...
Status = NtOpenFile(
&TempDirectoryHandle,
FILE_TRAVERSE | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
);
if (!NT_SUCCESS(Status)) {
// If we failed, remap no such file to STATUS_SXS_ASSEMBLY_NOT_FOUND.
if (Status == STATUS_NO_SUCH_FILE) {
Status = STATUS_SXS_ASSEMBLY_NOT_FOUND;
} else {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: Unable to open assembly directory under storage root \"%S\"; Status = 0x%08lx\n", String.Buffer, Status);
}
goto Exit;
}
// Hey, we found it!
// add a slash to the path on the way out and we're done!
if (TotalLength <= PreAllocatedString->MaximumLength) {
// The caller's static string is big enough; just use it.
RtlCopyMemory(
PreAllocatedString->Buffer,
String.Buffer,
String.Length);
*StringUsed = PreAllocatedString;
} else {
// If we already have a dynamic string, just give them our pointer.
if (String.Buffer != Buffer) {
DynamicString->Buffer = String.Buffer;
String.Buffer = NULL;
} else {
// Otherwise we do our first allocation on the way out...
DynamicString->Buffer = (RtlAllocateStringRoutine)(TotalLength);
if (DynamicString->Buffer == NULL) {
Status = STATUS_NO_MEMORY;
goto Exit;
}
RtlCopyMemory(
DynamicString->Buffer,
String.Buffer,
String.Length);
}
DynamicString->MaximumLength = (USHORT) TotalLength;
*StringUsed = DynamicString;
}
Cursor = (PWSTR) (((ULONG_PTR) (*StringUsed)->Buffer) + String.Length);
*Cursor++ = L'\\';
*Cursor++ = L'\0';
(*StringUsed)->Length = (USHORT) (String.Length + sizeof(WCHAR)); // aka "TotalLength - sizeof(WCHAR)" but this seemed cleaner
*OpenDirectoryHandle = TempDirectoryHandle;
TempDirectoryHandle = NULL;
Status = STATUS_SUCCESS;
Exit:
DbgPrintFunctionExit(__FUNCTION__, Status);
if (FreeBuffer != NULL) {
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
}
if ((String.Buffer != NULL) && (String.Buffer != Buffer)) {
(RtlFreeStringRoutine)(String.Buffer);
}
if (TempDirectoryHandle != NULL) {
RTL_SOFT_VERIFY(NT_SUCCESS(NtClose(TempDirectoryHandle)));
}
return Status;
}
#if 0 /* dead code */
NTSTATUS
NTAPI
RtlResolveAssemblyStorageMapEntry(
IN ULONG Flags,
IN PACTIVATION_CONTEXT ActivationContext,
IN ULONG AssemblyRosterIndex,
IN PASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_ROUTINE Callback,
IN PVOID CallbackContext
)
{
NTSTATUS Status = STATUS_SUCCESS;
PCACTIVATION_CONTEXT_DATA ActivationContextData = NULL;
PASSEMBLY_STORAGE_MAP Map = NULL;
PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRosterHeader = NULL;
PPEB Peb = NtCurrentPeb();
DbgPrintFunctionEntry(__FUNCTION__);
ASSERT_OK_TO_WRITE_PEB();
RTLP_DISALLOW_THE_EMPTY_ACTIVATION_CONTEXT(ActivationContext);
Status = RtlpGetActivationContextDataStorageMapAndRosterHeader(
0,
Peb,
ActivationContext,
&ActivationContextData,
&Map,
&AssemblyRosterHeader);
if (!NT_SUCCESS(Status))
goto Exit;
if (ActivationContextData == NULL) {
ASSERT(ActivationContext == NULL);
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: RtlResolveAssemblyStorageMapEntry() asked to resolve an assembly storage entry when no activation context data is available.\n");
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
if (AssemblyRosterIndex >= AssemblyRosterHeader->EntryCount) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: %s() bad parameters: AssemblyRosterIndex 0x%lx >= AssemblyRosterHeader->EntryCount 0x%lx\n",
__FUNCTION__,
AssemblyRosterIndex,
AssemblyRosterHeader->EntryCount
);
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
Status = RtlpResolveAssemblyStorageMapEntry(Map, ActivationContextData, AssemblyRosterIndex, Callback, CallbackContext);
if (!NT_SUCCESS(Status))
goto Exit;
Status = STATUS_SUCCESS;
Exit:
DbgPrintFunctionExit(__FUNCTION__, Status);
return Status;
}
#endif /* dead code */
NTSTATUS
NTAPI
RtlGetAssemblyStorageRoot(
IN ULONG Flags,
IN PACTIVATION_CONTEXT ActivationContext,
IN ULONG AssemblyRosterIndex,
OUT PCUNICODE_STRING *AssemblyStorageRoot,
IN PASSEMBLY_STORAGE_MAP_RESOLUTION_CALLBACK_ROUTINE Callback,
IN PVOID CallbackContext
)
{
NTSTATUS Status = STATUS_SUCCESS;
PCACTIVATION_CONTEXT_DATA ActivationContextData = NULL;
PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRosterHeader = NULL;
PASSEMBLY_STORAGE_MAP AssemblyStorageMap = NULL;
const PPEB Peb = NtCurrentPeb();
DbgPrintFunctionEntry(__FUNCTION__);
ASSERT_OK_TO_WRITE_PEB();
RTLP_DISALLOW_THE_EMPTY_ACTIVATION_CONTEXT(ActivationContext);
if (AssemblyStorageRoot != NULL) {
*AssemblyStorageRoot = NULL;
}
if ((Flags & ~(RTL_GET_ASSEMBLY_STORAGE_ROOT_FLAG_ACTIVATION_CONTEXT_USE_PROCESS_DEFAULT
| RTL_GET_ASSEMBLY_STORAGE_ROOT_FLAG_ACTIVATION_CONTEXT_USE_SYSTEM_DEFAULT))
||
(AssemblyRosterIndex < 1) ||
(AssemblyStorageRoot == NULL) ||
(Callback == NULL)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: %s() bad parameters:\n"
"SXS: Flags : 0x%lx\n"
"SXS: AssemblyRosterIndex: 0x%lx\n"
"SXS: AssemblyStorageRoot: %p\n"
"SXS: Callback : %p\n",
__FUNCTION__,
Flags,
AssemblyRosterIndex,
AssemblyStorageRoot,
Callback
);
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
// Simple implementation: just resolve it and if it resolves OK, return the string in the
// storage map.
Status =
RtlpGetActivationContextDataStorageMapAndRosterHeader(
((Flags & RTL_GET_ASSEMBLY_STORAGE_ROOT_FLAG_ACTIVATION_CONTEXT_USE_PROCESS_DEFAULT)
? RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_PROCESS_DEFAULT
: 0)
| ((Flags & RTL_GET_ASSEMBLY_STORAGE_ROOT_FLAG_ACTIVATION_CONTEXT_USE_SYSTEM_DEFAULT)
? RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_SYSTEM_DEFAULT
: 0),
Peb,
ActivationContext,
&ActivationContextData,
&AssemblyStorageMap,
&AssemblyRosterHeader
);
if (!NT_SUCCESS(Status)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: RtlGetAssemblyStorageRoot() unable to get activation context data, storage map and assembly roster header. Status = 0x%08lx\n", Status);
goto Exit;
}
// It's possible that there wasn't anything...
if (ActivationContextData != NULL) {
ASSERT(AssemblyRosterHeader != NULL);
ASSERT(AssemblyStorageMap != NULL);
if ((AssemblyRosterHeader == NULL) || (AssemblyStorageMap == NULL)) {
Status = STATUS_INTERNAL_ERROR;
goto Exit;
}
if (AssemblyRosterIndex >= AssemblyRosterHeader->EntryCount) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: %s() bad parameters AssemblyRosterIndex 0x%lx "
">= AssemblyRosterHeader->EntryCount: 0x%lx\n",
__FUNCTION__,
AssemblyRosterIndex,
AssemblyRosterHeader->EntryCount
);
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
Status = RtlpResolveAssemblyStorageMapEntry(AssemblyStorageMap, ActivationContextData, AssemblyRosterIndex, Callback, CallbackContext);
if (!NT_SUCCESS(Status)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: RtlGetAssemblyStorageRoot() unable to resolve storage map entry. Status = 0x%08lx\n", Status);
goto Exit;
}
// I guess we're done!
ASSERT(AssemblyStorageMap->AssemblyArray[AssemblyRosterIndex] != NULL);
if (AssemblyStorageMap->AssemblyArray[AssemblyRosterIndex] == NULL) {
Status = STATUS_INTERNAL_ERROR;
goto Exit;
}
*AssemblyStorageRoot = &AssemblyStorageMap->AssemblyArray[AssemblyRosterIndex]->DosPath;
}
Status = STATUS_SUCCESS;
Exit:
DbgPrintFunctionExit(__FUNCTION__, Status);
return Status;
}
NTSTATUS
RtlpGetActivationContextDataStorageMapAndRosterHeader(
ULONG Flags,
PPEB Peb,
PACTIVATION_CONTEXT ActivationContext,
PCACTIVATION_CONTEXT_DATA *ActivationContextData,
PASSEMBLY_STORAGE_MAP *AssemblyStorageMap,
PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER *AssemblyRosterHeader
)
{
NTSTATUS Status = STATUS_SUCCESS;
PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER TempAssemblyRosterHeader = NULL;
PCACTIVATION_CONTEXT_DATA* TempActivationContextData = NULL;
PASSEMBLY_STORAGE_MAP* TempAssemblyStorageMap = NULL;
WCHAR LocalAssemblyDirectoryBuffer[DOS_MAX_PATH_LENGTH];
UNICODE_STRING LocalAssemblyDirectory = {0};
DbgPrintFunctionEntry(__FUNCTION__);
LocalAssemblyDirectoryBuffer[0] = 0;
LocalAssemblyDirectory.Length = 0;
LocalAssemblyDirectory.MaximumLength = sizeof(WCHAR);
LocalAssemblyDirectory.Buffer = LocalAssemblyDirectoryBuffer;
ASSERT(Peb != NULL);
RTLP_DISALLOW_THE_EMPTY_ACTIVATION_CONTEXT(ActivationContext);
if (ActivationContextData != NULL) {
*ActivationContextData = NULL;
}
if (AssemblyStorageMap != NULL) {
*AssemblyStorageMap = NULL;
}
if (AssemblyRosterHeader != NULL) {
*AssemblyRosterHeader = NULL;
}
if (
(Flags & ~(RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_PROCESS_DEFAULT
| RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_SYSTEM_DEFAULT))
||
(Peb == NULL) ||
(ActivationContextData == NULL) ||
(AssemblyStorageMap == NULL)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: %s() bad parameters:\n"
"SXS: Flags : 0x%lx\n"
"SXS: Peb : %p\n"
"SXS: ActivationContextData: %p\n"
"SXS: AssemblyStorageMap : %p\n"
__FUNCTION__,
Flags,
Peb,
ActivationContextData,
AssemblyStorageMap
);
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
if (ActivationContext == ACTCTX_PROCESS_DEFAULT
|| ActivationContext == ACTCTX_SYSTEM_DEFAULT
|| (Flags & (
RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_PROCESS_DEFAULT
| RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_SYSTEM_DEFAULT))) {
//
// NOTE the ambiguity here. Maybe we'll clean this up.
//
// The flags override.
// ActivationContext == ACTCTX_PROCESS_DEFAULT could still be system default.
//
if (ActivationContext == ACTCTX_SYSTEM_DEFAULT
|| (Flags & RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_SYSTEM_DEFAULT)
) {
TempActivationContextData = (PACTIVATION_CONTEXT_DATA*)(&Peb->SystemDefaultActivationContextData);
TempAssemblyStorageMap = (PASSEMBLY_STORAGE_MAP*)(&Peb->SystemAssemblyStorageMap);
if (*TempActivationContextData != NULL) {
TempAssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) *TempActivationContextData) + (*TempActivationContextData)->AssemblyRosterOffset);
}
}
else if (ActivationContext == ACTCTX_PROCESS_DEFAULT || (Flags & RTLP_GET_ACTIVATION_CONTEXT_DATA_STORAGE_MAP_AND_ROSTER_HEADER_USE_PROCESS_DEFAULT)) {
TempActivationContextData = (PACTIVATION_CONTEXT_DATA*)(&Peb->ActivationContextData);
TempAssemblyStorageMap = (PASSEMBLY_STORAGE_MAP*)(&Peb->ProcessAssemblyStorageMap);
if (*TempActivationContextData != NULL) {
TempAssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) *TempActivationContextData) + (*TempActivationContextData)->AssemblyRosterOffset);
if (*TempAssemblyStorageMap == NULL) {
UNICODE_STRING ImagePathName;
// Capture the image path name so that we don't overrun allocated buffers because someone's
// randomly tweaking the RTL_USER_PROCESS_PARAMETERS.
ImagePathName = Peb->ProcessParameters->ImagePathName;
// The process default local assembly directory is the image name plus ".local".
// The process default private assembly directory is the image path.
if ((ImagePathName.Length + sizeof(LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX)) > sizeof(LocalAssemblyDirectoryBuffer)) {
if ((ImagePathName.Length + sizeof(LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX)) > UNICODE_STRING_MAX_BYTES) {
Status = STATUS_NAME_TOO_LONG;
goto Exit;
}
LocalAssemblyDirectory.MaximumLength = (USHORT) (ImagePathName.Length + sizeof(LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX));
LocalAssemblyDirectory.Buffer = (RtlAllocateStringRoutine)(LocalAssemblyDirectory.MaximumLength);
if (LocalAssemblyDirectory.Buffer == NULL) {
Status = STATUS_NO_MEMORY;
goto Exit;
}
} else {
LocalAssemblyDirectory.MaximumLength = sizeof(LocalAssemblyDirectoryBuffer);
LocalAssemblyDirectory.Buffer = LocalAssemblyDirectoryBuffer;
}
RtlCopyMemory(
LocalAssemblyDirectory.Buffer,
ImagePathName.Buffer,
ImagePathName.Length);
RtlCopyMemory(
&LocalAssemblyDirectory.Buffer[ImagePathName.Length / sizeof(WCHAR)],
LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX,
sizeof(LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX));
LocalAssemblyDirectory.Length = ImagePathName.Length + sizeof(LOCAL_ASSEMBLY_STORAGE_DIR_SUFFIX) - sizeof(WCHAR);
if (!NT_SUCCESS(Status))
goto Exit;
}
}
}
if (*TempActivationContextData != NULL) {
if (*TempAssemblyStorageMap == NULL) {
PASSEMBLY_STORAGE_MAP Map = (PASSEMBLY_STORAGE_MAP) RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(ASSEMBLY_STORAGE_MAP) + (TempAssemblyRosterHeader->EntryCount * sizeof(PASSEMBLY_STORAGE_MAP_ENTRY)));
if (Map == NULL) {
Status = STATUS_NO_MEMORY;
goto Exit;
}
Status = RtlpInitializeAssemblyStorageMap(Map, TempAssemblyRosterHeader->EntryCount, (PASSEMBLY_STORAGE_MAP_ENTRY *) (Map + 1));
if (!NT_SUCCESS(Status)) {
RtlFreeHeap(RtlProcessHeap(), 0, Map);
goto Exit;
}
if (InterlockedCompareExchangePointer(TempAssemblyStorageMap, Map, NULL) != NULL) {
// We were not the first ones in. Free ours and use the one allocated.
RtlpUninitializeAssemblyStorageMap(Map);
RtlFreeHeap(RtlProcessHeap(), 0, Map);
}
}
} else {
ASSERT(*TempAssemblyStorageMap == NULL);
}
*AssemblyStorageMap = (PASSEMBLY_STORAGE_MAP) *TempAssemblyStorageMap;
} else {
TempActivationContextData = (PACTIVATION_CONTEXT_DATA*)(&ActivationContext->ActivationContextData);
ASSERT(*TempActivationContextData != NULL);
if (*TempActivationContextData == NULL) {
Status = STATUS_INTERNAL_ERROR;
goto Exit;
}
TempAssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) *TempActivationContextData) + (*TempActivationContextData)->AssemblyRosterOffset);
*AssemblyStorageMap = &ActivationContext->StorageMap;
}
if (ActivationContextData != NULL)
*ActivationContextData = *TempActivationContextData;
if (AssemblyRosterHeader != NULL)
*AssemblyRosterHeader = TempAssemblyRosterHeader;
Status = STATUS_SUCCESS;
Exit:
DbgPrintFunctionExit(__FUNCTION__, Status);
if ((LocalAssemblyDirectory.Buffer != NULL) &&
(LocalAssemblyDirectory.Buffer != LocalAssemblyDirectoryBuffer)) {
RtlFreeUnicodeString(&LocalAssemblyDirectory);
}
return Status;
}