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: %d\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: %d\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
);
1529 if (!NT_SUCCESS(Status
))
1531 /* Checksum failed, so don't even try going further -- kill SMSS */
1532 RtlInitUnicodeString(&ErrorResponse
,
1533 L
"Verification of a KnownDLL failed.");
1534 ErrorParameters
[0] = (ULONG
)&ErrorResponse
;
1535 ErrorParameters
[1] = Status
;
1536 ErrorParameters
[2] = (ULONG
)&RegEntry
->Value
;
1537 SmpTerminate(ErrorParameters
, 5, RTL_NUMBER_OF(ErrorParameters
));
1540 if (!(ImageCharacteristics
& IMAGE_FILE_DLL
))
1542 /* An invalid known DLL entry will also kill SMSS */
1543 RtlInitUnicodeString(&ErrorResponse
,
1544 L
"Non-DLL file included in KnownDLL list.");
1545 ErrorParameters
[0] = (ULONG
)&ErrorResponse
;
1546 ErrorParameters
[1] = STATUS_INVALID_IMPORT_OF_NON_DLL
;
1547 ErrorParameters
[2] = (ULONG
)&RegEntry
->Value
;
1548 SmpTerminate(ErrorParameters
, 5, RTL_NUMBER_OF(ErrorParameters
));
1552 /* Temporarily hack the SD to use a default DACL for this section */
1553 if (SmpLiberalSecurityDescriptor
)
1555 OldFlag
= SmpLiberalSecurityDescriptor
->Control
;
1556 SmpLiberalSecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1559 /* Create the section for this known DLL */
1560 InitializeObjectAttributes(&ObjectAttributes
,
1564 SmpLiberalSecurityDescriptor
)
1565 Status
= NtCreateSection(&SectionHandle
,
1574 if (SmpLiberalSecurityDescriptor
) SmpLiberalSecurityDescriptor
->Control
= OldFlag
;
1576 /* Check if we created the section okay */
1577 if (NT_SUCCESS(Status
))
1579 /* We can close it now, since it's marked permanent */
1580 Status1
= NtClose(SectionHandle
);
1581 ASSERT(NT_SUCCESS(Status1
));
1585 /* If we couldn't make it "known", that's fine and keep going */
1586 DPRINT1("SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n",
1587 &RegEntry
->Value
, Status
);
1590 /* Close the file since we can move on to the next one */
1591 Status1
= NtClose(FileHandle
);
1592 ASSERT(NT_SUCCESS(Status1
));
1594 /* Go to the next entry */
1595 NextEntry
= NextEntry
->Flink
;
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 DPRINT("Setting %wZ to %S\n", &ValueName
, L
"Windows_NT");
1705 Status
= NtSetValueKey(KeyHandle
,
1710 wcslen(L
"Windows_NT") * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1711 if (!NT_SUCCESS(Status
))
1713 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1714 &ValueName
, Status
);
1719 /* Next, let's write the CPU architecture variable */
1720 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_ARCHITECTURE");
1721 switch (ProcessorInfo
.ProcessorArchitecture
)
1723 /* Pick the correct string that matches the architecture */
1724 case PROCESSOR_ARCHITECTURE_INTEL
:
1728 case PROCESSOR_ARCHITECTURE_AMD64
:
1729 ArchName
= L
"AMD64";
1732 case PROCESSOR_ARCHITECTURE_IA64
:
1737 ArchName
= L
"Unknown";
1742 DPRINT("Setting %wZ to %S\n", &ValueName
, ArchName
);
1743 Status
= NtSetValueKey(KeyHandle
,
1748 wcslen(ArchName
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1749 if (!NT_SUCCESS(Status
))
1751 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1752 &ValueName
, Status
);
1757 /* And now let's write the processor level */
1758 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_LEVEL");
1759 swprintf(ValueBuffer
, L
"%u", ProcessorInfo
.ProcessorLevel
);
1760 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1761 Status
= NtSetValueKey(KeyHandle
,
1766 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1767 if (!NT_SUCCESS(Status
))
1769 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1770 &ValueName
, Status
);
1775 /* Now open the hardware CPU key */
1776 RtlInitUnicodeString(&DestinationString
,
1777 L
"\\Registry\\Machine\\Hardware\\Description\\System\\"
1778 L
"CentralProcessor\\0");
1779 InitializeObjectAttributes(&ObjectAttributes
,
1781 OBJ_CASE_INSENSITIVE
,
1784 Status
= NtOpenKey(&KeyHandle2
, KEY_READ
, &ObjectAttributes
);
1785 if (!NT_SUCCESS(Status
))
1787 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString
, Status
);
1792 /* So that we can read the identifier out of it... */
1793 RtlInitUnicodeString(&ValueName
, L
"Identifier");
1794 Status
= NtQueryValueKey(KeyHandle2
,
1796 KeyValuePartialInformation
,
1798 sizeof(ValueBuffer
),
1800 if (!NT_SUCCESS(Status
))
1802 NtClose(KeyHandle2
);
1804 DPRINT1("SMSS: Unable to read %wZ\\%wZ - %x\n",
1805 &DestinationString
, &ValueName
, Status
);
1809 /* As well as the vendor... */
1810 RtlInitUnicodeString(&ValueName
, L
"VendorIdentifier");
1811 Status
= NtQueryValueKey(KeyHandle2
,
1813 KeyValuePartialInformation
,
1815 sizeof(ValueBuffer2
),
1817 NtClose(KeyHandle2
);
1818 if (NT_SUCCESS(Status
))
1820 /* To combine it into a single string */
1821 swprintf((PWCHAR
)PartialInfo
->Data
+ wcslen((PWCHAR
)PartialInfo
->Data
),
1823 PartialInfo2
->Data
);
1826 /* So that we can set this as the PROCESSOR_IDENTIFIER variable */
1827 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_IDENTIFIER");
1828 DPRINT("Setting %wZ to %S\n", &ValueName
, PartialInfo
->Data
);
1829 Status
= NtSetValueKey(KeyHandle
,
1834 wcslen((PWCHAR
)PartialInfo
->Data
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1835 if (!NT_SUCCESS(Status
))
1837 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1838 &ValueName
, Status
);
1843 /* Now let's get the processor architecture */
1844 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_REVISION");
1845 switch (ProcessorInfo
.ProcessorArchitecture
)
1847 /* Check if this is an older Intel CPU */
1848 case PROCESSOR_ARCHITECTURE_INTEL
:
1849 if ((ProcessorInfo
.ProcessorRevision
>> 8) == 0xFF)
1851 /* These guys used a revision + stepping, so get the rev only */
1852 swprintf(ValueBuffer
, L
"%02x", ProcessorInfo
.ProcessorRevision
& 0xFF);
1853 _wcsupr(ValueBuffer
);
1857 /* Modern Intel, as well as 64-bit CPUs use a revision without stepping */
1858 case PROCESSOR_ARCHITECTURE_IA64
:
1859 case PROCESSOR_ARCHITECTURE_AMD64
:
1860 swprintf(ValueBuffer
, L
"%04x", ProcessorInfo
.ProcessorRevision
);
1863 /* And anything else we'll just read the whole revision identifier */
1865 swprintf(ValueBuffer
, L
"%u", ProcessorInfo
.ProcessorRevision
);
1869 /* Write the revision to the registry */
1870 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1871 Status
= NtSetValueKey(KeyHandle
,
1876 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1877 if (!NT_SUCCESS(Status
))
1879 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1880 &ValueName
, Status
);
1885 /* And finally, write the number of CPUs */
1886 RtlInitUnicodeString(&ValueName
, L
"NUMBER_OF_PROCESSORS");
1887 swprintf(ValueBuffer
, L
"%u", BasicInfo
.NumberOfProcessors
);
1888 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1889 Status
= NtSetValueKey(KeyHandle
,
1894 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1895 if (!NT_SUCCESS(Status
))
1897 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1898 &ValueName
, Status
);
1903 /* Now we need to write the safeboot option key in a different format */
1904 RtlInitUnicodeString(&DestinationString
,
1905 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
1906 L
"Control\\Safeboot\\Option");
1907 InitializeObjectAttributes(&ObjectAttributes
,
1909 OBJ_CASE_INSENSITIVE
,
1912 Status
= NtOpenKey(&KeyHandle2
, KEY_ALL_ACCESS
, &ObjectAttributes
);
1913 if (NT_SUCCESS(Status
))
1915 /* This was indeed a safeboot, so check what kind of safeboot it was */
1916 RtlInitUnicodeString(&ValueName
, L
"OptionValue");
1917 Status
= NtQueryValueKey(KeyHandle2
,
1919 KeyValuePartialInformation
,
1921 sizeof(ValueBuffer
),
1923 NtClose(KeyHandle2
);
1924 if (NT_SUCCESS(Status
))
1926 /* Convert from the integer value to the correct specifier */
1927 RtlInitUnicodeString(&ValueName
, L
"SAFEBOOT_OPTION");
1928 switch (*(PULONG
)PartialInfo
->Data
)
1931 wcscpy(ValueBuffer
, L
"MINIMAL");
1934 wcscpy(ValueBuffer
, L
"NETWORK");
1937 wcscpy(ValueBuffer
, L
"DSREPAIR");
1941 /* And write it in the environment! */
1942 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1943 Status
= NtSetValueKey(KeyHandle
,
1948 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1949 if (!NT_SUCCESS(Status
))
1951 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1952 &ValueName
, Status
);
1959 DPRINT1("SMSS: Failed querying safeboot option = %x\n", Status
);
1963 /* We are all done now */
1965 return STATUS_SUCCESS
;
1970 SmpProcessFileRenames(VOID
)
1972 BOOLEAN OldState
, HavePrivilege
= FALSE
;
1974 HANDLE FileHandle
, OtherFileHandle
;
1975 FILE_INFORMATION_CLASS InformationClass
;
1976 OBJECT_ATTRIBUTES ObjectAttributes
;
1977 IO_STATUS_BLOCK IoStatusBlock
;
1978 UNICODE_STRING FileString
;
1979 FILE_BASIC_INFORMATION BasicInfo
;
1980 FILE_DISPOSITION_INFORMATION DeleteInformation
;
1981 PFILE_RENAME_INFORMATION Buffer
;
1982 PLIST_ENTRY Head
, NextEntry
;
1983 PSMP_REGISTRY_VALUE RegEntry
;
1985 ULONG ValueLength
, Length
;
1987 /* Give us access to restore any files we want */
1988 Status
= RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, TRUE
, FALSE
, &OldState
);
1989 if (NT_SUCCESS(Status
)) HavePrivilege
= TRUE
;
1991 /* Process pending files to rename */
1992 Head
= &SmpFileRenameList
;
1993 while (!IsListEmpty(Head
))
1995 /* Get this entry */
1996 NextEntry
= RemoveHeadList(Head
);
1997 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1998 DPRINT1("Processing PFRO: %wZ/%wZ\n", &RegEntry
->Value
, &RegEntry
->Name
);
2000 /* Skip past the '@' marker */
2001 if (!(RegEntry
->Value
.Length
) && (*RegEntry
->Name
.Buffer
== L
'@'))
2003 RegEntry
->Name
.Length
-= sizeof(UNICODE_NULL
);
2004 RegEntry
->Name
.Buffer
++;
2007 /* Open the file for delete access */
2008 InitializeObjectAttributes(&ObjectAttributes
,
2010 OBJ_CASE_INSENSITIVE
,
2013 Status
= NtOpenFile(&OtherFileHandle
,
2014 DELETE
| SYNCHRONIZE
,
2017 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2018 FILE_SYNCHRONOUS_IO_NONALERT
);
2019 if (!NT_SUCCESS(Status
)) goto Quickie
;
2021 /* Check if it's a rename or just a delete */
2022 ValueLength
= RegEntry
->Value
.Length
;
2025 /* Just a delete, set up the class, length and buffer */
2026 InformationClass
= FileDispositionInformation
;
2027 Length
= sizeof(DeleteInformation
);
2028 Buffer
= (PFILE_RENAME_INFORMATION
)&DeleteInformation
;
2030 /* Set the delete disposition */
2031 DeleteInformation
.DeleteFile
= TRUE
;
2035 /* This is a rename, setup the class and length */
2036 InformationClass
= FileRenameInformation
;
2037 Length
= ValueLength
+ sizeof(FILE_RENAME_INFORMATION
);
2039 /* Skip past the special markers */
2040 FileName
= RegEntry
->Value
.Buffer
;
2041 if ((*FileName
== L
'!') || (*FileName
== L
'@'))
2044 Length
-= sizeof(UNICODE_NULL
);
2047 /* Now allocate the buffer for the rename information */
2048 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag
, Length
);
2051 /* Setup the buffer to point to the filename, and copy it */
2052 Buffer
->RootDirectory
= NULL
;
2053 Buffer
->FileNameLength
= Length
- sizeof(FILE_RENAME_INFORMATION
);
2054 Buffer
->ReplaceIfExists
= FileName
!= RegEntry
->Value
.Buffer
;
2055 RtlCopyMemory(Buffer
->FileName
, FileName
, Buffer
->FileNameLength
);
2060 Status
= STATUS_NO_MEMORY
;
2064 /* Check if everything is okay till here */
2065 if (NT_SUCCESS(Status
))
2067 /* Now either rename or delete the file as requested */
2068 Status
= NtSetInformationFile(OtherFileHandle
,
2074 /* Check if we seem to have failed because the file was readonly */
2075 if ((NT_SUCCESS(Status
) &&
2076 (InformationClass
== FileRenameInformation
) &&
2077 (Status
== STATUS_OBJECT_NAME_COLLISION
) &&
2078 (Buffer
->ReplaceIfExists
)))
2080 /* Open the file for write attribute access this time... */
2081 DPRINT1("\nSMSS: %wZ => %wZ failed - Status == %x, Possible readonly target\n",
2084 STATUS_OBJECT_NAME_COLLISION
);
2085 FileString
.Length
= RegEntry
->Value
.Length
- sizeof(WCHAR
);
2086 FileString
.MaximumLength
= RegEntry
->Value
.MaximumLength
- sizeof(WCHAR
);
2087 FileString
.Buffer
= FileName
;
2088 InitializeObjectAttributes(&ObjectAttributes
,
2090 OBJ_CASE_INSENSITIVE
,
2093 Status
= NtOpenFile(&FileHandle
,
2094 FILE_WRITE_ATTRIBUTES
| SYNCHRONIZE
,
2097 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2098 FILE_SYNCHRONOUS_IO_NONALERT
);
2099 if (!NT_SUCCESS(Status
))
2101 /* That didn't work, so bail out */
2102 DPRINT1(" SMSS: Open Existing file Failed - Status == %x\n",
2107 /* Now remove the read-only attribute from the file */
2108 DPRINT1(" SMSS: Open Existing Success\n");
2109 RtlZeroMemory(&BasicInfo
, sizeof(BasicInfo
));
2110 BasicInfo
.FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
2111 Status
= NtSetInformationFile(FileHandle
,
2115 FileBasicInformation
);
2116 NtClose(FileHandle
);
2117 if (!NT_SUCCESS(Status
))
2119 /* That didn't work, bail out */
2120 DPRINT1(" SMSS: Set To NORMAL Failed - Status == %x\n",
2125 /* Now that the file is no longer read-only, delete! */
2126 DPRINT1(" SMSS: Set To NORMAL OK\n");
2127 Status
= NtSetInformationFile(OtherFileHandle
,
2131 FileRenameInformation
);
2132 if (!NT_SUCCESS(Status
))
2134 /* That failed too! */
2135 DPRINT1(" SMSS: Re-Rename Failed - Status == %x\n",
2141 DPRINT1(" SMSS: Re-Rename Worked OK\n");
2148 /* Close the file handle and check the operation result */
2149 NtClose(OtherFileHandle
);
2151 if (!NT_SUCCESS(Status
))
2153 /* We totally failed */
2154 DPRINT1("SMSS: %wZ => %wZ failed - Status == %x\n",
2155 &RegEntry
->Name
, &RegEntry
->Value
, Status
);
2157 else if (RegEntry
->Value
.Length
)
2159 /* We succeed with a rename */
2160 DPRINT1("SMSS: %wZ (renamed to) %wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
2164 /* We suceeded with a delete */
2165 DPRINT1("SMSS: %wZ (deleted)\n", &RegEntry
->Name
);
2168 /* Now free this entry and keep going */
2169 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2170 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2171 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2174 /* Put back the restore privilege if we had requested it, and return */
2175 if (HavePrivilege
) RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, FALSE
, FALSE
, &OldState
);
2181 SmpLoadDataFromRegistry(OUT PUNICODE_STRING InitialCommand
)
2184 PLIST_ENTRY Head
, NextEntry
;
2185 PSMP_REGISTRY_VALUE RegEntry
;
2186 PVOID OriginalEnvironment
;
2187 ULONG MuSessionId
= 0;
2188 OBJECT_ATTRIBUTES ObjectAttributes
;
2190 UNICODE_STRING DestinationString
;
2192 /* Initialize the keywords we'll be looking for */
2193 RtlInitUnicodeString(&SmpDebugKeyword
, L
"debug");
2194 RtlInitUnicodeString(&SmpASyncKeyword
, L
"async");
2195 RtlInitUnicodeString(&SmpAutoChkKeyword
, L
"autocheck");
2197 /* Initialize all the registry-associated list heads */
2198 InitializeListHead(&SmpBootExecuteList
);
2199 InitializeListHead(&SmpSetupExecuteList
);
2200 InitializeListHead(&SmpPagingFileList
);
2201 InitializeListHead(&SmpDosDevicesList
);
2202 InitializeListHead(&SmpFileRenameList
);
2203 InitializeListHead(&SmpKnownDllsList
);
2204 InitializeListHead(&SmpExcludeKnownDllsList
);
2205 InitializeListHead(&SmpSubSystemList
);
2206 InitializeListHead(&SmpSubSystemsToLoad
);
2207 InitializeListHead(&SmpSubSystemsToDefer
);
2208 InitializeListHead(&SmpExecuteList
);
2209 SmpPagingFileInitialize();
2211 /* Initialize the SMSS environment */
2212 Status
= RtlCreateEnvironment(TRUE
, &SmpDefaultEnvironment
);
2213 if (!NT_SUCCESS(Status
))
2215 /* Fail if there was a problem */
2216 DPRINT1("SMSS: Unable to allocate default environment - Status == %X\n",
2218 SMSS_CHECKPOINT(RtlCreateEnvironment
, Status
);
2222 /* Check if we were booted in PE mode (LiveCD should have this) */
2223 RtlInitUnicodeString(&DestinationString
,
2224 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
2225 L
"Control\\MiniNT");
2226 InitializeObjectAttributes(&ObjectAttributes
,
2228 OBJ_CASE_INSENSITIVE
,
2231 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
2232 if (NT_SUCCESS(Status
))
2234 /* If the key exists, we were */
2239 /* Print out if this is the case */
2240 if (MiniNTBoot
) DPRINT1("SMSS: !!! MiniNT Boot !!!\n");
2242 /* Open the environment key to see if we are booted in safe mode */
2243 RtlInitUnicodeString(&DestinationString
,
2244 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
2245 L
"Control\\Session Manager\\Environment");
2246 InitializeObjectAttributes(&ObjectAttributes
,
2248 OBJ_CASE_INSENSITIVE
,
2251 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
2252 if (NT_SUCCESS(Status
))
2254 /* Delete the value if we found it */
2255 RtlInitUnicodeString(&DestinationString
, L
"SAFEBOOT_OPTION");
2256 NtDeleteValueKey(KeyHandle
, &DestinationString
);
2260 /* Switch environments, then query the registry for all needed settings */
2261 OriginalEnvironment
= NtCurrentPeb()->ProcessParameters
->Environment
;
2262 NtCurrentPeb()->ProcessParameters
->Environment
= SmpDefaultEnvironment
;
2263 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
2265 SmpRegistryConfigurationTable
,
2268 SmpDefaultEnvironment
= NtCurrentPeb()->ProcessParameters
->Environment
;
2269 NtCurrentPeb()->ProcessParameters
->Environment
= OriginalEnvironment
;
2270 if (!NT_SUCCESS(Status
))
2272 /* We failed somewhere in registry initialization, which is bad... */
2273 DPRINT1("SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status
);
2274 SMSS_CHECKPOINT(RtlQueryRegistryValues
, Status
);
2278 /* Now we can start acting on the registry settings. First to DOS devices */
2279 Status
= SmpInitializeDosDevices();
2280 if (!NT_SUCCESS(Status
))
2283 DPRINT1("SMSS: Unable to initialize DosDevices configuration - Status == %lx\n",
2285 SMSS_CHECKPOINT(SmpInitializeDosDevices
, Status
);
2289 /* Next create the session directory... */
2290 RtlInitUnicodeString(&DestinationString
, L
"\\Sessions");
2291 InitializeObjectAttributes(&ObjectAttributes
,
2293 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
2295 SmpPrimarySecurityDescriptor
);
2296 Status
= NtCreateDirectoryObject(&SmpSessionsObjectDirectory
,
2297 DIRECTORY_ALL_ACCESS
,
2299 if (!NT_SUCCESS(Status
))
2302 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
2303 &DestinationString
, Status
);
2304 SMSS_CHECKPOINT(NtCreateDirectoryObject
, Status
);
2308 /* Next loop all the boot execute binaries */
2309 Head
= &SmpBootExecuteList
;
2310 while (!IsListEmpty(Head
))
2312 /* Remove each one from the list */
2313 NextEntry
= RemoveHeadList(Head
);
2316 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2317 SmpExecuteCommand(&RegEntry
->Name
, 0, NULL
, 0);
2320 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2321 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2322 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2325 /* Now do any pending file rename operations... */
2326 if (!MiniNTBoot
) SmpProcessFileRenames();
2328 /* And initialize known DLLs... */
2329 Status
= SmpInitializeKnownDlls();
2330 if (!NT_SUCCESS(Status
))
2332 /* Fail if that didn't work */
2333 DPRINT1("SMSS: Unable to initialize KnownDll configuration - Status == %lx\n",
2335 SMSS_CHECKPOINT(SmpInitializeKnownDlls
, Status
);
2339 /* Loop every page file */
2340 Head
= &SmpPagingFileList
;
2341 while (!IsListEmpty(Head
))
2343 /* Remove each one from the list */
2344 NextEntry
= RemoveHeadList(Head
);
2346 /* Create the descriptor for it */
2347 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2348 SmpCreatePagingFileDescriptor(&RegEntry
->Name
);
2351 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2352 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2353 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2356 /* Now create all the paging files for the descriptors that we have */
2357 SmpCreatePagingFiles();
2359 /* Tell Cm it's now safe to fully enable write access to the registry */
2360 NtInitializeRegistry(CM_BOOT_FLAG_SMSS
);
2362 /* Create all the system-based environment variables for later inheriting */
2363 Status
= SmpCreateDynamicEnvironmentVariables();
2364 if (!NT_SUCCESS(Status
))
2366 /* Handle failure */
2367 SMSS_CHECKPOINT(SmpCreateDynamicEnvironmentVariables
, Status
);
2371 /* And finally load all the subsytems for our first session! */
2372 Status
= SmpLoadSubSystemsForMuSession(&MuSessionId
,
2373 &SmpWindowsSubSysProcessId
,
2375 ASSERT(MuSessionId
== 0);
2376 if (!NT_SUCCESS(Status
)) SMSS_CHECKPOINT(SmpLoadSubSystemsForMuSession
, Status
);
2382 SmpInit(IN PUNICODE_STRING InitialCommand
,
2383 OUT PHANDLE ProcessHandle
)
2385 NTSTATUS Status
, Status2
;
2386 OBJECT_ATTRIBUTES ObjectAttributes
;
2387 UNICODE_STRING PortName
, EventName
;
2388 HANDLE EventHandle
, PortHandle
;
2389 ULONG HardErrorMode
;
2391 /* Create the SMSS Heap */
2392 SmBaseTag
= RtlCreateTagHeap(RtlGetProcessHeap(),
2396 SmpHeap
= RtlGetProcessHeap();
2398 /* Enable hard errors */
2399 HardErrorMode
= TRUE
;
2400 NtSetInformationProcess(NtCurrentProcess(),
2401 ProcessDefaultHardErrorMode
,
2403 sizeof(HardErrorMode
));
2405 /* Initialize the subsystem list and the session list, plus their locks */
2406 RtlInitializeCriticalSection(&SmpKnownSubSysLock
);
2407 InitializeListHead(&SmpKnownSubSysHead
);
2408 RtlInitializeCriticalSection(&SmpSessionListLock
);
2409 InitializeListHead(&SmpSessionListHead
);
2411 /* Initialize the process list */
2412 InitializeListHead(&NativeProcessList
);
2414 /* Initialize session parameters */
2415 SmpNextSessionId
= 1;
2416 SmpNextSessionIdScanMode
= 0;
2417 SmpDbgSsLoaded
= FALSE
;
2419 /* Create the initial security descriptors */
2420 Status
= SmpCreateSecurityDescriptors(TRUE
);
2421 if (!NT_SUCCESS(Status
))
2424 SMSS_CHECKPOINT(SmpCreateSecurityDescriptors
, Status
);
2428 /* Initialize subsystem names */
2429 RtlInitUnicodeString(&SmpSubsystemName
, L
"NT-Session Manager");
2430 RtlInitUnicodeString(&PosixName
, L
"POSIX");
2431 RtlInitUnicodeString(&Os2Name
, L
"OS2");
2433 /* Create the SM API Port */
2434 RtlInitUnicodeString(&PortName
, L
"\\SmApiPort2");
2435 InitializeObjectAttributes(&ObjectAttributes
, &PortName
, 0, NULL
, NULL
);
2436 Status
= NtCreatePort(&PortHandle
,
2438 sizeof(SB_CONNECTION_INFO
),
2440 sizeof(SB_API_MSG
) * 32);
2441 ASSERT(NT_SUCCESS(Status
));
2442 SmpDebugPort
= PortHandle
;
2444 /* Create two SM API threads */
2445 Status
= RtlCreateUserThread(NtCurrentProcess(),
2455 ASSERT(NT_SUCCESS(Status
));
2456 Status
= RtlCreateUserThread(NtCurrentProcess(),
2466 ASSERT(NT_SUCCESS(Status
));
2468 /* Create the write event that autochk can set after running */
2469 RtlInitUnicodeString(&EventName
, L
"\\Device\\VolumesSafeForWriteAccess");
2470 InitializeObjectAttributes(&ObjectAttributes
,
2475 Status2
= NtCreateEvent(&EventHandle
,
2480 if (!NT_SUCCESS(Status2
))
2482 /* Should never really fail */
2483 DPRINT1("SMSS: Unable to create %wZ event - Status == %lx\n",
2484 &EventName
, Status2
);
2485 ASSERT(NT_SUCCESS(Status2
));
2488 /* Now initialize everything else based on the registry parameters */
2489 Status
= SmpLoadDataFromRegistry(InitialCommand
);
2490 if (NT_SUCCESS(Status
))
2492 /* Autochk should've run now. Set the event and save the CSRSS handle */
2493 *ProcessHandle
= SmpWindowsSubSysProcess
;
2494 NtSetEvent(EventHandle
, 0);
2495 NtClose(EventHandle
);