--- /dev/null
+/*
+ * 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 ********************************************************************/
+
+typedef struct _INIT_BUFFER
+{
+ WCHAR DebugBuffer[256];
+ RTL_USER_PROCESS_INFORMATION ProcessInfo;
+} INIT_BUFFER, *PINIT_BUFFER;
+
+/* NT Initial User Application */
+WCHAR NtInitialUserProcessBuffer[128] = L"\\SystemRoot\\System32\\smss.exe";
+ULONG NtInitialUserProcessBufferLength = sizeof(NtInitialUserProcessBuffer) -
+ sizeof(WCHAR);
+ULONG NtInitialUserProcessBufferType = REG_SZ;
+
+UNICODE_STRING NtSystemRoot;
+
+/* FUNCTIONS ******************************************************************/
+
+NTSTATUS
+NTAPI
+ExpLoadInitialProcess(IN PINIT_BUFFER InitBuffer,
+ OUT PRTL_USER_PROCESS_PARAMETERS *ProcessParameters,
+ OUT PCHAR *ProcessEnvironment)
+{
+ NTSTATUS Status;
+ SIZE_T Size;
+ PWSTR p;
+ UNICODE_STRING NullString = RTL_CONSTANT_STRING(L"");
+ UNICODE_STRING SmssName, Environment, SystemDriveString, DebugString;
+ PVOID EnvironmentPtr = NULL;
+ PRTL_USER_PROCESS_INFORMATION ProcessInformation;
+ PRTL_USER_PROCESS_PARAMETERS ProcessParams = NULL;
+
+ NullString.Length = sizeof(WCHAR);
+
+ /* Use the initial buffer, after the strings */
+ ProcessInformation = &InitBuffer->ProcessInfo;
+
+ /* Allocate memory for the process parameters */
+ Size = sizeof(*ProcessParams) + ((MAX_PATH * 6) * sizeof(WCHAR));
+ Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
+ (PVOID*)&ProcessParams,
+ 0,
+ &Size,
+ MEM_COMMIT,
+ PAGE_READWRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failed, display error */
+ p = InitBuffer->DebugBuffer;
+ _snwprintf(p,
+ 256 * sizeof(WCHAR),
+ L"INIT: Unable to allocate Process Parameters. 0x%lx",
+ Status);
+ RtlInitUnicodeString(&DebugString, p);
+ ZwDisplayString(&DebugString);
+
+ /* Bugcheck the system */
+ return Status;
+ }
+
+ /* Setup the basic header, and give the process the low 1MB to itself */
+ ProcessParams->Length = (ULONG)Size;
+ ProcessParams->MaximumLength = (ULONG)Size;
+ ProcessParams->Flags = RTL_USER_PROCESS_PARAMETERS_NORMALIZED |
+ RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB;
+
+ /* Allocate a page for the environment */
+ Size = PAGE_SIZE;
+ Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
+ &EnvironmentPtr,
+ 0,
+ &Size,
+ MEM_COMMIT,
+ PAGE_READWRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failed, display error */
+ p = InitBuffer->DebugBuffer;
+ _snwprintf(p,
+ 256 * sizeof(WCHAR),
+ L"INIT: Unable to allocate Process Environment. 0x%lx",
+ Status);
+ RtlInitUnicodeString(&DebugString, p);
+ ZwDisplayString(&DebugString);
+
+ /* Bugcheck the system */
+ return Status;
+ }
+
+ /* Write the pointer */
+ ProcessParams->Environment = EnvironmentPtr;
+
+ /* Make a buffer for the DOS path */
+ p = (PWSTR)(ProcessParams + 1);
+ ProcessParams->CurrentDirectory.DosPath.Buffer = p;
+ ProcessParams->CurrentDirectory.DosPath.MaximumLength = MAX_PATH *
+ sizeof(WCHAR);
+
+ /* Copy the DOS path */
+ RtlCopyUnicodeString(&ProcessParams->CurrentDirectory.DosPath,
+ &NtSystemRoot);
+
+ /* Make a buffer for the DLL Path */
+ p = (PWSTR)((PCHAR)ProcessParams->CurrentDirectory.DosPath.Buffer +
+ ProcessParams->CurrentDirectory.DosPath.MaximumLength);
+ ProcessParams->DllPath.Buffer = p;
+ ProcessParams->DllPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
+
+ /* Copy the DLL path and append the system32 directory */
+ RtlCopyUnicodeString(&ProcessParams->DllPath,
+ &ProcessParams->CurrentDirectory.DosPath);
+ RtlAppendUnicodeToString(&ProcessParams->DllPath, L"\\System32");
+
+ /* Make a buffer for the image name */
+ p = (PWSTR)((PCHAR)ProcessParams->DllPath.Buffer +
+ ProcessParams->DllPath.MaximumLength);
+ ProcessParams->ImagePathName.Buffer = p;
+ ProcessParams->ImagePathName.MaximumLength = MAX_PATH * sizeof(WCHAR);
+
+ /* Make sure the buffer is a valid string which within the given length */
+ if ((NtInitialUserProcessBufferType != REG_SZ) ||
+ ((NtInitialUserProcessBufferLength != MAXULONG) &&
+ ((NtInitialUserProcessBufferLength < sizeof(WCHAR)) ||
+ (NtInitialUserProcessBufferLength >
+ sizeof(NtInitialUserProcessBuffer) - sizeof(WCHAR)))))
+ {
+ /* Invalid initial process string, bugcheck */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Cut out anything after a space */
+ p = NtInitialUserProcessBuffer;
+ while ((*p) && (*p != L' ')) p++;
+
+ /* Set the image path length */
+ ProcessParams->ImagePathName.Length =
+ (USHORT)((PCHAR)p - (PCHAR)NtInitialUserProcessBuffer);
+
+ /* Copy the actual buffer */
+ RtlCopyMemory(ProcessParams->ImagePathName.Buffer,
+ NtInitialUserProcessBuffer,
+ ProcessParams->ImagePathName.Length);
+
+ /* Null-terminate it */
+ ProcessParams->ImagePathName.Buffer[ProcessParams->ImagePathName.Length /
+ sizeof(WCHAR)] = UNICODE_NULL;
+
+ /* Make a buffer for the command line */
+ p = (PWSTR)((PCHAR)ProcessParams->ImagePathName.Buffer +
+ ProcessParams->ImagePathName.MaximumLength);
+ ProcessParams->CommandLine.Buffer = p;
+ ProcessParams->CommandLine.MaximumLength = MAX_PATH * sizeof(WCHAR);
+
+ /* Add the image name to the command line */
+ RtlAppendUnicodeToString(&ProcessParams->CommandLine,
+ NtInitialUserProcessBuffer);
+
+ /* Create the environment string */
+ RtlInitEmptyUnicodeString(&Environment,
+ ProcessParams->Environment,
+ (USHORT)Size);
+
+ /* Append the DLL path to it */
+ RtlAppendUnicodeToString(&Environment, L"Path=" );
+ RtlAppendUnicodeStringToString(&Environment, &ProcessParams->DllPath);
+ RtlAppendUnicodeStringToString(&Environment, &NullString);
+
+ /* Create the system drive string */
+ SystemDriveString = NtSystemRoot;
+ SystemDriveString.Length = 2 * sizeof(WCHAR);
+
+ /* Append it to the environment */
+ RtlAppendUnicodeToString(&Environment, L"SystemDrive=");
+ RtlAppendUnicodeStringToString(&Environment, &SystemDriveString);
+ RtlAppendUnicodeStringToString(&Environment, &NullString);
+
+ /* Append the system root to the environment */
+ RtlAppendUnicodeToString(&Environment, L"SystemRoot=");
+ RtlAppendUnicodeStringToString(&Environment, &NtSystemRoot);
+ RtlAppendUnicodeStringToString(&Environment, &NullString);
+
+ /* Create SMSS process */
+ SmssName = ProcessParams->ImagePathName;
+ Status = RtlCreateUserProcess(&SmssName,
+ OBJ_CASE_INSENSITIVE,
+ RtlDeNormalizeProcessParams(ProcessParams),
+ NULL,
+ NULL,
+ NULL,
+ FALSE,
+ NULL,
+ NULL,
+ ProcessInformation);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failed, display error */
+ p = InitBuffer->DebugBuffer;
+ _snwprintf(p,
+ 256 * sizeof(WCHAR),
+ L"INIT: Unable to create Session Manager. 0x%lx",
+ Status);
+ RtlInitUnicodeString(&DebugString, p);
+ ZwDisplayString(&DebugString);
+
+ /* Bugcheck the system */
+ return Status;
+ }
+
+ /* Resume the thread */
+ Status = ZwResumeThread(ProcessInformation->ThreadHandle, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failed, display error */
+ p = InitBuffer->DebugBuffer;
+ _snwprintf(p,
+ 256 * sizeof(WCHAR),
+ L"INIT: Unable to resume Session Manager. 0x%lx",
+ Status);
+ RtlInitUnicodeString(&DebugString, p);
+ ZwDisplayString(&DebugString);
+
+ /* Bugcheck the system */
+ return Status;
+ }
+
+ /* Return success */
+ *ProcessParameters = ProcessParams;
+ *ProcessEnvironment = EnvironmentPtr;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+LaunchOldSmss(VOID)
+{
+ PINIT_BUFFER InitBuffer;
+ PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;
+ PRTL_USER_PROCESS_INFORMATION ProcessInfo;
+ LARGE_INTEGER Timeout;
+ NTSTATUS Status;
+ PCHAR Environment;
+ SIZE_T Size;
+
+ /* Setup system root */
+ RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot);
+
+ /* Allocate the initialization buffer */
+ InitBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(INIT_BUFFER));
+ if (!InitBuffer)
+ {
+ /* Bugcheck */
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Launch initial process */
+ ProcessInfo = &InitBuffer->ProcessInfo;
+ Status = ExpLoadInitialProcess(InitBuffer, &ProcessParameters, &Environment);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failed, display error */
+ DPRINT1("INIT: Session Manager failed to load.\n");
+ return Status;
+ }
+
+ /* Wait 5 seconds for initial process to initialize */
+ Timeout.QuadPart = Int32x32To64(5, -10000000);
+ Status = ZwWaitForSingleObject(ProcessInfo->ProcessHandle, FALSE, &Timeout);
+ if (Status == STATUS_SUCCESS)
+ {
+ /* Failed, display error */
+ DPRINT1("INIT: Session Manager terminated.\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ /* Close process handles */
+ ZwClose(ProcessInfo->ThreadHandle);
+ ZwClose(ProcessInfo->ProcessHandle);
+
+ /* Free the initial process environment */
+ Size = 0;
+ ZwFreeVirtualMemory(NtCurrentProcess(),
+ (PVOID*)&Environment,
+ &Size,
+ MEM_RELEASE);
+
+ /* Free the initial process parameters */
+ Size = 0;
+ ZwFreeVirtualMemory(NtCurrentProcess(),
+ (PVOID*)&ProcessParameters,
+ &Size,
+ MEM_RELEASE);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+__cdecl
+_main(IN INT argc,
+ IN PCHAR argv[],
+ IN PCHAR envp[],
+ IN ULONG DebugFlag)
+{
+ NTSTATUS Status;
+
+ /* Launch the original SMSS */
+ DPRINT1("SMSS-2 Loaded... Launching original SMSS\n");
+ Status = LaunchOldSmss();
+
+ /* Terminate this SMSS for now, later we'll have an LPC thread running */
+ return NtTerminateThread(NtCurrentThread(), Status);
+}
+
+/* EOF */