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
,
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 SmpConfigureEnvironment
,
730 RTL_QUERY_REGISTRY_SUBKEY
,
739 SmpConfigureSubSystems
,
740 RTL_QUERY_REGISTRY_SUBKEY
,
749 SmpConfigureSubSystems
,
750 RTL_QUERY_REGISTRY_NOEXPAND
,
759 SmpConfigureSubSystems
,
760 RTL_QUERY_REGISTRY_NOEXPAND
,
769 SmpConfigureSubSystems
,
779 SmpConfigureMemoryMgmt
,
780 RTL_QUERY_REGISTRY_TOPKEY
,
791 /* FUNCTIONS ******************************************************************/
795 SmpTranslateSystemPartitionInformation(VOID
)
798 UNICODE_STRING UnicodeString
, LinkTarget
, SearchString
, SystemPartition
;
799 OBJECT_ATTRIBUTES ObjectAttributes
;
800 HANDLE KeyHandle
, LinkHandle
;
801 CHAR ValueBuffer
[512 + sizeof(KEY_VALUE_PARTIAL_INFORMATION
)];
802 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PVOID
)ValueBuffer
;
803 ULONG Length
, Context
;
804 CHAR DirInfoBuffer
[512 + sizeof(OBJECT_DIRECTORY_INFORMATION
)];
805 POBJECT_DIRECTORY_INFORMATION DirInfo
= (PVOID
)DirInfoBuffer
;
806 WCHAR LinkBuffer
[MAX_PATH
];
808 /* Open the setup key */
809 RtlInitUnicodeString(&UnicodeString
, L
"\\Registry\\Machine\\System\\Setup");
810 InitializeObjectAttributes(&ObjectAttributes
,
812 OBJ_CASE_INSENSITIVE
,
815 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
816 if (!NT_SUCCESS(Status
))
818 DPRINT1("SMSS: can't open system setup key for reading: 0x%x\n", Status
);
822 /* Query the system partition */
823 RtlInitUnicodeString(&UnicodeString
, L
"SystemPartition");
824 Status
= NtQueryValueKey(KeyHandle
,
826 KeyValuePartialInformation
,
831 if (!NT_SUCCESS(Status
))
833 DPRINT1("SMSS: can't query SystemPartition value: 0x%x\n", Status
);
837 /* Initialize the system partition string string */
838 RtlInitUnicodeString(&SystemPartition
, (PWCHAR
)PartialInfo
->Data
);
840 /* Enumerate the directory looking for the symbolic link string */
841 RtlInitUnicodeString(&SearchString
, L
"SymbolicLink");
842 RtlInitEmptyUnicodeString(&LinkTarget
, LinkBuffer
, sizeof(LinkBuffer
));
843 Status
= NtQueryDirectoryObject(SmpDosDevicesObjectDirectory
,
845 sizeof(DirInfoBuffer
),
850 if (!NT_SUCCESS(Status
))
852 DPRINT1("SMSS: can't find drive letter for system partition\n");
856 /* Keep searching until we find it */
860 if ((RtlEqualUnicodeString(&DirInfo
->TypeName
, &SearchString
, TRUE
)) &&
861 (DirInfo
->Name
.Length
== 2 * sizeof(WCHAR
)) &&
862 (DirInfo
->Name
.Buffer
[1] == L
':'))
864 /* Looks like we found it, open the link to get its target */
865 InitializeObjectAttributes(&ObjectAttributes
,
867 OBJ_CASE_INSENSITIVE
,
868 SmpDosDevicesObjectDirectory
,
870 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
871 SYMBOLIC_LINK_ALL_ACCESS
,
873 if (NT_SUCCESS(Status
))
875 /* Open worked, query the target now */
876 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
881 /* Check if it matches the string we had found earlier */
882 if ((NT_SUCCESS(Status
)) &&
883 ((RtlEqualUnicodeString(&SystemPartition
,
886 ((RtlPrefixUnicodeString(&SystemPartition
,
889 (LinkTarget
.Buffer
[SystemPartition
.Length
/ sizeof(WCHAR
)] == L
'\\'))))
897 /* Couldn't find it, try again */
898 Status
= NtQueryDirectoryObject(SmpDosDevicesObjectDirectory
,
900 sizeof(DirInfoBuffer
),
905 } while (NT_SUCCESS(Status
));
906 if (!NT_SUCCESS(Status
))
908 DPRINT1("SMSS: can't find drive letter for system partition\n");
912 /* Open the setup key again, for full access this time */
913 RtlInitUnicodeString(&UnicodeString
,
914 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup");
915 InitializeObjectAttributes(&ObjectAttributes
,
917 OBJ_CASE_INSENSITIVE
,
920 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
921 if (!NT_SUCCESS(Status
))
923 DPRINT1("SMSS: can't open software setup key for writing: 0x%x\n",
928 /* Wrap up the end of the link buffer */
929 wcsncpy(LinkBuffer
, DirInfo
->Name
.Buffer
, 2);
930 LinkBuffer
[2] = L
'\\';
931 LinkBuffer
[3] = L
'\0';
933 /* Now set this as the "BootDir" */
934 RtlInitUnicodeString(&UnicodeString
, L
"BootDir");
935 Status
= NtSetValueKey(KeyHandle
,
941 if (!NT_SUCCESS(Status
))
943 DPRINT1("SMSS: couldn't write BootDir value: 0x%x\n", Status
);
950 SmpCreateSecurityDescriptors(IN BOOLEAN InitialCall
)
953 PSID WorldSid
= NULL
, AdminSid
= NULL
, SystemSid
= NULL
;
954 PSID RestrictedSid
= NULL
, OwnerSid
= NULL
;
955 SID_IDENTIFIER_AUTHORITY WorldAuthority
= {SECURITY_WORLD_SID_AUTHORITY
};
956 SID_IDENTIFIER_AUTHORITY NtAuthority
= {SECURITY_NT_AUTHORITY
};
957 SID_IDENTIFIER_AUTHORITY CreatorAuthority
= {SECURITY_CREATOR_SID_AUTHORITY
};
958 ULONG AclLength
, SidLength
;
961 BOOLEAN ProtectionRequired
= FALSE
;
963 /* Check if this is the first call */
966 /* Create and set the primary descriptor */
967 SmpPrimarySecurityDescriptor
= &SmpPrimarySDBody
;
968 Status
= RtlCreateSecurityDescriptor(SmpPrimarySecurityDescriptor
,
969 SECURITY_DESCRIPTOR_REVISION
);
970 ASSERT(NT_SUCCESS(Status
));
971 Status
= RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor
,
975 ASSERT(NT_SUCCESS(Status
));
977 /* Create and set the liberal descriptor */
978 SmpLiberalSecurityDescriptor
= &SmpLiberalSDBody
;
979 Status
= RtlCreateSecurityDescriptor(SmpLiberalSecurityDescriptor
,
980 SECURITY_DESCRIPTOR_REVISION
);
981 ASSERT(NT_SUCCESS(Status
));
982 Status
= RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor
,
986 ASSERT(NT_SUCCESS(Status
));
988 /* Create and set the \KnownDlls descriptor */
989 SmpKnownDllsSecurityDescriptor
= &SmpKnownDllsSDBody
;
990 Status
= RtlCreateSecurityDescriptor(SmpKnownDllsSecurityDescriptor
,
991 SECURITY_DESCRIPTOR_REVISION
);
992 ASSERT(NT_SUCCESS(Status
));
993 Status
= RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor
,
997 ASSERT(NT_SUCCESS(Status
));
999 /* Create and Set the \ApiPort descriptor */
1000 SmpApiPortSecurityDescriptor
= &SmpApiPortSDBody
;
1001 Status
= RtlCreateSecurityDescriptor(SmpApiPortSecurityDescriptor
,
1002 SECURITY_DESCRIPTOR_REVISION
);
1003 ASSERT(NT_SUCCESS(Status
));
1004 Status
= RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor
,
1008 ASSERT(NT_SUCCESS(Status
));
1011 /* Check if protection was requested in the registry (on by default) */
1012 if (SmpProtectionMode
& 1) ProtectionRequired
= TRUE
;
1014 /* Exit if there's nothing to do */
1015 if (!(InitialCall
|| ProtectionRequired
)) return STATUS_SUCCESS
;
1017 /* Build the world SID */
1018 Status
= RtlAllocateAndInitializeSid(&WorldAuthority
, 1,
1020 0, 0, 0, 0, 0, 0, 0,
1022 if (!NT_SUCCESS(Status
))
1028 /* Build the admin SID */
1029 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 2,
1030 SECURITY_BUILTIN_DOMAIN_RID
,
1031 DOMAIN_ALIAS_RID_ADMINS
,
1034 if (!NT_SUCCESS(Status
))
1040 /* Build the owner SID */
1041 Status
= RtlAllocateAndInitializeSid(&CreatorAuthority
, 1,
1042 SECURITY_CREATOR_OWNER_RID
,
1043 0, 0, 0, 0, 0, 0, 0,
1045 if (!NT_SUCCESS(Status
))
1051 /* Build the restricted SID */
1052 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 1,
1053 SECURITY_RESTRICTED_CODE_RID
,
1054 0, 0, 0, 0, 0, 0, 0,
1056 if (!NT_SUCCESS(Status
))
1058 RestrictedSid
= NULL
;
1062 /* Build the system SID */
1063 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 1,
1064 SECURITY_LOCAL_SYSTEM_RID
,
1065 0, 0, 0, 0, 0, 0, 0,
1067 if (!NT_SUCCESS(Status
))
1073 /* Now check if we're creating the core descriptors */
1076 /* We're skipping NextAcl so we have to do this here */
1077 SidLength
= RtlLengthSid(WorldSid
) + RtlLengthSid(RestrictedSid
) + RtlLengthSid(AdminSid
);
1082 /* Allocate an ACL with two ACEs with two SIDs each */
1083 SidLength
= RtlLengthSid(SystemSid
) + RtlLengthSid(AdminSid
);
1084 AclLength
= sizeof(ACL
) + 2 * sizeof(ACCESS_ALLOWED_ACE
) + SidLength
;
1085 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1086 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1087 if (!NT_SUCCESS(Status
)) goto NextAcl
;
1089 /* Now build the ACL and add the two ACEs */
1090 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1091 ASSERT(NT_SUCCESS(Status
));
1092 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1093 ASSERT(NT_SUCCESS(Status
));
1094 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, SystemSid
);
1095 ASSERT(NT_SUCCESS(Status
));
1097 /* Set this as the DACL */
1098 Status
= RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor
,
1102 ASSERT(NT_SUCCESS(Status
));
1105 /* Allocate an ACL with 6 ACEs, two ACEs per SID */
1106 SidLength
= RtlLengthSid(WorldSid
) + RtlLengthSid(RestrictedSid
) + RtlLengthSid(AdminSid
);
1108 AclLength
= sizeof(ACL
) + 6 * sizeof(ACCESS_ALLOWED_ACE
) + SidLength
;
1109 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1110 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1111 if (!NT_SUCCESS(Status
)) goto NotInitial
;
1113 /* Now build the ACL and add the six ACEs */
1114 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1115 ASSERT(NT_SUCCESS(Status
));
1116 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
, WorldSid
);
1117 ASSERT(NT_SUCCESS(Status
));
1118 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
, RestrictedSid
);
1119 ASSERT(NT_SUCCESS(Status
));
1120 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1121 ASSERT(NT_SUCCESS(Status
));
1122 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, WorldSid
);
1123 ASSERT(NT_SUCCESS(Status
));
1124 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, RestrictedSid
);
1125 ASSERT(NT_SUCCESS(Status
));
1126 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1127 ASSERT(NT_SUCCESS(Status
));
1129 /* Now edit the last three ACEs and make them inheritable */
1130 Status
= RtlGetAce(Acl
, 3, (PVOID
)&Ace
);
1131 ASSERT(NT_SUCCESS(Status
));
1132 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1133 Status
= RtlGetAce(Acl
, 4, (PVOID
)&Ace
);
1134 ASSERT(NT_SUCCESS(Status
));
1135 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1136 Status
= RtlGetAce(Acl
, 5, (PVOID
)&Ace
);
1137 ASSERT(NT_SUCCESS(Status
));
1138 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1140 /* Set this as the DACL */
1141 Status
= RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor
,
1145 ASSERT(NT_SUCCESS(Status
));
1148 /* The initial ACLs have been created, are we also protecting objects? */
1149 if (!ProtectionRequired
) goto Quickie
;
1151 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
1152 SidLength
+= RtlLengthSid(OwnerSid
);
1153 AclLength
= sizeof(ACL
) + 7 * sizeof (ACCESS_ALLOWED_ACE
) + 2 * SidLength
;
1154 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1155 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1156 if (!NT_SUCCESS(Status
)) goto Quickie
;
1158 /* Build the ACL and add the seven ACEs */
1159 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1160 ASSERT(NT_SUCCESS(Status
));
1161 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, WorldSid
);
1162 ASSERT(NT_SUCCESS(Status
));
1163 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, RestrictedSid
);
1164 ASSERT(NT_SUCCESS(Status
));
1165 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1166 ASSERT(NT_SUCCESS(Status
));
1167 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, WorldSid
);
1168 ASSERT(NT_SUCCESS(Status
));
1169 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, RestrictedSid
);
1170 ASSERT(NT_SUCCESS(Status
));
1171 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1172 ASSERT(NT_SUCCESS(Status
));
1173 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, OwnerSid
);
1174 ASSERT(NT_SUCCESS(Status
));
1176 /* Edit the last 4 ACEs to make then inheritable */
1177 Status
= RtlGetAce(Acl
, 3, (PVOID
)&Ace
);
1178 ASSERT(NT_SUCCESS(Status
));
1179 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1180 Status
= RtlGetAce(Acl
, 4, (PVOID
)&Ace
);
1181 ASSERT(NT_SUCCESS(Status
));
1182 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1183 Status
= RtlGetAce(Acl
, 5, (PVOID
)&Ace
);
1184 ASSERT(NT_SUCCESS(Status
));
1185 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1186 Status
= RtlGetAce(Acl
, 6, (PVOID
)&Ace
);
1187 ASSERT(NT_SUCCESS(Status
));
1188 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1190 /* Set this as the DACL for the primary SD */
1191 Status
= RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor
,
1195 ASSERT(NT_SUCCESS(Status
));
1197 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
1198 AclLength
= sizeof(ACL
) + 7 * sizeof (ACCESS_ALLOWED_ACE
) + 2 * SidLength
;
1199 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1200 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1201 if (!NT_SUCCESS(Status
)) goto Quickie
;
1203 /* Build the ACL and add the seven ACEs */
1204 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1205 ASSERT(NT_SUCCESS(Status
));
1206 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, WorldSid
);
1207 ASSERT(NT_SUCCESS(Status
));
1208 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, RestrictedSid
);
1209 ASSERT(NT_SUCCESS(Status
));
1210 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1211 ASSERT(NT_SUCCESS(Status
));
1212 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, WorldSid
);
1213 ASSERT(NT_SUCCESS(Status
));
1214 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, RestrictedSid
);
1215 ASSERT(NT_SUCCESS(Status
));
1216 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1217 ASSERT(NT_SUCCESS(Status
));
1218 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, OwnerSid
);
1219 ASSERT(NT_SUCCESS(Status
));
1221 /* Edit the last 4 ACEs to make then inheritable */
1222 Status
= RtlGetAce(Acl
, 3, (PVOID
)&Ace
);
1223 ASSERT(NT_SUCCESS(Status
));
1224 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1225 Status
= RtlGetAce(Acl
, 4, (PVOID
)&Ace
);
1226 ASSERT(NT_SUCCESS(Status
));
1227 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1228 Status
= RtlGetAce(Acl
, 5, (PVOID
)&Ace
);
1229 ASSERT(NT_SUCCESS(Status
));
1230 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1231 Status
= RtlGetAce(Acl
, 6, (PVOID
)&Ace
);
1232 ASSERT(NT_SUCCESS(Status
));
1233 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1235 /* Now set this as the DACL for the liberal SD */
1236 Status
= RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor
,
1240 ASSERT(NT_SUCCESS(Status
));
1243 /* Cleanup the SIDs */
1244 if (OwnerSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, OwnerSid
);
1245 if (AdminSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, AdminSid
);
1246 if (WorldSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid
);
1247 if (SystemSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, SystemSid
);
1248 if (RestrictedSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSid
);
1254 SmpInitializeDosDevices(VOID
)
1257 PSMP_REGISTRY_VALUE RegEntry
;
1258 SECURITY_DESCRIPTOR_CONTROL OldFlag
= 0;
1259 OBJECT_ATTRIBUTES ObjectAttributes
;
1260 UNICODE_STRING DestinationString
;
1262 PLIST_ENTRY NextEntry
, Head
;
1264 /* Open the GLOBAL?? directory */
1265 RtlInitUnicodeString(&DestinationString
, L
"\\??");
1266 InitializeObjectAttributes(&ObjectAttributes
,
1268 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1271 Status
= NtOpenDirectoryObject(&SmpDosDevicesObjectDirectory
,
1272 DIRECTORY_ALL_ACCESS
,
1274 if (!NT_SUCCESS(Status
))
1276 DPRINT1("SMSS: Unable to open %wZ directory - Status == %lx\n",
1277 &DestinationString
, Status
);
1281 /* Loop the DOS devices */
1282 Head
= &SmpDosDevicesList
;
1283 while (!IsListEmpty(Head
))
1285 /* Get the entry and remove it */
1286 NextEntry
= RemoveHeadList(Head
);
1287 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1289 /* Initialize the attributes, and see which descriptor is being used */
1290 InitializeObjectAttributes(&ObjectAttributes
,
1292 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1293 SmpDosDevicesObjectDirectory
,
1294 SmpPrimarySecurityDescriptor
);
1295 if (SmpPrimarySecurityDescriptor
)
1297 /* Save the old flag and set it while we create this link */
1298 OldFlag
= SmpPrimarySecurityDescriptor
->Control
;
1299 SmpPrimarySecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1302 /* Create the symbolic link */
1303 DPRINT("Creating symlink for %wZ to %wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
1304 Status
= NtCreateSymbolicLinkObject(&DirHandle
,
1305 SYMBOLIC_LINK_ALL_ACCESS
,
1308 if (Status
== STATUS_OBJECT_NAME_EXISTS
)
1310 /* Make it temporary and get rid of the handle */
1311 NtMakeTemporaryObject(DirHandle
);
1314 /* Treat this as success, and see if we got a name back */
1315 Status
= STATUS_SUCCESS
;
1316 if (RegEntry
->Value
.Length
)
1318 /* Create it now with this name */
1319 ObjectAttributes
.Attributes
&= ~OBJ_OPENIF
;
1320 Status
= NtCreateSymbolicLinkObject(&DirHandle
,
1321 SYMBOLIC_LINK_ALL_ACCESS
,
1327 /* If we were using a security descriptor, restore the non-defaulted flag */
1328 if (ObjectAttributes
.SecurityDescriptor
)
1330 SmpPrimarySecurityDescriptor
->Control
= OldFlag
;
1333 /* Print a failure if we failed to create the symbolic link */
1334 if (!NT_SUCCESS(Status
))
1336 DPRINT1("SMSS: Unable to create %wZ => %wZ symbolic link object - Status == 0x%lx\n",
1343 /* Close the handle */
1346 /* Free this entry */
1347 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
1348 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
1349 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
1352 /* Return the status */
1358 SmpProcessModuleImports(IN PVOID Unused
,
1359 IN PCHAR ImportName
)
1361 ULONG Length
= 0, Chars
;
1362 WCHAR Buffer
[MAX_PATH
];
1363 PWCHAR DllName
, DllValue
;
1364 ANSI_STRING ImportString
;
1365 UNICODE_STRING ImportUnicodeString
;
1368 /* Skip NTDLL since it's already always mapped */
1369 if (!_stricmp(ImportName
, "ntdll.dll")) return;
1371 /* Initialize our strings */
1372 RtlInitAnsiString(&ImportString
, ImportName
);
1373 RtlInitEmptyUnicodeString(&ImportUnicodeString
, Buffer
, sizeof(Buffer
));
1374 Status
= RtlAnsiStringToUnicodeString(&ImportUnicodeString
, &ImportString
, FALSE
);
1375 if (!NT_SUCCESS(Status
)) return;
1377 /* Loop in case we find a forwarder */
1378 ImportUnicodeString
.MaximumLength
= ImportUnicodeString
.Length
+ sizeof(UNICODE_NULL
);
1379 while (Length
< ImportUnicodeString
.Length
)
1381 if (ImportUnicodeString
.Buffer
[Length
/ sizeof(WCHAR
)] == L
'.') break;
1382 Length
+= sizeof(WCHAR
);
1385 /* Break up the values as needed */
1386 DllValue
= ImportUnicodeString
.Buffer
;
1387 DllName
= &ImportUnicodeString
.Buffer
[ImportUnicodeString
.MaximumLength
/ sizeof(WCHAR
)];
1388 Chars
= Length
>> 1;
1389 wcsncpy(DllName
, ImportUnicodeString
.Buffer
, Chars
);
1392 /* Add the DLL to the list */
1393 SmpSaveRegistryValue(&SmpKnownDllsList
, DllName
, DllValue
, TRUE
);
1398 SmpInitializeKnownDllsInternal(IN PUNICODE_STRING Directory
,
1399 IN PUNICODE_STRING Path
)
1401 HANDLE DirFileHandle
, DirHandle
, SectionHandle
, FileHandle
, LinkHandle
;
1402 UNICODE_STRING NtPath
, DestinationString
;
1403 OBJECT_ATTRIBUTES ObjectAttributes
;
1404 NTSTATUS Status
, Status1
;
1405 PLIST_ENTRY NextEntry
;
1406 PSMP_REGISTRY_VALUE RegEntry
;
1407 //ULONG_PTR ErrorParameters[3];
1408 //UNICODE_STRING ErrorResponse;
1409 IO_STATUS_BLOCK IoStatusBlock
;
1410 SECURITY_DESCRIPTOR_CONTROL OldFlag
= 0;
1411 USHORT ImageCharacteristics
;
1413 /* Initialize to NULL */
1414 DirFileHandle
= NULL
;
1416 NtPath
.Buffer
= NULL
;
1418 /* Create the \KnownDLLs directory */
1419 InitializeObjectAttributes(&ObjectAttributes
,
1421 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1423 SmpKnownDllsSecurityDescriptor
);
1424 Status
= NtCreateDirectoryObject(&DirHandle
,
1425 DIRECTORY_ALL_ACCESS
,
1427 if (!NT_SUCCESS(Status
))
1429 /* Handle failure */
1430 DPRINT1("SMSS: Unable to create %wZ directory - Status == %lx\n",
1435 /* Convert the path to native format */
1436 if (!RtlDosPathNameToNtPathName_U(Path
->Buffer
, &NtPath
, NULL
, NULL
))
1438 /* Fail if this didn't work */
1439 DPRINT1("SMSS: Unable to to convert %wZ to an Nt path\n", Path
);
1440 Status
= STATUS_OBJECT_NAME_INVALID
;
1444 /* Open the path that was specified, which should be a directory */
1445 InitializeObjectAttributes(&ObjectAttributes
,
1447 OBJ_CASE_INSENSITIVE
,
1450 Status
= NtOpenFile(&DirFileHandle
,
1451 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
1454 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1455 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
1456 if (!NT_SUCCESS(Status
))
1458 /* Fail if we couldn't open it */
1459 DPRINT1("SMSS: Unable to open a handle to the KnownDll directory (%wZ)"
1460 "- Status == %lx\n",
1467 /* Temporarily hack the SD to use a default DACL for this symbolic link */
1468 if (SmpPrimarySecurityDescriptor
)
1470 OldFlag
= SmpPrimarySecurityDescriptor
->Control
;
1471 SmpPrimarySecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1474 /* Create a symbolic link to the directory in the object manager */
1475 RtlInitUnicodeString(&DestinationString
, L
"KnownDllPath");
1476 InitializeObjectAttributes(&ObjectAttributes
,
1478 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1480 SmpPrimarySecurityDescriptor
);
1481 Status
= NtCreateSymbolicLinkObject(&LinkHandle
,
1482 SYMBOLIC_LINK_ALL_ACCESS
,
1487 if (SmpPrimarySecurityDescriptor
) SmpPrimarySecurityDescriptor
->Control
= OldFlag
;
1489 /* Check if the symlink was created */
1490 if (!NT_SUCCESS(Status
))
1492 /* It wasn't, so bail out since the OS needs it to exist */
1493 DPRINT1("SMSS: Unable to create %wZ symbolic link - Status == %lx\n",
1494 &DestinationString
, Status
);
1499 /* We created it permanent, we can go ahead and close the handle now */
1500 Status1
= NtClose(LinkHandle
);
1501 ASSERT(NT_SUCCESS(Status1
));
1503 /* Now loop the known DLLs */
1504 NextEntry
= SmpKnownDllsList
.Flink
;
1505 while (NextEntry
!= &SmpKnownDllsList
)
1507 /* Get the entry and skip it if it's in the exluded list */
1508 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1509 DPRINT("Processing known DLL: %wZ-%wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
1510 if ((SmpFindRegistryValue(&SmpExcludeKnownDllsList
,
1511 RegEntry
->Name
.Buffer
)) ||
1512 (SmpFindRegistryValue(&SmpExcludeKnownDllsList
,
1513 RegEntry
->Value
.Buffer
)))
1518 /* Open the actual file */
1519 InitializeObjectAttributes(&ObjectAttributes
,
1521 OBJ_CASE_INSENSITIVE
,
1524 Status
= NtOpenFile(&FileHandle
,
1525 SYNCHRONIZE
| FILE_EXECUTE
,
1528 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1529 FILE_NON_DIRECTORY_FILE
|
1530 FILE_SYNCHRONOUS_IO_NONALERT
);
1531 if (!NT_SUCCESS(Status
)) break;
1534 Status
= LdrVerifyImageMatchesChecksum((HANDLE
)((ULONG_PTR
)FileHandle
| 1),
1535 SmpProcessModuleImports
,
1537 &ImageCharacteristics
);
1539 if (!NT_SUCCESS(Status
))
1541 /* Checksum failed, so don't even try going further -- kill SMSS */
1542 RtlInitUnicodeString(&ErrorResponse
,
1543 L
"Verification of a KnownDLL failed.");
1544 ErrorParameters
[0] = (ULONG
)&ErrorResponse
;
1545 ErrorParameters
[1] = Status
;
1546 ErrorParameters
[2] = (ULONG
)&RegEntry
->Value
;
1547 SmpTerminate(ErrorParameters
, 5, RTL_NUMBER_OF(ErrorParameters
));
1550 if (!(ImageCharacteristics
& IMAGE_FILE_DLL
))
1552 /* An invalid known DLL entry will also kill SMSS */
1553 RtlInitUnicodeString(&ErrorResponse
,
1554 L
"Non-DLL file included in KnownDLL list.");
1555 ErrorParameters
[0] = (ULONG
)&ErrorResponse
;
1556 ErrorParameters
[1] = STATUS_INVALID_IMPORT_OF_NON_DLL
;
1557 ErrorParameters
[2] = (ULONG
)&RegEntry
->Value
;
1558 SmpTerminate(ErrorParameters
, 5, RTL_NUMBER_OF(ErrorParameters
));
1562 /* Temporarily hack the SD to use a default DACL for this section */
1563 if (SmpLiberalSecurityDescriptor
)
1565 OldFlag
= SmpLiberalSecurityDescriptor
->Control
;
1566 SmpLiberalSecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1569 /* Create the section for this known DLL */
1570 InitializeObjectAttributes(&ObjectAttributes
,
1574 SmpLiberalSecurityDescriptor
)
1575 Status
= NtCreateSection(&SectionHandle
,
1584 if (SmpLiberalSecurityDescriptor
) SmpLiberalSecurityDescriptor
->Control
= OldFlag
;
1586 /* Check if we created the section okay */
1587 if (NT_SUCCESS(Status
))
1589 /* We can close it now, since it's marked permanent */
1590 Status1
= NtClose(SectionHandle
);
1591 ASSERT(NT_SUCCESS(Status1
));
1595 /* If we couldn't make it "known", that's fine and keep going */
1596 DPRINT1("SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n",
1597 &RegEntry
->Value
, Status
);
1600 /* Close the file since we can move on to the next one */
1601 Status1
= NtClose(FileHandle
);
1602 ASSERT(NT_SUCCESS(Status1
));
1604 /* Go to the next entry */
1605 NextEntry
= NextEntry
->Flink
;
1609 /* Close both handles and free the NT path buffer */
1612 Status1
= NtClose(DirHandle
);
1613 ASSERT(NT_SUCCESS(Status1
));
1617 Status1
= NtClose(DirFileHandle
);
1618 ASSERT(NT_SUCCESS(Status1
));
1620 if (NtPath
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath
.Buffer
);
1626 SmpInitializeKnownDlls(VOID
)
1629 PSMP_REGISTRY_VALUE RegEntry
;
1630 UNICODE_STRING DestinationString
;
1631 PLIST_ENTRY Head
, NextEntry
;
1633 /* Call the internal function */
1634 RtlInitUnicodeString(&DestinationString
, L
"\\KnownDlls");
1635 Status
= SmpInitializeKnownDllsInternal(&DestinationString
, &SmpKnownDllPath
);
1637 /* Wipe out the list regardless of success */
1638 Head
= &SmpKnownDllsList
;
1639 while (!IsListEmpty(Head
))
1641 /* Remove this entry */
1642 NextEntry
= RemoveHeadList(Head
);
1645 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1646 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
1647 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
1648 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
1657 SmpCreateDynamicEnvironmentVariables(VOID
)
1660 SYSTEM_BASIC_INFORMATION BasicInfo
;
1661 SYSTEM_PROCESSOR_INFORMATION ProcessorInfo
;
1662 OBJECT_ATTRIBUTES ObjectAttributes
;
1663 UNICODE_STRING ValueName
, DestinationString
;
1664 HANDLE KeyHandle
, KeyHandle2
;
1667 WCHAR ValueBuffer
[512], ValueBuffer2
[512];
1668 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PVOID
)ValueBuffer
;
1669 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo2
= (PVOID
)ValueBuffer2
;
1671 /* Get system basic information -- we'll need the CPU count */
1672 Status
= NtQuerySystemInformation(SystemBasicInformation
,
1676 if (!NT_SUCCESS(Status
))
1678 /* Bail out on failure */
1679 DPRINT1("SMSS: Unable to query system basic information - %x\n", Status
);
1683 /* Get the processor information, we'll query a bunch of revision info */
1684 Status
= NtQuerySystemInformation(SystemProcessorInformation
,
1686 sizeof(ProcessorInfo
),
1688 if (!NT_SUCCESS(Status
))
1690 /* Bail out on failure */
1691 DPRINT1("SMSS: Unable to query system processor information - %x\n", Status
);
1695 /* We'll be writing all these environment variables over here */
1696 RtlInitUnicodeString(&DestinationString
,
1697 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
1698 L
"Control\\Session Manager\\Environment");
1699 InitializeObjectAttributes(&ObjectAttributes
,
1701 OBJ_CASE_INSENSITIVE
,
1704 Status
= NtOpenKey(&KeyHandle
, GENERIC_WRITE
, &ObjectAttributes
);
1705 if (!NT_SUCCESS(Status
))
1707 /* Bail out on failure */
1708 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString
, Status
);
1712 /* First let's write the OS variable */
1713 RtlInitUnicodeString(&ValueName
, L
"OS");
1714 DPRINT("Setting %wZ to %S\n", &ValueName
, L
"Windows_NT");
1715 Status
= NtSetValueKey(KeyHandle
,
1720 wcslen(L
"Windows_NT") * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1721 if (!NT_SUCCESS(Status
))
1723 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1724 &ValueName
, Status
);
1729 /* Next, let's write the CPU architecture variable */
1730 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_ARCHITECTURE");
1731 switch (ProcessorInfo
.ProcessorArchitecture
)
1733 /* Pick the correct string that matches the architecture */
1734 case PROCESSOR_ARCHITECTURE_INTEL
:
1738 case PROCESSOR_ARCHITECTURE_AMD64
:
1739 ArchName
= L
"AMD64";
1742 case PROCESSOR_ARCHITECTURE_IA64
:
1747 ArchName
= L
"Unknown";
1752 DPRINT("Setting %wZ to %S\n", &ValueName
, ArchName
);
1753 Status
= NtSetValueKey(KeyHandle
,
1758 wcslen(ArchName
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1759 if (!NT_SUCCESS(Status
))
1761 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1762 &ValueName
, Status
);
1767 /* And now let's write the processor level */
1768 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_LEVEL");
1769 swprintf(ValueBuffer
, L
"%u", ProcessorInfo
.ProcessorLevel
);
1770 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1771 Status
= NtSetValueKey(KeyHandle
,
1776 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1777 if (!NT_SUCCESS(Status
))
1779 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1780 &ValueName
, Status
);
1785 /* Now open the hardware CPU key */
1786 RtlInitUnicodeString(&DestinationString
,
1787 L
"\\Registry\\Machine\\Hardware\\Description\\System\\"
1788 L
"CentralProcessor\\0");
1789 InitializeObjectAttributes(&ObjectAttributes
,
1791 OBJ_CASE_INSENSITIVE
,
1794 Status
= NtOpenKey(&KeyHandle2
, KEY_READ
, &ObjectAttributes
);
1795 if (!NT_SUCCESS(Status
))
1797 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString
, Status
);
1802 /* So that we can read the identifier out of it... */
1803 RtlInitUnicodeString(&ValueName
, L
"Identifier");
1804 Status
= NtQueryValueKey(KeyHandle2
,
1806 KeyValuePartialInformation
,
1808 sizeof(ValueBuffer
),
1810 if (!NT_SUCCESS(Status
))
1812 NtClose(KeyHandle2
);
1814 DPRINT1("SMSS: Unable to read %wZ\\%wZ - %x\n",
1815 &DestinationString
, &ValueName
, Status
);
1819 /* As well as the vendor... */
1820 RtlInitUnicodeString(&ValueName
, L
"VendorIdentifier");
1821 Status
= NtQueryValueKey(KeyHandle2
,
1823 KeyValuePartialInformation
,
1825 sizeof(ValueBuffer2
),
1827 NtClose(KeyHandle2
);
1828 if (NT_SUCCESS(Status
))
1830 /* To combine it into a single string */
1831 swprintf((PWCHAR
)PartialInfo
->Data
+ wcslen((PWCHAR
)PartialInfo
->Data
),
1833 PartialInfo2
->Data
);
1836 /* So that we can set this as the PROCESSOR_IDENTIFIER variable */
1837 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_IDENTIFIER");
1838 DPRINT("Setting %wZ to %S\n", &ValueName
, PartialInfo
->Data
);
1839 Status
= NtSetValueKey(KeyHandle
,
1844 wcslen((PWCHAR
)PartialInfo
->Data
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1845 if (!NT_SUCCESS(Status
))
1847 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1848 &ValueName
, Status
);
1853 /* Now let's get the processor architecture */
1854 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_REVISION");
1855 switch (ProcessorInfo
.ProcessorArchitecture
)
1857 /* Check if this is an older Intel CPU */
1858 case PROCESSOR_ARCHITECTURE_INTEL
:
1859 if ((ProcessorInfo
.ProcessorRevision
>> 8) == 0xFF)
1861 /* These guys used a revision + stepping, so get the rev only */
1862 swprintf(ValueBuffer
, L
"%02x", ProcessorInfo
.ProcessorRevision
& 0xFF);
1863 _wcsupr(ValueBuffer
);
1867 /* Modern Intel, as well as 64-bit CPUs use a revision without stepping */
1868 case PROCESSOR_ARCHITECTURE_IA64
:
1869 case PROCESSOR_ARCHITECTURE_AMD64
:
1870 swprintf(ValueBuffer
, L
"%04x", ProcessorInfo
.ProcessorRevision
);
1873 /* And anything else we'll just read the whole revision identifier */
1875 swprintf(ValueBuffer
, L
"%u", ProcessorInfo
.ProcessorRevision
);
1879 /* Write the revision to the registry */
1880 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1881 Status
= NtSetValueKey(KeyHandle
,
1886 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1887 if (!NT_SUCCESS(Status
))
1889 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1890 &ValueName
, Status
);
1895 /* And finally, write the number of CPUs */
1896 RtlInitUnicodeString(&ValueName
, L
"NUMBER_OF_PROCESSORS");
1897 swprintf(ValueBuffer
, L
"%u", BasicInfo
.NumberOfProcessors
);
1898 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1899 Status
= NtSetValueKey(KeyHandle
,
1904 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1905 if (!NT_SUCCESS(Status
))
1907 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1908 &ValueName
, Status
);
1913 /* Now we need to write the safeboot option key in a different format */
1914 RtlInitUnicodeString(&DestinationString
,
1915 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
1916 L
"Control\\Safeboot\\Option");
1917 InitializeObjectAttributes(&ObjectAttributes
,
1919 OBJ_CASE_INSENSITIVE
,
1922 Status
= NtOpenKey(&KeyHandle2
, KEY_ALL_ACCESS
, &ObjectAttributes
);
1923 if (NT_SUCCESS(Status
))
1925 /* This was indeed a safeboot, so check what kind of safeboot it was */
1926 RtlInitUnicodeString(&ValueName
, L
"OptionValue");
1927 Status
= NtQueryValueKey(KeyHandle2
,
1929 KeyValuePartialInformation
,
1931 sizeof(ValueBuffer
),
1933 NtClose(KeyHandle2
);
1934 if (NT_SUCCESS(Status
))
1936 /* Convert from the integer value to the correct specifier */
1937 RtlInitUnicodeString(&ValueName
, L
"SAFEBOOT_OPTION");
1938 switch (*(PULONG
)PartialInfo
->Data
)
1941 wcscpy(ValueBuffer
, L
"MINIMAL");
1944 wcscpy(ValueBuffer
, L
"NETWORK");
1947 wcscpy(ValueBuffer
, L
"DSREPAIR");
1951 /* And write it in the environment! */
1952 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1953 Status
= NtSetValueKey(KeyHandle
,
1958 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1959 if (!NT_SUCCESS(Status
))
1961 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1962 &ValueName
, Status
);
1969 DPRINT1("SMSS: Failed querying safeboot option = %x\n", Status
);
1973 /* We are all done now */
1975 return STATUS_SUCCESS
;
1980 SmpProcessFileRenames(VOID
)
1982 BOOLEAN OldState
, HavePrivilege
= FALSE
;
1984 HANDLE FileHandle
, OtherFileHandle
;
1985 FILE_INFORMATION_CLASS InformationClass
;
1986 OBJECT_ATTRIBUTES ObjectAttributes
;
1987 IO_STATUS_BLOCK IoStatusBlock
;
1988 UNICODE_STRING FileString
;
1989 FILE_BASIC_INFORMATION BasicInfo
;
1990 FILE_DISPOSITION_INFORMATION DeleteInformation
;
1991 PFILE_RENAME_INFORMATION Buffer
;
1992 PLIST_ENTRY Head
, NextEntry
;
1993 PSMP_REGISTRY_VALUE RegEntry
;
1995 ULONG ValueLength
, Length
;
1997 /* Give us access to restore any files we want */
1998 Status
= RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, TRUE
, FALSE
, &OldState
);
1999 if (NT_SUCCESS(Status
)) HavePrivilege
= TRUE
;
2001 /* Process pending files to rename */
2002 Head
= &SmpFileRenameList
;
2003 while (!IsListEmpty(Head
))
2005 /* Get this entry */
2006 NextEntry
= RemoveHeadList(Head
);
2007 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2008 DPRINT1("Processing PFRO: %wZ/%wZ\n", &RegEntry
->Value
, &RegEntry
->Name
);
2010 /* Skip past the '@' marker */
2011 if (!(RegEntry
->Value
.Length
) && (*RegEntry
->Name
.Buffer
== L
'@'))
2013 RegEntry
->Name
.Length
-= sizeof(UNICODE_NULL
);
2014 RegEntry
->Name
.Buffer
++;
2017 /* Open the file for delete access */
2018 InitializeObjectAttributes(&ObjectAttributes
,
2020 OBJ_CASE_INSENSITIVE
,
2023 Status
= NtOpenFile(&OtherFileHandle
,
2024 DELETE
| SYNCHRONIZE
,
2027 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2028 FILE_SYNCHRONOUS_IO_NONALERT
);
2029 if (!NT_SUCCESS(Status
)) goto Quickie
;
2031 /* Check if it's a rename or just a delete */
2032 ValueLength
= RegEntry
->Value
.Length
;
2035 /* Just a delete, set up the class, length and buffer */
2036 InformationClass
= FileDispositionInformation
;
2037 Length
= sizeof(DeleteInformation
);
2038 Buffer
= (PFILE_RENAME_INFORMATION
)&DeleteInformation
;
2040 /* Set the delete disposition */
2041 DeleteInformation
.DeleteFile
= TRUE
;
2045 /* This is a rename, setup the class and length */
2046 InformationClass
= FileRenameInformation
;
2047 Length
= ValueLength
+ sizeof(FILE_RENAME_INFORMATION
);
2049 /* Skip past the special markers */
2050 FileName
= RegEntry
->Value
.Buffer
;
2051 if ((*FileName
== L
'!') || (*FileName
== L
'@'))
2054 Length
-= sizeof(UNICODE_NULL
);
2057 /* Now allocate the buffer for the rename information */
2058 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag
, Length
);
2061 /* Setup the buffer to point to the filename, and copy it */
2062 Buffer
->RootDirectory
= NULL
;
2063 Buffer
->FileNameLength
= Length
- sizeof(FILE_RENAME_INFORMATION
);
2064 Buffer
->ReplaceIfExists
= FileName
!= RegEntry
->Value
.Buffer
;
2065 RtlCopyMemory(Buffer
->FileName
, FileName
, Buffer
->FileNameLength
);
2070 Status
= STATUS_NO_MEMORY
;
2074 /* Check if everything is okay till here */
2075 if (NT_SUCCESS(Status
))
2077 /* Now either rename or delete the file as requested */
2078 Status
= NtSetInformationFile(OtherFileHandle
,
2084 /* Check if we seem to have failed because the file was readonly */
2085 if ((NT_SUCCESS(Status
) &&
2086 (InformationClass
== FileRenameInformation
) &&
2087 (Status
== STATUS_OBJECT_NAME_COLLISION
) &&
2088 (Buffer
->ReplaceIfExists
)))
2090 /* Open the file for write attribute access this time... */
2091 DPRINT1("\nSMSS: %wZ => %wZ failed - Status == %x, Possible readonly target\n",
2094 STATUS_OBJECT_NAME_COLLISION
);
2095 FileString
.Length
= RegEntry
->Value
.Length
- sizeof(WCHAR
);
2096 FileString
.MaximumLength
= RegEntry
->Value
.MaximumLength
- sizeof(WCHAR
);
2097 FileString
.Buffer
= FileName
;
2098 InitializeObjectAttributes(&ObjectAttributes
,
2100 OBJ_CASE_INSENSITIVE
,
2103 Status
= NtOpenFile(&FileHandle
,
2104 FILE_WRITE_ATTRIBUTES
| SYNCHRONIZE
,
2107 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2108 FILE_SYNCHRONOUS_IO_NONALERT
);
2109 if (!NT_SUCCESS(Status
))
2111 /* That didn't work, so bail out */
2112 DPRINT1(" SMSS: Open Existing file Failed - Status == %x\n",
2117 /* Now remove the read-only attribute from the file */
2118 DPRINT1(" SMSS: Open Existing Success\n");
2119 RtlZeroMemory(&BasicInfo
, sizeof(BasicInfo
));
2120 BasicInfo
.FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
2121 Status
= NtSetInformationFile(FileHandle
,
2125 FileBasicInformation
);
2126 NtClose(FileHandle
);
2127 if (!NT_SUCCESS(Status
))
2129 /* That didn't work, bail out */
2130 DPRINT1(" SMSS: Set To NORMAL Failed - Status == %x\n",
2135 /* Now that the file is no longer read-only, delete! */
2136 DPRINT1(" SMSS: Set To NORMAL OK\n");
2137 Status
= NtSetInformationFile(OtherFileHandle
,
2141 FileRenameInformation
);
2142 if (!NT_SUCCESS(Status
))
2144 /* That failed too! */
2145 DPRINT1(" SMSS: Re-Rename Failed - Status == %x\n",
2151 DPRINT1(" SMSS: Re-Rename Worked OK\n");
2158 /* Close the file handle and check the operation result */
2159 NtClose(OtherFileHandle
);
2161 if (!NT_SUCCESS(Status
))
2163 /* We totally failed */
2164 DPRINT1("SMSS: %wZ => %wZ failed - Status == %x\n",
2165 &RegEntry
->Name
, &RegEntry
->Value
, Status
);
2167 else if (RegEntry
->Value
.Length
)
2169 /* We succeed with a rename */
2170 DPRINT1("SMSS: %wZ (renamed to) %wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
2174 /* We suceeded with a delete */
2175 DPRINT1("SMSS: %wZ (deleted)\n", &RegEntry
->Name
);
2178 /* Now free this entry and keep going */
2179 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2180 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2181 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2184 /* Put back the restore privilege if we had requested it, and return */
2185 if (HavePrivilege
) RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, FALSE
, FALSE
, &OldState
);
2191 SmpLoadDataFromRegistry(OUT PUNICODE_STRING InitialCommand
)
2194 PLIST_ENTRY Head
, NextEntry
;
2195 PSMP_REGISTRY_VALUE RegEntry
;
2196 PVOID OriginalEnvironment
;
2197 ULONG MuSessionId
= 0;
2198 OBJECT_ATTRIBUTES ObjectAttributes
;
2200 UNICODE_STRING DestinationString
;
2202 /* Initialize the keywords we'll be looking for */
2203 RtlInitUnicodeString(&SmpDebugKeyword
, L
"debug");
2204 RtlInitUnicodeString(&SmpASyncKeyword
, L
"async");
2205 RtlInitUnicodeString(&SmpAutoChkKeyword
, L
"autocheck");
2207 /* Initialize all the registry-associated list heads */
2208 InitializeListHead(&SmpBootExecuteList
);
2209 InitializeListHead(&SmpSetupExecuteList
);
2210 InitializeListHead(&SmpPagingFileList
);
2211 InitializeListHead(&SmpDosDevicesList
);
2212 InitializeListHead(&SmpFileRenameList
);
2213 InitializeListHead(&SmpKnownDllsList
);
2214 InitializeListHead(&SmpExcludeKnownDllsList
);
2215 InitializeListHead(&SmpSubSystemList
);
2216 InitializeListHead(&SmpSubSystemsToLoad
);
2217 InitializeListHead(&SmpSubSystemsToDefer
);
2218 InitializeListHead(&SmpExecuteList
);
2219 SmpPagingFileInitialize();
2221 /* Initialize the SMSS environment */
2222 Status
= RtlCreateEnvironment(TRUE
, &SmpDefaultEnvironment
);
2223 if (!NT_SUCCESS(Status
))
2225 /* Fail if there was a problem */
2226 DPRINT1("SMSS: Unable to allocate default environment - Status == %X\n",
2228 SMSS_CHECKPOINT(RtlCreateEnvironment
, Status
);
2232 /* Check if we were booted in PE mode (LiveCD should have this) */
2233 RtlInitUnicodeString(&DestinationString
,
2234 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
2235 L
"Control\\MiniNT");
2236 InitializeObjectAttributes(&ObjectAttributes
,
2238 OBJ_CASE_INSENSITIVE
,
2241 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
2242 if (NT_SUCCESS(Status
))
2244 /* If the key exists, we were */
2249 /* Print out if this is the case */
2250 if (MiniNTBoot
) DPRINT1("SMSS: !!! MiniNT Boot !!!\n");
2252 /* Open the environment key to see if we are booted in safe mode */
2253 RtlInitUnicodeString(&DestinationString
,
2254 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
2255 L
"Control\\Session Manager\\Environment");
2256 InitializeObjectAttributes(&ObjectAttributes
,
2258 OBJ_CASE_INSENSITIVE
,
2261 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
2262 if (NT_SUCCESS(Status
))
2264 /* Delete the value if we found it */
2265 RtlInitUnicodeString(&DestinationString
, L
"SAFEBOOT_OPTION");
2266 NtDeleteValueKey(KeyHandle
, &DestinationString
);
2270 /* Switch environments, then query the registry for all needed settings */
2271 OriginalEnvironment
= NtCurrentPeb()->ProcessParameters
->Environment
;
2272 NtCurrentPeb()->ProcessParameters
->Environment
= SmpDefaultEnvironment
;
2273 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
2275 SmpRegistryConfigurationTable
,
2278 SmpDefaultEnvironment
= NtCurrentPeb()->ProcessParameters
->Environment
;
2279 NtCurrentPeb()->ProcessParameters
->Environment
= OriginalEnvironment
;
2280 if (!NT_SUCCESS(Status
))
2282 /* We failed somewhere in registry initialization, which is bad... */
2283 DPRINT1("SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status
);
2284 SMSS_CHECKPOINT(RtlQueryRegistryValues
, Status
);
2288 /* Now we can start acting on the registry settings. First to DOS devices */
2289 Status
= SmpInitializeDosDevices();
2290 if (!NT_SUCCESS(Status
))
2293 DPRINT1("SMSS: Unable to initialize DosDevices configuration - Status == %lx\n",
2295 SMSS_CHECKPOINT(SmpInitializeDosDevices
, Status
);
2299 /* Next create the session directory... */
2300 RtlInitUnicodeString(&DestinationString
, L
"\\Sessions");
2301 InitializeObjectAttributes(&ObjectAttributes
,
2303 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
2305 SmpPrimarySecurityDescriptor
);
2306 Status
= NtCreateDirectoryObject(&SmpSessionsObjectDirectory
,
2307 DIRECTORY_ALL_ACCESS
,
2309 if (!NT_SUCCESS(Status
))
2312 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
2313 &DestinationString
, Status
);
2314 SMSS_CHECKPOINT(NtCreateDirectoryObject
, Status
);
2318 /* Next loop all the boot execute binaries */
2319 Head
= &SmpBootExecuteList
;
2320 while (!IsListEmpty(Head
))
2322 /* Remove each one from the list */
2323 NextEntry
= RemoveHeadList(Head
);
2326 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2327 SmpExecuteCommand(&RegEntry
->Name
, 0, NULL
, 0);
2330 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2331 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2332 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2335 /* Now do any pending file rename operations... */
2336 if (!MiniNTBoot
) SmpProcessFileRenames();
2338 /* And initialize known DLLs... */
2339 Status
= SmpInitializeKnownDlls();
2340 if (!NT_SUCCESS(Status
))
2342 /* Fail if that didn't work */
2343 DPRINT1("SMSS: Unable to initialize KnownDll configuration - Status == %lx\n",
2345 SMSS_CHECKPOINT(SmpInitializeKnownDlls
, Status
);
2349 /* Loop every page file */
2350 Head
= &SmpPagingFileList
;
2351 while (!IsListEmpty(Head
))
2353 /* Remove each one from the list */
2354 NextEntry
= RemoveHeadList(Head
);
2356 /* Create the descriptor for it */
2357 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2358 SmpCreatePagingFileDescriptor(&RegEntry
->Name
);
2361 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2362 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2363 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2366 /* Now create all the paging files for the descriptors that we have */
2367 SmpCreatePagingFiles();
2369 /* Tell Cm it's now safe to fully enable write access to the registry */
2370 NtInitializeRegistry(CM_BOOT_FLAG_SMSS
);
2372 /* Create all the system-based environment variables for later inheriting */
2373 Status
= SmpCreateDynamicEnvironmentVariables();
2374 if (!NT_SUCCESS(Status
))
2376 /* Handle failure */
2377 SMSS_CHECKPOINT(SmpCreateDynamicEnvironmentVariables
, Status
);
2381 /* And finally load all the subsytems for our first session! */
2382 Status
= SmpLoadSubSystemsForMuSession(&MuSessionId
,
2383 &SmpWindowsSubSysProcessId
,
2385 ASSERT(MuSessionId
== 0);
2386 if (!NT_SUCCESS(Status
)) SMSS_CHECKPOINT(SmpLoadSubSystemsForMuSession
, Status
);
2392 SmpInit(IN PUNICODE_STRING InitialCommand
,
2393 OUT PHANDLE ProcessHandle
)
2395 NTSTATUS Status
, Status2
;
2396 OBJECT_ATTRIBUTES ObjectAttributes
;
2397 UNICODE_STRING PortName
, EventName
;
2398 HANDLE EventHandle
, PortHandle
;
2399 ULONG HardErrorMode
;
2401 /* Create the SMSS Heap */
2402 SmBaseTag
= RtlCreateTagHeap(RtlGetProcessHeap(),
2406 SmpHeap
= RtlGetProcessHeap();
2408 /* Enable hard errors */
2409 HardErrorMode
= TRUE
;
2410 NtSetInformationProcess(NtCurrentProcess(),
2411 ProcessDefaultHardErrorMode
,
2413 sizeof(HardErrorMode
));
2415 /* Initialize the subsystem list and the session list, plus their locks */
2416 RtlInitializeCriticalSection(&SmpKnownSubSysLock
);
2417 InitializeListHead(&SmpKnownSubSysHead
);
2418 RtlInitializeCriticalSection(&SmpSessionListLock
);
2419 InitializeListHead(&SmpSessionListHead
);
2421 /* Initialize the process list */
2422 InitializeListHead(&NativeProcessList
);
2424 /* Initialize session parameters */
2425 SmpNextSessionId
= 1;
2426 SmpNextSessionIdScanMode
= 0;
2427 SmpDbgSsLoaded
= FALSE
;
2429 /* Create the initial security descriptors */
2430 Status
= SmpCreateSecurityDescriptors(TRUE
);
2431 if (!NT_SUCCESS(Status
))
2434 SMSS_CHECKPOINT(SmpCreateSecurityDescriptors
, Status
);
2438 /* Initialize subsystem names */
2439 RtlInitUnicodeString(&SmpSubsystemName
, L
"NT-Session Manager");
2440 RtlInitUnicodeString(&PosixName
, L
"POSIX");
2441 RtlInitUnicodeString(&Os2Name
, L
"OS2");
2443 /* Create the SM API Port */
2444 RtlInitUnicodeString(&PortName
, L
"\\SmApiPort2");
2445 InitializeObjectAttributes(&ObjectAttributes
, &PortName
, 0, NULL
, NULL
);
2446 Status
= NtCreatePort(&PortHandle
,
2448 sizeof(SB_CONNECTION_INFO
),
2450 sizeof(SB_API_MSG
) * 32);
2451 ASSERT(NT_SUCCESS(Status
));
2452 SmpDebugPort
= PortHandle
;
2454 /* Create two SM API threads */
2455 Status
= RtlCreateUserThread(NtCurrentProcess(),
2465 ASSERT(NT_SUCCESS(Status
));
2466 Status
= RtlCreateUserThread(NtCurrentProcess(),
2476 ASSERT(NT_SUCCESS(Status
));
2478 /* Create the write event that autochk can set after running */
2479 RtlInitUnicodeString(&EventName
, L
"\\Device\\VolumesSafeForWriteAccess");
2480 InitializeObjectAttributes(&ObjectAttributes
,
2485 Status2
= NtCreateEvent(&EventHandle
,
2490 if (!NT_SUCCESS(Status2
))
2492 /* Should never really fail */
2493 DPRINT1("SMSS: Unable to create %wZ event - Status == %lx\n",
2494 &EventName
, Status2
);
2495 ASSERT(NT_SUCCESS(Status2
));
2498 /* Now initialize everything else based on the registry parameters */
2499 Status
= SmpLoadDataFromRegistry(InitialCommand
);
2500 if (NT_SUCCESS(Status
))
2502 /* Autochk should've run now. Set the event and save the CSRSS handle */
2503 *ProcessHandle
= SmpWindowsSubSysProcess
;
2504 NtSetEvent(EventHandle
, 0);
2505 NtClose(EventHandle
);