+++ /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"
-
-#include <pseh/pseh2.h>
-
-#define NDEBUG
-#include <debug.h>
-
-/* GLOBALS ********************************************************************/
-
-UNICODE_STRING SmpSystemRoot;
-ULONG AttachedSessionId = -1;
-BOOLEAN SmpDebug, SmpEnableDots;
-HANDLE SmApiPort;
-HANDLE SmpInitialCommandProcessId;
-
-/* FUNCTIONS ******************************************************************/
-
-/* GCC's incompetence strikes again */
-VOID
-sprintf_nt(IN PCHAR Buffer,
- IN PCHAR Format,
- IN ...)
-{
- va_list ap;
- va_start(ap, Format);
- sprintf(Buffer, Format, ap);
- va_end(ap);
-}
-
-NTSTATUS
-NTAPI
-SmpExecuteImage(IN PUNICODE_STRING FileName,
- IN PUNICODE_STRING Directory,
- IN PUNICODE_STRING CommandLine,
- IN ULONG MuSessionId,
- IN ULONG Flags,
- IN PRTL_USER_PROCESS_INFORMATION ProcessInformation)
-{
- PRTL_USER_PROCESS_INFORMATION ProcessInfo;
- NTSTATUS Status;
- RTL_USER_PROCESS_INFORMATION LocalProcessInfo;
- PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
-
- /* Use the input process information if we have it, otherwise use local */
- ProcessInfo = ProcessInformation;
- if (!ProcessInfo) ProcessInfo = &LocalProcessInfo;
-
- /* Create parameters for the target process */
- Status = RtlCreateProcessParameters(&ProcessParameters,
- FileName,
- SmpDefaultLibPath.Length ?
- &SmpDefaultLibPath : NULL,
- Directory,
- CommandLine,
- SmpDefaultEnvironment,
- NULL,
- NULL,
- NULL,
- 0);
- if (!NT_SUCCESS(Status))
- {
- /* This is a pretty bad failure. ASSERT on checked builds and exit */
- ASSERTMSG("RtlCreateProcessParameters", NT_SUCCESS(Status));
- DPRINT1("SMSS: RtlCreateProcessParameters failed for %wZ - Status == %lx\n",
- FileName, Status);
- return Status;
- }
-
- /* Set the size field as required */
- ProcessInfo->Size = sizeof(RTL_USER_PROCESS_INFORMATION);
-
- /* Check if the debug flag was requested */
- if (Flags & SMP_DEBUG_FLAG)
- {
- /* Write it in the process parameters */
- ProcessParameters->DebugFlags = 1;
- }
- else
- {
- /* Otherwise inherit the flag that was passed to SMSS itself */
- ProcessParameters->DebugFlags = SmpDebug;
- }
-
- /* Subsystems get the first 1MB of memory reserved for DOS/IVT purposes */
- if (Flags & SMP_SUBSYSTEM_FLAG)
- {
- ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB;
- }
-
- /* And always force NX for anything that SMSS launches */
- ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_NX;
-
- /* Now create the process */
- Status = RtlCreateUserProcess(FileName,
- OBJ_CASE_INSENSITIVE,
- ProcessParameters,
- NULL,
- NULL,
- NULL,
- FALSE,
- NULL,
- NULL,
- ProcessInfo);
- RtlDestroyProcessParameters(ProcessParameters);
- if (!NT_SUCCESS(Status))
- {
- /* If we couldn't create it, fail back to the caller */
- DPRINT1("SMSS: Failed load of %wZ - Status == %lx\n",
- FileName, Status);
- return Status;
- }
-
- /* Associate a session with this process */
- Status = SmpSetProcessMuSessionId(ProcessInfo->ProcessHandle, MuSessionId);
-
- /* If the application is deferred (suspended), there's nothing to do */
- if (Flags & SMP_DEFERRED_FLAG) return Status;
-
- /* Otherwise, get ready to start it, but make sure it's a native app */
- if (ProcessInfo->ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_NATIVE)
- {
- /* Resume it */
- NtResumeThread(ProcessInfo->ThreadHandle, NULL);
- if (!(Flags & SMP_ASYNC_FLAG))
- {
- /* Block on it unless Async was requested */
- NtWaitForSingleObject(ProcessInfo->ThreadHandle, FALSE, NULL);
- }
-
- /* It's up and running now, close our handles */
- NtClose(ProcessInfo->ThreadHandle);
- NtClose(ProcessInfo->ProcessHandle);
- }
- else
- {
- /* This image is invalid, so kill it, close our handles, and fail */
- Status = STATUS_INVALID_IMAGE_FORMAT;
- NtTerminateProcess(ProcessInfo->ProcessHandle, Status);
- NtWaitForSingleObject(ProcessInfo->ThreadHandle, 0, 0);
- NtClose(ProcessInfo->ThreadHandle);
- NtClose(ProcessInfo->ProcessHandle);
- DPRINT1("SMSS: Not an NT image - %wZ\n", FileName);
- }
-
- /* Return the outcome of the process create */
- return Status;
-}
-
-NTSTATUS
-NTAPI
-SmpInvokeAutoChk(IN PUNICODE_STRING FileName,
- IN PUNICODE_STRING Directory,
- IN PUNICODE_STRING Arguments,
- IN ULONG Flags)
-{
- ANSI_STRING MessageString;
- CHAR MessageBuffer[256];
- UNICODE_STRING Destination;
- WCHAR Buffer[1024];
- BOOLEAN BootState, BootOkay, ShutdownOkay;
-
- /* Check if autochk should show dots (if the user booted with /SOS) */
- if (SmpQueryRegistrySosOption()) SmpEnableDots = FALSE;
-
- /* Make sure autochk was actually found */
- if (Flags & SMP_INVALID_PATH)
- {
- /* It wasn't, so create an error message to print on the screen */
- sprintf_nt(MessageBuffer,
- "%wZ program not found - skipping AUTOCHECK\r\n",
- FileName);
- RtlInitAnsiString(&MessageString, MessageBuffer);
- if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&Destination,
- &MessageString,
- TRUE)))
- {
- /* And show it */
- NtDisplayString(&Destination);
- RtlFreeUnicodeString(&Destination);
- }
- }
- else
- {
- /* Autochk is there, so record the BSD state */
- BootState = SmpSaveAndClearBootStatusData(&BootOkay, &ShutdownOkay);
-
- /* Build the path to autochk and place its arguments */
- RtlInitEmptyUnicodeString(&Destination, Buffer, sizeof(Buffer));
- RtlAppendUnicodeStringToString(&Destination, FileName);
- RtlAppendUnicodeToString(&Destination, L" ");
- RtlAppendUnicodeStringToString(&Destination, Arguments);
-
- /* Execute it */
- SmpExecuteImage(FileName,
- Directory,
- &Destination,
- 0,
- Flags & ~SMP_AUTOCHK_FLAG,
- NULL);
-
- /* Restore the BSD state */
- if (BootState) SmpRestoreBootStatusData(BootOkay, ShutdownOkay);
- }
-
- /* We're all done! */
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-SmpExecuteCommand(IN PUNICODE_STRING CommandLine,
- IN ULONG MuSessionId,
- OUT PHANDLE ProcessId,
- IN ULONG Flags)
-{
- NTSTATUS Status;
- UNICODE_STRING Arguments, Directory, FileName;
-
- /* There's no longer a debugging subsystem */
- if (Flags & SMP_DEBUG_FLAG) return STATUS_SUCCESS;
-
- /* Parse the command line to see what execution flags are requested */
- Status = SmpParseCommandLine(CommandLine,
- &Flags,
- &FileName,
- &Directory,
- &Arguments);
- if (!NT_SUCCESS(Status))
- {
- /* Fail if we couldn't do that */
- DPRINT1("SMSS: SmpParseCommandLine( %wZ ) failed - Status == %lx\n",
- CommandLine, Status);
- return Status;
- }
-
- /* Check if autochk is requested */
- if (Flags & SMP_AUTOCHK_FLAG)
- {
- /* Run it */
- Status = SmpInvokeAutoChk(&FileName, &Directory, &Arguments, Flags);
- }
- else if (Flags & SMP_SUBSYSTEM_FLAG)
- {
- Status = SmpLoadSubSystem(&FileName,
- &Directory,
- CommandLine,
- MuSessionId,
- ProcessId,
- Flags);
- }
- else if (Flags & SMP_INVALID_PATH)
- {
- /* An invalid image was specified, fail */
- DPRINT1("SMSS: Image file (%wZ) not found\n", &FileName);
- Status = STATUS_OBJECT_NAME_NOT_FOUND;
- }
- else
- {
- /* An actual image name was present -- execute it */
- Status = SmpExecuteImage(&FileName,
- &Directory,
- CommandLine,
- MuSessionId,
- Flags,
- NULL);
- }
-
- /* Free all the token parameters */
- if (FileName.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, FileName.Buffer);
- if (Directory.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Directory.Buffer);
- if (Arguments.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Arguments.Buffer);
-
- /* Return to the caller */
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("SMSS: Command '%wZ' failed - Status == %x\n",
- CommandLine, Status);
- }
- return Status;
-}
-
-NTSTATUS
-NTAPI
-SmpExecuteInitialCommand(IN ULONG MuSessionId,
- IN PUNICODE_STRING InitialCommand,
- IN HANDLE InitialCommandProcess,
- OUT PHANDLE ReturnPid)
-{
- NTSTATUS Status;
- RTL_USER_PROCESS_INFORMATION ProcessInfo;
- UNICODE_STRING Arguments, ImageFileDirectory, ImageFileName;
- ULONG Flags = 0;
-
- /* Check if we haven't yet connected to ourselves */
- if (!SmApiPort)
- {
- /* Connect to ourselves, as a client */
- Status = SmConnectToSm(0, 0, 0, &SmApiPort);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("SMSS: Unable to connect to SM - Status == %lx\n", Status);
- return Status;
- }
- }
-
- /* Parse the initial command line */
- Status = SmpParseCommandLine(InitialCommand,
- &Flags,
- &ImageFileName,
- &ImageFileDirectory,
- &Arguments);
- if (Flags & SMP_INVALID_PATH)
- {
- /* Fail if it doesn't exist */
- DPRINT1("SMSS: Initial command image (%wZ) not found\n", &ImageFileName);
- if (ImageFileName.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, ImageFileName.Buffer);
- return STATUS_OBJECT_NAME_NOT_FOUND;
- }
-
- /* And fail if any other reason is also true */
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("SMSS: SmpParseCommandLine( %wZ ) failed - Status == %lx\n",
- InitialCommand, Status);
- return Status;
- }
-
- /* Execute the initial command -- but defer its full execution */
- Status = SmpExecuteImage(&ImageFileName,
- &ImageFileDirectory,
- InitialCommand,
- MuSessionId,
- SMP_DEFERRED_FLAG,
- &ProcessInfo);
-
- /* Free any buffers we had lying around */
- if (ImageFileName.Buffer)
- {
- RtlFreeHeap(RtlGetProcessHeap(), 0, ImageFileName.Buffer);
- }
- if (ImageFileDirectory.Buffer)
- {
- RtlFreeHeap(RtlGetProcessHeap(), 0, ImageFileDirectory.Buffer);
- }
- if (Arguments.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Arguments.Buffer);
-
- /* Bail out if we couldn't execute the initial command */
- if (!NT_SUCCESS(Status)) return Status;
-
- /* Now duplicate the handle to this process */
- Status = NtDuplicateObject(NtCurrentProcess(),
- ProcessInfo.ProcessHandle,
- NtCurrentProcess(),
- InitialCommandProcess,
- PROCESS_ALL_ACCESS,
- 0,
- 0);
- if (!NT_SUCCESS(Status))
- {
- /* Kill it utterly if duplication failed */
- DPRINT1("SMSS: DupObject Failed. Status == %lx\n", Status);
- NtTerminateProcess(ProcessInfo.ProcessHandle, Status);
- NtResumeThread(ProcessInfo.ThreadHandle, NULL);
- NtClose(ProcessInfo.ThreadHandle);
- NtClose(ProcessInfo.ProcessHandle);
- return Status;
- }
-
- /* Return PID to the caller, and set this as the initial command PID */
- if (ReturnPid) *ReturnPid = ProcessInfo.ClientId.UniqueProcess;
- if (!MuSessionId) SmpInitialCommandProcessId = ProcessInfo.ClientId.UniqueProcess;
-
- /* Now call our server execution function to wrap up its initialization */
- Status = SmExecPgm(SmApiPort, &ProcessInfo, FALSE);
- if (!NT_SUCCESS(Status)) DPRINT1("SMSS: SmExecPgm Failed. Status == %lx\n", Status);
- return Status;
-}
-
-NTSTATUS
-NTAPI
-SmpTerminate(IN PULONG_PTR Parameters,
- IN ULONG ParameterMask,
- IN ULONG ParameterCount)
-{
- NTSTATUS Status;
- BOOLEAN Old;
- ULONG Response;
-
- /* Give the shutdown privilege to the thread */
- if (RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, TRUE, &Old) ==
- STATUS_NO_TOKEN)
- {
- /* Thread doesn't have a token, give it to the entire process */
- RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old);
- }
-
- /* Take down the process/machine with a hard error */
- Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
- ParameterCount,
- ParameterMask,
- Parameters,
- OptionShutdownSystem,
- &Response);
-
- /* Terminate the process if the hard error didn't already */
- return NtTerminateProcess(NtCurrentProcess(), Status);
-}
-
-LONG
-SmpUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo)
-{
- ULONG_PTR Parameters[4];
- UNICODE_STRING DestinationString;
-
- /* Print and breakpoint into the debugger */
- DbgPrint("SMSS: Unhandled exception - Status == %x IP == %p\n",
- ExceptionInfo->ExceptionRecord->ExceptionCode,
- ExceptionInfo->ExceptionRecord->ExceptionAddress);
- DbgPrint(" Memory Address: %x Read/Write: %x\n",
- ExceptionInfo->ExceptionRecord->ExceptionInformation[0],
- ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
- DbgBreakPoint();
-
- /* Build the hard error and terminate */
- RtlInitUnicodeString(&DestinationString, L"Unhandled Exception in Session Manager");
- Parameters[0] = (ULONG_PTR)&DestinationString;
- Parameters[1] = ExceptionInfo->ExceptionRecord->ExceptionCode;
- Parameters[2] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress;
- Parameters[3] = (ULONG_PTR)ExceptionInfo->ContextRecord;
- SmpTerminate(Parameters, 1, RTL_NUMBER_OF(Parameters));
-
- /* We should never get here */
- ASSERT(FALSE);
- return EXCEPTION_EXECUTE_HANDLER;
-}
-
-NTSTATUS
-__cdecl
-_main(IN INT argc,
- IN PCHAR argv[],
- IN PCHAR envp[],
- IN ULONG DebugFlag)
-{
- NTSTATUS Status;
- KPRIORITY SetBasePriority;
- ULONG_PTR Parameters[4];
- HANDLE Handles[2];
- PVOID State;
- ULONG Flags;
- PROCESS_BASIC_INFORMATION ProcessInfo;
- UNICODE_STRING DbgString, InitialCommand;
-
- /* Make us critical */
- RtlSetProcessIsCritical(TRUE, NULL, FALSE);
- RtlSetThreadIsCritical(TRUE, NULL, FALSE);
-
- /* Raise our priority */
- SetBasePriority = 11;
- Status = NtSetInformationProcess(NtCurrentProcess(),
- ProcessBasePriority,
- (PVOID)&SetBasePriority,
- sizeof(SetBasePriority));
- ASSERT(NT_SUCCESS(Status));
-
- /* Save the debug flag if it was passed */
- if (DebugFlag) SmpDebug = DebugFlag != 0;
-
- /* Build the hard error parameters */
- Parameters[0] = (ULONG_PTR)&DbgString;
- Parameters[1] = Parameters[2] = Parameters[3] = 0;
-
- /* Enter SEH so we can terminate correctly if anything goes wrong */
- _SEH2_TRY
- {
- /* Initialize SMSS */
- Status = SmpInit(&InitialCommand, Handles);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("SMSS: SmpInit return failure - Status == %x\n", Status);
- RtlInitUnicodeString(&DbgString, L"Session Manager Initialization");
- Parameters[1] = Status;
- _SEH2_LEAVE;
- }
-
- /* Get the global flags */
- Status = NtQuerySystemInformation(SystemFlagsInformation,
- &Flags,
- sizeof(Flags),
- NULL);
- ASSERT(NT_SUCCESS(Status));
-
- /* Before executing the initial command check if the debug flag is on */
- if (Flags & (FLG_DEBUG_INITIAL_COMMAND | FLG_DEBUG_INITIAL_COMMAND_EX))
- {
- /* SMSS should launch ntsd with a few parameters at this point */
- DPRINT1("Global Flags Set to SMSS Debugging: Not yet supported\n");
- }
-
- /* Execute the initial command (Winlogon.exe) */
- Status = SmpExecuteInitialCommand(0, &InitialCommand, &Handles[1], NULL);
- if (!NT_SUCCESS(Status))
- {
- /* Fail and raise a hard error */
- DPRINT1("SMSS: Execute Initial Command failed\n");
- RtlInitUnicodeString(&DbgString,
- L"Session Manager ExecuteInitialCommand");
- Parameters[1] = Status;
- _SEH2_LEAVE;
- }
-
- /* Check if we're already attached to a session */
- Status = SmpAcquirePrivilege(SE_LOAD_DRIVER_PRIVILEGE, &State);
- if (AttachedSessionId != -1)
- {
- /* Detach from it, we should be in no session right now */
- Status = NtSetSystemInformation(SystemSessionDetach,
- &AttachedSessionId,
- sizeof(AttachedSessionId));
- ASSERT(NT_SUCCESS(Status));
- AttachedSessionId = -1;
- }
- SmpReleasePrivilege(State);
-
- /* Wait on either CSRSS or Winlogon to die */
- Status = NtWaitForMultipleObjects(RTL_NUMBER_OF(Handles),
- Handles,
- WaitAny,
- FALSE,
- NULL);
- if (Status == STATUS_WAIT_0)
- {
- /* CSRSS is dead, get exit code and prepare for the hard error */
- RtlInitUnicodeString(&DbgString, L"Windows SubSystem");
- Status = NtQueryInformationProcess(Handles[0],
- ProcessBasicInformation,
- &ProcessInfo,
- sizeof(ProcessInfo),
- NULL);
- DPRINT1("SMSS: Windows subsystem terminated when it wasn't supposed to.\n");
- }
- else
- {
- /* The initial command is dead or we have another failure */
- RtlInitUnicodeString(&DbgString, L"Windows Logon Process");
- if (Status == STATUS_WAIT_1)
- {
- /* Winlogon.exe got terminated, get its exit code */
- Status = NtQueryInformationProcess(Handles[1],
- ProcessBasicInformation,
- &ProcessInfo,
- sizeof(ProcessInfo),
- NULL);
- }
- else
- {
- /* Something else satisfied our wait, so set the wait status */
- ProcessInfo.ExitStatus = Status;
- Status = STATUS_SUCCESS;
- }
- DPRINT1("SMSS: Initial command '%wZ' terminated when it wasn't supposed to.\n",
- &InitialCommand);
- }
-
- /* Check if NtQueryInformationProcess was successful */
- if (NT_SUCCESS(Status))
- {
- /* Then we must have a valid exit status in the structure, use it */
- Parameters[1] = ProcessInfo.ExitStatus;
- }
- else
- {
- /* We really don't know what happened, so set a generic error */
- Parameters[1] = STATUS_UNSUCCESSFUL;
- }
- }
- _SEH2_EXCEPT(SmpUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
- {
- /* The filter should never return here */
- ASSERT(FALSE);
- }
- _SEH2_END;
-
- /* Something in the init loop failed, terminate SMSS */
- return SmpTerminate(Parameters, 1, RTL_NUMBER_OF(Parameters));
-}
-
-/* EOF */