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