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