xref: /reactos/base/system/smss/smss.c (revision f43ce465)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS Windows-Compatible Session Manager
3c2c66affSColin Finck  * LICENSE:         BSD 2-Clause License
4c2c66affSColin Finck  * FILE:            base/system/smss/smss.c
5c2c66affSColin Finck  * PURPOSE:         Main SMSS Code
6c2c66affSColin Finck  * PROGRAMMERS:     Alex Ionescu
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
9c2c66affSColin Finck /* INCLUDES *******************************************************************/
10c2c66affSColin Finck 
11c2c66affSColin Finck #include "smss.h"
12c2c66affSColin Finck 
13c2c66affSColin Finck #include <pseh/pseh2.h>
14c2c66affSColin Finck 
15c2c66affSColin Finck #define NDEBUG
16c2c66affSColin Finck #include <debug.h>
17c2c66affSColin Finck 
18c2c66affSColin Finck /* GLOBALS ********************************************************************/
19c2c66affSColin Finck 
20c2c66affSColin Finck UNICODE_STRING SmpSystemRoot;
21c2c66affSColin Finck ULONG AttachedSessionId = -1;
22c2c66affSColin Finck BOOLEAN SmpDebug, SmpEnableDots;
23c2c66affSColin Finck HANDLE SmApiPort;
24c2c66affSColin Finck HANDLE SmpInitialCommandProcessId;
25c2c66affSColin Finck 
26c2c66affSColin Finck /* FUNCTIONS ******************************************************************/
27c2c66affSColin Finck 
28c2c66affSColin Finck NTSTATUS
29c2c66affSColin Finck 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)30c2c66affSColin Finck SmpExecuteImage(IN PUNICODE_STRING FileName,
31c2c66affSColin Finck                 IN PUNICODE_STRING Directory,
32c2c66affSColin Finck                 IN PUNICODE_STRING CommandLine,
33c2c66affSColin Finck                 IN ULONG MuSessionId,
34c2c66affSColin Finck                 IN ULONG Flags,
35c2c66affSColin Finck                 IN PRTL_USER_PROCESS_INFORMATION ProcessInformation)
36c2c66affSColin Finck {
37c2c66affSColin Finck     PRTL_USER_PROCESS_INFORMATION ProcessInfo;
38c2c66affSColin Finck     NTSTATUS Status;
39c2c66affSColin Finck     RTL_USER_PROCESS_INFORMATION LocalProcessInfo;
40c2c66affSColin Finck     PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
41c2c66affSColin Finck 
42c2c66affSColin Finck     /* Use the input process information if we have it, otherwise use local */
43c2c66affSColin Finck     ProcessInfo = ProcessInformation;
44c2c66affSColin Finck     if (!ProcessInfo) ProcessInfo = &LocalProcessInfo;
45c2c66affSColin Finck 
46c2c66affSColin Finck     /* Create parameters for the target process */
47c2c66affSColin Finck     Status = RtlCreateProcessParameters(&ProcessParameters,
48c2c66affSColin Finck                                         FileName,
49c2c66affSColin Finck                                         SmpDefaultLibPath.Length ?
50c2c66affSColin Finck                                         &SmpDefaultLibPath : NULL,
51c2c66affSColin Finck                                         Directory,
52c2c66affSColin Finck                                         CommandLine,
53c2c66affSColin Finck                                         SmpDefaultEnvironment,
54c2c66affSColin Finck                                         NULL,
55c2c66affSColin Finck                                         NULL,
56c2c66affSColin Finck                                         NULL,
57c2c66affSColin Finck                                         0);
58c2c66affSColin Finck     if (!NT_SUCCESS(Status))
59c2c66affSColin Finck     {
60c2c66affSColin Finck         /* This is a pretty bad failure. ASSERT on checked builds and exit */
617d6bda16SSerge Gautherie         ASSERTMSG("RtlCreateProcessParameters failed.\n", NT_SUCCESS(Status));
62c2c66affSColin Finck         DPRINT1("SMSS: RtlCreateProcessParameters failed for %wZ - Status == %lx\n",
63c2c66affSColin Finck                 FileName, Status);
64c2c66affSColin Finck         return Status;
65c2c66affSColin Finck     }
66c2c66affSColin Finck 
67c2c66affSColin Finck     /* Set the size field as required */
68*f43ce465SHermès Bélusca-Maïto     ProcessInfo->Size = sizeof(*ProcessInfo);
69c2c66affSColin Finck 
70c2c66affSColin Finck     /* Check if the debug flag was requested */
71c2c66affSColin Finck     if (Flags & SMP_DEBUG_FLAG)
72c2c66affSColin Finck     {
73c2c66affSColin Finck         /* Write it in the process parameters */
74c2c66affSColin Finck         ProcessParameters->DebugFlags = 1;
75c2c66affSColin Finck     }
76c2c66affSColin Finck     else
77c2c66affSColin Finck     {
78c2c66affSColin Finck         /* Otherwise inherit the flag that was passed to SMSS itself */
79c2c66affSColin Finck         ProcessParameters->DebugFlags = SmpDebug;
80c2c66affSColin Finck     }
81c2c66affSColin Finck 
82c2c66affSColin Finck     /* Subsystems get the first 1MB of memory reserved for DOS/IVT purposes */
83c2c66affSColin Finck     if (Flags & SMP_SUBSYSTEM_FLAG)
84c2c66affSColin Finck     {
85c2c66affSColin Finck         ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB;
86c2c66affSColin Finck     }
87c2c66affSColin Finck 
88c2c66affSColin Finck     /* And always force NX for anything that SMSS launches */
89c2c66affSColin Finck     ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_NX;
90c2c66affSColin Finck 
91*f43ce465SHermès Bélusca-Maïto     /* Now create the process in suspended state */
92c2c66affSColin Finck     Status = RtlCreateUserProcess(FileName,
93c2c66affSColin Finck                                   OBJ_CASE_INSENSITIVE,
94c2c66affSColin Finck                                   ProcessParameters,
95c2c66affSColin Finck                                   NULL,
96c2c66affSColin Finck                                   NULL,
97c2c66affSColin Finck                                   NULL,
98c2c66affSColin Finck                                   FALSE,
99c2c66affSColin Finck                                   NULL,
100c2c66affSColin Finck                                   NULL,
101c2c66affSColin Finck                                   ProcessInfo);
102c2c66affSColin Finck     RtlDestroyProcessParameters(ProcessParameters);
103c2c66affSColin Finck     if (!NT_SUCCESS(Status))
104c2c66affSColin Finck     {
105c2c66affSColin Finck         /* If we couldn't create it, fail back to the caller */
106c2c66affSColin Finck         DPRINT1("SMSS: Failed load of %wZ - Status  == %lx\n",
107c2c66affSColin Finck                 FileName, Status);
108c2c66affSColin Finck         return Status;
109c2c66affSColin Finck     }
110c2c66affSColin Finck 
111c2c66affSColin Finck     /* Associate a session with this process */
112c2c66affSColin Finck     Status = SmpSetProcessMuSessionId(ProcessInfo->ProcessHandle, MuSessionId);
113c2c66affSColin Finck 
114c2c66affSColin Finck     /* If the application is deferred (suspended), there's nothing to do */
115c2c66affSColin Finck     if (Flags & SMP_DEFERRED_FLAG) return Status;
116c2c66affSColin Finck 
117c2c66affSColin Finck     /* Otherwise, get ready to start it, but make sure it's a native app */
118c2c66affSColin Finck     if (ProcessInfo->ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_NATIVE)
119c2c66affSColin Finck     {
120c2c66affSColin Finck         /* Resume it */
121c2c66affSColin Finck         NtResumeThread(ProcessInfo->ThreadHandle, NULL);
122c2c66affSColin Finck         if (!(Flags & SMP_ASYNC_FLAG))
123c2c66affSColin Finck         {
124c2c66affSColin Finck             /* Block on it unless Async was requested */
125c2c66affSColin Finck             NtWaitForSingleObject(ProcessInfo->ThreadHandle, FALSE, NULL);
126c2c66affSColin Finck         }
127c2c66affSColin Finck 
128c2c66affSColin Finck         /* It's up and running now, close our handles */
129c2c66affSColin Finck         NtClose(ProcessInfo->ThreadHandle);
130c2c66affSColin Finck         NtClose(ProcessInfo->ProcessHandle);
131c2c66affSColin Finck     }
132c2c66affSColin Finck     else
133c2c66affSColin Finck     {
134c2c66affSColin Finck         /* This image is invalid, so kill it, close our handles, and fail */
135c2c66affSColin Finck         Status = STATUS_INVALID_IMAGE_FORMAT;
136c2c66affSColin Finck         NtTerminateProcess(ProcessInfo->ProcessHandle, Status);
137*f43ce465SHermès Bélusca-Maïto         NtWaitForSingleObject(ProcessInfo->ThreadHandle, FALSE, NULL);
138c2c66affSColin Finck         NtClose(ProcessInfo->ThreadHandle);
139c2c66affSColin Finck         NtClose(ProcessInfo->ProcessHandle);
140c2c66affSColin Finck         DPRINT1("SMSS: Not an NT image - %wZ\n", FileName);
141c2c66affSColin Finck     }
142c2c66affSColin Finck 
143c2c66affSColin Finck     /* Return the outcome of the process create */
144c2c66affSColin Finck     return Status;
145c2c66affSColin Finck }
146c2c66affSColin Finck 
147c2c66affSColin Finck NTSTATUS
148c2c66affSColin Finck NTAPI
SmpInvokeAutoChk(IN PUNICODE_STRING FileName,IN PUNICODE_STRING Directory,IN PUNICODE_STRING Arguments,IN ULONG Flags)149c2c66affSColin Finck SmpInvokeAutoChk(IN PUNICODE_STRING FileName,
150c2c66affSColin Finck                  IN PUNICODE_STRING Directory,
151c2c66affSColin Finck                  IN PUNICODE_STRING Arguments,
152c2c66affSColin Finck                  IN ULONG Flags)
153c2c66affSColin Finck {
154c2c66affSColin Finck     ANSI_STRING MessageString;
155c2c66affSColin Finck     CHAR MessageBuffer[256];
156c2c66affSColin Finck     UNICODE_STRING Destination;
157c2c66affSColin Finck     WCHAR Buffer[1024];
158c2c66affSColin Finck     BOOLEAN BootState, BootOkay, ShutdownOkay;
159c2c66affSColin Finck 
160c2c66affSColin Finck     /* Check if autochk should show dots (if the user booted with /SOS) */
161c2c66affSColin Finck     if (SmpQueryRegistrySosOption()) SmpEnableDots = FALSE;
162c2c66affSColin Finck 
163c2c66affSColin Finck     /* Make sure autochk was actually found */
164c2c66affSColin Finck     if (Flags & SMP_INVALID_PATH)
165c2c66affSColin Finck     {
166c2c66affSColin Finck         /* It wasn't, so create an error message to print on the screen */
1670997e902SHermès Bélusca-Maïto         RtlStringCbPrintfA(MessageBuffer,
1680997e902SHermès Bélusca-Maïto                            sizeof(MessageBuffer),
169c2c66affSColin Finck                            "%wZ program not found - skipping AUTOCHECK\r\n",
170c2c66affSColin Finck                            FileName);
171c2c66affSColin Finck         RtlInitAnsiString(&MessageString, MessageBuffer);
172c2c66affSColin Finck         if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&Destination,
173c2c66affSColin Finck                                                     &MessageString,
174c2c66affSColin Finck                                                     TRUE)))
175c2c66affSColin Finck         {
176c2c66affSColin Finck             /* And show it */
177c2c66affSColin Finck             NtDisplayString(&Destination);
178c2c66affSColin Finck             RtlFreeUnicodeString(&Destination);
179c2c66affSColin Finck         }
180c2c66affSColin Finck     }
181c2c66affSColin Finck     else
182c2c66affSColin Finck     {
183c2c66affSColin Finck         /* Autochk is there, so record the BSD state */
184c2c66affSColin Finck         BootState = SmpSaveAndClearBootStatusData(&BootOkay, &ShutdownOkay);
185c2c66affSColin Finck 
186c2c66affSColin Finck         /* Build the path to autochk and place its arguments */
187c2c66affSColin Finck         RtlInitEmptyUnicodeString(&Destination, Buffer, sizeof(Buffer));
188c2c66affSColin Finck         RtlAppendUnicodeStringToString(&Destination, FileName);
189c2c66affSColin Finck         RtlAppendUnicodeToString(&Destination, L" ");
190c2c66affSColin Finck         RtlAppendUnicodeStringToString(&Destination, Arguments);
191c2c66affSColin Finck 
192c2c66affSColin Finck         /* Execute it */
193c2c66affSColin Finck         SmpExecuteImage(FileName,
194c2c66affSColin Finck                         Directory,
195c2c66affSColin Finck                         &Destination,
196c2c66affSColin Finck                         0,
197c2c66affSColin Finck                         Flags & ~SMP_AUTOCHK_FLAG,
198c2c66affSColin Finck                         NULL);
199c2c66affSColin Finck 
200c2c66affSColin Finck         /* Restore the BSD state */
201c2c66affSColin Finck         if (BootState) SmpRestoreBootStatusData(BootOkay, ShutdownOkay);
202c2c66affSColin Finck     }
203c2c66affSColin Finck 
204c2c66affSColin Finck     /* We're all done! */
205c2c66affSColin Finck     return STATUS_SUCCESS;
206c2c66affSColin Finck }
207c2c66affSColin Finck 
208c2c66affSColin Finck NTSTATUS
209c2c66affSColin Finck NTAPI
SmpExecuteCommand(IN PUNICODE_STRING CommandLine,IN ULONG MuSessionId,OUT PHANDLE ProcessId,IN ULONG Flags)210c2c66affSColin Finck SmpExecuteCommand(IN PUNICODE_STRING CommandLine,
211c2c66affSColin Finck                   IN ULONG MuSessionId,
212c2c66affSColin Finck                   OUT PHANDLE ProcessId,
213c2c66affSColin Finck                   IN ULONG Flags)
214c2c66affSColin Finck {
215c2c66affSColin Finck     NTSTATUS Status;
216c2c66affSColin Finck     UNICODE_STRING Arguments, Directory, FileName;
217c2c66affSColin Finck 
218c2c66affSColin Finck     /* There's no longer a debugging subsystem */
219c2c66affSColin Finck     if (Flags & SMP_DEBUG_FLAG) return STATUS_SUCCESS;
220c2c66affSColin Finck 
221c2c66affSColin Finck     /* Parse the command line to see what execution flags are requested */
222c2c66affSColin Finck     Status = SmpParseCommandLine(CommandLine,
223c2c66affSColin Finck                                  &Flags,
224c2c66affSColin Finck                                  &FileName,
225c2c66affSColin Finck                                  &Directory,
226c2c66affSColin Finck                                  &Arguments);
227c2c66affSColin Finck     if (!NT_SUCCESS(Status))
228c2c66affSColin Finck     {
229c2c66affSColin Finck         /* Fail if we couldn't do that */
230c2c66affSColin Finck         DPRINT1("SMSS: SmpParseCommandLine( %wZ ) failed - Status == %lx\n",
231c2c66affSColin Finck                 CommandLine, Status);
232c2c66affSColin Finck         return Status;
233c2c66affSColin Finck     }
234c2c66affSColin Finck 
235c2c66affSColin Finck     /* Check if autochk is requested */
236c2c66affSColin Finck     if (Flags & SMP_AUTOCHK_FLAG)
237c2c66affSColin Finck     {
238c2c66affSColin Finck         /* Run it */
239c2c66affSColin Finck         Status = SmpInvokeAutoChk(&FileName, &Directory, &Arguments, Flags);
240c2c66affSColin Finck     }
241c2c66affSColin Finck     else if (Flags & SMP_SUBSYSTEM_FLAG)
242c2c66affSColin Finck     {
243c2c66affSColin Finck         Status = SmpLoadSubSystem(&FileName,
244c2c66affSColin Finck                                   &Directory,
245c2c66affSColin Finck                                   CommandLine,
246c2c66affSColin Finck                                   MuSessionId,
247c2c66affSColin Finck                                   ProcessId,
248c2c66affSColin Finck                                   Flags);
249c2c66affSColin Finck     }
250c2c66affSColin Finck     else if (Flags & SMP_INVALID_PATH)
251c2c66affSColin Finck     {
252c2c66affSColin Finck         /* An invalid image was specified, fail */
253c2c66affSColin Finck         DPRINT1("SMSS: Image file (%wZ) not found\n", &FileName);
254c2c66affSColin Finck         Status = STATUS_OBJECT_NAME_NOT_FOUND;
255c2c66affSColin Finck     }
256c2c66affSColin Finck     else
257c2c66affSColin Finck     {
258*f43ce465SHermès Bélusca-Maïto         /* An actual image name was present, execute it */
259c2c66affSColin Finck         Status = SmpExecuteImage(&FileName,
260c2c66affSColin Finck                                  &Directory,
261c2c66affSColin Finck                                  CommandLine,
262c2c66affSColin Finck                                  MuSessionId,
263c2c66affSColin Finck                                  Flags,
264c2c66affSColin Finck                                  NULL);
265c2c66affSColin Finck     }
266c2c66affSColin Finck 
267c2c66affSColin Finck     /* Free all the token parameters */
268c2c66affSColin Finck     if (FileName.Buffer)  RtlFreeHeap(RtlGetProcessHeap(), 0, FileName.Buffer);
269c2c66affSColin Finck     if (Directory.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Directory.Buffer);
270c2c66affSColin Finck     if (Arguments.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Arguments.Buffer);
271c2c66affSColin Finck 
272c2c66affSColin Finck     /* Return to the caller */
273c2c66affSColin Finck     if (!NT_SUCCESS(Status))
274c2c66affSColin Finck     {
275c2c66affSColin Finck         DPRINT1("SMSS: Command '%wZ' failed - Status == %x\n",
276c2c66affSColin Finck                 CommandLine, Status);
277c2c66affSColin Finck     }
278c2c66affSColin Finck     return Status;
279c2c66affSColin Finck }
280c2c66affSColin Finck 
281c2c66affSColin Finck NTSTATUS
282c2c66affSColin Finck NTAPI
SmpExecuteInitialCommand(IN ULONG MuSessionId,IN PUNICODE_STRING InitialCommand,IN HANDLE InitialCommandProcess,OUT PHANDLE ReturnPid)283c2c66affSColin Finck SmpExecuteInitialCommand(IN ULONG MuSessionId,
284c2c66affSColin Finck                          IN PUNICODE_STRING InitialCommand,
285c2c66affSColin Finck                          IN HANDLE InitialCommandProcess,
286c2c66affSColin Finck                          OUT PHANDLE ReturnPid)
287c2c66affSColin Finck {
288c2c66affSColin Finck     NTSTATUS Status;
289c2c66affSColin Finck     RTL_USER_PROCESS_INFORMATION ProcessInfo;
290*f43ce465SHermès Bélusca-Maïto     UNICODE_STRING Arguments, Directory, FileName;
291c2c66affSColin Finck     ULONG Flags = 0;
292c2c66affSColin Finck 
293c2c66affSColin Finck     /* Check if we haven't yet connected to ourselves */
294c2c66affSColin Finck     if (!SmApiPort)
295c2c66affSColin Finck     {
296c2c66affSColin Finck         /* Connect to ourselves, as a client */
297f766ca5eSHermès Bélusca-Maïto         Status = SmConnectToSm(NULL, NULL, 0, &SmApiPort);
298c2c66affSColin Finck         if (!NT_SUCCESS(Status))
299c2c66affSColin Finck         {
300c2c66affSColin Finck             DPRINT1("SMSS: Unable to connect to SM - Status == %lx\n", Status);
301c2c66affSColin Finck             return Status;
302c2c66affSColin Finck         }
303c2c66affSColin Finck     }
304c2c66affSColin Finck 
305c2c66affSColin Finck     /* Parse the initial command line */
306c2c66affSColin Finck     Status = SmpParseCommandLine(InitialCommand,
307c2c66affSColin Finck                                  &Flags,
308*f43ce465SHermès Bélusca-Maïto                                  &FileName,
309*f43ce465SHermès Bélusca-Maïto                                  &Directory,
310c2c66affSColin Finck                                  &Arguments);
311c2c66affSColin Finck     if (Flags & SMP_INVALID_PATH)
312c2c66affSColin Finck     {
313c2c66affSColin Finck         /* Fail if it doesn't exist */
314*f43ce465SHermès Bélusca-Maïto         DPRINT1("SMSS: Initial command image (%wZ) not found\n", &FileName);
315*f43ce465SHermès Bélusca-Maïto         if (FileName.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, FileName.Buffer);
316c2c66affSColin Finck         return STATUS_OBJECT_NAME_NOT_FOUND;
317c2c66affSColin Finck     }
318c2c66affSColin Finck 
319c2c66affSColin Finck     /* And fail if any other reason is also true */
320c2c66affSColin Finck     if (!NT_SUCCESS(Status))
321c2c66affSColin Finck     {
322c2c66affSColin Finck         DPRINT1("SMSS: SmpParseCommandLine( %wZ ) failed - Status == %lx\n",
323c2c66affSColin Finck                 InitialCommand, Status);
324c2c66affSColin Finck         return Status;
325c2c66affSColin Finck     }
326c2c66affSColin Finck 
327*f43ce465SHermès Bélusca-Maïto     /* Execute the initial command, but defer its full execution */
328*f43ce465SHermès Bélusca-Maïto     Status = SmpExecuteImage(&FileName,
329*f43ce465SHermès Bélusca-Maïto                              &Directory,
330c2c66affSColin Finck                              InitialCommand,
331c2c66affSColin Finck                              MuSessionId,
332c2c66affSColin Finck                              SMP_DEFERRED_FLAG,
333c2c66affSColin Finck                              &ProcessInfo);
334c2c66affSColin Finck 
335*f43ce465SHermès Bélusca-Maïto     /* Free all the token parameters */
336*f43ce465SHermès Bélusca-Maïto     if (FileName.Buffer)  RtlFreeHeap(RtlGetProcessHeap(), 0, FileName.Buffer);
337*f43ce465SHermès Bélusca-Maïto     if (Directory.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Directory.Buffer);
338c2c66affSColin Finck     if (Arguments.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Arguments.Buffer);
339c2c66affSColin Finck 
340c2c66affSColin Finck     /* Bail out if we couldn't execute the initial command */
341c2c66affSColin Finck     if (!NT_SUCCESS(Status)) return Status;
342c2c66affSColin Finck 
343c2c66affSColin Finck     /* Now duplicate the handle to this process */
344c2c66affSColin Finck     Status = NtDuplicateObject(NtCurrentProcess(),
345c2c66affSColin Finck                                ProcessInfo.ProcessHandle,
346c2c66affSColin Finck                                NtCurrentProcess(),
347c2c66affSColin Finck                                InitialCommandProcess,
348c2c66affSColin Finck                                PROCESS_ALL_ACCESS,
349c2c66affSColin Finck                                0,
350c2c66affSColin Finck                                0);
351c2c66affSColin Finck     if (!NT_SUCCESS(Status))
352c2c66affSColin Finck     {
353c2c66affSColin Finck         /* Kill it utterly if duplication failed */
354c2c66affSColin Finck         DPRINT1("SMSS: DupObject Failed. Status == %lx\n", Status);
355c2c66affSColin Finck         NtTerminateProcess(ProcessInfo.ProcessHandle, Status);
356c2c66affSColin Finck         NtResumeThread(ProcessInfo.ThreadHandle, NULL);
357c2c66affSColin Finck         NtClose(ProcessInfo.ThreadHandle);
358c2c66affSColin Finck         NtClose(ProcessInfo.ProcessHandle);
359c2c66affSColin Finck         return Status;
360c2c66affSColin Finck     }
361c2c66affSColin Finck 
362c2c66affSColin Finck     /* Return PID to the caller, and set this as the initial command PID */
363c2c66affSColin Finck     if (ReturnPid) *ReturnPid = ProcessInfo.ClientId.UniqueProcess;
364c2c66affSColin Finck     if (!MuSessionId) SmpInitialCommandProcessId = ProcessInfo.ClientId.UniqueProcess;
365c2c66affSColin Finck 
366c2c66affSColin Finck     /* Now call our server execution function to wrap up its initialization */
367c2c66affSColin Finck     Status = SmExecPgm(SmApiPort, &ProcessInfo, FALSE);
368c2c66affSColin Finck     if (!NT_SUCCESS(Status)) DPRINT1("SMSS: SmExecPgm Failed. Status == %lx\n", Status);
369c2c66affSColin Finck     return Status;
370c2c66affSColin Finck }
371c2c66affSColin Finck 
372c2c66affSColin Finck NTSTATUS
373c2c66affSColin Finck NTAPI
SmpTerminate(IN PULONG_PTR Parameters,IN ULONG ParameterMask,IN ULONG ParameterCount)374c2c66affSColin Finck SmpTerminate(IN PULONG_PTR Parameters,
375c2c66affSColin Finck              IN ULONG ParameterMask,
376c2c66affSColin Finck              IN ULONG ParameterCount)
377c2c66affSColin Finck {
378c2c66affSColin Finck     NTSTATUS Status;
379c2c66affSColin Finck     BOOLEAN Old;
380c2c66affSColin Finck     ULONG Response;
381c2c66affSColin Finck 
382c2c66affSColin Finck     /* Give the shutdown privilege to the thread */
383c2c66affSColin Finck     if (RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, TRUE, &Old) ==
384c2c66affSColin Finck         STATUS_NO_TOKEN)
385c2c66affSColin Finck     {
386c2c66affSColin Finck         /* Thread doesn't have a token, give it to the entire process */
387c2c66affSColin Finck         RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old);
388c2c66affSColin Finck     }
389c2c66affSColin Finck 
390c2c66affSColin Finck     /* Take down the process/machine with a hard error */
391c2c66affSColin Finck     Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
392c2c66affSColin Finck                               ParameterCount,
393c2c66affSColin Finck                               ParameterMask,
394c2c66affSColin Finck                               Parameters,
395c2c66affSColin Finck                               OptionShutdownSystem,
396c2c66affSColin Finck                               &Response);
397c2c66affSColin Finck 
398c2c66affSColin Finck     /* Terminate the process if the hard error didn't already */
399c2c66affSColin Finck     return NtTerminateProcess(NtCurrentProcess(), Status);
400c2c66affSColin Finck }
401c2c66affSColin Finck 
402c2c66affSColin Finck LONG
SmpUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo)403c2c66affSColin Finck SmpUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo)
404c2c66affSColin Finck {
405c2c66affSColin Finck     ULONG_PTR Parameters[4];
406*f43ce465SHermès Bélusca-Maïto     UNICODE_STRING ErrorString;
407c2c66affSColin Finck 
408c2c66affSColin Finck     /* Print and breakpoint into the debugger */
409c2c66affSColin Finck     DbgPrint("SMSS: Unhandled exception - Status == %x  IP == %p\n",
410c2c66affSColin Finck              ExceptionInfo->ExceptionRecord->ExceptionCode,
411c2c66affSColin Finck              ExceptionInfo->ExceptionRecord->ExceptionAddress);
412c2c66affSColin Finck     DbgPrint("      Memory Address: %x  Read/Write: %x\n",
413c2c66affSColin Finck              ExceptionInfo->ExceptionRecord->ExceptionInformation[0],
414c2c66affSColin Finck              ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
415c2c66affSColin Finck     DbgBreakPoint();
416c2c66affSColin Finck 
417c2c66affSColin Finck     /* Build the hard error and terminate */
418*f43ce465SHermès Bélusca-Maïto     RtlInitUnicodeString(&ErrorString, L"Unhandled Exception in Session Manager");
419*f43ce465SHermès Bélusca-Maïto     Parameters[0] = (ULONG_PTR)&ErrorString;
420c2c66affSColin Finck     Parameters[1] = ExceptionInfo->ExceptionRecord->ExceptionCode;
421c2c66affSColin Finck     Parameters[2] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress;
422c2c66affSColin Finck     Parameters[3] = (ULONG_PTR)ExceptionInfo->ContextRecord;
423c2c66affSColin Finck     SmpTerminate(Parameters, 1, RTL_NUMBER_OF(Parameters));
424c2c66affSColin Finck 
425c2c66affSColin Finck     /* We should never get here */
426c2c66affSColin Finck     ASSERT(FALSE);
427c2c66affSColin Finck     return EXCEPTION_EXECUTE_HANDLER;
428c2c66affSColin Finck }
429c2c66affSColin Finck 
430c2c66affSColin Finck NTSTATUS
431c2c66affSColin Finck __cdecl
_main(IN INT argc,IN PCHAR argv[],IN PCHAR envp[],IN ULONG DebugFlag)432c2c66affSColin Finck _main(IN INT argc,
433c2c66affSColin Finck       IN PCHAR argv[],
434c2c66affSColin Finck       IN PCHAR envp[],
435c2c66affSColin Finck       IN ULONG DebugFlag)
436c2c66affSColin Finck {
437c2c66affSColin Finck     NTSTATUS Status;
438c2c66affSColin Finck     KPRIORITY SetBasePriority;
439c2c66affSColin Finck     ULONG_PTR Parameters[4];
440c2c66affSColin Finck     HANDLE Handles[2];
441c2c66affSColin Finck     PVOID State;
442c2c66affSColin Finck     ULONG Flags;
443c2c66affSColin Finck     PROCESS_BASIC_INFORMATION ProcessInfo;
444c2c66affSColin Finck     UNICODE_STRING DbgString, InitialCommand;
445c2c66affSColin Finck 
446c2c66affSColin Finck     /* Make us critical */
447c2c66affSColin Finck     RtlSetProcessIsCritical(TRUE, NULL, FALSE);
448c2c66affSColin Finck     RtlSetThreadIsCritical(TRUE, NULL, FALSE);
449c2c66affSColin Finck 
450c2c66affSColin Finck     /* Raise our priority */
451c2c66affSColin Finck     SetBasePriority = 11;
452c2c66affSColin Finck     Status = NtSetInformationProcess(NtCurrentProcess(),
453c2c66affSColin Finck                                      ProcessBasePriority,
454c2c66affSColin Finck                                      (PVOID)&SetBasePriority,
455c2c66affSColin Finck                                      sizeof(SetBasePriority));
456c2c66affSColin Finck     ASSERT(NT_SUCCESS(Status));
457c2c66affSColin Finck 
458c2c66affSColin Finck     /* Save the debug flag if it was passed */
459c2c66affSColin Finck     if (DebugFlag) SmpDebug = DebugFlag != 0;
460c2c66affSColin Finck 
461c2c66affSColin Finck     /* Build the hard error parameters */
462c2c66affSColin Finck     Parameters[0] = (ULONG_PTR)&DbgString;
463c2c66affSColin Finck     Parameters[1] = Parameters[2] = Parameters[3] = 0;
464c2c66affSColin Finck 
465c2c66affSColin Finck     /* Enter SEH so we can terminate correctly if anything goes wrong */
466c2c66affSColin Finck     _SEH2_TRY
467c2c66affSColin Finck     {
468c2c66affSColin Finck         /* Initialize SMSS */
469cb8c8693SHermès Bélusca-Maïto         Status = SmpInit(&InitialCommand, &Handles[0]);
470c2c66affSColin Finck         if (!NT_SUCCESS(Status))
471c2c66affSColin Finck         {
472c2c66affSColin Finck             DPRINT1("SMSS: SmpInit return failure - Status == %x\n", Status);
473c2c66affSColin Finck             RtlInitUnicodeString(&DbgString, L"Session Manager Initialization");
474c2c66affSColin Finck             Parameters[1] = Status;
475c2c66affSColin Finck             _SEH2_LEAVE;
476c2c66affSColin Finck         }
477c2c66affSColin Finck 
478c2c66affSColin Finck         /* Get the global flags */
479c2c66affSColin Finck         Status = NtQuerySystemInformation(SystemFlagsInformation,
480c2c66affSColin Finck                                           &Flags,
481c2c66affSColin Finck                                           sizeof(Flags),
482c2c66affSColin Finck                                           NULL);
483c2c66affSColin Finck         ASSERT(NT_SUCCESS(Status));
484c2c66affSColin Finck 
485c2c66affSColin Finck         /* Before executing the initial command check if the debug flag is on */
486c2c66affSColin Finck         if (Flags & (FLG_DEBUG_INITIAL_COMMAND | FLG_DEBUG_INITIAL_COMMAND_EX))
487c2c66affSColin Finck         {
488c2c66affSColin Finck             /* SMSS should launch ntsd with a few parameters at this point */
489c2c66affSColin Finck             DPRINT1("Global Flags Set to SMSS Debugging: Not yet supported\n");
490c2c66affSColin Finck         }
491c2c66affSColin Finck 
492c2c66affSColin Finck         /* Execute the initial command (Winlogon.exe) */
493c2c66affSColin Finck         Status = SmpExecuteInitialCommand(0, &InitialCommand, &Handles[1], NULL);
494c2c66affSColin Finck         if (!NT_SUCCESS(Status))
495c2c66affSColin Finck         {
496c2c66affSColin Finck             /* Fail and raise a hard error */
497c2c66affSColin Finck             DPRINT1("SMSS: Execute Initial Command failed\n");
498c2c66affSColin Finck             RtlInitUnicodeString(&DbgString,
499c2c66affSColin Finck                                  L"Session Manager ExecuteInitialCommand");
500c2c66affSColin Finck             Parameters[1] = Status;
501c2c66affSColin Finck             _SEH2_LEAVE;
502c2c66affSColin Finck         }
503c2c66affSColin Finck 
504c2c66affSColin Finck         /*  Check if we're already attached to a session */
505c2c66affSColin Finck         Status = SmpAcquirePrivilege(SE_LOAD_DRIVER_PRIVILEGE, &State);
506c2c66affSColin Finck         if (AttachedSessionId != -1)
507c2c66affSColin Finck         {
508c2c66affSColin Finck             /* Detach from it, we should be in no session right now */
509c2c66affSColin Finck             Status = NtSetSystemInformation(SystemSessionDetach,
510c2c66affSColin Finck                                             &AttachedSessionId,
511c2c66affSColin Finck                                             sizeof(AttachedSessionId));
512c2c66affSColin Finck             ASSERT(NT_SUCCESS(Status));
513c2c66affSColin Finck             AttachedSessionId = -1;
514c2c66affSColin Finck         }
515c2c66affSColin Finck         SmpReleasePrivilege(State);
516c2c66affSColin Finck 
517c2c66affSColin Finck         /* Wait on either CSRSS or Winlogon to die */
518c2c66affSColin Finck         Status = NtWaitForMultipleObjects(RTL_NUMBER_OF(Handles),
519c2c66affSColin Finck                                           Handles,
520c2c66affSColin Finck                                           WaitAny,
521c2c66affSColin Finck                                           FALSE,
522c2c66affSColin Finck                                           NULL);
523c2c66affSColin Finck         if (Status == STATUS_WAIT_0)
524c2c66affSColin Finck         {
525c2c66affSColin Finck             /* CSRSS is dead, get exit code and prepare for the hard error */
526c2c66affSColin Finck             RtlInitUnicodeString(&DbgString, L"Windows SubSystem");
527c2c66affSColin Finck             Status = NtQueryInformationProcess(Handles[0],
528c2c66affSColin Finck                                                ProcessBasicInformation,
529c2c66affSColin Finck                                                &ProcessInfo,
530c2c66affSColin Finck                                                sizeof(ProcessInfo),
531c2c66affSColin Finck                                                NULL);
532c2c66affSColin Finck             DPRINT1("SMSS: Windows subsystem terminated when it wasn't supposed to.\n");
533c2c66affSColin Finck         }
534c2c66affSColin Finck         else
535c2c66affSColin Finck         {
536c2c66affSColin Finck             /* The initial command is dead or we have another failure */
537c2c66affSColin Finck             RtlInitUnicodeString(&DbgString, L"Windows Logon Process");
538c2c66affSColin Finck             if (Status == STATUS_WAIT_1)
539c2c66affSColin Finck             {
540c2c66affSColin Finck                 /* Winlogon.exe got terminated, get its exit code */
541c2c66affSColin Finck                 Status = NtQueryInformationProcess(Handles[1],
542c2c66affSColin Finck                                                    ProcessBasicInformation,
543c2c66affSColin Finck                                                    &ProcessInfo,
544c2c66affSColin Finck                                                    sizeof(ProcessInfo),
545c2c66affSColin Finck                                                    NULL);
546c2c66affSColin Finck             }
547c2c66affSColin Finck             else
548c2c66affSColin Finck             {
549c2c66affSColin Finck                 /* Something else satisfied our wait, so set the wait status */
550c2c66affSColin Finck                 ProcessInfo.ExitStatus = Status;
551c2c66affSColin Finck                 Status = STATUS_SUCCESS;
552c2c66affSColin Finck             }
553c2c66affSColin Finck             DPRINT1("SMSS: Initial command '%wZ' terminated when it wasn't supposed to.\n",
554c2c66affSColin Finck                     &InitialCommand);
555c2c66affSColin Finck         }
556c2c66affSColin Finck 
557c2c66affSColin Finck         /* Check if NtQueryInformationProcess was successful */
558c2c66affSColin Finck         if (NT_SUCCESS(Status))
559c2c66affSColin Finck         {
560c2c66affSColin Finck             /* Then we must have a valid exit status in the structure, use it */
561c2c66affSColin Finck             Parameters[1] = ProcessInfo.ExitStatus;
562c2c66affSColin Finck         }
563c2c66affSColin Finck         else
564c2c66affSColin Finck         {
565c2c66affSColin Finck             /* We really don't know what happened, so set a generic error */
566c2c66affSColin Finck             Parameters[1] = STATUS_UNSUCCESSFUL;
567c2c66affSColin Finck         }
568c2c66affSColin Finck     }
569c2c66affSColin Finck     _SEH2_EXCEPT(SmpUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
570c2c66affSColin Finck     {
571c2c66affSColin Finck         /* The filter should never return here */
572c2c66affSColin Finck         ASSERT(FALSE);
573c2c66affSColin Finck     }
574c2c66affSColin Finck     _SEH2_END;
575c2c66affSColin Finck 
576c2c66affSColin Finck     /* Something in the init loop failed, terminate SMSS */
577c2c66affSColin Finck     return SmpTerminate(Parameters, 1, RTL_NUMBER_OF(Parameters));
578c2c66affSColin Finck }
579c2c66affSColin Finck 
580c2c66affSColin Finck /* EOF */
581