* Sync up to trunk r55544.
[reactos.git] / base / system / smss2 / smss.c
1 /*
2 * PROJECT: ReactOS Windows-Compatible Session Manager
3 * LICENSE: BSD 2-Clause License
4 * FILE: base/system/smss/smss.c
5 * PURPOSE: Main SMSS Code
6 * PROGRAMMERS: Alex Ionescu
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "smss.h"
12 #define NDEBUG
13 #include "debug.h"
14
15 /* GLOBALS ********************************************************************/
16
17 typedef struct _INIT_BUFFER
18 {
19 WCHAR DebugBuffer[256];
20 RTL_USER_PROCESS_INFORMATION ProcessInfo;
21 } INIT_BUFFER, *PINIT_BUFFER;
22
23 /* NT Initial User Application */
24 WCHAR NtInitialUserProcessBuffer[128] = L"\\SystemRoot\\System32\\smss.exe";
25 ULONG NtInitialUserProcessBufferLength = sizeof(NtInitialUserProcessBuffer) -
26 sizeof(WCHAR);
27 ULONG NtInitialUserProcessBufferType = REG_SZ;
28
29 UNICODE_STRING SmpSystemRoot;
30 ULONG AttachedSessionId = -1;
31 BOOLEAN SmpDebug, SmpEnableDots;
32 HANDLE SmApiPort;
33 HANDLE SmpInitialCommandProcessId;
34
35 /* FUNCTIONS ******************************************************************/
36
37 /* GCC's incompetence strikes again */
38 VOID
39 sprintf_nt(IN PCHAR Buffer,
40 IN PCHAR Format,
41 IN ...)
42 {
43 va_list ap;
44 va_start(ap, Format);
45 sprintf(Buffer, Format, ap);
46 va_end(ap);
47 }
48
49 NTSTATUS
50 NTAPI
51 SmpExecuteImage(IN PUNICODE_STRING FileName,
52 IN PUNICODE_STRING Directory,
53 IN PUNICODE_STRING CommandLine,
54 IN ULONG MuSessionId,
55 IN ULONG Flags,
56 IN PRTL_USER_PROCESS_INFORMATION ProcessInformation)
57 {
58 PRTL_USER_PROCESS_INFORMATION ProcessInfo;
59 NTSTATUS Status;
60 RTL_USER_PROCESS_INFORMATION LocalProcessInfo;
61 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
62 DPRINT1("Executing image: %wZ\n", FileName);
63
64 /* Use the input process information if we have it, otherwise use local */
65 ProcessInfo = ProcessInformation;
66 if (!ProcessInfo) ProcessInfo = &LocalProcessInfo;
67
68 /* Create parameters for the target process */
69 Status = RtlCreateProcessParameters(&ProcessParameters,
70 FileName,
71 SmpDefaultLibPath.Length ?
72 &SmpDefaultLibPath : NULL,
73 Directory,
74 CommandLine,
75 SmpDefaultEnvironment,
76 NULL,
77 NULL,
78 NULL,
79 0);
80 if (!NT_SUCCESS(Status))
81 {
82 /* This is a pretty bad failure. ASSERT on checked builds and exit */
83 ASSERTMSG(NT_SUCCESS(Status), "RtlCreateProcessParameters");
84 DPRINT1("SMSS: RtlCreateProcessParameters failed for %wZ - Status == %lx\n",
85 FileName, Status);
86 return Status;
87 }
88
89 /* Set the size field as required */
90 ProcessInfo->Size = sizeof(RTL_USER_PROCESS_INFORMATION);
91
92 /* Check if the debug flag was requested */
93 if (Flags & SMP_DEBUG_FLAG)
94 {
95 /* Write it in the process parameters */
96 ProcessParameters->DebugFlags = 1;
97 }
98 else
99 {
100 /* Otherwise inherit the flag that was passed to SMSS itself */
101 ProcessParameters->DebugFlags = SmpDebug;
102 }
103
104 /* Subsystems get the first 1MB of memory reserved for DOS/IVT purposes */
105 if (Flags & SMP_SUBSYSTEM_FLAG)
106 {
107 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB;
108 }
109
110 /* And always force NX for anything that SMSS launches */
111 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_NX;
112
113 /* Now create the process */
114 Status = RtlCreateUserProcess(FileName,
115 OBJ_CASE_INSENSITIVE,
116 ProcessParameters,
117 NULL,
118 NULL,
119 NULL,
120 FALSE,
121 NULL,
122 NULL,
123 ProcessInfo);
124 RtlDestroyProcessParameters(ProcessParameters);
125 if (!NT_SUCCESS(Status))
126 {
127 /* If we couldn't create it, fail back to the caller */
128 DPRINT1("SMSS: Failed load of %wZ - Status == %lx\n",
129 FileName, Status);
130 return Status;
131 }
132
133 /* Associate a session with this process */
134 Status = SmpSetProcessMuSessionId(ProcessInfo->ProcessHandle, MuSessionId);
135
136 /* If the application is deferred (suspended), there's nothing to do */
137 if (Flags & SMP_DEFERRED_FLAG) return Status;
138
139 /* Otherwise, get ready to start it, but make sure it's a native app */
140 if (ProcessInfo->ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_NATIVE)
141 {
142 /* Resume it */
143 NtResumeThread(ProcessInfo->ThreadHandle, NULL);
144 if (!(Flags & SMP_ASYNC_FLAG))
145 {
146 /* Block on it unless Async was requested */
147 NtWaitForSingleObject(ProcessInfo->ThreadHandle, FALSE, NULL);
148 }
149
150 /* It's up and running now, close our handles */
151 NtClose(ProcessInfo->ThreadHandle);
152 NtClose(ProcessInfo->ProcessHandle);
153 }
154 else
155 {
156 /* This image is invalid, so kill it, close our handles, and fail */
157 Status = STATUS_INVALID_IMAGE_FORMAT;
158 NtTerminateProcess(ProcessInfo->ProcessHandle, Status);
159 NtWaitForSingleObject(ProcessInfo->ThreadHandle, 0, 0);
160 NtClose(ProcessInfo->ThreadHandle);
161 NtClose(ProcessInfo->ProcessHandle);
162 DPRINT1("SMSS: Not an NT image - %wZ\n", FileName);
163 }
164
165 /* Return the outcome of the process create */
166 return Status;
167 }
168
169 NTSTATUS
170 NTAPI
171 SmpInvokeAutoChk(IN PUNICODE_STRING FileName,
172 IN PUNICODE_STRING Directory,
173 IN PUNICODE_STRING Arguments,
174 IN ULONG Flags)
175 {
176 ANSI_STRING DestinationString;
177 CHAR SourceString[256];
178 UNICODE_STRING Destination;
179 WCHAR Buffer[1024];
180 BOOLEAN BootState, BootOkay, ShutdownOkay;
181
182 /* Check if autochk should show dots (if the user booted with /SOS) */
183 if (SmpQueryRegistrySosOption()) SmpEnableDots = FALSE;
184
185 /* Make sure autochk was actually found */
186 if (Flags & SMP_INVALID_PATH)
187 {
188 /* It wasn't, so create an error message to print on the screen */
189 sprintf_nt(SourceString,
190 "%wZ program not found - skipping AUTOCHECK\n",
191 FileName);
192 RtlInitAnsiString(&DestinationString, SourceString);
193 if (RtlAnsiStringToUnicodeString(&Destination,
194 &DestinationString,
195 TRUE))
196 {
197 /* And show it */
198 NtDisplayString(&Destination);
199 RtlFreeUnicodeString(&Destination);
200 }
201 }
202 else
203 {
204 /* Autochk is there, so record the BSD state */
205 BootState = SmpSaveAndClearBootStatusData(&BootOkay, &ShutdownOkay);
206
207 /* Build the path to autochk and place its arguments */
208 RtlInitEmptyUnicodeString(&Destination, Buffer, sizeof(Buffer));
209 RtlAppendUnicodeStringToString(&Destination, FileName);
210 RtlAppendUnicodeToString(&Destination, L" ");
211 RtlAppendUnicodeStringToString(&Destination, Arguments);
212
213 /* Execute it */
214 SmpExecuteImage(FileName,
215 Directory,
216 &Destination,
217 0,
218 Flags & ~SMP_AUTOCHK_FLAG,
219 NULL);
220
221 /* Restore the BSD state */
222 if (BootState) SmpRestoreBootStatusData(BootOkay, ShutdownOkay);
223 }
224
225 /* We're all done! */
226 return STATUS_SUCCESS;
227 }
228
229 NTSTATUS
230 NTAPI
231 SmpExecuteCommand(IN PUNICODE_STRING CommandLine,
232 IN ULONG MuSessionId,
233 OUT PHANDLE ProcessId,
234 IN ULONG Flags)
235 {
236 NTSTATUS Status;
237 UNICODE_STRING Arguments, Directory, FileName;
238
239 /* There's no longer a debugging subsystem */
240 if (Flags & SMP_DEBUG_FLAG) return STATUS_SUCCESS;
241
242 /* Parse the command line to see what execution flags are requested */
243 Status = SmpParseCommandLine(CommandLine,
244 &Flags,
245 &FileName,
246 &Directory,
247 &Arguments);
248 if (!NT_SUCCESS(Status))
249 {
250 /* Fail if we couldn't do that */
251 DPRINT1("SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n",
252 CommandLine, Status);
253 return Status;
254 }
255
256 /* Check if autochk is requested */
257 if (Flags & SMP_AUTOCHK_FLAG)
258 {
259 /* Run it */
260 Status = SmpInvokeAutoChk(&FileName, &Directory, &Arguments, Flags);
261 }
262 else if (Flags & SMP_SUBSYSTEM_FLAG)
263 {
264 Status = SmpLoadSubSystem(&FileName,
265 &Directory,
266 CommandLine,
267 MuSessionId,
268 ProcessId,
269 Flags);
270 }
271 else if (Flags & SMP_INVALID_PATH)
272 {
273 /* An invalid image was specified, fail */
274 DPRINT1("SMSS: Image file (%wZ) not found\n", &FileName);
275 Status = STATUS_OBJECT_NAME_NOT_FOUND;
276 }
277 else
278 {
279 /* An actual image name was present -- execute it */
280 Status = SmpExecuteImage(&FileName,
281 &Directory,
282 CommandLine,
283 MuSessionId,
284 Flags,
285 NULL);
286 }
287
288 /* Free all the token parameters */
289 if (FileName.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, FileName.Buffer);
290 if (Directory.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Directory.Buffer);
291 if (Arguments.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Arguments.Buffer);
292
293 /* Return to the caller */
294 if (!NT_SUCCESS(Status))
295 {
296 DPRINT1("SMSS: Command '%wZ' failed - Status == %x\n",
297 CommandLine, Status);
298 }
299 return Status;
300 }
301
302 NTSTATUS
303 NTAPI
304 SmpExecuteInitialCommand(IN ULONG MuSessionId,
305 IN PUNICODE_STRING InitialCommand,
306 IN HANDLE InitialCommandProcess,
307 OUT PHANDLE ReturnPid)
308 {
309 NTSTATUS Status;
310 RTL_USER_PROCESS_INFORMATION ProcessInfo;
311 UNICODE_STRING Arguments, ImageFileDirectory, ImageFileName;
312 ULONG Flags = 0;
313
314 /* Check if we haven't yet connected to ourselves */
315 if (!SmApiPort)
316 {
317 /* Connect to ourselves, as a client */
318 Status = SmConnectToSm(0, 0, 0, &SmApiPort);
319 if (!NT_SUCCESS(Status))
320 {
321 DPRINT1("SMSS: Unable to connect to SM - Status == %lx\n", Status);
322 return Status;
323 }
324 }
325
326 /* Parse the initial command line */
327 Status = SmpParseCommandLine(InitialCommand,
328 (PULONG)&Flags,
329 &ImageFileName,
330 &ImageFileDirectory,
331 &Arguments);
332 if (Flags & SMP_INVALID_PATH)
333 {
334 /* Fail if it doesn't exist */
335 DPRINT1("SMSS: Initial command image (%wZ) not found\n", &ImageFileName);
336 if (ImageFileName.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, ImageFileName.Buffer);
337 return STATUS_OBJECT_NAME_NOT_FOUND;
338 }
339
340 /* And fail if any other reason is also true */
341 if (!NT_SUCCESS(Status))
342 {
343 DPRINT1("SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n",
344 InitialCommand, Status);
345 return Status;
346 }
347
348 /* Execute the initial command -- but defer its full execution */
349 Status = SmpExecuteImage(&ImageFileName,
350 &ImageFileDirectory,
351 InitialCommand,
352 MuSessionId,
353 SMP_DEFERRED_FLAG,
354 &ProcessInfo);
355
356 /* Free any buffers we had lying around */
357 if (ImageFileName.Buffer)
358 {
359 RtlFreeHeap(RtlGetProcessHeap(), 0, ImageFileName.Buffer);
360 }
361 if (ImageFileDirectory.Buffer)
362 {
363 RtlFreeHeap(RtlGetProcessHeap(), 0, ImageFileDirectory.Buffer);
364 }
365 if (Arguments.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Arguments.Buffer);
366
367 /* Bail out if we couldn't execute the initial command */
368 if (!NT_SUCCESS(Status)) return Status;
369
370 /* Now duplicate the handle to this process */
371 Status = NtDuplicateObject(NtCurrentProcess(),
372 ProcessInfo.ProcessHandle,
373 NtCurrentProcess(),
374 InitialCommandProcess,
375 PROCESS_ALL_ACCESS,
376 0,
377 0);
378 if (!NT_SUCCESS(Status))
379 {
380 /* Kill it utterly if duplication failed */
381 DPRINT1("SMSS: DupObject Failed. Status == %lx\n", Status);
382 NtTerminateProcess(ProcessInfo.ProcessHandle, Status);
383 NtResumeThread(ProcessInfo.ThreadHandle, NULL);
384 NtClose(ProcessInfo.ThreadHandle);
385 NtClose(ProcessInfo.ProcessHandle);
386 return Status;
387 }
388
389 /* Return PID to the caller, and set this as the initial command PID */
390 if (ReturnPid) *ReturnPid = ProcessInfo.ClientId.UniqueProcess;
391 if (!MuSessionId) SmpInitialCommandProcessId = ProcessInfo.ClientId.UniqueProcess;
392
393 /* Now call our server execution function to wrap up its initialization */
394 Status = SmExecPgm(SmApiPort, &ProcessInfo, FALSE);
395 if (!NT_SUCCESS(Status)) DPRINT1("SMSS: SmExecPgm Failed. Status == %lx\n", Status);
396 return Status;
397 }
398
399 NTSTATUS
400 NTAPI
401 ExpLoadInitialProcess(IN PINIT_BUFFER InitBuffer,
402 OUT PRTL_USER_PROCESS_PARAMETERS *ProcessParameters,
403 OUT PCHAR *ProcessEnvironment)
404 {
405 NTSTATUS Status;
406 SIZE_T Size;
407 PWSTR p;
408 UNICODE_STRING NullString = RTL_CONSTANT_STRING(L"");
409 UNICODE_STRING SmssName, DebugString;
410 PVOID EnvironmentPtr = NULL;
411 PRTL_USER_PROCESS_INFORMATION ProcessInformation;
412 PRTL_USER_PROCESS_PARAMETERS ProcessParams = NULL;
413
414 NullString.Length = sizeof(WCHAR);
415
416 /* Use the initial buffer, after the strings */
417 ProcessInformation = &InitBuffer->ProcessInfo;
418
419 /* Allocate memory for the process parameters */
420 Size = sizeof(*ProcessParams) + ((MAX_PATH * 6) * sizeof(WCHAR));
421 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
422 (PVOID*)&ProcessParams,
423 0,
424 &Size,
425 MEM_COMMIT,
426 PAGE_READWRITE);
427 if (!NT_SUCCESS(Status))
428 {
429 /* Failed, display error */
430 p = InitBuffer->DebugBuffer;
431 _snwprintf(p,
432 256 * sizeof(WCHAR),
433 L"INIT: Unable to allocate Process Parameters. 0x%lx",
434 Status);
435 RtlInitUnicodeString(&DebugString, p);
436 ZwDisplayString(&DebugString);
437
438 /* Bugcheck the system */
439 return Status;
440 }
441
442 /* Setup the basic header, and give the process the low 1MB to itself */
443 ProcessParams->Length = (ULONG)Size;
444 ProcessParams->MaximumLength = (ULONG)Size;
445 ProcessParams->Flags = RTL_USER_PROCESS_PARAMETERS_NORMALIZED |
446 RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB;
447
448 /* Allocate a page for the environment */
449 Size = PAGE_SIZE;
450 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
451 &EnvironmentPtr,
452 0,
453 &Size,
454 MEM_COMMIT,
455 PAGE_READWRITE);
456 if (!NT_SUCCESS(Status))
457 {
458 /* Failed, display error */
459 p = InitBuffer->DebugBuffer;
460 _snwprintf(p,
461 256 * sizeof(WCHAR),
462 L"INIT: Unable to allocate Process Environment. 0x%lx",
463 Status);
464 RtlInitUnicodeString(&DebugString, p);
465 ZwDisplayString(&DebugString);
466
467 /* Bugcheck the system */
468 return Status;
469 }
470
471 /* Write the pointer */
472 ProcessParams->Environment = EnvironmentPtr;
473
474 /* Make a buffer for the DOS path */
475 p = (PWSTR)(ProcessParams + 1);
476 ProcessParams->CurrentDirectory.DosPath.Buffer = p;
477 ProcessParams->CurrentDirectory.DosPath.MaximumLength = MAX_PATH *
478 sizeof(WCHAR);
479
480 /* Copy the DOS path */
481 RtlCopyUnicodeString(&ProcessParams->CurrentDirectory.DosPath,
482 &SmpSystemRoot);
483
484 /* Make a buffer for the DLL Path */
485 p = (PWSTR)((PCHAR)ProcessParams->CurrentDirectory.DosPath.Buffer +
486 ProcessParams->CurrentDirectory.DosPath.MaximumLength);
487 ProcessParams->DllPath.Buffer = p;
488 ProcessParams->DllPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
489
490 /* Copy the DLL path and append the system32 directory */
491 RtlCopyUnicodeString(&ProcessParams->DllPath,
492 &ProcessParams->CurrentDirectory.DosPath);
493 RtlAppendUnicodeToString(&ProcessParams->DllPath, L"\\System32");
494
495 /* Make a buffer for the image name */
496 p = (PWSTR)((PCHAR)ProcessParams->DllPath.Buffer +
497 ProcessParams->DllPath.MaximumLength);
498 ProcessParams->ImagePathName.Buffer = p;
499 ProcessParams->ImagePathName.MaximumLength = MAX_PATH * sizeof(WCHAR);
500
501 /* Make sure the buffer is a valid string which within the given length */
502 if ((NtInitialUserProcessBufferType != REG_SZ) ||
503 ((NtInitialUserProcessBufferLength != MAXULONG) &&
504 ((NtInitialUserProcessBufferLength < sizeof(WCHAR)) ||
505 (NtInitialUserProcessBufferLength >
506 sizeof(NtInitialUserProcessBuffer) - sizeof(WCHAR)))))
507 {
508 /* Invalid initial process string, bugcheck */
509 return STATUS_INVALID_PARAMETER;
510 }
511
512 /* Cut out anything after a space */
513 p = NtInitialUserProcessBuffer;
514 while ((*p) && (*p != L' ')) p++;
515
516 /* Set the image path length */
517 ProcessParams->ImagePathName.Length =
518 (USHORT)((PCHAR)p - (PCHAR)NtInitialUserProcessBuffer);
519
520 /* Copy the actual buffer */
521 RtlCopyMemory(ProcessParams->ImagePathName.Buffer,
522 NtInitialUserProcessBuffer,
523 ProcessParams->ImagePathName.Length);
524
525 /* Null-terminate it */
526 ProcessParams->ImagePathName.Buffer[ProcessParams->ImagePathName.Length /
527 sizeof(WCHAR)] = UNICODE_NULL;
528
529 /* Make a buffer for the command line */
530 p = (PWSTR)((PCHAR)ProcessParams->ImagePathName.Buffer +
531 ProcessParams->ImagePathName.MaximumLength);
532 ProcessParams->CommandLine.Buffer = p;
533 ProcessParams->CommandLine.MaximumLength = MAX_PATH * sizeof(WCHAR);
534
535 /* Add the image name to the command line */
536 RtlAppendUnicodeToString(&ProcessParams->CommandLine,
537 NtInitialUserProcessBuffer);
538
539 /* Create the environment string */
540 ProcessParams->Environment = SmpDefaultEnvironment;
541
542 /* Create SMSS process */
543 SmssName = ProcessParams->ImagePathName;
544 Status = RtlCreateUserProcess(&SmssName,
545 OBJ_CASE_INSENSITIVE,
546 RtlDeNormalizeProcessParams(ProcessParams),
547 NULL,
548 NULL,
549 NULL,
550 FALSE,
551 NULL,
552 NULL,
553 ProcessInformation);
554 if (!NT_SUCCESS(Status))
555 {
556 /* Failed, display error */
557 p = InitBuffer->DebugBuffer;
558 _snwprintf(p,
559 256 * sizeof(WCHAR),
560 L"INIT: Unable to create Session Manager. 0x%lx",
561 Status);
562 RtlInitUnicodeString(&DebugString, p);
563 ZwDisplayString(&DebugString);
564
565 /* Bugcheck the system */
566 return Status;
567 }
568
569 /* Resume the thread */
570 Status = ZwResumeThread(ProcessInformation->ThreadHandle, NULL);
571 if (!NT_SUCCESS(Status))
572 {
573 /* Failed, display error */
574 p = InitBuffer->DebugBuffer;
575 _snwprintf(p,
576 256 * sizeof(WCHAR),
577 L"INIT: Unable to resume Session Manager. 0x%lx",
578 Status);
579 RtlInitUnicodeString(&DebugString, p);
580 ZwDisplayString(&DebugString);
581
582 /* Bugcheck the system */
583 return Status;
584 }
585
586 /* Return success */
587 *ProcessParameters = ProcessParams;
588 *ProcessEnvironment = EnvironmentPtr;
589 return STATUS_SUCCESS;
590 }
591
592 NTSTATUS
593 NTAPI
594 LaunchOldSmss(VOID)
595 {
596 PINIT_BUFFER InitBuffer;
597 PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;
598 PRTL_USER_PROCESS_INFORMATION ProcessInfo;
599 NTSTATUS Status;
600 PCHAR Environment;
601
602 /* Initialize the system root */
603 RtlInitUnicodeString(&SmpSystemRoot, SharedUserData->NtSystemRoot);
604
605 /* Allocate the initialization buffer */
606 InitBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(INIT_BUFFER));
607 if (!InitBuffer)
608 {
609 /* Bugcheck */
610 return STATUS_NO_MEMORY;
611 }
612
613 /* Launch initial process */
614 ProcessInfo = &InitBuffer->ProcessInfo;
615 Status = ExpLoadInitialProcess(InitBuffer, &ProcessParameters, &Environment);
616 if (!NT_SUCCESS(Status))
617 {
618 /* Failed, display error */
619 DPRINT1("INIT: Session Manager failed to load.\n");
620 return Status;
621 }
622
623 /* Return the handle and status */
624 return Status;
625 }
626
627 NTSTATUS
628 NTAPI
629 SmpTerminate(IN PULONG_PTR Parameters,
630 IN ULONG ParameterMask,
631 IN ULONG ParameterCount)
632 {
633 NTSTATUS Status;
634 BOOLEAN Old;
635 ULONG Response;
636
637 /* Give the shutdown privilege to the thread */
638 if (RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, TRUE, &Old) ==
639 STATUS_NO_TOKEN)
640 {
641 /* Thread doesn't have a token, give it to the entire process */
642 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old);
643 }
644
645 /* Take down the process/machine with a hard error */
646 Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
647 ParameterCount,
648 ParameterMask,
649 Parameters,
650 OptionShutdownSystem,
651 &Response);
652
653 /* Terminate the process if the hard error didn't already */
654 return NtTerminateProcess(NtCurrentProcess(), Status);
655 }
656
657 LONG
658 SmpUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo)
659 {
660 ULONG_PTR Parameters[4];
661 UNICODE_STRING DestinationString;
662
663 /* Print and breakpoint into the debugger */
664 DbgPrint("SMSS: Unhandled exception - Status == %x IP == %x\n",
665 ExceptionInfo->ExceptionRecord->ExceptionCode,
666 ExceptionInfo->ExceptionRecord->ExceptionAddress);
667 DbgPrint(" Memory Address: %x Read/Write: %x\n",
668 ExceptionInfo->ExceptionRecord->ExceptionInformation[0],
669 ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
670 DbgBreakPoint();
671
672 /* Build the hard error and terminate */
673 RtlInitUnicodeString(&DestinationString, L"Unhandled Exception in Session Manager");
674 Parameters[0] = (ULONG_PTR)&DestinationString;
675 Parameters[1] = ExceptionInfo->ExceptionRecord->ExceptionCode;
676 Parameters[2] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress;
677 Parameters[3] = (ULONG_PTR)ExceptionInfo->ContextRecord;
678 SmpTerminate(Parameters, 1, RTL_NUMBER_OF(Parameters));
679
680 /* We hould never get here */
681 ASSERT(FALSE);
682 return EXCEPTION_EXECUTE_HANDLER;
683 }
684
685 NTSTATUS
686 _main(IN INT argc,
687 IN PCHAR argv[],
688 IN PCHAR envp[],
689 IN ULONG DebugFlag)
690 {
691 NTSTATUS Status;
692 KPRIORITY SetBasePriority;
693 ULONG_PTR Parameters[4];
694 HANDLE Handles[2];
695 PVOID State;
696 ULONG Flags;
697 PROCESS_BASIC_INFORMATION ProcessInfo;
698 UNICODE_STRING DbgString, InitialCommand;
699
700 /* Make us critical */
701 RtlSetProcessIsCritical(TRUE, NULL, FALSE);
702 RtlSetThreadIsCritical(TRUE, NULL, FALSE);
703
704 /* Raise our priority */
705 SetBasePriority = 11;
706 Status = NtSetInformationProcess(NtCurrentProcess(),
707 ProcessBasePriority,
708 (PVOID)&SetBasePriority,
709 sizeof(SetBasePriority));
710 ASSERT(NT_SUCCESS(Status));
711
712 /* Save the debug flag if it was passed */
713 if (DebugFlag) SmpDebug = DebugFlag;
714
715 /* Build the hard error parameters */
716 Parameters[0] = (ULONG_PTR)&DbgString;
717 Parameters[1] = Parameters[2] = Parameters[3] = 0;
718
719 /* Enter SEH so we can terminate correctly if anything goes wrong */
720 _SEH2_TRY
721 {
722 LARGE_INTEGER Infinite = {{0x80000000, 0x7FFFFFFF}};
723
724 /* Initialize SMSS */
725 Status = SmpInit(&InitialCommand, Handles);
726 if (!NT_SUCCESS(Status))
727 {
728 DPRINT1("SMSS: SmpInit return failure - Status == %x\n", Status);
729 RtlInitUnicodeString(&DbgString, L"Session Manager Initialization");
730 Parameters[1] = Status;
731 DPRINT1("SMSS-2 Loaded... Launching original SMSS\n");
732 //_SEH2_LEAVE; Hack so that setup can work. will go away later
733 Status = LaunchOldSmss();
734 if (!NT_SUCCESS(Status)) return Status;
735 return NtDelayExecution(FALSE, &Infinite);
736 }
737
738 /* Get the global flags */
739 Status = NtQuerySystemInformation(SystemFlagsInformation,
740 &Flags,
741 sizeof(Flags),
742 NULL);
743 ASSERT(NT_SUCCESS(Status));
744
745 /* Before executing the initial command check if the debug flag is on */
746 if (Flags & (FLG_DEBUG_INITIAL_COMMAND | FLG_DEBUG_INITIAL_COMMAND_EX))
747 {
748 /* SMSS should launch ntsd with a few parameters at this point */
749 DPRINT1("Global Flags Set to SMSS Debugging: Not yet supported\n");
750 }
751
752 /* Execute the initial command (Winlogon.exe) */
753 Status = SmpExecuteInitialCommand(0, &InitialCommand, &Handles[1], NULL);
754 if (!NT_SUCCESS(Status))
755 {
756 /* Fail and raise a hard error */
757 DPRINT1("SMSS: Execute Initial Command failed\n");
758 RtlInitUnicodeString(&DbgString,
759 L"Session Manager ExecuteInitialCommand");
760 Parameters[1] = Status;
761 //_SEH2_LEAVE;
762 DPRINT1("SMSS-2 Loaded... Launching original SMSS\n");
763 Status = LaunchOldSmss();
764 if (!NT_SUCCESS(Status)) return Status;
765 return NtDelayExecution(FALSE, &Infinite);
766 }
767
768 /* Check if we're already attached to a session */
769 Status = SmpAcquirePrivilege(SE_LOAD_DRIVER_PRIVILEGE, &State);
770 if (AttachedSessionId != -1)
771 {
772 /* Detach from it, we should be in no session right now */
773 Status = NtSetSystemInformation(SystemSessionDetach,
774 &AttachedSessionId,
775 sizeof(AttachedSessionId));
776 ASSERT(NT_SUCCESS(Status));
777 AttachedSessionId = -1;
778 }
779 SmpReleasePrivilege(State);
780
781 /* Wait on either CSRSS or Winlogon to die */
782 Status = NtWaitForMultipleObjects(RTL_NUMBER_OF(Handles),
783 Handles,
784 WaitAny,
785 FALSE,
786 NULL);
787 if (Status == STATUS_WAIT_0)
788 {
789 /* CSRSS is dead, get exit code and prepare for the hard error */
790 RtlInitUnicodeString(&DbgString, L"Windows SubSystem");
791 Status = NtQueryInformationProcess(Handles[0],
792 ProcessBasicInformation,
793 &ProcessInfo,
794 sizeof(ProcessInfo),
795 NULL);
796 DPRINT1("SMSS: Windows subsystem terminated when it wasn't supposed to.\n");
797 }
798 else
799 {
800 /* The initial command is dead or we have another failure */
801 RtlInitUnicodeString(&DbgString, L"Windows Logon Process");
802 if (Status == STATUS_WAIT_1)
803 {
804 /* Winlogon.exe got terminated, get its exit code */
805 Status = NtQueryInformationProcess(Handles[1],
806 ProcessBasicInformation,
807 &ProcessInfo,
808 sizeof(ProcessInfo),
809 NULL);
810 }
811 else
812 {
813 /* Something else satisfied our wait, so set the wait status */
814 ProcessInfo.ExitStatus = Status;
815 Status = STATUS_SUCCESS;
816 }
817 DPRINT1("SMSS: Initial command '%wZ' terminated when it wasn't supposed to.\n",
818 &InitialCommand);
819 }
820
821 /* Check if NtQueryInformationProcess was successful */
822 if (NT_SUCCESS(Status))
823 {
824 /* Then we must have a valid exit status in the structure, use it */
825 Parameters[1] = ProcessInfo.ExitStatus;
826 }
827 else
828 {
829 /* We really don't know what happened, so set a generic error */
830 Parameters[1] = STATUS_UNSUCCESSFUL;
831 }
832 }
833 _SEH2_EXCEPT(SmpUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
834 {
835 /* The filter should never return here */
836 ASSERT(FALSE);
837 }
838 _SEH2_END;
839
840 /* Something in the init loop failed, terminate SMSS */
841 return SmpTerminate(Parameters, 1, RTL_NUMBER_OF(Parameters));
842 }
843
844 /* EOF */