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 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 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 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 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 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