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 CHAR ValueBuffer[512 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)]; 793 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer; 794 ULONG Length, Context; 795 CHAR DirInfoBuffer[512 + sizeof(OBJECT_DIRECTORY_INFORMATION)]; 796 POBJECT_DIRECTORY_INFORMATION DirInfo = (PVOID)DirInfoBuffer; 797 WCHAR LinkBuffer[MAX_PATH]; 798 799 /* Open the setup key */ 800 RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\Setup"); 801 InitializeObjectAttributes(&ObjectAttributes, 802 &UnicodeString, 803 OBJ_CASE_INSENSITIVE, 804 NULL, 805 NULL); 806 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 807 if (!NT_SUCCESS(Status)) 808 { 809 DPRINT1("SMSS: can't open system setup key for reading: 0x%x\n", Status); 810 return; 811 } 812 813 /* Query the system partition */ 814 RtlInitUnicodeString(&UnicodeString, L"SystemPartition"); 815 Status = NtQueryValueKey(KeyHandle, 816 &UnicodeString, 817 KeyValuePartialInformation, 818 PartialInfo, 819 sizeof(ValueBuffer), 820 &Length); 821 NtClose(KeyHandle); 822 if (!NT_SUCCESS(Status)) 823 { 824 DPRINT1("SMSS: can't query SystemPartition value: 0x%x\n", Status); 825 return; 826 } 827 828 /* Initialize the system partition string string */ 829 RtlInitUnicodeString(&SystemPartition, (PWCHAR)PartialInfo->Data); 830 831 /* Enumerate the directory looking for the symbolic link string */ 832 RtlInitUnicodeString(&SearchString, L"SymbolicLink"); 833 RtlInitEmptyUnicodeString(&LinkTarget, LinkBuffer, sizeof(LinkBuffer)); 834 Status = NtQueryDirectoryObject(SmpDosDevicesObjectDirectory, 835 DirInfo, 836 sizeof(DirInfoBuffer), 837 TRUE, 838 TRUE, 839 &Context, 840 NULL); 841 if (!NT_SUCCESS(Status)) 842 { 843 DPRINT1("SMSS: can't find drive letter for system partition\n"); 844 return; 845 } 846 847 /* Keep searching until we find it */ 848 do 849 { 850 /* Is this it? */ 851 if ((RtlEqualUnicodeString(&DirInfo->TypeName, &SearchString, TRUE)) && 852 (DirInfo->Name.Length == 2 * sizeof(WCHAR)) && 853 (DirInfo->Name.Buffer[1] == L':')) 854 { 855 /* Looks like we found it, open the link to get its target */ 856 InitializeObjectAttributes(&ObjectAttributes, 857 &DirInfo->Name, 858 OBJ_CASE_INSENSITIVE, 859 SmpDosDevicesObjectDirectory, 860 NULL); 861 Status = NtOpenSymbolicLinkObject(&LinkHandle, 862 SYMBOLIC_LINK_ALL_ACCESS, 863 &ObjectAttributes); 864 if (NT_SUCCESS(Status)) 865 { 866 /* Open worked, query the target now */ 867 Status = NtQuerySymbolicLinkObject(LinkHandle, 868 &LinkTarget, 869 NULL); 870 NtClose(LinkHandle); 871 872 /* Check if it matches the string we had found earlier */ 873 if ((NT_SUCCESS(Status)) && 874 ((RtlEqualUnicodeString(&SystemPartition, 875 &LinkTarget, 876 TRUE)) || 877 ((RtlPrefixUnicodeString(&SystemPartition, 878 &LinkTarget, 879 TRUE)) && 880 (LinkTarget.Buffer[SystemPartition.Length / sizeof(WCHAR)] == L'\\')))) 881 { 882 /* All done */ 883 break; 884 } 885 } 886 } 887 888 /* Couldn't find it, try again */ 889 Status = NtQueryDirectoryObject(SmpDosDevicesObjectDirectory, 890 DirInfo, 891 sizeof(DirInfoBuffer), 892 TRUE, 893 FALSE, 894 &Context, 895 NULL); 896 } while (NT_SUCCESS(Status)); 897 if (!NT_SUCCESS(Status)) 898 { 899 DPRINT1("SMSS: can't find drive letter for system partition\n"); 900 return; 901 } 902 903 /* Open the setup key again, for full access this time */ 904 RtlInitUnicodeString(&UnicodeString, 905 L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup"); 906 InitializeObjectAttributes(&ObjectAttributes, 907 &UnicodeString, 908 OBJ_CASE_INSENSITIVE, 909 NULL, 910 NULL); 911 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes); 912 if (!NT_SUCCESS(Status)) 913 { 914 DPRINT1("SMSS: can't open software setup key for writing: 0x%x\n", 915 Status); 916 return; 917 } 918 919 /* Wrap up the end of the link buffer */ 920 wcsncpy(LinkBuffer, DirInfo->Name.Buffer, 2); 921 LinkBuffer[2] = L'\\'; 922 LinkBuffer[3] = L'\0'; 923 924 /* Now set this as the "BootDir" */ 925 RtlInitUnicodeString(&UnicodeString, L"BootDir"); 926 Status = NtSetValueKey(KeyHandle, 927 &UnicodeString, 928 0, 929 REG_SZ, 930 LinkBuffer, 931 4 * sizeof(WCHAR)); 932 if (!NT_SUCCESS(Status)) 933 { 934 DPRINT1("SMSS: couldn't write BootDir value: 0x%x\n", Status); 935 } 936 NtClose(KeyHandle); 937 } 938 939 NTSTATUS 940 NTAPI 941 SmpCreateSecurityDescriptors(IN BOOLEAN InitialCall) 942 { 943 NTSTATUS Status; 944 PSID WorldSid = NULL, AdminSid = NULL, SystemSid = NULL; 945 PSID RestrictedSid = NULL, OwnerSid = NULL; 946 SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY}; 947 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; 948 SID_IDENTIFIER_AUTHORITY CreatorAuthority = {SECURITY_CREATOR_SID_AUTHORITY}; 949 ULONG AclLength, SidLength; 950 PACL Acl; 951 PACE_HEADER Ace; 952 BOOLEAN ProtectionRequired = FALSE; 953 954 /* Check if this is the first call */ 955 if (InitialCall) 956 { 957 /* Create and set the primary descriptor */ 958 SmpPrimarySecurityDescriptor = &SmpPrimarySDBody; 959 Status = RtlCreateSecurityDescriptor(SmpPrimarySecurityDescriptor, 960 SECURITY_DESCRIPTOR_REVISION); 961 ASSERT(NT_SUCCESS(Status)); 962 Status = RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor, 963 TRUE, 964 NULL, 965 FALSE); 966 ASSERT(NT_SUCCESS(Status)); 967 968 /* Create and set the liberal descriptor */ 969 SmpLiberalSecurityDescriptor = &SmpLiberalSDBody; 970 Status = RtlCreateSecurityDescriptor(SmpLiberalSecurityDescriptor, 971 SECURITY_DESCRIPTOR_REVISION); 972 ASSERT(NT_SUCCESS(Status)); 973 Status = RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor, 974 TRUE, 975 NULL, 976 FALSE); 977 ASSERT(NT_SUCCESS(Status)); 978 979 /* Create and set the \KnownDlls descriptor */ 980 SmpKnownDllsSecurityDescriptor = &SmpKnownDllsSDBody; 981 Status = RtlCreateSecurityDescriptor(SmpKnownDllsSecurityDescriptor, 982 SECURITY_DESCRIPTOR_REVISION); 983 ASSERT(NT_SUCCESS(Status)); 984 Status = RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor, 985 TRUE, 986 NULL, 987 FALSE); 988 ASSERT(NT_SUCCESS(Status)); 989 990 /* Create and Set the \ApiPort descriptor */ 991 SmpApiPortSecurityDescriptor = &SmpApiPortSDBody; 992 Status = RtlCreateSecurityDescriptor(SmpApiPortSecurityDescriptor, 993 SECURITY_DESCRIPTOR_REVISION); 994 ASSERT(NT_SUCCESS(Status)); 995 Status = RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor, 996 TRUE, 997 NULL, 998 FALSE); 999 ASSERT(NT_SUCCESS(Status)); 1000 } 1001 1002 /* Check if protection was requested in the registry (on by default) */ 1003 if (SmpProtectionMode & 1) ProtectionRequired = TRUE; 1004 1005 /* Exit if there's nothing to do */ 1006 if (!(InitialCall || ProtectionRequired)) return STATUS_SUCCESS; 1007 1008 /* Build the world SID */ 1009 Status = RtlAllocateAndInitializeSid(&WorldAuthority, 1, 1010 SECURITY_WORLD_RID, 1011 0, 0, 0, 0, 0, 0, 0, 1012 &WorldSid); 1013 if (!NT_SUCCESS(Status)) 1014 { 1015 WorldSid = NULL; 1016 goto Quickie; 1017 } 1018 1019 /* Build the admin SID */ 1020 Status = RtlAllocateAndInitializeSid(&NtAuthority, 2, 1021 SECURITY_BUILTIN_DOMAIN_RID, 1022 DOMAIN_ALIAS_RID_ADMINS, 1023 0, 0, 0, 0, 0, 0, 1024 &AdminSid); 1025 if (!NT_SUCCESS(Status)) 1026 { 1027 AdminSid = NULL; 1028 goto Quickie; 1029 } 1030 1031 /* Build the owner SID */ 1032 Status = RtlAllocateAndInitializeSid(&CreatorAuthority, 1, 1033 SECURITY_CREATOR_OWNER_RID, 1034 0, 0, 0, 0, 0, 0, 0, 1035 &OwnerSid); 1036 if (!NT_SUCCESS(Status)) 1037 { 1038 OwnerSid = NULL; 1039 goto Quickie; 1040 } 1041 1042 /* Build the restricted SID */ 1043 Status = RtlAllocateAndInitializeSid(&NtAuthority, 1, 1044 SECURITY_RESTRICTED_CODE_RID, 1045 0, 0, 0, 0, 0, 0, 0, 1046 &RestrictedSid); 1047 if (!NT_SUCCESS(Status)) 1048 { 1049 RestrictedSid = NULL; 1050 goto Quickie; 1051 } 1052 1053 /* Build the system SID */ 1054 Status = RtlAllocateAndInitializeSid(&NtAuthority, 1, 1055 SECURITY_LOCAL_SYSTEM_RID, 1056 0, 0, 0, 0, 0, 0, 0, 1057 &SystemSid); 1058 if (!NT_SUCCESS(Status)) 1059 { 1060 SystemSid = NULL; 1061 goto Quickie; 1062 } 1063 1064 /* Now check if we're creating the core descriptors */ 1065 if (!InitialCall) 1066 { 1067 /* We're skipping NextAcl so we have to do this here */ 1068 SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(RestrictedSid) + RtlLengthSid(AdminSid); 1069 SidLength *= 2; 1070 goto NotInitial; 1071 } 1072 1073 /* Allocate an ACL with two ACEs with two SIDs each */ 1074 SidLength = RtlLengthSid(SystemSid) + RtlLengthSid(AdminSid); 1075 AclLength = sizeof(ACL) + 2 * sizeof(ACCESS_ALLOWED_ACE) + SidLength; 1076 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength); 1077 if (!Acl) Status = STATUS_NO_MEMORY; 1078 if (!NT_SUCCESS(Status)) goto NextAcl; 1079 1080 /* Now build the ACL and add the two ACEs */ 1081 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2); 1082 ASSERT(NT_SUCCESS(Status)); 1083 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1084 ASSERT(NT_SUCCESS(Status)); 1085 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, SystemSid); 1086 ASSERT(NT_SUCCESS(Status)); 1087 1088 /* Set this as the DACL */ 1089 Status = RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor, 1090 TRUE, 1091 Acl, 1092 FALSE); 1093 ASSERT(NT_SUCCESS(Status)); 1094 1095 NextAcl: 1096 /* Allocate an ACL with 6 ACEs, two ACEs per SID */ 1097 SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(RestrictedSid) + RtlLengthSid(AdminSid); 1098 SidLength *= 2; 1099 AclLength = sizeof(ACL) + 6 * sizeof(ACCESS_ALLOWED_ACE) + SidLength; 1100 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength); 1101 if (!Acl) Status = STATUS_NO_MEMORY; 1102 if (!NT_SUCCESS(Status)) goto NotInitial; 1103 1104 /* Now build the ACL and add the six ACEs */ 1105 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2); 1106 ASSERT(NT_SUCCESS(Status)); 1107 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE, WorldSid); 1108 ASSERT(NT_SUCCESS(Status)); 1109 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE, RestrictedSid); 1110 ASSERT(NT_SUCCESS(Status)); 1111 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1112 ASSERT(NT_SUCCESS(Status)); 1113 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid); 1114 ASSERT(NT_SUCCESS(Status)); 1115 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid); 1116 ASSERT(NT_SUCCESS(Status)); 1117 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1118 ASSERT(NT_SUCCESS(Status)); 1119 1120 /* Now edit the last three ACEs and make them inheritable */ 1121 Status = RtlGetAce(Acl, 3, (PVOID)&Ace); 1122 ASSERT(NT_SUCCESS(Status)); 1123 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1124 Status = RtlGetAce(Acl, 4, (PVOID)&Ace); 1125 ASSERT(NT_SUCCESS(Status)); 1126 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1127 Status = RtlGetAce(Acl, 5, (PVOID)&Ace); 1128 ASSERT(NT_SUCCESS(Status)); 1129 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1130 1131 /* Set this as the DACL */ 1132 Status = RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor, 1133 TRUE, 1134 Acl, 1135 FALSE); 1136 ASSERT(NT_SUCCESS(Status)); 1137 1138 NotInitial: 1139 /* The initial ACLs have been created, are we also protecting objects? */ 1140 if (!ProtectionRequired) goto Quickie; 1141 1142 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */ 1143 SidLength += RtlLengthSid(OwnerSid); 1144 AclLength = sizeof(ACL) + 7 * sizeof (ACCESS_ALLOWED_ACE) + 2 * SidLength; 1145 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength); 1146 if (!Acl) Status = STATUS_NO_MEMORY; 1147 if (!NT_SUCCESS(Status)) goto Quickie; 1148 1149 /* Build the ACL and add the seven ACEs */ 1150 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2); 1151 ASSERT(NT_SUCCESS(Status)); 1152 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, WorldSid); 1153 ASSERT(NT_SUCCESS(Status)); 1154 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, RestrictedSid); 1155 ASSERT(NT_SUCCESS(Status)); 1156 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1157 ASSERT(NT_SUCCESS(Status)); 1158 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, WorldSid); 1159 ASSERT(NT_SUCCESS(Status)); 1160 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, RestrictedSid); 1161 ASSERT(NT_SUCCESS(Status)); 1162 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1163 ASSERT(NT_SUCCESS(Status)); 1164 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, OwnerSid); 1165 ASSERT(NT_SUCCESS(Status)); 1166 1167 /* Edit the last 4 ACEs to make then inheritable */ 1168 Status = RtlGetAce(Acl, 3, (PVOID)&Ace); 1169 ASSERT(NT_SUCCESS(Status)); 1170 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1171 Status = RtlGetAce(Acl, 4, (PVOID)&Ace); 1172 ASSERT(NT_SUCCESS(Status)); 1173 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1174 Status = RtlGetAce(Acl, 5, (PVOID)&Ace); 1175 ASSERT(NT_SUCCESS(Status)); 1176 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1177 Status = RtlGetAce(Acl, 6, (PVOID)&Ace); 1178 ASSERT(NT_SUCCESS(Status)); 1179 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1180 1181 /* Set this as the DACL for the primary SD */ 1182 Status = RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor, 1183 TRUE, 1184 Acl, 1185 FALSE); 1186 ASSERT(NT_SUCCESS(Status)); 1187 1188 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */ 1189 AclLength = sizeof(ACL) + 7 * sizeof (ACCESS_ALLOWED_ACE) + 2 * SidLength; 1190 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength); 1191 if (!Acl) Status = STATUS_NO_MEMORY; 1192 if (!NT_SUCCESS(Status)) goto Quickie; 1193 1194 /* Build the ACL and add the seven ACEs */ 1195 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2); 1196 ASSERT(NT_SUCCESS(Status)); 1197 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid); 1198 ASSERT(NT_SUCCESS(Status)); 1199 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid); 1200 ASSERT(NT_SUCCESS(Status)); 1201 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1202 ASSERT(NT_SUCCESS(Status)); 1203 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid); 1204 ASSERT(NT_SUCCESS(Status)); 1205 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid); 1206 ASSERT(NT_SUCCESS(Status)); 1207 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid); 1208 ASSERT(NT_SUCCESS(Status)); 1209 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, OwnerSid); 1210 ASSERT(NT_SUCCESS(Status)); 1211 1212 /* Edit the last 4 ACEs to make then inheritable */ 1213 Status = RtlGetAce(Acl, 3, (PVOID)&Ace); 1214 ASSERT(NT_SUCCESS(Status)); 1215 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1216 Status = RtlGetAce(Acl, 4, (PVOID)&Ace); 1217 ASSERT(NT_SUCCESS(Status)); 1218 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1219 Status = RtlGetAce(Acl, 5, (PVOID)&Ace); 1220 ASSERT(NT_SUCCESS(Status)); 1221 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1222 Status = RtlGetAce(Acl, 6, (PVOID)&Ace); 1223 ASSERT(NT_SUCCESS(Status)); 1224 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; 1225 1226 /* Now set this as the DACL for the liberal SD */ 1227 Status = RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor, 1228 TRUE, 1229 Acl, 1230 FALSE); 1231 ASSERT(NT_SUCCESS(Status)); 1232 1233 Quickie: 1234 /* Cleanup the SIDs */ 1235 if (OwnerSid) RtlFreeHeap(RtlGetProcessHeap(), 0, OwnerSid); 1236 if (AdminSid) RtlFreeHeap(RtlGetProcessHeap(), 0, AdminSid); 1237 if (WorldSid) RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid); 1238 if (SystemSid) RtlFreeHeap(RtlGetProcessHeap(), 0, SystemSid); 1239 if (RestrictedSid) RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSid); 1240 return Status; 1241 } 1242 1243 NTSTATUS 1244 NTAPI 1245 SmpInitializeDosDevices(VOID) 1246 { 1247 NTSTATUS Status; 1248 PSMP_REGISTRY_VALUE RegEntry; 1249 SECURITY_DESCRIPTOR_CONTROL OldFlag = 0; 1250 OBJECT_ATTRIBUTES ObjectAttributes; 1251 UNICODE_STRING DestinationString; 1252 HANDLE DirHandle; 1253 PLIST_ENTRY NextEntry, Head; 1254 1255 /* Open the GLOBAL?? directory */ 1256 RtlInitUnicodeString(&DestinationString, L"\\??"); 1257 InitializeObjectAttributes(&ObjectAttributes, 1258 &DestinationString, 1259 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, 1260 NULL, 1261 NULL); 1262 Status = NtOpenDirectoryObject(&SmpDosDevicesObjectDirectory, 1263 DIRECTORY_ALL_ACCESS, 1264 &ObjectAttributes); 1265 if (!NT_SUCCESS(Status)) 1266 { 1267 DPRINT1("SMSS: Unable to open %wZ directory - Status == %lx\n", 1268 &DestinationString, Status); 1269 return Status; 1270 } 1271 1272 /* Loop the DOS devices */ 1273 Head = &SmpDosDevicesList; 1274 while (!IsListEmpty(Head)) 1275 { 1276 /* Get the entry and remove it */ 1277 NextEntry = RemoveHeadList(Head); 1278 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 1279 1280 /* Initialize the attributes, and see which descriptor is being used */ 1281 InitializeObjectAttributes(&ObjectAttributes, 1282 &RegEntry->Name, 1283 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, 1284 SmpDosDevicesObjectDirectory, 1285 SmpPrimarySecurityDescriptor); 1286 if (SmpPrimarySecurityDescriptor) 1287 { 1288 /* Save the old flag and set it while we create this link */ 1289 OldFlag = SmpPrimarySecurityDescriptor->Control; 1290 SmpPrimarySecurityDescriptor->Control |= SE_DACL_DEFAULTED; 1291 } 1292 1293 /* Create the symbolic link */ 1294 DPRINT("Creating symlink for %wZ to %wZ\n", &RegEntry->Name, &RegEntry->Value); 1295 Status = NtCreateSymbolicLinkObject(&DirHandle, 1296 SYMBOLIC_LINK_ALL_ACCESS, 1297 &ObjectAttributes, 1298 &RegEntry->Value); 1299 if (Status == STATUS_OBJECT_NAME_EXISTS) 1300 { 1301 /* Make it temporary and get rid of the handle */ 1302 NtMakeTemporaryObject(DirHandle); 1303 NtClose(DirHandle); 1304 1305 /* Treat this as success, and see if we got a name back */ 1306 Status = STATUS_SUCCESS; 1307 if (RegEntry->Value.Length) 1308 { 1309 /* Create it now with this name */ 1310 ObjectAttributes.Attributes &= ~OBJ_OPENIF; 1311 Status = NtCreateSymbolicLinkObject(&DirHandle, 1312 SYMBOLIC_LINK_ALL_ACCESS, 1313 &ObjectAttributes, 1314 &RegEntry->Value); 1315 } 1316 } 1317 1318 /* If we were using a security descriptor, restore the non-defaulted flag */ 1319 if (ObjectAttributes.SecurityDescriptor) 1320 { 1321 SmpPrimarySecurityDescriptor->Control = OldFlag; 1322 } 1323 1324 /* Print a failure if we failed to create the symbolic link */ 1325 if (!NT_SUCCESS(Status)) 1326 { 1327 DPRINT1("SMSS: Unable to create %wZ => %wZ symbolic link object - Status == 0x%lx\n", 1328 &RegEntry->Name, 1329 &RegEntry->Value, 1330 Status); 1331 break; 1332 } 1333 1334 /* Close the handle */ 1335 NtClose(DirHandle); 1336 1337 /* Free this entry */ 1338 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue); 1339 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer); 1340 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry); 1341 } 1342 1343 /* Return the status */ 1344 return Status; 1345 } 1346 1347 VOID 1348 NTAPI 1349 SmpProcessModuleImports(IN PVOID Unused, 1350 IN PCHAR ImportName) 1351 { 1352 ULONG Length = 0, Chars; 1353 WCHAR Buffer[MAX_PATH]; 1354 PWCHAR DllName, DllValue; 1355 ANSI_STRING ImportString; 1356 UNICODE_STRING ImportUnicodeString; 1357 NTSTATUS Status; 1358 1359 /* Skip NTDLL since it's already always mapped */ 1360 if (!_stricmp(ImportName, "ntdll.dll")) return; 1361 1362 /* Initialize our strings */ 1363 RtlInitAnsiString(&ImportString, ImportName); 1364 RtlInitEmptyUnicodeString(&ImportUnicodeString, Buffer, sizeof(Buffer)); 1365 Status = RtlAnsiStringToUnicodeString(&ImportUnicodeString, &ImportString, FALSE); 1366 if (!NT_SUCCESS(Status)) return; 1367 1368 /* Loop in case we find a forwarder */ 1369 ImportUnicodeString.MaximumLength = ImportUnicodeString.Length + sizeof(UNICODE_NULL); 1370 while (Length < ImportUnicodeString.Length) 1371 { 1372 if (ImportUnicodeString.Buffer[Length / sizeof(WCHAR)] == L'.') break; 1373 Length += sizeof(WCHAR); 1374 } 1375 1376 /* Break up the values as needed */ 1377 DllValue = ImportUnicodeString.Buffer; 1378 DllName = &ImportUnicodeString.Buffer[ImportUnicodeString.MaximumLength / sizeof(WCHAR)]; 1379 Chars = Length >> 1; 1380 wcsncpy(DllName, ImportUnicodeString.Buffer, Chars); 1381 DllName[Chars] = 0; 1382 1383 /* Add the DLL to the list */ 1384 SmpSaveRegistryValue(&SmpKnownDllsList, DllName, DllValue, TRUE); 1385 } 1386 1387 NTSTATUS 1388 NTAPI 1389 SmpInitializeKnownDllsInternal(IN PUNICODE_STRING Directory, 1390 IN PUNICODE_STRING Path) 1391 { 1392 HANDLE DirFileHandle, DirHandle, SectionHandle, FileHandle, LinkHandle; 1393 UNICODE_STRING NtPath, DestinationString; 1394 OBJECT_ATTRIBUTES ObjectAttributes; 1395 NTSTATUS Status, Status1; 1396 PLIST_ENTRY NextEntry; 1397 PSMP_REGISTRY_VALUE RegEntry; 1398 ULONG_PTR ErrorParameters[3]; 1399 UNICODE_STRING ErrorResponse; 1400 IO_STATUS_BLOCK IoStatusBlock; 1401 SECURITY_DESCRIPTOR_CONTROL OldFlag = 0; 1402 USHORT ImageCharacteristics; 1403 1404 /* Initialize to NULL */ 1405 DirFileHandle = NULL; 1406 DirHandle = NULL; 1407 NtPath.Buffer = NULL; 1408 1409 /* Create the \KnownDLLs directory */ 1410 InitializeObjectAttributes(&ObjectAttributes, 1411 Directory, 1412 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, 1413 NULL, 1414 SmpKnownDllsSecurityDescriptor); 1415 Status = NtCreateDirectoryObject(&DirHandle, 1416 DIRECTORY_ALL_ACCESS, 1417 &ObjectAttributes); 1418 if (!NT_SUCCESS(Status)) 1419 { 1420 /* Handle failure */ 1421 DPRINT1("SMSS: Unable to create %wZ directory - Status == %lx\n", 1422 Directory, Status); 1423 return Status; 1424 } 1425 1426 /* Convert the path to native format */ 1427 if (!RtlDosPathNameToNtPathName_U(Path->Buffer, &NtPath, NULL, NULL)) 1428 { 1429 /* Fail if this didn't work */ 1430 DPRINT1("SMSS: Unable to to convert %wZ to an Nt path\n", Path); 1431 Status = STATUS_OBJECT_NAME_INVALID; 1432 goto Quickie; 1433 } 1434 1435 /* Open the path that was specified, which should be a directory */ 1436 InitializeObjectAttributes(&ObjectAttributes, 1437 &NtPath, 1438 OBJ_CASE_INSENSITIVE, 1439 NULL, 1440 NULL); 1441 Status = NtOpenFile(&DirFileHandle, 1442 FILE_LIST_DIRECTORY | SYNCHRONIZE, 1443 &ObjectAttributes, 1444 &IoStatusBlock, 1445 FILE_SHARE_READ | FILE_SHARE_WRITE, 1446 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 1447 if (!NT_SUCCESS(Status)) 1448 { 1449 /* Fail if we couldn't open it */ 1450 DPRINT1("SMSS: Unable to open a handle to the KnownDll directory (%wZ)" 1451 "- Status == %lx\n", 1452 Path, 1453 Status); 1454 FileHandle = NULL; 1455 goto Quickie; 1456 } 1457 1458 /* Temporarily hack the SD to use a default DACL for this symbolic link */ 1459 if (SmpPrimarySecurityDescriptor) 1460 { 1461 OldFlag = SmpPrimarySecurityDescriptor->Control; 1462 SmpPrimarySecurityDescriptor->Control |= SE_DACL_DEFAULTED; 1463 } 1464 1465 /* Create a symbolic link to the directory in the object manager */ 1466 RtlInitUnicodeString(&DestinationString, L"KnownDllPath"); 1467 InitializeObjectAttributes(&ObjectAttributes, 1468 &DestinationString, 1469 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, 1470 DirHandle, 1471 SmpPrimarySecurityDescriptor); 1472 Status = NtCreateSymbolicLinkObject(&LinkHandle, 1473 SYMBOLIC_LINK_ALL_ACCESS, 1474 &ObjectAttributes, 1475 Path); 1476 1477 /* Undo the hack */ 1478 if (SmpPrimarySecurityDescriptor) SmpPrimarySecurityDescriptor->Control = OldFlag; 1479 1480 /* Check if the symlink was created */ 1481 if (!NT_SUCCESS(Status)) 1482 { 1483 /* It wasn't, so bail out since the OS needs it to exist */ 1484 DPRINT1("SMSS: Unable to create %wZ symbolic link - Status == %lx\n", 1485 &DestinationString, Status); 1486 LinkHandle = NULL; 1487 goto Quickie; 1488 } 1489 1490 /* We created it permanent, we can go ahead and close the handle now */ 1491 Status1 = NtClose(LinkHandle); 1492 ASSERT(NT_SUCCESS(Status1)); 1493 1494 /* Now loop the known DLLs */ 1495 NextEntry = SmpKnownDllsList.Flink; 1496 while (NextEntry != &SmpKnownDllsList) 1497 { 1498 /* Get the entry and move on */ 1499 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 1500 NextEntry = NextEntry->Flink; 1501 1502 DPRINT("Processing known DLL: %wZ-%wZ\n", &RegEntry->Name, &RegEntry->Value); 1503 1504 /* Skip the entry if it's in the excluded list */ 1505 if ((SmpFindRegistryValue(&SmpExcludeKnownDllsList, 1506 RegEntry->Name.Buffer)) || 1507 (SmpFindRegistryValue(&SmpExcludeKnownDllsList, 1508 RegEntry->Value.Buffer))) 1509 { 1510 continue; 1511 } 1512 1513 /* Open the actual file */ 1514 InitializeObjectAttributes(&ObjectAttributes, 1515 &RegEntry->Value, 1516 OBJ_CASE_INSENSITIVE, 1517 DirFileHandle, 1518 NULL); 1519 Status1 = NtOpenFile(&FileHandle, 1520 SYNCHRONIZE | FILE_EXECUTE, 1521 &ObjectAttributes, 1522 &IoStatusBlock, 1523 FILE_SHARE_READ | FILE_SHARE_DELETE, 1524 FILE_NON_DIRECTORY_FILE | 1525 FILE_SYNCHRONOUS_IO_NONALERT); 1526 /* If we failed, skip it */ 1527 if (!NT_SUCCESS(Status1)) continue; 1528 1529 /* Checksum it */ 1530 Status = LdrVerifyImageMatchesChecksum((HANDLE)((ULONG_PTR)FileHandle | 1), 1531 SmpProcessModuleImports, 1532 RegEntry, 1533 &ImageCharacteristics); 1534 if (!NT_SUCCESS(Status)) 1535 { 1536 /* Checksum failed, so don't even try going further -- kill SMSS */ 1537 RtlInitUnicodeString(&ErrorResponse, 1538 L"Verification of a KnownDLL failed."); 1539 ErrorParameters[0] = (ULONG_PTR)&ErrorResponse; 1540 ErrorParameters[1] = Status; 1541 ErrorParameters[2] = (ULONG_PTR)&RegEntry->Value; 1542 SmpTerminate(ErrorParameters, 5, RTL_NUMBER_OF(ErrorParameters)); 1543 } 1544 else if (!(ImageCharacteristics & IMAGE_FILE_DLL)) 1545 { 1546 /* An invalid known DLL entry will also kill SMSS */ 1547 RtlInitUnicodeString(&ErrorResponse, 1548 L"Non-DLL file included in KnownDLL list."); 1549 ErrorParameters[0] = (ULONG_PTR)&ErrorResponse; 1550 ErrorParameters[1] = STATUS_INVALID_IMPORT_OF_NON_DLL; 1551 ErrorParameters[2] = (ULONG_PTR)&RegEntry->Value; 1552 SmpTerminate(ErrorParameters, 5, RTL_NUMBER_OF(ErrorParameters)); 1553 } 1554 1555 /* Temporarily hack the SD to use a default DACL for this section */ 1556 if (SmpLiberalSecurityDescriptor) 1557 { 1558 OldFlag = SmpLiberalSecurityDescriptor->Control; 1559 SmpLiberalSecurityDescriptor->Control |= SE_DACL_DEFAULTED; 1560 } 1561 1562 /* Create the section for this known DLL */ 1563 InitializeObjectAttributes(&ObjectAttributes, 1564 &RegEntry->Value, 1565 OBJ_PERMANENT, 1566 DirHandle, 1567 SmpLiberalSecurityDescriptor) 1568 Status = NtCreateSection(&SectionHandle, 1569 SECTION_ALL_ACCESS, 1570 &ObjectAttributes, 1571 0, 1572 PAGE_EXECUTE, 1573 SEC_IMAGE, 1574 FileHandle); 1575 1576 /* Undo the hack */ 1577 if (SmpLiberalSecurityDescriptor) SmpLiberalSecurityDescriptor->Control = OldFlag; 1578 1579 /* Check if we created the section okay */ 1580 if (NT_SUCCESS(Status)) 1581 { 1582 /* We can close it now, since it's marked permanent */ 1583 Status1 = NtClose(SectionHandle); 1584 ASSERT(NT_SUCCESS(Status1)); 1585 } 1586 else 1587 { 1588 /* If we couldn't make it "known", that's fine and keep going */ 1589 DPRINT1("SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n", 1590 &RegEntry->Value, Status); 1591 } 1592 1593 /* Close the file since we can move on to the next one */ 1594 Status1 = NtClose(FileHandle); 1595 ASSERT(NT_SUCCESS(Status1)); 1596 } 1597 1598 Quickie: 1599 /* Close both handles and free the NT path buffer */ 1600 if (DirHandle) 1601 { 1602 Status1 = NtClose(DirHandle); 1603 ASSERT(NT_SUCCESS(Status1)); 1604 } 1605 if (DirFileHandle) 1606 { 1607 Status1 = NtClose(DirFileHandle); 1608 ASSERT(NT_SUCCESS(Status1)); 1609 } 1610 if (NtPath.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath.Buffer); 1611 return Status; 1612 } 1613 1614 NTSTATUS 1615 NTAPI 1616 SmpInitializeKnownDlls(VOID) 1617 { 1618 NTSTATUS Status; 1619 PSMP_REGISTRY_VALUE RegEntry; 1620 UNICODE_STRING DestinationString; 1621 PLIST_ENTRY Head, NextEntry; 1622 1623 /* Call the internal function */ 1624 RtlInitUnicodeString(&DestinationString, L"\\KnownDlls"); 1625 Status = SmpInitializeKnownDllsInternal(&DestinationString, &SmpKnownDllPath); 1626 1627 /* Wipe out the list regardless of success */ 1628 Head = &SmpKnownDllsList; 1629 while (!IsListEmpty(Head)) 1630 { 1631 /* Remove this entry */ 1632 NextEntry = RemoveHeadList(Head); 1633 1634 /* Free it */ 1635 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 1636 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue); 1637 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer); 1638 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry); 1639 } 1640 1641 /* All done */ 1642 return Status; 1643 } 1644 1645 NTSTATUS 1646 NTAPI 1647 SmpCreateDynamicEnvironmentVariables(VOID) 1648 { 1649 NTSTATUS Status; 1650 SYSTEM_BASIC_INFORMATION BasicInfo; 1651 SYSTEM_PROCESSOR_INFORMATION ProcessorInfo; 1652 OBJECT_ATTRIBUTES ObjectAttributes; 1653 UNICODE_STRING ValueName, DestinationString; 1654 HANDLE KeyHandle, KeyHandle2; 1655 ULONG ResultLength; 1656 PWCHAR ValueData; 1657 WCHAR ValueBuffer[512], ValueBuffer2[512]; 1658 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer; 1659 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo2 = (PVOID)ValueBuffer2; 1660 1661 /* Get system basic information -- we'll need the CPU count */ 1662 Status = NtQuerySystemInformation(SystemBasicInformation, 1663 &BasicInfo, 1664 sizeof(BasicInfo), 1665 NULL); 1666 if (!NT_SUCCESS(Status)) 1667 { 1668 /* Bail out on failure */ 1669 DPRINT1("SMSS: Unable to query system basic information - %x\n", Status); 1670 return Status; 1671 } 1672 1673 /* Get the processor information, we'll query a bunch of revision info */ 1674 Status = NtQuerySystemInformation(SystemProcessorInformation, 1675 &ProcessorInfo, 1676 sizeof(ProcessorInfo), 1677 NULL); 1678 if (!NT_SUCCESS(Status)) 1679 { 1680 /* Bail out on failure */ 1681 DPRINT1("SMSS: Unable to query system processor information - %x\n", Status); 1682 return Status; 1683 } 1684 1685 /* We'll be writing all these environment variables over here */ 1686 RtlInitUnicodeString(&DestinationString, 1687 L"\\Registry\\Machine\\System\\CurrentControlSet\\" 1688 L"Control\\Session Manager\\Environment"); 1689 InitializeObjectAttributes(&ObjectAttributes, 1690 &DestinationString, 1691 OBJ_CASE_INSENSITIVE, 1692 NULL, 1693 NULL); 1694 Status = NtOpenKey(&KeyHandle, GENERIC_WRITE, &ObjectAttributes); 1695 if (!NT_SUCCESS(Status)) 1696 { 1697 /* Bail out on failure */ 1698 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString, Status); 1699 return Status; 1700 } 1701 1702 /* First let's write the OS variable */ 1703 RtlInitUnicodeString(&ValueName, L"OS"); 1704 ValueData = L"Windows_NT"; 1705 DPRINT("Setting %wZ to %S\n", &ValueName, ValueData); 1706 Status = NtSetValueKey(KeyHandle, 1707 &ValueName, 1708 0, 1709 REG_SZ, 1710 ValueData, 1711 (wcslen(ValueData) + 1) * sizeof(WCHAR)); 1712 if (!NT_SUCCESS(Status)) 1713 { 1714 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n", 1715 &ValueName, Status); 1716 NtClose(KeyHandle); 1717 return Status; 1718 } 1719 1720 /* Next, let's write the CPU architecture variable */ 1721 RtlInitUnicodeString(&ValueName, L"PROCESSOR_ARCHITECTURE"); 1722 switch (ProcessorInfo.ProcessorArchitecture) 1723 { 1724 /* Pick the correct string that matches the architecture */ 1725 case PROCESSOR_ARCHITECTURE_INTEL: 1726 ValueData = L"x86"; 1727 break; 1728 1729 case PROCESSOR_ARCHITECTURE_AMD64: 1730 ValueData = L"AMD64"; 1731 break; 1732 1733 case PROCESSOR_ARCHITECTURE_IA64: 1734 ValueData = L"IA64"; 1735 break; 1736 1737 default: 1738 ValueData = L"Unknown"; 1739 break; 1740 } 1741 1742 /* Set it */ 1743 DPRINT("Setting %wZ to %S\n", &ValueName, ValueData); 1744 Status = NtSetValueKey(KeyHandle, 1745 &ValueName, 1746 0, 1747 REG_SZ, 1748 ValueData, 1749 (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 /* And now let's write the processor level */ 1759 RtlInitUnicodeString(&ValueName, L"PROCESSOR_LEVEL"); 1760 swprintf(ValueBuffer, L"%u", ProcessorInfo.ProcessorLevel); 1761 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer); 1762 Status = NtSetValueKey(KeyHandle, 1763 &ValueName, 1764 0, 1765 REG_SZ, 1766 ValueBuffer, 1767 (wcslen(ValueBuffer) + 1) * sizeof(WCHAR)); 1768 if (!NT_SUCCESS(Status)) 1769 { 1770 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n", 1771 &ValueName, Status); 1772 NtClose(KeyHandle); 1773 return Status; 1774 } 1775 1776 /* Now open the hardware CPU key */ 1777 RtlInitUnicodeString(&DestinationString, 1778 L"\\Registry\\Machine\\Hardware\\Description\\System\\" 1779 L"CentralProcessor\\0"); 1780 InitializeObjectAttributes(&ObjectAttributes, 1781 &DestinationString, 1782 OBJ_CASE_INSENSITIVE, 1783 NULL, 1784 NULL); 1785 Status = NtOpenKey(&KeyHandle2, KEY_READ, &ObjectAttributes); 1786 if (!NT_SUCCESS(Status)) 1787 { 1788 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString, Status); 1789 NtClose(KeyHandle); 1790 return Status; 1791 } 1792 1793 /* So that we can read the identifier out of it... */ 1794 RtlInitUnicodeString(&ValueName, L"Identifier"); 1795 Status = NtQueryValueKey(KeyHandle2, 1796 &ValueName, 1797 KeyValuePartialInformation, 1798 PartialInfo, 1799 sizeof(ValueBuffer), 1800 &ResultLength); 1801 if (!NT_SUCCESS(Status)) 1802 { 1803 NtClose(KeyHandle2); 1804 NtClose(KeyHandle); 1805 DPRINT1("SMSS: Unable to read %wZ\\%wZ - %x\n", 1806 &DestinationString, &ValueName, Status); 1807 return Status; 1808 } 1809 1810 /* As well as the vendor... */ 1811 RtlInitUnicodeString(&ValueName, L"VendorIdentifier"); 1812 Status = NtQueryValueKey(KeyHandle2, 1813 &ValueName, 1814 KeyValuePartialInformation, 1815 PartialInfo2, 1816 sizeof(ValueBuffer2), 1817 &ResultLength); 1818 NtClose(KeyHandle2); 1819 if (NT_SUCCESS(Status)) 1820 { 1821 /* To combine it into a single string */ 1822 swprintf((PWCHAR)PartialInfo->Data + wcslen((PWCHAR)PartialInfo->Data), 1823 L", %S", 1824 PartialInfo2->Data); 1825 } 1826 1827 /* So that we can set this as the PROCESSOR_IDENTIFIER variable */ 1828 RtlInitUnicodeString(&ValueName, L"PROCESSOR_IDENTIFIER"); 1829 DPRINT("Setting %wZ to %s\n", &ValueName, PartialInfo->Data); 1830 Status = NtSetValueKey(KeyHandle, 1831 &ValueName, 1832 0, 1833 REG_SZ, 1834 PartialInfo->Data, 1835 (wcslen((PWCHAR)PartialInfo->Data) + 1) * sizeof(WCHAR)); 1836 if (!NT_SUCCESS(Status)) 1837 { 1838 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n", 1839 &ValueName, Status); 1840 NtClose(KeyHandle); 1841 return Status; 1842 } 1843 1844 /* Now let's get the processor architecture */ 1845 RtlInitUnicodeString(&ValueName, L"PROCESSOR_REVISION"); 1846 switch (ProcessorInfo.ProcessorArchitecture) 1847 { 1848 /* Check if this is an older Intel CPU */ 1849 case PROCESSOR_ARCHITECTURE_INTEL: 1850 if ((ProcessorInfo.ProcessorRevision >> 8) == 0xFF) 1851 { 1852 /* These guys used a revision + stepping, so get the rev only */ 1853 swprintf(ValueBuffer, L"%02x", ProcessorInfo.ProcessorRevision & 0xFF); 1854 _wcsupr(ValueBuffer); 1855 break; 1856 } 1857 1858 /* Modern Intel, as well as 64-bit CPUs use a revision without stepping */ 1859 case PROCESSOR_ARCHITECTURE_IA64: 1860 case PROCESSOR_ARCHITECTURE_AMD64: 1861 swprintf(ValueBuffer, L"%04x", ProcessorInfo.ProcessorRevision); 1862 break; 1863 1864 /* And anything else we'll just read the whole revision identifier */ 1865 default: 1866 swprintf(ValueBuffer, L"%u", ProcessorInfo.ProcessorRevision); 1867 break; 1868 } 1869 1870 /* Write the revision to the registry */ 1871 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer); 1872 Status = NtSetValueKey(KeyHandle, 1873 &ValueName, 1874 0, 1875 REG_SZ, 1876 ValueBuffer, 1877 (wcslen(ValueBuffer) + 1) * sizeof(WCHAR)); 1878 if (!NT_SUCCESS(Status)) 1879 { 1880 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n", 1881 &ValueName, Status); 1882 NtClose(KeyHandle); 1883 return Status; 1884 } 1885 1886 /* And finally, write the number of CPUs */ 1887 RtlInitUnicodeString(&ValueName, L"NUMBER_OF_PROCESSORS"); 1888 swprintf(ValueBuffer, L"%d", BasicInfo.NumberOfProcessors); 1889 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer); 1890 Status = NtSetValueKey(KeyHandle, 1891 &ValueName, 1892 0, 1893 REG_SZ, 1894 ValueBuffer, 1895 (wcslen(ValueBuffer) + 1) * sizeof(WCHAR)); 1896 if (!NT_SUCCESS(Status)) 1897 { 1898 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n", 1899 &ValueName, Status); 1900 NtClose(KeyHandle); 1901 return Status; 1902 } 1903 1904 /* Now we need to write the safeboot option key in a different format */ 1905 RtlInitUnicodeString(&DestinationString, 1906 L"\\Registry\\Machine\\System\\CurrentControlSet\\" 1907 L"Control\\Safeboot\\Option"); 1908 InitializeObjectAttributes(&ObjectAttributes, 1909 &DestinationString, 1910 OBJ_CASE_INSENSITIVE, 1911 NULL, 1912 NULL); 1913 Status = NtOpenKey(&KeyHandle2, KEY_ALL_ACCESS, &ObjectAttributes); 1914 if (NT_SUCCESS(Status)) 1915 { 1916 /* This was indeed a safeboot, so check what kind of safeboot it was */ 1917 RtlInitUnicodeString(&ValueName, L"OptionValue"); 1918 Status = NtQueryValueKey(KeyHandle2, 1919 &ValueName, 1920 KeyValuePartialInformation, 1921 PartialInfo, 1922 sizeof(ValueBuffer), 1923 &ResultLength); 1924 NtClose(KeyHandle2); 1925 if (NT_SUCCESS(Status)) 1926 { 1927 /* Convert from the integer value to the correct specifier */ 1928 RtlInitUnicodeString(&ValueName, L"SAFEBOOT_OPTION"); 1929 switch (*(PULONG)PartialInfo->Data) 1930 { 1931 case 1: 1932 wcscpy(ValueBuffer, L"MINIMAL"); 1933 break; 1934 case 2: 1935 wcscpy(ValueBuffer, L"NETWORK"); 1936 break; 1937 case 3: 1938 wcscpy(ValueBuffer, L"DSREPAIR"); 1939 break; 1940 } 1941 1942 /* And write it in the environment! */ 1943 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer); 1944 Status = NtSetValueKey(KeyHandle, 1945 &ValueName, 1946 0, 1947 REG_SZ, 1948 ValueBuffer, 1949 (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 else 1959 { 1960 DPRINT1("SMSS: Failed querying safeboot option = %x\n", Status); 1961 } 1962 } 1963 1964 /* We are all done now */ 1965 NtClose(KeyHandle); 1966 return STATUS_SUCCESS; 1967 } 1968 1969 NTSTATUS 1970 NTAPI 1971 SmpProcessFileRenames(VOID) 1972 { 1973 BOOLEAN OldState, HavePrivilege = FALSE; 1974 NTSTATUS Status; 1975 HANDLE FileHandle, OtherFileHandle; 1976 FILE_INFORMATION_CLASS InformationClass; 1977 OBJECT_ATTRIBUTES ObjectAttributes; 1978 IO_STATUS_BLOCK IoStatusBlock; 1979 UNICODE_STRING FileString; 1980 FILE_BASIC_INFORMATION BasicInfo; 1981 FILE_DISPOSITION_INFORMATION DeleteInformation; 1982 PFILE_RENAME_INFORMATION Buffer; 1983 PLIST_ENTRY Head, NextEntry; 1984 PSMP_REGISTRY_VALUE RegEntry; 1985 PWCHAR FileName; 1986 ULONG ValueLength, Length; 1987 1988 /* Give us access to restore any files we want */ 1989 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &OldState); 1990 if (NT_SUCCESS(Status)) HavePrivilege = TRUE; 1991 1992 // FIXME: Handle SFC-protected file renames! 1993 if (SmpAllowProtectedRenames) 1994 DPRINT1("SMSS: FIXME: Handle SFC-protected file renames!\n"); 1995 1996 /* Process pending files to rename */ 1997 Head = &SmpFileRenameList; 1998 while (!IsListEmpty(Head)) 1999 { 2000 /* Get this entry */ 2001 NextEntry = RemoveHeadList(Head); 2002 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 2003 DPRINT("Processing PFRO: '%wZ' / '%wZ'\n", &RegEntry->Value, &RegEntry->Name); 2004 2005 /* Skip past the '@' marker */ 2006 if (!(RegEntry->Value.Length) && (*RegEntry->Name.Buffer == L'@')) 2007 { 2008 RegEntry->Name.Length -= sizeof(UNICODE_NULL); 2009 RegEntry->Name.Buffer++; 2010 } 2011 2012 /* Open the file for delete access */ 2013 InitializeObjectAttributes(&ObjectAttributes, 2014 &RegEntry->Name, 2015 OBJ_CASE_INSENSITIVE, 2016 NULL, 2017 NULL); 2018 Status = NtOpenFile(&OtherFileHandle, 2019 DELETE | SYNCHRONIZE, 2020 &ObjectAttributes, 2021 &IoStatusBlock, 2022 FILE_SHARE_READ | FILE_SHARE_WRITE, 2023 FILE_SYNCHRONOUS_IO_NONALERT); 2024 if (!NT_SUCCESS(Status)) goto Quickie; 2025 2026 /* Check if it's a rename or just a delete */ 2027 ValueLength = RegEntry->Value.Length; 2028 if (!ValueLength) 2029 { 2030 /* Just a delete, set up the class, length and buffer */ 2031 InformationClass = FileDispositionInformation; 2032 Length = sizeof(DeleteInformation); 2033 Buffer = (PFILE_RENAME_INFORMATION)&DeleteInformation; 2034 2035 /* Set the delete disposition */ 2036 DeleteInformation.DeleteFile = TRUE; 2037 } 2038 else 2039 { 2040 /* This is a rename, setup the class and length */ 2041 InformationClass = FileRenameInformation; 2042 Length = ValueLength + sizeof(FILE_RENAME_INFORMATION); 2043 2044 /* Skip past the special markers */ 2045 FileName = RegEntry->Value.Buffer; 2046 if ((*FileName == L'!') || (*FileName == L'@')) 2047 { 2048 FileName++; 2049 Length -= sizeof(UNICODE_NULL); 2050 } 2051 2052 /* Now allocate the buffer for the rename information */ 2053 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag, Length); 2054 if (Buffer) 2055 { 2056 /* Setup the buffer to point to the filename, and copy it */ 2057 Buffer->RootDirectory = NULL; 2058 Buffer->FileNameLength = Length - sizeof(FILE_RENAME_INFORMATION); 2059 Buffer->ReplaceIfExists = FileName != RegEntry->Value.Buffer; 2060 RtlCopyMemory(Buffer->FileName, FileName, Buffer->FileNameLength); 2061 } 2062 else 2063 { 2064 /* Fail */ 2065 Status = STATUS_NO_MEMORY; 2066 } 2067 } 2068 2069 /* Check if everything is okay till here */ 2070 if (NT_SUCCESS(Status)) 2071 { 2072 /* Now either rename or delete the file as requested */ 2073 Status = NtSetInformationFile(OtherFileHandle, 2074 &IoStatusBlock, 2075 Buffer, 2076 Length, 2077 InformationClass); 2078 2079 /* Check if we seem to have failed because the file was readonly */ 2080 if (!NT_SUCCESS(Status) && 2081 (InformationClass == FileRenameInformation) && 2082 (Status == STATUS_OBJECT_NAME_COLLISION) && 2083 Buffer->ReplaceIfExists) 2084 { 2085 /* Open the file for write attribute access this time... */ 2086 DPRINT("\nSMSS: '%wZ' => '%wZ' failed - Status == %x, Possible readonly target\n", 2087 &RegEntry->Name, 2088 &RegEntry->Value, 2089 STATUS_OBJECT_NAME_COLLISION); 2090 FileString.Length = RegEntry->Value.Length - sizeof(WCHAR); 2091 FileString.MaximumLength = RegEntry->Value.MaximumLength - sizeof(WCHAR); 2092 FileString.Buffer = FileName; 2093 InitializeObjectAttributes(&ObjectAttributes, 2094 &FileString, 2095 OBJ_CASE_INSENSITIVE, 2096 NULL, 2097 NULL); 2098 Status = NtOpenFile(&FileHandle, 2099 FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, 2100 &ObjectAttributes, 2101 &IoStatusBlock, 2102 FILE_SHARE_READ | FILE_SHARE_WRITE, 2103 FILE_SYNCHRONOUS_IO_NONALERT); 2104 if (!NT_SUCCESS(Status)) 2105 { 2106 /* That didn't work, so bail out */ 2107 DPRINT1(" SMSS: Open Existing file Failed - Status == %x\n", 2108 Status); 2109 } 2110 else 2111 { 2112 /* Now remove the read-only attribute from the file */ 2113 DPRINT(" SMSS: Open Existing Success\n"); 2114 RtlZeroMemory(&BasicInfo, sizeof(BasicInfo)); 2115 BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL; 2116 Status = NtSetInformationFile(FileHandle, 2117 &IoStatusBlock, 2118 &BasicInfo, 2119 sizeof(BasicInfo), 2120 FileBasicInformation); 2121 NtClose(FileHandle); 2122 if (!NT_SUCCESS(Status)) 2123 { 2124 /* That didn't work, bail out */ 2125 DPRINT1(" SMSS: Set To NORMAL Failed - Status == %x\n", 2126 Status); 2127 } 2128 else 2129 { 2130 /* Now that the file is no longer read-only, delete! */ 2131 DPRINT(" SMSS: Set To NORMAL OK\n"); 2132 Status = NtSetInformationFile(OtherFileHandle, 2133 &IoStatusBlock, 2134 Buffer, 2135 Length, 2136 FileRenameInformation); 2137 if (!NT_SUCCESS(Status)) 2138 { 2139 /* That failed too! */ 2140 DPRINT1(" SMSS: Re-Rename Failed - Status == %x\n", 2141 Status); 2142 } 2143 else 2144 { 2145 /* Everything ok */ 2146 DPRINT(" SMSS: Re-Rename Worked OK\n"); 2147 } 2148 } 2149 } 2150 } 2151 } 2152 2153 /* Close the file handle and check the operation result */ 2154 NtClose(OtherFileHandle); 2155 Quickie: 2156 if (!NT_SUCCESS(Status)) 2157 { 2158 /* We totally failed */ 2159 DPRINT1("SMSS: '%wZ' => '%wZ' failed - Status == %x\n", 2160 &RegEntry->Name, &RegEntry->Value, Status); 2161 } 2162 else if (RegEntry->Value.Length) 2163 { 2164 /* We succeed with a rename */ 2165 DPRINT("SMSS: '%wZ' (renamed to) '%wZ'\n", &RegEntry->Name, &RegEntry->Value); 2166 } 2167 else 2168 { 2169 /* We succeeded with a delete */ 2170 DPRINT("SMSS: '%wZ' (deleted)\n", &RegEntry->Name); 2171 } 2172 2173 /* Now free this entry and keep going */ 2174 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue); 2175 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer); 2176 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry); 2177 } 2178 2179 /* Put back the restore privilege if we had requested it, and return */ 2180 if (HavePrivilege) RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, FALSE, FALSE, &OldState); 2181 return Status; 2182 } 2183 2184 NTSTATUS 2185 NTAPI 2186 SmpLoadDataFromRegistry(OUT PUNICODE_STRING InitialCommand) 2187 { 2188 NTSTATUS Status; 2189 PLIST_ENTRY Head, NextEntry; 2190 PSMP_REGISTRY_VALUE RegEntry; 2191 PVOID OriginalEnvironment; 2192 ULONG MuSessionId = 0; 2193 OBJECT_ATTRIBUTES ObjectAttributes; 2194 HANDLE KeyHandle; 2195 UNICODE_STRING DestinationString; 2196 2197 /* Initialize the keywords we'll be looking for */ 2198 RtlInitUnicodeString(&SmpDebugKeyword, L"debug"); 2199 RtlInitUnicodeString(&SmpASyncKeyword, L"async"); 2200 RtlInitUnicodeString(&SmpAutoChkKeyword, L"autocheck"); 2201 2202 /* Initialize all the registry-associated list heads */ 2203 InitializeListHead(&SmpBootExecuteList); 2204 InitializeListHead(&SmpSetupExecuteList); 2205 InitializeListHead(&SmpPagingFileList); 2206 InitializeListHead(&SmpDosDevicesList); 2207 InitializeListHead(&SmpFileRenameList); 2208 InitializeListHead(&SmpKnownDllsList); 2209 InitializeListHead(&SmpExcludeKnownDllsList); 2210 InitializeListHead(&SmpSubSystemList); 2211 InitializeListHead(&SmpSubSystemsToLoad); 2212 InitializeListHead(&SmpSubSystemsToDefer); 2213 InitializeListHead(&SmpExecuteList); 2214 SmpPagingFileInitialize(); 2215 2216 /* Initialize the SMSS environment */ 2217 Status = RtlCreateEnvironment(TRUE, &SmpDefaultEnvironment); 2218 if (!NT_SUCCESS(Status)) 2219 { 2220 /* Fail if there was a problem */ 2221 DPRINT1("SMSS: Unable to allocate default environment - Status == %X\n", 2222 Status); 2223 SMSS_CHECKPOINT(RtlCreateEnvironment, Status); 2224 return Status; 2225 } 2226 2227 /* Check if we were booted in PE mode (LiveCD should have this) */ 2228 RtlInitUnicodeString(&DestinationString, 2229 L"\\Registry\\Machine\\System\\CurrentControlSet\\" 2230 L"Control\\MiniNT"); 2231 InitializeObjectAttributes(&ObjectAttributes, 2232 &DestinationString, 2233 OBJ_CASE_INSENSITIVE, 2234 NULL, 2235 NULL); 2236 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes); 2237 if (NT_SUCCESS(Status)) 2238 { 2239 /* If the key exists, we were */ 2240 NtClose(KeyHandle); 2241 MiniNTBoot = TRUE; 2242 } 2243 2244 /* Print out if this is the case */ 2245 if (MiniNTBoot) DPRINT("SMSS: !!! MiniNT Boot !!!\n"); 2246 2247 /* Open the environment key to see if we are booted in safe mode */ 2248 RtlInitUnicodeString(&DestinationString, 2249 L"\\Registry\\Machine\\System\\CurrentControlSet\\" 2250 L"Control\\Session Manager\\Environment"); 2251 InitializeObjectAttributes(&ObjectAttributes, 2252 &DestinationString, 2253 OBJ_CASE_INSENSITIVE, 2254 NULL, 2255 NULL); 2256 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes); 2257 if (NT_SUCCESS(Status)) 2258 { 2259 /* Delete the value if we found it */ 2260 RtlInitUnicodeString(&DestinationString, L"SAFEBOOT_OPTION"); 2261 NtDeleteValueKey(KeyHandle, &DestinationString); 2262 NtClose(KeyHandle); 2263 } 2264 2265 /* Switch environments, then query the registry for all needed settings */ 2266 OriginalEnvironment = NtCurrentPeb()->ProcessParameters->Environment; 2267 NtCurrentPeb()->ProcessParameters->Environment = SmpDefaultEnvironment; 2268 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, 2269 L"Session Manager", 2270 SmpRegistryConfigurationTable, 2271 NULL, 2272 NULL); 2273 SmpDefaultEnvironment = NtCurrentPeb()->ProcessParameters->Environment; 2274 NtCurrentPeb()->ProcessParameters->Environment = OriginalEnvironment; 2275 if (!NT_SUCCESS(Status)) 2276 { 2277 /* We failed somewhere in registry initialization, which is bad... */ 2278 DPRINT1("SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status); 2279 SMSS_CHECKPOINT(RtlQueryRegistryValues, Status); 2280 return Status; 2281 } 2282 2283 /* Now we can start acting on the registry settings. First to DOS devices */ 2284 Status = SmpInitializeDosDevices(); 2285 if (!NT_SUCCESS(Status)) 2286 { 2287 /* Failed */ 2288 DPRINT1("SMSS: Unable to initialize DosDevices configuration - Status == %lx\n", 2289 Status); 2290 SMSS_CHECKPOINT(SmpInitializeDosDevices, Status); 2291 return Status; 2292 } 2293 2294 /* Next create the session directory... */ 2295 RtlInitUnicodeString(&DestinationString, L"\\Sessions"); 2296 InitializeObjectAttributes(&ObjectAttributes, 2297 &DestinationString, 2298 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, 2299 NULL, 2300 SmpPrimarySecurityDescriptor); 2301 Status = NtCreateDirectoryObject(&SmpSessionsObjectDirectory, 2302 DIRECTORY_ALL_ACCESS, 2303 &ObjectAttributes); 2304 if (!NT_SUCCESS(Status)) 2305 { 2306 /* Fail */ 2307 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n", 2308 &DestinationString, Status); 2309 SMSS_CHECKPOINT(NtCreateDirectoryObject, Status); 2310 return Status; 2311 } 2312 2313 /* Next loop all the boot execute binaries */ 2314 Head = &SmpBootExecuteList; 2315 while (!IsListEmpty(Head)) 2316 { 2317 /* Remove each one from the list */ 2318 NextEntry = RemoveHeadList(Head); 2319 2320 /* Execute it */ 2321 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 2322 SmpExecuteCommand(&RegEntry->Name, 0, NULL, 0); 2323 2324 /* And free it */ 2325 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue); 2326 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer); 2327 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry); 2328 } 2329 2330 /* Now do any pending file rename operations... */ 2331 if (!MiniNTBoot) SmpProcessFileRenames(); 2332 2333 /* And initialize known DLLs... */ 2334 Status = SmpInitializeKnownDlls(); 2335 if (!NT_SUCCESS(Status)) 2336 { 2337 /* Fail if that didn't work */ 2338 DPRINT1("SMSS: Unable to initialize KnownDll configuration - Status == %lx\n", 2339 Status); 2340 SMSS_CHECKPOINT(SmpInitializeKnownDlls, Status); 2341 return Status; 2342 } 2343 2344 /* Create the needed page files */ 2345 if (!MiniNTBoot) 2346 { 2347 /* Loop every page file */ 2348 Head = &SmpPagingFileList; 2349 while (!IsListEmpty(Head)) 2350 { 2351 /* Remove each one from the list */ 2352 NextEntry = RemoveHeadList(Head); 2353 2354 /* Create the descriptor for it */ 2355 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry); 2356 SmpCreatePagingFileDescriptor(&RegEntry->Name); 2357 2358 /* And free it */ 2359 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue); 2360 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer); 2361 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry); 2362 } 2363 2364 /* Now create all the paging files for the descriptors that we have */ 2365 SmpCreatePagingFiles(); 2366 } 2367 2368 /* Tell Cm it's now safe to fully enable write access to the registry */ 2369 NtInitializeRegistry(CM_BOOT_FLAG_SMSS); 2370 2371 /* Create all the system-based environment variables for later inheriting */ 2372 Status = SmpCreateDynamicEnvironmentVariables(); 2373 if (!NT_SUCCESS(Status)) 2374 { 2375 /* Handle failure */ 2376 SMSS_CHECKPOINT(SmpCreateDynamicEnvironmentVariables, Status); 2377 return Status; 2378 } 2379 2380 /* And finally load all the subsystems for our first session! */ 2381 Status = SmpLoadSubSystemsForMuSession(&MuSessionId, 2382 &SmpWindowsSubSysProcessId, 2383 InitialCommand); 2384 ASSERT(MuSessionId == 0); 2385 if (!NT_SUCCESS(Status)) SMSS_CHECKPOINT(SmpLoadSubSystemsForMuSession, Status); 2386 return Status; 2387 } 2388 2389 NTSTATUS 2390 NTAPI 2391 SmpInit(IN PUNICODE_STRING InitialCommand, 2392 OUT PHANDLE ProcessHandle) 2393 { 2394 NTSTATUS Status, Status2; 2395 OBJECT_ATTRIBUTES ObjectAttributes; 2396 UNICODE_STRING PortName, EventName; 2397 HANDLE EventHandle, PortHandle; 2398 ULONG HardErrorMode; 2399 2400 /* Create the SMSS Heap */ 2401 SmBaseTag = RtlCreateTagHeap(RtlGetProcessHeap(), 2402 0, 2403 L"SMSS!", 2404 L"INIT"); 2405 SmpHeap = RtlGetProcessHeap(); 2406 2407 /* Enable hard errors */ 2408 HardErrorMode = TRUE; 2409 NtSetInformationProcess(NtCurrentProcess(), 2410 ProcessDefaultHardErrorMode, 2411 &HardErrorMode, 2412 sizeof(HardErrorMode)); 2413 2414 /* Initialize the subsystem list and the session list, plus their locks */ 2415 RtlInitializeCriticalSection(&SmpKnownSubSysLock); 2416 InitializeListHead(&SmpKnownSubSysHead); 2417 RtlInitializeCriticalSection(&SmpSessionListLock); 2418 InitializeListHead(&SmpSessionListHead); 2419 2420 /* Initialize the process list */ 2421 InitializeListHead(&NativeProcessList); 2422 2423 /* Initialize session parameters */ 2424 SmpNextSessionId = 1; 2425 SmpNextSessionIdScanMode = 0; 2426 SmpDbgSsLoaded = FALSE; 2427 2428 /* Create the initial security descriptors */ 2429 Status = SmpCreateSecurityDescriptors(TRUE); 2430 if (!NT_SUCCESS(Status)) 2431 { 2432 /* Fail */ 2433 SMSS_CHECKPOINT(SmpCreateSecurityDescriptors, Status); 2434 return Status; 2435 } 2436 2437 /* Initialize subsystem names */ 2438 RtlInitUnicodeString(&SmpSubsystemName, L"NT-Session Manager"); 2439 RtlInitUnicodeString(&PosixName, L"POSIX"); 2440 RtlInitUnicodeString(&Os2Name, L"OS2"); 2441 2442 /* Create the SM API Port */ 2443 RtlInitUnicodeString(&PortName, L"\\SmApiPort"); 2444 InitializeObjectAttributes(&ObjectAttributes, &PortName, 0, NULL, NULL); 2445 Status = NtCreatePort(&PortHandle, 2446 &ObjectAttributes, 2447 sizeof(SB_CONNECTION_INFO), 2448 sizeof(SM_API_MSG), 2449 sizeof(SB_API_MSG) * 32); 2450 ASSERT(NT_SUCCESS(Status)); 2451 SmpDebugPort = PortHandle; 2452 2453 /* Create two SM API threads */ 2454 Status = RtlCreateUserThread(NtCurrentProcess(), 2455 NULL, 2456 FALSE, 2457 0, 2458 0, 2459 0, 2460 SmpApiLoop, 2461 PortHandle, 2462 NULL, 2463 NULL); 2464 ASSERT(NT_SUCCESS(Status)); 2465 Status = RtlCreateUserThread(NtCurrentProcess(), 2466 NULL, 2467 FALSE, 2468 0, 2469 0, 2470 0, 2471 SmpApiLoop, 2472 PortHandle, 2473 NULL, 2474 NULL); 2475 ASSERT(NT_SUCCESS(Status)); 2476 2477 /* Create the write event that autochk can set after running */ 2478 RtlInitUnicodeString(&EventName, L"\\Device\\VolumesSafeForWriteAccess"); 2479 InitializeObjectAttributes(&ObjectAttributes, 2480 &EventName, 2481 OBJ_PERMANENT, 2482 NULL, 2483 NULL); 2484 Status2 = NtCreateEvent(&EventHandle, 2485 EVENT_ALL_ACCESS, 2486 &ObjectAttributes, 2487 0, 2488 0); 2489 if (!NT_SUCCESS(Status2)) 2490 { 2491 /* Should never really fail */ 2492 DPRINT1("SMSS: Unable to create %wZ event - Status == %lx\n", 2493 &EventName, Status2); 2494 ASSERT(NT_SUCCESS(Status2)); 2495 } 2496 2497 /* Now initialize everything else based on the registry parameters */ 2498 Status = SmpLoadDataFromRegistry(InitialCommand); 2499 if (NT_SUCCESS(Status)) 2500 { 2501 /* Autochk should've run now. Set the event and save the CSRSS handle */ 2502 *ProcessHandle = SmpWindowsSubSysProcess; 2503 NtSetEvent(EventHandle, 0); 2504 NtClose(EventHandle); 2505 } 2506 2507 /* All done */ 2508 return Status; 2509 } 2510