xref: /reactos/base/system/smss/smsubsys.c (revision 2dddbd5c)
1 /*
2  * PROJECT:         ReactOS Windows-Compatible Session Manager
3  * LICENSE:         BSD 2-Clause License
4  * FILE:            base/system/smss/smsubsys.c
5  * PURPOSE:         Main SMSS Code
6  * PROGRAMMERS:     Alex Ionescu
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include "smss.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS ********************************************************************/
17 
18 RTL_CRITICAL_SECTION SmpKnownSubSysLock;
19 LIST_ENTRY SmpKnownSubSysHead;
20 HANDLE SmpWindowsSubSysProcess;
21 HANDLE SmpWindowsSubSysProcessId;
22 BOOLEAN RegPosixSingleInstance;
23 WCHAR InitialCommandBuffer[256];
24 
25 /* FUNCTIONS ******************************************************************/
26 
27 NTSTATUS
28 NTAPI
SmpCallCsrCreateProcess(IN PSB_API_MSG SbApiMsg,IN USHORT MessageLength,IN HANDLE PortHandle)29 SmpCallCsrCreateProcess(IN PSB_API_MSG SbApiMsg,
30                         IN USHORT MessageLength,
31                         IN HANDLE PortHandle)
32 {
33     NTSTATUS Status;
34 
35     /* Initialize the header and send the message to CSRSS */
36     SbApiMsg->h.u2.ZeroInit = 0;
37     SbApiMsg->h.u1.s1.DataLength = MessageLength + 8;
38     SbApiMsg->h.u1.s1.TotalLength = sizeof(SB_API_MSG);
39     SbApiMsg->ApiNumber = SbpCreateProcess;
40     Status = NtRequestWaitReplyPort(PortHandle, &SbApiMsg->h, &SbApiMsg->h);
41     if (NT_SUCCESS(Status)) Status = SbApiMsg->ReturnValue;
42     return Status;
43 }
44 
45 VOID
46 NTAPI
SmpDereferenceSubsystem(IN PSMP_SUBSYSTEM SubSystem)47 SmpDereferenceSubsystem(IN PSMP_SUBSYSTEM SubSystem)
48 {
49     /* Acquire the database lock while we (potentially) destroy this subsystem */
50     RtlEnterCriticalSection(&SmpKnownSubSysLock);
51 
52     /* Drop the reference and see if it's terminating */
53     if (!(--SubSystem->ReferenceCount) && (SubSystem->Terminating))
54     {
55         /* Close all handles and free it */
56         if (SubSystem->Event) NtClose(SubSystem->Event);
57         if (SubSystem->ProcessHandle) NtClose(SubSystem->ProcessHandle);
58         if (SubSystem->SbApiPort) NtClose(SubSystem->SbApiPort);
59         RtlFreeHeap(SmpHeap, 0, SubSystem);
60     }
61 
62     /* Release the database lock */
63     RtlLeaveCriticalSection(&SmpKnownSubSysLock);
64 }
65 
66 PSMP_SUBSYSTEM
67 NTAPI
SmpLocateKnownSubSysByCid(IN PCLIENT_ID ClientId)68 SmpLocateKnownSubSysByCid(IN PCLIENT_ID ClientId)
69 {
70     PSMP_SUBSYSTEM Subsystem = NULL;
71     PLIST_ENTRY NextEntry;
72 
73     /* Lock the subsystem database */
74     RtlEnterCriticalSection(&SmpKnownSubSysLock);
75 
76     /* Loop each subsystem in the database */
77     NextEntry = SmpKnownSubSysHead.Flink;
78     while (NextEntry != &SmpKnownSubSysHead)
79     {
80         /* Check if this one matches the client ID and is still valid */
81         Subsystem = CONTAINING_RECORD(NextEntry, SMP_SUBSYSTEM, Entry);
82         if ((*(PULONGLONG)&Subsystem->ClientId == *(PULONGLONG)ClientId) &&
83             !(Subsystem->Terminating))
84         {
85             /* Add a reference and return it */
86             Subsystem->ReferenceCount++;
87             break;
88         }
89 
90         /* Reset the current pointer and keep searching */
91         Subsystem = NULL;
92         NextEntry = NextEntry->Flink;
93     }
94 
95     /* Release the lock and return the subsystem we found */
96     RtlLeaveCriticalSection(&SmpKnownSubSysLock);
97     return Subsystem;
98 }
99 
100 PSMP_SUBSYSTEM
101 NTAPI
SmpLocateKnownSubSysByType(IN ULONG MuSessionId,IN ULONG ImageType)102 SmpLocateKnownSubSysByType(IN ULONG MuSessionId,
103                            IN ULONG ImageType)
104 {
105     PSMP_SUBSYSTEM Subsystem = NULL;
106     PLIST_ENTRY NextEntry;
107 
108     /* Lock the subsystem database */
109     RtlEnterCriticalSection(&SmpKnownSubSysLock);
110 
111     /* Loop each subsystem in the database */
112     NextEntry = SmpKnownSubSysHead.Flink;
113     while (NextEntry != &SmpKnownSubSysHead)
114     {
115         /* Check if this one matches the image and uID, and is still valid */
116         Subsystem = CONTAINING_RECORD(NextEntry, SMP_SUBSYSTEM, Entry);
117         if ((Subsystem->ImageType == ImageType) &&
118             !(Subsystem->Terminating) &&
119             (Subsystem->MuSessionId == MuSessionId))
120         {
121             /* Return it referenced for the caller */
122             Subsystem->ReferenceCount++;
123             break;
124         }
125 
126         /* Reset the current pointer and keep searching */
127         Subsystem = NULL;
128         NextEntry = NextEntry->Flink;
129     }
130 
131     /* Release the lock and return the subsystem we found */
132     RtlLeaveCriticalSection(&SmpKnownSubSysLock);
133     return Subsystem;
134 }
135 
136 NTSTATUS
137 NTAPI
SmpLoadSubSystem(IN PUNICODE_STRING FileName,IN PUNICODE_STRING Directory,IN PUNICODE_STRING CommandLine,IN ULONG MuSessionId,OUT PHANDLE ProcessId,IN ULONG Flags)138 SmpLoadSubSystem(IN PUNICODE_STRING FileName,
139                  IN PUNICODE_STRING Directory,
140                  IN PUNICODE_STRING CommandLine,
141                  IN ULONG MuSessionId,
142                  OUT PHANDLE ProcessId,
143                  IN ULONG Flags)
144 {
145     PSMP_SUBSYSTEM Subsystem, NewSubsystem, KnownSubsystem = NULL;
146     HANDLE SubSysProcessId;
147     NTSTATUS Status = STATUS_SUCCESS;
148     SB_API_MSG SbApiMsg;
149     RTL_USER_PROCESS_INFORMATION ProcessInformation;
150     LARGE_INTEGER Timeout;
151     PVOID State;
152     PSB_CREATE_PROCESS_MSG CreateProcess = &SbApiMsg.u.CreateProcess;
153     PSB_CREATE_SESSION_MSG CreateSession = &SbApiMsg.u.CreateSession;
154 
155     /* Make sure this is a found subsystem */
156     if (Flags & SMP_INVALID_PATH)
157     {
158         DPRINT1("SMSS: Unable to find subsystem - %wZ\n", FileName);
159         return STATUS_OBJECT_NAME_NOT_FOUND;
160     }
161 
162     /* Don't use a session if the flag is set */
163     if (Flags & 0x80) MuSessionId = 0;
164 
165     /* Lock the subsystems while we do a look up */
166     RtlEnterCriticalSection(&SmpKnownSubSysLock);
167     while (TRUE)
168     {
169         /* Check if we found a subsystem not yet fully initialized */
170         Subsystem = SmpLocateKnownSubSysByType(MuSessionId, -1);
171         if (!Subsystem) break;
172         RtlLeaveCriticalSection(&SmpKnownSubSysLock);
173 
174         /* Wait on it to initialize */
175         NtWaitForSingleObject(Subsystem->Event, FALSE, NULL);
176 
177         /* Dereference it and try the next one */
178         RtlEnterCriticalSection(&SmpKnownSubSysLock);
179         SmpDereferenceSubsystem(Subsystem);
180     }
181 
182     /* Check if this is a POSIX subsystem */
183     if (Flags & SMP_POSIX_FLAG)
184     {
185         /* Do we already have it? */
186         Subsystem = SmpLocateKnownSubSysByType(MuSessionId, IMAGE_SUBSYSTEM_POSIX_CUI);
187     }
188     else if (Flags & SMP_OS2_FLAG)
189     {
190         /* This is an OS/2 subsystem, do we we already have it? */
191         Subsystem = SmpLocateKnownSubSysByType(MuSessionId, IMAGE_SUBSYSTEM_OS2_CUI);
192     }
193 
194     /* Check if we already have one of the optional subsystems for the session */
195     if (Subsystem)
196     {
197         /* Dereference and return, no work to do */
198         SmpDereferenceSubsystem(Subsystem);
199         RtlLeaveCriticalSection(&SmpKnownSubSysLock);
200         return STATUS_SUCCESS;
201     }
202 
203     /* Allocate a new subsystem! */
204     NewSubsystem = RtlAllocateHeap(SmpHeap, SmBaseTag, sizeof(SMP_SUBSYSTEM));
205     if (!NewSubsystem)
206     {
207         RtlLeaveCriticalSection(&SmpKnownSubSysLock);
208         return STATUS_NO_MEMORY;
209     }
210 
211     /* Initialize its header and reference count */
212     NewSubsystem->ReferenceCount = 1;
213     NewSubsystem->MuSessionId = MuSessionId;
214     NewSubsystem->ImageType = -1;
215 
216     /* Clear out all the other data for now */
217     NewSubsystem->Terminating = FALSE;
218     NewSubsystem->ProcessHandle = NULL;
219     NewSubsystem->Event = NULL;
220     NewSubsystem->PortHandle = NULL;
221     NewSubsystem->SbApiPort = NULL;
222 
223     /* Create the event we'll be waiting on for initialization */
224     Status = NtCreateEvent(&NewSubsystem->Event,
225                            EVENT_ALL_ACCESS,
226                            NULL,
227                            NotificationEvent,
228                            FALSE);
229     if (!NT_SUCCESS(Status))
230     {
231         /* This failed, bail out */
232         RtlFreeHeap(SmpHeap, 0, NewSubsystem);
233         RtlLeaveCriticalSection(&SmpKnownSubSysLock);
234         return STATUS_NO_MEMORY;
235     }
236 
237     /* Insert the subsystem and release the lock. It can now be found */
238     InsertTailList(&SmpKnownSubSysHead, &NewSubsystem->Entry);
239     RtlLeaveCriticalSection(&SmpKnownSubSysLock);
240 
241     /* The OS/2 and POSIX subsystems are actually Windows applications! */
242     if (Flags & (SMP_POSIX_FLAG | SMP_OS2_FLAG))
243     {
244         /* Locate the Windows subsystem for this session */
245         KnownSubsystem = SmpLocateKnownSubSysByType(MuSessionId,
246                                                     IMAGE_SUBSYSTEM_WINDOWS_GUI);
247         if (!KnownSubsystem)
248         {
249             DPRINT1("SMSS: SmpLoadSubSystem - SmpLocateKnownSubSysByType Failed\n");
250             goto Quickie2;
251         }
252 
253         /* Fill out all the process details and call CSRSS to launch it */
254         CreateProcess->In.ImageName = FileName;
255         CreateProcess->In.CurrentDirectory = Directory;
256         CreateProcess->In.CommandLine = CommandLine;
257         CreateProcess->In.DllPath = SmpDefaultLibPath.Length ?
258                                     &SmpDefaultLibPath : NULL;
259         CreateProcess->In.Flags = Flags | SMP_DEFERRED_FLAG;
260         CreateProcess->In.DebugFlags = SmpDebug;
261         Status = SmpCallCsrCreateProcess(&SbApiMsg,
262                                          sizeof(*CreateProcess),
263                                          KnownSubsystem->SbApiPort);
264         if (!NT_SUCCESS(Status))
265         {
266             /* Handle failures */
267             DPRINT1("SMSS: SmpLoadSubSystem - SmpCallCsrCreateProcess Failed with  Status %lx\n",
268                     Status);
269             goto Quickie2;
270         }
271 
272         /* Save the process information we'll need for the create session */
273         ProcessInformation.ProcessHandle = CreateProcess->Out.ProcessHandle;
274         ProcessInformation.ThreadHandle = CreateProcess->Out.ThreadHandle;
275         ProcessInformation.ClientId = CreateProcess->Out.ClientId;
276         ProcessInformation.ImageInformation.SubSystemType = CreateProcess->Out.SubsystemType;
277     }
278     else
279     {
280         /* This must be CSRSS itself, so just launch it and that's it */
281         Status = SmpExecuteImage(FileName,
282                                  Directory,
283                                  CommandLine,
284                                  MuSessionId,
285                                  Flags | SMP_DEFERRED_FLAG,
286                                  &ProcessInformation);
287         if (!NT_SUCCESS(Status))
288         {
289             /* Handle failures */
290             DPRINT1("SMSS: SmpLoadSubSystem - SmpExecuteImage Failed with  Status %lx\n",
291                     Status);
292             goto Quickie2;
293         }
294     }
295 
296     /* Fill out the handle and client ID in the subsystem structure now */
297     NewSubsystem->ProcessHandle = ProcessInformation.ProcessHandle;
298     NewSubsystem->ClientId = ProcessInformation.ClientId;
299 
300     /* Check if we launched a native image or a subsystem-backed image */
301     if (ProcessInformation.ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_NATIVE)
302     {
303         /* This must be CSRSS itself, since it's a native subsystem image */
304         SubSysProcessId = ProcessInformation.ClientId.UniqueProcess;
305         if ((ProcessId) && !(*ProcessId)) *ProcessId = SubSysProcessId;
306 
307         /* Was this the initial CSRSS on Session 0? */
308         if (!MuSessionId)
309         {
310             /* Then save it in the global variables */
311             SmpWindowsSubSysProcessId = SubSysProcessId;
312             SmpWindowsSubSysProcess = ProcessInformation.ProcessHandle;
313         }
314         ASSERT(NT_SUCCESS(Status));
315     }
316     else
317     {
318         /* This is the POSIX or OS/2 subsystem process, copy its information */
319         CreateSession->ProcessInfo = ProcessInformation;
320 
321         CreateSession->DbgSessionId = 0;
322         *(PULONGLONG)&CreateSession->DbgUiClientId = 0;
323 
324         /* This should find CSRSS because they are POSIX or OS/2 subsystems */
325         Subsystem = SmpLocateKnownSubSysByType(MuSessionId,
326                                                ProcessInformation.ImageInformation.SubSystemType);
327         if (!Subsystem)
328         {
329             /* Odd failure -- but handle it anyway */
330             Status = STATUS_NO_SUCH_PACKAGE;
331             DPRINT1("SMSS: SmpLoadSubSystem - SmpLocateKnownSubSysByType Failed with  Status %lx for sessionid %lu\n",
332                     Status,
333                     MuSessionId);
334             goto Quickie;
335         }
336 
337         /* Duplicate the parent process handle for the subsystem to have */
338         Status = NtDuplicateObject(NtCurrentProcess(),
339                                    ProcessInformation.ProcessHandle,
340                                    Subsystem->ProcessHandle,
341                                    &CreateSession->ProcessInfo.ProcessHandle,
342                                    PROCESS_ALL_ACCESS,
343                                    0,
344                                    0);
345         if (!NT_SUCCESS(Status))
346         {
347             /* Fail since this is critical */
348             DPRINT1("SMSS: SmpLoadSubSystem - NtDuplicateObject Failed with  Status %lx for sessionid %lu\n",
349                     Status,
350                     MuSessionId);
351             goto Quickie;
352         }
353 
354         /* Duplicate the initial thread handle for the subsystem to have */
355         Status = NtDuplicateObject(NtCurrentProcess(),
356                                    ProcessInformation.ThreadHandle,
357                                    Subsystem->ProcessHandle,
358                                    &CreateSession->ProcessInfo.ThreadHandle,
359                                    THREAD_ALL_ACCESS,
360                                    0,
361                                    0);
362         if (!NT_SUCCESS(Status))
363         {
364             /* Fail since this is critical */
365             DPRINT1("SMSS: SmpLoadSubSystem - NtDuplicateObject Failed with  Status %lx for sessionid %lu\n",
366                     Status,
367                     MuSessionId);
368             goto Quickie;
369         }
370 
371         /* Allocate an internal Session ID for this subsystem */
372         CreateSession->SessionId = SmpAllocateSessionId(Subsystem, NULL);
373 
374         /* Send the create session message to the subsystem */
375         SbApiMsg.ReturnValue = STATUS_SUCCESS;
376         SbApiMsg.h.u2.ZeroInit = 0;
377         SbApiMsg.h.u1.s1.DataLength = sizeof(SB_CREATE_SESSION_MSG) + 8;
378         SbApiMsg.h.u1.s1.TotalLength = sizeof(SB_API_MSG);
379         SbApiMsg.ApiNumber = SbpCreateSession;
380         Status = NtRequestWaitReplyPort(Subsystem->SbApiPort,
381                                         &SbApiMsg.h,
382                                         &SbApiMsg.h);
383         if (NT_SUCCESS(Status)) Status = SbApiMsg.ReturnValue;
384         if (!NT_SUCCESS(Status))
385         {
386             /* Delete the session and handle failure if the LPC call failed */
387             SmpDeleteSession(CreateSession->SessionId);
388             DPRINT1("SMSS: SmpLoadSubSystem - NtRequestWaitReplyPort Failed with  Status %lx for sessionid %lu\n",
389                     Status,
390                     MuSessionId);
391             goto Quickie;
392         }
393     }
394 
395     /* Okay, everything looks good to go, initialize this subsystem now! */
396     Status = NtResumeThread(ProcessInformation.ThreadHandle, NULL);
397     if (!NT_SUCCESS(Status))
398     {
399         /* That didn't work -- back out of everything */
400         DPRINT1("SMSS: SmpLoadSubSystem - NtResumeThread failed Status %lx\n", Status);
401         goto Quickie;
402     }
403 
404     /* Check if this was the subsystem for a different session */
405     if (MuSessionId)
406     {
407         /* Wait up to 60 seconds for it to initialize */
408         Timeout.QuadPart = -600000000;
409         Status = NtWaitForSingleObject(NewSubsystem->Event, FALSE, &Timeout);
410 
411         /* Timeout is done -- does this session still exist? */
412         if (!SmpCheckDuplicateMuSessionId(MuSessionId))
413         {
414             /* Nope, it died. Cleanup should've ocurred in a different path. */
415             DPRINT1("SMSS: SmpLoadSubSystem - session deleted\n");
416             return STATUS_DELETE_PENDING;
417         }
418 
419         /* Check if we timed our or there was another error with the wait */
420         if (Status != STATUS_WAIT_0)
421         {
422             /* Something is wrong with the subsystem, so back out of everything */
423             DPRINT1("SMSS: SmpLoadSubSystem - Timeout waiting for subsystem connect with Status %lx for sessionid %lu\n",
424                     Status,
425                     MuSessionId);
426             goto Quickie;
427         }
428     }
429     else
430     {
431         /* This a session 0 subsystem, just wait for it to initialize */
432         NtWaitForSingleObject(NewSubsystem->Event, FALSE, NULL);
433     }
434 
435     /* Subsystem is created, resumed, and initialized. Close handles and exit */
436     NtClose(ProcessInformation.ThreadHandle);
437     Status = STATUS_SUCCESS;
438     goto Quickie2;
439 
440 Quickie:
441     /* This is the failure path. First check if we need to detach from session */
442     if ((AttachedSessionId == -1) || (Flags & (SMP_POSIX_FLAG | SMP_OS2_FLAG)))
443     {
444         /* We were not attached, or did not launch subsystems that required it */
445         DPRINT1("SMSS: Did not detach from Session Space: SessionId=%x Flags=%x Status=%x\n",
446                 AttachedSessionId,
447                 Flags | SMP_DEFERRED_FLAG,
448                 Status);
449     }
450     else
451     {
452         /* Get the privilege we need for detachment */
453         Status = SmpAcquirePrivilege(SE_LOAD_DRIVER_PRIVILEGE, &State);
454         if (!NT_SUCCESS(Status))
455         {
456             /* We can't detach without it */
457             DPRINT1("SMSS: Did not detach from Session Space: SessionId=%x Flags=%x Status=%x\n",
458                     AttachedSessionId,
459                     Flags | SMP_DEFERRED_FLAG,
460                     Status);
461         }
462         else
463         {
464             /* Now detach from the session */
465             Status = NtSetSystemInformation(SystemSessionDetach,
466                                             &AttachedSessionId,
467                                             sizeof(AttachedSessionId));
468             if (!NT_SUCCESS(Status))
469             {
470                 /* Failed to detach. Note the DPRINT1 has a typo in Windows */
471                 DPRINT1("SMSS: SmpStartCsr, Couldn't Detach from Session Space. Status=%x\n", Status);
472                 ASSERT(NT_SUCCESS(Status));
473             }
474             else
475             {
476                 /* Detachment worked, reset our attached session ID */
477                 AttachedSessionId = -1;
478             }
479 
480             /* And release the privilege we acquired */
481             SmpReleasePrivilege(State);
482         }
483     }
484 
485     /* Since this is the failure path, terminate the subsystem process */
486     NtTerminateProcess(ProcessInformation.ProcessHandle, Status);
487     NtClose(ProcessInformation.ThreadHandle);
488 
489 Quickie2:
490     /* This is the cleanup path -- first dereference our subsystems */
491     RtlEnterCriticalSection(&SmpKnownSubSysLock);
492     if (Subsystem) SmpDereferenceSubsystem(Subsystem);
493     if (KnownSubsystem) SmpDereferenceSubsystem(KnownSubsystem);
494 
495     /* In the failure case, destroy the new subsystem we just created */
496     if (!NT_SUCCESS(Status))
497     {
498         RemoveEntryList(&NewSubsystem->Entry);
499         NtSetEvent(NewSubsystem->Event, NULL);
500         SmpDereferenceSubsystem(NewSubsystem);
501     }
502 
503     /* Finally, we're all done! */
504     RtlLeaveCriticalSection(&SmpKnownSubSysLock);
505     return Status;
506 }
507 
508 NTSTATUS
509 NTAPI
SmpLoadSubSystemsForMuSession(IN PULONG MuSessionId,OUT PHANDLE ProcessId,IN PUNICODE_STRING InitialCommand)510 SmpLoadSubSystemsForMuSession(IN PULONG MuSessionId,
511                               OUT PHANDLE ProcessId,
512                               IN PUNICODE_STRING InitialCommand)
513 {
514     NTSTATUS Status = STATUS_SUCCESS, Status2;
515     PSMP_REGISTRY_VALUE RegEntry;
516     UNICODE_STRING DestinationString, NtPath;
517     PLIST_ENTRY NextEntry;
518     LARGE_INTEGER Timeout;
519     PVOID State;
520 
521     /* Write a few last registry keys with the boot partition information */
522     SmpTranslateSystemPartitionInformation();
523 
524     /* Process "SetupExecute" values */
525     NextEntry = SmpSetupExecuteList.Flink;
526     while (NextEntry != &SmpSetupExecuteList)
527     {
528         /* Execute each one and move on */
529         RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
530         SmpExecuteCommand(&RegEntry->Name, 0, NULL, 0);
531         NextEntry = NextEntry->Flink;
532     }
533 
534     /* Now process the subsystems */
535     NextEntry = SmpSubSystemList.Flink;
536     while (NextEntry != &SmpSubSystemList)
537     {
538         /* Get the entry and check if this is the special Win32k entry */
539         RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
540         if (_wcsicmp(RegEntry->Name.Buffer, L"Kmode") == 0)
541         {
542             /* Translate it */
543             if (!RtlDosPathNameToNtPathName_U(RegEntry->Value.Buffer,
544                                               &NtPath,
545                                               NULL,
546                                               NULL))
547             {
548                 Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
549                 DPRINT1("Failed: %lx\n", Status);
550             }
551             else
552             {
553                 /* Get the driver privilege */
554                 Status = SmpAcquirePrivilege(SE_LOAD_DRIVER_PRIVILEGE, &State);
555                 if (NT_SUCCESS(Status))
556                 {
557                     /* Create the new session */
558                     ASSERT(AttachedSessionId == -1);
559                     Status = NtSetSystemInformation(SystemSessionCreate,
560                                                     MuSessionId,
561                                                     sizeof(*MuSessionId));
562                     if (!NT_SUCCESS(Status))
563                     {
564                         DPRINT1("SMSS: Session space creation failed\n");
565                         SmpReleasePrivilege(State);
566                         RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath.Buffer);
567                         return Status;
568                     }
569                     AttachedSessionId = *MuSessionId;
570 
571                     /*
572                      * Start Win32k.sys on this session. Use a hardcoded value
573                      * instead of the Kmode one...
574                      */
575                     RtlInitUnicodeString(&DestinationString,
576                                          L"\\SystemRoot\\System32\\win32k.sys");
577                     Status = NtSetSystemInformation(SystemExtendServiceTableInformation,
578                                                     &DestinationString,
579                                                     sizeof(DestinationString));
580                     RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath.Buffer);
581                     SmpReleasePrivilege(State);
582                     if (!NT_SUCCESS(Status))
583                     {
584                         DPRINT1("SMSS: Load of WIN32K failed.\n");
585                         return Status;
586                     }
587                 }
588             }
589         }
590 
591         /* Next entry */
592         NextEntry = NextEntry->Flink;
593     }
594 
595     /* Now parse the required subsystem list */
596     NextEntry = SmpSubSystemsToLoad.Flink;
597     while (NextEntry != &SmpSubSystemsToLoad)
598     {
599         /* Get each entry and check if it's the internal debug or not */
600         RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
601         if (_wcsicmp(RegEntry->Name.Buffer, L"Debug") == 0)
602         {
603             /* Load the internal debug system */
604             Status = SmpExecuteCommand(&RegEntry->Value,
605                                        *MuSessionId,
606                                        ProcessId,
607                                        SMP_DEBUG_FLAG | SMP_SUBSYSTEM_FLAG);
608         }
609         else
610         {
611             /* Load the required subsystem */
612             Status = SmpExecuteCommand(&RegEntry->Value,
613                                        *MuSessionId,
614                                        ProcessId,
615                                        SMP_SUBSYSTEM_FLAG);
616         }
617         if (!NT_SUCCESS(Status))
618         {
619             DPRINT1("SMSS: Subsystem execute failed (%wZ)\n", &RegEntry->Value);
620             return Status;
621         }
622 
623         /* Move to the next entry */
624         NextEntry = NextEntry->Flink;
625     }
626 
627     /* Process the "Execute" list now */
628     NextEntry = SmpExecuteList.Blink;
629     if (NextEntry != &SmpExecuteList)
630     {
631         /* Get the custom initial command */
632         RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
633 
634         /* Write the initial command and wait for 5 seconds (why??!) */
635         *InitialCommand = RegEntry->Name;
636         Timeout.QuadPart = -50000000;
637         NtDelayExecution(FALSE, &Timeout);
638     }
639     else
640     {
641         /* Use the default Winlogon initial command */
642         RtlInitUnicodeString(InitialCommand, L"winlogon.exe");
643         InitialCommandBuffer[0] = UNICODE_NULL;
644 
645         /* Check if there's a debugger for Winlogon */
646         Status2 = LdrQueryImageFileExecutionOptions(InitialCommand,
647                                                     L"Debugger",
648                                                     REG_SZ,
649                                                     InitialCommandBuffer,
650                                                     sizeof(InitialCommandBuffer) -
651                                                     InitialCommand->Length,
652                                                     NULL);
653         if ((NT_SUCCESS(Status2)) && (InitialCommandBuffer[0]))
654         {
655             /* Put the debugger string with the Winlogon string */
656             RtlStringCbCatW(InitialCommandBuffer, sizeof(InitialCommandBuffer), L" ");
657             RtlStringCbCatW(InitialCommandBuffer, sizeof(InitialCommandBuffer), InitialCommand->Buffer);
658             RtlInitUnicodeString(InitialCommand, InitialCommandBuffer);
659         }
660     }
661 
662     /* Finally check if there was a custom initial command */
663     NextEntry = SmpExecuteList.Flink;
664     while (NextEntry != &SmpExecuteList)
665     {
666         /* Execute each one */
667         RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
668         SmpExecuteCommand(&RegEntry->Name, *MuSessionId, NULL, 0);
669         NextEntry = NextEntry->Flink;
670     }
671 
672     /* Return status */
673     return Status;
674 }
675