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 *******************************************************************/
16 /* GLOBALS ********************************************************************/
18 UNICODE_STRING SmpSubsystemName
, PosixName
, Os2Name
;
19 LIST_ENTRY SmpBootExecuteList
, SmpSetupExecuteList
, SmpPagingFileList
;
20 LIST_ENTRY SmpDosDevicesList
, SmpFileRenameList
, SmpKnownDllsList
;
21 LIST_ENTRY SmpExcludeKnownDllsList
, SmpSubSystemList
, SmpSubSystemsToLoad
;
22 LIST_ENTRY SmpSubSystemsToDefer
, SmpExecuteList
, NativeProcessList
;
26 HANDLE SmpDebugPort
, SmpDosDevicesObjectDirectory
;
27 PWCHAR SmpDefaultEnvironment
, SmpDefaultLibPathBuffer
;
28 UNICODE_STRING SmpKnownDllPath
, SmpDefaultLibPath
;
29 ULONG SmpCalledConfigEnv
;
31 ULONG SmpInitProgressByLine
;
32 NTSTATUS SmpInitReturnStatus
;
33 PVOID SmpInitLastCall
;
35 SECURITY_DESCRIPTOR SmpPrimarySDBody
, SmpLiberalSDBody
, SmpKnownDllsSDBody
;
36 SECURITY_DESCRIPTOR SmpApiPortSDBody
;
37 PISECURITY_DESCRIPTOR SmpPrimarySecurityDescriptor
, SmpLiberalSecurityDescriptor
;
38 PISECURITY_DESCRIPTOR SmpKnownDllsSecurityDescriptor
, SmpApiPortSecurityDescriptor
;
40 ULONG SmpAllowProtectedRenames
, SmpProtectionMode
= 1;
43 #define SMSS_CHECKPOINT(x, y) \
45 SmpInitProgressByLine = __LINE__; \
46 SmpInitReturnStatus = (y); \
47 SmpInitLastCall = (x); \
50 /* REGISTRY CONFIGURATION *****************************************************/
54 SmpSaveRegistryValue(IN PLIST_ENTRY ListAddress
,
59 PSMP_REGISTRY_VALUE RegEntry
;
60 UNICODE_STRING NameString
, ValueString
;
61 ANSI_STRING AnsiValueString
;
62 PLIST_ENTRY NextEntry
;
64 /* Convert to unicode strings */
65 RtlInitUnicodeString(&NameString
, Name
);
66 RtlInitUnicodeString(&ValueString
, Value
);
68 /* In case this is the first value, initialize a new list/structure */
71 /* Check if we should do a duplicate check */
74 /* Loop the current list */
75 NextEntry
= ListAddress
->Flink
;
76 while (NextEntry
!= ListAddress
)
79 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
81 /* Check if the value name matches */
82 if (!RtlCompareUnicodeString(&RegEntry
->Name
, &NameString
, TRUE
))
84 /* Check if the value is the exact same thing */
85 if (!RtlCompareUnicodeString(&RegEntry
->Value
, &ValueString
, TRUE
))
87 /* Fail -- the same setting is being set twice */
88 return STATUS_OBJECT_NAME_EXISTS
;
91 /* We found the list, and this isn't a duplicate value */
95 /* This wasn't a match, keep going */
96 NextEntry
= NextEntry
->Flink
;
101 /* Are we adding on, or creating a new entry */
104 /* A new entry -- allocate it */
105 RegEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
107 NameString
.MaximumLength
+
108 sizeof(SMP_REGISTRY_VALUE
));
109 if (!RegEntry
) return STATUS_NO_MEMORY
;
111 /* Initialize the list and set all values to NULL */
112 InitializeListHead(&RegEntry
->Entry
);
113 RegEntry
->AnsiValue
= NULL
;
114 RegEntry
->Value
.Buffer
= NULL
;
116 /* Copy and initialize the value name */
117 RegEntry
->Name
.Buffer
= (PWCHAR
)(RegEntry
+ 1);
118 RegEntry
->Name
.Length
= NameString
.Length
;
119 RegEntry
->Name
.MaximumLength
= NameString
.MaximumLength
;
120 RtlCopyMemory(RegEntry
->Name
.Buffer
,
122 NameString
.MaximumLength
);
124 /* Add this entry into the list */
125 InsertTailList(ListAddress
, &RegEntry
->Entry
);
128 /* Did we have an old value buffer? */
129 if (RegEntry
->Value
.Buffer
)
132 ASSERT(RegEntry
->Value
.Length
!= 0);
133 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
136 /* Is there no value associated? */
139 /* We're done here */
140 RtlInitUnicodeString(&RegEntry
->Value
, NULL
);
141 return STATUS_SUCCESS
;
144 /* There is a value, so allocate a buffer for it */
145 RegEntry
->Value
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
147 ValueString
.MaximumLength
);
148 if (!RegEntry
->Value
.Buffer
)
150 /* Out of memory, undo */
151 RemoveEntryList(&RegEntry
->Entry
);
152 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
153 return STATUS_NO_MEMORY
;
156 /* Copy the value into the entry */
157 RegEntry
->Value
.Length
= ValueString
.Length
;
158 RegEntry
->Value
.MaximumLength
= ValueString
.MaximumLength
;
159 RtlCopyMemory(RegEntry
->Value
.Buffer
,
161 ValueString
.MaximumLength
);
163 /* Now allocate memory for an ANSI copy of it */
164 RegEntry
->AnsiValue
= RtlAllocateHeap(RtlGetProcessHeap(),
166 (ValueString
.Length
/ sizeof(WCHAR
)) +
168 if (!RegEntry
->AnsiValue
)
170 /* Out of memory, undo */
171 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
172 RemoveEntryList(&RegEntry
->Entry
);
173 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
174 return STATUS_NO_MEMORY
;
177 /* Convert the Unicode value string and return success */
178 RtlInitEmptyAnsiString(&AnsiValueString
,
180 (ValueString
.Length
/ sizeof(WCHAR
)) +
182 RtlUnicodeStringToAnsiString(&AnsiValueString
, &ValueString
, FALSE
);
183 return STATUS_SUCCESS
;
188 SmpFindRegistryValue(IN PLIST_ENTRY List
,
191 PSMP_REGISTRY_VALUE RegEntry
;
192 UNICODE_STRING ValueString
;
193 PLIST_ENTRY NextEntry
;
195 /* Initialize the value name sting */
196 RtlInitUnicodeString(&ValueString
, ValueName
);
199 NextEntry
= List
->Flink
;
200 while (NextEntry
!= List
)
203 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
205 /* Check if the value name matches */
206 if (!RtlCompareUnicodeString(&RegEntry
->Name
, &ValueString
, TRUE
)) break;
208 /* It doesn't, move on */
209 NextEntry
= NextEntry
->Flink
;
212 /* If we looped back, return NULL, otherwise return the entry we found */
213 if (NextEntry
== List
) RegEntry
= NULL
;
219 SmpConfigureProtectionMode(IN PWSTR ValueName
,
222 IN ULONG ValueLength
,
224 IN PVOID EntryContext
)
226 /* Make sure the value is valid */
227 if (ValueLength
== sizeof(ULONG
))
230 SmpProtectionMode
= *(PULONG
)ValueData
;
234 /* Default is to protect stuff */
235 SmpProtectionMode
= 1;
238 /* Recreate the security descriptors to take into account security mode */
239 SmpCreateSecurityDescriptors(FALSE
);
240 DPRINT("SmpProtectionMode: %lu\n", SmpProtectionMode
);
241 return STATUS_SUCCESS
;
246 SmpConfigureAllowProtectedRenames(IN PWSTR ValueName
,
249 IN ULONG ValueLength
,
251 IN PVOID EntryContext
)
253 /* Make sure the value is valid */
254 if (ValueLength
== sizeof(ULONG
))
257 SmpAllowProtectedRenames
= *(PULONG
)ValueData
;
261 /* Default is to not allow protected renames */
262 SmpAllowProtectedRenames
= 0;
265 DPRINT("SmpAllowProtectedRenames: %lu\n", SmpAllowProtectedRenames
);
266 return STATUS_SUCCESS
;
271 SmpConfigureObjectDirectories(IN PWSTR ValueName
,
274 IN ULONG ValueLength
,
276 IN PVOID EntryContext
)
278 PISECURITY_DESCRIPTOR SecDescriptor
;
280 OBJECT_ATTRIBUTES ObjectAttributes
;
282 UNICODE_STRING RpcString
, WindowsString
, SearchString
;
283 PWCHAR SourceString
= ValueData
;
285 /* Initialize the two strings we will be looking for */
286 RtlInitUnicodeString(&RpcString
, L
"\\RPC Control");
287 RtlInitUnicodeString(&WindowsString
, L
"\\Windows");
289 /* Loop the registry data we received */
290 while (*SourceString
)
292 /* Assume primary SD for most objects */
293 RtlInitUnicodeString(&SearchString
, SourceString
);
294 SecDescriptor
= SmpPrimarySecurityDescriptor
;
296 /* But for these two always set the liberal descriptor */
297 if ((RtlEqualUnicodeString(&SearchString
, &RpcString
, TRUE
)) ||
298 (RtlEqualUnicodeString(&SearchString
, &WindowsString
, TRUE
)))
300 SecDescriptor
= SmpLiberalSecurityDescriptor
;
303 /* Create the requested directory with the requested descriptor */
304 InitializeObjectAttributes(&ObjectAttributes
,
306 OBJ_CASE_INSENSITIVE
|
311 DPRINT("Creating: %wZ directory\n", &SearchString
);
312 Status
= NtCreateDirectoryObject(&DirHandle
,
313 DIRECTORY_ALL_ACCESS
,
315 if (!NT_SUCCESS(Status
))
318 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
319 &SearchString
, Status
);
323 /* It worked, now close the handle */
327 /* Move to the next requested object */
328 while (*SourceString
++);
332 return STATUS_SUCCESS
;
337 SmpConfigureMemoryMgmt(IN PWSTR ValueName
,
340 IN ULONG ValueLength
,
342 IN PVOID EntryContext
)
344 /* Save this is into a list */
345 return SmpSaveRegistryValue(EntryContext
, ValueData
, NULL
, TRUE
);
350 SmpConfigureFileRenames(IN PWSTR ValueName
,
353 IN ULONG ValueLength
,
355 IN PVOID EntryContext
)
358 static PWCHAR Canary
;
360 /* Check if this is the second call */
363 /* Save the data into the list */
364 DPRINT1("Renamed file: %S-%S\n", Canary
, ValueData
);
365 Status
= SmpSaveRegistryValue(EntryContext
, Canary
, ValueData
, FALSE
);
370 /* This it the first call, do nothing until we get the second call */
372 Status
= STATUS_SUCCESS
;
375 /* Return the status */
381 SmpConfigureExcludeKnownDlls(IN PWSTR ValueName
,
384 IN ULONG ValueLength
,
386 IN PVOID EntryContext
)
391 /* Make sure the value type is valid */
392 if ((ValueType
== REG_MULTI_SZ
) || (ValueType
== REG_SZ
))
394 /* Keep going for each DLL in the list */
398 /* Add this to the linked list */
399 DPRINT("Excluded DLL: %S\n", DllName
);
400 Status
= SmpSaveRegistryValue(EntryContext
, DllName
, NULL
, TRUE
);
402 /* Bail out on failure or if only one DLL name was present */
403 if (!(NT_SUCCESS(Status
)) || (ValueType
== REG_SZ
)) return Status
;
405 /* Otherwise, move to the next DLL name */
411 return STATUS_SUCCESS
;
416 SmpConfigureDosDevices(IN PWSTR ValueName
,
419 IN ULONG ValueLength
,
421 IN PVOID EntryContext
)
423 /* Save into linked list */
424 return SmpSaveRegistryValue(EntryContext
, ValueName
, ValueData
, TRUE
);
429 SmpInitializeKnownDllPath(IN PUNICODE_STRING DllPath
,
435 /* Allocate the buffer */
436 DllPath
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag
, Length
);
439 /* Fill out the rest of the string */
440 DllPath
->MaximumLength
= (USHORT
)Length
;
441 DllPath
->Length
= (USHORT
)Length
- sizeof(UNICODE_NULL
);
443 /* Copy the actual path and return success */
444 RtlCopyMemory(DllPath
->Buffer
, Buffer
, Length
);
445 Status
= STATUS_SUCCESS
;
449 /* Fail with out of memory code */
450 Status
= STATUS_NO_MEMORY
;
459 SmpConfigureKnownDlls(IN PWSTR ValueName
,
462 IN ULONG ValueLength
,
464 IN PVOID EntryContext
)
466 /* Check which value is being set */
467 if (_wcsicmp(ValueName
, L
"DllDirectory") == 0)
469 /* This is the directory, initialize it */
470 DPRINT("KnownDll Path: %S\n", ValueData
);
471 return SmpInitializeKnownDllPath(&SmpKnownDllPath
, ValueData
, ValueLength
);
475 /* Add to the linked list -- this is a file */
476 return SmpSaveRegistryValue(EntryContext
, ValueName
, ValueData
, TRUE
);
482 SmpConfigureEnvironment(IN PWSTR ValueName
,
485 IN ULONG ValueLength
,
487 IN PVOID EntryContext
)
490 UNICODE_STRING ValueString
, DataString
;
492 /* Convert the strings into UNICODE_STRING and set the variable defined */
493 RtlInitUnicodeString(&ValueString
, ValueName
);
494 RtlInitUnicodeString(&DataString
, ValueData
);
495 DPRINT("Setting %wZ = %wZ\n", &ValueString
, &DataString
);
496 Status
= RtlSetEnvironmentVariable(0, &ValueString
, &DataString
);
497 if (!NT_SUCCESS(Status
))
499 DPRINT1("SMSS: 'SET %wZ = %wZ' failed - Status == %lx\n",
500 &ValueString
, &DataString
, Status
);
504 /* Check if the path is being set, and wait for the second instantiation */
505 if ((_wcsicmp(ValueName
, L
"Path") == 0) && (++SmpCalledConfigEnv
== 2))
507 /* Allocate the path buffer */
508 SmpDefaultLibPathBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
511 if (!SmpDefaultLibPathBuffer
) return STATUS_NO_MEMORY
;
513 /* Copy the data into it and create the UNICODE_STRING to hold it */
514 RtlCopyMemory(SmpDefaultLibPathBuffer
, ValueData
, ValueLength
);
515 RtlInitUnicodeString(&SmpDefaultLibPath
, SmpDefaultLibPathBuffer
);
519 return STATUS_SUCCESS
;
524 SmpConfigureSubSystems(IN PWSTR ValueName
,
527 IN ULONG ValueLength
,
529 IN PVOID EntryContext
)
531 PSMP_REGISTRY_VALUE RegEntry
;
532 PWCHAR SubsystemName
;
534 /* Is this a required or optional subsystem? */
535 if ((_wcsicmp(ValueName
, L
"Required") != 0) &&
536 (_wcsicmp(ValueName
, L
"Optional") != 0))
538 /* It isn't, is this the PSI flag? */
539 if ((_wcsicmp(ValueName
, L
"PosixSingleInstance") != 0) ||
540 (ValueType
!= REG_DWORD
))
542 /* It isn't, must be a subsystem entry, add it to the list */
543 DPRINT("Subsystem entry: %S-%S\n", ValueName
, ValueData
);
544 return SmpSaveRegistryValue(EntryContext
, ValueName
, ValueData
, TRUE
);
547 /* This was the PSI flag, save it and exit */
548 RegPosixSingleInstance
= TRUE
;
549 return STATUS_SUCCESS
;
552 /* This should be one of the required/optional lists. Is the type valid? */
553 if (ValueType
== REG_MULTI_SZ
)
555 /* It is, get the first subsystem */
556 SubsystemName
= ValueData
;
557 while (*SubsystemName
)
559 /* We should have already put it into the list when we found it */
560 DPRINT("Found subsystem: %S\n", SubsystemName
);
561 RegEntry
= SmpFindRegistryValue(EntryContext
, SubsystemName
);
564 /* This subsystem doesn't exist, so skip it */
565 DPRINT1("SMSS: Invalid subsystem name - %ws\n", SubsystemName
);
569 /* Found it -- remove it from the main list */
570 RemoveEntryList(&RegEntry
->Entry
);
572 /* Figure out which list to put it in */
573 if (_wcsicmp(ValueName
, L
"Required") == 0)
575 /* Put it into the required list */
576 DPRINT("Required\n");
577 InsertTailList(&SmpSubSystemsToLoad
, &RegEntry
->Entry
);
581 /* Put it into the optional list */
582 DPRINT("Optional\n");
583 InsertTailList(&SmpSubSystemsToDefer
, &RegEntry
->Entry
);
587 /* Move to the next name */
588 while (*SubsystemName
++);
593 return STATUS_SUCCESS
;
596 RTL_QUERY_REGISTRY_TABLE
597 SmpRegistryConfigurationTable
[] =
600 SmpConfigureProtectionMode
,
610 SmpConfigureAllowProtectedRenames
,
611 0, //RTL_QUERY_REGISTRY_DELETE,
612 L
"AllowProtectedRenames",
620 SmpConfigureObjectDirectories
,
622 L
"ObjectDirectories",
625 L
"\\Windows\0\\RPC Control\0",
630 SmpConfigureMemoryMgmt
,
635 L
"autocheck AutoChk.exe *\0",
640 SmpConfigureMemoryMgmt
,
641 RTL_QUERY_REGISTRY_TOPKEY
,
643 &SmpSetupExecuteList
,
650 SmpConfigureFileRenames
,
651 0, //RTL_QUERY_REGISTRY_DELETE,
652 L
"PendingFileRenameOperations",
660 SmpConfigureFileRenames
,
661 0, //RTL_QUERY_REGISTRY_DELETE,
662 L
"PendingFileRenameOperations2",
670 SmpConfigureExcludeKnownDlls
,
672 L
"ExcludeFromKnownDlls",
673 &SmpExcludeKnownDllsList
,
681 RTL_QUERY_REGISTRY_SUBKEY
,
682 L
"Memory Management",
690 SmpConfigureMemoryMgmt
,
695 L
"?:\\pagefile.sys\0",
700 SmpConfigureDosDevices
,
701 RTL_QUERY_REGISTRY_SUBKEY
,
710 SmpConfigureKnownDlls
,
711 RTL_QUERY_REGISTRY_SUBKEY
,
720 SmpConfigureEnvironment
,
721 RTL_QUERY_REGISTRY_SUBKEY
,
730 SmpConfigureSubSystems
,
731 RTL_QUERY_REGISTRY_SUBKEY
,
740 SmpConfigureSubSystems
,
741 RTL_QUERY_REGISTRY_NOEXPAND
,
750 SmpConfigureSubSystems
,
751 RTL_QUERY_REGISTRY_NOEXPAND
,
760 SmpConfigureSubSystems
,
770 SmpConfigureMemoryMgmt
,
771 RTL_QUERY_REGISTRY_TOPKEY
,
782 /* FUNCTIONS ******************************************************************/
786 SmpTranslateSystemPartitionInformation(VOID
)
789 UNICODE_STRING UnicodeString
, LinkTarget
, SearchString
, SystemPartition
;
790 OBJECT_ATTRIBUTES ObjectAttributes
;
791 HANDLE KeyHandle
, LinkHandle
;
792 CHAR ValueBuffer
[512 + sizeof(KEY_VALUE_PARTIAL_INFORMATION
)];
793 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PVOID
)ValueBuffer
;
794 ULONG Length
, Context
;
795 CHAR DirInfoBuffer
[512 + sizeof(OBJECT_DIRECTORY_INFORMATION
)];
796 POBJECT_DIRECTORY_INFORMATION DirInfo
= (PVOID
)DirInfoBuffer
;
797 WCHAR LinkBuffer
[MAX_PATH
];
799 /* Open the setup key */
800 RtlInitUnicodeString(&UnicodeString
, L
"\\Registry\\Machine\\System\\Setup");
801 InitializeObjectAttributes(&ObjectAttributes
,
803 OBJ_CASE_INSENSITIVE
,
806 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
807 if (!NT_SUCCESS(Status
))
809 DPRINT1("SMSS: can't open system setup key for reading: 0x%x\n", Status
);
813 /* Query the system partition */
814 RtlInitUnicodeString(&UnicodeString
, L
"SystemPartition");
815 Status
= NtQueryValueKey(KeyHandle
,
817 KeyValuePartialInformation
,
822 if (!NT_SUCCESS(Status
))
824 DPRINT1("SMSS: can't query SystemPartition value: 0x%x\n", Status
);
828 /* Initialize the system partition string string */
829 RtlInitUnicodeString(&SystemPartition
, (PWCHAR
)PartialInfo
->Data
);
831 /* Enumerate the directory looking for the symbolic link string */
832 RtlInitUnicodeString(&SearchString
, L
"SymbolicLink");
833 RtlInitEmptyUnicodeString(&LinkTarget
, LinkBuffer
, sizeof(LinkBuffer
));
834 Status
= NtQueryDirectoryObject(SmpDosDevicesObjectDirectory
,
836 sizeof(DirInfoBuffer
),
841 if (!NT_SUCCESS(Status
))
843 DPRINT1("SMSS: can't find drive letter for system partition\n");
847 /* Keep searching until we find it */
851 if ((RtlEqualUnicodeString(&DirInfo
->TypeName
, &SearchString
, TRUE
)) &&
852 (DirInfo
->Name
.Length
== 2 * sizeof(WCHAR
)) &&
853 (DirInfo
->Name
.Buffer
[1] == L
':'))
855 /* Looks like we found it, open the link to get its target */
856 InitializeObjectAttributes(&ObjectAttributes
,
858 OBJ_CASE_INSENSITIVE
,
859 SmpDosDevicesObjectDirectory
,
861 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
862 SYMBOLIC_LINK_ALL_ACCESS
,
864 if (NT_SUCCESS(Status
))
866 /* Open worked, query the target now */
867 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
872 /* Check if it matches the string we had found earlier */
873 if ((NT_SUCCESS(Status
)) &&
874 ((RtlEqualUnicodeString(&SystemPartition
,
877 ((RtlPrefixUnicodeString(&SystemPartition
,
880 (LinkTarget
.Buffer
[SystemPartition
.Length
/ sizeof(WCHAR
)] == L
'\\'))))
888 /* Couldn't find it, try again */
889 Status
= NtQueryDirectoryObject(SmpDosDevicesObjectDirectory
,
891 sizeof(DirInfoBuffer
),
896 } while (NT_SUCCESS(Status
));
897 if (!NT_SUCCESS(Status
))
899 DPRINT1("SMSS: can't find drive letter for system partition\n");
903 /* Open the setup key again, for full access this time */
904 RtlInitUnicodeString(&UnicodeString
,
905 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup");
906 InitializeObjectAttributes(&ObjectAttributes
,
908 OBJ_CASE_INSENSITIVE
,
911 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
912 if (!NT_SUCCESS(Status
))
914 DPRINT1("SMSS: can't open software setup key for writing: 0x%x\n",
919 /* Wrap up the end of the link buffer */
920 wcsncpy(LinkBuffer
, DirInfo
->Name
.Buffer
, 2);
921 LinkBuffer
[2] = L
'\\';
922 LinkBuffer
[3] = L
'\0';
924 /* Now set this as the "BootDir" */
925 RtlInitUnicodeString(&UnicodeString
, L
"BootDir");
926 Status
= NtSetValueKey(KeyHandle
,
932 if (!NT_SUCCESS(Status
))
934 DPRINT1("SMSS: couldn't write BootDir value: 0x%x\n", Status
);
941 SmpCreateSecurityDescriptors(IN BOOLEAN InitialCall
)
944 PSID WorldSid
= NULL
, AdminSid
= NULL
, SystemSid
= NULL
;
945 PSID RestrictedSid
= NULL
, OwnerSid
= NULL
;
946 SID_IDENTIFIER_AUTHORITY WorldAuthority
= {SECURITY_WORLD_SID_AUTHORITY
};
947 SID_IDENTIFIER_AUTHORITY NtAuthority
= {SECURITY_NT_AUTHORITY
};
948 SID_IDENTIFIER_AUTHORITY CreatorAuthority
= {SECURITY_CREATOR_SID_AUTHORITY
};
949 ULONG AclLength
, SidLength
;
952 BOOLEAN ProtectionRequired
= FALSE
;
954 /* Check if this is the first call */
957 /* Create and set the primary descriptor */
958 SmpPrimarySecurityDescriptor
= &SmpPrimarySDBody
;
959 Status
= RtlCreateSecurityDescriptor(SmpPrimarySecurityDescriptor
,
960 SECURITY_DESCRIPTOR_REVISION
);
961 ASSERT(NT_SUCCESS(Status
));
962 Status
= RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor
,
966 ASSERT(NT_SUCCESS(Status
));
968 /* Create and set the liberal descriptor */
969 SmpLiberalSecurityDescriptor
= &SmpLiberalSDBody
;
970 Status
= RtlCreateSecurityDescriptor(SmpLiberalSecurityDescriptor
,
971 SECURITY_DESCRIPTOR_REVISION
);
972 ASSERT(NT_SUCCESS(Status
));
973 Status
= RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor
,
977 ASSERT(NT_SUCCESS(Status
));
979 /* Create and set the \KnownDlls descriptor */
980 SmpKnownDllsSecurityDescriptor
= &SmpKnownDllsSDBody
;
981 Status
= RtlCreateSecurityDescriptor(SmpKnownDllsSecurityDescriptor
,
982 SECURITY_DESCRIPTOR_REVISION
);
983 ASSERT(NT_SUCCESS(Status
));
984 Status
= RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor
,
988 ASSERT(NT_SUCCESS(Status
));
990 /* Create and Set the \ApiPort descriptor */
991 SmpApiPortSecurityDescriptor
= &SmpApiPortSDBody
;
992 Status
= RtlCreateSecurityDescriptor(SmpApiPortSecurityDescriptor
,
993 SECURITY_DESCRIPTOR_REVISION
);
994 ASSERT(NT_SUCCESS(Status
));
995 Status
= RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor
,
999 ASSERT(NT_SUCCESS(Status
));
1002 /* Check if protection was requested in the registry (on by default) */
1003 if (SmpProtectionMode
& 1) ProtectionRequired
= TRUE
;
1005 /* Exit if there's nothing to do */
1006 if (!(InitialCall
|| ProtectionRequired
)) return STATUS_SUCCESS
;
1008 /* Build the world SID */
1009 Status
= RtlAllocateAndInitializeSid(&WorldAuthority
, 1,
1011 0, 0, 0, 0, 0, 0, 0,
1013 if (!NT_SUCCESS(Status
))
1019 /* Build the admin SID */
1020 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 2,
1021 SECURITY_BUILTIN_DOMAIN_RID
,
1022 DOMAIN_ALIAS_RID_ADMINS
,
1025 if (!NT_SUCCESS(Status
))
1031 /* Build the owner SID */
1032 Status
= RtlAllocateAndInitializeSid(&CreatorAuthority
, 1,
1033 SECURITY_CREATOR_OWNER_RID
,
1034 0, 0, 0, 0, 0, 0, 0,
1036 if (!NT_SUCCESS(Status
))
1042 /* Build the restricted SID */
1043 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 1,
1044 SECURITY_RESTRICTED_CODE_RID
,
1045 0, 0, 0, 0, 0, 0, 0,
1047 if (!NT_SUCCESS(Status
))
1049 RestrictedSid
= NULL
;
1053 /* Build the system SID */
1054 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 1,
1055 SECURITY_LOCAL_SYSTEM_RID
,
1056 0, 0, 0, 0, 0, 0, 0,
1058 if (!NT_SUCCESS(Status
))
1064 /* Now check if we're creating the core descriptors */
1067 /* We're skipping NextAcl so we have to do this here */
1068 SidLength
= RtlLengthSid(WorldSid
) + RtlLengthSid(RestrictedSid
) + RtlLengthSid(AdminSid
);
1073 /* Allocate an ACL with two ACEs with two SIDs each */
1074 SidLength
= RtlLengthSid(SystemSid
) + RtlLengthSid(AdminSid
);
1075 AclLength
= sizeof(ACL
) + 2 * sizeof(ACCESS_ALLOWED_ACE
) + SidLength
;
1076 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1077 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1078 if (!NT_SUCCESS(Status
)) goto NextAcl
;
1080 /* Now build the ACL and add the two ACEs */
1081 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1082 ASSERT(NT_SUCCESS(Status
));
1083 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1084 ASSERT(NT_SUCCESS(Status
));
1085 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, SystemSid
);
1086 ASSERT(NT_SUCCESS(Status
));
1088 /* Set this as the DACL */
1089 Status
= RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor
,
1093 ASSERT(NT_SUCCESS(Status
));
1096 /* Allocate an ACL with 6 ACEs, two ACEs per SID */
1097 SidLength
= RtlLengthSid(WorldSid
) + RtlLengthSid(RestrictedSid
) + RtlLengthSid(AdminSid
);
1099 AclLength
= sizeof(ACL
) + 6 * sizeof(ACCESS_ALLOWED_ACE
) + SidLength
;
1100 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1101 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1102 if (!NT_SUCCESS(Status
)) goto NotInitial
;
1104 /* Now build the ACL and add the six ACEs */
1105 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1106 ASSERT(NT_SUCCESS(Status
));
1107 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
, WorldSid
);
1108 ASSERT(NT_SUCCESS(Status
));
1109 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
, RestrictedSid
);
1110 ASSERT(NT_SUCCESS(Status
));
1111 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1112 ASSERT(NT_SUCCESS(Status
));
1113 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, WorldSid
);
1114 ASSERT(NT_SUCCESS(Status
));
1115 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, RestrictedSid
);
1116 ASSERT(NT_SUCCESS(Status
));
1117 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1118 ASSERT(NT_SUCCESS(Status
));
1120 /* Now edit the last three ACEs and make them inheritable */
1121 Status
= RtlGetAce(Acl
, 3, (PVOID
)&Ace
);
1122 ASSERT(NT_SUCCESS(Status
));
1123 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1124 Status
= RtlGetAce(Acl
, 4, (PVOID
)&Ace
);
1125 ASSERT(NT_SUCCESS(Status
));
1126 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1127 Status
= RtlGetAce(Acl
, 5, (PVOID
)&Ace
);
1128 ASSERT(NT_SUCCESS(Status
));
1129 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1131 /* Set this as the DACL */
1132 Status
= RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor
,
1136 ASSERT(NT_SUCCESS(Status
));
1139 /* The initial ACLs have been created, are we also protecting objects? */
1140 if (!ProtectionRequired
) goto Quickie
;
1142 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
1143 SidLength
+= RtlLengthSid(OwnerSid
);
1144 AclLength
= sizeof(ACL
) + 7 * sizeof (ACCESS_ALLOWED_ACE
) + 2 * SidLength
;
1145 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1146 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1147 if (!NT_SUCCESS(Status
)) goto Quickie
;
1149 /* Build the ACL and add the seven ACEs */
1150 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1151 ASSERT(NT_SUCCESS(Status
));
1152 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, WorldSid
);
1153 ASSERT(NT_SUCCESS(Status
));
1154 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, RestrictedSid
);
1155 ASSERT(NT_SUCCESS(Status
));
1156 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1157 ASSERT(NT_SUCCESS(Status
));
1158 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, WorldSid
);
1159 ASSERT(NT_SUCCESS(Status
));
1160 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, RestrictedSid
);
1161 ASSERT(NT_SUCCESS(Status
));
1162 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1163 ASSERT(NT_SUCCESS(Status
));
1164 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, OwnerSid
);
1165 ASSERT(NT_SUCCESS(Status
));
1167 /* Edit the last 4 ACEs to make then inheritable */
1168 Status
= RtlGetAce(Acl
, 3, (PVOID
)&Ace
);
1169 ASSERT(NT_SUCCESS(Status
));
1170 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1171 Status
= RtlGetAce(Acl
, 4, (PVOID
)&Ace
);
1172 ASSERT(NT_SUCCESS(Status
));
1173 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1174 Status
= RtlGetAce(Acl
, 5, (PVOID
)&Ace
);
1175 ASSERT(NT_SUCCESS(Status
));
1176 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1177 Status
= RtlGetAce(Acl
, 6, (PVOID
)&Ace
);
1178 ASSERT(NT_SUCCESS(Status
));
1179 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1181 /* Set this as the DACL for the primary SD */
1182 Status
= RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor
,
1186 ASSERT(NT_SUCCESS(Status
));
1188 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
1189 AclLength
= sizeof(ACL
) + 7 * sizeof (ACCESS_ALLOWED_ACE
) + 2 * SidLength
;
1190 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1191 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1192 if (!NT_SUCCESS(Status
)) goto Quickie
;
1194 /* Build the ACL and add the seven ACEs */
1195 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1196 ASSERT(NT_SUCCESS(Status
));
1197 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, WorldSid
);
1198 ASSERT(NT_SUCCESS(Status
));
1199 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, RestrictedSid
);
1200 ASSERT(NT_SUCCESS(Status
));
1201 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1202 ASSERT(NT_SUCCESS(Status
));
1203 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, WorldSid
);
1204 ASSERT(NT_SUCCESS(Status
));
1205 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, RestrictedSid
);
1206 ASSERT(NT_SUCCESS(Status
));
1207 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1208 ASSERT(NT_SUCCESS(Status
));
1209 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, OwnerSid
);
1210 ASSERT(NT_SUCCESS(Status
));
1212 /* Edit the last 4 ACEs to make then inheritable */
1213 Status
= RtlGetAce(Acl
, 3, (PVOID
)&Ace
);
1214 ASSERT(NT_SUCCESS(Status
));
1215 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1216 Status
= RtlGetAce(Acl
, 4, (PVOID
)&Ace
);
1217 ASSERT(NT_SUCCESS(Status
));
1218 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1219 Status
= RtlGetAce(Acl
, 5, (PVOID
)&Ace
);
1220 ASSERT(NT_SUCCESS(Status
));
1221 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1222 Status
= RtlGetAce(Acl
, 6, (PVOID
)&Ace
);
1223 ASSERT(NT_SUCCESS(Status
));
1224 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1226 /* Now set this as the DACL for the liberal SD */
1227 Status
= RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor
,
1231 ASSERT(NT_SUCCESS(Status
));
1234 /* Cleanup the SIDs */
1235 if (OwnerSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, OwnerSid
);
1236 if (AdminSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, AdminSid
);
1237 if (WorldSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid
);
1238 if (SystemSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, SystemSid
);
1239 if (RestrictedSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSid
);
1245 SmpInitializeDosDevices(VOID
)
1248 PSMP_REGISTRY_VALUE RegEntry
;
1249 SECURITY_DESCRIPTOR_CONTROL OldFlag
= 0;
1250 OBJECT_ATTRIBUTES ObjectAttributes
;
1251 UNICODE_STRING DestinationString
;
1253 PLIST_ENTRY NextEntry
, Head
;
1255 /* Open the GLOBAL?? directory */
1256 RtlInitUnicodeString(&DestinationString
, L
"\\??");
1257 InitializeObjectAttributes(&ObjectAttributes
,
1259 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1262 Status
= NtOpenDirectoryObject(&SmpDosDevicesObjectDirectory
,
1263 DIRECTORY_ALL_ACCESS
,
1265 if (!NT_SUCCESS(Status
))
1267 DPRINT1("SMSS: Unable to open %wZ directory - Status == %lx\n",
1268 &DestinationString
, Status
);
1272 /* Loop the DOS devices */
1273 Head
= &SmpDosDevicesList
;
1274 while (!IsListEmpty(Head
))
1276 /* Get the entry and remove it */
1277 NextEntry
= RemoveHeadList(Head
);
1278 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1280 /* Initialize the attributes, and see which descriptor is being used */
1281 InitializeObjectAttributes(&ObjectAttributes
,
1283 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1284 SmpDosDevicesObjectDirectory
,
1285 SmpPrimarySecurityDescriptor
);
1286 if (SmpPrimarySecurityDescriptor
)
1288 /* Save the old flag and set it while we create this link */
1289 OldFlag
= SmpPrimarySecurityDescriptor
->Control
;
1290 SmpPrimarySecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1293 /* Create the symbolic link */
1294 DPRINT("Creating symlink for %wZ to %wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
1295 Status
= NtCreateSymbolicLinkObject(&DirHandle
,
1296 SYMBOLIC_LINK_ALL_ACCESS
,
1299 if (Status
== STATUS_OBJECT_NAME_EXISTS
)
1301 /* Make it temporary and get rid of the handle */
1302 NtMakeTemporaryObject(DirHandle
);
1305 /* Treat this as success, and see if we got a name back */
1306 Status
= STATUS_SUCCESS
;
1307 if (RegEntry
->Value
.Length
)
1309 /* Create it now with this name */
1310 ObjectAttributes
.Attributes
&= ~OBJ_OPENIF
;
1311 Status
= NtCreateSymbolicLinkObject(&DirHandle
,
1312 SYMBOLIC_LINK_ALL_ACCESS
,
1318 /* If we were using a security descriptor, restore the non-defaulted flag */
1319 if (ObjectAttributes
.SecurityDescriptor
)
1321 SmpPrimarySecurityDescriptor
->Control
= OldFlag
;
1324 /* Print a failure if we failed to create the symbolic link */
1325 if (!NT_SUCCESS(Status
))
1327 DPRINT1("SMSS: Unable to create %wZ => %wZ symbolic link object - Status == 0x%lx\n",
1334 /* Close the handle */
1337 /* Free this entry */
1338 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
1339 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
1340 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
1343 /* Return the status */
1349 SmpProcessModuleImports(IN PVOID Unused
,
1350 IN PCHAR ImportName
)
1352 ULONG Length
= 0, Chars
;
1353 WCHAR Buffer
[MAX_PATH
];
1354 PWCHAR DllName
, DllValue
;
1355 ANSI_STRING ImportString
;
1356 UNICODE_STRING ImportUnicodeString
;
1359 /* Skip NTDLL since it's already always mapped */
1360 if (!_stricmp(ImportName
, "ntdll.dll")) return;
1362 /* Initialize our strings */
1363 RtlInitAnsiString(&ImportString
, ImportName
);
1364 RtlInitEmptyUnicodeString(&ImportUnicodeString
, Buffer
, sizeof(Buffer
));
1365 Status
= RtlAnsiStringToUnicodeString(&ImportUnicodeString
, &ImportString
, FALSE
);
1366 if (!NT_SUCCESS(Status
)) return;
1368 /* Loop in case we find a forwarder */
1369 ImportUnicodeString
.MaximumLength
= ImportUnicodeString
.Length
+ sizeof(UNICODE_NULL
);
1370 while (Length
< ImportUnicodeString
.Length
)
1372 if (ImportUnicodeString
.Buffer
[Length
/ sizeof(WCHAR
)] == L
'.') break;
1373 Length
+= sizeof(WCHAR
);
1376 /* Break up the values as needed */
1377 DllValue
= ImportUnicodeString
.Buffer
;
1378 DllName
= &ImportUnicodeString
.Buffer
[ImportUnicodeString
.MaximumLength
/ sizeof(WCHAR
)];
1379 Chars
= Length
>> 1;
1380 wcsncpy(DllName
, ImportUnicodeString
.Buffer
, Chars
);
1383 /* Add the DLL to the list */
1384 SmpSaveRegistryValue(&SmpKnownDllsList
, DllName
, DllValue
, TRUE
);
1389 SmpInitializeKnownDllsInternal(IN PUNICODE_STRING Directory
,
1390 IN PUNICODE_STRING Path
)
1392 HANDLE DirFileHandle
, DirHandle
, SectionHandle
, FileHandle
, LinkHandle
;
1393 UNICODE_STRING NtPath
, DestinationString
;
1394 OBJECT_ATTRIBUTES ObjectAttributes
;
1395 NTSTATUS Status
, Status1
;
1396 PLIST_ENTRY NextEntry
;
1397 PSMP_REGISTRY_VALUE RegEntry
;
1398 ULONG_PTR ErrorParameters
[3];
1399 UNICODE_STRING ErrorResponse
;
1400 IO_STATUS_BLOCK IoStatusBlock
;
1401 SECURITY_DESCRIPTOR_CONTROL OldFlag
= 0;
1402 USHORT ImageCharacteristics
;
1404 /* Initialize to NULL */
1405 DirFileHandle
= NULL
;
1407 NtPath
.Buffer
= NULL
;
1409 /* Create the \KnownDLLs directory */
1410 InitializeObjectAttributes(&ObjectAttributes
,
1412 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1414 SmpKnownDllsSecurityDescriptor
);
1415 Status
= NtCreateDirectoryObject(&DirHandle
,
1416 DIRECTORY_ALL_ACCESS
,
1418 if (!NT_SUCCESS(Status
))
1420 /* Handle failure */
1421 DPRINT1("SMSS: Unable to create %wZ directory - Status == %lx\n",
1426 /* Convert the path to native format */
1427 if (!RtlDosPathNameToNtPathName_U(Path
->Buffer
, &NtPath
, NULL
, NULL
))
1429 /* Fail if this didn't work */
1430 DPRINT1("SMSS: Unable to to convert %wZ to an Nt path\n", Path
);
1431 Status
= STATUS_OBJECT_NAME_INVALID
;
1435 /* Open the path that was specified, which should be a directory */
1436 InitializeObjectAttributes(&ObjectAttributes
,
1438 OBJ_CASE_INSENSITIVE
,
1441 Status
= NtOpenFile(&DirFileHandle
,
1442 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
1445 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1446 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
1447 if (!NT_SUCCESS(Status
))
1449 /* Fail if we couldn't open it */
1450 DPRINT1("SMSS: Unable to open a handle to the KnownDll directory (%wZ)"
1451 "- Status == %lx\n",
1458 /* Temporarily hack the SD to use a default DACL for this symbolic link */
1459 if (SmpPrimarySecurityDescriptor
)
1461 OldFlag
= SmpPrimarySecurityDescriptor
->Control
;
1462 SmpPrimarySecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1465 /* Create a symbolic link to the directory in the object manager */
1466 RtlInitUnicodeString(&DestinationString
, L
"KnownDllPath");
1467 InitializeObjectAttributes(&ObjectAttributes
,
1469 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1471 SmpPrimarySecurityDescriptor
);
1472 Status
= NtCreateSymbolicLinkObject(&LinkHandle
,
1473 SYMBOLIC_LINK_ALL_ACCESS
,
1478 if (SmpPrimarySecurityDescriptor
) SmpPrimarySecurityDescriptor
->Control
= OldFlag
;
1480 /* Check if the symlink was created */
1481 if (!NT_SUCCESS(Status
))
1483 /* It wasn't, so bail out since the OS needs it to exist */
1484 DPRINT1("SMSS: Unable to create %wZ symbolic link - Status == %lx\n",
1485 &DestinationString
, Status
);
1490 /* We created it permanent, we can go ahead and close the handle now */
1491 Status1
= NtClose(LinkHandle
);
1492 ASSERT(NT_SUCCESS(Status1
));
1494 /* Now loop the known DLLs */
1495 NextEntry
= SmpKnownDllsList
.Flink
;
1496 while (NextEntry
!= &SmpKnownDllsList
)
1498 /* Get the entry and skip it if it's in the exluded list */
1499 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1500 DPRINT("Processing known DLL: %wZ-%wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
1501 if ((SmpFindRegistryValue(&SmpExcludeKnownDllsList
,
1502 RegEntry
->Name
.Buffer
)) ||
1503 (SmpFindRegistryValue(&SmpExcludeKnownDllsList
,
1504 RegEntry
->Value
.Buffer
)))
1509 /* Open the actual file */
1510 InitializeObjectAttributes(&ObjectAttributes
,
1512 OBJ_CASE_INSENSITIVE
,
1515 Status
= NtOpenFile(&FileHandle
,
1516 SYNCHRONIZE
| FILE_EXECUTE
,
1519 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1520 FILE_NON_DIRECTORY_FILE
|
1521 FILE_SYNCHRONOUS_IO_NONALERT
);
1522 if (!NT_SUCCESS(Status
)) break;
1525 Status
= LdrVerifyImageMatchesChecksum((HANDLE
)((ULONG_PTR
)FileHandle
| 1),
1526 SmpProcessModuleImports
,
1528 &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
));
1551 /* Temporarily hack the SD to use a default DACL for this section */
1552 if (SmpLiberalSecurityDescriptor
)
1554 OldFlag
= SmpLiberalSecurityDescriptor
->Control
;
1555 SmpLiberalSecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1558 /* Create the section for this known DLL */
1559 InitializeObjectAttributes(&ObjectAttributes
,
1563 SmpLiberalSecurityDescriptor
)
1564 Status
= NtCreateSection(&SectionHandle
,
1573 if (SmpLiberalSecurityDescriptor
) SmpLiberalSecurityDescriptor
->Control
= OldFlag
;
1575 /* Check if we created the section okay */
1576 if (NT_SUCCESS(Status
))
1578 /* We can close it now, since it's marked permanent */
1579 Status1
= NtClose(SectionHandle
);
1580 ASSERT(NT_SUCCESS(Status1
));
1584 /* If we couldn't make it "known", that's fine and keep going */
1585 DPRINT1("SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n",
1586 &RegEntry
->Value
, Status
);
1589 /* Close the file since we can move on to the next one */
1590 Status1
= NtClose(FileHandle
);
1591 ASSERT(NT_SUCCESS(Status1
));
1593 /* Go to the next entry */
1594 NextEntry
= NextEntry
->Flink
;
1598 /* Close both handles and free the NT path buffer */
1601 Status1
= NtClose(DirHandle
);
1602 ASSERT(NT_SUCCESS(Status1
));
1606 Status1
= NtClose(DirFileHandle
);
1607 ASSERT(NT_SUCCESS(Status1
));
1609 if (NtPath
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath
.Buffer
);
1615 SmpInitializeKnownDlls(VOID
)
1618 PSMP_REGISTRY_VALUE RegEntry
;
1619 UNICODE_STRING DestinationString
;
1620 PLIST_ENTRY Head
, NextEntry
;
1622 /* Call the internal function */
1623 RtlInitUnicodeString(&DestinationString
, L
"\\KnownDlls");
1624 Status
= SmpInitializeKnownDllsInternal(&DestinationString
, &SmpKnownDllPath
);
1626 /* Wipe out the list regardless of success */
1627 Head
= &SmpKnownDllsList
;
1628 while (!IsListEmpty(Head
))
1630 /* Remove this entry */
1631 NextEntry
= RemoveHeadList(Head
);
1634 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1635 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
1636 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
1637 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
1646 SmpCreateDynamicEnvironmentVariables(VOID
)
1649 SYSTEM_BASIC_INFORMATION BasicInfo
;
1650 SYSTEM_PROCESSOR_INFORMATION ProcessorInfo
;
1651 OBJECT_ATTRIBUTES ObjectAttributes
;
1652 UNICODE_STRING ValueName
, DestinationString
;
1653 HANDLE KeyHandle
, KeyHandle2
;
1656 WCHAR ValueBuffer
[512], ValueBuffer2
[512];
1657 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PVOID
)ValueBuffer
;
1658 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo2
= (PVOID
)ValueBuffer2
;
1660 /* Get system basic information -- we'll need the CPU count */
1661 Status
= NtQuerySystemInformation(SystemBasicInformation
,
1665 if (!NT_SUCCESS(Status
))
1667 /* Bail out on failure */
1668 DPRINT1("SMSS: Unable to query system basic information - %x\n", Status
);
1672 /* Get the processor information, we'll query a bunch of revision info */
1673 Status
= NtQuerySystemInformation(SystemProcessorInformation
,
1675 sizeof(ProcessorInfo
),
1677 if (!NT_SUCCESS(Status
))
1679 /* Bail out on failure */
1680 DPRINT1("SMSS: Unable to query system processor information - %x\n", Status
);
1684 /* We'll be writing all these environment variables over here */
1685 RtlInitUnicodeString(&DestinationString
,
1686 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
1687 L
"Control\\Session Manager\\Environment");
1688 InitializeObjectAttributes(&ObjectAttributes
,
1690 OBJ_CASE_INSENSITIVE
,
1693 Status
= NtOpenKey(&KeyHandle
, GENERIC_WRITE
, &ObjectAttributes
);
1694 if (!NT_SUCCESS(Status
))
1696 /* Bail out on failure */
1697 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString
, Status
);
1701 /* First let's write the OS variable */
1702 RtlInitUnicodeString(&ValueName
, L
"OS");
1703 DPRINT("Setting %wZ to %S\n", &ValueName
, L
"Windows_NT");
1704 Status
= NtSetValueKey(KeyHandle
,
1709 wcslen(L
"Windows_NT") * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1710 if (!NT_SUCCESS(Status
))
1712 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1713 &ValueName
, Status
);
1718 /* Next, let's write the CPU architecture variable */
1719 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_ARCHITECTURE");
1720 switch (ProcessorInfo
.ProcessorArchitecture
)
1722 /* Pick the correct string that matches the architecture */
1723 case PROCESSOR_ARCHITECTURE_INTEL
:
1727 case PROCESSOR_ARCHITECTURE_AMD64
:
1728 ArchName
= L
"AMD64";
1731 case PROCESSOR_ARCHITECTURE_IA64
:
1736 ArchName
= L
"Unknown";
1741 DPRINT("Setting %wZ to %S\n", &ValueName
, ArchName
);
1742 Status
= NtSetValueKey(KeyHandle
,
1747 wcslen(ArchName
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1748 if (!NT_SUCCESS(Status
))
1750 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1751 &ValueName
, Status
);
1756 /* And now let's write the processor level */
1757 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_LEVEL");
1758 swprintf(ValueBuffer
, L
"%u", ProcessorInfo
.ProcessorLevel
);
1759 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1760 Status
= NtSetValueKey(KeyHandle
,
1765 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1766 if (!NT_SUCCESS(Status
))
1768 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1769 &ValueName
, Status
);
1774 /* Now open the hardware CPU key */
1775 RtlInitUnicodeString(&DestinationString
,
1776 L
"\\Registry\\Machine\\Hardware\\Description\\System\\"
1777 L
"CentralProcessor\\0");
1778 InitializeObjectAttributes(&ObjectAttributes
,
1780 OBJ_CASE_INSENSITIVE
,
1783 Status
= NtOpenKey(&KeyHandle2
, KEY_READ
, &ObjectAttributes
);
1784 if (!NT_SUCCESS(Status
))
1786 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString
, Status
);
1791 /* So that we can read the identifier out of it... */
1792 RtlInitUnicodeString(&ValueName
, L
"Identifier");
1793 Status
= NtQueryValueKey(KeyHandle2
,
1795 KeyValuePartialInformation
,
1797 sizeof(ValueBuffer
),
1799 if (!NT_SUCCESS(Status
))
1801 NtClose(KeyHandle2
);
1803 DPRINT1("SMSS: Unable to read %wZ\\%wZ - %x\n",
1804 &DestinationString
, &ValueName
, Status
);
1808 /* As well as the vendor... */
1809 RtlInitUnicodeString(&ValueName
, L
"VendorIdentifier");
1810 Status
= NtQueryValueKey(KeyHandle2
,
1812 KeyValuePartialInformation
,
1814 sizeof(ValueBuffer2
),
1816 NtClose(KeyHandle2
);
1817 if (NT_SUCCESS(Status
))
1819 /* To combine it into a single string */
1820 swprintf((PWCHAR
)PartialInfo
->Data
+ wcslen((PWCHAR
)PartialInfo
->Data
),
1822 PartialInfo2
->Data
);
1825 /* So that we can set this as the PROCESSOR_IDENTIFIER variable */
1826 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_IDENTIFIER");
1827 DPRINT("Setting %wZ to %s\n", &ValueName
, PartialInfo
->Data
);
1828 Status
= NtSetValueKey(KeyHandle
,
1833 wcslen((PWCHAR
)PartialInfo
->Data
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1834 if (!NT_SUCCESS(Status
))
1836 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1837 &ValueName
, Status
);
1842 /* Now let's get the processor architecture */
1843 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_REVISION");
1844 switch (ProcessorInfo
.ProcessorArchitecture
)
1846 /* Check if this is an older Intel CPU */
1847 case PROCESSOR_ARCHITECTURE_INTEL
:
1848 if ((ProcessorInfo
.ProcessorRevision
>> 8) == 0xFF)
1850 /* These guys used a revision + stepping, so get the rev only */
1851 swprintf(ValueBuffer
, L
"%02x", ProcessorInfo
.ProcessorRevision
& 0xFF);
1852 _wcsupr(ValueBuffer
);
1856 /* Modern Intel, as well as 64-bit CPUs use a revision without stepping */
1857 case PROCESSOR_ARCHITECTURE_IA64
:
1858 case PROCESSOR_ARCHITECTURE_AMD64
:
1859 swprintf(ValueBuffer
, L
"%04x", ProcessorInfo
.ProcessorRevision
);
1862 /* And anything else we'll just read the whole revision identifier */
1864 swprintf(ValueBuffer
, L
"%u", ProcessorInfo
.ProcessorRevision
);
1868 /* Write the revision to the registry */
1869 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1870 Status
= NtSetValueKey(KeyHandle
,
1875 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1876 if (!NT_SUCCESS(Status
))
1878 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1879 &ValueName
, Status
);
1884 /* And finally, write the number of CPUs */
1885 RtlInitUnicodeString(&ValueName
, L
"NUMBER_OF_PROCESSORS");
1886 swprintf(ValueBuffer
, L
"%d", BasicInfo
.NumberOfProcessors
);
1887 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1888 Status
= NtSetValueKey(KeyHandle
,
1893 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1894 if (!NT_SUCCESS(Status
))
1896 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1897 &ValueName
, Status
);
1902 /* Now we need to write the safeboot option key in a different format */
1903 RtlInitUnicodeString(&DestinationString
,
1904 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
1905 L
"Control\\Safeboot\\Option");
1906 InitializeObjectAttributes(&ObjectAttributes
,
1908 OBJ_CASE_INSENSITIVE
,
1911 Status
= NtOpenKey(&KeyHandle2
, KEY_ALL_ACCESS
, &ObjectAttributes
);
1912 if (NT_SUCCESS(Status
))
1914 /* This was indeed a safeboot, so check what kind of safeboot it was */
1915 RtlInitUnicodeString(&ValueName
, L
"OptionValue");
1916 Status
= NtQueryValueKey(KeyHandle2
,
1918 KeyValuePartialInformation
,
1920 sizeof(ValueBuffer
),
1922 NtClose(KeyHandle2
);
1923 if (NT_SUCCESS(Status
))
1925 /* Convert from the integer value to the correct specifier */
1926 RtlInitUnicodeString(&ValueName
, L
"SAFEBOOT_OPTION");
1927 switch (*(PULONG
)PartialInfo
->Data
)
1930 wcscpy(ValueBuffer
, L
"MINIMAL");
1933 wcscpy(ValueBuffer
, L
"NETWORK");
1936 wcscpy(ValueBuffer
, L
"DSREPAIR");
1940 /* And write it in the environment! */
1941 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1942 Status
= NtSetValueKey(KeyHandle
,
1947 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1948 if (!NT_SUCCESS(Status
))
1950 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1951 &ValueName
, Status
);
1958 DPRINT1("SMSS: Failed querying safeboot option = %x\n", Status
);
1962 /* We are all done now */
1964 return STATUS_SUCCESS
;
1969 SmpProcessFileRenames(VOID
)
1971 BOOLEAN OldState
, HavePrivilege
= FALSE
;
1973 HANDLE FileHandle
, OtherFileHandle
;
1974 FILE_INFORMATION_CLASS InformationClass
;
1975 OBJECT_ATTRIBUTES ObjectAttributes
;
1976 IO_STATUS_BLOCK IoStatusBlock
;
1977 UNICODE_STRING FileString
;
1978 FILE_BASIC_INFORMATION BasicInfo
;
1979 FILE_DISPOSITION_INFORMATION DeleteInformation
;
1980 PFILE_RENAME_INFORMATION Buffer
;
1981 PLIST_ENTRY Head
, NextEntry
;
1982 PSMP_REGISTRY_VALUE RegEntry
;
1984 ULONG ValueLength
, Length
;
1986 /* Give us access to restore any files we want */
1987 Status
= RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, TRUE
, FALSE
, &OldState
);
1988 if (NT_SUCCESS(Status
)) HavePrivilege
= TRUE
;
1990 /* Process pending files to rename */
1991 Head
= &SmpFileRenameList
;
1992 while (!IsListEmpty(Head
))
1994 /* Get this entry */
1995 NextEntry
= RemoveHeadList(Head
);
1996 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1997 DPRINT1("Processing PFRO: %wZ/%wZ\n", &RegEntry
->Value
, &RegEntry
->Name
);
1999 /* Skip past the '@' marker */
2000 if (!(RegEntry
->Value
.Length
) && (*RegEntry
->Name
.Buffer
== L
'@'))
2002 RegEntry
->Name
.Length
-= sizeof(UNICODE_NULL
);
2003 RegEntry
->Name
.Buffer
++;
2006 /* Open the file for delete access */
2007 InitializeObjectAttributes(&ObjectAttributes
,
2009 OBJ_CASE_INSENSITIVE
,
2012 Status
= NtOpenFile(&OtherFileHandle
,
2013 DELETE
| SYNCHRONIZE
,
2016 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2017 FILE_SYNCHRONOUS_IO_NONALERT
);
2018 if (!NT_SUCCESS(Status
)) goto Quickie
;
2020 /* Check if it's a rename or just a delete */
2021 ValueLength
= RegEntry
->Value
.Length
;
2024 /* Just a delete, set up the class, length and buffer */
2025 InformationClass
= FileDispositionInformation
;
2026 Length
= sizeof(DeleteInformation
);
2027 Buffer
= (PFILE_RENAME_INFORMATION
)&DeleteInformation
;
2029 /* Set the delete disposition */
2030 DeleteInformation
.DeleteFile
= TRUE
;
2034 /* This is a rename, setup the class and length */
2035 InformationClass
= FileRenameInformation
;
2036 Length
= ValueLength
+ sizeof(FILE_RENAME_INFORMATION
);
2038 /* Skip past the special markers */
2039 FileName
= RegEntry
->Value
.Buffer
;
2040 if ((*FileName
== L
'!') || (*FileName
== L
'@'))
2043 Length
-= sizeof(UNICODE_NULL
);
2046 /* Now allocate the buffer for the rename information */
2047 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag
, Length
);
2050 /* Setup the buffer to point to the filename, and copy it */
2051 Buffer
->RootDirectory
= NULL
;
2052 Buffer
->FileNameLength
= Length
- sizeof(FILE_RENAME_INFORMATION
);
2053 Buffer
->ReplaceIfExists
= FileName
!= RegEntry
->Value
.Buffer
;
2054 RtlCopyMemory(Buffer
->FileName
, FileName
, Buffer
->FileNameLength
);
2059 Status
= STATUS_NO_MEMORY
;
2063 /* Check if everything is okay till here */
2064 if (NT_SUCCESS(Status
))
2066 /* Now either rename or delete the file as requested */
2067 Status
= NtSetInformationFile(OtherFileHandle
,
2073 /* Check if we seem to have failed because the file was readonly */
2074 if ((NT_SUCCESS(Status
) &&
2075 (InformationClass
== FileRenameInformation
) &&
2076 (Status
== STATUS_OBJECT_NAME_COLLISION
) &&
2077 (Buffer
->ReplaceIfExists
)))
2079 /* Open the file for write attribute access this time... */
2080 DPRINT1("\nSMSS: %wZ => %wZ failed - Status == %x, Possible readonly target\n",
2083 STATUS_OBJECT_NAME_COLLISION
);
2084 FileString
.Length
= RegEntry
->Value
.Length
- sizeof(WCHAR
);
2085 FileString
.MaximumLength
= RegEntry
->Value
.MaximumLength
- sizeof(WCHAR
);
2086 FileString
.Buffer
= FileName
;
2087 InitializeObjectAttributes(&ObjectAttributes
,
2089 OBJ_CASE_INSENSITIVE
,
2092 Status
= NtOpenFile(&FileHandle
,
2093 FILE_WRITE_ATTRIBUTES
| SYNCHRONIZE
,
2096 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2097 FILE_SYNCHRONOUS_IO_NONALERT
);
2098 if (!NT_SUCCESS(Status
))
2100 /* That didn't work, so bail out */
2101 DPRINT1(" SMSS: Open Existing file Failed - Status == %x\n",
2106 /* Now remove the read-only attribute from the file */
2107 DPRINT1(" SMSS: Open Existing Success\n");
2108 RtlZeroMemory(&BasicInfo
, sizeof(BasicInfo
));
2109 BasicInfo
.FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
2110 Status
= NtSetInformationFile(FileHandle
,
2114 FileBasicInformation
);
2115 NtClose(FileHandle
);
2116 if (!NT_SUCCESS(Status
))
2118 /* That didn't work, bail out */
2119 DPRINT1(" SMSS: Set To NORMAL Failed - Status == %x\n",
2124 /* Now that the file is no longer read-only, delete! */
2125 DPRINT1(" SMSS: Set To NORMAL OK\n");
2126 Status
= NtSetInformationFile(OtherFileHandle
,
2130 FileRenameInformation
);
2131 if (!NT_SUCCESS(Status
))
2133 /* That failed too! */
2134 DPRINT1(" SMSS: Re-Rename Failed - Status == %x\n",
2140 DPRINT1(" SMSS: Re-Rename Worked OK\n");
2147 /* Close the file handle and check the operation result */
2148 NtClose(OtherFileHandle
);
2150 if (!NT_SUCCESS(Status
))
2152 /* We totally failed */
2153 DPRINT1("SMSS: %wZ => %wZ failed - Status == %x\n",
2154 &RegEntry
->Name
, &RegEntry
->Value
, Status
);
2156 else if (RegEntry
->Value
.Length
)
2158 /* We succeed with a rename */
2159 DPRINT1("SMSS: %wZ (renamed to) %wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
2163 /* We suceeded with a delete */
2164 DPRINT1("SMSS: %wZ (deleted)\n", &RegEntry
->Name
);
2167 /* Now free this entry and keep going */
2168 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2169 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2170 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2173 /* Put back the restore privilege if we had requested it, and return */
2174 if (HavePrivilege
) RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, FALSE
, FALSE
, &OldState
);
2180 SmpLoadDataFromRegistry(OUT PUNICODE_STRING InitialCommand
)
2183 PLIST_ENTRY Head
, NextEntry
;
2184 PSMP_REGISTRY_VALUE RegEntry
;
2185 PVOID OriginalEnvironment
;
2186 ULONG MuSessionId
= 0;
2187 OBJECT_ATTRIBUTES ObjectAttributes
;
2189 UNICODE_STRING DestinationString
;
2191 /* Initialize the keywords we'll be looking for */
2192 RtlInitUnicodeString(&SmpDebugKeyword
, L
"debug");
2193 RtlInitUnicodeString(&SmpASyncKeyword
, L
"async");
2194 RtlInitUnicodeString(&SmpAutoChkKeyword
, L
"autocheck");
2196 /* Initialize all the registry-associated list heads */
2197 InitializeListHead(&SmpBootExecuteList
);
2198 InitializeListHead(&SmpSetupExecuteList
);
2199 InitializeListHead(&SmpPagingFileList
);
2200 InitializeListHead(&SmpDosDevicesList
);
2201 InitializeListHead(&SmpFileRenameList
);
2202 InitializeListHead(&SmpKnownDllsList
);
2203 InitializeListHead(&SmpExcludeKnownDllsList
);
2204 InitializeListHead(&SmpSubSystemList
);
2205 InitializeListHead(&SmpSubSystemsToLoad
);
2206 InitializeListHead(&SmpSubSystemsToDefer
);
2207 InitializeListHead(&SmpExecuteList
);
2208 SmpPagingFileInitialize();
2210 /* Initialize the SMSS environment */
2211 Status
= RtlCreateEnvironment(TRUE
, &SmpDefaultEnvironment
);
2212 if (!NT_SUCCESS(Status
))
2214 /* Fail if there was a problem */
2215 DPRINT1("SMSS: Unable to allocate default environment - Status == %X\n",
2217 SMSS_CHECKPOINT(RtlCreateEnvironment
, Status
);
2221 /* Check if we were booted in PE mode (LiveCD should have this) */
2222 RtlInitUnicodeString(&DestinationString
,
2223 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
2224 L
"Control\\MiniNT");
2225 InitializeObjectAttributes(&ObjectAttributes
,
2227 OBJ_CASE_INSENSITIVE
,
2230 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
2231 if (NT_SUCCESS(Status
))
2233 /* If the key exists, we were */
2238 /* Print out if this is the case */
2239 if (MiniNTBoot
) DPRINT1("SMSS: !!! MiniNT Boot !!!\n");
2241 /* Open the environment key to see if we are booted in safe mode */
2242 RtlInitUnicodeString(&DestinationString
,
2243 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
2244 L
"Control\\Session Manager\\Environment");
2245 InitializeObjectAttributes(&ObjectAttributes
,
2247 OBJ_CASE_INSENSITIVE
,
2250 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
2251 if (NT_SUCCESS(Status
))
2253 /* Delete the value if we found it */
2254 RtlInitUnicodeString(&DestinationString
, L
"SAFEBOOT_OPTION");
2255 NtDeleteValueKey(KeyHandle
, &DestinationString
);
2259 /* Switch environments, then query the registry for all needed settings */
2260 OriginalEnvironment
= NtCurrentPeb()->ProcessParameters
->Environment
;
2261 NtCurrentPeb()->ProcessParameters
->Environment
= SmpDefaultEnvironment
;
2262 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
2264 SmpRegistryConfigurationTable
,
2267 SmpDefaultEnvironment
= NtCurrentPeb()->ProcessParameters
->Environment
;
2268 NtCurrentPeb()->ProcessParameters
->Environment
= OriginalEnvironment
;
2269 if (!NT_SUCCESS(Status
))
2271 /* We failed somewhere in registry initialization, which is bad... */
2272 DPRINT1("SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status
);
2273 SMSS_CHECKPOINT(RtlQueryRegistryValues
, Status
);
2277 /* Now we can start acting on the registry settings. First to DOS devices */
2278 Status
= SmpInitializeDosDevices();
2279 if (!NT_SUCCESS(Status
))
2282 DPRINT1("SMSS: Unable to initialize DosDevices configuration - Status == %lx\n",
2284 SMSS_CHECKPOINT(SmpInitializeDosDevices
, Status
);
2288 /* Next create the session directory... */
2289 RtlInitUnicodeString(&DestinationString
, L
"\\Sessions");
2290 InitializeObjectAttributes(&ObjectAttributes
,
2292 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
2294 SmpPrimarySecurityDescriptor
);
2295 Status
= NtCreateDirectoryObject(&SmpSessionsObjectDirectory
,
2296 DIRECTORY_ALL_ACCESS
,
2298 if (!NT_SUCCESS(Status
))
2301 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
2302 &DestinationString
, Status
);
2303 SMSS_CHECKPOINT(NtCreateDirectoryObject
, Status
);
2307 /* Next loop all the boot execute binaries */
2308 Head
= &SmpBootExecuteList
;
2309 while (!IsListEmpty(Head
))
2311 /* Remove each one from the list */
2312 NextEntry
= RemoveHeadList(Head
);
2315 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2316 SmpExecuteCommand(&RegEntry
->Name
, 0, NULL
, 0);
2319 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2320 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2321 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2324 /* Now do any pending file rename operations... */
2325 if (!MiniNTBoot
) SmpProcessFileRenames();
2327 /* And initialize known DLLs... */
2328 Status
= SmpInitializeKnownDlls();
2329 if (!NT_SUCCESS(Status
))
2331 /* Fail if that didn't work */
2332 DPRINT1("SMSS: Unable to initialize KnownDll configuration - Status == %lx\n",
2334 SMSS_CHECKPOINT(SmpInitializeKnownDlls
, Status
);
2338 /* Loop every page file */
2339 Head
= &SmpPagingFileList
;
2340 while (!IsListEmpty(Head
))
2342 /* Remove each one from the list */
2343 NextEntry
= RemoveHeadList(Head
);
2345 /* Create the descriptor for it */
2346 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2347 SmpCreatePagingFileDescriptor(&RegEntry
->Name
);
2350 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2351 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2352 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2355 /* Now create all the paging files for the descriptors that we have */
2356 SmpCreatePagingFiles();
2358 /* Tell Cm it's now safe to fully enable write access to the registry */
2359 NtInitializeRegistry(CM_BOOT_FLAG_SMSS
);
2361 /* Create all the system-based environment variables for later inheriting */
2362 Status
= SmpCreateDynamicEnvironmentVariables();
2363 if (!NT_SUCCESS(Status
))
2365 /* Handle failure */
2366 SMSS_CHECKPOINT(SmpCreateDynamicEnvironmentVariables
, Status
);
2370 /* And finally load all the subsytems for our first session! */
2371 Status
= SmpLoadSubSystemsForMuSession(&MuSessionId
,
2372 &SmpWindowsSubSysProcessId
,
2374 ASSERT(MuSessionId
== 0);
2375 if (!NT_SUCCESS(Status
)) SMSS_CHECKPOINT(SmpLoadSubSystemsForMuSession
, Status
);
2381 SmpInit(IN PUNICODE_STRING InitialCommand
,
2382 OUT PHANDLE ProcessHandle
)
2384 NTSTATUS Status
, Status2
;
2385 OBJECT_ATTRIBUTES ObjectAttributes
;
2386 UNICODE_STRING PortName
, EventName
;
2387 HANDLE EventHandle
, PortHandle
;
2388 ULONG HardErrorMode
;
2390 /* Create the SMSS Heap */
2391 SmBaseTag
= RtlCreateTagHeap(RtlGetProcessHeap(),
2395 SmpHeap
= RtlGetProcessHeap();
2397 /* Enable hard errors */
2398 HardErrorMode
= TRUE
;
2399 NtSetInformationProcess(NtCurrentProcess(),
2400 ProcessDefaultHardErrorMode
,
2402 sizeof(HardErrorMode
));
2404 /* Initialize the subsystem list and the session list, plus their locks */
2405 RtlInitializeCriticalSection(&SmpKnownSubSysLock
);
2406 InitializeListHead(&SmpKnownSubSysHead
);
2407 RtlInitializeCriticalSection(&SmpSessionListLock
);
2408 InitializeListHead(&SmpSessionListHead
);
2410 /* Initialize the process list */
2411 InitializeListHead(&NativeProcessList
);
2413 /* Initialize session parameters */
2414 SmpNextSessionId
= 1;
2415 SmpNextSessionIdScanMode
= 0;
2416 SmpDbgSsLoaded
= FALSE
;
2418 /* Create the initial security descriptors */
2419 Status
= SmpCreateSecurityDescriptors(TRUE
);
2420 if (!NT_SUCCESS(Status
))
2423 SMSS_CHECKPOINT(SmpCreateSecurityDescriptors
, Status
);
2427 /* Initialize subsystem names */
2428 RtlInitUnicodeString(&SmpSubsystemName
, L
"NT-Session Manager");
2429 RtlInitUnicodeString(&PosixName
, L
"POSIX");
2430 RtlInitUnicodeString(&Os2Name
, L
"OS2");
2432 /* Create the SM API Port */
2433 RtlInitUnicodeString(&PortName
, L
"\\SmApiPort");
2434 InitializeObjectAttributes(&ObjectAttributes
, &PortName
, 0, NULL
, NULL
);
2435 Status
= NtCreatePort(&PortHandle
,
2437 sizeof(SB_CONNECTION_INFO
),
2439 sizeof(SB_API_MSG
) * 32);
2440 ASSERT(NT_SUCCESS(Status
));
2441 SmpDebugPort
= PortHandle
;
2443 /* Create two SM API threads */
2444 Status
= RtlCreateUserThread(NtCurrentProcess(),
2454 ASSERT(NT_SUCCESS(Status
));
2455 Status
= RtlCreateUserThread(NtCurrentProcess(),
2465 ASSERT(NT_SUCCESS(Status
));
2467 /* Create the write event that autochk can set after running */
2468 RtlInitUnicodeString(&EventName
, L
"\\Device\\VolumesSafeForWriteAccess");
2469 InitializeObjectAttributes(&ObjectAttributes
,
2474 Status2
= NtCreateEvent(&EventHandle
,
2479 if (!NT_SUCCESS(Status2
))
2481 /* Should never really fail */
2482 DPRINT1("SMSS: Unable to create %wZ event - Status == %lx\n",
2483 &EventName
, Status2
);
2484 ASSERT(NT_SUCCESS(Status2
));
2487 /* Now initialize everything else based on the registry parameters */
2488 Status
= SmpLoadDataFromRegistry(InitialCommand
);
2489 if (NT_SUCCESS(Status
))
2491 /* Autochk should've run now. Set the event and save the CSRSS handle */
2492 *ProcessHandle
= SmpWindowsSubSysProcess
;
2493 NtSetEvent(EventHandle
, 0);
2494 NtClose(EventHandle
);