mirror of
https://github.com/reactos/reactos.git
synced 2024-06-22 05:51:29 +00:00
dfb761830d
[SMSS2]: Implement the main LPC loop and handle all the supported APIs (all stubs for now). Also handle new connection requests and implement SmpHandleConnectionRequest. [SMSS2]: Implement subsystem helper functions. [SMSS2]: Use SmApiPort2 instead of Sm2ApiPort. [SMSS2]: Rename the SMSRV_APIs not to conflict with the function names, nor with the client functions in smlib. svn path=/trunk/; revision=55478
301 lines
11 KiB
C
301 lines
11 KiB
C
/*
|
|
* 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 ********************************************************************/
|
|
|
|
RTL_CRITICAL_SECTION SmpKnownSubSysLock;
|
|
LIST_ENTRY SmpKnownSubSysHead;
|
|
HANDLE SmpWindowsSubSysProcess;
|
|
HANDLE SmpWindowsSubSysProcessId;
|
|
BOOLEAN RegPosixSingleInstance;
|
|
WCHAR InitialCommandBuffer[256];
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
SmpLoadSubSystemsForMuSession(IN PULONG MuSessionId,
|
|
OUT PHANDLE ProcessId,
|
|
IN PUNICODE_STRING InitialCommand)
|
|
{
|
|
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;
|
|
}
|
|
|