2012-01-30 02:10:39 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS Windows-Compatible Session Manager
|
|
|
|
* LICENSE: BSD 2-Clause License
|
|
|
|
* FILE: base/system/smss/smss.c
|
|
|
|
* PURPOSE: Main SMSS Code
|
|
|
|
* PROGRAMMERS: Alex Ionescu
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
|
|
|
|
#include "smss.h"
|
|
|
|
#define NDEBUG
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
|
2012-01-30 03:44:27 +00:00
|
|
|
RTL_CRITICAL_SECTION SmpKnownSubSysLock;
|
|
|
|
LIST_ENTRY SmpKnownSubSysHead;
|
|
|
|
HANDLE SmpWindowsSubSysProcess;
|
2012-01-30 05:32:34 +00:00
|
|
|
HANDLE SmpWindowsSubSysProcessId;
|
[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
|
|
|
BOOLEAN RegPosixSingleInstance;
|
2012-02-06 18:57:18 +00:00
|
|
|
WCHAR InitialCommandBuffer[256];
|
2012-01-30 03:44:27 +00:00
|
|
|
|
2012-01-30 02:10:39 +00:00
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
|
2012-02-07 07:13:42 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
SmpDereferenceSubsystem(IN PSMP_SUBSYSTEM SubSystem)
|
|
|
|
{
|
|
|
|
/* Acquire the database lock while we (potentially) destroy this subsystem */
|
|
|
|
RtlEnterCriticalSection(&SmpKnownSubSysLock);
|
|
|
|
|
|
|
|
/* Drop the reference and see if it's terminating */
|
|
|
|
if (!(--SubSystem->ReferenceCount) && (SubSystem->Terminating))
|
|
|
|
{
|
|
|
|
/* Close all handles and free it */
|
|
|
|
if (SubSystem->Event) NtClose(SubSystem->Event);
|
|
|
|
if (SubSystem->ProcessHandle) NtClose(SubSystem->ProcessHandle);
|
|
|
|
if (SubSystem->SbApiPort) NtClose(SubSystem->SbApiPort);
|
|
|
|
RtlFreeHeap(SmpHeap, 0, SubSystem);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Release the database lock */
|
|
|
|
RtlLeaveCriticalSection(&SmpKnownSubSysLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
PSMP_SUBSYSTEM
|
|
|
|
NTAPI
|
|
|
|
SmpLocateKnownSubSysByCid(IN PCLIENT_ID ClientId)
|
|
|
|
{
|
|
|
|
PSMP_SUBSYSTEM Subsystem = NULL;
|
|
|
|
PLIST_ENTRY NextEntry;
|
|
|
|
|
|
|
|
/* Lock the subsystem database */
|
|
|
|
RtlEnterCriticalSection(&SmpKnownSubSysLock);
|
|
|
|
|
|
|
|
/* Loop each subsystem in the database */
|
|
|
|
NextEntry = SmpKnownSubSysHead.Flink;
|
|
|
|
while (NextEntry != &SmpKnownSubSysHead)
|
|
|
|
{
|
|
|
|
/* Check if this one matches the client ID and is still valid */
|
|
|
|
Subsystem = CONTAINING_RECORD(NextEntry, SMP_SUBSYSTEM, Entry);
|
|
|
|
if ((*(PULONGLONG)&Subsystem->ClientId == *(PULONGLONG)&ClientId) &&
|
|
|
|
!(Subsystem->Terminating))
|
|
|
|
{
|
|
|
|
/* Add a reference and return it */
|
|
|
|
Subsystem->ReferenceCount++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset the current pointer and keep earching */
|
|
|
|
Subsystem = NULL;
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Release the lock and return the subsystem we found */
|
|
|
|
RtlLeaveCriticalSection(&SmpKnownSubSysLock);
|
|
|
|
return Subsystem;
|
|
|
|
}
|
|
|
|
|
|
|
|
PSMP_SUBSYSTEM
|
|
|
|
NTAPI
|
|
|
|
SmpLocateKnownSubSysByType(IN ULONG MuSessionId,
|
|
|
|
IN ULONG ImageType)
|
|
|
|
{
|
|
|
|
PSMP_SUBSYSTEM Subsystem = NULL;
|
|
|
|
PLIST_ENTRY NextEntry;
|
|
|
|
|
|
|
|
/* Lock the subsystem database */
|
|
|
|
RtlEnterCriticalSection(&SmpKnownSubSysLock);
|
|
|
|
|
|
|
|
/* Loop each subsystem in the database */
|
|
|
|
NextEntry = SmpKnownSubSysHead.Flink;
|
|
|
|
while (NextEntry != &SmpKnownSubSysHead)
|
|
|
|
{
|
|
|
|
/* Check if this one matches the image and uID, and is still valid */
|
|
|
|
Subsystem = CONTAINING_RECORD(NextEntry, SMP_SUBSYSTEM, Entry);
|
|
|
|
if ((Subsystem->ImageType == ImageType) &&
|
|
|
|
!(Subsystem->Terminating) &&
|
|
|
|
(Subsystem->MuSessionId == MuSessionId))
|
|
|
|
{
|
|
|
|
/* Return it referenced for the caller */
|
|
|
|
Subsystem->ReferenceCount++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset the current pointer and keep earching */
|
|
|
|
Subsystem = NULL;
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Release the lock and return the subsystem we found */
|
|
|
|
RtlLeaveCriticalSection(&SmpKnownSubSysLock);
|
|
|
|
return Subsystem;
|
|
|
|
}
|
|
|
|
|
2012-01-31 02:38:42 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpLoadSubSystem(IN PUNICODE_STRING FileName,
|
|
|
|
IN PUNICODE_STRING Directory,
|
|
|
|
IN PUNICODE_STRING CommandLine,
|
|
|
|
IN ULONG MuSessionId,
|
|
|
|
OUT PHANDLE ProcessId)
|
|
|
|
{
|
|
|
|
DPRINT1("Should start subsystem %wZ for Session: %lx\n", FileName, MuSessionId);
|
2012-02-06 18:57:18 +00:00
|
|
|
return STATUS_SUCCESS;
|
2012-01-31 02:38:42 +00:00
|
|
|
}
|
|
|
|
|
2012-01-30 05:32:34 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
SmpLoadSubSystemsForMuSession(IN PULONG MuSessionId,
|
|
|
|
OUT PHANDLE ProcessId,
|
|
|
|
IN PUNICODE_STRING InitialCommand)
|
|
|
|
{
|
2012-02-06 18:57:18 +00:00
|
|
|
NTSTATUS Status = STATUS_SUCCESS, Status2;
|
|
|
|
PSMP_REGISTRY_VALUE RegEntry;
|
|
|
|
UNICODE_STRING DestinationString, NtPath;
|
|
|
|
PLIST_ENTRY NextEntry;
|
|
|
|
LARGE_INTEGER Timeout;
|
|
|
|
PVOID State;
|
|
|
|
|
|
|
|
/* Write a few last registry keys with the boot partition information */
|
|
|
|
SmpTranslateSystemPartitionInformation();
|
|
|
|
|
|
|
|
/* Process "SetupExecute" values */
|
|
|
|
NextEntry = SmpSetupExecuteList.Flink;
|
|
|
|
while (NextEntry != &SmpSetupExecuteList)
|
|
|
|
{
|
|
|
|
/* Execute each one and move on */
|
|
|
|
RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
|
|
|
|
DPRINT1("SetupExecute entry: %wZ\n", &RegEntry->Name);
|
|
|
|
SmpExecuteCommand(&RegEntry->Name, 0, NULL, 0);
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now process the subsystems */
|
|
|
|
NextEntry = SmpSubSystemList.Flink;
|
|
|
|
while (NextEntry != &SmpSubSystemList)
|
|
|
|
{
|
|
|
|
/* Get the entry and check if this is the special Win32k entry */
|
|
|
|
RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
|
|
|
|
DPRINT1("Subsystem: %wZ\n", &RegEntry->Name);
|
|
|
|
if (!_wcsicmp(RegEntry->Name.Buffer, L"Kmode"))
|
|
|
|
{
|
|
|
|
/* Translate it */
|
|
|
|
if (!RtlDosPathNameToNtPathName_U(RegEntry->Value.Buffer,
|
|
|
|
&NtPath,
|
|
|
|
NULL,
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
|
|
|
|
DPRINT1("Failed: %lx\n", Status);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Get the driver privilege */
|
|
|
|
Status = SmpAcquirePrivilege(SE_LOAD_DRIVER_PRIVILEGE, &State);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Create the new session */
|
|
|
|
ASSERT(AttachedSessionId == -1);
|
|
|
|
Status = NtSetSystemInformation(SystemSessionCreate,
|
|
|
|
MuSessionId,
|
|
|
|
sizeof(*MuSessionId));
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: Session space creation failed\n");
|
|
|
|
SmpReleasePrivilege(State);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath.Buffer);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
AttachedSessionId = *MuSessionId;
|
|
|
|
|
|
|
|
/* Start Win32k.sys on this session */
|
|
|
|
DPRINT1("Starting win32k.sys...\n");
|
|
|
|
RtlInitUnicodeString(&DestinationString,
|
|
|
|
L"\\SystemRoot\\System32\\win32k.sys");
|
|
|
|
Status = NtSetSystemInformation(SystemExtendServiceTableInformation,
|
|
|
|
&DestinationString,
|
|
|
|
sizeof(DestinationString));
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath.Buffer);
|
|
|
|
SmpReleasePrivilege(State);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("SMSS: Load of WIN32K failed.\n");
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Next entry */
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now parse the required subsystem list */
|
|
|
|
NextEntry = SmpSubSystemsToLoad.Flink;
|
|
|
|
while (NextEntry != &SmpSubSystemsToLoad)
|
|
|
|
{
|
|
|
|
/* Get each entry and check if it's the internal debug or not */
|
|
|
|
RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
|
|
|
|
DPRINT1("Subsystem (required): %wZ\n", &RegEntry->Name);
|
|
|
|
if (_wcsicmp(RegEntry->Name.Buffer, L"debug"))
|
|
|
|
{
|
|
|
|
/* Load the required subsystem */
|
|
|
|
Status = SmpExecuteCommand(&RegEntry->Value,
|
|
|
|
*MuSessionId,
|
|
|
|
ProcessId,
|
|
|
|
SMP_SUBSYSTEM_FLAG);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Load the internal debug system */
|
|
|
|
Status = SmpExecuteCommand(&RegEntry->Value,
|
|
|
|
*MuSessionId,
|
|
|
|
ProcessId,
|
|
|
|
SMP_DEBUG_FLAG | SMP_SUBSYSTEM_FLAG);
|
|
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DbgPrint("SMSS: Subsystem execute failed (%WZ)\n", &RegEntry->Value);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Move to the next entry */
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process the "Execute" list now */
|
|
|
|
NextEntry = SmpExecuteList.Blink;
|
|
|
|
if (NextEntry != &SmpExecuteList)
|
|
|
|
{
|
|
|
|
/* Get the custom initial command */
|
|
|
|
RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
|
|
|
|
DPRINT1("Initial command found: %wZ\n", &RegEntry->Name);
|
|
|
|
|
|
|
|
/* Write the initial command and wait for 5 seconds (why??!) */
|
|
|
|
*InitialCommand = RegEntry->Name;
|
|
|
|
Timeout.QuadPart = -50000000;
|
|
|
|
NtDelayExecution(FALSE, &Timeout);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Use the default Winlogon initial command */
|
|
|
|
RtlInitUnicodeString(InitialCommand, L"winlogon.exe");
|
|
|
|
InitialCommandBuffer[0] = UNICODE_NULL;
|
|
|
|
DPRINT1("Initial command found: %wZ\n", InitialCommand);
|
|
|
|
|
|
|
|
/* Check if there's a debugger for Winlogon */
|
|
|
|
Status2 = LdrQueryImageFileExecutionOptions(InitialCommand,
|
|
|
|
L"Debugger",
|
|
|
|
REG_SZ,
|
|
|
|
InitialCommandBuffer,
|
|
|
|
sizeof(InitialCommandBuffer) -
|
|
|
|
InitialCommand->Length,
|
|
|
|
NULL);
|
|
|
|
if ((NT_SUCCESS(Status2)) && (InitialCommandBuffer[0]))
|
|
|
|
{
|
|
|
|
/* Put the debugger string with the Winlogon string */
|
|
|
|
wcscat(InitialCommandBuffer, L" ");
|
|
|
|
wcscat(InitialCommandBuffer, InitialCommand->Buffer);
|
|
|
|
RtlInitUnicodeString(InitialCommand, InitialCommandBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finally check if there was a custom initial command */
|
|
|
|
NextEntry = SmpExecuteList.Flink;
|
|
|
|
while (NextEntry != &SmpExecuteList)
|
|
|
|
{
|
|
|
|
/* Execute each one */
|
|
|
|
RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
|
|
|
|
DPRINT1("Initial command (custom): %wZ\n", &RegEntry->Name);
|
|
|
|
SmpExecuteCommand(&RegEntry->Name, *MuSessionId, NULL, 0);
|
|
|
|
NextEntry = NextEntry->Flink;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return status */
|
|
|
|
return Status;
|
2012-01-30 05:32:34 +00:00
|
|
|
}
|
|
|
|
|