[REACTOS]
[reactos.git] / reactos / 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
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
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
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
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 earching */
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
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 earching */
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
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, SbApiMsg2;
149 RTL_USER_PROCESS_INFORMATION ProcessInformation;
150 LARGE_INTEGER Timeout;
151 PVOID State;
152 PSB_CREATE_PROCESS_MSG CreateProcess = &SbApiMsg.CreateProcess;
153 PSB_CREATE_SESSION_MSG CreateSession = &SbApiMsg.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 iniitalized */
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 wating 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 RtlCopyMemory(&CreateSession->ProcessInfo,
320 &ProcessInformation,
321 sizeof(CreateSession->ProcessInfo));
322
323 /* Not sure these field mean what I think they do -- but clear them */
324 *(PULONGLONG)&CreateSession->ClientId = 0;
325 CreateSession->MuSessionId = 0;
326
327 /* This should find CSRSS because they are POSIX or OS/2 subsystems */
328 Subsystem = SmpLocateKnownSubSysByType(MuSessionId,
329 ProcessInformation.ImageInformation.SubSystemType);
330 if (!Subsystem)
331 {
332 /* Odd failure -- but handle it anyway */
333 Status = STATUS_NO_SUCH_PACKAGE;
334 DPRINT1("SMSS: SmpLoadSubSystem - SmpLocateKnownSubSysByType Failed with Status %lx for sessionid %lu\n",
335 Status,
336 MuSessionId);
337 goto Quickie;
338 }
339
340 /* Duplicate the parent process handle for the subsystem to have */
341 Status = NtDuplicateObject(NtCurrentProcess(),
342 ProcessInformation.ProcessHandle,
343 Subsystem->ProcessHandle,
344 &CreateSession->ProcessInfo.ProcessHandle,
345 PROCESS_ALL_ACCESS,
346 0,
347 0);
348 if (!NT_SUCCESS(Status))
349 {
350 /* Fail since this is critical */
351 DPRINT1("SMSS: SmpLoadSubSystem - NtDuplicateObject Failed with Status %lx for sessionid %lu\n",
352 Status,
353 MuSessionId);
354 goto Quickie;
355 }
356
357 /* Duplicate the initial thread handle for the subsystem to have */
358 Status = NtDuplicateObject(NtCurrentProcess(),
359 ProcessInformation.ThreadHandle,
360 Subsystem->ProcessHandle,
361 &CreateSession->ProcessInfo.ThreadHandle,
362 THREAD_ALL_ACCESS,
363 0,
364 0);
365 if (!NT_SUCCESS(Status))
366 {
367 /* Fail since this is critical */
368 DPRINT1("SMSS: SmpLoadSubSystem - NtDuplicateObject Failed with Status %lx for sessionid %lu\n",
369 Status,
370 MuSessionId);
371 goto Quickie;
372 }
373
374 /* Allocate an internal Session ID for this subsystem */
375 MuSessionId = SmpAllocateSessionId(Subsystem, 0);
376 CreateSession->SessionId = MuSessionId;
377
378 /* Send the create session message to the subsystem */
379 SbApiMsg2.ReturnValue = STATUS_SUCCESS;
380 SbApiMsg2.h.u2.ZeroInit = 0;
381 SbApiMsg2.h.u1.s1.DataLength = sizeof(SB_CREATE_SESSION_MSG) + 8;
382 SbApiMsg2.h.u1.s1.TotalLength = sizeof(SB_API_MSG);
383 Status = NtRequestWaitReplyPort(Subsystem->SbApiPort,
384 &SbApiMsg2.h,
385 &SbApiMsg2.h);
386 if (NT_SUCCESS(Status)) Status = SbApiMsg2.ReturnValue;
387 if (!NT_SUCCESS(Status))
388 {
389 /* Delete the session and handle failure if the LPC call failed */
390 SmpDeleteSession(CreateSession->SessionId);
391 DPRINT1("SMSS: SmpLoadSubSystem - NtRequestWaitReplyPort Failed with Status %lx for sessionid %lu\n",
392 Status,
393 CreateSession->SessionId);
394 goto Quickie;
395 }
396 }
397
398 /* Okay, everything looks good to go, initialize this subsystem now! */
399 Status = NtResumeThread(ProcessInformation.ThreadHandle, NULL);
400 if (!NT_SUCCESS(Status))
401 {
402 /* That didn't work -- back out of everything */
403 DPRINT1("SMSS: SmpLoadSubSystem - NtResumeThread failed Status %lx\n", Status);
404 goto Quickie;
405 }
406
407 /* Check if this was the subsystem for a different session */
408 if (MuSessionId)
409 {
410 /* Wait up to 60 seconds for it to initialize */
411 Timeout.QuadPart = -600000000;
412 Status = NtWaitForSingleObject(NewSubsystem->Event, FALSE, &Timeout);
413
414 /* Timeout is done -- does this session still exist? */
415 if (!SmpCheckDuplicateMuSessionId(MuSessionId))
416 {
417 /* Nope, it died. Cleanup should've ocurred in a different path. */
418 DPRINT1("SMSS: SmpLoadSubSystem - session deleted\n");
419 return STATUS_DELETE_PENDING;
420 }
421
422 /* Check if we timed our or there was another error with the wait */
423 if (Status != STATUS_WAIT_0)
424 {
425 /* Something is wrong with the subsystem, so back out of everything */
426 DPRINT1("SMSS: SmpLoadSubSystem - Timeout waiting for subsystem connect with Status %lx for sessionid %lu\n",
427 Status,
428 MuSessionId);
429 goto Quickie;
430 }
431 }
432 else
433 {
434 /* This a session 0 subsystem, just wait for it to initialize */
435 NtWaitForSingleObject(NewSubsystem->Event, FALSE, NULL);
436 }
437
438 /* Subsystem is created, resumed, and initialized. Close handles and exit */
439 NtClose(ProcessInformation.ThreadHandle);
440 Status = STATUS_SUCCESS;
441 goto Quickie2;
442
443 Quickie:
444 /* This is the failure path. First check if we need to detach from session */
445 if ((AttachedSessionId == -1) || (Flags & (SMP_POSIX_FLAG | SMP_OS2_FLAG)))
446 {
447 /* We were not attached, or did not launch subsystems that required it */
448 DPRINT1("SMSS: Did not detach from Session Space: SessionId=%x Flags=%x Status=%x\n",
449 AttachedSessionId,
450 Flags | SMP_DEFERRED_FLAG,
451 Status);
452 }
453 else
454 {
455 /* Get the privilege we need for detachment */
456 Status = SmpAcquirePrivilege(SE_LOAD_DRIVER_PRIVILEGE, &State);
457 if (!NT_SUCCESS(Status))
458 {
459 /* We can't detach without it */
460 DPRINT1("SMSS: Did not detach from Session Space: SessionId=%x Flags=%x Status=%x\n",
461 AttachedSessionId,
462 Flags | SMP_DEFERRED_FLAG,
463 Status);
464 }
465 else
466 {
467 /* Now detach from the session */
468 Status = NtSetSystemInformation(SystemSessionDetach,
469 &AttachedSessionId,
470 sizeof(AttachedSessionId));
471 if (!NT_SUCCESS(Status))
472 {
473 /* Failed to detach. Note the DPRINT1 has a typo in Windows */
474 DPRINT1("SMSS: SmpStartCsr, Couldn't Detach from Session Space. Status=%x\n", Status);
475 ASSERT(NT_SUCCESS(Status));
476 }
477 else
478 {
479 /* Detachment worked, reset our attached session ID */
480 AttachedSessionId = -1;
481 }
482
483 /* And release the privilege we acquired */
484 SmpReleasePrivilege(State);
485 }
486 }
487
488 /* Since this is the failure path, terminate the subsystem process */
489 NtTerminateProcess(ProcessInformation.ProcessHandle, Status);
490 NtClose(ProcessInformation.ThreadHandle);
491
492 Quickie2:
493 /* This is the cleanup path -- first dereference our subsystems */
494 RtlEnterCriticalSection(&SmpKnownSubSysLock);
495 if (Subsystem) SmpDereferenceSubsystem(Subsystem);
496 if (KnownSubsystem) SmpDereferenceSubsystem(KnownSubsystem);
497
498 /* In the failure case, destroy the new subsystem we just created */
499 if (!NT_SUCCESS(Status))
500 {
501 RemoveEntryList(&NewSubsystem->Entry);
502 NtSetEvent(NewSubsystem->Event, 0);
503 if (NewSubsystem) SmpDereferenceSubsystem(NewSubsystem);
504 }
505
506 /* Finally, we're all done! */
507 RtlLeaveCriticalSection(&SmpKnownSubSysLock);
508 return Status;
509 }
510
511 NTSTATUS
512 NTAPI
513 SmpLoadSubSystemsForMuSession(IN PULONG MuSessionId,
514 OUT PHANDLE ProcessId,
515 IN PUNICODE_STRING InitialCommand)
516 {
517 NTSTATUS Status = STATUS_SUCCESS, Status2;
518 PSMP_REGISTRY_VALUE RegEntry;
519 UNICODE_STRING DestinationString, NtPath;
520 PLIST_ENTRY NextEntry;
521 LARGE_INTEGER Timeout;
522 PVOID State;
523
524 /* Write a few last registry keys with the boot partition information */
525 SmpTranslateSystemPartitionInformation();
526
527 /* Process "SetupExecute" values */
528 NextEntry = SmpSetupExecuteList.Flink;
529 while (NextEntry != &SmpSetupExecuteList)
530 {
531 /* Execute each one and move on */
532 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
533 SmpExecuteCommand(&RegEntry->Name, 0, NULL, 0);
534 NextEntry = NextEntry->Flink;
535 }
536
537 /* Now process the subsystems */
538 NextEntry = SmpSubSystemList.Flink;
539 while (NextEntry != &SmpSubSystemList)
540 {
541 /* Get the entry and check if this is the special Win32k entry */
542 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
543 if (_wcsicmp(RegEntry->Name.Buffer, L"Kmode") == 0)
544 {
545 /* Translate it */
546 if (!RtlDosPathNameToNtPathName_U(RegEntry->Value.Buffer,
547 &NtPath,
548 NULL,
549 NULL))
550 {
551 Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
552 DPRINT1("Failed: %lx\n", Status);
553 }
554 else
555 {
556 /* Get the driver privilege */
557 Status = SmpAcquirePrivilege(SE_LOAD_DRIVER_PRIVILEGE, &State);
558 if (NT_SUCCESS(Status))
559 {
560 /* Create the new session */
561 ASSERT(AttachedSessionId == -1);
562 Status = NtSetSystemInformation(SystemSessionCreate,
563 MuSessionId,
564 sizeof(*MuSessionId));
565 if (!NT_SUCCESS(Status))
566 {
567 DPRINT1("SMSS: Session space creation failed\n");
568 SmpReleasePrivilege(State);
569 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath.Buffer);
570 return Status;
571 }
572 AttachedSessionId = *MuSessionId;
573
574 /*
575 * Start Win32k.sys on this session. Use a hardcoded value
576 * instead of the Kmode one...
577 */
578 RtlInitUnicodeString(&DestinationString,
579 L"\\SystemRoot\\System32\\win32k.sys");
580 Status = NtSetSystemInformation(SystemExtendServiceTableInformation,
581 &DestinationString,
582 sizeof(DestinationString));
583 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath.Buffer);
584 SmpReleasePrivilege(State);
585 if (!NT_SUCCESS(Status))
586 {
587 DPRINT1("SMSS: Load of WIN32K failed.\n");
588 return Status;
589 }
590 }
591 }
592 }
593
594 /* Next entry */
595 NextEntry = NextEntry->Flink;
596 }
597
598 /* Now parse the required subsystem list */
599 NextEntry = SmpSubSystemsToLoad.Flink;
600 while (NextEntry != &SmpSubSystemsToLoad)
601 {
602 /* Get each entry and check if it's the internal debug or not */
603 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
604 if (_wcsicmp(RegEntry->Name.Buffer, L"Debug") == 0)
605 {
606 /* Load the internal debug system */
607 Status = SmpExecuteCommand(&RegEntry->Value,
608 *MuSessionId,
609 ProcessId,
610 SMP_DEBUG_FLAG | SMP_SUBSYSTEM_FLAG);
611 }
612 else
613 {
614 /* Load the required subsystem */
615 Status = SmpExecuteCommand(&RegEntry->Value,
616 *MuSessionId,
617 ProcessId,
618 SMP_SUBSYSTEM_FLAG);
619 }
620 if (!NT_SUCCESS(Status))
621 {
622 DbgPrint("SMSS: Subsystem execute failed (%wZ)\n", &RegEntry->Value);
623 return Status;
624 }
625
626 /* Move to the next entry */
627 NextEntry = NextEntry->Flink;
628 }
629
630 /* Process the "Execute" list now */
631 NextEntry = SmpExecuteList.Blink;
632 if (NextEntry != &SmpExecuteList)
633 {
634 /* Get the custom initial command */
635 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
636
637 /* Write the initial command and wait for 5 seconds (why??!) */
638 *InitialCommand = RegEntry->Name;
639 Timeout.QuadPart = -50000000;
640 NtDelayExecution(FALSE, &Timeout);
641 }
642 else
643 {
644 /* Use the default Winlogon initial command */
645 RtlInitUnicodeString(InitialCommand, L"winlogon.exe");
646 InitialCommandBuffer[0] = UNICODE_NULL;
647
648 /* Check if there's a debugger for Winlogon */
649 Status2 = LdrQueryImageFileExecutionOptions(InitialCommand,
650 L"Debugger",
651 REG_SZ,
652 InitialCommandBuffer,
653 sizeof(InitialCommandBuffer) -
654 InitialCommand->Length,
655 NULL);
656 if ((NT_SUCCESS(Status2)) && (InitialCommandBuffer[0]))
657 {
658 /* Put the debugger string with the Winlogon string */
659 wcscat(InitialCommandBuffer, L" ");
660 wcscat(InitialCommandBuffer, InitialCommand->Buffer);
661 RtlInitUnicodeString(InitialCommand, InitialCommandBuffer);
662 }
663 }
664
665 /* Finally check if there was a custom initial command */
666 NextEntry = SmpExecuteList.Flink;
667 while (NextEntry != &SmpExecuteList)
668 {
669 /* Execute each one */
670 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
671 SmpExecuteCommand(&RegEntry->Name, *MuSessionId, NULL, 0);
672 NextEntry = NextEntry->Flink;
673 }
674
675 /* Return status */
676 return Status;
677 }