1 /* 2 * PROJECT: ReactOS Windows-Compatible Session Manager 3 * LICENSE: BSD 2-Clause License 4 * FILE: base/system/smss/sminit.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 UNICODE_STRING SmpSubsystemName, PosixName, Os2Name; 19 LIST_ENTRY SmpBootExecuteList, SmpSetupExecuteList, SmpPagingFileList; 20 LIST_ENTRY SmpDosDevicesList, SmpFileRenameList, SmpKnownDllsList; 21 LIST_ENTRY SmpExcludeKnownDllsList, SmpSubSystemList, SmpSubSystemsToLoad; 22 LIST_ENTRY SmpSubSystemsToDefer, SmpExecuteList, NativeProcessList; 23 24 PVOID SmpHeap; 25 ULONG SmBaseTag; 26 HANDLE SmpDebugPort, SmpDosDevicesObjectDirectory; 27 PWCHAR SmpDefaultEnvironment, SmpDefaultLibPathBuffer; 28 UNICODE_STRING SmpKnownDllPath, SmpDefaultLibPath; 29 ULONG SmpCalledConfigEnv; 30 31 ULONG SmpInitProgressByLine; 32 NTSTATUS SmpInitReturnStatus; 33 PVOID SmpInitLastCall; 34 35 SECURITY_DESCRIPTOR SmpPrimarySDBody, SmpLiberalSDBody, SmpKnownDllsSDBody; 36 SECURITY_DESCRIPTOR SmpApiPortSDBody; 37 PISECURITY_DESCRIPTOR SmpPrimarySecurityDescriptor, SmpLiberalSecurityDescriptor; 38 PISECURITY_DESCRIPTOR SmpKnownDllsSecurityDescriptor, SmpApiPortSecurityDescriptor; 39 40 ULONG SmpAllowProtectedRenames, SmpProtectionMode = 1; 41 BOOLEAN MiniNTBoot = FALSE; 42 43 #define SMSS_CHECKPOINT(x, y) \ 44 { \ 45 SmpInitProgressByLine = __LINE__; \ 46 SmpInitReturnStatus = (y); \ 47 SmpInitLastCall = (x); \ 48 } 49 50 /* REGISTRY CONFIGURATION *****************************************************/ 51 52 NTSTATUS 53 NTAPI 54 SmpSaveRegistryValue(IN PLIST_ENTRY ListAddress, 55 IN PWSTR Name, 56 IN PWCHAR Value, 57 IN BOOLEAN Flags) 58 { 59 PSMP_REGISTRY_VALUE RegEntry; 60 UNICODE_STRING NameString, ValueString; 61 ANSI_STRING AnsiValueString; 62 PLIST_ENTRY NextEntry; 63 64 /* Convert to unicode strings */ 65 RtlInitUnicodeString(&NameString, Name); 66 RtlInitUnicodeString(&ValueString, Value); 67 68 /* In case this is the first value, initialize a new list/structure */ 69 RegEntry = NULL; 70 71 /* Check if we should do a duplicate check */ 72 if (Flags) 73 { 74 /* Loop the current list */ 75 NextEntry = ListAddress->Flink; 76 while (NextEntry != ListAddress) 77 { 78 /* Get each entry */ 79 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 80 81 /* Check if the value name matches */ 82 if (!RtlCompareUnicodeString(&RegEntry->Name, &NameString, TRUE)) 83 { 84 /* Check if the value is the exact same thing */ 85 if (!RtlCompareUnicodeString(&RegEntry->Value, &ValueString, TRUE)) 86 { 87 /* Fail -- the same setting is being set twice */ 88 return STATUS_OBJECT_NAME_EXISTS; 89 } 90 91 /* We found the list, and this isn't a duplicate value */ 92 break; 93 } 94 95 /* This wasn't a match, keep going */ 96 NextEntry = NextEntry->Flink; 97 RegEntry = NULL; 98 } 99 } 100 101 /* Are we adding on, or creating a new entry */ 102 if (!RegEntry) 103 { 104 /* A new entry -- allocate it */ 105 RegEntry = RtlAllocateHeap(RtlGetProcessHeap(), 106 SmBaseTag, 107 sizeof(SMP_REGISTRY_VALUE) + 108 NameString.MaximumLength); 109 if (!RegEntry) return STATUS_NO_MEMORY; 110 111 /* Initialize the list and set all values to NULL */ 112 InitializeListHead(&RegEntry->Entry); 113 RegEntry->AnsiValue = NULL; 114 RegEntry->Value.Buffer = NULL; 115 116 /* Copy and initialize the value name */ 117 RegEntry->Name.Buffer = (PWCHAR)(RegEntry + 1); 118 RegEntry->Name.Length = NameString.Length; 119 RegEntry->Name.MaximumLength = NameString.MaximumLength; 120 RtlCopyMemory(RegEntry->Name.Buffer, 121 NameString.Buffer, 122 NameString.MaximumLength); 123 124 /* Add this entry into the list */ 125 InsertTailList(ListAddress, &RegEntry->Entry); 126 } 127 128 /* Did we have an old value buffer? */ 129 if (RegEntry->Value.Buffer) 130 { 131 /* Free it */ 132 ASSERT(RegEntry->Value.Length != 0); 133 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer); 134 } 135 136 /* Is there no value associated? */ 137 if (!Value) 138 { 139 /* We're done here */ 140 RtlInitUnicodeString(&RegEntry->Value, NULL); 141 return STATUS_SUCCESS; 142 } 143 144 /* There is a value, so allocate a buffer for it */ 145 RegEntry->Value.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 146 SmBaseTag, 147 ValueString.MaximumLength); 148 if (!RegEntry->Value.Buffer) 149 { 150 /* Out of memory, undo */ 151 RemoveEntryList(&RegEntry->Entry); 152 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry); 153 return STATUS_NO_MEMORY; 154 } 155 156 /* Copy the value into the entry */ 157 RegEntry->Value.Length = ValueString.Length; 158 RegEntry->Value.MaximumLength = ValueString.MaximumLength; 159 RtlCopyMemory(RegEntry->Value.Buffer, 160 ValueString.Buffer, 161 ValueString.MaximumLength); 162 163 /* Now allocate memory for an ANSI copy of it */ 164 RegEntry->AnsiValue = RtlAllocateHeap(RtlGetProcessHeap(), 165 SmBaseTag, 166 (ValueString.Length / sizeof(WCHAR)) + 167 sizeof(ANSI_NULL)); 168 if (!RegEntry->AnsiValue) 169 { 170 /* Out of memory, undo */ 171 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer); 172 RemoveEntryList(&RegEntry->Entry); 173 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry); 174 return STATUS_NO_MEMORY; 175 } 176 177 /* Convert the Unicode value string and return success */ 178 RtlInitEmptyAnsiString(&AnsiValueString, 179 RegEntry->AnsiValue, 180 (ValueString.Length / sizeof(WCHAR)) + 181 sizeof(ANSI_NULL)); 182 RtlUnicodeStringToAnsiString(&AnsiValueString, &ValueString, FALSE); 183 return STATUS_SUCCESS; 184 } 185 186 PSMP_REGISTRY_VALUE 187 NTAPI 188 SmpFindRegistryValue(IN PLIST_ENTRY List, 189 IN PWSTR ValueName) 190 { 191 PSMP_REGISTRY_VALUE RegEntry; 192 UNICODE_STRING ValueString; 193 PLIST_ENTRY NextEntry; 194 195 /* Initialize the value name sting */ 196 RtlInitUnicodeString(&ValueString, ValueName); 197 198 /* Loop the list */ 199 NextEntry = List->Flink; 200 while (NextEntry != List) 201 { 202 /* Get each entry */ 203 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 204 205 /* Check if the value name matches */ 206 if (!RtlCompareUnicodeString(&RegEntry->Name, &ValueString, TRUE)) break; 207 208 /* It doesn't, move on */ 209 NextEntry = NextEntry->Flink; 210 } 211 212 /* If we looped back, return NULL, otherwise return the entry we found */ 213 if (NextEntry == List) RegEntry = NULL; 214 return RegEntry; 215 } 216 217 NTSTATUS 218 NTAPI 219 SmpConfigureProtectionMode(IN PWSTR ValueName, 220 IN ULONG ValueType, 221 IN PVOID ValueData, 222 IN ULONG ValueLength, 223 IN PVOID Context, 224 IN PVOID EntryContext) 225 { 226 /* Make sure the value is valid */ 227 if (ValueLength == sizeof(ULONG)) 228 { 229 /* Read it */ 230 SmpProtectionMode = *(PULONG)ValueData; 231 } 232 else 233 { 234 /* Default is to protect stuff */ 235 SmpProtectionMode = 1; 236 } 237 238 /* Recreate the security descriptors to take into account security mode */ 239 SmpCreateSecurityDescriptors(FALSE); 240 DPRINT("SmpProtectionMode: %lu\n", SmpProtectionMode); 241 return STATUS_SUCCESS; 242 } 243 244 NTSTATUS 245 NTAPI 246 SmpConfigureAllowProtectedRenames(IN PWSTR ValueName, 247 IN ULONG ValueType, 248 IN PVOID ValueData, 249 IN ULONG ValueLength, 250 IN PVOID Context, 251 IN PVOID EntryContext) 252 { 253 /* Make sure the value is valid */ 254 if (ValueLength == sizeof(ULONG)) 255 { 256 /* Read it */ 257 SmpAllowProtectedRenames = *(PULONG)ValueData; 258 } 259 else 260 { 261 /* Default is to not allow protected renames */ 262 SmpAllowProtectedRenames = 0; 263 } 264 265 DPRINT("SmpAllowProtectedRenames: %lu\n", SmpAllowProtectedRenames); 266 return STATUS_SUCCESS; 267 } 268 269 NTSTATUS 270 NTAPI 271 SmpConfigureObjectDirectories(IN PWSTR ValueName, 272 IN ULONG ValueType, 273 IN PVOID ValueData, 274 IN ULONG ValueLength, 275 IN PVOID Context, 276 IN PVOID EntryContext) 277 { 278 PISECURITY_DESCRIPTOR SecDescriptor; 279 NTSTATUS Status; 280 OBJECT_ATTRIBUTES ObjectAttributes; 281 HANDLE DirHandle; 282 UNICODE_STRING RpcString, WindowsString, SearchString; 283 PWCHAR SourceString = ValueData; 284 285 /* Initialize the two strings we will be looking for */ 286 RtlInitUnicodeString(&RpcString, L"\\RPC Control"); 287 RtlInitUnicodeString(&WindowsString, L"\\Windows"); 288 289 /* Loop the registry data we received */ 290 while (*SourceString) 291 { 292 /* Assume primary SD for most objects */ 293 RtlInitUnicodeString(&SearchString, SourceString); 294 SecDescriptor = SmpPrimarySecurityDescriptor; 295 296 /* But for these two always set the liberal descriptor */ 297 if ((RtlEqualUnicodeString(&SearchString, &RpcString, TRUE)) || 298 (RtlEqualUnicodeString(&SearchString, &WindowsString, TRUE))) 299 { 300 SecDescriptor = SmpLiberalSecurityDescriptor; 301 } 302 303 /* Create the requested directory with the requested descriptor */ 304 InitializeObjectAttributes(&ObjectAttributes, 305 &SearchString, 306 OBJ_CASE_INSENSITIVE | 307 OBJ_OPENIF | 308 OBJ_PERMANENT, 309 NULL, 310 SecDescriptor); 311 DPRINT("Creating: %wZ directory\n", &SearchString); 312 Status = NtCreateDirectoryObject(&DirHandle, 313 DIRECTORY_ALL_ACCESS, 314 &ObjectAttributes); 315 if (!NT_SUCCESS(Status)) 316 { 317 /* Failure case */ 318 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n", 319 &SearchString, Status); 320 } 321 else 322 { 323 /* It worked, now close the handle */ 324 NtClose(DirHandle); 325 } 326 327 /* Move to the next requested object */ 328 SourceString += wcslen(SourceString) + 1; 329 } 330 331 /* All done */ 332 return STATUS_SUCCESS; 333 } 334 335 NTSTATUS 336 NTAPI 337 SmpConfigureMemoryMgmt(IN PWSTR ValueName, 338 IN ULONG ValueType, 339 IN PVOID ValueData, 340 IN ULONG ValueLength, 341 IN PVOID Context, 342 IN PVOID EntryContext) 343 { 344 /* Save this is into a list */ 345 return SmpSaveRegistryValue(EntryContext, ValueData, NULL, TRUE); 346 } 347 348 NTSTATUS 349 NTAPI 350 SmpConfigureFileRenames(IN PWSTR ValueName, 351 IN ULONG ValueType, 352 IN PVOID ValueData, 353 IN ULONG ValueLength, 354 IN PVOID Context, 355 IN PVOID EntryContext) 356 { 357 NTSTATUS Status; 358 static PWCHAR Canary = NULL; 359 360 /* Check if this is the second call */ 361 if (Canary) 362 { 363 /* Save the data into the list */ 364 DPRINT("Renamed file: '%S' - '%S'\n", Canary, ValueData); 365 Status = SmpSaveRegistryValue(EntryContext, Canary, ValueData, FALSE); 366 Canary = NULL; 367 } 368 else 369 { 370 /* This it the first call, do nothing until we get the second call */ 371 Canary = ValueData; 372 Status = STATUS_SUCCESS; 373 } 374 375 /* Return the status */ 376 return Status; 377 } 378 379 NTSTATUS 380 NTAPI 381 SmpConfigureExcludeKnownDlls(IN PWSTR ValueName, 382 IN ULONG ValueType, 383 IN PVOID ValueData, 384 IN ULONG ValueLength, 385 IN PVOID Context, 386 IN PVOID EntryContext) 387 { 388 PWCHAR DllName; 389 NTSTATUS Status; 390 391 /* Make sure the value type is valid */ 392 if ((ValueType == REG_MULTI_SZ) || (ValueType == REG_SZ)) 393 { 394 /* Keep going for each DLL in the list */ 395 DllName = ValueData; 396 while (*DllName) 397 { 398 /* Add this to the linked list */ 399 DPRINT("Excluded DLL: %S\n", DllName); 400 Status = SmpSaveRegistryValue(EntryContext, DllName, NULL, TRUE); 401 402 /* Bail out on failure or if only one DLL name was present */ 403 if (!(NT_SUCCESS(Status)) || (ValueType == REG_SZ)) return Status; 404 405 /* Otherwise, move to the next DLL name */ 406 DllName += wcslen(DllName) + 1; 407 } 408 } 409 410 /* All done */ 411 return STATUS_SUCCESS; 412 } 413 414 NTSTATUS 415 NTAPI 416 SmpConfigureDosDevices(IN PWSTR ValueName, 417 IN ULONG ValueType, 418 IN PVOID ValueData, 419 IN ULONG ValueLength, 420 IN PVOID Context, 421 IN PVOID EntryContext) 422 { 423 /* Save into linked list */ 424 return SmpSaveRegistryValue(EntryContext, ValueName, ValueData, TRUE); 425 } 426 427 NTSTATUS 428 NTAPI 429 SmpInitializeKnownDllPath(IN PUNICODE_STRING DllPath, 430 IN PWCHAR Buffer, 431 IN ULONG Length) 432 { 433 NTSTATUS Status; 434 435 /* Allocate the buffer */ 436 DllPath->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag, Length); 437 if (DllPath->Buffer) 438 { 439 /* Fill out the rest of the string */ 440 DllPath->MaximumLength = (USHORT)Length; 441 DllPath->Length = (USHORT)Length - sizeof(UNICODE_NULL); 442 443 /* Copy the actual path and return success */ 444 RtlCopyMemory(DllPath->Buffer, Buffer, Length); 445 Status = STATUS_SUCCESS; 446 } 447 else 448 { 449 /* Fail with out of memory code */ 450 Status = STATUS_NO_MEMORY; 451 } 452 453 /* Return result */ 454 return Status; 455 } 456 457 NTSTATUS 458 NTAPI 459 SmpConfigureKnownDlls(IN PWSTR ValueName, 460 IN ULONG ValueType, 461 IN PVOID ValueData, 462 IN ULONG ValueLength, 463 IN PVOID Context, 464 IN PVOID EntryContext) 465 { 466 /* Check which value is being set */ 467 if (_wcsicmp(ValueName, L"DllDirectory") == 0) 468 { 469 /* This is the directory, initialize it */ 470 DPRINT("KnownDll Path: %S\n", ValueData); 471 return SmpInitializeKnownDllPath(&SmpKnownDllPath, ValueData, ValueLength); 472 } 473 else 474 { 475 /* Add to the linked list -- this is a file */ 476 return SmpSaveRegistryValue(EntryContext, ValueName, ValueData, TRUE); 477 } 478 } 479 480 NTSTATUS 481 NTAPI 482 SmpConfigureEnvironment(IN PWSTR ValueName, 483 IN ULONG ValueType, 484 IN PVOID ValueData, 485 IN ULONG ValueLength, 486 IN PVOID Context, 487 IN PVOID EntryContext) 488 { 489 NTSTATUS Status; 490 UNICODE_STRING ValueString, DataString; 491 492 /* Convert the strings into UNICODE_STRING and set the variable defined */ 493 RtlInitUnicodeString(&ValueString, ValueName); 494 RtlInitUnicodeString(&DataString, ValueData); 495 DPRINT("Setting %wZ = %wZ\n", &ValueString, &DataString); 496 Status = RtlSetEnvironmentVariable(0, &ValueString, &DataString); 497 if (!NT_SUCCESS(Status)) 498 { 499 DPRINT1("SMSS: 'SET %wZ = %wZ' failed - Status == %lx\n", 500 &ValueString, &DataString, Status); 501 return Status; 502 } 503 504 /* Check if the path is being set, and wait for the second instantiation */ 505 if ((_wcsicmp(ValueName, L"Path") == 0) && (++SmpCalledConfigEnv == 2)) 506 { 507 /* Allocate the path buffer */ 508 SmpDefaultLibPathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 509 SmBaseTag, 510 ValueLength); 511 if (!SmpDefaultLibPathBuffer) return STATUS_NO_MEMORY; 512 513 /* Copy the data into it and create the UNICODE_STRING to hold it */ 514 RtlCopyMemory(SmpDefaultLibPathBuffer, ValueData, ValueLength); 515 RtlInitUnicodeString(&SmpDefaultLibPath, SmpDefaultLibPathBuffer); 516 } 517 518 /* All good */ 519 return STATUS_SUCCESS; 520 } 521 522 NTSTATUS 523 NTAPI 524 SmpConfigureSubSystems(IN PWSTR ValueName, 525 IN ULONG ValueType, 526 IN PVOID ValueData, 527 IN ULONG ValueLength, 528 IN PVOID Context, 529 IN PVOID EntryContext) 530 { 531 PSMP_REGISTRY_VALUE RegEntry; 532 PWCHAR SubsystemName; 533 534 /* Is this a required or optional subsystem? */ 535 if ((_wcsicmp(ValueName, L"Required") != 0) && 536 (_wcsicmp(ValueName, L"Optional") != 0)) 537 { 538 /* It isn't, is this the PSI flag? */ 539 if ((_wcsicmp(ValueName, L"PosixSingleInstance") != 0) || 540 (ValueType != REG_DWORD)) 541 { 542 /* It isn't, must be a subsystem entry, add it to the list */ 543 DPRINT("Subsystem entry: %S-%S\n", ValueName, ValueData); 544 return SmpSaveRegistryValue(EntryContext, ValueName, ValueData, TRUE); 545 } 546 547 /* This was the PSI flag, save it and exit */ 548 RegPosixSingleInstance = TRUE; 549 return STATUS_SUCCESS; 550 } 551 552 /* This should be one of the required/optional lists. Is the type valid? */ 553 if (ValueType == REG_MULTI_SZ) 554 { 555 /* It is, get the first subsystem */ 556 SubsystemName = ValueData; 557 while (*SubsystemName) 558 { 559 /* We should have already put it into the list when we found it */ 560 DPRINT("Found subsystem: %S\n", SubsystemName); 561 RegEntry = SmpFindRegistryValue(EntryContext, SubsystemName); 562 if (!RegEntry) 563 { 564 /* This subsystem doesn't exist, so skip it */ 565 DPRINT1("SMSS: Invalid subsystem name - %ws\n", SubsystemName); 566 } 567 else 568 { 569 /* Found it -- remove it from the main list */ 570 RemoveEntryList(&RegEntry->Entry); 571 572 /* Figure out which list to put it in */ 573 if (_wcsicmp(ValueName, L"Required") == 0) 574 { 575 /* Put it into the required list */ 576 DPRINT("Required\n"); 577 InsertTailList(&SmpSubSystemsToLoad, &RegEntry->Entry); 578 } 579 else 580 { 581 /* Put it into the optional list */ 582 DPRINT("Optional\n"); 583 InsertTailList(&SmpSubSystemsToDefer, &RegEntry->Entry); 584 } 585 } 586 587 /* Move to the next name */ 588 SubsystemName += wcslen(SubsystemName) + 1; 589 } 590 } 591 592 /* All done! */ 593 return STATUS_SUCCESS; 594 } 595 596 RTL_QUERY_REGISTRY_TABLE 597 SmpRegistryConfigurationTable[] = 598 { 599 { 600 SmpConfigureProtectionMode, 601 0, 602 L"ProtectionMode", 603 NULL, 604 REG_DWORD, 605 NULL, 606 0 607 }, 608 609 { 610 SmpConfigureAllowProtectedRenames, 611 RTL_QUERY_REGISTRY_DELETE, 612 L"AllowProtectedRenames", 613 NULL, 614 REG_DWORD, 615 NULL, 616 0 617 }, 618 619 { 620 SmpConfigureObjectDirectories, 621 0, 622 L"ObjectDirectories", 623 NULL, 624 REG_MULTI_SZ, 625 L"\\Windows\0\\RPC Control\0", 626 0 627 }, 628 629 { 630 SmpConfigureMemoryMgmt, 631 0, 632 L"BootExecute", 633 &SmpBootExecuteList, 634 REG_MULTI_SZ, 635 L"autocheck AutoChk.exe *\0", 636 0 637 }, 638 639 { 640 SmpConfigureMemoryMgmt, 641 RTL_QUERY_REGISTRY_TOPKEY, 642 L"SetupExecute", 643 &SmpSetupExecuteList, 644 REG_NONE, 645 NULL, 646 0 647 }, 648 649 { 650 SmpConfigureFileRenames, 651 RTL_QUERY_REGISTRY_DELETE, 652 L"PendingFileRenameOperations", 653 &SmpFileRenameList, 654 REG_NONE, 655 NULL, 656 0 657 }, 658 659 { 660 SmpConfigureFileRenames, 661 RTL_QUERY_REGISTRY_DELETE, 662 L"PendingFileRenameOperations2", 663 &SmpFileRenameList, 664 REG_NONE, 665 NULL, 666 0 667 }, 668 669 { 670 SmpConfigureExcludeKnownDlls, 671 0, 672 L"ExcludeFromKnownDlls", 673 &SmpExcludeKnownDllsList, 674 REG_MULTI_SZ, 675 L"\0", 676 0 677 }, 678 679 { 680 NULL, 681 RTL_QUERY_REGISTRY_SUBKEY, 682 L"Memory Management", 683 NULL, 684 REG_NONE, 685 NULL, 686 0 687 }, 688 689 { 690 SmpConfigureMemoryMgmt, 691 0, 692 L"PagingFiles", 693 &SmpPagingFileList, 694 REG_MULTI_SZ, 695 L"?:\\pagefile.sys\0", 696 0 697 }, 698 699 { 700 SmpConfigureDosDevices, 701 RTL_QUERY_REGISTRY_SUBKEY, 702 L"DOS Devices", 703 &SmpDosDevicesList, 704 REG_NONE, 705 NULL, 706 0 707 }, 708 709 { 710 SmpConfigureKnownDlls, 711 RTL_QUERY_REGISTRY_SUBKEY, 712 L"KnownDlls", 713 &SmpKnownDllsList, 714 REG_NONE, 715 NULL, 716 0 717 }, 718 719 { 720 SmpConfigureEnvironment, 721 RTL_QUERY_REGISTRY_SUBKEY, 722 L"Environment", 723 NULL, 724 REG_NONE, 725 NULL, 726 0 727 }, 728 729 { 730 SmpConfigureSubSystems, 731 RTL_QUERY_REGISTRY_SUBKEY, 732 L"SubSystems", 733 &SmpSubSystemList, 734 REG_NONE, 735 NULL, 736 0 737 }, 738 739 { 740 SmpConfigureSubSystems, 741 RTL_QUERY_REGISTRY_NOEXPAND, 742 L"Required", 743 &SmpSubSystemList, 744 REG_MULTI_SZ, 745 L"Debug\0Windows\0", 746 0 747 }, 748 749 { 750 SmpConfigureSubSystems, 751 RTL_QUERY_REGISTRY_NOEXPAND, 752 L"Optional", 753 &SmpSubSystemList, 754 REG_NONE, 755 NULL, 756 0 757 }, 758 759 { 760 SmpConfigureSubSystems, 761 0, 762 L"Kmode", 763 &SmpSubSystemList, 764 REG_NONE, 765 NULL, 766 0 767 }, 768 769 { 770 SmpConfigureMemoryMgmt, 771 RTL_QUERY_REGISTRY_TOPKEY, 772 L"Execute", 773 &SmpExecuteList, 774 REG_NONE, 775 NULL, 776 0 777 }, 778 779 {0}, 780 }; 781 782 /* FUNCTIONS ******************************************************************/ 783 784 VOID 785 NTAPI 786 SmpTranslateSystemPartitionInformation(VOID) 787 { 788 NTSTATUS Status; 789 UNICODE_STRING UnicodeString, LinkTarget, SearchString, SystemPartition; 790 OBJECT_ATTRIBUTES ObjectAttributes; 791 HANDLE KeyHandle, LinkHandle; 792 ULONG Length, Context; 793 size_t StrLength; 794 WCHAR LinkBuffer[MAX_PATH]; 795 CHAR ValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 512]; 796 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer; 797 CHAR DirInfoBuffer[sizeof(OBJECT_DIRECTORY_INFORMATION) + 512]; 798 POBJECT_DIRECTORY_INFORMATION DirInfo = (PVOID)DirInfoBuffer; 799 800 /* Open the setup key */ 801 RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\Setup"); 802 InitializeObjectAttributes(&ObjectAttributes, 803 &UnicodeString, 804 OBJ_CASE_INSENSITIVE, 805 NULL, 806 NULL); 807 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 808 if (!NT_SUCCESS(Status)) 809 { 810 DPRINT1("SMSS: Cannot open system setup key for reading: 0x%x\n", Status); 811 return; 812 } 813 814 /* Query the system partition */ 815 RtlInitUnicodeString(&UnicodeString, L"SystemPartition"); 816 Status = NtQueryValueKey(KeyHandle, 817 &UnicodeString, 818 KeyValuePartialInformation, 819 PartialInfo, 820 sizeof(ValueBuffer), 821 &Length); 822 NtClose(KeyHandle); 823 if (!NT_SUCCESS(Status) || 824 ((PartialInfo->Type != REG_SZ) && (PartialInfo->Type != REG_EXPAND_SZ))) 825 { 826 DPRINT1("SMSS: Cannot query SystemPartition value (Type %lu, Status 0x%x)\n", 827 PartialInfo->Type, Status); 828 return; 829 } 830 831 /* Initialize the system partition string */ 832 RtlInitEmptyUnicodeString(&SystemPartition, 833 (PWCHAR)PartialInfo->Data, 834 PartialInfo->DataLength); 835 RtlStringCbLengthW(SystemPartition.Buffer, 836 SystemPartition.MaximumLength, 837 &StrLength); 838 SystemPartition.Length = (USHORT)StrLength; 839 840 /* Enumerate the directory looking for the symbolic link string */ 841 RtlInitUnicodeString(&SearchString, L"SymbolicLink"); 842 RtlInitEmptyUnicodeString(&LinkTarget, LinkBuffer, sizeof(LinkBuffer)); 843 Status = NtQueryDirectoryObject(SmpDosDevicesObjectDirectory, 844 DirInfo, 845 sizeof(DirInfoBuffer), 846 TRUE, 847 TRUE, 848 &Context, 849 NULL); 850 if (!NT_SUCCESS(Status)) 851 { 852 DPRINT1("SMSS: Cannot find drive letter for system partition\n"); 853 return; 854 } 855 856 /* Keep searching until we find it */ 857 do 858 { 859 /* Is this it? */ 860 if ((RtlEqualUnicodeString(&DirInfo->TypeName, &SearchString, TRUE)) && 861 (DirInfo->Name.Length == 2 * sizeof(WCHAR)) && 862 (DirInfo->Name.Buffer[1] == L':')) 863 { 864 /* Looks like we found it, open the link to get its target */ 865 InitializeObjectAttributes(&ObjectAttributes, 866 &DirInfo->Name, 867 OBJ_CASE_INSENSITIVE, 868 SmpDosDevicesObjectDirectory, 869 NULL); 870 Status = NtOpenSymbolicLinkObject(&LinkHandle, 871 SYMBOLIC_LINK_ALL_ACCESS, 872 &ObjectAttributes); 873 if (NT_SUCCESS(Status)) 874 { 875 /* Open worked, query the target now */ 876 Status = NtQuerySymbolicLinkObject(LinkHandle, 877 &LinkTarget, 878 NULL); 879 NtClose(LinkHandle); 880 881 /* Check if it matches the string we had found earlier */ 882 if ((NT_SUCCESS(Status)) && 883 ((RtlEqualUnicodeString(&SystemPartition, 884 &LinkTarget, 885 TRUE)) || 886 ((RtlPrefixUnicodeString(&SystemPartition, 887 &LinkTarget, 888 TRUE)) && 889 (LinkTarget.Buffer[SystemPartition.Length / sizeof(WCHAR)] == L'\\')))) 890 { 891 /* All done */ 892 break; 893 } 894 } 895 } 896 897 /* Couldn't find it, try again */ 898 Status = NtQueryDirectoryObject(SmpDosDevicesObjectDirectory, 899 DirInfo, 900 sizeof(DirInfoBuffer), 901 TRUE, 902 FALSE, 903 &Context, 904 NULL); 905 } while (NT_SUCCESS(Status)); 906 if (!NT_SUCCESS(Status)) 907 { 908 DPRINT1("SMSS: Cannot find drive letter for system partition\n"); 909 return; 910 } 911 912 /* Open the setup key again, for full access this time */ 913 RtlInitUnicodeString(&UnicodeString, 914 L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup"); 915 InitializeObjectAttributes(&ObjectAttributes, 916 &UnicodeString, 917 OBJ_CASE_INSENSITIVE, 918 NULL, 919 NULL); 920 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes); 921 if (!NT_SUCCESS(Status)) 922 { 923 DPRINT1("SMSS: Cannot open software setup key for writing: 0x%x\n", 924 Status); 925 return; 926 } 927 928 /* Wrap up the end of the link buffer */ 929 wcsncpy(LinkBuffer, DirInfo->Name.Buffer, 2); 930 LinkBuffer[2] = L'\\'; 931 LinkBuffer[3] = L'\0'; 932 933 /* Now set this as the "BootDir" */ 934 RtlInitUnicodeString(&UnicodeString, L"BootDir"); 935 Status = NtSetValueKey(KeyHandle, 936 &UnicodeString, 937 0, 938 REG_SZ, 939 LinkBuffer, 940 4 * sizeof(WCHAR)); 941 if (!NT_SUCCESS(Status)) 942 { 943 DPRINT1("SMSS: couldn't write BootDir value: 0x%x\n", Status); 944 } 945 NtClose(KeyHandle); 946 } 947 948 NTSTATUS 949 NTAPI 950 SmpCreateSecurityDescriptors(IN BOOLEAN InitialCall) 951 { 952 NTSTATUS Status; 953 PSID WorldSid = NULL, AdminSid = NULL, SystemSid = NULL; 954 PSID RestrictedSid = NULL, OwnerSid = NULL; 955 SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY}; 956 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; 957 SID_IDENTIFIER_AUTHORITY CreatorAuthority = {SECURITY_CREATOR_SID_AUTHORITY}; 958 ULONG AclLength, SidLength; 959 PACL Acl; 960 PACE_HEADER Ace; 961 BOOLEAN ProtectionRequired = FALSE; 962 963 /* Check if this is the first call */ 964 if (InitialCall) 965 { 966 /* Create and set the primary descriptor */ 967 SmpPrimarySecurityDescriptor = &SmpPrimarySDBody; 968 Status = RtlCreateSecurityDescriptor(SmpPrimarySecurityDescriptor, 969 SECURITY_DESCRIPTOR_REVISION); 970 ASSERT(NT_SUCCESS(Status)); 971 Status = RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor, 972 TRUE, 973 NULL, 974 FALSE); 975 ASSERT(NT_SUCCESS(Status)); 976 977 /* Create and set the liberal descriptor */ 978 SmpLiberalSecurityDescriptor = &SmpLiberalSDBody; 979 Status = RtlCreateSecurityDescriptor(SmpLiberalSecurityDescriptor, 980 SECURITY_DESCRIPTOR_REVISION); 981 ASSERT(NT_SUCCESS(Status)); 982 Status = RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor, 983 TRUE, 984 NULL, 985 FALSE); 986 ASSERT(NT_SUCCESS(Status)); 987 988 /* Create and set the \KnownDlls descriptor */ 989 SmpKnownDllsSecurityDescriptor = &SmpKnownDllsSDBody; 990 Status = RtlCreateSecurityDescriptor(SmpKnownDllsSecurityDescriptor, 991 SECURITY_DESCRIPTOR_REVISION); 992 ASSERT(NT_SUCCESS(Status)); 993 Status = RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor, 994 TRUE, 995 NULL, 996 FALSE); 997 ASSERT(NT_SUCCESS(Status)); 998 999 /* Create and Set the \ApiPort descriptor */ 1000 SmpApiPortSecurityDescriptor = &SmpApiPortSDBody; 1001 Status = RtlCreateSecurityDescriptor(SmpApiPortSecurityDescriptor, 1002 SECURITY_DESCRIPTOR_REVISION); 1003 ASSERT(NT_SUCCESS(Status)); 1004 Status = RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor, 1005 TRUE, 1006 NULL, 1007 FALSE); 1008 ASSERT(NT_SUCCESS(Status)); 1009 } 1010 1011 /* Check if protection was requested in the registry (on by default) */ 1012 if (SmpProtectionMode & 1) ProtectionRequired = TRUE; 1013 1014 /* Exit if there's nothing to do */ 1015 if (!(InitialCall || ProtectionRequired)) return STATUS_SUCCESS; 1016 1017 /* Build the world SID */ 1018 Status = RtlAllocateAndInitializeSid(&WorldAuthority, 1, 1019 SECURITY_WORLD_RID, 1020 0, 0, 0, 0, 0, 0, 0, 1021 &WorldSid); 1022 if (!NT_SUCCESS(Status)) 1023 { 1024 WorldSid = NULL; 1025 goto Quickie; 1026 } 1027 1028 /* Build the admin SID */ 1029 Status = RtlAllocateAndInitializeSid(&NtAuthority, 2, 1030 SECURITY_BUILTIN_DOMAIN_RID, 1031 DOMAIN_ALIAS_RID_ADMINS, 1032 0, 0, 0, 0, 0, 0, 1033 &AdminSid); 1034 if (!NT_SUCCESS(Status)) 1035 { 1036 AdminSid = NULL; 1037 goto Quickie; 1038 } 1039 1040 /* Build the owner SID */ 1041 Status = RtlAllocateAndInitializeSid(&CreatorAuthority, 1, 1042 SECURITY_CREATOR_OWNER_RID, 1043 0, 0, 0, 0, 0, 0, 0, 1044 &OwnerSid); 1045 if (!NT_SUCCESS(Status)) 1046 { 1047 OwnerSid = NULL; 1048 goto Quickie; 1049 } 1050 1051 /* Build the restricted SID */ 1052 Status = RtlAllocateAndInitializeSid(&NtAuthority, 1, 1053 SECURITY_RESTRICTED_CODE_RID, 1054 0, 0, 0, 0, 0, 0, 0, 1055 &RestrictedSid); 1056 if (!NT_SUCCESS(Status)) 1057 { 1058 RestrictedSid = NULL; 1059 goto Quickie; 1060 } 1061 1062 /* Build the system SID */ 1063 Status = RtlAllocateAndInitializeSid(&NtAuthority, 1, 1064 SECURITY_LOCAL_SYSTEM_RID, 1065 0, 0, 0, 0, 0, 0, 0, 1066 &SystemSid); 1067 if (!NT_SUCCESS(Status)) 1068 { 1069 SystemSid = NULL; 1070 goto Quickie; 1071 } 1072 1073 /* Now check if we're creating the core descriptors */ 1074 if (!InitialCall) 1075 { 1076 /* We're skipping NextAcl so we have to do this here */ 1077 SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(RestrictedSid) + RtlLengthSid(AdminSid); 1078 SidLength *= 2; 1079 goto NotInitial; 1080 } 1081 1082 /* Allocate an ACL with two ACEs with two SIDs each */ 1083 SidLength = RtlLengthSid(SystemSid) + RtlLengthSid(AdminSid); 1084 AclLength = sizeof(ACL) + 2 * sizeof(ACCESS_ALLOWED_ACE) + SidLength; 1085 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength); 1086 if (!Acl) Status = STATUS_NO_MEMORY; 1087 if (!NT_SUCCESS(Status)) goto NextAcl; 1088 1089 /* Now build the ACL and add the two ACEs */ 1090 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2); 1091 ASSERT(NT_SUCCESS(Status)); 1092 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1093 ASSERT(NT_SUCCESS(Status)); 1094 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, SystemSid); 1095 ASSERT(NT_SUCCESS(Status)); 1096 1097 /* Set this as the DACL */ 1098 Status = RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor, 1099 TRUE, 1100 Acl, 1101 FALSE); 1102 ASSERT(NT_SUCCESS(Status)); 1103 1104 NextAcl: 1105 /* Allocate an ACL with 6 ACEs, two ACEs per SID */ 1106 SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(RestrictedSid) + RtlLengthSid(AdminSid); 1107 SidLength *= 2; 1108 AclLength = sizeof(ACL) + 6 * sizeof(ACCESS_ALLOWED_ACE) + SidLength; 1109 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength); 1110 if (!Acl) Status = STATUS_NO_MEMORY; 1111 if (!NT_SUCCESS(Status)) goto NotInitial; 1112 1113 /* Now build the ACL and add the six ACEs */ 1114 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2); 1115 ASSERT(NT_SUCCESS(Status)); 1116 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE, WorldSid); 1117 ASSERT(NT_SUCCESS(Status)); 1118 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE, RestrictedSid); 1119 ASSERT(NT_SUCCESS(Status)); 1120 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1121 ASSERT(NT_SUCCESS(Status)); 1122 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid); 1123 ASSERT(NT_SUCCESS(Status)); 1124 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid); 1125 ASSERT(NT_SUCCESS(Status)); 1126 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1127 ASSERT(NT_SUCCESS(Status)); 1128 1129 /* Now edit the last three ACEs and make them inheritable */ 1130 Status = RtlGetAce(Acl, 3, (PVOID)&Ace); 1131 ASSERT(NT_SUCCESS(Status)); 1132 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1133 Status = RtlGetAce(Acl, 4, (PVOID)&Ace); 1134 ASSERT(NT_SUCCESS(Status)); 1135 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1136 Status = RtlGetAce(Acl, 5, (PVOID)&Ace); 1137 ASSERT(NT_SUCCESS(Status)); 1138 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1139 1140 /* Set this as the DACL */ 1141 Status = RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor, 1142 TRUE, 1143 Acl, 1144 FALSE); 1145 ASSERT(NT_SUCCESS(Status)); 1146 1147 NotInitial: 1148 /* The initial ACLs have been created, are we also protecting objects? */ 1149 if (!ProtectionRequired) goto Quickie; 1150 1151 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */ 1152 SidLength += RtlLengthSid(OwnerSid); 1153 AclLength = sizeof(ACL) + 7 * sizeof (ACCESS_ALLOWED_ACE) + 2 * SidLength; 1154 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength); 1155 if (!Acl) Status = STATUS_NO_MEMORY; 1156 if (!NT_SUCCESS(Status)) goto Quickie; 1157 1158 /* Build the ACL and add the seven ACEs */ 1159 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2); 1160 ASSERT(NT_SUCCESS(Status)); 1161 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, WorldSid); 1162 ASSERT(NT_SUCCESS(Status)); 1163 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, RestrictedSid); 1164 ASSERT(NT_SUCCESS(Status)); 1165 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1166 ASSERT(NT_SUCCESS(Status)); 1167 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, WorldSid); 1168 ASSERT(NT_SUCCESS(Status)); 1169 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, RestrictedSid); 1170 ASSERT(NT_SUCCESS(Status)); 1171 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1172 ASSERT(NT_SUCCESS(Status)); 1173 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, OwnerSid); 1174 ASSERT(NT_SUCCESS(Status)); 1175 1176 /* Edit the last 4 ACEs to make then inheritable */ 1177 Status = RtlGetAce(Acl, 3, (PVOID)&Ace); 1178 ASSERT(NT_SUCCESS(Status)); 1179 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1180 Status = RtlGetAce(Acl, 4, (PVOID)&Ace); 1181 ASSERT(NT_SUCCESS(Status)); 1182 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1183 Status = RtlGetAce(Acl, 5, (PVOID)&Ace); 1184 ASSERT(NT_SUCCESS(Status)); 1185 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1186 Status = RtlGetAce(Acl, 6, (PVOID)&Ace); 1187 ASSERT(NT_SUCCESS(Status)); 1188 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1189 1190 /* Set this as the DACL for the primary SD */ 1191 Status = RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor, 1192 TRUE, 1193 Acl, 1194 FALSE); 1195 ASSERT(NT_SUCCESS(Status)); 1196 1197 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */ 1198 AclLength = sizeof(ACL) + 7 * sizeof (ACCESS_ALLOWED_ACE) + 2 * SidLength; 1199 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength); 1200 if (!Acl) Status = STATUS_NO_MEMORY; 1201 if (!NT_SUCCESS(Status)) goto Quickie; 1202 1203 /* Build the ACL and add the seven ACEs */ 1204 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2); 1205 ASSERT(NT_SUCCESS(Status)); 1206 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid); 1207 ASSERT(NT_SUCCESS(Status)); 1208 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid); 1209 ASSERT(NT_SUCCESS(Status)); 1210 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1211 ASSERT(NT_SUCCESS(Status)); 1212 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid); 1213 ASSERT(NT_SUCCESS(Status)); 1214 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid); 1215 ASSERT(NT_SUCCESS(Status)); 1216 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1217 ASSERT(NT_SUCCESS(Status)); 1218 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, OwnerSid); 1219 ASSERT(NT_SUCCESS(Status)); 1220 1221 /* Edit the last 4 ACEs to make then inheritable */ 1222 Status = RtlGetAce(Acl, 3, (PVOID)&Ace); 1223 ASSERT(NT_SUCCESS(Status)); 1224 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1225 Status = RtlGetAce(Acl, 4, (PVOID)&Ace); 1226 ASSERT(NT_SUCCESS(Status)); 1227 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1228 Status = RtlGetAce(Acl, 5, (PVOID)&Ace); 1229 ASSERT(NT_SUCCESS(Status)); 1230 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1231 Status = RtlGetAce(Acl, 6, (PVOID)&Ace); 1232 ASSERT(NT_SUCCESS(Status)); 1233 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1234 1235 /* Now set this as the DACL for the liberal SD */ 1236 Status = RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor, 1237 TRUE, 1238 Acl, 1239 FALSE); 1240 ASSERT(NT_SUCCESS(Status)); 1241 1242 Quickie: 1243 /* Cleanup the SIDs */ 1244 if (OwnerSid) RtlFreeHeap(RtlGetProcessHeap(), 0, OwnerSid); 1245 if (AdminSid) RtlFreeHeap(RtlGetProcessHeap(), 0, AdminSid); 1246 if (WorldSid) RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid); 1247 if (SystemSid) RtlFreeHeap(RtlGetProcessHeap(), 0, SystemSid); 1248 if (RestrictedSid) RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSid); 1249 return Status; 1250 } 1251 1252 NTSTATUS 1253 NTAPI 1254 SmpInitializeDosDevices(VOID) 1255 { 1256 NTSTATUS Status; 1257 PSMP_REGISTRY_VALUE RegEntry; 1258 SECURITY_DESCRIPTOR_CONTROL OldFlag = 0; 1259 OBJECT_ATTRIBUTES ObjectAttributes; 1260 UNICODE_STRING DestinationString; 1261 HANDLE DirHandle; 1262 PLIST_ENTRY NextEntry, Head; 1263 1264 /* Open the GLOBAL?? directory */ 1265 RtlInitUnicodeString(&DestinationString, L"\\??"); 1266 InitializeObjectAttributes(&ObjectAttributes, 1267 &DestinationString, 1268 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, 1269 NULL, 1270 NULL); 1271 Status = NtOpenDirectoryObject(&SmpDosDevicesObjectDirectory, 1272 DIRECTORY_ALL_ACCESS, 1273 &ObjectAttributes); 1274 if (!NT_SUCCESS(Status)) 1275 { 1276 DPRINT1("SMSS: Unable to open %wZ directory - Status == %lx\n", 1277 &DestinationString, Status); 1278 return Status; 1279 } 1280 1281 /* Loop the DOS devices */ 1282 Head = &SmpDosDevicesList; 1283 while (!IsListEmpty(Head)) 1284 { 1285 /* Get the entry and remove it */ 1286 NextEntry = RemoveHeadList(Head); 1287 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 1288 1289 /* Initialize the attributes, and see which descriptor is being used */ 1290 InitializeObjectAttributes(&ObjectAttributes, 1291 &RegEntry->Name, 1292 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, 1293 SmpDosDevicesObjectDirectory, 1294 SmpPrimarySecurityDescriptor); 1295 if (SmpPrimarySecurityDescriptor) 1296 { 1297 /* Save the old flag and set it while we create this link */ 1298 OldFlag = SmpPrimarySecurityDescriptor->Control; 1299 SmpPrimarySecurityDescriptor->Control |= SE_DACL_DEFAULTED; 1300 } 1301 1302 /* Create the symbolic link */ 1303 DPRINT("Creating symlink for %wZ to %wZ\n", &RegEntry->Name, &RegEntry->Value); 1304 Status = NtCreateSymbolicLinkObject(&DirHandle, 1305 SYMBOLIC_LINK_ALL_ACCESS, 1306 &ObjectAttributes, 1307 &RegEntry->Value); 1308 if (Status == STATUS_OBJECT_NAME_EXISTS) 1309 { 1310 /* Make it temporary and get rid of the handle */ 1311 NtMakeTemporaryObject(DirHandle); 1312 NtClose(DirHandle); 1313 1314 /* Treat this as success, and see if we got a name back */ 1315 Status = STATUS_SUCCESS; 1316 if (RegEntry->Value.Length) 1317 { 1318 /* Create it now with this name */ 1319 ObjectAttributes.Attributes &= ~OBJ_OPENIF; 1320 Status = NtCreateSymbolicLinkObject(&DirHandle, 1321 SYMBOLIC_LINK_ALL_ACCESS, 1322 &ObjectAttributes, 1323 &RegEntry->Value); 1324 } 1325 } 1326 1327 /* If we were using a security descriptor, restore the non-defaulted flag */ 1328 if (ObjectAttributes.SecurityDescriptor) 1329 { 1330 SmpPrimarySecurityDescriptor->Control = OldFlag; 1331 } 1332 1333 /* Print a failure if we failed to create the symbolic link */ 1334 if (!NT_SUCCESS(Status)) 1335 { 1336 DPRINT1("SMSS: Unable to create %wZ => %wZ symbolic link object - Status == 0x%lx\n", 1337 &RegEntry->Name, 1338 &RegEntry->Value, 1339 Status); 1340 break; 1341 } 1342 1343 /* Close the handle */ 1344 NtClose(DirHandle); 1345 1346 /* Free this entry */ 1347 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue); 1348 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer); 1349 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry); 1350 } 1351 1352 /* Return the status */ 1353 return Status; 1354 } 1355 1356 VOID 1357 NTAPI 1358 SmpProcessModuleImports(IN PVOID Unused, 1359 IN PCHAR ImportName) 1360 { 1361 ULONG Length = 0; 1362 WCHAR Buffer[MAX_PATH]; 1363 PWCHAR DllName, DllValue; 1364 ANSI_STRING ImportString; 1365 UNICODE_STRING ImportUnicodeString; 1366 NTSTATUS Status; 1367 1368 /* Skip NTDLL since it's already always mapped */ 1369 if (!_stricmp(ImportName, "ntdll.dll")) return; 1370 1371 /* Initialize our strings */ 1372 RtlInitAnsiString(&ImportString, ImportName); 1373 RtlInitEmptyUnicodeString(&ImportUnicodeString, Buffer, sizeof(Buffer)); 1374 Status = RtlAnsiStringToUnicodeString(&ImportUnicodeString, &ImportString, FALSE); 1375 if (!NT_SUCCESS(Status)) return; 1376 1377 /* Loop to find the DLL file extension */ 1378 while (Length < ImportUnicodeString.Length) 1379 { 1380 if (ImportUnicodeString.Buffer[Length / sizeof(WCHAR)] == L'.') break; 1381 Length += sizeof(WCHAR); 1382 } 1383 1384 /* 1385 * Break up the values as needed; the buffer acquires the form: 1386 * "dll_name.dll\0dll_name\0" 1387 */ 1388 DllValue = ImportUnicodeString.Buffer; 1389 DllName = &ImportUnicodeString.Buffer[(ImportUnicodeString.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR)]; 1390 RtlStringCbCopyNW(DllName, 1391 ImportUnicodeString.MaximumLength - (ImportUnicodeString.Length + sizeof(UNICODE_NULL)), 1392 ImportUnicodeString.Buffer, Length); 1393 1394 /* Add the DLL to the list */ 1395 SmpSaveRegistryValue(&SmpKnownDllsList, DllName, DllValue, TRUE); 1396 } 1397 1398 NTSTATUS 1399 NTAPI 1400 SmpInitializeKnownDllsInternal(IN PUNICODE_STRING Directory, 1401 IN PUNICODE_STRING Path) 1402 { 1403 HANDLE DirFileHandle, DirHandle, SectionHandle, FileHandle, LinkHandle; 1404 UNICODE_STRING NtPath, DestinationString; 1405 OBJECT_ATTRIBUTES ObjectAttributes; 1406 NTSTATUS Status, Status1; 1407 PLIST_ENTRY NextEntry; 1408 PSMP_REGISTRY_VALUE RegEntry; 1409 ULONG_PTR ErrorParameters[3]; 1410 UNICODE_STRING ErrorResponse; 1411 IO_STATUS_BLOCK IoStatusBlock; 1412 SECURITY_DESCRIPTOR_CONTROL OldFlag = 0; 1413 USHORT ImageCharacteristics; 1414 1415 /* Initialize to NULL */ 1416 DirFileHandle = NULL; 1417 DirHandle = NULL; 1418 NtPath.Buffer = NULL; 1419 1420 /* Create the \KnownDLLs directory */ 1421 InitializeObjectAttributes(&ObjectAttributes, 1422 Directory, 1423 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, 1424 NULL, 1425 SmpKnownDllsSecurityDescriptor); 1426 Status = NtCreateDirectoryObject(&DirHandle, 1427 DIRECTORY_ALL_ACCESS, 1428 &ObjectAttributes); 1429 if (!NT_SUCCESS(Status)) 1430 { 1431 /* Handle failure */ 1432 DPRINT1("SMSS: Unable to create %wZ directory - Status == %lx\n", 1433 Directory, Status); 1434 return Status; 1435 } 1436 1437 /* Convert the path to native format */ 1438 if (!RtlDosPathNameToNtPathName_U(Path->Buffer, &NtPath, NULL, NULL)) 1439 { 1440 /* Fail if this didn't work */ 1441 DPRINT1("SMSS: Unable to to convert %wZ to an Nt path\n", Path); 1442 Status = STATUS_OBJECT_NAME_INVALID; 1443 goto Quickie; 1444 } 1445 1446 /* Open the path that was specified, which should be a directory */ 1447 InitializeObjectAttributes(&ObjectAttributes, 1448 &NtPath, 1449 OBJ_CASE_INSENSITIVE, 1450 NULL, 1451 NULL); 1452 Status = NtOpenFile(&DirFileHandle, 1453 FILE_LIST_DIRECTORY | SYNCHRONIZE, 1454 &ObjectAttributes, 1455 &IoStatusBlock, 1456 FILE_SHARE_READ | FILE_SHARE_WRITE, 1457 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 1458 if (!NT_SUCCESS(Status)) 1459 { 1460 /* Fail if we couldn't open it */ 1461 DPRINT1("SMSS: Unable to open a handle to the KnownDll directory (%wZ)" 1462 "- Status == %lx\n", 1463 Path, 1464 Status); 1465 FileHandle = NULL; 1466 goto Quickie; 1467 } 1468 1469 /* Temporarily hack the SD to use a default DACL for this symbolic link */ 1470 if (SmpPrimarySecurityDescriptor) 1471 { 1472 OldFlag = SmpPrimarySecurityDescriptor->Control; 1473 SmpPrimarySecurityDescriptor->Control |= SE_DACL_DEFAULTED; 1474 } 1475 1476 /* Create a symbolic link to the directory in the object manager */ 1477 RtlInitUnicodeString(&DestinationString, L"KnownDllPath"); 1478 InitializeObjectAttributes(&ObjectAttributes, 1479 &DestinationString, 1480 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, 1481 DirHandle, 1482 SmpPrimarySecurityDescriptor); 1483 Status = NtCreateSymbolicLinkObject(&LinkHandle, 1484 SYMBOLIC_LINK_ALL_ACCESS, 1485 &ObjectAttributes, 1486 Path); 1487 1488 /* Undo the hack */ 1489 if (SmpPrimarySecurityDescriptor) SmpPrimarySecurityDescriptor->Control = OldFlag; 1490 1491 /* Check if the symlink was created */ 1492 if (!NT_SUCCESS(Status)) 1493 { 1494 /* It wasn't, so bail out since the OS needs it to exist */ 1495 DPRINT1("SMSS: Unable to create %wZ symbolic link - Status == %lx\n", 1496 &DestinationString, Status); 1497 LinkHandle = NULL; 1498 goto Quickie; 1499 } 1500 1501 /* We created it permanent, we can go ahead and close the handle now */ 1502 Status1 = NtClose(LinkHandle); 1503 ASSERT(NT_SUCCESS(Status1)); 1504 1505 /* Now loop the known DLLs */ 1506 NextEntry = SmpKnownDllsList.Flink; 1507 while (NextEntry != &SmpKnownDllsList) 1508 { 1509 /* Get the entry and move on */ 1510 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 1511 NextEntry = NextEntry->Flink; 1512 1513 DPRINT("Processing known DLL: %wZ-%wZ\n", &RegEntry->Name, &RegEntry->Value); 1514 1515 /* Skip the entry if it's in the excluded list */ 1516 if ((SmpFindRegistryValue(&SmpExcludeKnownDllsList, 1517 RegEntry->Name.Buffer)) || 1518 (SmpFindRegistryValue(&SmpExcludeKnownDllsList, 1519 RegEntry->Value.Buffer))) 1520 { 1521 continue; 1522 } 1523 1524 /* Open the actual file */ 1525 InitializeObjectAttributes(&ObjectAttributes, 1526 &RegEntry->Value, 1527 OBJ_CASE_INSENSITIVE, 1528 DirFileHandle, 1529 NULL); 1530 Status1 = NtOpenFile(&FileHandle, 1531 SYNCHRONIZE | FILE_EXECUTE, 1532 &ObjectAttributes, 1533 &IoStatusBlock, 1534 FILE_SHARE_READ | FILE_SHARE_DELETE, 1535 FILE_NON_DIRECTORY_FILE | 1536 FILE_SYNCHRONOUS_IO_NONALERT); 1537 /* If we failed, skip it */ 1538 if (!NT_SUCCESS(Status1)) continue; 1539 1540 /* Checksum it */ 1541 Status = LdrVerifyImageMatchesChecksum((HANDLE)((ULONG_PTR)FileHandle | 1), 1542 SmpProcessModuleImports, 1543 RegEntry, 1544 &ImageCharacteristics); 1545 if (!NT_SUCCESS(Status)) 1546 { 1547 /* Checksum failed, so don't even try going further -- kill SMSS */ 1548 RtlInitUnicodeString(&ErrorResponse, 1549 L"Verification of a KnownDLL failed."); 1550 ErrorParameters[0] = (ULONG_PTR)&ErrorResponse; 1551 ErrorParameters[1] = Status; 1552 ErrorParameters[2] = (ULONG_PTR)&RegEntry->Value; 1553 SmpTerminate(ErrorParameters, 5, RTL_NUMBER_OF(ErrorParameters)); 1554 } 1555 else if (!(ImageCharacteristics & IMAGE_FILE_DLL)) 1556 { 1557 /* An invalid known DLL entry will also kill SMSS */ 1558 RtlInitUnicodeString(&ErrorResponse, 1559 L"Non-DLL file included in KnownDLL list."); 1560 ErrorParameters[0] = (ULONG_PTR)&ErrorResponse; 1561 ErrorParameters[1] = STATUS_INVALID_IMPORT_OF_NON_DLL; 1562 ErrorParameters[2] = (ULONG_PTR)&RegEntry->Value; 1563 SmpTerminate(ErrorParameters, 5, RTL_NUMBER_OF(ErrorParameters)); 1564 } 1565 1566 /* Temporarily hack the SD to use a default DACL for this section */ 1567 if (SmpLiberalSecurityDescriptor) 1568 { 1569 OldFlag = SmpLiberalSecurityDescriptor->Control; 1570 SmpLiberalSecurityDescriptor->Control |= SE_DACL_DEFAULTED; 1571 } 1572 1573 /* Create the section for this known DLL */ 1574 InitializeObjectAttributes(&ObjectAttributes, 1575 &RegEntry->Value, 1576 OBJ_PERMANENT, 1577 DirHandle, 1578 SmpLiberalSecurityDescriptor) 1579 Status = NtCreateSection(&SectionHandle, 1580 SECTION_ALL_ACCESS, 1581 &ObjectAttributes, 1582 0, 1583 PAGE_EXECUTE, 1584 SEC_IMAGE, 1585 FileHandle); 1586 1587 /* Undo the hack */ 1588 if (SmpLiberalSecurityDescriptor) SmpLiberalSecurityDescriptor->Control = OldFlag; 1589 1590 /* Check if we created the section okay */ 1591 if (NT_SUCCESS(Status)) 1592 { 1593 /* We can close it now, since it's marked permanent */ 1594 Status1 = NtClose(SectionHandle); 1595 ASSERT(NT_SUCCESS(Status1)); 1596 } 1597 else 1598 { 1599 /* If we couldn't make it "known", that's fine and keep going */ 1600 DPRINT1("SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n", 1601 &RegEntry->Value, Status); 1602 } 1603 1604 /* Close the file since we can move on to the next one */ 1605 Status1 = NtClose(FileHandle); 1606 ASSERT(NT_SUCCESS(Status1)); 1607 } 1608 1609 Quickie: 1610 /* Close both handles and free the NT path buffer */ 1611 if (DirHandle) 1612 { 1613 Status1 = NtClose(DirHandle); 1614 ASSERT(NT_SUCCESS(Status1)); 1615 } 1616 if (DirFileHandle) 1617 { 1618 Status1 = NtClose(DirFileHandle); 1619 ASSERT(NT_SUCCESS(Status1)); 1620 } 1621 if (NtPath.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath.Buffer); 1622 return Status; 1623 } 1624 1625 NTSTATUS 1626 NTAPI 1627 SmpInitializeKnownDlls(VOID) 1628 { 1629 NTSTATUS Status; 1630 PSMP_REGISTRY_VALUE RegEntry; 1631 UNICODE_STRING DestinationString; 1632 PLIST_ENTRY Head, NextEntry; 1633 1634 /* Call the internal function */ 1635 RtlInitUnicodeString(&DestinationString, L"\\KnownDlls"); 1636 Status = SmpInitializeKnownDllsInternal(&DestinationString, &SmpKnownDllPath); 1637 1638 /* Wipe out the list regardless of success */ 1639 Head = &SmpKnownDllsList; 1640 while (!IsListEmpty(Head)) 1641 { 1642 /* Remove this entry */ 1643 NextEntry = RemoveHeadList(Head); 1644 1645 /* Free it */ 1646 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 1647 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue); 1648 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer); 1649 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry); 1650 } 1651 1652 /* All done */ 1653 return Status; 1654 } 1655 1656 NTSTATUS 1657 NTAPI 1658 SmpCreateDynamicEnvironmentVariables(VOID) 1659 { 1660 NTSTATUS Status; 1661 SYSTEM_BASIC_INFORMATION BasicInfo; 1662 SYSTEM_PROCESSOR_INFORMATION ProcessorInfo; 1663 OBJECT_ATTRIBUTES ObjectAttributes; 1664 UNICODE_STRING ValueName, DestinationString; 1665 HANDLE KeyHandle, KeyHandle2; 1666 PWCHAR ValueData; 1667 ULONG ResultLength; 1668 size_t StrLength; 1669 WCHAR ValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 512]; 1670 WCHAR ValueBuffer2[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 512]; 1671 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer; 1672 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo2 = (PVOID)ValueBuffer2; 1673 1674 /* Get system basic information -- we'll need the CPU count */ 1675 Status = NtQuerySystemInformation(SystemBasicInformation, 1676 &BasicInfo, 1677 sizeof(BasicInfo), 1678 NULL); 1679 if (!NT_SUCCESS(Status)) 1680 { 1681 /* Bail out on failure */ 1682 DPRINT1("SMSS: Unable to query system basic information - %x\n", Status); 1683 return Status; 1684 } 1685 1686 /* Get the processor information, we'll query a bunch of revision info */ 1687 Status = NtQuerySystemInformation(SystemProcessorInformation, 1688 &ProcessorInfo, 1689 sizeof(ProcessorInfo), 1690 NULL); 1691 if (!NT_SUCCESS(Status)) 1692 { 1693 /* Bail out on failure */ 1694 DPRINT1("SMSS: Unable to query system processor information - %x\n", Status); 1695 return Status; 1696 } 1697 1698 /* We'll be writing all these environment variables over here */ 1699 RtlInitUnicodeString(&DestinationString, 1700 L"\\Registry\\Machine\\System\\CurrentControlSet\\" 1701 L"Control\\Session Manager\\Environment"); 1702 InitializeObjectAttributes(&ObjectAttributes, 1703 &DestinationString, 1704 OBJ_CASE_INSENSITIVE, 1705 NULL, 1706 NULL); 1707 Status = NtOpenKey(&KeyHandle, GENERIC_WRITE, &ObjectAttributes); 1708 if (!NT_SUCCESS(Status)) 1709 { 1710 /* Bail out on failure */ 1711 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString, Status); 1712 return Status; 1713 } 1714 1715 /* First let's write the OS variable */ 1716 RtlInitUnicodeString(&ValueName, L"OS"); 1717 ValueData = L"Windows_NT"; 1718 DPRINT("Setting %wZ to %S\n", &ValueName, ValueData); 1719 Status = NtSetValueKey(KeyHandle, 1720 &ValueName, 1721 0, 1722 REG_SZ, 1723 ValueData, 1724 (wcslen(ValueData) + 1) * sizeof(WCHAR)); 1725 if (!NT_SUCCESS(Status)) 1726 { 1727 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n", 1728 &ValueName, Status); 1729 NtClose(KeyHandle); 1730 return Status; 1731 } 1732 1733 /* Next, let's write the CPU architecture variable */ 1734 RtlInitUnicodeString(&ValueName, L"PROCESSOR_ARCHITECTURE"); 1735 switch (ProcessorInfo.ProcessorArchitecture) 1736 { 1737 /* Pick the correct string that matches the architecture */ 1738 case PROCESSOR_ARCHITECTURE_INTEL: 1739 ValueData = L"x86"; 1740 break; 1741 1742 case PROCESSOR_ARCHITECTURE_AMD64: 1743 ValueData = L"AMD64"; 1744 break; 1745 1746 case PROCESSOR_ARCHITECTURE_IA64: 1747 ValueData = L"IA64"; 1748 break; 1749 1750 default: 1751 ValueData = L"Unknown"; 1752 break; 1753 } 1754 1755 /* Set it */ 1756 DPRINT("Setting %wZ to %S\n", &ValueName, ValueData); 1757 Status = NtSetValueKey(KeyHandle, 1758 &ValueName, 1759 0, 1760 REG_SZ, 1761 ValueData, 1762 (wcslen(ValueData) + 1) * sizeof(WCHAR)); 1763 if (!NT_SUCCESS(Status)) 1764 { 1765 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n", 1766 &ValueName, Status); 1767 NtClose(KeyHandle); 1768 return Status; 1769 } 1770 1771 /* And now let's write the processor level */ 1772 RtlInitUnicodeString(&ValueName, L"PROCESSOR_LEVEL"); 1773 swprintf(ValueBuffer, L"%u", ProcessorInfo.ProcessorLevel); 1774 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer); 1775 Status = NtSetValueKey(KeyHandle, 1776 &ValueName, 1777 0, 1778 REG_SZ, 1779 ValueBuffer, 1780 (wcslen(ValueBuffer) + 1) * sizeof(WCHAR)); 1781 if (!NT_SUCCESS(Status)) 1782 { 1783 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n", 1784 &ValueName, Status); 1785 NtClose(KeyHandle); 1786 return Status; 1787 } 1788 1789 /* Now open the hardware CPU key */ 1790 RtlInitUnicodeString(&DestinationString, 1791 L"\\Registry\\Machine\\Hardware\\Description\\System\\" 1792 L"CentralProcessor\\0"); 1793 InitializeObjectAttributes(&ObjectAttributes, 1794 &DestinationString, 1795 OBJ_CASE_INSENSITIVE, 1796 NULL, 1797 NULL); 1798 Status = NtOpenKey(&KeyHandle2, KEY_READ, &ObjectAttributes); 1799 if (!NT_SUCCESS(Status)) 1800 { 1801 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString, Status); 1802 NtClose(KeyHandle); 1803 return Status; 1804 } 1805 1806 /* So that we can read the identifier out of it... */ 1807 RtlInitUnicodeString(&ValueName, L"Identifier"); 1808 Status = NtQueryValueKey(KeyHandle2, 1809 &ValueName, 1810 KeyValuePartialInformation, 1811 PartialInfo, 1812 sizeof(ValueBuffer), 1813 &ResultLength); 1814 if (!NT_SUCCESS(Status) || 1815 ((PartialInfo->Type != REG_SZ) && (PartialInfo->Type != REG_EXPAND_SZ))) 1816 { 1817 NtClose(KeyHandle2); 1818 NtClose(KeyHandle); 1819 DPRINT1("SMSS: Unable to read %wZ\\%wZ (Type %lu, Status 0x%x)\n", 1820 &DestinationString, &ValueName, PartialInfo->Type, Status); 1821 return Status; 1822 } 1823 1824 /* Initialize the string so that it can be large enough 1825 * to contain both the identifier and the vendor strings. */ 1826 RtlInitEmptyUnicodeString(&DestinationString, 1827 (PWCHAR)PartialInfo->Data, 1828 sizeof(ValueBuffer) - 1829 FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)); 1830 RtlStringCbLengthW(DestinationString.Buffer, 1831 PartialInfo->DataLength, 1832 &StrLength); 1833 DestinationString.Length = (USHORT)StrLength; 1834 1835 /* As well as the vendor... */ 1836 RtlInitUnicodeString(&ValueName, L"VendorIdentifier"); 1837 Status = NtQueryValueKey(KeyHandle2, 1838 &ValueName, 1839 KeyValuePartialInformation, 1840 PartialInfo2, 1841 sizeof(ValueBuffer2), 1842 &ResultLength); 1843 NtClose(KeyHandle2); 1844 if (NT_SUCCESS(Status) && 1845 ((PartialInfo2->Type == REG_SZ) || (PartialInfo2->Type == REG_EXPAND_SZ))) 1846 { 1847 /* To combine it into a single string */ 1848 RtlStringCbPrintfW(DestinationString.Buffer + DestinationString.Length / sizeof(WCHAR), 1849 DestinationString.MaximumLength - DestinationString.Length, 1850 L", %.*s", 1851 PartialInfo2->DataLength / sizeof(WCHAR), 1852 (PWCHAR)PartialInfo2->Data); 1853 DestinationString.Length = (USHORT)(wcslen(DestinationString.Buffer) * sizeof(WCHAR)); 1854 } 1855 1856 /* So that we can set this as the PROCESSOR_IDENTIFIER variable */ 1857 RtlInitUnicodeString(&ValueName, L"PROCESSOR_IDENTIFIER"); 1858 DPRINT("Setting %wZ to %wZ\n", &ValueName, &DestinationString); 1859 Status = NtSetValueKey(KeyHandle, 1860 &ValueName, 1861 0, 1862 REG_SZ, 1863 DestinationString.Buffer, 1864 DestinationString.Length + sizeof(UNICODE_NULL)); 1865 if (!NT_SUCCESS(Status)) 1866 { 1867 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n", 1868 &ValueName, Status); 1869 NtClose(KeyHandle); 1870 return Status; 1871 } 1872 1873 /* Now let's get the processor architecture */ 1874 RtlInitUnicodeString(&ValueName, L"PROCESSOR_REVISION"); 1875 switch (ProcessorInfo.ProcessorArchitecture) 1876 { 1877 /* Check if this is an older Intel CPU */ 1878 case PROCESSOR_ARCHITECTURE_INTEL: 1879 if ((ProcessorInfo.ProcessorRevision >> 8) == 0xFF) 1880 { 1881 /* These guys used a revision + stepping, so get the rev only */ 1882 swprintf(ValueBuffer, L"%02x", ProcessorInfo.ProcessorRevision & 0xFF); 1883 _wcsupr(ValueBuffer); 1884 break; 1885 } 1886 1887 /* Modern Intel, as well as 64-bit CPUs use a revision without stepping */ 1888 case PROCESSOR_ARCHITECTURE_IA64: 1889 case PROCESSOR_ARCHITECTURE_AMD64: 1890 swprintf(ValueBuffer, L"%04x", ProcessorInfo.ProcessorRevision); 1891 break; 1892 1893 /* And anything else we'll just read the whole revision identifier */ 1894 default: 1895 swprintf(ValueBuffer, L"%u", ProcessorInfo.ProcessorRevision); 1896 break; 1897 } 1898 1899 /* Write the revision to the registry */ 1900 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer); 1901 Status = NtSetValueKey(KeyHandle, 1902 &ValueName, 1903 0, 1904 REG_SZ, 1905 ValueBuffer, 1906 (wcslen(ValueBuffer) + 1) * sizeof(WCHAR)); 1907 if (!NT_SUCCESS(Status)) 1908 { 1909 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n", 1910 &ValueName, Status); 1911 NtClose(KeyHandle); 1912 return Status; 1913 } 1914 1915 /* And finally, write the number of CPUs */ 1916 RtlInitUnicodeString(&ValueName, L"NUMBER_OF_PROCESSORS"); 1917 swprintf(ValueBuffer, L"%d", BasicInfo.NumberOfProcessors); 1918 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer); 1919 Status = NtSetValueKey(KeyHandle, 1920 &ValueName, 1921 0, 1922 REG_SZ, 1923 ValueBuffer, 1924 (wcslen(ValueBuffer) + 1) * sizeof(WCHAR)); 1925 if (!NT_SUCCESS(Status)) 1926 { 1927 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n", 1928 &ValueName, Status); 1929 NtClose(KeyHandle); 1930 return Status; 1931 } 1932 1933 /* Now we need to write the safeboot option key in a different format */ 1934 RtlInitUnicodeString(&DestinationString, 1935 L"\\Registry\\Machine\\System\\CurrentControlSet\\" 1936 L"Control\\Safeboot\\Option"); 1937 InitializeObjectAttributes(&ObjectAttributes, 1938 &DestinationString, 1939 OBJ_CASE_INSENSITIVE, 1940 NULL, 1941 NULL); 1942 Status = NtOpenKey(&KeyHandle2, KEY_ALL_ACCESS, &ObjectAttributes); 1943 if (NT_SUCCESS(Status)) 1944 { 1945 /* This was indeed a safeboot, so check what kind of safeboot it was */ 1946 RtlInitUnicodeString(&ValueName, L"OptionValue"); 1947 Status = NtQueryValueKey(KeyHandle2, 1948 &ValueName, 1949 KeyValuePartialInformation, 1950 PartialInfo, 1951 sizeof(ValueBuffer), 1952 &ResultLength); 1953 NtClose(KeyHandle2); 1954 if (NT_SUCCESS(Status) && 1955 (PartialInfo->Type == REG_DWORD) && 1956 (PartialInfo->DataLength >= sizeof(ULONG))) 1957 { 1958 /* Convert from the integer value to the correct specifier */ 1959 RtlInitUnicodeString(&ValueName, L"SAFEBOOT_OPTION"); 1960 switch (*(PULONG)PartialInfo->Data) 1961 { 1962 case 1: 1963 wcscpy(ValueBuffer, L"MINIMAL"); 1964 break; 1965 case 2: 1966 wcscpy(ValueBuffer, L"NETWORK"); 1967 break; 1968 case 3: 1969 wcscpy(ValueBuffer, L"DSREPAIR"); 1970 break; 1971 } 1972 1973 /* And write it in the environment! */ 1974 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer); 1975 Status = NtSetValueKey(KeyHandle, 1976 &ValueName, 1977 0, 1978 REG_SZ, 1979 ValueBuffer, 1980 (wcslen(ValueBuffer) + 1) * sizeof(WCHAR)); 1981 if (!NT_SUCCESS(Status)) 1982 { 1983 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n", 1984 &ValueName, Status); 1985 NtClose(KeyHandle); 1986 return Status; 1987 } 1988 } 1989 else 1990 { 1991 DPRINT1("SMSS: Failed to query SAFEBOOT option (Type %lu, Status 0x%x)\n", 1992 PartialInfo->Type, Status); 1993 } 1994 } 1995 1996 /* We are all done now */ 1997 NtClose(KeyHandle); 1998 return STATUS_SUCCESS; 1999 } 2000 2001 NTSTATUS 2002 NTAPI 2003 SmpProcessFileRenames(VOID) 2004 { 2005 BOOLEAN OldState, HavePrivilege = FALSE; 2006 NTSTATUS Status; 2007 HANDLE FileHandle, OtherFileHandle; 2008 FILE_INFORMATION_CLASS InformationClass; 2009 OBJECT_ATTRIBUTES ObjectAttributes; 2010 IO_STATUS_BLOCK IoStatusBlock; 2011 UNICODE_STRING FileString; 2012 FILE_BASIC_INFORMATION BasicInfo; 2013 FILE_DISPOSITION_INFORMATION DeleteInformation; 2014 PFILE_RENAME_INFORMATION Buffer; 2015 PLIST_ENTRY Head, NextEntry; 2016 PSMP_REGISTRY_VALUE RegEntry; 2017 PWCHAR FileName; 2018 ULONG ValueLength, Length; 2019 2020 /* Give us access to restore any files we want */ 2021 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &OldState); 2022 if (NT_SUCCESS(Status)) HavePrivilege = TRUE; 2023 2024 // FIXME: Handle SFC-protected file renames! 2025 if (SmpAllowProtectedRenames) 2026 DPRINT1("SMSS: FIXME: Handle SFC-protected file renames!\n"); 2027 2028 /* Process pending files to rename */ 2029 Head = &SmpFileRenameList; 2030 while (!IsListEmpty(Head)) 2031 { 2032 /* Get this entry */ 2033 NextEntry = RemoveHeadList(Head); 2034 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 2035 DPRINT("Processing PFRO: '%wZ' / '%wZ'\n", &RegEntry->Value, &RegEntry->Name); 2036 2037 /* Skip past the '@' marker */ 2038 if (!(RegEntry->Value.Length) && (*RegEntry->Name.Buffer == L'@')) 2039 { 2040 RegEntry->Name.Length -= sizeof(UNICODE_NULL); 2041 RegEntry->Name.Buffer++; 2042 } 2043 2044 /* Open the file for delete access */ 2045 InitializeObjectAttributes(&ObjectAttributes, 2046 &RegEntry->Name, 2047 OBJ_CASE_INSENSITIVE, 2048 NULL, 2049 NULL); 2050 Status = NtOpenFile(&OtherFileHandle, 2051 DELETE | SYNCHRONIZE, 2052 &ObjectAttributes, 2053 &IoStatusBlock, 2054 FILE_SHARE_READ | FILE_SHARE_WRITE, 2055 FILE_SYNCHRONOUS_IO_NONALERT); 2056 if (!NT_SUCCESS(Status)) goto Quickie; 2057 2058 /* Check if it's a rename or just a delete */ 2059 ValueLength = RegEntry->Value.Length; 2060 if (!ValueLength) 2061 { 2062 /* Just a delete, set up the class, length and buffer */ 2063 InformationClass = FileDispositionInformation; 2064 Length = sizeof(DeleteInformation); 2065 Buffer = (PFILE_RENAME_INFORMATION)&DeleteInformation; 2066 2067 /* Set the delete disposition */ 2068 DeleteInformation.DeleteFile = TRUE; 2069 } 2070 else 2071 { 2072 /* This is a rename, setup the class and length */ 2073 InformationClass = FileRenameInformation; 2074 Length = ValueLength + sizeof(FILE_RENAME_INFORMATION); 2075 2076 /* Skip past the special markers */ 2077 FileName = RegEntry->Value.Buffer; 2078 if ((*FileName == L'!') || (*FileName == L'@')) 2079 { 2080 FileName++; 2081 Length -= sizeof(UNICODE_NULL); 2082 } 2083 2084 /* Now allocate the buffer for the rename information */ 2085 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag, Length); 2086 if (Buffer) 2087 { 2088 /* Setup the buffer to point to the filename, and copy it */ 2089 Buffer->RootDirectory = NULL; 2090 Buffer->FileNameLength = Length - sizeof(FILE_RENAME_INFORMATION); 2091 Buffer->ReplaceIfExists = FileName != RegEntry->Value.Buffer; 2092 RtlCopyMemory(Buffer->FileName, FileName, Buffer->FileNameLength); 2093 } 2094 else 2095 { 2096 /* Fail */ 2097 Status = STATUS_NO_MEMORY; 2098 } 2099 } 2100 2101 /* Check if everything is okay till here */ 2102 if (NT_SUCCESS(Status)) 2103 { 2104 /* Now either rename or delete the file as requested */ 2105 Status = NtSetInformationFile(OtherFileHandle, 2106 &IoStatusBlock, 2107 Buffer, 2108 Length, 2109 InformationClass); 2110 2111 /* Check if we seem to have failed because the file was readonly */ 2112 if (!NT_SUCCESS(Status) && 2113 (InformationClass == FileRenameInformation) && 2114 (Status == STATUS_OBJECT_NAME_COLLISION) && 2115 Buffer->ReplaceIfExists) 2116 { 2117 /* Open the file for write attribute access this time... */ 2118 DPRINT("\nSMSS: '%wZ' => '%wZ' failed - Status == %x, Possible readonly target\n", 2119 &RegEntry->Name, 2120 &RegEntry->Value, 2121 STATUS_OBJECT_NAME_COLLISION); 2122 FileString.Length = RegEntry->Value.Length - sizeof(WCHAR); 2123 FileString.MaximumLength = RegEntry->Value.MaximumLength - sizeof(WCHAR); 2124 FileString.Buffer = FileName; 2125 InitializeObjectAttributes(&ObjectAttributes, 2126 &FileString, 2127 OBJ_CASE_INSENSITIVE, 2128 NULL, 2129 NULL); 2130 Status = NtOpenFile(&FileHandle, 2131 FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, 2132 &ObjectAttributes, 2133 &IoStatusBlock, 2134 FILE_SHARE_READ | FILE_SHARE_WRITE, 2135 FILE_SYNCHRONOUS_IO_NONALERT); 2136 if (!NT_SUCCESS(Status)) 2137 { 2138 /* That didn't work, so bail out */ 2139 DPRINT1(" SMSS: Open Existing file Failed - Status == %x\n", 2140 Status); 2141 } 2142 else 2143 { 2144 /* Now remove the read-only attribute from the file */ 2145 DPRINT(" SMSS: Open Existing Success\n"); 2146 RtlZeroMemory(&BasicInfo, sizeof(BasicInfo)); 2147 BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL; 2148 Status = NtSetInformationFile(FileHandle, 2149 &IoStatusBlock, 2150 &BasicInfo, 2151 sizeof(BasicInfo), 2152 FileBasicInformation); 2153 NtClose(FileHandle); 2154 if (!NT_SUCCESS(Status)) 2155 { 2156 /* That didn't work, bail out */ 2157 DPRINT1(" SMSS: Set To NORMAL Failed - Status == %x\n", 2158 Status); 2159 } 2160 else 2161 { 2162 /* Now that the file is no longer read-only, delete! */ 2163 DPRINT(" SMSS: Set To NORMAL OK\n"); 2164 Status = NtSetInformationFile(OtherFileHandle, 2165 &IoStatusBlock, 2166 Buffer, 2167 Length, 2168 FileRenameInformation); 2169 if (!NT_SUCCESS(Status)) 2170 { 2171 /* That failed too! */ 2172 DPRINT1(" SMSS: Re-Rename Failed - Status == %x\n", 2173 Status); 2174 } 2175 else 2176 { 2177 /* Everything ok */ 2178 DPRINT(" SMSS: Re-Rename Worked OK\n"); 2179 } 2180 } 2181 } 2182 } 2183 } 2184 2185 /* Close the file handle and check the operation result */ 2186 NtClose(OtherFileHandle); 2187 Quickie: 2188 if (!NT_SUCCESS(Status)) 2189 { 2190 /* We totally failed */ 2191 DPRINT1("SMSS: '%wZ' => '%wZ' failed - Status == %x\n", 2192 &RegEntry->Name, &RegEntry->Value, Status); 2193 } 2194 else if (RegEntry->Value.Length) 2195 { 2196 /* We succeed with a rename */ 2197 DPRINT("SMSS: '%wZ' (renamed to) '%wZ'\n", &RegEntry->Name, &RegEntry->Value); 2198 } 2199 else 2200 { 2201 /* We succeeded with a delete */ 2202 DPRINT("SMSS: '%wZ' (deleted)\n", &RegEntry->Name); 2203 } 2204 2205 /* Now free this entry and keep going */ 2206 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue); 2207 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer); 2208 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry); 2209 } 2210 2211 /* Put back the restore privilege if we had requested it, and return */ 2212 if (HavePrivilege) RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, FALSE, FALSE, &OldState); 2213 return Status; 2214 } 2215 2216 NTSTATUS 2217 NTAPI 2218 SmpLoadDataFromRegistry(OUT PUNICODE_STRING InitialCommand) 2219 { 2220 NTSTATUS Status; 2221 PLIST_ENTRY Head, NextEntry; 2222 PSMP_REGISTRY_VALUE RegEntry; 2223 PVOID OriginalEnvironment; 2224 ULONG MuSessionId = 0; 2225 OBJECT_ATTRIBUTES ObjectAttributes; 2226 HANDLE KeyHandle; 2227 UNICODE_STRING DestinationString; 2228 2229 /* Initialize the keywords we'll be looking for */ 2230 RtlInitUnicodeString(&SmpDebugKeyword, L"debug"); 2231 RtlInitUnicodeString(&SmpASyncKeyword, L"async"); 2232 RtlInitUnicodeString(&SmpAutoChkKeyword, L"autocheck"); 2233 2234 /* Initialize all the registry-associated list heads */ 2235 InitializeListHead(&SmpBootExecuteList); 2236 InitializeListHead(&SmpSetupExecuteList); 2237 InitializeListHead(&SmpPagingFileList); 2238 InitializeListHead(&SmpDosDevicesList); 2239 InitializeListHead(&SmpFileRenameList); 2240 InitializeListHead(&SmpKnownDllsList); 2241 InitializeListHead(&SmpExcludeKnownDllsList); 2242 InitializeListHead(&SmpSubSystemList); 2243 InitializeListHead(&SmpSubSystemsToLoad); 2244 InitializeListHead(&SmpSubSystemsToDefer); 2245 InitializeListHead(&SmpExecuteList); 2246 SmpPagingFileInitialize(); 2247 2248 /* Initialize the SMSS environment */ 2249 Status = RtlCreateEnvironment(TRUE, &SmpDefaultEnvironment); 2250 if (!NT_SUCCESS(Status)) 2251 { 2252 /* Fail if there was a problem */ 2253 DPRINT1("SMSS: Unable to allocate default environment - Status == %X\n", 2254 Status); 2255 SMSS_CHECKPOINT(RtlCreateEnvironment, Status); 2256 return Status; 2257 } 2258 2259 /* Check if we were booted in PE mode (LiveCD should have this) */ 2260 RtlInitUnicodeString(&DestinationString, 2261 L"\\Registry\\Machine\\System\\CurrentControlSet\\" 2262 L"Control\\MiniNT"); 2263 InitializeObjectAttributes(&ObjectAttributes, 2264 &DestinationString, 2265 OBJ_CASE_INSENSITIVE, 2266 NULL, 2267 NULL); 2268 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes); 2269 if (NT_SUCCESS(Status)) 2270 { 2271 /* If the key exists, we were */ 2272 NtClose(KeyHandle); 2273 MiniNTBoot = TRUE; 2274 } 2275 2276 /* Print out if this is the case */ 2277 if (MiniNTBoot) DPRINT("SMSS: !!! MiniNT Boot !!!\n"); 2278 2279 /* Open the environment key to see if we are booted in safe mode */ 2280 RtlInitUnicodeString(&DestinationString, 2281 L"\\Registry\\Machine\\System\\CurrentControlSet\\" 2282 L"Control\\Session Manager\\Environment"); 2283 InitializeObjectAttributes(&ObjectAttributes, 2284 &DestinationString, 2285 OBJ_CASE_INSENSITIVE, 2286 NULL, 2287 NULL); 2288 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes); 2289 if (NT_SUCCESS(Status)) 2290 { 2291 /* Delete the value if we found it */ 2292 RtlInitUnicodeString(&DestinationString, L"SAFEBOOT_OPTION"); 2293 NtDeleteValueKey(KeyHandle, &DestinationString); 2294 NtClose(KeyHandle); 2295 } 2296 2297 /* Switch environments, then query the registry for all needed settings */ 2298 OriginalEnvironment = NtCurrentPeb()->ProcessParameters->Environment; 2299 NtCurrentPeb()->ProcessParameters->Environment = SmpDefaultEnvironment; 2300 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, 2301 L"Session Manager", 2302 SmpRegistryConfigurationTable, 2303 NULL, 2304 NULL); 2305 SmpDefaultEnvironment = NtCurrentPeb()->ProcessParameters->Environment; 2306 NtCurrentPeb()->ProcessParameters->Environment = OriginalEnvironment; 2307 if (!NT_SUCCESS(Status)) 2308 { 2309 /* We failed somewhere in registry initialization, which is bad... */ 2310 DPRINT1("SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status); 2311 SMSS_CHECKPOINT(RtlQueryRegistryValues, Status); 2312 return Status; 2313 } 2314 2315 /* Now we can start acting on the registry settings. First to DOS devices */ 2316 Status = SmpInitializeDosDevices(); 2317 if (!NT_SUCCESS(Status)) 2318 { 2319 /* Failed */ 2320 DPRINT1("SMSS: Unable to initialize DosDevices configuration - Status == %lx\n", 2321 Status); 2322 SMSS_CHECKPOINT(SmpInitializeDosDevices, Status); 2323 return Status; 2324 } 2325 2326 /* Next create the session directory... */ 2327 RtlInitUnicodeString(&DestinationString, L"\\Sessions"); 2328 InitializeObjectAttributes(&ObjectAttributes, 2329 &DestinationString, 2330 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, 2331 NULL, 2332 SmpPrimarySecurityDescriptor); 2333 Status = NtCreateDirectoryObject(&SmpSessionsObjectDirectory, 2334 DIRECTORY_ALL_ACCESS, 2335 &ObjectAttributes); 2336 if (!NT_SUCCESS(Status)) 2337 { 2338 /* Fail */ 2339 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n", 2340 &DestinationString, Status); 2341 SMSS_CHECKPOINT(NtCreateDirectoryObject, Status); 2342 return Status; 2343 } 2344 2345 /* Next loop all the boot execute binaries */ 2346 Head = &SmpBootExecuteList; 2347 while (!IsListEmpty(Head)) 2348 { 2349 /* Remove each one from the list */ 2350 NextEntry = RemoveHeadList(Head); 2351 2352 /* Execute it */ 2353 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 2354 SmpExecuteCommand(&RegEntry->Name, 0, NULL, 0); 2355 2356 /* And free it */ 2357 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue); 2358 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer); 2359 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry); 2360 } 2361 2362 /* Now do any pending file rename operations... */ 2363 if (!MiniNTBoot) SmpProcessFileRenames(); 2364 2365 /* And initialize known DLLs... */ 2366 Status = SmpInitializeKnownDlls(); 2367 if (!NT_SUCCESS(Status)) 2368 { 2369 /* Fail if that didn't work */ 2370 DPRINT1("SMSS: Unable to initialize KnownDll configuration - Status == %lx\n", 2371 Status); 2372 SMSS_CHECKPOINT(SmpInitializeKnownDlls, Status); 2373 return Status; 2374 } 2375 2376 /* Create the needed page files */ 2377 if (!MiniNTBoot) 2378 { 2379 /* Loop every page file */ 2380 Head = &SmpPagingFileList; 2381 while (!IsListEmpty(Head)) 2382 { 2383 /* Remove each one from the list */ 2384 NextEntry = RemoveHeadList(Head); 2385 2386 /* Create the descriptor for it */ 2387 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 2388 SmpCreatePagingFileDescriptor(&RegEntry->Name); 2389 2390 /* And free it */ 2391 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue); 2392 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer); 2393 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry); 2394 } 2395 2396 /* Now create all the paging files for the descriptors that we have */ 2397 SmpCreatePagingFiles(); 2398 } 2399 2400 /* Tell Cm it's now safe to fully enable write access to the registry */ 2401 NtInitializeRegistry(CM_BOOT_FLAG_SMSS); 2402 2403 /* Create all the system-based environment variables for later inheriting */ 2404 Status = SmpCreateDynamicEnvironmentVariables(); 2405 if (!NT_SUCCESS(Status)) 2406 { 2407 /* Handle failure */ 2408 SMSS_CHECKPOINT(SmpCreateDynamicEnvironmentVariables, Status); 2409 return Status; 2410 } 2411 2412 /* And finally load all the subsystems for our first session! */ 2413 Status = SmpLoadSubSystemsForMuSession(&MuSessionId, 2414 &SmpWindowsSubSysProcessId, 2415 InitialCommand); 2416 ASSERT(MuSessionId == 0); 2417 if (!NT_SUCCESS(Status)) SMSS_CHECKPOINT(SmpLoadSubSystemsForMuSession, Status); 2418 return Status; 2419 } 2420 2421 NTSTATUS 2422 NTAPI 2423 SmpInit(IN PUNICODE_STRING InitialCommand, 2424 OUT PHANDLE ProcessHandle) 2425 { 2426 NTSTATUS Status, Status2; 2427 OBJECT_ATTRIBUTES ObjectAttributes; 2428 UNICODE_STRING PortName, EventName; 2429 HANDLE EventHandle, PortHandle; 2430 ULONG HardErrorMode; 2431 2432 /* Create the SMSS Heap */ 2433 SmBaseTag = RtlCreateTagHeap(RtlGetProcessHeap(), 2434 0, 2435 L"SMSS!", 2436 L"INIT"); 2437 SmpHeap = RtlGetProcessHeap(); 2438 2439 /* Enable hard errors */ 2440 HardErrorMode = TRUE; 2441 NtSetInformationProcess(NtCurrentProcess(), 2442 ProcessDefaultHardErrorMode, 2443 &HardErrorMode, 2444 sizeof(HardErrorMode)); 2445 2446 /* Initialize the subsystem list and the session list, plus their locks */ 2447 RtlInitializeCriticalSection(&SmpKnownSubSysLock); 2448 InitializeListHead(&SmpKnownSubSysHead); 2449 RtlInitializeCriticalSection(&SmpSessionListLock); 2450 InitializeListHead(&SmpSessionListHead); 2451 2452 /* Initialize the process list */ 2453 InitializeListHead(&NativeProcessList); 2454 2455 /* Initialize session parameters */ 2456 SmpNextSessionId = 1; 2457 SmpNextSessionIdScanMode = 0; 2458 SmpDbgSsLoaded = FALSE; 2459 2460 /* Create the initial security descriptors */ 2461 Status = SmpCreateSecurityDescriptors(TRUE); 2462 if (!NT_SUCCESS(Status)) 2463 { 2464 /* Fail */ 2465 SMSS_CHECKPOINT(SmpCreateSecurityDescriptors, Status); 2466 return Status; 2467 } 2468 2469 /* Initialize subsystem names */ 2470 RtlInitUnicodeString(&SmpSubsystemName, L"NT-Session Manager"); 2471 RtlInitUnicodeString(&PosixName, L"POSIX"); 2472 RtlInitUnicodeString(&Os2Name, L"OS2"); 2473 2474 /* Create the SM API Port */ 2475 RtlInitUnicodeString(&PortName, L"\\SmApiPort"); 2476 InitializeObjectAttributes(&ObjectAttributes, &PortName, 0, NULL, SmpApiPortSecurityDescriptor); 2477 Status = NtCreatePort(&PortHandle, 2478 &ObjectAttributes, 2479 sizeof(SB_CONNECTION_INFO), 2480 sizeof(SM_API_MSG), 2481 sizeof(SB_API_MSG) * 32); 2482 ASSERT(NT_SUCCESS(Status)); 2483 SmpDebugPort = PortHandle; 2484 2485 /* Create two SM API threads */ 2486 Status = RtlCreateUserThread(NtCurrentProcess(), 2487 NULL, 2488 FALSE, 2489 0, 2490 0, 2491 0, 2492 SmpApiLoop, 2493 PortHandle, 2494 NULL, 2495 NULL); 2496 ASSERT(NT_SUCCESS(Status)); 2497 Status = RtlCreateUserThread(NtCurrentProcess(), 2498 NULL, 2499 FALSE, 2500 0, 2501 0, 2502 0, 2503 SmpApiLoop, 2504 PortHandle, 2505 NULL, 2506 NULL); 2507 ASSERT(NT_SUCCESS(Status)); 2508 2509 /* Create the write event that autochk can set after running */ 2510 RtlInitUnicodeString(&EventName, L"\\Device\\VolumesSafeForWriteAccess"); 2511 InitializeObjectAttributes(&ObjectAttributes, 2512 &EventName, 2513 OBJ_PERMANENT, 2514 NULL, 2515 NULL); 2516 Status2 = NtCreateEvent(&EventHandle, 2517 EVENT_ALL_ACCESS, 2518 &ObjectAttributes, 2519 0, 2520 0); 2521 if (!NT_SUCCESS(Status2)) 2522 { 2523 /* Should never really fail */ 2524 DPRINT1("SMSS: Unable to create %wZ event - Status == %lx\n", 2525 &EventName, Status2); 2526 ASSERT(NT_SUCCESS(Status2)); 2527 } 2528 2529 /* Now initialize everything else based on the registry parameters */ 2530 Status = SmpLoadDataFromRegistry(InitialCommand); 2531 if (NT_SUCCESS(Status)) 2532 { 2533 /* Autochk should've run now. Set the event and save the CSRSS handle */ 2534 *ProcessHandle = SmpWindowsSubSysProcess; 2535 NtSetEvent(EventHandle, 0); 2536 NtClose(EventHandle); 2537 } 2538 2539 /* All done */ 2540 return Status; 2541 } 2542