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