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