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
9 /* INCLUDES *******************************************************************/
16 /* GLOBALS ********************************************************************/
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
;
26 HANDLE SmpDebugPort
, SmpDosDevicesObjectDirectory
;
27 PWCHAR SmpDefaultEnvironment
, SmpDefaultLibPathBuffer
;
28 UNICODE_STRING SmpKnownDllPath
, SmpDefaultLibPath
;
29 ULONG SmpCalledConfigEnv
;
31 ULONG SmpInitProgressByLine
;
32 NTSTATUS SmpInitReturnStatus
;
33 PVOID SmpInitLastCall
;
35 SECURITY_DESCRIPTOR SmpPrimarySDBody
, SmpLiberalSDBody
, SmpKnownDllsSDBody
;
36 SECURITY_DESCRIPTOR SmpApiPortSDBody
;
37 PISECURITY_DESCRIPTOR SmpPrimarySecurityDescriptor
, SmpLiberalSecurityDescriptor
;
38 PISECURITY_DESCRIPTOR SmpKnownDllsSecurityDescriptor
, SmpApiPortSecurityDescriptor
;
40 ULONG SmpAllowProtectedRenames
, SmpProtectionMode
= 1;
41 BOOLEAN MiniNTBoot
= FALSE
;
43 #define SMSS_CHECKPOINT(x, y) \
45 SmpInitProgressByLine = __LINE__; \
46 SmpInitReturnStatus = (y); \
47 SmpInitLastCall = (x); \
50 /* REGISTRY CONFIGURATION *****************************************************/
54 SmpSaveRegistryValue(IN PLIST_ENTRY ListAddress
,
59 PSMP_REGISTRY_VALUE RegEntry
;
60 UNICODE_STRING NameString
, ValueString
;
61 ANSI_STRING AnsiValueString
;
62 PLIST_ENTRY NextEntry
;
64 /* Convert to unicode strings */
65 RtlInitUnicodeString(&NameString
, Name
);
66 RtlInitUnicodeString(&ValueString
, Value
);
68 /* In case this is the first value, initialize a new list/structure */
71 /* Check if we should do a duplicate check */
74 /* Loop the current list */
75 NextEntry
= ListAddress
->Flink
;
76 while (NextEntry
!= ListAddress
)
79 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
81 /* Check if the value name matches */
82 if (!RtlCompareUnicodeString(&RegEntry
->Name
, &NameString
, TRUE
))
84 /* Check if the value is the exact same thing */
85 if (!RtlCompareUnicodeString(&RegEntry
->Value
, &ValueString
, TRUE
))
87 /* Fail -- the same setting is being set twice */
88 return STATUS_OBJECT_NAME_EXISTS
;
91 /* We found the list, and this isn't a duplicate value */
95 /* This wasn't a match, keep going */
96 NextEntry
= NextEntry
->Flink
;
101 /* Are we adding on, or creating a new entry */
104 /* A new entry -- allocate it */
105 RegEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
107 sizeof(SMP_REGISTRY_VALUE
) +
108 NameString
.MaximumLength
);
109 if (!RegEntry
) return STATUS_NO_MEMORY
;
111 /* Initialize the list and set all values to NULL */
112 InitializeListHead(&RegEntry
->Entry
);
113 RegEntry
->AnsiValue
= NULL
;
114 RegEntry
->Value
.Buffer
= NULL
;
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
,
122 NameString
.MaximumLength
);
124 /* Add this entry into the list */
125 InsertTailList(ListAddress
, &RegEntry
->Entry
);
128 /* Did we have an old value buffer? */
129 if (RegEntry
->Value
.Buffer
)
132 ASSERT(RegEntry
->Value
.Length
!= 0);
133 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
136 /* Is there no value associated? */
139 /* We're done here */
140 RtlInitUnicodeString(&RegEntry
->Value
, NULL
);
141 return STATUS_SUCCESS
;
144 /* There is a value, so allocate a buffer for it */
145 RegEntry
->Value
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
147 ValueString
.MaximumLength
);
148 if (!RegEntry
->Value
.Buffer
)
150 /* Out of memory, undo */
151 RemoveEntryList(&RegEntry
->Entry
);
152 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
153 return STATUS_NO_MEMORY
;
156 /* Copy the value into the entry */
157 RegEntry
->Value
.Length
= ValueString
.Length
;
158 RegEntry
->Value
.MaximumLength
= ValueString
.MaximumLength
;
159 RtlCopyMemory(RegEntry
->Value
.Buffer
,
161 ValueString
.MaximumLength
);
163 /* Now allocate memory for an ANSI copy of it */
164 RegEntry
->AnsiValue
= RtlAllocateHeap(RtlGetProcessHeap(),
166 (ValueString
.Length
/ sizeof(WCHAR
)) +
168 if (!RegEntry
->AnsiValue
)
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
;
177 /* Convert the Unicode value string and return success */
178 RtlInitEmptyAnsiString(&AnsiValueString
,
180 (ValueString
.Length
/ sizeof(WCHAR
)) +
182 RtlUnicodeStringToAnsiString(&AnsiValueString
, &ValueString
, FALSE
);
183 return STATUS_SUCCESS
;
188 SmpFindRegistryValue(IN PLIST_ENTRY List
,
191 PSMP_REGISTRY_VALUE RegEntry
;
192 UNICODE_STRING ValueString
;
193 PLIST_ENTRY NextEntry
;
195 /* Initialize the value name sting */
196 RtlInitUnicodeString(&ValueString
, ValueName
);
199 NextEntry
= List
->Flink
;
200 while (NextEntry
!= List
)
203 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
205 /* Check if the value name matches */
206 if (!RtlCompareUnicodeString(&RegEntry
->Name
, &ValueString
, TRUE
)) break;
208 /* It doesn't, move on */
209 NextEntry
= NextEntry
->Flink
;
212 /* If we looped back, return NULL, otherwise return the entry we found */
213 if (NextEntry
== List
) RegEntry
= NULL
;
219 SmpConfigureProtectionMode(IN PWSTR ValueName
,
222 IN ULONG ValueLength
,
224 IN PVOID EntryContext
)
226 /* Make sure the value is valid */
227 if (ValueLength
== sizeof(ULONG
))
230 SmpProtectionMode
= *(PULONG
)ValueData
;
234 /* Default is to protect stuff */
235 SmpProtectionMode
= 1;
238 /* Recreate the security descriptors to take into account security mode */
239 SmpCreateSecurityDescriptors(FALSE
);
240 DPRINT("SmpProtectionMode: %lu\n", SmpProtectionMode
);
241 return STATUS_SUCCESS
;
246 SmpConfigureAllowProtectedRenames(IN PWSTR ValueName
,
249 IN ULONG ValueLength
,
251 IN PVOID EntryContext
)
253 /* Make sure the value is valid */
254 if (ValueLength
== sizeof(ULONG
))
257 SmpAllowProtectedRenames
= *(PULONG
)ValueData
;
261 /* Default is to not allow protected renames */
262 SmpAllowProtectedRenames
= 0;
265 DPRINT("SmpAllowProtectedRenames: %lu\n", SmpAllowProtectedRenames
);
266 return STATUS_SUCCESS
;
271 SmpConfigureObjectDirectories(IN PWSTR ValueName
,
274 IN ULONG ValueLength
,
276 IN PVOID EntryContext
)
278 PISECURITY_DESCRIPTOR SecDescriptor
;
280 OBJECT_ATTRIBUTES ObjectAttributes
;
282 UNICODE_STRING RpcString
, WindowsString
, SearchString
;
283 PWCHAR SourceString
= ValueData
;
285 /* Initialize the two strings we will be looking for */
286 RtlInitUnicodeString(&RpcString
, L
"\\RPC Control");
287 RtlInitUnicodeString(&WindowsString
, L
"\\Windows");
289 /* Loop the registry data we received */
290 while (*SourceString
)
292 /* Assume primary SD for most objects */
293 RtlInitUnicodeString(&SearchString
, SourceString
);
294 SecDescriptor
= SmpPrimarySecurityDescriptor
;
296 /* But for these two always set the liberal descriptor */
297 if ((RtlEqualUnicodeString(&SearchString
, &RpcString
, TRUE
)) ||
298 (RtlEqualUnicodeString(&SearchString
, &WindowsString
, TRUE
)))
300 SecDescriptor
= SmpLiberalSecurityDescriptor
;
303 /* Create the requested directory with the requested descriptor */
304 InitializeObjectAttributes(&ObjectAttributes
,
306 OBJ_CASE_INSENSITIVE
|
311 DPRINT("Creating: %wZ directory\n", &SearchString
);
312 Status
= NtCreateDirectoryObject(&DirHandle
,
313 DIRECTORY_ALL_ACCESS
,
315 if (!NT_SUCCESS(Status
))
318 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
319 &SearchString
, Status
);
323 /* It worked, now close the handle */
327 /* Move to the next requested object */
328 SourceString
+= wcslen(SourceString
) + 1;
332 return STATUS_SUCCESS
;
337 SmpConfigureMemoryMgmt(IN PWSTR ValueName
,
340 IN ULONG ValueLength
,
342 IN PVOID EntryContext
)
344 /* Save this is into a list */
345 return SmpSaveRegistryValue(EntryContext
, ValueData
, NULL
, TRUE
);
350 SmpConfigureFileRenames(IN PWSTR ValueName
,
353 IN ULONG ValueLength
,
355 IN PVOID EntryContext
)
358 static PWCHAR Canary
= NULL
;
360 /* Check if this is the second call */
363 /* Save the data into the list */
364 DPRINT("Renamed file: '%S' - '%S'\n", Canary
, ValueData
);
365 Status
= SmpSaveRegistryValue(EntryContext
, Canary
, ValueData
, FALSE
);
370 /* This it the first call, do nothing until we get the second call */
372 Status
= STATUS_SUCCESS
;
375 /* Return the status */
381 SmpConfigureExcludeKnownDlls(IN PWSTR ValueName
,
384 IN ULONG ValueLength
,
386 IN PVOID EntryContext
)
391 /* Make sure the value type is valid */
392 if ((ValueType
== REG_MULTI_SZ
) || (ValueType
== REG_SZ
))
394 /* Keep going for each DLL in the list */
398 /* Add this to the linked list */
399 DPRINT("Excluded DLL: %S\n", DllName
);
400 Status
= SmpSaveRegistryValue(EntryContext
, DllName
, NULL
, TRUE
);
402 /* Bail out on failure or if only one DLL name was present */
403 if (!(NT_SUCCESS(Status
)) || (ValueType
== REG_SZ
)) return Status
;
405 /* Otherwise, move to the next DLL name */
406 DllName
+= wcslen(DllName
) + 1;
411 return STATUS_SUCCESS
;
416 SmpConfigureDosDevices(IN PWSTR ValueName
,
419 IN ULONG ValueLength
,
421 IN PVOID EntryContext
)
423 /* Save into linked list */
424 return SmpSaveRegistryValue(EntryContext
, ValueName
, ValueData
, TRUE
);
429 SmpInitializeKnownDllPath(IN PUNICODE_STRING DllPath
,
435 /* Allocate the buffer */
436 DllPath
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag
, Length
);
439 /* Fill out the rest of the string */
440 DllPath
->MaximumLength
= (USHORT
)Length
;
441 DllPath
->Length
= (USHORT
)Length
- sizeof(UNICODE_NULL
);
443 /* Copy the actual path and return success */
444 RtlCopyMemory(DllPath
->Buffer
, Buffer
, Length
);
445 Status
= STATUS_SUCCESS
;
449 /* Fail with out of memory code */
450 Status
= STATUS_NO_MEMORY
;
459 SmpConfigureKnownDlls(IN PWSTR ValueName
,
462 IN ULONG ValueLength
,
464 IN PVOID EntryContext
)
466 /* Check which value is being set */
467 if (_wcsicmp(ValueName
, L
"DllDirectory") == 0)
469 /* This is the directory, initialize it */
470 DPRINT("KnownDll Path: %S\n", ValueData
);
471 return SmpInitializeKnownDllPath(&SmpKnownDllPath
, ValueData
, ValueLength
);
475 /* Add to the linked list -- this is a file */
476 return SmpSaveRegistryValue(EntryContext
, ValueName
, ValueData
, TRUE
);
482 SmpConfigureEnvironment(IN PWSTR ValueName
,
485 IN ULONG ValueLength
,
487 IN PVOID EntryContext
)
490 UNICODE_STRING ValueString
, DataString
;
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
))
499 DPRINT1("SMSS: 'SET %wZ = %wZ' failed - Status == %lx\n",
500 &ValueString
, &DataString
, Status
);
504 /* Check if the path is being set, and wait for the second instantiation */
505 if ((_wcsicmp(ValueName
, L
"Path") == 0) && (++SmpCalledConfigEnv
== 2))
507 /* Allocate the path buffer */
508 SmpDefaultLibPathBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
511 if (!SmpDefaultLibPathBuffer
) return STATUS_NO_MEMORY
;
513 /* Copy the data into it and create the UNICODE_STRING to hold it */
514 RtlCopyMemory(SmpDefaultLibPathBuffer
, ValueData
, ValueLength
);
515 RtlInitUnicodeString(&SmpDefaultLibPath
, SmpDefaultLibPathBuffer
);
519 return STATUS_SUCCESS
;
524 SmpConfigureSubSystems(IN PWSTR ValueName
,
527 IN ULONG ValueLength
,
529 IN PVOID EntryContext
)
531 PSMP_REGISTRY_VALUE RegEntry
;
532 PWCHAR SubsystemName
;
534 /* Is this a required or optional subsystem? */
535 if ((_wcsicmp(ValueName
, L
"Required") != 0) &&
536 (_wcsicmp(ValueName
, L
"Optional") != 0))
538 /* It isn't, is this the PSI flag? */
539 if ((_wcsicmp(ValueName
, L
"PosixSingleInstance") != 0) ||
540 (ValueType
!= REG_DWORD
))
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
);
547 /* This was the PSI flag, save it and exit */
548 RegPosixSingleInstance
= TRUE
;
549 return STATUS_SUCCESS
;
552 /* This should be one of the required/optional lists. Is the type valid? */
553 if (ValueType
== REG_MULTI_SZ
)
555 /* It is, get the first subsystem */
556 SubsystemName
= ValueData
;
557 while (*SubsystemName
)
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
);
564 /* This subsystem doesn't exist, so skip it */
565 DPRINT1("SMSS: Invalid subsystem name - %ws\n", SubsystemName
);
569 /* Found it -- remove it from the main list */
570 RemoveEntryList(&RegEntry
->Entry
);
572 /* Figure out which list to put it in */
573 if (_wcsicmp(ValueName
, L
"Required") == 0)
575 /* Put it into the required list */
576 DPRINT("Required\n");
577 InsertTailList(&SmpSubSystemsToLoad
, &RegEntry
->Entry
);
581 /* Put it into the optional list */
582 DPRINT("Optional\n");
583 InsertTailList(&SmpSubSystemsToDefer
, &RegEntry
->Entry
);
587 /* Move to the next name */
588 SubsystemName
+= wcslen(SubsystemName
) + 1;
593 return STATUS_SUCCESS
;
596 RTL_QUERY_REGISTRY_TABLE
597 SmpRegistryConfigurationTable
[] =
600 SmpConfigureProtectionMode
,
610 SmpConfigureAllowProtectedRenames
,
611 RTL_QUERY_REGISTRY_DELETE
,
612 L
"AllowProtectedRenames",
620 SmpConfigureObjectDirectories
,
622 L
"ObjectDirectories",
625 L
"\\Windows\0\\RPC Control\0",
630 SmpConfigureMemoryMgmt
,
635 L
"autocheck AutoChk.exe *\0",
640 SmpConfigureMemoryMgmt
,
641 RTL_QUERY_REGISTRY_TOPKEY
,
643 &SmpSetupExecuteList
,
650 SmpConfigureFileRenames
,
651 RTL_QUERY_REGISTRY_DELETE
,
652 L
"PendingFileRenameOperations",
660 SmpConfigureFileRenames
,
661 RTL_QUERY_REGISTRY_DELETE
,
662 L
"PendingFileRenameOperations2",
670 SmpConfigureExcludeKnownDlls
,
672 L
"ExcludeFromKnownDlls",
673 &SmpExcludeKnownDllsList
,
681 RTL_QUERY_REGISTRY_SUBKEY
,
682 L
"Memory Management",
690 SmpConfigureMemoryMgmt
,
695 L
"?:\\pagefile.sys\0",
700 SmpConfigureDosDevices
,
701 RTL_QUERY_REGISTRY_SUBKEY
,
710 SmpConfigureKnownDlls
,
711 RTL_QUERY_REGISTRY_SUBKEY
,
720 SmpConfigureEnvironment
,
721 RTL_QUERY_REGISTRY_SUBKEY
,
730 SmpConfigureSubSystems
,
731 RTL_QUERY_REGISTRY_SUBKEY
,
740 SmpConfigureSubSystems
,
741 RTL_QUERY_REGISTRY_NOEXPAND
,
750 SmpConfigureSubSystems
,
751 RTL_QUERY_REGISTRY_NOEXPAND
,
760 SmpConfigureSubSystems
,
770 SmpConfigureMemoryMgmt
,
771 RTL_QUERY_REGISTRY_TOPKEY
,
782 /* FUNCTIONS ******************************************************************/
786 SmpTranslateSystemPartitionInformation(VOID
)
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
];
799 /* Open the setup key */
800 RtlInitUnicodeString(&UnicodeString
, L
"\\Registry\\Machine\\System\\Setup");
801 InitializeObjectAttributes(&ObjectAttributes
,
803 OBJ_CASE_INSENSITIVE
,
806 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
807 if (!NT_SUCCESS(Status
))
809 DPRINT1("SMSS: can't open system setup key for reading: 0x%x\n", Status
);
813 /* Query the system partition */
814 RtlInitUnicodeString(&UnicodeString
, L
"SystemPartition");
815 Status
= NtQueryValueKey(KeyHandle
,
817 KeyValuePartialInformation
,
822 if (!NT_SUCCESS(Status
))
824 DPRINT1("SMSS: can't query SystemPartition value: 0x%x\n", Status
);
828 /* Initialize the system partition string string */
829 RtlInitUnicodeString(&SystemPartition
, (PWCHAR
)PartialInfo
->Data
);
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
,
836 sizeof(DirInfoBuffer
),
841 if (!NT_SUCCESS(Status
))
843 DPRINT1("SMSS: can't find drive letter for system partition\n");
847 /* Keep searching until we find it */
851 if ((RtlEqualUnicodeString(&DirInfo
->TypeName
, &SearchString
, TRUE
)) &&
852 (DirInfo
->Name
.Length
== 2 * sizeof(WCHAR
)) &&
853 (DirInfo
->Name
.Buffer
[1] == L
':'))
855 /* Looks like we found it, open the link to get its target */
856 InitializeObjectAttributes(&ObjectAttributes
,
858 OBJ_CASE_INSENSITIVE
,
859 SmpDosDevicesObjectDirectory
,
861 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
862 SYMBOLIC_LINK_ALL_ACCESS
,
864 if (NT_SUCCESS(Status
))
866 /* Open worked, query the target now */
867 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
872 /* Check if it matches the string we had found earlier */
873 if ((NT_SUCCESS(Status
)) &&
874 ((RtlEqualUnicodeString(&SystemPartition
,
877 ((RtlPrefixUnicodeString(&SystemPartition
,
880 (LinkTarget
.Buffer
[SystemPartition
.Length
/ sizeof(WCHAR
)] == L
'\\'))))
888 /* Couldn't find it, try again */
889 Status
= NtQueryDirectoryObject(SmpDosDevicesObjectDirectory
,
891 sizeof(DirInfoBuffer
),
896 } while (NT_SUCCESS(Status
));
897 if (!NT_SUCCESS(Status
))
899 DPRINT1("SMSS: can't find drive letter for system partition\n");
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
,
908 OBJ_CASE_INSENSITIVE
,
911 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
912 if (!NT_SUCCESS(Status
))
914 DPRINT1("SMSS: can't open software setup key for writing: 0x%x\n",
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';
924 /* Now set this as the "BootDir" */
925 RtlInitUnicodeString(&UnicodeString
, L
"BootDir");
926 Status
= NtSetValueKey(KeyHandle
,
932 if (!NT_SUCCESS(Status
))
934 DPRINT1("SMSS: couldn't write BootDir value: 0x%x\n", Status
);
941 SmpCreateSecurityDescriptors(IN BOOLEAN InitialCall
)
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
;
952 BOOLEAN ProtectionRequired
= FALSE
;
954 /* Check if this is the first call */
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
,
966 ASSERT(NT_SUCCESS(Status
));
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
,
977 ASSERT(NT_SUCCESS(Status
));
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
,
988 ASSERT(NT_SUCCESS(Status
));
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
,
999 ASSERT(NT_SUCCESS(Status
));
1002 /* Check if protection was requested in the registry (on by default) */
1003 if (SmpProtectionMode
& 1) ProtectionRequired
= TRUE
;
1005 /* Exit if there's nothing to do */
1006 if (!(InitialCall
|| ProtectionRequired
)) return STATUS_SUCCESS
;
1008 /* Build the world SID */
1009 Status
= RtlAllocateAndInitializeSid(&WorldAuthority
, 1,
1011 0, 0, 0, 0, 0, 0, 0,
1013 if (!NT_SUCCESS(Status
))
1019 /* Build the admin SID */
1020 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 2,
1021 SECURITY_BUILTIN_DOMAIN_RID
,
1022 DOMAIN_ALIAS_RID_ADMINS
,
1025 if (!NT_SUCCESS(Status
))
1031 /* Build the owner SID */
1032 Status
= RtlAllocateAndInitializeSid(&CreatorAuthority
, 1,
1033 SECURITY_CREATOR_OWNER_RID
,
1034 0, 0, 0, 0, 0, 0, 0,
1036 if (!NT_SUCCESS(Status
))
1042 /* Build the restricted SID */
1043 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 1,
1044 SECURITY_RESTRICTED_CODE_RID
,
1045 0, 0, 0, 0, 0, 0, 0,
1047 if (!NT_SUCCESS(Status
))
1049 RestrictedSid
= NULL
;
1053 /* Build the system SID */
1054 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 1,
1055 SECURITY_LOCAL_SYSTEM_RID
,
1056 0, 0, 0, 0, 0, 0, 0,
1058 if (!NT_SUCCESS(Status
))
1064 /* Now check if we're creating the core descriptors */
1067 /* We're skipping NextAcl so we have to do this here */
1068 SidLength
= RtlLengthSid(WorldSid
) + RtlLengthSid(RestrictedSid
) + RtlLengthSid(AdminSid
);
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
;
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
));
1088 /* Set this as the DACL */
1089 Status
= RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor
,
1093 ASSERT(NT_SUCCESS(Status
));
1096 /* Allocate an ACL with 6 ACEs, two ACEs per SID */
1097 SidLength
= RtlLengthSid(WorldSid
) + RtlLengthSid(RestrictedSid
) + RtlLengthSid(AdminSid
);
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
;
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
));
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
;
1131 /* Set this as the DACL */
1132 Status
= RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor
,
1136 ASSERT(NT_SUCCESS(Status
));
1139 /* The initial ACLs have been created, are we also protecting objects? */
1140 if (!ProtectionRequired
) goto Quickie
;
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
;
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
));
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
;
1181 /* Set this as the DACL for the primary SD */
1182 Status
= RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor
,
1186 ASSERT(NT_SUCCESS(Status
));
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
;
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
));
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
;
1226 /* Now set this as the DACL for the liberal SD */
1227 Status
= RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor
,
1231 ASSERT(NT_SUCCESS(Status
));
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
);
1245 SmpInitializeDosDevices(VOID
)
1248 PSMP_REGISTRY_VALUE RegEntry
;
1249 SECURITY_DESCRIPTOR_CONTROL OldFlag
= 0;
1250 OBJECT_ATTRIBUTES ObjectAttributes
;
1251 UNICODE_STRING DestinationString
;
1253 PLIST_ENTRY NextEntry
, Head
;
1255 /* Open the GLOBAL?? directory */
1256 RtlInitUnicodeString(&DestinationString
, L
"\\??");
1257 InitializeObjectAttributes(&ObjectAttributes
,
1259 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1262 Status
= NtOpenDirectoryObject(&SmpDosDevicesObjectDirectory
,
1263 DIRECTORY_ALL_ACCESS
,
1265 if (!NT_SUCCESS(Status
))
1267 DPRINT1("SMSS: Unable to open %wZ directory - Status == %lx\n",
1268 &DestinationString
, Status
);
1272 /* Loop the DOS devices */
1273 Head
= &SmpDosDevicesList
;
1274 while (!IsListEmpty(Head
))
1276 /* Get the entry and remove it */
1277 NextEntry
= RemoveHeadList(Head
);
1278 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1280 /* Initialize the attributes, and see which descriptor is being used */
1281 InitializeObjectAttributes(&ObjectAttributes
,
1283 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1284 SmpDosDevicesObjectDirectory
,
1285 SmpPrimarySecurityDescriptor
);
1286 if (SmpPrimarySecurityDescriptor
)
1288 /* Save the old flag and set it while we create this link */
1289 OldFlag
= SmpPrimarySecurityDescriptor
->Control
;
1290 SmpPrimarySecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
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
,
1299 if (Status
== STATUS_OBJECT_NAME_EXISTS
)
1301 /* Make it temporary and get rid of the handle */
1302 NtMakeTemporaryObject(DirHandle
);
1305 /* Treat this as success, and see if we got a name back */
1306 Status
= STATUS_SUCCESS
;
1307 if (RegEntry
->Value
.Length
)
1309 /* Create it now with this name */
1310 ObjectAttributes
.Attributes
&= ~OBJ_OPENIF
;
1311 Status
= NtCreateSymbolicLinkObject(&DirHandle
,
1312 SYMBOLIC_LINK_ALL_ACCESS
,
1318 /* If we were using a security descriptor, restore the non-defaulted flag */
1319 if (ObjectAttributes
.SecurityDescriptor
)
1321 SmpPrimarySecurityDescriptor
->Control
= OldFlag
;
1324 /* Print a failure if we failed to create the symbolic link */
1325 if (!NT_SUCCESS(Status
))
1327 DPRINT1("SMSS: Unable to create %wZ => %wZ symbolic link object - Status == 0x%lx\n",
1334 /* Close the handle */
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
);
1343 /* Return the status */
1349 SmpProcessModuleImports(IN PVOID Unused
,
1350 IN PCHAR ImportName
)
1352 ULONG Length
= 0, Chars
;
1353 WCHAR Buffer
[MAX_PATH
];
1354 PWCHAR DllName
, DllValue
;
1355 ANSI_STRING ImportString
;
1356 UNICODE_STRING ImportUnicodeString
;
1359 /* Skip NTDLL since it's already always mapped */
1360 if (!_stricmp(ImportName
, "ntdll.dll")) return;
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;
1368 /* Loop in case we find a forwarder */
1369 ImportUnicodeString
.MaximumLength
= ImportUnicodeString
.Length
+ sizeof(UNICODE_NULL
);
1370 while (Length
< ImportUnicodeString
.Length
)
1372 if (ImportUnicodeString
.Buffer
[Length
/ sizeof(WCHAR
)] == L
'.') break;
1373 Length
+= sizeof(WCHAR
);
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
);
1383 /* Add the DLL to the list */
1384 SmpSaveRegistryValue(&SmpKnownDllsList
, DllName
, DllValue
, TRUE
);
1389 SmpInitializeKnownDllsInternal(IN PUNICODE_STRING Directory
,
1390 IN PUNICODE_STRING Path
)
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
;
1404 /* Initialize to NULL */
1405 DirFileHandle
= NULL
;
1407 NtPath
.Buffer
= NULL
;
1409 /* Create the \KnownDLLs directory */
1410 InitializeObjectAttributes(&ObjectAttributes
,
1412 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1414 SmpKnownDllsSecurityDescriptor
);
1415 Status
= NtCreateDirectoryObject(&DirHandle
,
1416 DIRECTORY_ALL_ACCESS
,
1418 if (!NT_SUCCESS(Status
))
1420 /* Handle failure */
1421 DPRINT1("SMSS: Unable to create %wZ directory - Status == %lx\n",
1426 /* Convert the path to native format */
1427 if (!RtlDosPathNameToNtPathName_U(Path
->Buffer
, &NtPath
, NULL
, NULL
))
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
;
1435 /* Open the path that was specified, which should be a directory */
1436 InitializeObjectAttributes(&ObjectAttributes
,
1438 OBJ_CASE_INSENSITIVE
,
1441 Status
= NtOpenFile(&DirFileHandle
,
1442 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
1445 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1446 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
1447 if (!NT_SUCCESS(Status
))
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",
1458 /* Temporarily hack the SD to use a default DACL for this symbolic link */
1459 if (SmpPrimarySecurityDescriptor
)
1461 OldFlag
= SmpPrimarySecurityDescriptor
->Control
;
1462 SmpPrimarySecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1465 /* Create a symbolic link to the directory in the object manager */
1466 RtlInitUnicodeString(&DestinationString
, L
"KnownDllPath");
1467 InitializeObjectAttributes(&ObjectAttributes
,
1469 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1471 SmpPrimarySecurityDescriptor
);
1472 Status
= NtCreateSymbolicLinkObject(&LinkHandle
,
1473 SYMBOLIC_LINK_ALL_ACCESS
,
1478 if (SmpPrimarySecurityDescriptor
) SmpPrimarySecurityDescriptor
->Control
= OldFlag
;
1480 /* Check if the symlink was created */
1481 if (!NT_SUCCESS(Status
))
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
);
1490 /* We created it permanent, we can go ahead and close the handle now */
1491 Status1
= NtClose(LinkHandle
);
1492 ASSERT(NT_SUCCESS(Status1
));
1494 /* Now loop the known DLLs */
1495 NextEntry
= SmpKnownDllsList
.Flink
;
1496 while (NextEntry
!= &SmpKnownDllsList
)
1498 /* Get the entry and move on */
1499 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1500 NextEntry
= NextEntry
->Flink
;
1502 DPRINT("Processing known DLL: %wZ-%wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
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
)))
1513 /* Open the actual file */
1514 InitializeObjectAttributes(&ObjectAttributes
,
1516 OBJ_CASE_INSENSITIVE
,
1519 Status1
= NtOpenFile(&FileHandle
,
1520 SYNCHRONIZE
| FILE_EXECUTE
,
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;
1530 Status
= LdrVerifyImageMatchesChecksum((HANDLE
)((ULONG_PTR
)FileHandle
| 1),
1531 SmpProcessModuleImports
,
1533 &ImageCharacteristics
);
1534 if (!NT_SUCCESS(Status
))
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
));
1544 else if (!(ImageCharacteristics
& IMAGE_FILE_DLL
))
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
));
1555 /* Temporarily hack the SD to use a default DACL for this section */
1556 if (SmpLiberalSecurityDescriptor
)
1558 OldFlag
= SmpLiberalSecurityDescriptor
->Control
;
1559 SmpLiberalSecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1562 /* Create the section for this known DLL */
1563 InitializeObjectAttributes(&ObjectAttributes
,
1567 SmpLiberalSecurityDescriptor
)
1568 Status
= NtCreateSection(&SectionHandle
,
1577 if (SmpLiberalSecurityDescriptor
) SmpLiberalSecurityDescriptor
->Control
= OldFlag
;
1579 /* Check if we created the section okay */
1580 if (NT_SUCCESS(Status
))
1582 /* We can close it now, since it's marked permanent */
1583 Status1
= NtClose(SectionHandle
);
1584 ASSERT(NT_SUCCESS(Status1
));
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
);
1593 /* Close the file since we can move on to the next one */
1594 Status1
= NtClose(FileHandle
);
1595 ASSERT(NT_SUCCESS(Status1
));
1599 /* Close both handles and free the NT path buffer */
1602 Status1
= NtClose(DirHandle
);
1603 ASSERT(NT_SUCCESS(Status1
));
1607 Status1
= NtClose(DirFileHandle
);
1608 ASSERT(NT_SUCCESS(Status1
));
1610 if (NtPath
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath
.Buffer
);
1616 SmpInitializeKnownDlls(VOID
)
1619 PSMP_REGISTRY_VALUE RegEntry
;
1620 UNICODE_STRING DestinationString
;
1621 PLIST_ENTRY Head
, NextEntry
;
1623 /* Call the internal function */
1624 RtlInitUnicodeString(&DestinationString
, L
"\\KnownDlls");
1625 Status
= SmpInitializeKnownDllsInternal(&DestinationString
, &SmpKnownDllPath
);
1627 /* Wipe out the list regardless of success */
1628 Head
= &SmpKnownDllsList
;
1629 while (!IsListEmpty(Head
))
1631 /* Remove this entry */
1632 NextEntry
= RemoveHeadList(Head
);
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
);
1647 SmpCreateDynamicEnvironmentVariables(VOID
)
1650 SYSTEM_BASIC_INFORMATION BasicInfo
;
1651 SYSTEM_PROCESSOR_INFORMATION ProcessorInfo
;
1652 OBJECT_ATTRIBUTES ObjectAttributes
;
1653 UNICODE_STRING ValueName
, DestinationString
;
1654 HANDLE KeyHandle
, KeyHandle2
;
1657 WCHAR ValueBuffer
[512], ValueBuffer2
[512];
1658 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PVOID
)ValueBuffer
;
1659 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo2
= (PVOID
)ValueBuffer2
;
1661 /* Get system basic information -- we'll need the CPU count */
1662 Status
= NtQuerySystemInformation(SystemBasicInformation
,
1666 if (!NT_SUCCESS(Status
))
1668 /* Bail out on failure */
1669 DPRINT1("SMSS: Unable to query system basic information - %x\n", Status
);
1673 /* Get the processor information, we'll query a bunch of revision info */
1674 Status
= NtQuerySystemInformation(SystemProcessorInformation
,
1676 sizeof(ProcessorInfo
),
1678 if (!NT_SUCCESS(Status
))
1680 /* Bail out on failure */
1681 DPRINT1("SMSS: Unable to query system processor information - %x\n", Status
);
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
,
1691 OBJ_CASE_INSENSITIVE
,
1694 Status
= NtOpenKey(&KeyHandle
, GENERIC_WRITE
, &ObjectAttributes
);
1695 if (!NT_SUCCESS(Status
))
1697 /* Bail out on failure */
1698 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString
, Status
);
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
,
1711 (wcslen(ValueData
) + 1) * sizeof(WCHAR
));
1712 if (!NT_SUCCESS(Status
))
1714 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1715 &ValueName
, Status
);
1720 /* Next, let's write the CPU architecture variable */
1721 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_ARCHITECTURE");
1722 switch (ProcessorInfo
.ProcessorArchitecture
)
1724 /* Pick the correct string that matches the architecture */
1725 case PROCESSOR_ARCHITECTURE_INTEL
:
1729 case PROCESSOR_ARCHITECTURE_AMD64
:
1730 ValueData
= L
"AMD64";
1733 case PROCESSOR_ARCHITECTURE_IA64
:
1734 ValueData
= L
"IA64";
1738 ValueData
= L
"Unknown";
1743 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueData
);
1744 Status
= NtSetValueKey(KeyHandle
,
1749 (wcslen(ValueData
) + 1) * sizeof(WCHAR
));
1750 if (!NT_SUCCESS(Status
))
1752 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1753 &ValueName
, Status
);
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
,
1767 (wcslen(ValueBuffer
) + 1) * sizeof(WCHAR
));
1768 if (!NT_SUCCESS(Status
))
1770 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1771 &ValueName
, Status
);
1776 /* Now open the hardware CPU key */
1777 RtlInitUnicodeString(&DestinationString
,
1778 L
"\\Registry\\Machine\\Hardware\\Description\\System\\"
1779 L
"CentralProcessor\\0");
1780 InitializeObjectAttributes(&ObjectAttributes
,
1782 OBJ_CASE_INSENSITIVE
,
1785 Status
= NtOpenKey(&KeyHandle2
, KEY_READ
, &ObjectAttributes
);
1786 if (!NT_SUCCESS(Status
))
1788 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString
, Status
);
1793 /* So that we can read the identifier out of it... */
1794 RtlInitUnicodeString(&ValueName
, L
"Identifier");
1795 Status
= NtQueryValueKey(KeyHandle2
,
1797 KeyValuePartialInformation
,
1799 sizeof(ValueBuffer
),
1801 if (!NT_SUCCESS(Status
))
1803 NtClose(KeyHandle2
);
1805 DPRINT1("SMSS: Unable to read %wZ\\%wZ - %x\n",
1806 &DestinationString
, &ValueName
, Status
);
1810 /* As well as the vendor... */
1811 RtlInitUnicodeString(&ValueName
, L
"VendorIdentifier");
1812 Status
= NtQueryValueKey(KeyHandle2
,
1814 KeyValuePartialInformation
,
1816 sizeof(ValueBuffer2
),
1818 NtClose(KeyHandle2
);
1819 if (NT_SUCCESS(Status
))
1821 /* To combine it into a single string */
1822 swprintf((PWCHAR
)PartialInfo
->Data
+ wcslen((PWCHAR
)PartialInfo
->Data
),
1824 PartialInfo2
->Data
);
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
,
1835 (wcslen((PWCHAR
)PartialInfo
->Data
) + 1) * sizeof(WCHAR
));
1836 if (!NT_SUCCESS(Status
))
1838 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1839 &ValueName
, Status
);
1844 /* Now let's get the processor architecture */
1845 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_REVISION");
1846 switch (ProcessorInfo
.ProcessorArchitecture
)
1848 /* Check if this is an older Intel CPU */
1849 case PROCESSOR_ARCHITECTURE_INTEL
:
1850 if ((ProcessorInfo
.ProcessorRevision
>> 8) == 0xFF)
1852 /* These guys used a revision + stepping, so get the rev only */
1853 swprintf(ValueBuffer
, L
"%02x", ProcessorInfo
.ProcessorRevision
& 0xFF);
1854 _wcsupr(ValueBuffer
);
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
);
1864 /* And anything else we'll just read the whole revision identifier */
1866 swprintf(ValueBuffer
, L
"%u", ProcessorInfo
.ProcessorRevision
);
1870 /* Write the revision to the registry */
1871 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1872 Status
= NtSetValueKey(KeyHandle
,
1877 (wcslen(ValueBuffer
) + 1) * sizeof(WCHAR
));
1878 if (!NT_SUCCESS(Status
))
1880 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1881 &ValueName
, Status
);
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
,
1895 (wcslen(ValueBuffer
) + 1) * sizeof(WCHAR
));
1896 if (!NT_SUCCESS(Status
))
1898 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1899 &ValueName
, Status
);
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
,
1910 OBJ_CASE_INSENSITIVE
,
1913 Status
= NtOpenKey(&KeyHandle2
, KEY_ALL_ACCESS
, &ObjectAttributes
);
1914 if (NT_SUCCESS(Status
))
1916 /* This was indeed a safeboot, so check what kind of safeboot it was */
1917 RtlInitUnicodeString(&ValueName
, L
"OptionValue");
1918 Status
= NtQueryValueKey(KeyHandle2
,
1920 KeyValuePartialInformation
,
1922 sizeof(ValueBuffer
),
1924 NtClose(KeyHandle2
);
1925 if (NT_SUCCESS(Status
))
1927 /* Convert from the integer value to the correct specifier */
1928 RtlInitUnicodeString(&ValueName
, L
"SAFEBOOT_OPTION");
1929 switch (*(PULONG
)PartialInfo
->Data
)
1932 wcscpy(ValueBuffer
, L
"MINIMAL");
1935 wcscpy(ValueBuffer
, L
"NETWORK");
1938 wcscpy(ValueBuffer
, L
"DSREPAIR");
1942 /* And write it in the environment! */
1943 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1944 Status
= NtSetValueKey(KeyHandle
,
1949 (wcslen(ValueBuffer
) + 1) * sizeof(WCHAR
));
1950 if (!NT_SUCCESS(Status
))
1952 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1953 &ValueName
, Status
);
1960 DPRINT1("SMSS: Failed querying safeboot option = %x\n", Status
);
1964 /* We are all done now */
1966 return STATUS_SUCCESS
;
1971 SmpProcessFileRenames(VOID
)
1973 BOOLEAN OldState
, HavePrivilege
= FALSE
;
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
;
1986 ULONG ValueLength
, Length
;
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
;
1992 // FIXME: Handle SFC-protected file renames!
1993 if (SmpAllowProtectedRenames
)
1994 DPRINT1("SMSS: FIXME: Handle SFC-protected file renames!\n");
1996 /* Process pending files to rename */
1997 Head
= &SmpFileRenameList
;
1998 while (!IsListEmpty(Head
))
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
);
2005 /* Skip past the '@' marker */
2006 if (!(RegEntry
->Value
.Length
) && (*RegEntry
->Name
.Buffer
== L
'@'))
2008 RegEntry
->Name
.Length
-= sizeof(UNICODE_NULL
);
2009 RegEntry
->Name
.Buffer
++;
2012 /* Open the file for delete access */
2013 InitializeObjectAttributes(&ObjectAttributes
,
2015 OBJ_CASE_INSENSITIVE
,
2018 Status
= NtOpenFile(&OtherFileHandle
,
2019 DELETE
| SYNCHRONIZE
,
2022 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2023 FILE_SYNCHRONOUS_IO_NONALERT
);
2024 if (!NT_SUCCESS(Status
)) goto Quickie
;
2026 /* Check if it's a rename or just a delete */
2027 ValueLength
= RegEntry
->Value
.Length
;
2030 /* Just a delete, set up the class, length and buffer */
2031 InformationClass
= FileDispositionInformation
;
2032 Length
= sizeof(DeleteInformation
);
2033 Buffer
= (PFILE_RENAME_INFORMATION
)&DeleteInformation
;
2035 /* Set the delete disposition */
2036 DeleteInformation
.DeleteFile
= TRUE
;
2040 /* This is a rename, setup the class and length */
2041 InformationClass
= FileRenameInformation
;
2042 Length
= ValueLength
+ sizeof(FILE_RENAME_INFORMATION
);
2044 /* Skip past the special markers */
2045 FileName
= RegEntry
->Value
.Buffer
;
2046 if ((*FileName
== L
'!') || (*FileName
== L
'@'))
2049 Length
-= sizeof(UNICODE_NULL
);
2052 /* Now allocate the buffer for the rename information */
2053 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag
, Length
);
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
);
2065 Status
= STATUS_NO_MEMORY
;
2069 /* Check if everything is okay till here */
2070 if (NT_SUCCESS(Status
))
2072 /* Now either rename or delete the file as requested */
2073 Status
= NtSetInformationFile(OtherFileHandle
,
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
)
2085 /* Open the file for write attribute access this time... */
2086 DPRINT("\nSMSS: '%wZ' => '%wZ' failed - Status == %x, Possible readonly target\n",
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
,
2095 OBJ_CASE_INSENSITIVE
,
2098 Status
= NtOpenFile(&FileHandle
,
2099 FILE_WRITE_ATTRIBUTES
| SYNCHRONIZE
,
2102 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2103 FILE_SYNCHRONOUS_IO_NONALERT
);
2104 if (!NT_SUCCESS(Status
))
2106 /* That didn't work, so bail out */
2107 DPRINT1(" SMSS: Open Existing file Failed - Status == %x\n",
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
,
2120 FileBasicInformation
);
2121 NtClose(FileHandle
);
2122 if (!NT_SUCCESS(Status
))
2124 /* That didn't work, bail out */
2125 DPRINT1(" SMSS: Set To NORMAL Failed - Status == %x\n",
2130 /* Now that the file is no longer read-only, delete! */
2131 DPRINT(" SMSS: Set To NORMAL OK\n");
2132 Status
= NtSetInformationFile(OtherFileHandle
,
2136 FileRenameInformation
);
2137 if (!NT_SUCCESS(Status
))
2139 /* That failed too! */
2140 DPRINT1(" SMSS: Re-Rename Failed - Status == %x\n",
2146 DPRINT(" SMSS: Re-Rename Worked OK\n");
2153 /* Close the file handle and check the operation result */
2154 NtClose(OtherFileHandle
);
2156 if (!NT_SUCCESS(Status
))
2158 /* We totally failed */
2159 DPRINT1("SMSS: '%wZ' => '%wZ' failed - Status == %x\n",
2160 &RegEntry
->Name
, &RegEntry
->Value
, Status
);
2162 else if (RegEntry
->Value
.Length
)
2164 /* We succeed with a rename */
2165 DPRINT("SMSS: '%wZ' (renamed to) '%wZ'\n", &RegEntry
->Name
, &RegEntry
->Value
);
2169 /* We succeeded with a delete */
2170 DPRINT("SMSS: '%wZ' (deleted)\n", &RegEntry
->Name
);
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
);
2179 /* Put back the restore privilege if we had requested it, and return */
2180 if (HavePrivilege
) RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, FALSE
, FALSE
, &OldState
);
2186 SmpLoadDataFromRegistry(OUT PUNICODE_STRING InitialCommand
)
2189 PLIST_ENTRY Head
, NextEntry
;
2190 PSMP_REGISTRY_VALUE RegEntry
;
2191 PVOID OriginalEnvironment
;
2192 ULONG MuSessionId
= 0;
2193 OBJECT_ATTRIBUTES ObjectAttributes
;
2195 UNICODE_STRING DestinationString
;
2197 /* Initialize the keywords we'll be looking for */
2198 RtlInitUnicodeString(&SmpDebugKeyword
, L
"debug");
2199 RtlInitUnicodeString(&SmpASyncKeyword
, L
"async");
2200 RtlInitUnicodeString(&SmpAutoChkKeyword
, L
"autocheck");
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();
2216 /* Initialize the SMSS environment */
2217 Status
= RtlCreateEnvironment(TRUE
, &SmpDefaultEnvironment
);
2218 if (!NT_SUCCESS(Status
))
2220 /* Fail if there was a problem */
2221 DPRINT1("SMSS: Unable to allocate default environment - Status == %X\n",
2223 SMSS_CHECKPOINT(RtlCreateEnvironment
, Status
);
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
,
2233 OBJ_CASE_INSENSITIVE
,
2236 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
2237 if (NT_SUCCESS(Status
))
2239 /* If the key exists, we were */
2244 /* Print out if this is the case */
2245 if (MiniNTBoot
) DPRINT("SMSS: !!! MiniNT Boot !!!\n");
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
,
2253 OBJ_CASE_INSENSITIVE
,
2256 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
2257 if (NT_SUCCESS(Status
))
2259 /* Delete the value if we found it */
2260 RtlInitUnicodeString(&DestinationString
, L
"SAFEBOOT_OPTION");
2261 NtDeleteValueKey(KeyHandle
, &DestinationString
);
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
,
2270 SmpRegistryConfigurationTable
,
2273 SmpDefaultEnvironment
= NtCurrentPeb()->ProcessParameters
->Environment
;
2274 NtCurrentPeb()->ProcessParameters
->Environment
= OriginalEnvironment
;
2275 if (!NT_SUCCESS(Status
))
2277 /* We failed somewhere in registry initialization, which is bad... */
2278 DPRINT1("SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status
);
2279 SMSS_CHECKPOINT(RtlQueryRegistryValues
, Status
);
2283 /* Now we can start acting on the registry settings. First to DOS devices */
2284 Status
= SmpInitializeDosDevices();
2285 if (!NT_SUCCESS(Status
))
2288 DPRINT1("SMSS: Unable to initialize DosDevices configuration - Status == %lx\n",
2290 SMSS_CHECKPOINT(SmpInitializeDosDevices
, Status
);
2294 /* Next create the session directory... */
2295 RtlInitUnicodeString(&DestinationString
, L
"\\Sessions");
2296 InitializeObjectAttributes(&ObjectAttributes
,
2298 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
2300 SmpPrimarySecurityDescriptor
);
2301 Status
= NtCreateDirectoryObject(&SmpSessionsObjectDirectory
,
2302 DIRECTORY_ALL_ACCESS
,
2304 if (!NT_SUCCESS(Status
))
2307 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
2308 &DestinationString
, Status
);
2309 SMSS_CHECKPOINT(NtCreateDirectoryObject
, Status
);
2313 /* Next loop all the boot execute binaries */
2314 Head
= &SmpBootExecuteList
;
2315 while (!IsListEmpty(Head
))
2317 /* Remove each one from the list */
2318 NextEntry
= RemoveHeadList(Head
);
2321 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2322 SmpExecuteCommand(&RegEntry
->Name
, 0, NULL
, 0);
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
);
2330 /* Now do any pending file rename operations... */
2331 if (!MiniNTBoot
) SmpProcessFileRenames();
2333 /* And initialize known DLLs... */
2334 Status
= SmpInitializeKnownDlls();
2335 if (!NT_SUCCESS(Status
))
2337 /* Fail if that didn't work */
2338 DPRINT1("SMSS: Unable to initialize KnownDll configuration - Status == %lx\n",
2340 SMSS_CHECKPOINT(SmpInitializeKnownDlls
, Status
);
2344 /* Create the needed page files */
2347 /* Loop every page file */
2348 Head
= &SmpPagingFileList
;
2349 while (!IsListEmpty(Head
))
2351 /* Remove each one from the list */
2352 NextEntry
= RemoveHeadList(Head
);
2354 /* Create the descriptor for it */
2355 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2356 SmpCreatePagingFileDescriptor(&RegEntry
->Name
);
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
);
2364 /* Now create all the paging files for the descriptors that we have */
2365 SmpCreatePagingFiles();
2368 /* Tell Cm it's now safe to fully enable write access to the registry */
2369 NtInitializeRegistry(CM_BOOT_FLAG_SMSS
);
2371 /* Create all the system-based environment variables for later inheriting */
2372 Status
= SmpCreateDynamicEnvironmentVariables();
2373 if (!NT_SUCCESS(Status
))
2375 /* Handle failure */
2376 SMSS_CHECKPOINT(SmpCreateDynamicEnvironmentVariables
, Status
);
2380 /* And finally load all the subsystems for our first session! */
2381 Status
= SmpLoadSubSystemsForMuSession(&MuSessionId
,
2382 &SmpWindowsSubSysProcessId
,
2384 ASSERT(MuSessionId
== 0);
2385 if (!NT_SUCCESS(Status
)) SMSS_CHECKPOINT(SmpLoadSubSystemsForMuSession
, Status
);
2391 SmpInit(IN PUNICODE_STRING InitialCommand
,
2392 OUT PHANDLE ProcessHandle
)
2394 NTSTATUS Status
, Status2
;
2395 OBJECT_ATTRIBUTES ObjectAttributes
;
2396 UNICODE_STRING PortName
, EventName
;
2397 HANDLE EventHandle
, PortHandle
;
2398 ULONG HardErrorMode
;
2400 /* Create the SMSS Heap */
2401 SmBaseTag
= RtlCreateTagHeap(RtlGetProcessHeap(),
2405 SmpHeap
= RtlGetProcessHeap();
2407 /* Enable hard errors */
2408 HardErrorMode
= TRUE
;
2409 NtSetInformationProcess(NtCurrentProcess(),
2410 ProcessDefaultHardErrorMode
,
2412 sizeof(HardErrorMode
));
2414 /* Initialize the subsystem list and the session list, plus their locks */
2415 RtlInitializeCriticalSection(&SmpKnownSubSysLock
);
2416 InitializeListHead(&SmpKnownSubSysHead
);
2417 RtlInitializeCriticalSection(&SmpSessionListLock
);
2418 InitializeListHead(&SmpSessionListHead
);
2420 /* Initialize the process list */
2421 InitializeListHead(&NativeProcessList
);
2423 /* Initialize session parameters */
2424 SmpNextSessionId
= 1;
2425 SmpNextSessionIdScanMode
= 0;
2426 SmpDbgSsLoaded
= FALSE
;
2428 /* Create the initial security descriptors */
2429 Status
= SmpCreateSecurityDescriptors(TRUE
);
2430 if (!NT_SUCCESS(Status
))
2433 SMSS_CHECKPOINT(SmpCreateSecurityDescriptors
, Status
);
2437 /* Initialize subsystem names */
2438 RtlInitUnicodeString(&SmpSubsystemName
, L
"NT-Session Manager");
2439 RtlInitUnicodeString(&PosixName
, L
"POSIX");
2440 RtlInitUnicodeString(&Os2Name
, L
"OS2");
2442 /* Create the SM API Port */
2443 RtlInitUnicodeString(&PortName
, L
"\\SmApiPort");
2444 InitializeObjectAttributes(&ObjectAttributes
, &PortName
, 0, NULL
, SmpApiPortSecurityDescriptor
);
2445 Status
= NtCreatePort(&PortHandle
,
2447 sizeof(SB_CONNECTION_INFO
),
2449 sizeof(SB_API_MSG
) * 32);
2450 ASSERT(NT_SUCCESS(Status
));
2451 SmpDebugPort
= PortHandle
;
2453 /* Create two SM API threads */
2454 Status
= RtlCreateUserThread(NtCurrentProcess(),
2464 ASSERT(NT_SUCCESS(Status
));
2465 Status
= RtlCreateUserThread(NtCurrentProcess(),
2475 ASSERT(NT_SUCCESS(Status
));
2477 /* Create the write event that autochk can set after running */
2478 RtlInitUnicodeString(&EventName
, L
"\\Device\\VolumesSafeForWriteAccess");
2479 InitializeObjectAttributes(&ObjectAttributes
,
2484 Status2
= NtCreateEvent(&EventHandle
,
2489 if (!NT_SUCCESS(Status2
))
2491 /* Should never really fail */
2492 DPRINT1("SMSS: Unable to create %wZ event - Status == %lx\n",
2493 &EventName
, Status2
);
2494 ASSERT(NT_SUCCESS(Status2
));
2497 /* Now initialize everything else based on the registry parameters */
2498 Status
= SmpLoadDataFromRegistry(InitialCommand
);
2499 if (NT_SUCCESS(Status
))
2501 /* Autochk should've run now. Set the event and save the CSRSS handle */
2502 *ProcessHandle
= SmpWindowsSubSysProcess
;
2503 NtSetEvent(EventHandle
, 0);
2504 NtClose(EventHandle
);