2012-01-30 02:10:39 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS Windows-Compatible Session Manager
|
|
|
|
* LICENSE: BSD 2-Clause License
|
2015-09-18 10:13:50 +00:00
|
|
|
* FILE: base/system/smss/sminit.c
|
2012-01-30 02:10:39 +00:00
|
|
|
* PURPOSE: Main SMSS Code
|
|
|
|
* PROGRAMMERS: Alex Ionescu
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
|
|
|
|
#include "smss.h"
|
2014-01-13 13:16:07 +00:00
|
|
|
|
2012-01-30 02:10:39 +00:00
|
|
|
#define NDEBUG
|
2013-01-24 23:00:42 +00:00
|
|
|
#include <debug.h>
|
2012-01-30 02:10:39 +00:00
|
|
|
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
|
2012-01-30 03:44:27 +00:00
|
|
|
UNICODE_STRING SmpSubsystemName, PosixName, Os2Name;
|
2012-01-30 05:32:34 +00:00
|
|
|
LIST_ENTRY SmpBootExecuteList, SmpSetupExecuteList, SmpPagingFileList;
|
|
|
|
LIST_ENTRY SmpDosDevicesList, SmpFileRenameList, SmpKnownDllsList;
|
|
|
|
LIST_ENTRY SmpExcludeKnownDllsList, SmpSubSystemList, SmpSubSystemsToLoad;
|
|
|
|
LIST_ENTRY SmpSubSystemsToDefer, SmpExecuteList, NativeProcessList;
|
|
|
|
|
2012-01-30 19:29:30 +00:00
|
|
|
PVOID SmpHeap;
|
2012-01-30 03:44:27 +00:00
|
|
|
ULONG SmBaseTag;
|
2012-01-30 10:22:21 +00:00
|
|
|
HANDLE SmpDebugPort, SmpDosDevicesObjectDirectory;
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
PWCHAR SmpDefaultEnvironment, SmpDefaultLibPathBuffer;
|
|
|
|
UNICODE_STRING SmpKnownDllPath, SmpDefaultLibPath;
|
|
|
|
ULONG SmpCalledConfigEnv;
|
2012-01-30 05:32:34 +00:00
|
|
|
|
2012-01-30 03:44:27 +00:00
|
|
|
ULONG SmpInitProgressByLine;
|
|
|
|
NTSTATUS SmpInitReturnStatus;
|
|
|
|
PVOID SmpInitLastCall;
|
2012-01-30 05:32:34 +00:00
|
|
|
|
2012-01-30 03:44:27 +00:00
|
|
|
SECURITY_DESCRIPTOR SmpPrimarySDBody, SmpLiberalSDBody, SmpKnownDllsSDBody;
|
|
|
|
SECURITY_DESCRIPTOR SmpApiPortSDBody;
|
2012-01-30 10:22:21 +00:00
|
|
|
PISECURITY_DESCRIPTOR SmpPrimarySecurityDescriptor, SmpLiberalSecurityDescriptor;
|
|
|
|
PISECURITY_DESCRIPTOR SmpKnownDllsSecurityDescriptor, SmpApiPortSecurityDescriptor;
|
2012-01-30 05:32:34 +00:00
|
|
|
|
|
|
|
ULONG SmpAllowProtectedRenames, SmpProtectionMode = 1;
|
2016-01-07 16:57:05 +00:00
|
|
|
BOOLEAN MiniNTBoot = FALSE;
|
2012-01-30 03:44:27 +00:00
|
|
|
|
|
|
|
#define SMSS_CHECKPOINT(x, y) \
|
|
|
|
{ \
|
|
|
|
SmpInitProgressByLine = __LINE__; \
|
|
|
|
SmpInitReturnStatus = (y); \
|
|
|
|
SmpInitLastCall = (x); \
|
|
|
|
}
|
|
|
|
|
2012-01-30 05:32:34 +00:00
|
|
|
/* REGISTRY CONFIGURATION *****************************************************/
|
|
|
|
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpSaveRegistryValue(IN PLIST_ENTRY ListAddress,
|
|
|
|
IN PWSTR Name,
|
|
|
|
IN PWCHAR Value,
|
|
|
|
IN BOOLEAN Flags)
|
|
|
|
{
|
|
|
|
PSMP_REGISTRY_VALUE RegEntry;
|
|
|
|
UNICODE_STRING NameString, ValueString;
|
|
|
|
ANSI_STRING AnsiValueString;
|
|
|
|
PLIST_ENTRY NextEntry;
|
|
|
|
|
|
|
|
/* Convert to unicode strings */
|
|
|
|
RtlInitUnicodeString(&NameString, Name);
|
|
|
|
RtlInitUnicodeString(&ValueString, Value);
|
|
|
|
|
2012-02-03 11:21:15 +00:00
|
|
|
/* In case this is the first value, initialize a new list/structure */
|
|
|
|
RegEntry = NULL;
|
|
|
|
|
|
|
|
/* Check if we should do a duplicate check */
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
if (Flags)
|
|
|
|
{
|
|
|
|
/* Loop the current list */
|
|
|
|
NextEntry = ListAddress->Flink;
|
|
|
|
while (NextEntry != ListAddress)
|
|
|
|
{
|
|
|
|
/* Get each entry */
|
|
|
|
RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
|
|
|
|
|
|
|
|
/* Check if the value name matches */
|
|
|
|
if (!RtlCompareUnicodeString(&RegEntry->Name, &NameString, TRUE))
|
|
|
|
{
|
|
|
|
/* Check if the value is the exact same thing */
|
2012-02-03 11:21:15 +00:00
|
|
|
if (!RtlCompareUnicodeString(&RegEntry->Value, &ValueString, TRUE))
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
{
|
|
|
|
/* Fail -- the same setting is being set twice */
|
|
|
|
return STATUS_OBJECT_NAME_EXISTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We found the list, and this isn't a duplicate value */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This wasn't a match, keep going */
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
RegEntry = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Are we adding on, or creating a new entry */
|
|
|
|
if (!RegEntry)
|
|
|
|
{
|
|
|
|
/* A new entry -- allocate it */
|
|
|
|
RegEntry = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
|
|
SmBaseTag,
|
2015-02-20 22:03:23 +00:00
|
|
|
sizeof(SMP_REGISTRY_VALUE) +
|
|
|
|
NameString.MaximumLength);
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
if (!RegEntry) return STATUS_NO_MEMORY;
|
|
|
|
|
|
|
|
/* Initialize the list and set all values to NULL */
|
|
|
|
InitializeListHead(&RegEntry->Entry);
|
|
|
|
RegEntry->AnsiValue = NULL;
|
|
|
|
RegEntry->Value.Buffer = NULL;
|
|
|
|
|
|
|
|
/* Copy and initialize the value name */
|
|
|
|
RegEntry->Name.Buffer = (PWCHAR)(RegEntry + 1);
|
|
|
|
RegEntry->Name.Length = NameString.Length;
|
|
|
|
RegEntry->Name.MaximumLength = NameString.MaximumLength;
|
|
|
|
RtlCopyMemory(RegEntry->Name.Buffer,
|
|
|
|
NameString.Buffer,
|
|
|
|
NameString.MaximumLength);
|
|
|
|
|
|
|
|
/* Add this entry into the list */
|
|
|
|
InsertTailList(ListAddress, &RegEntry->Entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Did we have an old value buffer? */
|
|
|
|
if (RegEntry->Value.Buffer)
|
|
|
|
{
|
|
|
|
/* Free it */
|
2012-02-03 11:21:15 +00:00
|
|
|
ASSERT(RegEntry->Value.Length != 0);
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is there no value associated? */
|
|
|
|
if (!Value)
|
|
|
|
{
|
|
|
|
/* We're done here */
|
|
|
|
RtlInitUnicodeString(&RegEntry->Value, NULL);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* There is a value, so allocate a buffer for it */
|
|
|
|
RegEntry->Value.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
|
|
SmBaseTag,
|
|
|
|
ValueString.MaximumLength);
|
|
|
|
if (!RegEntry->Value.Buffer)
|
|
|
|
{
|
|
|
|
/* Out of memory, undo */
|
|
|
|
RemoveEntryList(&RegEntry->Entry);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
|
|
|
|
return STATUS_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy the value into the entry */
|
|
|
|
RegEntry->Value.Length = ValueString.Length;
|
|
|
|
RegEntry->Value.MaximumLength = ValueString.MaximumLength;
|
|
|
|
RtlCopyMemory(RegEntry->Value.Buffer,
|
|
|
|
ValueString.Buffer,
|
|
|
|
ValueString.MaximumLength);
|
|
|
|
|
|
|
|
/* Now allocate memory for an ANSI copy of it */
|
|
|
|
RegEntry->AnsiValue = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
|
|
SmBaseTag,
|
|
|
|
(ValueString.Length / sizeof(WCHAR)) +
|
|
|
|
sizeof(ANSI_NULL));
|
|
|
|
if (!RegEntry->AnsiValue)
|
|
|
|
{
|
|
|
|
/* Out of memory, undo */
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
|
|
|
|
RemoveEntryList(&RegEntry->Entry);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
|
|
|
|
return STATUS_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert the Unicode value string and return success */
|
|
|
|
RtlInitEmptyAnsiString(&AnsiValueString,
|
|
|
|
RegEntry->AnsiValue,
|
|
|
|
(ValueString.Length / sizeof(WCHAR)) +
|
|
|
|
sizeof(ANSI_NULL));
|
|
|
|
RtlUnicodeStringToAnsiString(&AnsiValueString, &ValueString, FALSE);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
PSMP_REGISTRY_VALUE
|
|
|
|
NTAPI
|
|
|
|
SmpFindRegistryValue(IN PLIST_ENTRY List,
|
|
|
|
IN PWSTR ValueName)
|
|
|
|
{
|
|
|
|
PSMP_REGISTRY_VALUE RegEntry;
|
|
|
|
UNICODE_STRING ValueString;
|
|
|
|
PLIST_ENTRY NextEntry;
|
|
|
|
|
|
|
|
/* Initialize the value name sting */
|
|
|
|
RtlInitUnicodeString(&ValueString, ValueName);
|
|
|
|
|
|
|
|
/* Loop the list */
|
|
|
|
NextEntry = List->Flink;
|
|
|
|
while (NextEntry != List)
|
|
|
|
{
|
|
|
|
/* Get each entry */
|
|
|
|
RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
|
|
|
|
|
|
|
|
/* Check if the value name matches */
|
|
|
|
if (!RtlCompareUnicodeString(&RegEntry->Name, &ValueString, TRUE)) break;
|
|
|
|
|
|
|
|
/* It doesn't, move on */
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we looped back, return NULL, otherwise return the entry we found */
|
|
|
|
if (NextEntry == List) RegEntry = NULL;
|
|
|
|
return RegEntry;
|
|
|
|
}
|
|
|
|
|
2012-01-30 05:32:34 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpConfigureProtectionMode(IN PWSTR ValueName,
|
|
|
|
IN ULONG ValueType,
|
|
|
|
IN PVOID ValueData,
|
|
|
|
IN ULONG ValueLength,
|
|
|
|
IN PVOID Context,
|
|
|
|
IN PVOID EntryContext)
|
|
|
|
{
|
|
|
|
/* Make sure the value is valid */
|
|
|
|
if (ValueLength == sizeof(ULONG))
|
|
|
|
{
|
|
|
|
/* Read it */
|
|
|
|
SmpProtectionMode = *(PULONG)ValueData;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Default is to protect stuff */
|
|
|
|
SmpProtectionMode = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Recreate the security descriptors to take into account security mode */
|
|
|
|
SmpCreateSecurityDescriptors(FALSE);
|
2013-09-03 12:02:52 +00:00
|
|
|
DPRINT("SmpProtectionMode: %lu\n", SmpProtectionMode);
|
2012-01-30 05:32:34 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpConfigureAllowProtectedRenames(IN PWSTR ValueName,
|
|
|
|
IN ULONG ValueType,
|
|
|
|
IN PVOID ValueData,
|
|
|
|
IN ULONG ValueLength,
|
|
|
|
IN PVOID Context,
|
|
|
|
IN PVOID EntryContext)
|
|
|
|
{
|
|
|
|
/* Make sure the value is valid */
|
|
|
|
if (ValueLength == sizeof(ULONG))
|
|
|
|
{
|
|
|
|
/* Read it */
|
|
|
|
SmpAllowProtectedRenames = *(PULONG)ValueData;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Default is to not allow protected renames */
|
|
|
|
SmpAllowProtectedRenames = 0;
|
|
|
|
}
|
|
|
|
|
2013-09-03 12:02:52 +00:00
|
|
|
DPRINT("SmpAllowProtectedRenames: %lu\n", SmpAllowProtectedRenames);
|
2012-01-30 05:32:34 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpConfigureObjectDirectories(IN PWSTR ValueName,
|
|
|
|
IN ULONG ValueType,
|
|
|
|
IN PVOID ValueData,
|
|
|
|
IN ULONG ValueLength,
|
|
|
|
IN PVOID Context,
|
|
|
|
IN PVOID EntryContext)
|
|
|
|
{
|
|
|
|
PISECURITY_DESCRIPTOR SecDescriptor;
|
|
|
|
NTSTATUS Status;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
HANDLE DirHandle;
|
|
|
|
UNICODE_STRING RpcString, WindowsString, SearchString;
|
|
|
|
PWCHAR SourceString = ValueData;
|
|
|
|
|
|
|
|
/* Initialize the two strings we will be looking for */
|
|
|
|
RtlInitUnicodeString(&RpcString, L"\\RPC Control");
|
|
|
|
RtlInitUnicodeString(&WindowsString, L"\\Windows");
|
|
|
|
|
|
|
|
/* Loop the registry data we received */
|
|
|
|
while (*SourceString)
|
|
|
|
{
|
|
|
|
/* Assume primary SD for most objects */
|
|
|
|
RtlInitUnicodeString(&SearchString, SourceString);
|
|
|
|
SecDescriptor = SmpPrimarySecurityDescriptor;
|
|
|
|
|
|
|
|
/* But for these two always set the liberal descriptor */
|
|
|
|
if ((RtlEqualUnicodeString(&SearchString, &RpcString, TRUE)) ||
|
|
|
|
(RtlEqualUnicodeString(&SearchString, &WindowsString, TRUE)))
|
|
|
|
{
|
|
|
|
SecDescriptor = SmpLiberalSecurityDescriptor;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create the requested directory with the requested descriptor */
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&SearchString,
|
|
|
|
OBJ_CASE_INSENSITIVE |
|
|
|
|
OBJ_OPENIF |
|
|
|
|
OBJ_PERMANENT,
|
|
|
|
NULL,
|
|
|
|
SecDescriptor);
|
2012-02-06 18:57:18 +00:00
|
|
|
DPRINT("Creating: %wZ directory\n", &SearchString);
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
Status = NtCreateDirectoryObject(&DirHandle,
|
|
|
|
DIRECTORY_ALL_ACCESS,
|
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Failure case */
|
|
|
|
DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
|
|
|
|
&SearchString, Status);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* It worked, now close the handle */
|
|
|
|
NtClose(DirHandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Move to the next requested object */
|
2016-01-07 16:57:05 +00:00
|
|
|
SourceString += wcslen(SourceString) + 1;
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* All done */
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpConfigureMemoryMgmt(IN PWSTR ValueName,
|
|
|
|
IN ULONG ValueType,
|
|
|
|
IN PVOID ValueData,
|
|
|
|
IN ULONG ValueLength,
|
|
|
|
IN PVOID Context,
|
|
|
|
IN PVOID EntryContext)
|
|
|
|
{
|
|
|
|
/* Save this is into a list */
|
|
|
|
return SmpSaveRegistryValue(EntryContext, ValueData, NULL, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpConfigureFileRenames(IN PWSTR ValueName,
|
|
|
|
IN ULONG ValueType,
|
|
|
|
IN PVOID ValueData,
|
|
|
|
IN ULONG ValueLength,
|
|
|
|
IN PVOID Context,
|
|
|
|
IN PVOID EntryContext)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
2015-02-20 22:03:23 +00:00
|
|
|
static PWCHAR Canary = NULL;
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
|
|
|
|
/* Check if this is the second call */
|
|
|
|
if (Canary)
|
|
|
|
{
|
|
|
|
/* Save the data into the list */
|
2016-03-22 18:34:18 +00:00
|
|
|
DPRINT("Renamed file: '%S' - '%S'\n", Canary, ValueData);
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
Status = SmpSaveRegistryValue(EntryContext, Canary, ValueData, FALSE);
|
2015-02-20 22:03:23 +00:00
|
|
|
Canary = NULL;
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* This it the first call, do nothing until we get the second call */
|
|
|
|
Canary = ValueData;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the status */
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpConfigureExcludeKnownDlls(IN PWSTR ValueName,
|
|
|
|
IN ULONG ValueType,
|
|
|
|
IN PVOID ValueData,
|
|
|
|
IN ULONG ValueLength,
|
|
|
|
IN PVOID Context,
|
|
|
|
IN PVOID EntryContext)
|
|
|
|
{
|
|
|
|
PWCHAR DllName;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
/* Make sure the value type is valid */
|
|
|
|
if ((ValueType == REG_MULTI_SZ) || (ValueType == REG_SZ))
|
|
|
|
{
|
|
|
|
/* Keep going for each DLL in the list */
|
|
|
|
DllName = ValueData;
|
|
|
|
while (*DllName)
|
|
|
|
{
|
|
|
|
/* Add this to the linked list */
|
2012-02-06 18:57:18 +00:00
|
|
|
DPRINT("Excluded DLL: %S\n", DllName);
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
Status = SmpSaveRegistryValue(EntryContext, DllName, NULL, TRUE);
|
|
|
|
|
|
|
|
/* Bail out on failure or if only one DLL name was present */
|
|
|
|
if (!(NT_SUCCESS(Status)) || (ValueType == REG_SZ)) return Status;
|
|
|
|
|
|
|
|
/* Otherwise, move to the next DLL name */
|
2016-01-07 16:57:05 +00:00
|
|
|
DllName += wcslen(DllName) + 1;
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All done */
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpConfigureDosDevices(IN PWSTR ValueName,
|
|
|
|
IN ULONG ValueType,
|
|
|
|
IN PVOID ValueData,
|
|
|
|
IN ULONG ValueLength,
|
|
|
|
IN PVOID Context,
|
|
|
|
IN PVOID EntryContext)
|
|
|
|
{
|
|
|
|
/* Save into linked list */
|
|
|
|
return SmpSaveRegistryValue(EntryContext, ValueName, ValueData, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpInitializeKnownDllPath(IN PUNICODE_STRING DllPath,
|
|
|
|
IN PWCHAR Buffer,
|
|
|
|
IN ULONG Length)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
/* Allocate the buffer */
|
|
|
|
DllPath->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag, Length);
|
|
|
|
if (DllPath->Buffer)
|
|
|
|
{
|
|
|
|
/* Fill out the rest of the string */
|
2012-02-02 20:50:22 +00:00
|
|
|
DllPath->MaximumLength = (USHORT)Length;
|
|
|
|
DllPath->Length = (USHORT)Length - sizeof(UNICODE_NULL);
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
|
|
|
|
/* Copy the actual path and return success */
|
|
|
|
RtlCopyMemory(DllPath->Buffer, Buffer, Length);
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Fail with out of memory code */
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return result */
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpConfigureKnownDlls(IN PWSTR ValueName,
|
|
|
|
IN ULONG ValueType,
|
|
|
|
IN PVOID ValueData,
|
|
|
|
IN ULONG ValueLength,
|
|
|
|
IN PVOID Context,
|
|
|
|
IN PVOID EntryContext)
|
|
|
|
{
|
|
|
|
/* Check which value is being set */
|
2013-01-26 23:56:07 +00:00
|
|
|
if (_wcsicmp(ValueName, L"DllDirectory") == 0)
|
|
|
|
{
|
|
|
|
/* This is the directory, initialize it */
|
|
|
|
DPRINT("KnownDll Path: %S\n", ValueData);
|
|
|
|
return SmpInitializeKnownDllPath(&SmpKnownDllPath, ValueData, ValueLength);
|
|
|
|
}
|
|
|
|
else
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
{
|
|
|
|
/* Add to the linked list -- this is a file */
|
|
|
|
return SmpSaveRegistryValue(EntryContext, ValueName, ValueData, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpConfigureEnvironment(IN PWSTR ValueName,
|
|
|
|
IN ULONG ValueType,
|
|
|
|
IN PVOID ValueData,
|
|
|
|
IN ULONG ValueLength,
|
|
|
|
IN PVOID Context,
|
|
|
|
IN PVOID EntryContext)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
UNICODE_STRING ValueString, DataString;
|
|
|
|
|
|
|
|
/* Convert the strings into UNICODE_STRING and set the variable defined */
|
|
|
|
RtlInitUnicodeString(&ValueString, ValueName);
|
|
|
|
RtlInitUnicodeString(&DataString, ValueData);
|
2012-02-06 18:57:18 +00:00
|
|
|
DPRINT("Setting %wZ = %wZ\n", &ValueString, &DataString);
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
Status = RtlSetEnvironmentVariable(0, &ValueString, &DataString);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: 'SET %wZ = %wZ' failed - Status == %lx\n",
|
|
|
|
&ValueString, &DataString, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the path is being set, and wait for the second instantiation */
|
2013-01-26 23:56:07 +00:00
|
|
|
if ((_wcsicmp(ValueName, L"Path") == 0) && (++SmpCalledConfigEnv == 2))
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
{
|
|
|
|
/* Allocate the path buffer */
|
|
|
|
SmpDefaultLibPathBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
|
|
SmBaseTag,
|
|
|
|
ValueLength);
|
|
|
|
if (!SmpDefaultLibPathBuffer) return STATUS_NO_MEMORY;
|
|
|
|
|
|
|
|
/* Copy the data into it and create the UNICODE_STRING to hold it */
|
|
|
|
RtlCopyMemory(SmpDefaultLibPathBuffer, ValueData, ValueLength);
|
|
|
|
RtlInitUnicodeString(&SmpDefaultLibPath, SmpDefaultLibPathBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All good */
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpConfigureSubSystems(IN PWSTR ValueName,
|
|
|
|
IN ULONG ValueType,
|
|
|
|
IN PVOID ValueData,
|
|
|
|
IN ULONG ValueLength,
|
|
|
|
IN PVOID Context,
|
|
|
|
IN PVOID EntryContext)
|
|
|
|
{
|
|
|
|
PSMP_REGISTRY_VALUE RegEntry;
|
|
|
|
PWCHAR SubsystemName;
|
|
|
|
|
2013-01-26 23:56:07 +00:00
|
|
|
/* Is this a required or optional subsystem? */
|
|
|
|
if ((_wcsicmp(ValueName, L"Required") != 0) &&
|
|
|
|
(_wcsicmp(ValueName, L"Optional") != 0))
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
{
|
|
|
|
/* It isn't, is this the PSI flag? */
|
2013-01-26 23:56:07 +00:00
|
|
|
if ((_wcsicmp(ValueName, L"PosixSingleInstance") != 0) ||
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
(ValueType != REG_DWORD))
|
|
|
|
{
|
|
|
|
/* It isn't, must be a subsystem entry, add it to the list */
|
2012-02-06 18:57:18 +00:00
|
|
|
DPRINT("Subsystem entry: %S-%S\n", ValueName, ValueData);
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
return SmpSaveRegistryValue(EntryContext, ValueName, ValueData, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This was the PSI flag, save it and exit */
|
|
|
|
RegPosixSingleInstance = TRUE;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This should be one of the required/optional lists. Is the type valid? */
|
|
|
|
if (ValueType == REG_MULTI_SZ)
|
|
|
|
{
|
|
|
|
/* It is, get the first subsystem */
|
|
|
|
SubsystemName = ValueData;
|
|
|
|
while (*SubsystemName)
|
|
|
|
{
|
|
|
|
/* We should have already put it into the list when we found it */
|
2012-02-06 18:57:18 +00:00
|
|
|
DPRINT("Found subsystem: %S\n", SubsystemName);
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
RegEntry = SmpFindRegistryValue(EntryContext, SubsystemName);
|
|
|
|
if (!RegEntry)
|
|
|
|
{
|
|
|
|
/* This subsystem doesn't exist, so skip it */
|
|
|
|
DPRINT1("SMSS: Invalid subsystem name - %ws\n", SubsystemName);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Found it -- remove it from the main list */
|
|
|
|
RemoveEntryList(&RegEntry->Entry);
|
|
|
|
|
|
|
|
/* Figure out which list to put it in */
|
2013-01-26 23:56:07 +00:00
|
|
|
if (_wcsicmp(ValueName, L"Required") == 0)
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
{
|
|
|
|
/* Put it into the required list */
|
2012-02-06 18:57:18 +00:00
|
|
|
DPRINT("Required\n");
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
InsertTailList(&SmpSubSystemsToLoad, &RegEntry->Entry);
|
|
|
|
}
|
2013-01-26 23:56:07 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Put it into the optional list */
|
|
|
|
DPRINT("Optional\n");
|
|
|
|
InsertTailList(&SmpSubSystemsToDefer, &RegEntry->Entry);
|
|
|
|
}
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Move to the next name */
|
2016-01-07 16:57:05 +00:00
|
|
|
SubsystemName += wcslen(SubsystemName) + 1;
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All done! */
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-01-30 05:32:34 +00:00
|
|
|
RTL_QUERY_REGISTRY_TABLE
|
|
|
|
SmpRegistryConfigurationTable[] =
|
|
|
|
{
|
|
|
|
{
|
|
|
|
SmpConfigureProtectionMode,
|
|
|
|
0,
|
|
|
|
L"ProtectionMode",
|
|
|
|
NULL,
|
|
|
|
REG_DWORD,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
},
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
|
2012-01-30 05:32:34 +00:00
|
|
|
{
|
|
|
|
SmpConfigureAllowProtectedRenames,
|
2016-01-07 19:03:35 +00:00
|
|
|
RTL_QUERY_REGISTRY_DELETE,
|
2012-01-30 05:32:34 +00:00
|
|
|
L"AllowProtectedRenames",
|
|
|
|
NULL,
|
|
|
|
REG_DWORD,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
},
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureObjectDirectories,
|
|
|
|
0,
|
|
|
|
L"ObjectDirectories",
|
|
|
|
NULL,
|
|
|
|
REG_MULTI_SZ,
|
|
|
|
L"\\Windows\0\\RPC Control\0",
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureMemoryMgmt,
|
|
|
|
0,
|
|
|
|
L"BootExecute",
|
|
|
|
&SmpBootExecuteList,
|
2013-07-19 22:32:34 +00:00
|
|
|
REG_MULTI_SZ,
|
|
|
|
L"autocheck AutoChk.exe *\0",
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureMemoryMgmt,
|
|
|
|
RTL_QUERY_REGISTRY_TOPKEY,
|
|
|
|
L"SetupExecute",
|
|
|
|
&SmpSetupExecuteList,
|
|
|
|
REG_NONE,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureFileRenames,
|
2016-01-07 19:03:35 +00:00
|
|
|
RTL_QUERY_REGISTRY_DELETE,
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
L"PendingFileRenameOperations",
|
|
|
|
&SmpFileRenameList,
|
|
|
|
REG_NONE,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureFileRenames,
|
2016-01-07 19:03:35 +00:00
|
|
|
RTL_QUERY_REGISTRY_DELETE,
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
L"PendingFileRenameOperations2",
|
|
|
|
&SmpFileRenameList,
|
|
|
|
REG_NONE,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureExcludeKnownDlls,
|
|
|
|
0,
|
|
|
|
L"ExcludeFromKnownDlls",
|
|
|
|
&SmpExcludeKnownDllsList,
|
|
|
|
REG_MULTI_SZ,
|
|
|
|
L"\0",
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
NULL,
|
|
|
|
RTL_QUERY_REGISTRY_SUBKEY,
|
|
|
|
L"Memory Management",
|
|
|
|
NULL,
|
|
|
|
REG_NONE,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureMemoryMgmt,
|
|
|
|
0,
|
|
|
|
L"PagingFiles",
|
|
|
|
&SmpPagingFileList,
|
|
|
|
REG_MULTI_SZ,
|
|
|
|
L"?:\\pagefile.sys\0",
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureDosDevices,
|
|
|
|
RTL_QUERY_REGISTRY_SUBKEY,
|
|
|
|
L"DOS Devices",
|
|
|
|
&SmpDosDevicesList,
|
|
|
|
REG_NONE,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureKnownDlls,
|
|
|
|
RTL_QUERY_REGISTRY_SUBKEY,
|
|
|
|
L"KnownDlls",
|
|
|
|
&SmpKnownDllsList,
|
|
|
|
REG_NONE,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureEnvironment,
|
|
|
|
RTL_QUERY_REGISTRY_SUBKEY,
|
|
|
|
L"Environment",
|
|
|
|
NULL,
|
|
|
|
REG_NONE,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureSubSystems,
|
|
|
|
RTL_QUERY_REGISTRY_SUBKEY,
|
|
|
|
L"SubSystems",
|
|
|
|
&SmpSubSystemList,
|
|
|
|
REG_NONE,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureSubSystems,
|
|
|
|
RTL_QUERY_REGISTRY_NOEXPAND,
|
|
|
|
L"Required",
|
|
|
|
&SmpSubSystemList,
|
|
|
|
REG_MULTI_SZ,
|
|
|
|
L"Debug\0Windows\0",
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureSubSystems,
|
|
|
|
RTL_QUERY_REGISTRY_NOEXPAND,
|
|
|
|
L"Optional",
|
|
|
|
&SmpSubSystemList,
|
|
|
|
REG_NONE,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureSubSystems,
|
|
|
|
0,
|
|
|
|
L"Kmode",
|
|
|
|
&SmpSubSystemList,
|
|
|
|
REG_NONE,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
SmpConfigureMemoryMgmt,
|
|
|
|
RTL_QUERY_REGISTRY_TOPKEY,
|
|
|
|
L"Execute",
|
|
|
|
&SmpExecuteList,
|
|
|
|
REG_NONE,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
2012-01-30 05:32:34 +00:00
|
|
|
{0},
|
|
|
|
};
|
|
|
|
|
2012-01-30 02:10:39 +00:00
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
|
2012-02-06 18:57:18 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
SmpTranslateSystemPartitionInformation(VOID)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
UNICODE_STRING UnicodeString, LinkTarget, SearchString, SystemPartition;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
HANDLE KeyHandle, LinkHandle;
|
|
|
|
CHAR ValueBuffer[512 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
|
|
|
|
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
|
|
|
|
ULONG Length, Context;
|
|
|
|
CHAR DirInfoBuffer[512 + sizeof(OBJECT_DIRECTORY_INFORMATION)];
|
|
|
|
POBJECT_DIRECTORY_INFORMATION DirInfo = (PVOID)DirInfoBuffer;
|
|
|
|
WCHAR LinkBuffer[MAX_PATH];
|
|
|
|
|
|
|
|
/* Open the setup key */
|
|
|
|
RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\Setup");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&UnicodeString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: can't open system setup key for reading: 0x%x\n", Status);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Query the system partition */
|
|
|
|
RtlInitUnicodeString(&UnicodeString, L"SystemPartition");
|
|
|
|
Status = NtQueryValueKey(KeyHandle,
|
|
|
|
&UnicodeString,
|
|
|
|
KeyValuePartialInformation,
|
|
|
|
PartialInfo,
|
|
|
|
sizeof(ValueBuffer),
|
|
|
|
&Length);
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: can't query SystemPartition value: 0x%x\n", Status);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the system partition string string */
|
|
|
|
RtlInitUnicodeString(&SystemPartition, (PWCHAR)PartialInfo->Data);
|
|
|
|
|
|
|
|
/* Enumerate the directory looking for the symbolic link string */
|
|
|
|
RtlInitUnicodeString(&SearchString, L"SymbolicLink");
|
|
|
|
RtlInitEmptyUnicodeString(&LinkTarget, LinkBuffer, sizeof(LinkBuffer));
|
|
|
|
Status = NtQueryDirectoryObject(SmpDosDevicesObjectDirectory,
|
|
|
|
DirInfo,
|
|
|
|
sizeof(DirInfoBuffer),
|
|
|
|
TRUE,
|
|
|
|
TRUE,
|
|
|
|
&Context,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: can't find drive letter for system partition\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Keep searching until we find it */
|
|
|
|
do
|
|
|
|
{
|
|
|
|
/* Is this it? */
|
|
|
|
if ((RtlEqualUnicodeString(&DirInfo->TypeName, &SearchString, TRUE)) &&
|
|
|
|
(DirInfo->Name.Length == 2 * sizeof(WCHAR)) &&
|
|
|
|
(DirInfo->Name.Buffer[1] == L':'))
|
|
|
|
{
|
|
|
|
/* Looks like we found it, open the link to get its target */
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&DirInfo->Name,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
SmpDosDevicesObjectDirectory,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenSymbolicLinkObject(&LinkHandle,
|
|
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
|
|
&ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Open worked, query the target now */
|
|
|
|
Status = NtQuerySymbolicLinkObject(LinkHandle,
|
|
|
|
&LinkTarget,
|
|
|
|
NULL);
|
|
|
|
NtClose(LinkHandle);
|
|
|
|
|
|
|
|
/* Check if it matches the string we had found earlier */
|
|
|
|
if ((NT_SUCCESS(Status)) &&
|
|
|
|
((RtlEqualUnicodeString(&SystemPartition,
|
|
|
|
&LinkTarget,
|
|
|
|
TRUE)) ||
|
|
|
|
((RtlPrefixUnicodeString(&SystemPartition,
|
|
|
|
&LinkTarget,
|
|
|
|
TRUE)) &&
|
|
|
|
(LinkTarget.Buffer[SystemPartition.Length / sizeof(WCHAR)] == L'\\'))))
|
|
|
|
{
|
|
|
|
/* All done */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Couldn't find it, try again */
|
|
|
|
Status = NtQueryDirectoryObject(SmpDosDevicesObjectDirectory,
|
|
|
|
DirInfo,
|
|
|
|
sizeof(DirInfoBuffer),
|
|
|
|
TRUE,
|
|
|
|
FALSE,
|
|
|
|
&Context,
|
|
|
|
NULL);
|
|
|
|
} while (NT_SUCCESS(Status));
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: can't find drive letter for system partition\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Open the setup key again, for full access this time */
|
|
|
|
RtlInitUnicodeString(&UnicodeString,
|
|
|
|
L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&UnicodeString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: can't open software setup key for writing: 0x%x\n",
|
|
|
|
Status);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wrap up the end of the link buffer */
|
|
|
|
wcsncpy(LinkBuffer, DirInfo->Name.Buffer, 2);
|
|
|
|
LinkBuffer[2] = L'\\';
|
|
|
|
LinkBuffer[3] = L'\0';
|
|
|
|
|
|
|
|
/* Now set this as the "BootDir" */
|
|
|
|
RtlInitUnicodeString(&UnicodeString, L"BootDir");
|
|
|
|
Status = NtSetValueKey(KeyHandle,
|
|
|
|
&UnicodeString,
|
|
|
|
0,
|
|
|
|
REG_SZ,
|
|
|
|
LinkBuffer,
|
|
|
|
4 * sizeof(WCHAR));
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: couldn't write BootDir value: 0x%x\n", Status);
|
|
|
|
}
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
}
|
|
|
|
|
2012-01-30 03:44:27 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpCreateSecurityDescriptors(IN BOOLEAN InitialCall)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
PSID WorldSid = NULL, AdminSid = NULL, SystemSid = NULL;
|
|
|
|
PSID RestrictedSid = NULL, OwnerSid = NULL;
|
|
|
|
SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
|
|
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
|
|
|
|
SID_IDENTIFIER_AUTHORITY CreatorAuthority = {SECURITY_CREATOR_SID_AUTHORITY};
|
|
|
|
ULONG AclLength, SidLength;
|
|
|
|
PACL Acl;
|
|
|
|
PACE_HEADER Ace;
|
|
|
|
BOOLEAN ProtectionRequired = FALSE;
|
|
|
|
|
|
|
|
/* Check if this is the first call */
|
|
|
|
if (InitialCall)
|
|
|
|
{
|
|
|
|
/* Create and set the primary descriptor */
|
|
|
|
SmpPrimarySecurityDescriptor = &SmpPrimarySDBody;
|
|
|
|
Status = RtlCreateSecurityDescriptor(SmpPrimarySecurityDescriptor,
|
|
|
|
SECURITY_DESCRIPTOR_REVISION);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor,
|
|
|
|
TRUE,
|
|
|
|
NULL,
|
|
|
|
FALSE);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
/* Create and set the liberal descriptor */
|
|
|
|
SmpLiberalSecurityDescriptor = &SmpLiberalSDBody;
|
|
|
|
Status = RtlCreateSecurityDescriptor(SmpLiberalSecurityDescriptor,
|
|
|
|
SECURITY_DESCRIPTOR_REVISION);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor,
|
|
|
|
TRUE,
|
|
|
|
NULL,
|
|
|
|
FALSE);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
/* Create and set the \KnownDlls descriptor */
|
|
|
|
SmpKnownDllsSecurityDescriptor = &SmpKnownDllsSDBody;
|
|
|
|
Status = RtlCreateSecurityDescriptor(SmpKnownDllsSecurityDescriptor,
|
|
|
|
SECURITY_DESCRIPTOR_REVISION);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor,
|
|
|
|
TRUE,
|
|
|
|
NULL,
|
|
|
|
FALSE);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
/* Create and Set the \ApiPort descriptor */
|
|
|
|
SmpApiPortSecurityDescriptor = &SmpApiPortSDBody;
|
|
|
|
Status = RtlCreateSecurityDescriptor(SmpApiPortSecurityDescriptor,
|
|
|
|
SECURITY_DESCRIPTOR_REVISION);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor,
|
|
|
|
TRUE,
|
|
|
|
NULL,
|
|
|
|
FALSE);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if protection was requested in the registry (on by default) */
|
|
|
|
if (SmpProtectionMode & 1) ProtectionRequired = TRUE;
|
|
|
|
|
|
|
|
/* Exit if there's nothing to do */
|
|
|
|
if (!(InitialCall || ProtectionRequired)) return STATUS_SUCCESS;
|
|
|
|
|
|
|
|
/* Build the world SID */
|
|
|
|
Status = RtlAllocateAndInitializeSid(&WorldAuthority, 1,
|
|
|
|
SECURITY_WORLD_RID,
|
|
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
|
|
&WorldSid);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
WorldSid = NULL;
|
|
|
|
goto Quickie;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build the admin SID */
|
|
|
|
Status = RtlAllocateAndInitializeSid(&NtAuthority, 2,
|
|
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
|
|
0, 0, 0, 0, 0, 0,
|
|
|
|
&AdminSid);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
AdminSid = NULL;
|
|
|
|
goto Quickie;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build the owner SID */
|
|
|
|
Status = RtlAllocateAndInitializeSid(&CreatorAuthority, 1,
|
|
|
|
SECURITY_CREATOR_OWNER_RID,
|
|
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
|
|
&OwnerSid);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
OwnerSid = NULL;
|
|
|
|
goto Quickie;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build the restricted SID */
|
|
|
|
Status = RtlAllocateAndInitializeSid(&NtAuthority, 1,
|
|
|
|
SECURITY_RESTRICTED_CODE_RID,
|
|
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
|
|
&RestrictedSid);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
RestrictedSid = NULL;
|
|
|
|
goto Quickie;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build the system SID */
|
|
|
|
Status = RtlAllocateAndInitializeSid(&NtAuthority, 1,
|
|
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
|
|
&SystemSid);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
SystemSid = NULL;
|
|
|
|
goto Quickie;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now check if we're creating the core descriptors */
|
|
|
|
if (!InitialCall)
|
|
|
|
{
|
|
|
|
/* We're skipping NextAcl so we have to do this here */
|
|
|
|
SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(RestrictedSid) + RtlLengthSid(AdminSid);
|
|
|
|
SidLength *= 2;
|
|
|
|
goto NotInitial;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate an ACL with two ACEs with two SIDs each */
|
|
|
|
SidLength = RtlLengthSid(SystemSid) + RtlLengthSid(AdminSid);
|
|
|
|
AclLength = sizeof(ACL) + 2 * sizeof(ACCESS_ALLOWED_ACE) + SidLength;
|
|
|
|
Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength);
|
|
|
|
if (!Acl) Status = STATUS_NO_MEMORY;
|
|
|
|
if (!NT_SUCCESS(Status)) goto NextAcl;
|
|
|
|
|
|
|
|
/* Now build the ACL and add the two ACEs */
|
|
|
|
Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, SystemSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
/* Set this as the DACL */
|
|
|
|
Status = RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor,
|
|
|
|
TRUE,
|
|
|
|
Acl,
|
|
|
|
FALSE);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
NextAcl:
|
|
|
|
/* Allocate an ACL with 6 ACEs, two ACEs per SID */
|
|
|
|
SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(RestrictedSid) + RtlLengthSid(AdminSid);
|
|
|
|
SidLength *= 2;
|
|
|
|
AclLength = sizeof(ACL) + 6 * sizeof(ACCESS_ALLOWED_ACE) + SidLength;
|
|
|
|
Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength);
|
|
|
|
if (!Acl) Status = STATUS_NO_MEMORY;
|
|
|
|
if (!NT_SUCCESS(Status)) goto NotInitial;
|
|
|
|
|
|
|
|
/* Now build the ACL and add the six ACEs */
|
|
|
|
Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE, WorldSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE, RestrictedSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
/* Now edit the last three ACEs and make them inheritable */
|
|
|
|
Status = RtlGetAce(Acl, 3, (PVOID)&Ace);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
|
|
|
|
Status = RtlGetAce(Acl, 4, (PVOID)&Ace);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
|
|
|
|
Status = RtlGetAce(Acl, 5, (PVOID)&Ace);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
|
|
|
|
|
|
|
|
/* Set this as the DACL */
|
|
|
|
Status = RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor,
|
|
|
|
TRUE,
|
|
|
|
Acl,
|
|
|
|
FALSE);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
NotInitial:
|
|
|
|
/* The initial ACLs have been created, are we also protecting objects? */
|
|
|
|
if (!ProtectionRequired) goto Quickie;
|
|
|
|
|
|
|
|
/* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
|
|
|
|
SidLength += RtlLengthSid(OwnerSid);
|
|
|
|
AclLength = sizeof(ACL) + 7 * sizeof (ACCESS_ALLOWED_ACE) + 2 * SidLength;
|
|
|
|
Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength);
|
|
|
|
if (!Acl) Status = STATUS_NO_MEMORY;
|
|
|
|
if (!NT_SUCCESS(Status)) goto Quickie;
|
|
|
|
|
|
|
|
/* Build the ACL and add the seven ACEs */
|
|
|
|
Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, WorldSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, RestrictedSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, WorldSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, RestrictedSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, OwnerSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
/* Edit the last 4 ACEs to make then inheritable */
|
|
|
|
Status = RtlGetAce(Acl, 3, (PVOID)&Ace);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
|
|
|
|
Status = RtlGetAce(Acl, 4, (PVOID)&Ace);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
|
|
|
|
Status = RtlGetAce(Acl, 5, (PVOID)&Ace);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
|
|
|
|
Status = RtlGetAce(Acl, 6, (PVOID)&Ace);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
|
|
|
|
|
|
|
|
/* Set this as the DACL for the primary SD */
|
|
|
|
Status = RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor,
|
|
|
|
TRUE,
|
|
|
|
Acl,
|
|
|
|
FALSE);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
/* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
|
|
|
|
AclLength = sizeof(ACL) + 7 * sizeof (ACCESS_ALLOWED_ACE) + 2 * SidLength;
|
|
|
|
Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength);
|
|
|
|
if (!Acl) Status = STATUS_NO_MEMORY;
|
|
|
|
if (!NT_SUCCESS(Status)) goto Quickie;
|
|
|
|
|
|
|
|
/* Build the ACL and add the seven ACEs */
|
|
|
|
Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, OwnerSid);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
/* Edit the last 4 ACEs to make then inheritable */
|
|
|
|
Status = RtlGetAce(Acl, 3, (PVOID)&Ace);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
|
|
|
|
Status = RtlGetAce(Acl, 4, (PVOID)&Ace);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
|
|
|
|
Status = RtlGetAce(Acl, 5, (PVOID)&Ace);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
|
|
|
|
Status = RtlGetAce(Acl, 6, (PVOID)&Ace);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
|
|
|
|
|
|
|
|
/* Now set this as the DACL for the liberal SD */
|
|
|
|
Status = RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor,
|
|
|
|
TRUE,
|
|
|
|
Acl,
|
|
|
|
FALSE);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
Quickie:
|
|
|
|
/* Cleanup the SIDs */
|
|
|
|
if (OwnerSid) RtlFreeHeap(RtlGetProcessHeap(), 0, OwnerSid);
|
|
|
|
if (AdminSid) RtlFreeHeap(RtlGetProcessHeap(), 0, AdminSid);
|
|
|
|
if (WorldSid) RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid);
|
|
|
|
if (SystemSid) RtlFreeHeap(RtlGetProcessHeap(), 0, SystemSid);
|
|
|
|
if (RestrictedSid) RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSid);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2012-01-30 05:32:34 +00:00
|
|
|
SmpInitializeDosDevices(VOID)
|
2012-01-30 03:44:27 +00:00
|
|
|
{
|
2012-01-30 10:22:21 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
PSMP_REGISTRY_VALUE RegEntry;
|
|
|
|
SECURITY_DESCRIPTOR_CONTROL OldFlag = 0;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING DestinationString;
|
|
|
|
HANDLE DirHandle;
|
|
|
|
PLIST_ENTRY NextEntry, Head;
|
|
|
|
|
|
|
|
/* Open the GLOBAL?? directory */
|
|
|
|
RtlInitUnicodeString(&DestinationString, L"\\??");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&DestinationString,
|
|
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenDirectoryObject(&SmpDosDevicesObjectDirectory,
|
|
|
|
DIRECTORY_ALL_ACCESS,
|
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: Unable to open %wZ directory - Status == %lx\n",
|
|
|
|
&DestinationString, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Loop the DOS devices */
|
|
|
|
Head = &SmpDosDevicesList;
|
|
|
|
while (!IsListEmpty(Head))
|
|
|
|
{
|
|
|
|
/* Get the entry and remove it */
|
|
|
|
NextEntry = RemoveHeadList(Head);
|
|
|
|
RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
|
|
|
|
|
|
|
|
/* Initialize the attributes, and see which descriptor is being used */
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&RegEntry->Name,
|
|
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
|
|
|
|
SmpDosDevicesObjectDirectory,
|
|
|
|
SmpPrimarySecurityDescriptor);
|
|
|
|
if (SmpPrimarySecurityDescriptor)
|
|
|
|
{
|
|
|
|
/* Save the old flag and set it while we create this link */
|
|
|
|
OldFlag = SmpPrimarySecurityDescriptor->Control;
|
|
|
|
SmpPrimarySecurityDescriptor->Control |= SE_DACL_DEFAULTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create the symbolic link */
|
2012-02-06 18:57:18 +00:00
|
|
|
DPRINT("Creating symlink for %wZ to %wZ\n", &RegEntry->Name, &RegEntry->Value);
|
2012-01-30 10:22:21 +00:00
|
|
|
Status = NtCreateSymbolicLinkObject(&DirHandle,
|
|
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
|
|
&ObjectAttributes,
|
|
|
|
&RegEntry->Value);
|
|
|
|
if (Status == STATUS_OBJECT_NAME_EXISTS)
|
|
|
|
{
|
|
|
|
/* Make it temporary and get rid of the handle */
|
|
|
|
NtMakeTemporaryObject(DirHandle);
|
|
|
|
NtClose(DirHandle);
|
|
|
|
|
|
|
|
/* Treat this as success, and see if we got a name back */
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
if (RegEntry->Value.Length)
|
|
|
|
{
|
|
|
|
/* Create it now with this name */
|
|
|
|
ObjectAttributes.Attributes &= ~OBJ_OPENIF;
|
|
|
|
Status = NtCreateSymbolicLinkObject(&DirHandle,
|
|
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
|
|
&ObjectAttributes,
|
|
|
|
&RegEntry->Value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we were using a security descriptor, restore the non-defaulted flag */
|
|
|
|
if (ObjectAttributes.SecurityDescriptor)
|
|
|
|
{
|
|
|
|
SmpPrimarySecurityDescriptor->Control = OldFlag;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print a failure if we failed to create the symbolic link */
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: Unable to create %wZ => %wZ symbolic link object - Status == 0x%lx\n",
|
|
|
|
&RegEntry->Name,
|
|
|
|
&RegEntry->Value,
|
|
|
|
Status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Close the handle */
|
|
|
|
NtClose(DirHandle);
|
|
|
|
|
|
|
|
/* Free this entry */
|
|
|
|
if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
|
|
|
|
if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the status */
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
SmpProcessModuleImports(IN PVOID Unused,
|
|
|
|
IN PCHAR ImportName)
|
|
|
|
{
|
|
|
|
ULONG Length = 0, Chars;
|
|
|
|
WCHAR Buffer[MAX_PATH];
|
|
|
|
PWCHAR DllName, DllValue;
|
|
|
|
ANSI_STRING ImportString;
|
|
|
|
UNICODE_STRING ImportUnicodeString;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
/* Skip NTDLL since it's already always mapped */
|
|
|
|
if (!_stricmp(ImportName, "ntdll.dll")) return;
|
|
|
|
|
|
|
|
/* Initialize our strings */
|
|
|
|
RtlInitAnsiString(&ImportString, ImportName);
|
|
|
|
RtlInitEmptyUnicodeString(&ImportUnicodeString, Buffer, sizeof(Buffer));
|
|
|
|
Status = RtlAnsiStringToUnicodeString(&ImportUnicodeString, &ImportString, FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) return;
|
|
|
|
|
|
|
|
/* Loop in case we find a forwarder */
|
|
|
|
ImportUnicodeString.MaximumLength = ImportUnicodeString.Length + sizeof(UNICODE_NULL);
|
|
|
|
while (Length < ImportUnicodeString.Length)
|
|
|
|
{
|
|
|
|
if (ImportUnicodeString.Buffer[Length / sizeof(WCHAR)] == L'.') break;
|
|
|
|
Length += sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Break up the values as needed */
|
|
|
|
DllValue = ImportUnicodeString.Buffer;
|
|
|
|
DllName = &ImportUnicodeString.Buffer[ImportUnicodeString.MaximumLength / sizeof(WCHAR)];
|
|
|
|
Chars = Length >> 1;
|
|
|
|
wcsncpy(DllName, ImportUnicodeString.Buffer, Chars);
|
|
|
|
DllName[Chars] = 0;
|
|
|
|
|
|
|
|
/* Add the DLL to the list */
|
|
|
|
SmpSaveRegistryValue(&SmpKnownDllsList, DllName, DllValue, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpInitializeKnownDllsInternal(IN PUNICODE_STRING Directory,
|
|
|
|
IN PUNICODE_STRING Path)
|
|
|
|
{
|
|
|
|
HANDLE DirFileHandle, DirHandle, SectionHandle, FileHandle, LinkHandle;
|
|
|
|
UNICODE_STRING NtPath, DestinationString;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
NTSTATUS Status, Status1;
|
|
|
|
PLIST_ENTRY NextEntry;
|
|
|
|
PSMP_REGISTRY_VALUE RegEntry;
|
2013-09-12 06:01:52 +00:00
|
|
|
ULONG_PTR ErrorParameters[3];
|
|
|
|
UNICODE_STRING ErrorResponse;
|
2012-01-30 10:22:21 +00:00
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
2012-02-02 20:50:22 +00:00
|
|
|
SECURITY_DESCRIPTOR_CONTROL OldFlag = 0;
|
2012-01-30 10:22:21 +00:00
|
|
|
USHORT ImageCharacteristics;
|
|
|
|
|
|
|
|
/* Initialize to NULL */
|
|
|
|
DirFileHandle = NULL;
|
|
|
|
DirHandle = NULL;
|
|
|
|
NtPath.Buffer = NULL;
|
|
|
|
|
|
|
|
/* Create the \KnownDLLs directory */
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
Directory,
|
|
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
|
|
|
|
NULL,
|
|
|
|
SmpKnownDllsSecurityDescriptor);
|
|
|
|
Status = NtCreateDirectoryObject(&DirHandle,
|
|
|
|
DIRECTORY_ALL_ACCESS,
|
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Handle failure */
|
|
|
|
DPRINT1("SMSS: Unable to create %wZ directory - Status == %lx\n",
|
|
|
|
Directory, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert the path to native format */
|
|
|
|
if (!RtlDosPathNameToNtPathName_U(Path->Buffer, &NtPath, NULL, NULL))
|
|
|
|
{
|
|
|
|
/* Fail if this didn't work */
|
|
|
|
DPRINT1("SMSS: Unable to to convert %wZ to an Nt path\n", Path);
|
|
|
|
Status = STATUS_OBJECT_NAME_INVALID;
|
|
|
|
goto Quickie;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Open the path that was specified, which should be a directory */
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&NtPath,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenFile(&DirFileHandle,
|
|
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
|
|
|
&ObjectAttributes,
|
|
|
|
&IoStatusBlock,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Fail if we couldn't open it */
|
|
|
|
DPRINT1("SMSS: Unable to open a handle to the KnownDll directory (%wZ)"
|
|
|
|
"- Status == %lx\n",
|
|
|
|
Path,
|
|
|
|
Status);
|
|
|
|
FileHandle = NULL;
|
|
|
|
goto Quickie;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Temporarily hack the SD to use a default DACL for this symbolic link */
|
|
|
|
if (SmpPrimarySecurityDescriptor)
|
|
|
|
{
|
|
|
|
OldFlag = SmpPrimarySecurityDescriptor->Control;
|
|
|
|
SmpPrimarySecurityDescriptor->Control |= SE_DACL_DEFAULTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a symbolic link to the directory in the object manager */
|
|
|
|
RtlInitUnicodeString(&DestinationString, L"KnownDllPath");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&DestinationString,
|
|
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
|
|
|
|
DirHandle,
|
|
|
|
SmpPrimarySecurityDescriptor);
|
|
|
|
Status = NtCreateSymbolicLinkObject(&LinkHandle,
|
|
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
|
|
&ObjectAttributes,
|
|
|
|
Path);
|
|
|
|
|
|
|
|
/* Undo the hack */
|
|
|
|
if (SmpPrimarySecurityDescriptor) SmpPrimarySecurityDescriptor->Control = OldFlag;
|
|
|
|
|
|
|
|
/* Check if the symlink was created */
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* It wasn't, so bail out since the OS needs it to exist */
|
|
|
|
DPRINT1("SMSS: Unable to create %wZ symbolic link - Status == %lx\n",
|
|
|
|
&DestinationString, Status);
|
|
|
|
LinkHandle = NULL;
|
|
|
|
goto Quickie;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We created it permanent, we can go ahead and close the handle now */
|
|
|
|
Status1 = NtClose(LinkHandle);
|
|
|
|
ASSERT(NT_SUCCESS(Status1));
|
|
|
|
|
|
|
|
/* Now loop the known DLLs */
|
|
|
|
NextEntry = SmpKnownDllsList.Flink;
|
|
|
|
while (NextEntry != &SmpKnownDllsList)
|
|
|
|
{
|
2016-01-07 16:57:05 +00:00
|
|
|
/* Get the entry and move on */
|
2012-01-30 10:22:21 +00:00
|
|
|
RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
|
2016-01-07 16:57:05 +00:00
|
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
|
2012-02-06 18:57:18 +00:00
|
|
|
DPRINT("Processing known DLL: %wZ-%wZ\n", &RegEntry->Name, &RegEntry->Value);
|
2016-01-07 16:57:05 +00:00
|
|
|
|
2016-11-05 14:55:55 +00:00
|
|
|
/* Skip the entry if it's in the excluded list */
|
2012-01-30 10:22:21 +00:00
|
|
|
if ((SmpFindRegistryValue(&SmpExcludeKnownDllsList,
|
|
|
|
RegEntry->Name.Buffer)) ||
|
|
|
|
(SmpFindRegistryValue(&SmpExcludeKnownDllsList,
|
|
|
|
RegEntry->Value.Buffer)))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Open the actual file */
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&RegEntry->Value,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
DirFileHandle,
|
|
|
|
NULL);
|
2016-01-07 16:57:05 +00:00
|
|
|
Status1 = NtOpenFile(&FileHandle,
|
|
|
|
SYNCHRONIZE | FILE_EXECUTE,
|
|
|
|
&ObjectAttributes,
|
|
|
|
&IoStatusBlock,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_DELETE,
|
|
|
|
FILE_NON_DIRECTORY_FILE |
|
|
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
/* If we failed, skip it */
|
|
|
|
if (!NT_SUCCESS(Status1)) continue;
|
2012-01-30 10:22:21 +00:00
|
|
|
|
|
|
|
/* Checksum it */
|
|
|
|
Status = LdrVerifyImageMatchesChecksum((HANDLE)((ULONG_PTR)FileHandle | 1),
|
|
|
|
SmpProcessModuleImports,
|
|
|
|
RegEntry,
|
|
|
|
&ImageCharacteristics);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Checksum failed, so don't even try going further -- kill SMSS */
|
|
|
|
RtlInitUnicodeString(&ErrorResponse,
|
|
|
|
L"Verification of a KnownDLL failed.");
|
2018-07-07 14:09:03 +00:00
|
|
|
ErrorParameters[0] = (ULONG_PTR)&ErrorResponse;
|
2012-01-30 10:22:21 +00:00
|
|
|
ErrorParameters[1] = Status;
|
2018-07-07 14:09:03 +00:00
|
|
|
ErrorParameters[2] = (ULONG_PTR)&RegEntry->Value;
|
2012-01-30 10:22:21 +00:00
|
|
|
SmpTerminate(ErrorParameters, 5, RTL_NUMBER_OF(ErrorParameters));
|
|
|
|
}
|
2016-01-07 16:57:05 +00:00
|
|
|
else if (!(ImageCharacteristics & IMAGE_FILE_DLL))
|
2012-01-30 10:22:21 +00:00
|
|
|
{
|
|
|
|
/* An invalid known DLL entry will also kill SMSS */
|
|
|
|
RtlInitUnicodeString(&ErrorResponse,
|
|
|
|
L"Non-DLL file included in KnownDLL list.");
|
2018-07-07 14:09:03 +00:00
|
|
|
ErrorParameters[0] = (ULONG_PTR)&ErrorResponse;
|
2012-01-30 10:22:21 +00:00
|
|
|
ErrorParameters[1] = STATUS_INVALID_IMPORT_OF_NON_DLL;
|
2018-07-07 14:09:03 +00:00
|
|
|
ErrorParameters[2] = (ULONG_PTR)&RegEntry->Value;
|
2012-01-30 10:22:21 +00:00
|
|
|
SmpTerminate(ErrorParameters, 5, RTL_NUMBER_OF(ErrorParameters));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Temporarily hack the SD to use a default DACL for this section */
|
|
|
|
if (SmpLiberalSecurityDescriptor)
|
|
|
|
{
|
|
|
|
OldFlag = SmpLiberalSecurityDescriptor->Control;
|
|
|
|
SmpLiberalSecurityDescriptor->Control |= SE_DACL_DEFAULTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create the section for this known DLL */
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&RegEntry->Value,
|
|
|
|
OBJ_PERMANENT,
|
|
|
|
DirHandle,
|
|
|
|
SmpLiberalSecurityDescriptor)
|
|
|
|
Status = NtCreateSection(&SectionHandle,
|
|
|
|
SECTION_ALL_ACCESS,
|
|
|
|
&ObjectAttributes,
|
|
|
|
0,
|
|
|
|
PAGE_EXECUTE,
|
|
|
|
SEC_IMAGE,
|
|
|
|
FileHandle);
|
|
|
|
|
|
|
|
/* Undo the hack */
|
|
|
|
if (SmpLiberalSecurityDescriptor) SmpLiberalSecurityDescriptor->Control = OldFlag;
|
|
|
|
|
|
|
|
/* Check if we created the section okay */
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* We can close it now, since it's marked permanent */
|
|
|
|
Status1 = NtClose(SectionHandle);
|
|
|
|
ASSERT(NT_SUCCESS(Status1));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If we couldn't make it "known", that's fine and keep going */
|
|
|
|
DPRINT1("SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n",
|
|
|
|
&RegEntry->Value, Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Close the file since we can move on to the next one */
|
|
|
|
Status1 = NtClose(FileHandle);
|
|
|
|
ASSERT(NT_SUCCESS(Status1));
|
|
|
|
}
|
|
|
|
|
|
|
|
Quickie:
|
|
|
|
/* Close both handles and free the NT path buffer */
|
|
|
|
if (DirHandle)
|
|
|
|
{
|
|
|
|
Status1 = NtClose(DirHandle);
|
|
|
|
ASSERT(NT_SUCCESS(Status1));
|
|
|
|
}
|
|
|
|
if (DirFileHandle)
|
|
|
|
{
|
|
|
|
Status1 = NtClose(DirFileHandle);
|
|
|
|
ASSERT(NT_SUCCESS(Status1));
|
|
|
|
}
|
|
|
|
if (NtPath.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath.Buffer);
|
|
|
|
return Status;
|
2012-01-30 03:44:27 +00:00
|
|
|
}
|
|
|
|
|
2012-01-30 05:32:34 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpInitializeKnownDlls(VOID)
|
|
|
|
{
|
2012-01-30 10:22:21 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
PSMP_REGISTRY_VALUE RegEntry;
|
|
|
|
UNICODE_STRING DestinationString;
|
|
|
|
PLIST_ENTRY Head, NextEntry;
|
|
|
|
|
|
|
|
/* Call the internal function */
|
|
|
|
RtlInitUnicodeString(&DestinationString, L"\\KnownDlls");
|
|
|
|
Status = SmpInitializeKnownDllsInternal(&DestinationString, &SmpKnownDllPath);
|
|
|
|
|
|
|
|
/* Wipe out the list regardless of success */
|
|
|
|
Head = &SmpKnownDllsList;
|
|
|
|
while (!IsListEmpty(Head))
|
|
|
|
{
|
|
|
|
/* Remove this entry */
|
|
|
|
NextEntry = RemoveHeadList(Head);
|
|
|
|
|
|
|
|
/* Free it */
|
|
|
|
RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All done */
|
|
|
|
return Status;
|
2012-01-30 05:32:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpCreateDynamicEnvironmentVariables(VOID)
|
|
|
|
{
|
2012-01-31 01:19:14 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
SYSTEM_BASIC_INFORMATION BasicInfo;
|
|
|
|
SYSTEM_PROCESSOR_INFORMATION ProcessorInfo;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING ValueName, DestinationString;
|
|
|
|
HANDLE KeyHandle, KeyHandle2;
|
|
|
|
ULONG ResultLength;
|
2016-01-07 16:57:05 +00:00
|
|
|
PWCHAR ValueData;
|
2012-01-31 01:19:14 +00:00
|
|
|
WCHAR ValueBuffer[512], ValueBuffer2[512];
|
|
|
|
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
|
|
|
|
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo2 = (PVOID)ValueBuffer2;
|
|
|
|
|
|
|
|
/* Get system basic information -- we'll need the CPU count */
|
|
|
|
Status = NtQuerySystemInformation(SystemBasicInformation,
|
|
|
|
&BasicInfo,
|
|
|
|
sizeof(BasicInfo),
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Bail out on failure */
|
|
|
|
DPRINT1("SMSS: Unable to query system basic information - %x\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the processor information, we'll query a bunch of revision info */
|
|
|
|
Status = NtQuerySystemInformation(SystemProcessorInformation,
|
|
|
|
&ProcessorInfo,
|
|
|
|
sizeof(ProcessorInfo),
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Bail out on failure */
|
|
|
|
DPRINT1("SMSS: Unable to query system processor information - %x\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We'll be writing all these environment variables over here */
|
|
|
|
RtlInitUnicodeString(&DestinationString,
|
|
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\"
|
2012-02-02 20:50:22 +00:00
|
|
|
L"Control\\Session Manager\\Environment");
|
2012-01-31 01:19:14 +00:00
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&DestinationString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&KeyHandle, GENERIC_WRITE, &ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Bail out on failure */
|
|
|
|
DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* First let's write the OS variable */
|
|
|
|
RtlInitUnicodeString(&ValueName, L"OS");
|
2016-01-07 16:57:05 +00:00
|
|
|
ValueData = L"Windows_NT";
|
|
|
|
DPRINT("Setting %wZ to %S\n", &ValueName, ValueData);
|
2012-01-31 01:19:14 +00:00
|
|
|
Status = NtSetValueKey(KeyHandle,
|
|
|
|
&ValueName,
|
|
|
|
0,
|
|
|
|
REG_SZ,
|
2016-01-07 16:57:05 +00:00
|
|
|
ValueData,
|
|
|
|
(wcslen(ValueData) + 1) * sizeof(WCHAR));
|
2012-01-31 01:19:14 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
|
|
|
|
&ValueName, Status);
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Next, let's write the CPU architecture variable */
|
|
|
|
RtlInitUnicodeString(&ValueName, L"PROCESSOR_ARCHITECTURE");
|
|
|
|
switch (ProcessorInfo.ProcessorArchitecture)
|
|
|
|
{
|
|
|
|
/* Pick the correct string that matches the architecture */
|
|
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
2016-01-07 16:57:05 +00:00
|
|
|
ValueData = L"x86";
|
2012-01-31 01:19:14 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
2016-01-07 16:57:05 +00:00
|
|
|
ValueData = L"AMD64";
|
2012-01-31 01:19:14 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PROCESSOR_ARCHITECTURE_IA64:
|
2016-01-07 16:57:05 +00:00
|
|
|
ValueData = L"IA64";
|
2012-01-31 01:19:14 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2016-01-07 16:57:05 +00:00
|
|
|
ValueData = L"Unknown";
|
2012-01-31 01:19:14 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set it */
|
2016-01-07 16:57:05 +00:00
|
|
|
DPRINT("Setting %wZ to %S\n", &ValueName, ValueData);
|
2012-01-31 01:19:14 +00:00
|
|
|
Status = NtSetValueKey(KeyHandle,
|
|
|
|
&ValueName,
|
|
|
|
0,
|
|
|
|
REG_SZ,
|
2016-01-07 16:57:05 +00:00
|
|
|
ValueData,
|
|
|
|
(wcslen(ValueData) + 1) * sizeof(WCHAR));
|
2012-01-31 01:19:14 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
|
|
|
|
&ValueName, Status);
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* And now let's write the processor level */
|
|
|
|
RtlInitUnicodeString(&ValueName, L"PROCESSOR_LEVEL");
|
|
|
|
swprintf(ValueBuffer, L"%u", ProcessorInfo.ProcessorLevel);
|
2012-02-06 18:57:18 +00:00
|
|
|
DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
|
2012-01-31 01:19:14 +00:00
|
|
|
Status = NtSetValueKey(KeyHandle,
|
|
|
|
&ValueName,
|
|
|
|
0,
|
|
|
|
REG_SZ,
|
|
|
|
ValueBuffer,
|
2016-01-07 16:57:05 +00:00
|
|
|
(wcslen(ValueBuffer) + 1) * sizeof(WCHAR));
|
2012-01-31 01:19:14 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
|
|
|
|
&ValueName, Status);
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now open the hardware CPU key */
|
|
|
|
RtlInitUnicodeString(&DestinationString,
|
|
|
|
L"\\Registry\\Machine\\Hardware\\Description\\System\\"
|
2012-02-02 20:50:22 +00:00
|
|
|
L"CentralProcessor\\0");
|
2012-01-31 01:19:14 +00:00
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&DestinationString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&KeyHandle2, KEY_READ, &ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString, Status);
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* So that we can read the identifier out of it... */
|
|
|
|
RtlInitUnicodeString(&ValueName, L"Identifier");
|
|
|
|
Status = NtQueryValueKey(KeyHandle2,
|
|
|
|
&ValueName,
|
|
|
|
KeyValuePartialInformation,
|
|
|
|
PartialInfo,
|
|
|
|
sizeof(ValueBuffer),
|
|
|
|
&ResultLength);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
NtClose(KeyHandle2);
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
DPRINT1("SMSS: Unable to read %wZ\\%wZ - %x\n",
|
|
|
|
&DestinationString, &ValueName, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* As well as the vendor... */
|
|
|
|
RtlInitUnicodeString(&ValueName, L"VendorIdentifier");
|
|
|
|
Status = NtQueryValueKey(KeyHandle2,
|
|
|
|
&ValueName,
|
|
|
|
KeyValuePartialInformation,
|
|
|
|
PartialInfo2,
|
|
|
|
sizeof(ValueBuffer2),
|
|
|
|
&ResultLength);
|
|
|
|
NtClose(KeyHandle2);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* To combine it into a single string */
|
|
|
|
swprintf((PWCHAR)PartialInfo->Data + wcslen((PWCHAR)PartialInfo->Data),
|
2013-09-03 12:02:52 +00:00
|
|
|
L", %S",
|
2012-01-31 01:19:14 +00:00
|
|
|
PartialInfo2->Data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* So that we can set this as the PROCESSOR_IDENTIFIER variable */
|
|
|
|
RtlInitUnicodeString(&ValueName, L"PROCESSOR_IDENTIFIER");
|
2013-09-03 12:02:52 +00:00
|
|
|
DPRINT("Setting %wZ to %s\n", &ValueName, PartialInfo->Data);
|
2012-01-31 01:19:14 +00:00
|
|
|
Status = NtSetValueKey(KeyHandle,
|
|
|
|
&ValueName,
|
|
|
|
0,
|
|
|
|
REG_SZ,
|
|
|
|
PartialInfo->Data,
|
2016-01-07 16:57:05 +00:00
|
|
|
(wcslen((PWCHAR)PartialInfo->Data) + 1) * sizeof(WCHAR));
|
2012-01-31 01:19:14 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
|
|
|
|
&ValueName, Status);
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now let's get the processor architecture */
|
|
|
|
RtlInitUnicodeString(&ValueName, L"PROCESSOR_REVISION");
|
|
|
|
switch (ProcessorInfo.ProcessorArchitecture)
|
|
|
|
{
|
|
|
|
/* Check if this is an older Intel CPU */
|
|
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
|
|
if ((ProcessorInfo.ProcessorRevision >> 8) == 0xFF)
|
|
|
|
{
|
|
|
|
/* These guys used a revision + stepping, so get the rev only */
|
|
|
|
swprintf(ValueBuffer, L"%02x", ProcessorInfo.ProcessorRevision & 0xFF);
|
|
|
|
_wcsupr(ValueBuffer);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Modern Intel, as well as 64-bit CPUs use a revision without stepping */
|
|
|
|
case PROCESSOR_ARCHITECTURE_IA64:
|
|
|
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
|
|
|
swprintf(ValueBuffer, L"%04x", ProcessorInfo.ProcessorRevision);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* And anything else we'll just read the whole revision identifier */
|
|
|
|
default:
|
|
|
|
swprintf(ValueBuffer, L"%u", ProcessorInfo.ProcessorRevision);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write the revision to the registry */
|
2012-02-06 18:57:18 +00:00
|
|
|
DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
|
2012-01-31 01:19:14 +00:00
|
|
|
Status = NtSetValueKey(KeyHandle,
|
|
|
|
&ValueName,
|
|
|
|
0,
|
|
|
|
REG_SZ,
|
|
|
|
ValueBuffer,
|
2016-01-07 16:57:05 +00:00
|
|
|
(wcslen(ValueBuffer) + 1) * sizeof(WCHAR));
|
2012-01-31 01:19:14 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
|
|
|
|
&ValueName, Status);
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* And finally, write the number of CPUs */
|
|
|
|
RtlInitUnicodeString(&ValueName, L"NUMBER_OF_PROCESSORS");
|
2013-09-03 12:02:52 +00:00
|
|
|
swprintf(ValueBuffer, L"%d", BasicInfo.NumberOfProcessors);
|
2012-02-06 18:57:18 +00:00
|
|
|
DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
|
2012-01-31 01:19:14 +00:00
|
|
|
Status = NtSetValueKey(KeyHandle,
|
|
|
|
&ValueName,
|
|
|
|
0,
|
|
|
|
REG_SZ,
|
|
|
|
ValueBuffer,
|
2016-01-07 16:57:05 +00:00
|
|
|
(wcslen(ValueBuffer) + 1) * sizeof(WCHAR));
|
2012-01-31 01:19:14 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
|
|
|
|
&ValueName, Status);
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now we need to write the safeboot option key in a different format */
|
|
|
|
RtlInitUnicodeString(&DestinationString,
|
|
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\"
|
2012-02-02 20:50:22 +00:00
|
|
|
L"Control\\Safeboot\\Option");
|
2012-01-31 01:19:14 +00:00
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&DestinationString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&KeyHandle2, KEY_ALL_ACCESS, &ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* This was indeed a safeboot, so check what kind of safeboot it was */
|
|
|
|
RtlInitUnicodeString(&ValueName, L"OptionValue");
|
|
|
|
Status = NtQueryValueKey(KeyHandle2,
|
|
|
|
&ValueName,
|
|
|
|
KeyValuePartialInformation,
|
|
|
|
PartialInfo,
|
|
|
|
sizeof(ValueBuffer),
|
|
|
|
&ResultLength);
|
|
|
|
NtClose(KeyHandle2);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Convert from the integer value to the correct specifier */
|
|
|
|
RtlInitUnicodeString(&ValueName, L"SAFEBOOT_OPTION");
|
|
|
|
switch (*(PULONG)PartialInfo->Data)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
wcscpy(ValueBuffer, L"MINIMAL");
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
wcscpy(ValueBuffer, L"NETWORK");
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
wcscpy(ValueBuffer, L"DSREPAIR");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* And write it in the environment! */
|
2012-02-06 18:57:18 +00:00
|
|
|
DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
|
2012-01-31 01:19:14 +00:00
|
|
|
Status = NtSetValueKey(KeyHandle,
|
|
|
|
&ValueName,
|
|
|
|
0,
|
|
|
|
REG_SZ,
|
|
|
|
ValueBuffer,
|
2016-01-07 16:57:05 +00:00
|
|
|
(wcslen(ValueBuffer) + 1) * sizeof(WCHAR));
|
2012-01-31 01:19:14 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
|
|
|
|
&ValueName, Status);
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: Failed querying safeboot option = %x\n", Status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We are all done now */
|
|
|
|
NtClose(KeyHandle);
|
2012-01-30 05:32:34 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpProcessFileRenames(VOID)
|
|
|
|
{
|
2012-02-22 11:31:04 +00:00
|
|
|
BOOLEAN OldState, HavePrivilege = FALSE;
|
2012-02-06 09:06:38 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
HANDLE FileHandle, OtherFileHandle;
|
|
|
|
FILE_INFORMATION_CLASS InformationClass;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
UNICODE_STRING FileString;
|
|
|
|
FILE_BASIC_INFORMATION BasicInfo;
|
|
|
|
FILE_DISPOSITION_INFORMATION DeleteInformation;
|
|
|
|
PFILE_RENAME_INFORMATION Buffer;
|
|
|
|
PLIST_ENTRY Head, NextEntry;
|
|
|
|
PSMP_REGISTRY_VALUE RegEntry;
|
|
|
|
PWCHAR FileName;
|
|
|
|
ULONG ValueLength, Length;
|
|
|
|
|
|
|
|
/* Give us access to restore any files we want */
|
|
|
|
Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &OldState);
|
|
|
|
if (NT_SUCCESS(Status)) HavePrivilege = TRUE;
|
|
|
|
|
2016-01-07 19:03:35 +00:00
|
|
|
// FIXME: Handle SFC-protected file renames!
|
|
|
|
if (SmpAllowProtectedRenames)
|
|
|
|
DPRINT1("SMSS: FIXME: Handle SFC-protected file renames!\n");
|
|
|
|
|
2012-02-06 09:06:38 +00:00
|
|
|
/* Process pending files to rename */
|
|
|
|
Head = &SmpFileRenameList;
|
|
|
|
while (!IsListEmpty(Head))
|
|
|
|
{
|
|
|
|
/* Get this entry */
|
|
|
|
NextEntry = RemoveHeadList(Head);
|
|
|
|
RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
|
2016-03-22 18:34:18 +00:00
|
|
|
DPRINT("Processing PFRO: '%wZ' / '%wZ'\n", &RegEntry->Value, &RegEntry->Name);
|
2012-02-06 09:06:38 +00:00
|
|
|
|
|
|
|
/* Skip past the '@' marker */
|
|
|
|
if (!(RegEntry->Value.Length) && (*RegEntry->Name.Buffer == L'@'))
|
|
|
|
{
|
|
|
|
RegEntry->Name.Length -= sizeof(UNICODE_NULL);
|
|
|
|
RegEntry->Name.Buffer++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Open the file for delete access */
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&RegEntry->Name,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenFile(&OtherFileHandle,
|
|
|
|
DELETE | SYNCHRONIZE,
|
|
|
|
&ObjectAttributes,
|
|
|
|
&IoStatusBlock,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
if (!NT_SUCCESS(Status)) goto Quickie;
|
|
|
|
|
|
|
|
/* Check if it's a rename or just a delete */
|
|
|
|
ValueLength = RegEntry->Value.Length;
|
|
|
|
if (!ValueLength)
|
|
|
|
{
|
|
|
|
/* Just a delete, set up the class, length and buffer */
|
|
|
|
InformationClass = FileDispositionInformation;
|
|
|
|
Length = sizeof(DeleteInformation);
|
|
|
|
Buffer = (PFILE_RENAME_INFORMATION)&DeleteInformation;
|
|
|
|
|
|
|
|
/* Set the delete disposition */
|
|
|
|
DeleteInformation.DeleteFile = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* This is a rename, setup the class and length */
|
|
|
|
InformationClass = FileRenameInformation;
|
|
|
|
Length = ValueLength + sizeof(FILE_RENAME_INFORMATION);
|
|
|
|
|
|
|
|
/* Skip past the special markers */
|
|
|
|
FileName = RegEntry->Value.Buffer;
|
|
|
|
if ((*FileName == L'!') || (*FileName == L'@'))
|
|
|
|
{
|
|
|
|
FileName++;
|
|
|
|
Length -= sizeof(UNICODE_NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now allocate the buffer for the rename information */
|
|
|
|
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag, Length);
|
|
|
|
if (Buffer)
|
|
|
|
{
|
|
|
|
/* Setup the buffer to point to the filename, and copy it */
|
|
|
|
Buffer->RootDirectory = NULL;
|
|
|
|
Buffer->FileNameLength = Length - sizeof(FILE_RENAME_INFORMATION);
|
|
|
|
Buffer->ReplaceIfExists = FileName != RegEntry->Value.Buffer;
|
|
|
|
RtlCopyMemory(Buffer->FileName, FileName, Buffer->FileNameLength);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Fail */
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if everything is okay till here */
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Now either rename or delete the file as requested */
|
|
|
|
Status = NtSetInformationFile(OtherFileHandle,
|
|
|
|
&IoStatusBlock,
|
|
|
|
Buffer,
|
|
|
|
Length,
|
|
|
|
InformationClass);
|
|
|
|
|
|
|
|
/* Check if we seem to have failed because the file was readonly */
|
2016-01-07 19:03:35 +00:00
|
|
|
if (!NT_SUCCESS(Status) &&
|
2012-02-06 09:06:38 +00:00
|
|
|
(InformationClass == FileRenameInformation) &&
|
|
|
|
(Status == STATUS_OBJECT_NAME_COLLISION) &&
|
2016-01-07 19:03:35 +00:00
|
|
|
Buffer->ReplaceIfExists)
|
2012-02-06 09:06:38 +00:00
|
|
|
{
|
|
|
|
/* Open the file for write attribute access this time... */
|
2016-03-22 18:34:18 +00:00
|
|
|
DPRINT("\nSMSS: '%wZ' => '%wZ' failed - Status == %x, Possible readonly target\n",
|
2012-02-06 09:06:38 +00:00
|
|
|
&RegEntry->Name,
|
|
|
|
&RegEntry->Value,
|
|
|
|
STATUS_OBJECT_NAME_COLLISION);
|
|
|
|
FileString.Length = RegEntry->Value.Length - sizeof(WCHAR);
|
|
|
|
FileString.MaximumLength = RegEntry->Value.MaximumLength - sizeof(WCHAR);
|
|
|
|
FileString.Buffer = FileName;
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&FileString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenFile(&FileHandle,
|
|
|
|
FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
|
|
|
|
&ObjectAttributes,
|
|
|
|
&IoStatusBlock,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* That didn't work, so bail out */
|
|
|
|
DPRINT1(" SMSS: Open Existing file Failed - Status == %x\n",
|
|
|
|
Status);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Now remove the read-only attribute from the file */
|
2016-03-22 18:34:18 +00:00
|
|
|
DPRINT(" SMSS: Open Existing Success\n");
|
2012-02-06 09:06:38 +00:00
|
|
|
RtlZeroMemory(&BasicInfo, sizeof(BasicInfo));
|
|
|
|
BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
|
|
Status = NtSetInformationFile(FileHandle,
|
|
|
|
&IoStatusBlock,
|
|
|
|
&BasicInfo,
|
|
|
|
sizeof(BasicInfo),
|
|
|
|
FileBasicInformation);
|
|
|
|
NtClose(FileHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* That didn't work, bail out */
|
|
|
|
DPRINT1(" SMSS: Set To NORMAL Failed - Status == %x\n",
|
|
|
|
Status);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Now that the file is no longer read-only, delete! */
|
2016-03-22 18:34:18 +00:00
|
|
|
DPRINT(" SMSS: Set To NORMAL OK\n");
|
2012-02-06 09:06:38 +00:00
|
|
|
Status = NtSetInformationFile(OtherFileHandle,
|
|
|
|
&IoStatusBlock,
|
|
|
|
Buffer,
|
|
|
|
Length,
|
|
|
|
FileRenameInformation);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* That failed too! */
|
|
|
|
DPRINT1(" SMSS: Re-Rename Failed - Status == %x\n",
|
|
|
|
Status);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Everything ok */
|
2016-03-22 18:34:18 +00:00
|
|
|
DPRINT(" SMSS: Re-Rename Worked OK\n");
|
2012-02-06 09:06:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Close the file handle and check the operation result */
|
|
|
|
NtClose(OtherFileHandle);
|
|
|
|
Quickie:
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* We totally failed */
|
2015-02-20 22:03:23 +00:00
|
|
|
DPRINT1("SMSS: '%wZ' => '%wZ' failed - Status == %x\n",
|
2012-02-06 09:06:38 +00:00
|
|
|
&RegEntry->Name, &RegEntry->Value, Status);
|
|
|
|
}
|
|
|
|
else if (RegEntry->Value.Length)
|
|
|
|
{
|
|
|
|
/* We succeed with a rename */
|
2016-03-22 18:34:18 +00:00
|
|
|
DPRINT("SMSS: '%wZ' (renamed to) '%wZ'\n", &RegEntry->Name, &RegEntry->Value);
|
2012-02-06 09:06:38 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-11-05 14:55:55 +00:00
|
|
|
/* We succeeded with a delete */
|
2016-03-22 18:34:18 +00:00
|
|
|
DPRINT("SMSS: '%wZ' (deleted)\n", &RegEntry->Name);
|
2012-02-06 09:06:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Now free this entry and keep going */
|
|
|
|
if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
|
|
|
|
if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Put back the restore privilege if we had requested it, and return */
|
|
|
|
if (HavePrivilege) RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, FALSE, FALSE, &OldState);
|
|
|
|
return Status;
|
2012-01-30 05:32:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpLoadDataFromRegistry(OUT PUNICODE_STRING InitialCommand)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
PLIST_ENTRY Head, NextEntry;
|
|
|
|
PSMP_REGISTRY_VALUE RegEntry;
|
|
|
|
PVOID OriginalEnvironment;
|
|
|
|
ULONG MuSessionId = 0;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
HANDLE KeyHandle;
|
|
|
|
UNICODE_STRING DestinationString;
|
[SMSS]: Co-exist with SMSS2 by using OBJ_OPENIF when creating object directories and sections, in case SMSS2 has already done so (which now it probably will).
[SMSS2]: Implement all the required registry configuration parsing functions. KnownDLLs, DosDevices, PageFiles, Subsystems, ExcludedKnownDLLs, PendingFileRenameOperations, ObjectDirectories, Environment keys are all processed and put into lists. Other than creating the object directories and setting the environment variables, though, no other work happens -- but we do DPRINT1 what should happen.
svn path=/trunk/; revision=55319
2012-01-30 08:02:17 +00:00
|
|
|
|
2012-01-30 05:32:34 +00:00
|
|
|
/* Initialize the keywords we'll be looking for */
|
|
|
|
RtlInitUnicodeString(&SmpDebugKeyword, L"debug");
|
|
|
|
RtlInitUnicodeString(&SmpASyncKeyword, L"async");
|
|
|
|
RtlInitUnicodeString(&SmpAutoChkKeyword, L"autocheck");
|
|
|
|
|
|
|
|
/* Initialize all the registry-associated list heads */
|
|
|
|
InitializeListHead(&SmpBootExecuteList);
|
|
|
|
InitializeListHead(&SmpSetupExecuteList);
|
|
|
|
InitializeListHead(&SmpPagingFileList);
|
|
|
|
InitializeListHead(&SmpDosDevicesList);
|
|
|
|
InitializeListHead(&SmpFileRenameList);
|
|
|
|
InitializeListHead(&SmpKnownDllsList);
|
|
|
|
InitializeListHead(&SmpExcludeKnownDllsList);
|
|
|
|
InitializeListHead(&SmpSubSystemList);
|
|
|
|
InitializeListHead(&SmpSubSystemsToLoad);
|
|
|
|
InitializeListHead(&SmpSubSystemsToDefer);
|
|
|
|
InitializeListHead(&SmpExecuteList);
|
|
|
|
SmpPagingFileInitialize();
|
|
|
|
|
|
|
|
/* Initialize the SMSS environment */
|
|
|
|
Status = RtlCreateEnvironment(TRUE, &SmpDefaultEnvironment);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Fail if there was a problem */
|
|
|
|
DPRINT1("SMSS: Unable to allocate default environment - Status == %X\n",
|
|
|
|
Status);
|
|
|
|
SMSS_CHECKPOINT(RtlCreateEnvironment, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if we were booted in PE mode (LiveCD should have this) */
|
|
|
|
RtlInitUnicodeString(&DestinationString,
|
|
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\"
|
2012-02-02 20:50:22 +00:00
|
|
|
L"Control\\MiniNT");
|
2012-01-30 05:32:34 +00:00
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&DestinationString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* If the key exists, we were */
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
MiniNTBoot = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print out if this is the case */
|
2016-03-22 18:34:18 +00:00
|
|
|
if (MiniNTBoot) DPRINT("SMSS: !!! MiniNT Boot !!!\n");
|
2012-01-30 05:32:34 +00:00
|
|
|
|
|
|
|
/* Open the environment key to see if we are booted in safe mode */
|
|
|
|
RtlInitUnicodeString(&DestinationString,
|
|
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\"
|
2012-02-02 20:50:22 +00:00
|
|
|
L"Control\\Session Manager\\Environment");
|
2012-01-30 05:32:34 +00:00
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&DestinationString,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Delete the value if we found it */
|
|
|
|
RtlInitUnicodeString(&DestinationString, L"SAFEBOOT_OPTION");
|
|
|
|
NtDeleteValueKey(KeyHandle, &DestinationString);
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Switch environments, then query the registry for all needed settings */
|
|
|
|
OriginalEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
|
|
|
|
NtCurrentPeb()->ProcessParameters->Environment = SmpDefaultEnvironment;
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
|
|
|
|
L"Session Manager",
|
|
|
|
SmpRegistryConfigurationTable,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
SmpDefaultEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
|
|
|
|
NtCurrentPeb()->ProcessParameters->Environment = OriginalEnvironment;
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* We failed somewhere in registry initialization, which is bad... */
|
|
|
|
DPRINT1("SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status);
|
|
|
|
SMSS_CHECKPOINT(RtlQueryRegistryValues, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now we can start acting on the registry settings. First to DOS devices */
|
|
|
|
Status = SmpInitializeDosDevices();
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Failed */
|
|
|
|
DPRINT1("SMSS: Unable to initialize DosDevices configuration - Status == %lx\n",
|
|
|
|
Status);
|
|
|
|
SMSS_CHECKPOINT(SmpInitializeDosDevices, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Next create the session directory... */
|
|
|
|
RtlInitUnicodeString(&DestinationString, L"\\Sessions");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&DestinationString,
|
|
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
|
|
|
|
NULL,
|
|
|
|
SmpPrimarySecurityDescriptor);
|
|
|
|
Status = NtCreateDirectoryObject(&SmpSessionsObjectDirectory,
|
|
|
|
DIRECTORY_ALL_ACCESS,
|
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Fail */
|
|
|
|
DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
|
|
|
|
&DestinationString, Status);
|
|
|
|
SMSS_CHECKPOINT(NtCreateDirectoryObject, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Next loop all the boot execute binaries */
|
|
|
|
Head = &SmpBootExecuteList;
|
|
|
|
while (!IsListEmpty(Head))
|
|
|
|
{
|
|
|
|
/* Remove each one from the list */
|
|
|
|
NextEntry = RemoveHeadList(Head);
|
|
|
|
|
|
|
|
/* Execute it */
|
|
|
|
RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
|
|
|
|
SmpExecuteCommand(&RegEntry->Name, 0, NULL, 0);
|
|
|
|
|
|
|
|
/* And free it */
|
|
|
|
if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
|
|
|
|
if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now do any pending file rename operations... */
|
|
|
|
if (!MiniNTBoot) SmpProcessFileRenames();
|
|
|
|
|
|
|
|
/* And initialize known DLLs... */
|
|
|
|
Status = SmpInitializeKnownDlls();
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Fail if that didn't work */
|
|
|
|
DPRINT1("SMSS: Unable to initialize KnownDll configuration - Status == %lx\n",
|
|
|
|
Status);
|
|
|
|
SMSS_CHECKPOINT(SmpInitializeKnownDlls, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2016-01-07 16:57:05 +00:00
|
|
|
/* Create the needed page files */
|
|
|
|
if (!MiniNTBoot)
|
2012-01-30 05:32:34 +00:00
|
|
|
{
|
2016-01-07 16:57:05 +00:00
|
|
|
/* Loop every page file */
|
|
|
|
Head = &SmpPagingFileList;
|
|
|
|
while (!IsListEmpty(Head))
|
|
|
|
{
|
|
|
|
/* Remove each one from the list */
|
|
|
|
NextEntry = RemoveHeadList(Head);
|
2012-01-30 05:32:34 +00:00
|
|
|
|
2016-01-07 16:57:05 +00:00
|
|
|
/* Create the descriptor for it */
|
|
|
|
RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
|
|
|
|
SmpCreatePagingFileDescriptor(&RegEntry->Name);
|
2012-01-30 05:32:34 +00:00
|
|
|
|
2016-01-07 16:57:05 +00:00
|
|
|
/* And free it */
|
|
|
|
if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
|
|
|
|
if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
|
|
|
|
}
|
2012-01-30 05:32:34 +00:00
|
|
|
|
2016-01-07 16:57:05 +00:00
|
|
|
/* Now create all the paging files for the descriptors that we have */
|
|
|
|
SmpCreatePagingFiles();
|
|
|
|
}
|
2012-01-30 05:32:34 +00:00
|
|
|
|
|
|
|
/* Tell Cm it's now safe to fully enable write access to the registry */
|
2012-01-31 01:19:14 +00:00
|
|
|
NtInitializeRegistry(CM_BOOT_FLAG_SMSS);
|
2012-01-30 05:32:34 +00:00
|
|
|
|
|
|
|
/* Create all the system-based environment variables for later inheriting */
|
|
|
|
Status = SmpCreateDynamicEnvironmentVariables();
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Handle failure */
|
|
|
|
SMSS_CHECKPOINT(SmpCreateDynamicEnvironmentVariables, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2016-11-05 14:55:55 +00:00
|
|
|
/* And finally load all the subsystems for our first session! */
|
2012-01-30 05:32:34 +00:00
|
|
|
Status = SmpLoadSubSystemsForMuSession(&MuSessionId,
|
|
|
|
&SmpWindowsSubSysProcessId,
|
|
|
|
InitialCommand);
|
|
|
|
ASSERT(MuSessionId == 0);
|
|
|
|
if (!NT_SUCCESS(Status)) SMSS_CHECKPOINT(SmpLoadSubSystemsForMuSession, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2012-01-30 02:10:39 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpInit(IN PUNICODE_STRING InitialCommand,
|
|
|
|
OUT PHANDLE ProcessHandle)
|
|
|
|
{
|
2012-01-30 03:44:27 +00:00
|
|
|
NTSTATUS Status, Status2;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING PortName, EventName;
|
|
|
|
HANDLE EventHandle, PortHandle;
|
|
|
|
ULONG HardErrorMode;
|
|
|
|
|
|
|
|
/* Create the SMSS Heap */
|
|
|
|
SmBaseTag = RtlCreateTagHeap(RtlGetProcessHeap(),
|
|
|
|
0,
|
|
|
|
L"SMSS!",
|
|
|
|
L"INIT");
|
|
|
|
SmpHeap = RtlGetProcessHeap();
|
|
|
|
|
|
|
|
/* Enable hard errors */
|
|
|
|
HardErrorMode = TRUE;
|
|
|
|
NtSetInformationProcess(NtCurrentProcess(),
|
|
|
|
ProcessDefaultHardErrorMode,
|
|
|
|
&HardErrorMode,
|
|
|
|
sizeof(HardErrorMode));
|
|
|
|
|
|
|
|
/* Initialize the subsystem list and the session list, plus their locks */
|
|
|
|
RtlInitializeCriticalSection(&SmpKnownSubSysLock);
|
|
|
|
InitializeListHead(&SmpKnownSubSysHead);
|
|
|
|
RtlInitializeCriticalSection(&SmpSessionListLock);
|
|
|
|
InitializeListHead(&SmpSessionListHead);
|
|
|
|
|
|
|
|
/* Initialize the process list */
|
|
|
|
InitializeListHead(&NativeProcessList);
|
|
|
|
|
|
|
|
/* Initialize session parameters */
|
|
|
|
SmpNextSessionId = 1;
|
|
|
|
SmpNextSessionIdScanMode = 0;
|
|
|
|
SmpDbgSsLoaded = FALSE;
|
2012-01-30 05:32:34 +00:00
|
|
|
|
2012-01-30 03:44:27 +00:00
|
|
|
/* Create the initial security descriptors */
|
|
|
|
Status = SmpCreateSecurityDescriptors(TRUE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Fail */
|
|
|
|
SMSS_CHECKPOINT(SmpCreateSecurityDescriptors, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize subsystem names */
|
|
|
|
RtlInitUnicodeString(&SmpSubsystemName, L"NT-Session Manager");
|
|
|
|
RtlInitUnicodeString(&PosixName, L"POSIX");
|
|
|
|
RtlInitUnicodeString(&Os2Name, L"OS2");
|
|
|
|
|
|
|
|
/* Create the SM API Port */
|
2013-09-12 08:02:05 +00:00
|
|
|
RtlInitUnicodeString(&PortName, L"\\SmApiPort");
|
2012-01-30 03:44:27 +00:00
|
|
|
InitializeObjectAttributes(&ObjectAttributes, &PortName, 0, NULL, NULL);
|
|
|
|
Status = NtCreatePort(&PortHandle,
|
|
|
|
&ObjectAttributes,
|
|
|
|
sizeof(SB_CONNECTION_INFO),
|
|
|
|
sizeof(SM_API_MSG),
|
|
|
|
sizeof(SB_API_MSG) * 32);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
SmpDebugPort = PortHandle;
|
|
|
|
|
|
|
|
/* Create two SM API threads */
|
|
|
|
Status = RtlCreateUserThread(NtCurrentProcess(),
|
|
|
|
NULL,
|
|
|
|
FALSE,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
SmpApiLoop,
|
|
|
|
PortHandle,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlCreateUserThread(NtCurrentProcess(),
|
|
|
|
NULL,
|
|
|
|
FALSE,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
SmpApiLoop,
|
|
|
|
PortHandle,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
/* Create the write event that autochk can set after running */
|
|
|
|
RtlInitUnicodeString(&EventName, L"\\Device\\VolumesSafeForWriteAccess");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&EventName,
|
|
|
|
OBJ_PERMANENT,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status2 = NtCreateEvent(&EventHandle,
|
|
|
|
EVENT_ALL_ACCESS,
|
|
|
|
&ObjectAttributes,
|
|
|
|
0,
|
|
|
|
0);
|
|
|
|
if (!NT_SUCCESS(Status2))
|
|
|
|
{
|
|
|
|
/* Should never really fail */
|
|
|
|
DPRINT1("SMSS: Unable to create %wZ event - Status == %lx\n",
|
|
|
|
&EventName, Status2);
|
|
|
|
ASSERT(NT_SUCCESS(Status2));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now initialize everything else based on the registry parameters */
|
|
|
|
Status = SmpLoadDataFromRegistry(InitialCommand);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Autochk should've run now. Set the event and save the CSRSS handle */
|
|
|
|
*ProcessHandle = SmpWindowsSubSysProcess;
|
|
|
|
NtSetEvent(EventHandle, 0);
|
|
|
|
NtClose(EventHandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All done */
|
|
|
|
return Status;
|
2012-01-30 02:10:39 +00:00
|
|
|
}
|