2 * PROJECT: ReactOS Windows-Compatible Session Manager
3 * LICENSE: BSD 2-Clause License
4 * FILE: base/system/smss/smss.c
5 * PURPOSE: Main SMSS Code
6 * PROGRAMMERS: Alex Ionescu
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 UNICODE_STRING SmpSubsystemName
, PosixName
, Os2Name
;
18 LIST_ENTRY SmpBootExecuteList
, SmpSetupExecuteList
, SmpPagingFileList
;
19 LIST_ENTRY SmpDosDevicesList
, SmpFileRenameList
, SmpKnownDllsList
;
20 LIST_ENTRY SmpExcludeKnownDllsList
, SmpSubSystemList
, SmpSubSystemsToLoad
;
21 LIST_ENTRY SmpSubSystemsToDefer
, SmpExecuteList
, NativeProcessList
;
25 HANDLE SmpDebugPort
, SmpDosDevicesObjectDirectory
;
26 PWCHAR SmpDefaultEnvironment
, SmpDefaultLibPathBuffer
;
27 UNICODE_STRING SmpKnownDllPath
, SmpDefaultLibPath
;
28 ULONG SmpCalledConfigEnv
;
30 ULONG SmpInitProgressByLine
;
31 NTSTATUS SmpInitReturnStatus
;
32 PVOID SmpInitLastCall
;
34 SECURITY_DESCRIPTOR SmpPrimarySDBody
, SmpLiberalSDBody
, SmpKnownDllsSDBody
;
35 SECURITY_DESCRIPTOR SmpApiPortSDBody
;
36 PISECURITY_DESCRIPTOR SmpPrimarySecurityDescriptor
, SmpLiberalSecurityDescriptor
;
37 PISECURITY_DESCRIPTOR SmpKnownDllsSecurityDescriptor
, SmpApiPortSecurityDescriptor
;
39 ULONG SmpAllowProtectedRenames
, SmpProtectionMode
= 1;
42 #define SMSS_CHECKPOINT(x, y) \
44 SmpInitProgressByLine = __LINE__; \
45 SmpInitReturnStatus = (y); \
46 SmpInitLastCall = (x); \
49 /* REGISTRY CONFIGURATION *****************************************************/
53 SmpSaveRegistryValue(IN PLIST_ENTRY ListAddress
,
58 PSMP_REGISTRY_VALUE RegEntry
;
59 UNICODE_STRING NameString
, ValueString
;
60 ANSI_STRING AnsiValueString
;
61 PLIST_ENTRY NextEntry
;
63 /* Convert to unicode strings */
64 RtlInitUnicodeString(&NameString
, Name
);
65 RtlInitUnicodeString(&ValueString
, Value
);
67 /* In case this is the first value, initialize a new list/structure */
70 /* Check if we should do a duplicate check */
73 /* Loop the current list */
74 NextEntry
= ListAddress
->Flink
;
75 while (NextEntry
!= ListAddress
)
78 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
80 /* Check if the value name matches */
81 if (!RtlCompareUnicodeString(&RegEntry
->Name
, &NameString
, TRUE
))
83 /* Check if the value is the exact same thing */
84 if (!RtlCompareUnicodeString(&RegEntry
->Value
, &ValueString
, TRUE
))
86 /* Fail -- the same setting is being set twice */
87 return STATUS_OBJECT_NAME_EXISTS
;
90 /* We found the list, and this isn't a duplicate value */
94 /* This wasn't a match, keep going */
95 NextEntry
= NextEntry
->Flink
;
100 /* Are we adding on, or creating a new entry */
103 /* A new entry -- allocate it */
104 RegEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
106 NameString
.MaximumLength
+
107 sizeof(SMP_REGISTRY_VALUE
));
108 if (!RegEntry
) return STATUS_NO_MEMORY
;
110 /* Initialize the list and set all values to NULL */
111 InitializeListHead(&RegEntry
->Entry
);
112 RegEntry
->AnsiValue
= NULL
;
113 RegEntry
->Value
.Buffer
= NULL
;
115 /* Copy and initialize the value name */
116 RegEntry
->Name
.Buffer
= (PWCHAR
)(RegEntry
+ 1);
117 RegEntry
->Name
.Length
= NameString
.Length
;
118 RegEntry
->Name
.MaximumLength
= NameString
.MaximumLength
;
119 RtlCopyMemory(RegEntry
->Name
.Buffer
,
121 NameString
.MaximumLength
);
123 /* Add this entry into the list */
124 InsertTailList(ListAddress
, &RegEntry
->Entry
);
127 /* Did we have an old value buffer? */
128 if (RegEntry
->Value
.Buffer
)
131 ASSERT(RegEntry
->Value
.Length
!= 0);
132 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
135 /* Is there no value associated? */
138 /* We're done here */
139 RtlInitUnicodeString(&RegEntry
->Value
, NULL
);
140 return STATUS_SUCCESS
;
143 /* There is a value, so allocate a buffer for it */
144 RegEntry
->Value
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
146 ValueString
.MaximumLength
);
147 if (!RegEntry
->Value
.Buffer
)
149 /* Out of memory, undo */
150 RemoveEntryList(&RegEntry
->Entry
);
151 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
152 return STATUS_NO_MEMORY
;
155 /* Copy the value into the entry */
156 RegEntry
->Value
.Length
= ValueString
.Length
;
157 RegEntry
->Value
.MaximumLength
= ValueString
.MaximumLength
;
158 RtlCopyMemory(RegEntry
->Value
.Buffer
,
160 ValueString
.MaximumLength
);
162 /* Now allocate memory for an ANSI copy of it */
163 RegEntry
->AnsiValue
= RtlAllocateHeap(RtlGetProcessHeap(),
165 (ValueString
.Length
/ sizeof(WCHAR
)) +
167 if (!RegEntry
->AnsiValue
)
169 /* Out of memory, undo */
170 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
171 RemoveEntryList(&RegEntry
->Entry
);
172 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
173 return STATUS_NO_MEMORY
;
176 /* Convert the Unicode value string and return success */
177 RtlInitEmptyAnsiString(&AnsiValueString
,
179 (ValueString
.Length
/ sizeof(WCHAR
)) +
181 RtlUnicodeStringToAnsiString(&AnsiValueString
, &ValueString
, FALSE
);
182 return STATUS_SUCCESS
;
187 SmpFindRegistryValue(IN PLIST_ENTRY List
,
190 PSMP_REGISTRY_VALUE RegEntry
;
191 UNICODE_STRING ValueString
;
192 PLIST_ENTRY NextEntry
;
194 /* Initialize the value name sting */
195 RtlInitUnicodeString(&ValueString
, ValueName
);
198 NextEntry
= List
->Flink
;
199 while (NextEntry
!= List
)
202 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
204 /* Check if the value name matches */
205 if (!RtlCompareUnicodeString(&RegEntry
->Name
, &ValueString
, TRUE
)) break;
207 /* It doesn't, move on */
208 NextEntry
= NextEntry
->Flink
;
211 /* If we looped back, return NULL, otherwise return the entry we found */
212 if (NextEntry
== List
) RegEntry
= NULL
;
218 SmpConfigureProtectionMode(IN PWSTR ValueName
,
221 IN ULONG ValueLength
,
223 IN PVOID EntryContext
)
225 /* Make sure the value is valid */
226 if (ValueLength
== sizeof(ULONG
))
229 SmpProtectionMode
= *(PULONG
)ValueData
;
233 /* Default is to protect stuff */
234 SmpProtectionMode
= 1;
237 /* Recreate the security descriptors to take into account security mode */
238 SmpCreateSecurityDescriptors(FALSE
);
239 DPRINT("SmpProtectionMode: %lu\n", SmpProtectionMode
);
240 return STATUS_SUCCESS
;
245 SmpConfigureAllowProtectedRenames(IN PWSTR ValueName
,
248 IN ULONG ValueLength
,
250 IN PVOID EntryContext
)
252 /* Make sure the value is valid */
253 if (ValueLength
== sizeof(ULONG
))
256 SmpAllowProtectedRenames
= *(PULONG
)ValueData
;
260 /* Default is to not allow protected renames */
261 SmpAllowProtectedRenames
= 0;
264 DPRINT("SmpAllowProtectedRenames: %lu\n", SmpAllowProtectedRenames
);
265 return STATUS_SUCCESS
;
270 SmpConfigureObjectDirectories(IN PWSTR ValueName
,
273 IN ULONG ValueLength
,
275 IN PVOID EntryContext
)
277 PISECURITY_DESCRIPTOR SecDescriptor
;
279 OBJECT_ATTRIBUTES ObjectAttributes
;
281 UNICODE_STRING RpcString
, WindowsString
, SearchString
;
282 PWCHAR SourceString
= ValueData
;
284 /* Initialize the two strings we will be looking for */
285 RtlInitUnicodeString(&RpcString
, L
"\\RPC Control");
286 RtlInitUnicodeString(&WindowsString
, L
"\\Windows");
288 /* Loop the registry data we received */
289 while (*SourceString
)
291 /* Assume primary SD for most objects */
292 RtlInitUnicodeString(&SearchString
, SourceString
);
293 SecDescriptor
= SmpPrimarySecurityDescriptor
;
295 /* But for these two always set the liberal descriptor */
296 if ((RtlEqualUnicodeString(&SearchString
, &RpcString
, TRUE
)) ||
297 (RtlEqualUnicodeString(&SearchString
, &WindowsString
, TRUE
)))
299 SecDescriptor
= SmpLiberalSecurityDescriptor
;
302 /* Create the requested directory with the requested descriptor */
303 InitializeObjectAttributes(&ObjectAttributes
,
305 OBJ_CASE_INSENSITIVE
|
310 DPRINT("Creating: %wZ directory\n", &SearchString
);
311 Status
= NtCreateDirectoryObject(&DirHandle
,
312 DIRECTORY_ALL_ACCESS
,
314 if (!NT_SUCCESS(Status
))
317 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
318 &SearchString
, Status
);
322 /* It worked, now close the handle */
326 /* Move to the next requested object */
327 while (*SourceString
++);
331 return STATUS_SUCCESS
;
336 SmpConfigureMemoryMgmt(IN PWSTR ValueName
,
339 IN ULONG ValueLength
,
341 IN PVOID EntryContext
)
343 /* Save this is into a list */
344 return SmpSaveRegistryValue(EntryContext
, ValueData
, NULL
, TRUE
);
349 SmpConfigureFileRenames(IN PWSTR ValueName
,
352 IN ULONG ValueLength
,
354 IN PVOID EntryContext
)
357 static PWCHAR Canary
;
359 /* Check if this is the second call */
362 /* Save the data into the list */
363 DPRINT1("Renamed file: %S-%S\n", Canary
, ValueData
);
364 Status
= SmpSaveRegistryValue(EntryContext
, Canary
, ValueData
, FALSE
);
369 /* This it the first call, do nothing until we get the second call */
371 Status
= STATUS_SUCCESS
;
374 /* Return the status */
380 SmpConfigureExcludeKnownDlls(IN PWSTR ValueName
,
383 IN ULONG ValueLength
,
385 IN PVOID EntryContext
)
390 /* Make sure the value type is valid */
391 if ((ValueType
== REG_MULTI_SZ
) || (ValueType
== REG_SZ
))
393 /* Keep going for each DLL in the list */
397 /* Add this to the linked list */
398 DPRINT("Excluded DLL: %S\n", DllName
);
399 Status
= SmpSaveRegistryValue(EntryContext
, DllName
, NULL
, TRUE
);
401 /* Bail out on failure or if only one DLL name was present */
402 if (!(NT_SUCCESS(Status
)) || (ValueType
== REG_SZ
)) return Status
;
404 /* Otherwise, move to the next DLL name */
410 return STATUS_SUCCESS
;
415 SmpConfigureDosDevices(IN PWSTR ValueName
,
418 IN ULONG ValueLength
,
420 IN PVOID EntryContext
)
422 /* Save into linked list */
423 return SmpSaveRegistryValue(EntryContext
, ValueName
, ValueData
, TRUE
);
428 SmpInitializeKnownDllPath(IN PUNICODE_STRING DllPath
,
434 /* Allocate the buffer */
435 DllPath
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag
, Length
);
438 /* Fill out the rest of the string */
439 DllPath
->MaximumLength
= (USHORT
)Length
;
440 DllPath
->Length
= (USHORT
)Length
- sizeof(UNICODE_NULL
);
442 /* Copy the actual path and return success */
443 RtlCopyMemory(DllPath
->Buffer
, Buffer
, Length
);
444 Status
= STATUS_SUCCESS
;
448 /* Fail with out of memory code */
449 Status
= STATUS_NO_MEMORY
;
458 SmpConfigureKnownDlls(IN PWSTR ValueName
,
461 IN ULONG ValueLength
,
463 IN PVOID EntryContext
)
465 /* Check which value is being set */
466 if (_wcsicmp(ValueName
, L
"DllDirectory") == 0)
468 /* This is the directory, initialize it */
469 DPRINT("KnownDll Path: %S\n", ValueData
);
470 return SmpInitializeKnownDllPath(&SmpKnownDllPath
, ValueData
, ValueLength
);
474 /* Add to the linked list -- this is a file */
475 return SmpSaveRegistryValue(EntryContext
, ValueName
, ValueData
, TRUE
);
481 SmpConfigureEnvironment(IN PWSTR ValueName
,
484 IN ULONG ValueLength
,
486 IN PVOID EntryContext
)
489 UNICODE_STRING ValueString
, DataString
;
491 /* Convert the strings into UNICODE_STRING and set the variable defined */
492 RtlInitUnicodeString(&ValueString
, ValueName
);
493 RtlInitUnicodeString(&DataString
, ValueData
);
494 DPRINT("Setting %wZ = %wZ\n", &ValueString
, &DataString
);
495 Status
= RtlSetEnvironmentVariable(0, &ValueString
, &DataString
);
496 if (!NT_SUCCESS(Status
))
498 DPRINT1("SMSS: 'SET %wZ = %wZ' failed - Status == %lx\n",
499 &ValueString
, &DataString
, Status
);
503 /* Check if the path is being set, and wait for the second instantiation */
504 if ((_wcsicmp(ValueName
, L
"Path") == 0) && (++SmpCalledConfigEnv
== 2))
506 /* Allocate the path buffer */
507 SmpDefaultLibPathBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
510 if (!SmpDefaultLibPathBuffer
) return STATUS_NO_MEMORY
;
512 /* Copy the data into it and create the UNICODE_STRING to hold it */
513 RtlCopyMemory(SmpDefaultLibPathBuffer
, ValueData
, ValueLength
);
514 RtlInitUnicodeString(&SmpDefaultLibPath
, SmpDefaultLibPathBuffer
);
518 return STATUS_SUCCESS
;
523 SmpConfigureSubSystems(IN PWSTR ValueName
,
526 IN ULONG ValueLength
,
528 IN PVOID EntryContext
)
530 PSMP_REGISTRY_VALUE RegEntry
;
531 PWCHAR SubsystemName
;
533 /* Is this a required or optional subsystem? */
534 if ((_wcsicmp(ValueName
, L
"Required") != 0) &&
535 (_wcsicmp(ValueName
, L
"Optional") != 0))
537 /* It isn't, is this the PSI flag? */
538 if ((_wcsicmp(ValueName
, L
"PosixSingleInstance") != 0) ||
539 (ValueType
!= REG_DWORD
))
541 /* It isn't, must be a subsystem entry, add it to the list */
542 DPRINT("Subsystem entry: %S-%S\n", ValueName
, ValueData
);
543 return SmpSaveRegistryValue(EntryContext
, ValueName
, ValueData
, TRUE
);
546 /* This was the PSI flag, save it and exit */
547 RegPosixSingleInstance
= TRUE
;
548 return STATUS_SUCCESS
;
551 /* This should be one of the required/optional lists. Is the type valid? */
552 if (ValueType
== REG_MULTI_SZ
)
554 /* It is, get the first subsystem */
555 SubsystemName
= ValueData
;
556 while (*SubsystemName
)
558 /* We should have already put it into the list when we found it */
559 DPRINT("Found subsystem: %S\n", SubsystemName
);
560 RegEntry
= SmpFindRegistryValue(EntryContext
, SubsystemName
);
563 /* This subsystem doesn't exist, so skip it */
564 DPRINT1("SMSS: Invalid subsystem name - %ws\n", SubsystemName
);
568 /* Found it -- remove it from the main list */
569 RemoveEntryList(&RegEntry
->Entry
);
571 /* Figure out which list to put it in */
572 if (_wcsicmp(ValueName
, L
"Required") == 0)
574 /* Put it into the required list */
575 DPRINT("Required\n");
576 InsertTailList(&SmpSubSystemsToLoad
, &RegEntry
->Entry
);
580 /* Put it into the optional list */
581 DPRINT("Optional\n");
582 InsertTailList(&SmpSubSystemsToDefer
, &RegEntry
->Entry
);
586 /* Move to the next name */
587 while (*SubsystemName
++);
592 return STATUS_SUCCESS
;
595 RTL_QUERY_REGISTRY_TABLE
596 SmpRegistryConfigurationTable
[] =
599 SmpConfigureProtectionMode
,
609 SmpConfigureAllowProtectedRenames
,
610 0, //RTL_QUERY_REGISTRY_DELETE,
611 L
"AllowProtectedRenames",
619 SmpConfigureObjectDirectories
,
621 L
"ObjectDirectories",
624 L
"\\Windows\0\\RPC Control\0",
629 SmpConfigureMemoryMgmt
,
634 L
"autocheck AutoChk.exe *\0",
639 SmpConfigureMemoryMgmt
,
640 RTL_QUERY_REGISTRY_TOPKEY
,
642 &SmpSetupExecuteList
,
649 SmpConfigureFileRenames
,
650 0, //RTL_QUERY_REGISTRY_DELETE,
651 L
"PendingFileRenameOperations",
659 SmpConfigureFileRenames
,
660 0, //RTL_QUERY_REGISTRY_DELETE,
661 L
"PendingFileRenameOperations2",
669 SmpConfigureExcludeKnownDlls
,
671 L
"ExcludeFromKnownDlls",
672 &SmpExcludeKnownDllsList
,
680 RTL_QUERY_REGISTRY_SUBKEY
,
681 L
"Memory Management",
689 SmpConfigureMemoryMgmt
,
694 L
"?:\\pagefile.sys\0",
699 SmpConfigureDosDevices
,
700 RTL_QUERY_REGISTRY_SUBKEY
,
709 SmpConfigureKnownDlls
,
710 RTL_QUERY_REGISTRY_SUBKEY
,
719 SmpConfigureEnvironment
,
720 RTL_QUERY_REGISTRY_SUBKEY
,
729 SmpConfigureSubSystems
,
730 RTL_QUERY_REGISTRY_SUBKEY
,
739 SmpConfigureSubSystems
,
740 RTL_QUERY_REGISTRY_NOEXPAND
,
749 SmpConfigureSubSystems
,
750 RTL_QUERY_REGISTRY_NOEXPAND
,
759 SmpConfigureSubSystems
,
769 SmpConfigureMemoryMgmt
,
770 RTL_QUERY_REGISTRY_TOPKEY
,
781 /* FUNCTIONS ******************************************************************/
785 SmpTranslateSystemPartitionInformation(VOID
)
788 UNICODE_STRING UnicodeString
, LinkTarget
, SearchString
, SystemPartition
;
789 OBJECT_ATTRIBUTES ObjectAttributes
;
790 HANDLE KeyHandle
, LinkHandle
;
791 CHAR ValueBuffer
[512 + sizeof(KEY_VALUE_PARTIAL_INFORMATION
)];
792 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PVOID
)ValueBuffer
;
793 ULONG Length
, Context
;
794 CHAR DirInfoBuffer
[512 + sizeof(OBJECT_DIRECTORY_INFORMATION
)];
795 POBJECT_DIRECTORY_INFORMATION DirInfo
= (PVOID
)DirInfoBuffer
;
796 WCHAR LinkBuffer
[MAX_PATH
];
798 /* Open the setup key */
799 RtlInitUnicodeString(&UnicodeString
, L
"\\Registry\\Machine\\System\\Setup");
800 InitializeObjectAttributes(&ObjectAttributes
,
802 OBJ_CASE_INSENSITIVE
,
805 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
806 if (!NT_SUCCESS(Status
))
808 DPRINT1("SMSS: can't open system setup key for reading: 0x%x\n", Status
);
812 /* Query the system partition */
813 RtlInitUnicodeString(&UnicodeString
, L
"SystemPartition");
814 Status
= NtQueryValueKey(KeyHandle
,
816 KeyValuePartialInformation
,
821 if (!NT_SUCCESS(Status
))
823 DPRINT1("SMSS: can't query SystemPartition value: 0x%x\n", Status
);
827 /* Initialize the system partition string string */
828 RtlInitUnicodeString(&SystemPartition
, (PWCHAR
)PartialInfo
->Data
);
830 /* Enumerate the directory looking for the symbolic link string */
831 RtlInitUnicodeString(&SearchString
, L
"SymbolicLink");
832 RtlInitEmptyUnicodeString(&LinkTarget
, LinkBuffer
, sizeof(LinkBuffer
));
833 Status
= NtQueryDirectoryObject(SmpDosDevicesObjectDirectory
,
835 sizeof(DirInfoBuffer
),
840 if (!NT_SUCCESS(Status
))
842 DPRINT1("SMSS: can't find drive letter for system partition\n");
846 /* Keep searching until we find it */
850 if ((RtlEqualUnicodeString(&DirInfo
->TypeName
, &SearchString
, TRUE
)) &&
851 (DirInfo
->Name
.Length
== 2 * sizeof(WCHAR
)) &&
852 (DirInfo
->Name
.Buffer
[1] == L
':'))
854 /* Looks like we found it, open the link to get its target */
855 InitializeObjectAttributes(&ObjectAttributes
,
857 OBJ_CASE_INSENSITIVE
,
858 SmpDosDevicesObjectDirectory
,
860 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
861 SYMBOLIC_LINK_ALL_ACCESS
,
863 if (NT_SUCCESS(Status
))
865 /* Open worked, query the target now */
866 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
871 /* Check if it matches the string we had found earlier */
872 if ((NT_SUCCESS(Status
)) &&
873 ((RtlEqualUnicodeString(&SystemPartition
,
876 ((RtlPrefixUnicodeString(&SystemPartition
,
879 (LinkTarget
.Buffer
[SystemPartition
.Length
/ sizeof(WCHAR
)] == L
'\\'))))
887 /* Couldn't find it, try again */
888 Status
= NtQueryDirectoryObject(SmpDosDevicesObjectDirectory
,
890 sizeof(DirInfoBuffer
),
895 } while (NT_SUCCESS(Status
));
896 if (!NT_SUCCESS(Status
))
898 DPRINT1("SMSS: can't find drive letter for system partition\n");
902 /* Open the setup key again, for full access this time */
903 RtlInitUnicodeString(&UnicodeString
,
904 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup");
905 InitializeObjectAttributes(&ObjectAttributes
,
907 OBJ_CASE_INSENSITIVE
,
910 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
911 if (!NT_SUCCESS(Status
))
913 DPRINT1("SMSS: can't open software setup key for writing: 0x%x\n",
918 /* Wrap up the end of the link buffer */
919 wcsncpy(LinkBuffer
, DirInfo
->Name
.Buffer
, 2);
920 LinkBuffer
[2] = L
'\\';
921 LinkBuffer
[3] = L
'\0';
923 /* Now set this as the "BootDir" */
924 RtlInitUnicodeString(&UnicodeString
, L
"BootDir");
925 Status
= NtSetValueKey(KeyHandle
,
931 if (!NT_SUCCESS(Status
))
933 DPRINT1("SMSS: couldn't write BootDir value: 0x%x\n", Status
);
940 SmpCreateSecurityDescriptors(IN BOOLEAN InitialCall
)
943 PSID WorldSid
= NULL
, AdminSid
= NULL
, SystemSid
= NULL
;
944 PSID RestrictedSid
= NULL
, OwnerSid
= NULL
;
945 SID_IDENTIFIER_AUTHORITY WorldAuthority
= {SECURITY_WORLD_SID_AUTHORITY
};
946 SID_IDENTIFIER_AUTHORITY NtAuthority
= {SECURITY_NT_AUTHORITY
};
947 SID_IDENTIFIER_AUTHORITY CreatorAuthority
= {SECURITY_CREATOR_SID_AUTHORITY
};
948 ULONG AclLength
, SidLength
;
951 BOOLEAN ProtectionRequired
= FALSE
;
953 /* Check if this is the first call */
956 /* Create and set the primary descriptor */
957 SmpPrimarySecurityDescriptor
= &SmpPrimarySDBody
;
958 Status
= RtlCreateSecurityDescriptor(SmpPrimarySecurityDescriptor
,
959 SECURITY_DESCRIPTOR_REVISION
);
960 ASSERT(NT_SUCCESS(Status
));
961 Status
= RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor
,
965 ASSERT(NT_SUCCESS(Status
));
967 /* Create and set the liberal descriptor */
968 SmpLiberalSecurityDescriptor
= &SmpLiberalSDBody
;
969 Status
= RtlCreateSecurityDescriptor(SmpLiberalSecurityDescriptor
,
970 SECURITY_DESCRIPTOR_REVISION
);
971 ASSERT(NT_SUCCESS(Status
));
972 Status
= RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor
,
976 ASSERT(NT_SUCCESS(Status
));
978 /* Create and set the \KnownDlls descriptor */
979 SmpKnownDllsSecurityDescriptor
= &SmpKnownDllsSDBody
;
980 Status
= RtlCreateSecurityDescriptor(SmpKnownDllsSecurityDescriptor
,
981 SECURITY_DESCRIPTOR_REVISION
);
982 ASSERT(NT_SUCCESS(Status
));
983 Status
= RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor
,
987 ASSERT(NT_SUCCESS(Status
));
989 /* Create and Set the \ApiPort descriptor */
990 SmpApiPortSecurityDescriptor
= &SmpApiPortSDBody
;
991 Status
= RtlCreateSecurityDescriptor(SmpApiPortSecurityDescriptor
,
992 SECURITY_DESCRIPTOR_REVISION
);
993 ASSERT(NT_SUCCESS(Status
));
994 Status
= RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor
,
998 ASSERT(NT_SUCCESS(Status
));
1001 /* Check if protection was requested in the registry (on by default) */
1002 if (SmpProtectionMode
& 1) ProtectionRequired
= TRUE
;
1004 /* Exit if there's nothing to do */
1005 if (!(InitialCall
|| ProtectionRequired
)) return STATUS_SUCCESS
;
1007 /* Build the world SID */
1008 Status
= RtlAllocateAndInitializeSid(&WorldAuthority
, 1,
1010 0, 0, 0, 0, 0, 0, 0,
1012 if (!NT_SUCCESS(Status
))
1018 /* Build the admin SID */
1019 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 2,
1020 SECURITY_BUILTIN_DOMAIN_RID
,
1021 DOMAIN_ALIAS_RID_ADMINS
,
1024 if (!NT_SUCCESS(Status
))
1030 /* Build the owner SID */
1031 Status
= RtlAllocateAndInitializeSid(&CreatorAuthority
, 1,
1032 SECURITY_CREATOR_OWNER_RID
,
1033 0, 0, 0, 0, 0, 0, 0,
1035 if (!NT_SUCCESS(Status
))
1041 /* Build the restricted SID */
1042 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 1,
1043 SECURITY_RESTRICTED_CODE_RID
,
1044 0, 0, 0, 0, 0, 0, 0,
1046 if (!NT_SUCCESS(Status
))
1048 RestrictedSid
= NULL
;
1052 /* Build the system SID */
1053 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 1,
1054 SECURITY_LOCAL_SYSTEM_RID
,
1055 0, 0, 0, 0, 0, 0, 0,
1057 if (!NT_SUCCESS(Status
))
1063 /* Now check if we're creating the core descriptors */
1066 /* We're skipping NextAcl so we have to do this here */
1067 SidLength
= RtlLengthSid(WorldSid
) + RtlLengthSid(RestrictedSid
) + RtlLengthSid(AdminSid
);
1072 /* Allocate an ACL with two ACEs with two SIDs each */
1073 SidLength
= RtlLengthSid(SystemSid
) + RtlLengthSid(AdminSid
);
1074 AclLength
= sizeof(ACL
) + 2 * sizeof(ACCESS_ALLOWED_ACE
) + SidLength
;
1075 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1076 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1077 if (!NT_SUCCESS(Status
)) goto NextAcl
;
1079 /* Now build the ACL and add the two ACEs */
1080 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1081 ASSERT(NT_SUCCESS(Status
));
1082 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1083 ASSERT(NT_SUCCESS(Status
));
1084 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, SystemSid
);
1085 ASSERT(NT_SUCCESS(Status
));
1087 /* Set this as the DACL */
1088 Status
= RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor
,
1092 ASSERT(NT_SUCCESS(Status
));
1095 /* Allocate an ACL with 6 ACEs, two ACEs per SID */
1096 SidLength
= RtlLengthSid(WorldSid
) + RtlLengthSid(RestrictedSid
) + RtlLengthSid(AdminSid
);
1098 AclLength
= sizeof(ACL
) + 6 * sizeof(ACCESS_ALLOWED_ACE
) + SidLength
;
1099 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1100 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1101 if (!NT_SUCCESS(Status
)) goto NotInitial
;
1103 /* Now build the ACL and add the six ACEs */
1104 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1105 ASSERT(NT_SUCCESS(Status
));
1106 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
, WorldSid
);
1107 ASSERT(NT_SUCCESS(Status
));
1108 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
, RestrictedSid
);
1109 ASSERT(NT_SUCCESS(Status
));
1110 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1111 ASSERT(NT_SUCCESS(Status
));
1112 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, WorldSid
);
1113 ASSERT(NT_SUCCESS(Status
));
1114 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, RestrictedSid
);
1115 ASSERT(NT_SUCCESS(Status
));
1116 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1117 ASSERT(NT_SUCCESS(Status
));
1119 /* Now edit the last three ACEs and make them inheritable */
1120 Status
= RtlGetAce(Acl
, 3, (PVOID
)&Ace
);
1121 ASSERT(NT_SUCCESS(Status
));
1122 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1123 Status
= RtlGetAce(Acl
, 4, (PVOID
)&Ace
);
1124 ASSERT(NT_SUCCESS(Status
));
1125 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1126 Status
= RtlGetAce(Acl
, 5, (PVOID
)&Ace
);
1127 ASSERT(NT_SUCCESS(Status
));
1128 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1130 /* Set this as the DACL */
1131 Status
= RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor
,
1135 ASSERT(NT_SUCCESS(Status
));
1138 /* The initial ACLs have been created, are we also protecting objects? */
1139 if (!ProtectionRequired
) goto Quickie
;
1141 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
1142 SidLength
+= RtlLengthSid(OwnerSid
);
1143 AclLength
= sizeof(ACL
) + 7 * sizeof (ACCESS_ALLOWED_ACE
) + 2 * SidLength
;
1144 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1145 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1146 if (!NT_SUCCESS(Status
)) goto Quickie
;
1148 /* Build the ACL and add the seven ACEs */
1149 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1150 ASSERT(NT_SUCCESS(Status
));
1151 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, WorldSid
);
1152 ASSERT(NT_SUCCESS(Status
));
1153 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, RestrictedSid
);
1154 ASSERT(NT_SUCCESS(Status
));
1155 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1156 ASSERT(NT_SUCCESS(Status
));
1157 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, WorldSid
);
1158 ASSERT(NT_SUCCESS(Status
));
1159 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, RestrictedSid
);
1160 ASSERT(NT_SUCCESS(Status
));
1161 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1162 ASSERT(NT_SUCCESS(Status
));
1163 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, OwnerSid
);
1164 ASSERT(NT_SUCCESS(Status
));
1166 /* Edit the last 4 ACEs to make then inheritable */
1167 Status
= RtlGetAce(Acl
, 3, (PVOID
)&Ace
);
1168 ASSERT(NT_SUCCESS(Status
));
1169 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1170 Status
= RtlGetAce(Acl
, 4, (PVOID
)&Ace
);
1171 ASSERT(NT_SUCCESS(Status
));
1172 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1173 Status
= RtlGetAce(Acl
, 5, (PVOID
)&Ace
);
1174 ASSERT(NT_SUCCESS(Status
));
1175 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1176 Status
= RtlGetAce(Acl
, 6, (PVOID
)&Ace
);
1177 ASSERT(NT_SUCCESS(Status
));
1178 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1180 /* Set this as the DACL for the primary SD */
1181 Status
= RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor
,
1185 ASSERT(NT_SUCCESS(Status
));
1187 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
1188 AclLength
= sizeof(ACL
) + 7 * sizeof (ACCESS_ALLOWED_ACE
) + 2 * SidLength
;
1189 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1190 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1191 if (!NT_SUCCESS(Status
)) goto Quickie
;
1193 /* Build the ACL and add the seven ACEs */
1194 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1195 ASSERT(NT_SUCCESS(Status
));
1196 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, WorldSid
);
1197 ASSERT(NT_SUCCESS(Status
));
1198 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, RestrictedSid
);
1199 ASSERT(NT_SUCCESS(Status
));
1200 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1201 ASSERT(NT_SUCCESS(Status
));
1202 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, WorldSid
);
1203 ASSERT(NT_SUCCESS(Status
));
1204 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, RestrictedSid
);
1205 ASSERT(NT_SUCCESS(Status
));
1206 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1207 ASSERT(NT_SUCCESS(Status
));
1208 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, OwnerSid
);
1209 ASSERT(NT_SUCCESS(Status
));
1211 /* Edit the last 4 ACEs to make then inheritable */
1212 Status
= RtlGetAce(Acl
, 3, (PVOID
)&Ace
);
1213 ASSERT(NT_SUCCESS(Status
));
1214 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1215 Status
= RtlGetAce(Acl
, 4, (PVOID
)&Ace
);
1216 ASSERT(NT_SUCCESS(Status
));
1217 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1218 Status
= RtlGetAce(Acl
, 5, (PVOID
)&Ace
);
1219 ASSERT(NT_SUCCESS(Status
));
1220 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1221 Status
= RtlGetAce(Acl
, 6, (PVOID
)&Ace
);
1222 ASSERT(NT_SUCCESS(Status
));
1223 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1225 /* Now set this as the DACL for the liberal SD */
1226 Status
= RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor
,
1230 ASSERT(NT_SUCCESS(Status
));
1233 /* Cleanup the SIDs */
1234 if (OwnerSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, OwnerSid
);
1235 if (AdminSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, AdminSid
);
1236 if (WorldSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid
);
1237 if (SystemSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, SystemSid
);
1238 if (RestrictedSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSid
);
1244 SmpInitializeDosDevices(VOID
)
1247 PSMP_REGISTRY_VALUE RegEntry
;
1248 SECURITY_DESCRIPTOR_CONTROL OldFlag
= 0;
1249 OBJECT_ATTRIBUTES ObjectAttributes
;
1250 UNICODE_STRING DestinationString
;
1252 PLIST_ENTRY NextEntry
, Head
;
1254 /* Open the GLOBAL?? directory */
1255 RtlInitUnicodeString(&DestinationString
, L
"\\??");
1256 InitializeObjectAttributes(&ObjectAttributes
,
1258 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1261 Status
= NtOpenDirectoryObject(&SmpDosDevicesObjectDirectory
,
1262 DIRECTORY_ALL_ACCESS
,
1264 if (!NT_SUCCESS(Status
))
1266 DPRINT1("SMSS: Unable to open %wZ directory - Status == %lx\n",
1267 &DestinationString
, Status
);
1271 /* Loop the DOS devices */
1272 Head
= &SmpDosDevicesList
;
1273 while (!IsListEmpty(Head
))
1275 /* Get the entry and remove it */
1276 NextEntry
= RemoveHeadList(Head
);
1277 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1279 /* Initialize the attributes, and see which descriptor is being used */
1280 InitializeObjectAttributes(&ObjectAttributes
,
1282 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1283 SmpDosDevicesObjectDirectory
,
1284 SmpPrimarySecurityDescriptor
);
1285 if (SmpPrimarySecurityDescriptor
)
1287 /* Save the old flag and set it while we create this link */
1288 OldFlag
= SmpPrimarySecurityDescriptor
->Control
;
1289 SmpPrimarySecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1292 /* Create the symbolic link */
1293 DPRINT("Creating symlink for %wZ to %wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
1294 Status
= NtCreateSymbolicLinkObject(&DirHandle
,
1295 SYMBOLIC_LINK_ALL_ACCESS
,
1298 if (Status
== STATUS_OBJECT_NAME_EXISTS
)
1300 /* Make it temporary and get rid of the handle */
1301 NtMakeTemporaryObject(DirHandle
);
1304 /* Treat this as success, and see if we got a name back */
1305 Status
= STATUS_SUCCESS
;
1306 if (RegEntry
->Value
.Length
)
1308 /* Create it now with this name */
1309 ObjectAttributes
.Attributes
&= ~OBJ_OPENIF
;
1310 Status
= NtCreateSymbolicLinkObject(&DirHandle
,
1311 SYMBOLIC_LINK_ALL_ACCESS
,
1317 /* If we were using a security descriptor, restore the non-defaulted flag */
1318 if (ObjectAttributes
.SecurityDescriptor
)
1320 SmpPrimarySecurityDescriptor
->Control
= OldFlag
;
1323 /* Print a failure if we failed to create the symbolic link */
1324 if (!NT_SUCCESS(Status
))
1326 DPRINT1("SMSS: Unable to create %wZ => %wZ symbolic link object - Status == 0x%lx\n",
1333 /* Close the handle */
1336 /* Free this entry */
1337 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
1338 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
1339 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
1342 /* Return the status */
1348 SmpProcessModuleImports(IN PVOID Unused
,
1349 IN PCHAR ImportName
)
1351 ULONG Length
= 0, Chars
;
1352 WCHAR Buffer
[MAX_PATH
];
1353 PWCHAR DllName
, DllValue
;
1354 ANSI_STRING ImportString
;
1355 UNICODE_STRING ImportUnicodeString
;
1358 /* Skip NTDLL since it's already always mapped */
1359 if (!_stricmp(ImportName
, "ntdll.dll")) return;
1361 /* Initialize our strings */
1362 RtlInitAnsiString(&ImportString
, ImportName
);
1363 RtlInitEmptyUnicodeString(&ImportUnicodeString
, Buffer
, sizeof(Buffer
));
1364 Status
= RtlAnsiStringToUnicodeString(&ImportUnicodeString
, &ImportString
, FALSE
);
1365 if (!NT_SUCCESS(Status
)) return;
1367 /* Loop in case we find a forwarder */
1368 ImportUnicodeString
.MaximumLength
= ImportUnicodeString
.Length
+ sizeof(UNICODE_NULL
);
1369 while (Length
< ImportUnicodeString
.Length
)
1371 if (ImportUnicodeString
.Buffer
[Length
/ sizeof(WCHAR
)] == L
'.') break;
1372 Length
+= sizeof(WCHAR
);
1375 /* Break up the values as needed */
1376 DllValue
= ImportUnicodeString
.Buffer
;
1377 DllName
= &ImportUnicodeString
.Buffer
[ImportUnicodeString
.MaximumLength
/ sizeof(WCHAR
)];
1378 Chars
= Length
>> 1;
1379 wcsncpy(DllName
, ImportUnicodeString
.Buffer
, Chars
);
1382 /* Add the DLL to the list */
1383 SmpSaveRegistryValue(&SmpKnownDllsList
, DllName
, DllValue
, TRUE
);
1388 SmpInitializeKnownDllsInternal(IN PUNICODE_STRING Directory
,
1389 IN PUNICODE_STRING Path
)
1391 HANDLE DirFileHandle
, DirHandle
, SectionHandle
, FileHandle
, LinkHandle
;
1392 UNICODE_STRING NtPath
, DestinationString
;
1393 OBJECT_ATTRIBUTES ObjectAttributes
;
1394 NTSTATUS Status
, Status1
;
1395 PLIST_ENTRY NextEntry
;
1396 PSMP_REGISTRY_VALUE RegEntry
;
1397 ULONG_PTR ErrorParameters
[3];
1398 UNICODE_STRING ErrorResponse
;
1399 IO_STATUS_BLOCK IoStatusBlock
;
1400 SECURITY_DESCRIPTOR_CONTROL OldFlag
= 0;
1401 USHORT ImageCharacteristics
;
1403 /* Initialize to NULL */
1404 DirFileHandle
= NULL
;
1406 NtPath
.Buffer
= NULL
;
1408 /* Create the \KnownDLLs directory */
1409 InitializeObjectAttributes(&ObjectAttributes
,
1411 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1413 SmpKnownDllsSecurityDescriptor
);
1414 Status
= NtCreateDirectoryObject(&DirHandle
,
1415 DIRECTORY_ALL_ACCESS
,
1417 if (!NT_SUCCESS(Status
))
1419 /* Handle failure */
1420 DPRINT1("SMSS: Unable to create %wZ directory - Status == %lx\n",
1425 /* Convert the path to native format */
1426 if (!RtlDosPathNameToNtPathName_U(Path
->Buffer
, &NtPath
, NULL
, NULL
))
1428 /* Fail if this didn't work */
1429 DPRINT1("SMSS: Unable to to convert %wZ to an Nt path\n", Path
);
1430 Status
= STATUS_OBJECT_NAME_INVALID
;
1434 /* Open the path that was specified, which should be a directory */
1435 InitializeObjectAttributes(&ObjectAttributes
,
1437 OBJ_CASE_INSENSITIVE
,
1440 Status
= NtOpenFile(&DirFileHandle
,
1441 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
1444 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1445 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
1446 if (!NT_SUCCESS(Status
))
1448 /* Fail if we couldn't open it */
1449 DPRINT1("SMSS: Unable to open a handle to the KnownDll directory (%wZ)"
1450 "- Status == %lx\n",
1457 /* Temporarily hack the SD to use a default DACL for this symbolic link */
1458 if (SmpPrimarySecurityDescriptor
)
1460 OldFlag
= SmpPrimarySecurityDescriptor
->Control
;
1461 SmpPrimarySecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1464 /* Create a symbolic link to the directory in the object manager */
1465 RtlInitUnicodeString(&DestinationString
, L
"KnownDllPath");
1466 InitializeObjectAttributes(&ObjectAttributes
,
1468 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1470 SmpPrimarySecurityDescriptor
);
1471 Status
= NtCreateSymbolicLinkObject(&LinkHandle
,
1472 SYMBOLIC_LINK_ALL_ACCESS
,
1477 if (SmpPrimarySecurityDescriptor
) SmpPrimarySecurityDescriptor
->Control
= OldFlag
;
1479 /* Check if the symlink was created */
1480 if (!NT_SUCCESS(Status
))
1482 /* It wasn't, so bail out since the OS needs it to exist */
1483 DPRINT1("SMSS: Unable to create %wZ symbolic link - Status == %lx\n",
1484 &DestinationString
, Status
);
1489 /* We created it permanent, we can go ahead and close the handle now */
1490 Status1
= NtClose(LinkHandle
);
1491 ASSERT(NT_SUCCESS(Status1
));
1493 /* Now loop the known DLLs */
1494 NextEntry
= SmpKnownDllsList
.Flink
;
1495 while (NextEntry
!= &SmpKnownDllsList
)
1497 /* Get the entry and skip it if it's in the exluded list */
1498 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1499 DPRINT("Processing known DLL: %wZ-%wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
1500 if ((SmpFindRegistryValue(&SmpExcludeKnownDllsList
,
1501 RegEntry
->Name
.Buffer
)) ||
1502 (SmpFindRegistryValue(&SmpExcludeKnownDllsList
,
1503 RegEntry
->Value
.Buffer
)))
1508 /* Open the actual file */
1509 InitializeObjectAttributes(&ObjectAttributes
,
1511 OBJ_CASE_INSENSITIVE
,
1514 Status
= NtOpenFile(&FileHandle
,
1515 SYNCHRONIZE
| FILE_EXECUTE
,
1518 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1519 FILE_NON_DIRECTORY_FILE
|
1520 FILE_SYNCHRONOUS_IO_NONALERT
);
1521 if (!NT_SUCCESS(Status
)) break;
1524 Status
= LdrVerifyImageMatchesChecksum((HANDLE
)((ULONG_PTR
)FileHandle
| 1),
1525 SmpProcessModuleImports
,
1527 &ImageCharacteristics
);
1528 if (!NT_SUCCESS(Status
))
1530 /* Checksum failed, so don't even try going further -- kill SMSS */
1531 RtlInitUnicodeString(&ErrorResponse
,
1532 L
"Verification of a KnownDLL failed.");
1533 ErrorParameters
[0] = (ULONG
)&ErrorResponse
;
1534 ErrorParameters
[1] = Status
;
1535 ErrorParameters
[2] = (ULONG
)&RegEntry
->Value
;
1536 SmpTerminate(ErrorParameters
, 5, RTL_NUMBER_OF(ErrorParameters
));
1539 if (!(ImageCharacteristics
& IMAGE_FILE_DLL
))
1541 /* An invalid known DLL entry will also kill SMSS */
1542 RtlInitUnicodeString(&ErrorResponse
,
1543 L
"Non-DLL file included in KnownDLL list.");
1544 ErrorParameters
[0] = (ULONG
)&ErrorResponse
;
1545 ErrorParameters
[1] = STATUS_INVALID_IMPORT_OF_NON_DLL
;
1546 ErrorParameters
[2] = (ULONG
)&RegEntry
->Value
;
1547 SmpTerminate(ErrorParameters
, 5, RTL_NUMBER_OF(ErrorParameters
));
1550 /* Temporarily hack the SD to use a default DACL for this section */
1551 if (SmpLiberalSecurityDescriptor
)
1553 OldFlag
= SmpLiberalSecurityDescriptor
->Control
;
1554 SmpLiberalSecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1557 /* Create the section for this known DLL */
1558 InitializeObjectAttributes(&ObjectAttributes
,
1562 SmpLiberalSecurityDescriptor
)
1563 Status
= NtCreateSection(&SectionHandle
,
1572 if (SmpLiberalSecurityDescriptor
) SmpLiberalSecurityDescriptor
->Control
= OldFlag
;
1574 /* Check if we created the section okay */
1575 if (NT_SUCCESS(Status
))
1577 /* We can close it now, since it's marked permanent */
1578 Status1
= NtClose(SectionHandle
);
1579 ASSERT(NT_SUCCESS(Status1
));
1583 /* If we couldn't make it "known", that's fine and keep going */
1584 DPRINT1("SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n",
1585 &RegEntry
->Value
, Status
);
1588 /* Close the file since we can move on to the next one */
1589 Status1
= NtClose(FileHandle
);
1590 ASSERT(NT_SUCCESS(Status1
));
1592 /* Go to the next entry */
1593 NextEntry
= NextEntry
->Flink
;
1597 /* Close both handles and free the NT path buffer */
1600 Status1
= NtClose(DirHandle
);
1601 ASSERT(NT_SUCCESS(Status1
));
1605 Status1
= NtClose(DirFileHandle
);
1606 ASSERT(NT_SUCCESS(Status1
));
1608 if (NtPath
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath
.Buffer
);
1614 SmpInitializeKnownDlls(VOID
)
1617 PSMP_REGISTRY_VALUE RegEntry
;
1618 UNICODE_STRING DestinationString
;
1619 PLIST_ENTRY Head
, NextEntry
;
1621 /* Call the internal function */
1622 RtlInitUnicodeString(&DestinationString
, L
"\\KnownDlls");
1623 Status
= SmpInitializeKnownDllsInternal(&DestinationString
, &SmpKnownDllPath
);
1625 /* Wipe out the list regardless of success */
1626 Head
= &SmpKnownDllsList
;
1627 while (!IsListEmpty(Head
))
1629 /* Remove this entry */
1630 NextEntry
= RemoveHeadList(Head
);
1633 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1634 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
1635 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
1636 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
1645 SmpCreateDynamicEnvironmentVariables(VOID
)
1648 SYSTEM_BASIC_INFORMATION BasicInfo
;
1649 SYSTEM_PROCESSOR_INFORMATION ProcessorInfo
;
1650 OBJECT_ATTRIBUTES ObjectAttributes
;
1651 UNICODE_STRING ValueName
, DestinationString
;
1652 HANDLE KeyHandle
, KeyHandle2
;
1655 WCHAR ValueBuffer
[512], ValueBuffer2
[512];
1656 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PVOID
)ValueBuffer
;
1657 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo2
= (PVOID
)ValueBuffer2
;
1659 /* Get system basic information -- we'll need the CPU count */
1660 Status
= NtQuerySystemInformation(SystemBasicInformation
,
1664 if (!NT_SUCCESS(Status
))
1666 /* Bail out on failure */
1667 DPRINT1("SMSS: Unable to query system basic information - %x\n", Status
);
1671 /* Get the processor information, we'll query a bunch of revision info */
1672 Status
= NtQuerySystemInformation(SystemProcessorInformation
,
1674 sizeof(ProcessorInfo
),
1676 if (!NT_SUCCESS(Status
))
1678 /* Bail out on failure */
1679 DPRINT1("SMSS: Unable to query system processor information - %x\n", Status
);
1683 /* We'll be writing all these environment variables over here */
1684 RtlInitUnicodeString(&DestinationString
,
1685 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
1686 L
"Control\\Session Manager\\Environment");
1687 InitializeObjectAttributes(&ObjectAttributes
,
1689 OBJ_CASE_INSENSITIVE
,
1692 Status
= NtOpenKey(&KeyHandle
, GENERIC_WRITE
, &ObjectAttributes
);
1693 if (!NT_SUCCESS(Status
))
1695 /* Bail out on failure */
1696 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString
, Status
);
1700 /* First let's write the OS variable */
1701 RtlInitUnicodeString(&ValueName
, L
"OS");
1702 DPRINT("Setting %wZ to %S\n", &ValueName
, L
"Windows_NT");
1703 Status
= NtSetValueKey(KeyHandle
,
1708 wcslen(L
"Windows_NT") * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1709 if (!NT_SUCCESS(Status
))
1711 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1712 &ValueName
, Status
);
1717 /* Next, let's write the CPU architecture variable */
1718 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_ARCHITECTURE");
1719 switch (ProcessorInfo
.ProcessorArchitecture
)
1721 /* Pick the correct string that matches the architecture */
1722 case PROCESSOR_ARCHITECTURE_INTEL
:
1726 case PROCESSOR_ARCHITECTURE_AMD64
:
1727 ArchName
= L
"AMD64";
1730 case PROCESSOR_ARCHITECTURE_IA64
:
1735 ArchName
= L
"Unknown";
1740 DPRINT("Setting %wZ to %S\n", &ValueName
, ArchName
);
1741 Status
= NtSetValueKey(KeyHandle
,
1746 wcslen(ArchName
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1747 if (!NT_SUCCESS(Status
))
1749 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1750 &ValueName
, Status
);
1755 /* And now let's write the processor level */
1756 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_LEVEL");
1757 swprintf(ValueBuffer
, L
"%u", ProcessorInfo
.ProcessorLevel
);
1758 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1759 Status
= NtSetValueKey(KeyHandle
,
1764 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1765 if (!NT_SUCCESS(Status
))
1767 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1768 &ValueName
, Status
);
1773 /* Now open the hardware CPU key */
1774 RtlInitUnicodeString(&DestinationString
,
1775 L
"\\Registry\\Machine\\Hardware\\Description\\System\\"
1776 L
"CentralProcessor\\0");
1777 InitializeObjectAttributes(&ObjectAttributes
,
1779 OBJ_CASE_INSENSITIVE
,
1782 Status
= NtOpenKey(&KeyHandle2
, KEY_READ
, &ObjectAttributes
);
1783 if (!NT_SUCCESS(Status
))
1785 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString
, Status
);
1790 /* So that we can read the identifier out of it... */
1791 RtlInitUnicodeString(&ValueName
, L
"Identifier");
1792 Status
= NtQueryValueKey(KeyHandle2
,
1794 KeyValuePartialInformation
,
1796 sizeof(ValueBuffer
),
1798 if (!NT_SUCCESS(Status
))
1800 NtClose(KeyHandle2
);
1802 DPRINT1("SMSS: Unable to read %wZ\\%wZ - %x\n",
1803 &DestinationString
, &ValueName
, Status
);
1807 /* As well as the vendor... */
1808 RtlInitUnicodeString(&ValueName
, L
"VendorIdentifier");
1809 Status
= NtQueryValueKey(KeyHandle2
,
1811 KeyValuePartialInformation
,
1813 sizeof(ValueBuffer2
),
1815 NtClose(KeyHandle2
);
1816 if (NT_SUCCESS(Status
))
1818 /* To combine it into a single string */
1819 swprintf((PWCHAR
)PartialInfo
->Data
+ wcslen((PWCHAR
)PartialInfo
->Data
),
1821 PartialInfo2
->Data
);
1824 /* So that we can set this as the PROCESSOR_IDENTIFIER variable */
1825 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_IDENTIFIER");
1826 DPRINT("Setting %wZ to %s\n", &ValueName
, PartialInfo
->Data
);
1827 Status
= NtSetValueKey(KeyHandle
,
1832 wcslen((PWCHAR
)PartialInfo
->Data
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1833 if (!NT_SUCCESS(Status
))
1835 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1836 &ValueName
, Status
);
1841 /* Now let's get the processor architecture */
1842 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_REVISION");
1843 switch (ProcessorInfo
.ProcessorArchitecture
)
1845 /* Check if this is an older Intel CPU */
1846 case PROCESSOR_ARCHITECTURE_INTEL
:
1847 if ((ProcessorInfo
.ProcessorRevision
>> 8) == 0xFF)
1849 /* These guys used a revision + stepping, so get the rev only */
1850 swprintf(ValueBuffer
, L
"%02x", ProcessorInfo
.ProcessorRevision
& 0xFF);
1851 _wcsupr(ValueBuffer
);
1855 /* Modern Intel, as well as 64-bit CPUs use a revision without stepping */
1856 case PROCESSOR_ARCHITECTURE_IA64
:
1857 case PROCESSOR_ARCHITECTURE_AMD64
:
1858 swprintf(ValueBuffer
, L
"%04x", ProcessorInfo
.ProcessorRevision
);
1861 /* And anything else we'll just read the whole revision identifier */
1863 swprintf(ValueBuffer
, L
"%u", ProcessorInfo
.ProcessorRevision
);
1867 /* Write the revision to the registry */
1868 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1869 Status
= NtSetValueKey(KeyHandle
,
1874 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1875 if (!NT_SUCCESS(Status
))
1877 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1878 &ValueName
, Status
);
1883 /* And finally, write the number of CPUs */
1884 RtlInitUnicodeString(&ValueName
, L
"NUMBER_OF_PROCESSORS");
1885 swprintf(ValueBuffer
, L
"%d", BasicInfo
.NumberOfProcessors
);
1886 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1887 Status
= NtSetValueKey(KeyHandle
,
1892 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1893 if (!NT_SUCCESS(Status
))
1895 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1896 &ValueName
, Status
);
1901 /* Now we need to write the safeboot option key in a different format */
1902 RtlInitUnicodeString(&DestinationString
,
1903 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
1904 L
"Control\\Safeboot\\Option");
1905 InitializeObjectAttributes(&ObjectAttributes
,
1907 OBJ_CASE_INSENSITIVE
,
1910 Status
= NtOpenKey(&KeyHandle2
, KEY_ALL_ACCESS
, &ObjectAttributes
);
1911 if (NT_SUCCESS(Status
))
1913 /* This was indeed a safeboot, so check what kind of safeboot it was */
1914 RtlInitUnicodeString(&ValueName
, L
"OptionValue");
1915 Status
= NtQueryValueKey(KeyHandle2
,
1917 KeyValuePartialInformation
,
1919 sizeof(ValueBuffer
),
1921 NtClose(KeyHandle2
);
1922 if (NT_SUCCESS(Status
))
1924 /* Convert from the integer value to the correct specifier */
1925 RtlInitUnicodeString(&ValueName
, L
"SAFEBOOT_OPTION");
1926 switch (*(PULONG
)PartialInfo
->Data
)
1929 wcscpy(ValueBuffer
, L
"MINIMAL");
1932 wcscpy(ValueBuffer
, L
"NETWORK");
1935 wcscpy(ValueBuffer
, L
"DSREPAIR");
1939 /* And write it in the environment! */
1940 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1941 Status
= NtSetValueKey(KeyHandle
,
1946 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1947 if (!NT_SUCCESS(Status
))
1949 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1950 &ValueName
, Status
);
1957 DPRINT1("SMSS: Failed querying safeboot option = %x\n", Status
);
1961 /* We are all done now */
1963 return STATUS_SUCCESS
;
1968 SmpProcessFileRenames(VOID
)
1970 BOOLEAN OldState
, HavePrivilege
= FALSE
;
1972 HANDLE FileHandle
, OtherFileHandle
;
1973 FILE_INFORMATION_CLASS InformationClass
;
1974 OBJECT_ATTRIBUTES ObjectAttributes
;
1975 IO_STATUS_BLOCK IoStatusBlock
;
1976 UNICODE_STRING FileString
;
1977 FILE_BASIC_INFORMATION BasicInfo
;
1978 FILE_DISPOSITION_INFORMATION DeleteInformation
;
1979 PFILE_RENAME_INFORMATION Buffer
;
1980 PLIST_ENTRY Head
, NextEntry
;
1981 PSMP_REGISTRY_VALUE RegEntry
;
1983 ULONG ValueLength
, Length
;
1985 /* Give us access to restore any files we want */
1986 Status
= RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, TRUE
, FALSE
, &OldState
);
1987 if (NT_SUCCESS(Status
)) HavePrivilege
= TRUE
;
1989 /* Process pending files to rename */
1990 Head
= &SmpFileRenameList
;
1991 while (!IsListEmpty(Head
))
1993 /* Get this entry */
1994 NextEntry
= RemoveHeadList(Head
);
1995 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1996 DPRINT1("Processing PFRO: %wZ/%wZ\n", &RegEntry
->Value
, &RegEntry
->Name
);
1998 /* Skip past the '@' marker */
1999 if (!(RegEntry
->Value
.Length
) && (*RegEntry
->Name
.Buffer
== L
'@'))
2001 RegEntry
->Name
.Length
-= sizeof(UNICODE_NULL
);
2002 RegEntry
->Name
.Buffer
++;
2005 /* Open the file for delete access */
2006 InitializeObjectAttributes(&ObjectAttributes
,
2008 OBJ_CASE_INSENSITIVE
,
2011 Status
= NtOpenFile(&OtherFileHandle
,
2012 DELETE
| SYNCHRONIZE
,
2015 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2016 FILE_SYNCHRONOUS_IO_NONALERT
);
2017 if (!NT_SUCCESS(Status
)) goto Quickie
;
2019 /* Check if it's a rename or just a delete */
2020 ValueLength
= RegEntry
->Value
.Length
;
2023 /* Just a delete, set up the class, length and buffer */
2024 InformationClass
= FileDispositionInformation
;
2025 Length
= sizeof(DeleteInformation
);
2026 Buffer
= (PFILE_RENAME_INFORMATION
)&DeleteInformation
;
2028 /* Set the delete disposition */
2029 DeleteInformation
.DeleteFile
= TRUE
;
2033 /* This is a rename, setup the class and length */
2034 InformationClass
= FileRenameInformation
;
2035 Length
= ValueLength
+ sizeof(FILE_RENAME_INFORMATION
);
2037 /* Skip past the special markers */
2038 FileName
= RegEntry
->Value
.Buffer
;
2039 if ((*FileName
== L
'!') || (*FileName
== L
'@'))
2042 Length
-= sizeof(UNICODE_NULL
);
2045 /* Now allocate the buffer for the rename information */
2046 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag
, Length
);
2049 /* Setup the buffer to point to the filename, and copy it */
2050 Buffer
->RootDirectory
= NULL
;
2051 Buffer
->FileNameLength
= Length
- sizeof(FILE_RENAME_INFORMATION
);
2052 Buffer
->ReplaceIfExists
= FileName
!= RegEntry
->Value
.Buffer
;
2053 RtlCopyMemory(Buffer
->FileName
, FileName
, Buffer
->FileNameLength
);
2058 Status
= STATUS_NO_MEMORY
;
2062 /* Check if everything is okay till here */
2063 if (NT_SUCCESS(Status
))
2065 /* Now either rename or delete the file as requested */
2066 Status
= NtSetInformationFile(OtherFileHandle
,
2072 /* Check if we seem to have failed because the file was readonly */
2073 if ((NT_SUCCESS(Status
) &&
2074 (InformationClass
== FileRenameInformation
) &&
2075 (Status
== STATUS_OBJECT_NAME_COLLISION
) &&
2076 (Buffer
->ReplaceIfExists
)))
2078 /* Open the file for write attribute access this time... */
2079 DPRINT1("\nSMSS: %wZ => %wZ failed - Status == %x, Possible readonly target\n",
2082 STATUS_OBJECT_NAME_COLLISION
);
2083 FileString
.Length
= RegEntry
->Value
.Length
- sizeof(WCHAR
);
2084 FileString
.MaximumLength
= RegEntry
->Value
.MaximumLength
- sizeof(WCHAR
);
2085 FileString
.Buffer
= FileName
;
2086 InitializeObjectAttributes(&ObjectAttributes
,
2088 OBJ_CASE_INSENSITIVE
,
2091 Status
= NtOpenFile(&FileHandle
,
2092 FILE_WRITE_ATTRIBUTES
| SYNCHRONIZE
,
2095 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2096 FILE_SYNCHRONOUS_IO_NONALERT
);
2097 if (!NT_SUCCESS(Status
))
2099 /* That didn't work, so bail out */
2100 DPRINT1(" SMSS: Open Existing file Failed - Status == %x\n",
2105 /* Now remove the read-only attribute from the file */
2106 DPRINT1(" SMSS: Open Existing Success\n");
2107 RtlZeroMemory(&BasicInfo
, sizeof(BasicInfo
));
2108 BasicInfo
.FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
2109 Status
= NtSetInformationFile(FileHandle
,
2113 FileBasicInformation
);
2114 NtClose(FileHandle
);
2115 if (!NT_SUCCESS(Status
))
2117 /* That didn't work, bail out */
2118 DPRINT1(" SMSS: Set To NORMAL Failed - Status == %x\n",
2123 /* Now that the file is no longer read-only, delete! */
2124 DPRINT1(" SMSS: Set To NORMAL OK\n");
2125 Status
= NtSetInformationFile(OtherFileHandle
,
2129 FileRenameInformation
);
2130 if (!NT_SUCCESS(Status
))
2132 /* That failed too! */
2133 DPRINT1(" SMSS: Re-Rename Failed - Status == %x\n",
2139 DPRINT1(" SMSS: Re-Rename Worked OK\n");
2146 /* Close the file handle and check the operation result */
2147 NtClose(OtherFileHandle
);
2149 if (!NT_SUCCESS(Status
))
2151 /* We totally failed */
2152 DPRINT1("SMSS: %wZ => %wZ failed - Status == %x\n",
2153 &RegEntry
->Name
, &RegEntry
->Value
, Status
);
2155 else if (RegEntry
->Value
.Length
)
2157 /* We succeed with a rename */
2158 DPRINT1("SMSS: %wZ (renamed to) %wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
2162 /* We suceeded with a delete */
2163 DPRINT1("SMSS: %wZ (deleted)\n", &RegEntry
->Name
);
2166 /* Now free this entry and keep going */
2167 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2168 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2169 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2172 /* Put back the restore privilege if we had requested it, and return */
2173 if (HavePrivilege
) RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, FALSE
, FALSE
, &OldState
);
2179 SmpLoadDataFromRegistry(OUT PUNICODE_STRING InitialCommand
)
2182 PLIST_ENTRY Head
, NextEntry
;
2183 PSMP_REGISTRY_VALUE RegEntry
;
2184 PVOID OriginalEnvironment
;
2185 ULONG MuSessionId
= 0;
2186 OBJECT_ATTRIBUTES ObjectAttributes
;
2188 UNICODE_STRING DestinationString
;
2190 /* Initialize the keywords we'll be looking for */
2191 RtlInitUnicodeString(&SmpDebugKeyword
, L
"debug");
2192 RtlInitUnicodeString(&SmpASyncKeyword
, L
"async");
2193 RtlInitUnicodeString(&SmpAutoChkKeyword
, L
"autocheck");
2195 /* Initialize all the registry-associated list heads */
2196 InitializeListHead(&SmpBootExecuteList
);
2197 InitializeListHead(&SmpSetupExecuteList
);
2198 InitializeListHead(&SmpPagingFileList
);
2199 InitializeListHead(&SmpDosDevicesList
);
2200 InitializeListHead(&SmpFileRenameList
);
2201 InitializeListHead(&SmpKnownDllsList
);
2202 InitializeListHead(&SmpExcludeKnownDllsList
);
2203 InitializeListHead(&SmpSubSystemList
);
2204 InitializeListHead(&SmpSubSystemsToLoad
);
2205 InitializeListHead(&SmpSubSystemsToDefer
);
2206 InitializeListHead(&SmpExecuteList
);
2207 SmpPagingFileInitialize();
2209 /* Initialize the SMSS environment */
2210 Status
= RtlCreateEnvironment(TRUE
, &SmpDefaultEnvironment
);
2211 if (!NT_SUCCESS(Status
))
2213 /* Fail if there was a problem */
2214 DPRINT1("SMSS: Unable to allocate default environment - Status == %X\n",
2216 SMSS_CHECKPOINT(RtlCreateEnvironment
, Status
);
2220 /* Check if we were booted in PE mode (LiveCD should have this) */
2221 RtlInitUnicodeString(&DestinationString
,
2222 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
2223 L
"Control\\MiniNT");
2224 InitializeObjectAttributes(&ObjectAttributes
,
2226 OBJ_CASE_INSENSITIVE
,
2229 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
2230 if (NT_SUCCESS(Status
))
2232 /* If the key exists, we were */
2237 /* Print out if this is the case */
2238 if (MiniNTBoot
) DPRINT1("SMSS: !!! MiniNT Boot !!!\n");
2240 /* Open the environment key to see if we are booted in safe mode */
2241 RtlInitUnicodeString(&DestinationString
,
2242 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
2243 L
"Control\\Session Manager\\Environment");
2244 InitializeObjectAttributes(&ObjectAttributes
,
2246 OBJ_CASE_INSENSITIVE
,
2249 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
2250 if (NT_SUCCESS(Status
))
2252 /* Delete the value if we found it */
2253 RtlInitUnicodeString(&DestinationString
, L
"SAFEBOOT_OPTION");
2254 NtDeleteValueKey(KeyHandle
, &DestinationString
);
2258 /* Switch environments, then query the registry for all needed settings */
2259 OriginalEnvironment
= NtCurrentPeb()->ProcessParameters
->Environment
;
2260 NtCurrentPeb()->ProcessParameters
->Environment
= SmpDefaultEnvironment
;
2261 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
2263 SmpRegistryConfigurationTable
,
2266 SmpDefaultEnvironment
= NtCurrentPeb()->ProcessParameters
->Environment
;
2267 NtCurrentPeb()->ProcessParameters
->Environment
= OriginalEnvironment
;
2268 if (!NT_SUCCESS(Status
))
2270 /* We failed somewhere in registry initialization, which is bad... */
2271 DPRINT1("SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status
);
2272 SMSS_CHECKPOINT(RtlQueryRegistryValues
, Status
);
2276 /* Now we can start acting on the registry settings. First to DOS devices */
2277 Status
= SmpInitializeDosDevices();
2278 if (!NT_SUCCESS(Status
))
2281 DPRINT1("SMSS: Unable to initialize DosDevices configuration - Status == %lx\n",
2283 SMSS_CHECKPOINT(SmpInitializeDosDevices
, Status
);
2287 /* Next create the session directory... */
2288 RtlInitUnicodeString(&DestinationString
, L
"\\Sessions");
2289 InitializeObjectAttributes(&ObjectAttributes
,
2291 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
2293 SmpPrimarySecurityDescriptor
);
2294 Status
= NtCreateDirectoryObject(&SmpSessionsObjectDirectory
,
2295 DIRECTORY_ALL_ACCESS
,
2297 if (!NT_SUCCESS(Status
))
2300 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
2301 &DestinationString
, Status
);
2302 SMSS_CHECKPOINT(NtCreateDirectoryObject
, Status
);
2306 /* Next loop all the boot execute binaries */
2307 Head
= &SmpBootExecuteList
;
2308 while (!IsListEmpty(Head
))
2310 /* Remove each one from the list */
2311 NextEntry
= RemoveHeadList(Head
);
2314 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2315 SmpExecuteCommand(&RegEntry
->Name
, 0, NULL
, 0);
2318 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2319 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2320 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2323 /* Now do any pending file rename operations... */
2324 if (!MiniNTBoot
) SmpProcessFileRenames();
2326 /* And initialize known DLLs... */
2327 Status
= SmpInitializeKnownDlls();
2328 if (!NT_SUCCESS(Status
))
2330 /* Fail if that didn't work */
2331 DPRINT1("SMSS: Unable to initialize KnownDll configuration - Status == %lx\n",
2333 SMSS_CHECKPOINT(SmpInitializeKnownDlls
, Status
);
2337 /* Loop every page file */
2338 Head
= &SmpPagingFileList
;
2339 while (!IsListEmpty(Head
))
2341 /* Remove each one from the list */
2342 NextEntry
= RemoveHeadList(Head
);
2344 /* Create the descriptor for it */
2345 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2346 SmpCreatePagingFileDescriptor(&RegEntry
->Name
);
2349 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2350 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2351 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2354 /* Now create all the paging files for the descriptors that we have */
2355 SmpCreatePagingFiles();
2357 /* Tell Cm it's now safe to fully enable write access to the registry */
2358 NtInitializeRegistry(CM_BOOT_FLAG_SMSS
);
2360 /* Create all the system-based environment variables for later inheriting */
2361 Status
= SmpCreateDynamicEnvironmentVariables();
2362 if (!NT_SUCCESS(Status
))
2364 /* Handle failure */
2365 SMSS_CHECKPOINT(SmpCreateDynamicEnvironmentVariables
, Status
);
2369 /* And finally load all the subsytems for our first session! */
2370 Status
= SmpLoadSubSystemsForMuSession(&MuSessionId
,
2371 &SmpWindowsSubSysProcessId
,
2373 ASSERT(MuSessionId
== 0);
2374 if (!NT_SUCCESS(Status
)) SMSS_CHECKPOINT(SmpLoadSubSystemsForMuSession
, Status
);
2380 SmpInit(IN PUNICODE_STRING InitialCommand
,
2381 OUT PHANDLE ProcessHandle
)
2383 NTSTATUS Status
, Status2
;
2384 OBJECT_ATTRIBUTES ObjectAttributes
;
2385 UNICODE_STRING PortName
, EventName
;
2386 HANDLE EventHandle
, PortHandle
;
2387 ULONG HardErrorMode
;
2389 /* Create the SMSS Heap */
2390 SmBaseTag
= RtlCreateTagHeap(RtlGetProcessHeap(),
2394 SmpHeap
= RtlGetProcessHeap();
2396 /* Enable hard errors */
2397 HardErrorMode
= TRUE
;
2398 NtSetInformationProcess(NtCurrentProcess(),
2399 ProcessDefaultHardErrorMode
,
2401 sizeof(HardErrorMode
));
2403 /* Initialize the subsystem list and the session list, plus their locks */
2404 RtlInitializeCriticalSection(&SmpKnownSubSysLock
);
2405 InitializeListHead(&SmpKnownSubSysHead
);
2406 RtlInitializeCriticalSection(&SmpSessionListLock
);
2407 InitializeListHead(&SmpSessionListHead
);
2409 /* Initialize the process list */
2410 InitializeListHead(&NativeProcessList
);
2412 /* Initialize session parameters */
2413 SmpNextSessionId
= 1;
2414 SmpNextSessionIdScanMode
= 0;
2415 SmpDbgSsLoaded
= FALSE
;
2417 /* Create the initial security descriptors */
2418 Status
= SmpCreateSecurityDescriptors(TRUE
);
2419 if (!NT_SUCCESS(Status
))
2422 SMSS_CHECKPOINT(SmpCreateSecurityDescriptors
, Status
);
2426 /* Initialize subsystem names */
2427 RtlInitUnicodeString(&SmpSubsystemName
, L
"NT-Session Manager");
2428 RtlInitUnicodeString(&PosixName
, L
"POSIX");
2429 RtlInitUnicodeString(&Os2Name
, L
"OS2");
2431 /* Create the SM API Port */
2432 RtlInitUnicodeString(&PortName
, L
"\\SmApiPort");
2433 InitializeObjectAttributes(&ObjectAttributes
, &PortName
, 0, NULL
, NULL
);
2434 Status
= NtCreatePort(&PortHandle
,
2436 sizeof(SB_CONNECTION_INFO
),
2438 sizeof(SB_API_MSG
) * 32);
2439 ASSERT(NT_SUCCESS(Status
));
2440 SmpDebugPort
= PortHandle
;
2442 /* Create two SM API threads */
2443 Status
= RtlCreateUserThread(NtCurrentProcess(),
2453 ASSERT(NT_SUCCESS(Status
));
2454 Status
= RtlCreateUserThread(NtCurrentProcess(),
2464 ASSERT(NT_SUCCESS(Status
));
2466 /* Create the write event that autochk can set after running */
2467 RtlInitUnicodeString(&EventName
, L
"\\Device\\VolumesSafeForWriteAccess");
2468 InitializeObjectAttributes(&ObjectAttributes
,
2473 Status2
= NtCreateEvent(&EventHandle
,
2478 if (!NT_SUCCESS(Status2
))
2480 /* Should never really fail */
2481 DPRINT1("SMSS: Unable to create %wZ event - Status == %lx\n",
2482 &EventName
, Status2
);
2483 ASSERT(NT_SUCCESS(Status2
));
2486 /* Now initialize everything else based on the registry parameters */
2487 Status
= SmpLoadDataFromRegistry(InitialCommand
);
2488 if (NT_SUCCESS(Status
))
2490 /* Autochk should've run now. Set the event and save the CSRSS handle */
2491 *ProcessHandle
= SmpWindowsSubSysProcess
;
2492 NtSetEvent(EventHandle
, 0);
2493 NtClose(EventHandle
);