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"))
468 /* Add to the linked list -- this is a file */
469 return SmpSaveRegistryValue(EntryContext
, ValueName
, ValueData
, TRUE
);
472 /* This is the directory, initialize it */
473 DPRINT("KnownDll Path: %S\n", ValueData
);
474 return SmpInitializeKnownDllPath(&SmpKnownDllPath
, ValueData
, ValueLength
);
479 SmpConfigureEnvironment(IN PWSTR ValueName
,
482 IN ULONG ValueLength
,
484 IN PVOID EntryContext
)
487 UNICODE_STRING ValueString
, DataString
;
489 /* Convert the strings into UNICODE_STRING and set the variable defined */
490 RtlInitUnicodeString(&ValueString
, ValueName
);
491 RtlInitUnicodeString(&DataString
, ValueData
);
492 DPRINT("Setting %wZ = %wZ\n", &ValueString
, &DataString
);
493 Status
= RtlSetEnvironmentVariable(0, &ValueString
, &DataString
);
494 if (!NT_SUCCESS(Status
))
496 DPRINT1("SMSS: 'SET %wZ = %wZ' failed - Status == %lx\n",
497 &ValueString
, &DataString
, Status
);
501 /* Check if the path is being set, and wait for the second instantiation */
502 if (!(_wcsicmp(ValueName
, L
"Path")) && (++SmpCalledConfigEnv
== 2))
504 /* Allocate the path buffer */
505 SmpDefaultLibPathBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
508 if (!SmpDefaultLibPathBuffer
) return STATUS_NO_MEMORY
;
510 /* Copy the data into it and create the UNICODE_STRING to hold it */
511 RtlCopyMemory(SmpDefaultLibPathBuffer
, ValueData
, ValueLength
);
512 RtlInitUnicodeString(&SmpDefaultLibPath
, SmpDefaultLibPathBuffer
);
516 return STATUS_SUCCESS
;
521 SmpConfigureSubSystems(IN PWSTR ValueName
,
524 IN ULONG ValueLength
,
526 IN PVOID EntryContext
)
528 PSMP_REGISTRY_VALUE RegEntry
;
529 PWCHAR SubsystemName
;
531 /* Is this a required or optional subsystem */
532 if ((_wcsicmp(ValueName
, L
"Required")) &&
533 (_wcsicmp(ValueName
, L
"Optional")))
535 /* It isn't, is this the PSI flag? */
536 if ((_wcsicmp(ValueName
, L
"PosixSingleInstance")) ||
537 (ValueType
!= REG_DWORD
))
539 /* It isn't, must be a subsystem entry, add it to the list */
540 DPRINT("Subsystem entry: %S-%S\n", ValueName
, ValueData
);
541 return SmpSaveRegistryValue(EntryContext
, ValueName
, ValueData
, TRUE
);
544 /* This was the PSI flag, save it and exit */
545 RegPosixSingleInstance
= TRUE
;
546 return STATUS_SUCCESS
;
549 /* This should be one of the required/optional lists. Is the type valid? */
550 if (ValueType
== REG_MULTI_SZ
)
552 /* It is, get the first subsystem */
553 SubsystemName
= ValueData
;
554 while (*SubsystemName
)
556 /* We should have already put it into the list when we found it */
557 DPRINT("Found subsystem: %S\n", SubsystemName
);
558 RegEntry
= SmpFindRegistryValue(EntryContext
, SubsystemName
);
561 /* This subsystem doesn't exist, so skip it */
562 DPRINT1("SMSS: Invalid subsystem name - %ws\n", SubsystemName
);
566 /* Found it -- remove it from the main list */
567 RemoveEntryList(&RegEntry
->Entry
);
569 /* Figure out which list to put it in */
570 if (_wcsicmp(ValueName
, L
"Required"))
572 /* Put it into the optional list */
573 DPRINT("Optional\n");
574 InsertTailList(&SmpSubSystemsToDefer
, &RegEntry
->Entry
);
578 /* Put it into the required list */
579 DPRINT("Required\n");
580 InsertTailList(&SmpSubSystemsToLoad
, &RegEntry
->Entry
);
584 /* Move to the next name */
585 while (*SubsystemName
++);
590 return STATUS_SUCCESS
;
593 RTL_QUERY_REGISTRY_TABLE
594 SmpRegistryConfigurationTable
[] =
597 SmpConfigureProtectionMode
,
607 SmpConfigureAllowProtectedRenames
,
608 0, //RTL_QUERY_REGISTRY_DELETE,
609 L
"AllowProtectedRenames",
617 SmpConfigureObjectDirectories
,
619 L
"ObjectDirectories",
622 L
"\\Windows\0\\RPC Control\0",
627 SmpConfigureMemoryMgmt
,
637 SmpConfigureMemoryMgmt
,
638 RTL_QUERY_REGISTRY_TOPKEY
,
640 &SmpSetupExecuteList
,
647 SmpConfigureFileRenames
,
648 0, //RTL_QUERY_REGISTRY_DELETE,
649 L
"PendingFileRenameOperations",
657 SmpConfigureFileRenames
,
658 0, //RTL_QUERY_REGISTRY_DELETE,
659 L
"PendingFileRenameOperations2",
667 SmpConfigureExcludeKnownDlls
,
669 L
"ExcludeFromKnownDlls",
670 &SmpExcludeKnownDllsList
,
678 RTL_QUERY_REGISTRY_SUBKEY
,
679 L
"Memory Management",
687 SmpConfigureMemoryMgmt
,
692 L
"?:\\pagefile.sys\0",
697 SmpConfigureDosDevices
,
698 RTL_QUERY_REGISTRY_SUBKEY
,
707 SmpConfigureKnownDlls
,
708 RTL_QUERY_REGISTRY_SUBKEY
,
717 SmpConfigureEnvironment
,
718 RTL_QUERY_REGISTRY_SUBKEY
,
727 SmpConfigureEnvironment
,
728 RTL_QUERY_REGISTRY_SUBKEY
,
737 SmpConfigureSubSystems
,
738 RTL_QUERY_REGISTRY_SUBKEY
,
747 SmpConfigureSubSystems
,
748 RTL_QUERY_REGISTRY_NOEXPAND
,
757 SmpConfigureSubSystems
,
758 RTL_QUERY_REGISTRY_NOEXPAND
,
767 SmpConfigureSubSystems
,
777 SmpConfigureMemoryMgmt
,
778 RTL_QUERY_REGISTRY_TOPKEY
,
789 /* FUNCTIONS ******************************************************************/
793 SmpTranslateSystemPartitionInformation(VOID
)
796 UNICODE_STRING UnicodeString
, LinkTarget
, SearchString
, SystemPartition
;
797 OBJECT_ATTRIBUTES ObjectAttributes
;
798 HANDLE KeyHandle
, LinkHandle
;
799 CHAR ValueBuffer
[512 + sizeof(KEY_VALUE_PARTIAL_INFORMATION
)];
800 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PVOID
)ValueBuffer
;
801 ULONG Length
, Context
;
802 CHAR DirInfoBuffer
[512 + sizeof(OBJECT_DIRECTORY_INFORMATION
)];
803 POBJECT_DIRECTORY_INFORMATION DirInfo
= (PVOID
)DirInfoBuffer
;
804 WCHAR LinkBuffer
[MAX_PATH
];
806 /* Open the setup key */
807 RtlInitUnicodeString(&UnicodeString
, L
"\\Registry\\Machine\\System\\Setup");
808 InitializeObjectAttributes(&ObjectAttributes
,
810 OBJ_CASE_INSENSITIVE
,
813 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
814 if (!NT_SUCCESS(Status
))
816 DPRINT1("SMSS: can't open system setup key for reading: 0x%x\n", Status
);
820 /* Query the system partition */
821 RtlInitUnicodeString(&UnicodeString
, L
"SystemPartition");
822 Status
= NtQueryValueKey(KeyHandle
,
824 KeyValuePartialInformation
,
829 if (!NT_SUCCESS(Status
))
831 DPRINT1("SMSS: can't query SystemPartition value: 0x%x\n", Status
);
835 /* Initialize the system partition string string */
836 RtlInitUnicodeString(&SystemPartition
, (PWCHAR
)PartialInfo
->Data
);
838 /* Enumerate the directory looking for the symbolic link string */
839 RtlInitUnicodeString(&SearchString
, L
"SymbolicLink");
840 RtlInitEmptyUnicodeString(&LinkTarget
, LinkBuffer
, sizeof(LinkBuffer
));
841 Status
= NtQueryDirectoryObject(SmpDosDevicesObjectDirectory
,
843 sizeof(DirInfoBuffer
),
848 if (!NT_SUCCESS(Status
))
850 DPRINT1("SMSS: can't find drive letter for system partition\n");
854 /* Keep searching until we find it */
858 if ((RtlEqualUnicodeString(&DirInfo
->TypeName
, &SearchString
, TRUE
)) &&
859 (DirInfo
->Name
.Length
== 2 * sizeof(WCHAR
)) &&
860 (DirInfo
->Name
.Buffer
[1] == L
':'))
862 /* Looks like we found it, open the link to get its target */
863 InitializeObjectAttributes(&ObjectAttributes
,
865 OBJ_CASE_INSENSITIVE
,
866 SmpDosDevicesObjectDirectory
,
868 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
869 SYMBOLIC_LINK_ALL_ACCESS
,
871 if (NT_SUCCESS(Status
))
873 /* Open worked, query the target now */
874 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
879 /* Check if it matches the string we had found earlier */
880 if ((NT_SUCCESS(Status
)) &&
881 ((RtlEqualUnicodeString(&SystemPartition
,
884 ((RtlPrefixUnicodeString(&SystemPartition
,
887 (LinkTarget
.Buffer
[SystemPartition
.Length
/ sizeof(WCHAR
)] == L
'\\'))))
895 /* Couldn't find it, try again */
896 Status
= NtQueryDirectoryObject(SmpDosDevicesObjectDirectory
,
898 sizeof(DirInfoBuffer
),
903 } while (NT_SUCCESS(Status
));
904 if (!NT_SUCCESS(Status
))
906 DPRINT1("SMSS: can't find drive letter for system partition\n");
910 /* Open the setup key again, for full access this time */
911 RtlInitUnicodeString(&UnicodeString
,
912 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup");
913 InitializeObjectAttributes(&ObjectAttributes
,
915 OBJ_CASE_INSENSITIVE
,
918 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
919 if (!NT_SUCCESS(Status
))
921 DPRINT1("SMSS: can't open software setup key for writing: 0x%x\n",
926 /* Wrap up the end of the link buffer */
927 wcsncpy(LinkBuffer
, DirInfo
->Name
.Buffer
, 2);
928 LinkBuffer
[2] = L
'\\';
929 LinkBuffer
[3] = L
'\0';
931 /* Now set this as the "BootDir" */
932 RtlInitUnicodeString(&UnicodeString
, L
"BootDir");
933 Status
= NtSetValueKey(KeyHandle
,
939 if (!NT_SUCCESS(Status
))
941 DPRINT1("SMSS: couldn't write BootDir value: 0x%x\n", Status
);
948 SmpCreateSecurityDescriptors(IN BOOLEAN InitialCall
)
951 PSID WorldSid
= NULL
, AdminSid
= NULL
, SystemSid
= NULL
;
952 PSID RestrictedSid
= NULL
, OwnerSid
= NULL
;
953 SID_IDENTIFIER_AUTHORITY WorldAuthority
= {SECURITY_WORLD_SID_AUTHORITY
};
954 SID_IDENTIFIER_AUTHORITY NtAuthority
= {SECURITY_NT_AUTHORITY
};
955 SID_IDENTIFIER_AUTHORITY CreatorAuthority
= {SECURITY_CREATOR_SID_AUTHORITY
};
956 ULONG AclLength
, SidLength
;
959 BOOLEAN ProtectionRequired
= FALSE
;
961 /* Check if this is the first call */
964 /* Create and set the primary descriptor */
965 SmpPrimarySecurityDescriptor
= &SmpPrimarySDBody
;
966 Status
= RtlCreateSecurityDescriptor(SmpPrimarySecurityDescriptor
,
967 SECURITY_DESCRIPTOR_REVISION
);
968 ASSERT(NT_SUCCESS(Status
));
969 Status
= RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor
,
973 ASSERT(NT_SUCCESS(Status
));
975 /* Create and set the liberal descriptor */
976 SmpLiberalSecurityDescriptor
= &SmpLiberalSDBody
;
977 Status
= RtlCreateSecurityDescriptor(SmpLiberalSecurityDescriptor
,
978 SECURITY_DESCRIPTOR_REVISION
);
979 ASSERT(NT_SUCCESS(Status
));
980 Status
= RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor
,
984 ASSERT(NT_SUCCESS(Status
));
986 /* Create and set the \KnownDlls descriptor */
987 SmpKnownDllsSecurityDescriptor
= &SmpKnownDllsSDBody
;
988 Status
= RtlCreateSecurityDescriptor(SmpKnownDllsSecurityDescriptor
,
989 SECURITY_DESCRIPTOR_REVISION
);
990 ASSERT(NT_SUCCESS(Status
));
991 Status
= RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor
,
995 ASSERT(NT_SUCCESS(Status
));
997 /* Create and Set the \ApiPort descriptor */
998 SmpApiPortSecurityDescriptor
= &SmpApiPortSDBody
;
999 Status
= RtlCreateSecurityDescriptor(SmpApiPortSecurityDescriptor
,
1000 SECURITY_DESCRIPTOR_REVISION
);
1001 ASSERT(NT_SUCCESS(Status
));
1002 Status
= RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor
,
1006 ASSERT(NT_SUCCESS(Status
));
1009 /* Check if protection was requested in the registry (on by default) */
1010 if (SmpProtectionMode
& 1) ProtectionRequired
= TRUE
;
1012 /* Exit if there's nothing to do */
1013 if (!(InitialCall
|| ProtectionRequired
)) return STATUS_SUCCESS
;
1015 /* Build the world SID */
1016 Status
= RtlAllocateAndInitializeSid(&WorldAuthority
, 1,
1018 0, 0, 0, 0, 0, 0, 0,
1020 if (!NT_SUCCESS(Status
))
1026 /* Build the admin SID */
1027 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 2,
1028 SECURITY_BUILTIN_DOMAIN_RID
,
1029 DOMAIN_ALIAS_RID_ADMINS
,
1032 if (!NT_SUCCESS(Status
))
1038 /* Build the owner SID */
1039 Status
= RtlAllocateAndInitializeSid(&CreatorAuthority
, 1,
1040 SECURITY_CREATOR_OWNER_RID
,
1041 0, 0, 0, 0, 0, 0, 0,
1043 if (!NT_SUCCESS(Status
))
1049 /* Build the restricted SID */
1050 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 1,
1051 SECURITY_RESTRICTED_CODE_RID
,
1052 0, 0, 0, 0, 0, 0, 0,
1054 if (!NT_SUCCESS(Status
))
1056 RestrictedSid
= NULL
;
1060 /* Build the system SID */
1061 Status
= RtlAllocateAndInitializeSid(&NtAuthority
, 1,
1062 SECURITY_LOCAL_SYSTEM_RID
,
1063 0, 0, 0, 0, 0, 0, 0,
1065 if (!NT_SUCCESS(Status
))
1071 /* Now check if we're creating the core descriptors */
1074 /* We're skipping NextAcl so we have to do this here */
1075 SidLength
= RtlLengthSid(WorldSid
) + RtlLengthSid(RestrictedSid
) + RtlLengthSid(AdminSid
);
1080 /* Allocate an ACL with two ACEs with two SIDs each */
1081 SidLength
= RtlLengthSid(SystemSid
) + RtlLengthSid(AdminSid
);
1082 AclLength
= sizeof(ACL
) + 2 * sizeof(ACCESS_ALLOWED_ACE
) + SidLength
;
1083 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1084 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1085 if (!NT_SUCCESS(Status
)) goto NextAcl
;
1087 /* Now build the ACL and add the two ACEs */
1088 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1089 ASSERT(NT_SUCCESS(Status
));
1090 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1091 ASSERT(NT_SUCCESS(Status
));
1092 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, SystemSid
);
1093 ASSERT(NT_SUCCESS(Status
));
1095 /* Set this as the DACL */
1096 Status
= RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor
,
1100 ASSERT(NT_SUCCESS(Status
));
1103 /* Allocate an ACL with 6 ACEs, two ACEs per SID */
1104 SidLength
= RtlLengthSid(WorldSid
) + RtlLengthSid(RestrictedSid
) + RtlLengthSid(AdminSid
);
1106 AclLength
= sizeof(ACL
) + 6 * sizeof(ACCESS_ALLOWED_ACE
) + SidLength
;
1107 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1108 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1109 if (!NT_SUCCESS(Status
)) goto NotInitial
;
1111 /* Now build the ACL and add the six ACEs */
1112 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1113 ASSERT(NT_SUCCESS(Status
));
1114 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
, WorldSid
);
1115 ASSERT(NT_SUCCESS(Status
));
1116 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
, RestrictedSid
);
1117 ASSERT(NT_SUCCESS(Status
));
1118 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1119 ASSERT(NT_SUCCESS(Status
));
1120 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, WorldSid
);
1121 ASSERT(NT_SUCCESS(Status
));
1122 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, RestrictedSid
);
1123 ASSERT(NT_SUCCESS(Status
));
1124 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1125 ASSERT(NT_SUCCESS(Status
));
1127 /* Now edit the last three ACEs and make them inheritable */
1128 Status
= RtlGetAce(Acl
, 3, (PVOID
)&Ace
);
1129 ASSERT(NT_SUCCESS(Status
));
1130 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1131 Status
= RtlGetAce(Acl
, 4, (PVOID
)&Ace
);
1132 ASSERT(NT_SUCCESS(Status
));
1133 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1134 Status
= RtlGetAce(Acl
, 5, (PVOID
)&Ace
);
1135 ASSERT(NT_SUCCESS(Status
));
1136 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1138 /* Set this as the DACL */
1139 Status
= RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor
,
1143 ASSERT(NT_SUCCESS(Status
));
1146 /* The initial ACLs have been created, are we also protecting objects? */
1147 if (!ProtectionRequired
) goto Quickie
;
1149 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
1150 SidLength
+= RtlLengthSid(OwnerSid
);
1151 AclLength
= sizeof(ACL
) + 7 * sizeof (ACCESS_ALLOWED_ACE
) + 2 * SidLength
;
1152 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1153 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1154 if (!NT_SUCCESS(Status
)) goto Quickie
;
1156 /* Build the ACL and add the seven ACEs */
1157 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1158 ASSERT(NT_SUCCESS(Status
));
1159 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, WorldSid
);
1160 ASSERT(NT_SUCCESS(Status
));
1161 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, RestrictedSid
);
1162 ASSERT(NT_SUCCESS(Status
));
1163 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1164 ASSERT(NT_SUCCESS(Status
));
1165 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, WorldSid
);
1166 ASSERT(NT_SUCCESS(Status
));
1167 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
, RestrictedSid
);
1168 ASSERT(NT_SUCCESS(Status
));
1169 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1170 ASSERT(NT_SUCCESS(Status
));
1171 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, OwnerSid
);
1172 ASSERT(NT_SUCCESS(Status
));
1174 /* Edit the last 4 ACEs to make then inheritable */
1175 Status
= RtlGetAce(Acl
, 3, (PVOID
)&Ace
);
1176 ASSERT(NT_SUCCESS(Status
));
1177 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1178 Status
= RtlGetAce(Acl
, 4, (PVOID
)&Ace
);
1179 ASSERT(NT_SUCCESS(Status
));
1180 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1181 Status
= RtlGetAce(Acl
, 5, (PVOID
)&Ace
);
1182 ASSERT(NT_SUCCESS(Status
));
1183 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1184 Status
= RtlGetAce(Acl
, 6, (PVOID
)&Ace
);
1185 ASSERT(NT_SUCCESS(Status
));
1186 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1188 /* Set this as the DACL for the primary SD */
1189 Status
= RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor
,
1193 ASSERT(NT_SUCCESS(Status
));
1195 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
1196 AclLength
= sizeof(ACL
) + 7 * sizeof (ACCESS_ALLOWED_ACE
) + 2 * SidLength
;
1197 Acl
= RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength
);
1198 if (!Acl
) Status
= STATUS_NO_MEMORY
;
1199 if (!NT_SUCCESS(Status
)) goto Quickie
;
1201 /* Build the ACL and add the seven ACEs */
1202 Status
= RtlCreateAcl(Acl
, AclLength
, ACL_REVISION2
);
1203 ASSERT(NT_SUCCESS(Status
));
1204 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, WorldSid
);
1205 ASSERT(NT_SUCCESS(Status
));
1206 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, RestrictedSid
);
1207 ASSERT(NT_SUCCESS(Status
));
1208 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1209 ASSERT(NT_SUCCESS(Status
));
1210 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, WorldSid
);
1211 ASSERT(NT_SUCCESS(Status
));
1212 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_EXECUTE
| GENERIC_READ
| GENERIC_WRITE
, RestrictedSid
);
1213 ASSERT(NT_SUCCESS(Status
));
1214 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, AdminSid
);
1215 ASSERT(NT_SUCCESS(Status
));
1216 Status
= RtlAddAccessAllowedAce(Acl
, ACL_REVISION2
, GENERIC_ALL
, OwnerSid
);
1217 ASSERT(NT_SUCCESS(Status
));
1219 /* Edit the last 4 ACEs to make then inheritable */
1220 Status
= RtlGetAce(Acl
, 3, (PVOID
)&Ace
);
1221 ASSERT(NT_SUCCESS(Status
));
1222 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1223 Status
= RtlGetAce(Acl
, 4, (PVOID
)&Ace
);
1224 ASSERT(NT_SUCCESS(Status
));
1225 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1226 Status
= RtlGetAce(Acl
, 5, (PVOID
)&Ace
);
1227 ASSERT(NT_SUCCESS(Status
));
1228 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1229 Status
= RtlGetAce(Acl
, 6, (PVOID
)&Ace
);
1230 ASSERT(NT_SUCCESS(Status
));
1231 Ace
->AceFlags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE
;
1233 /* Now set this as the DACL for the liberal SD */
1234 Status
= RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor
,
1238 ASSERT(NT_SUCCESS(Status
));
1241 /* Cleanup the SIDs */
1242 if (OwnerSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, OwnerSid
);
1243 if (AdminSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, AdminSid
);
1244 if (WorldSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid
);
1245 if (SystemSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, SystemSid
);
1246 if (RestrictedSid
) RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSid
);
1252 SmpInitializeDosDevices(VOID
)
1255 PSMP_REGISTRY_VALUE RegEntry
;
1256 SECURITY_DESCRIPTOR_CONTROL OldFlag
= 0;
1257 OBJECT_ATTRIBUTES ObjectAttributes
;
1258 UNICODE_STRING DestinationString
;
1260 PLIST_ENTRY NextEntry
, Head
;
1262 /* Open the GLOBAL?? directory */
1263 RtlInitUnicodeString(&DestinationString
, L
"\\??");
1264 InitializeObjectAttributes(&ObjectAttributes
,
1266 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1269 Status
= NtOpenDirectoryObject(&SmpDosDevicesObjectDirectory
,
1270 DIRECTORY_ALL_ACCESS
,
1272 if (!NT_SUCCESS(Status
))
1274 DPRINT1("SMSS: Unable to open %wZ directory - Status == %lx\n",
1275 &DestinationString
, Status
);
1279 /* Loop the DOS devices */
1280 Head
= &SmpDosDevicesList
;
1281 while (!IsListEmpty(Head
))
1283 /* Get the entry and remove it */
1284 NextEntry
= RemoveHeadList(Head
);
1285 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1287 /* Initialize the attributes, and see which descriptor is being used */
1288 InitializeObjectAttributes(&ObjectAttributes
,
1290 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1291 SmpDosDevicesObjectDirectory
,
1292 SmpPrimarySecurityDescriptor
);
1293 if (SmpPrimarySecurityDescriptor
)
1295 /* Save the old flag and set it while we create this link */
1296 OldFlag
= SmpPrimarySecurityDescriptor
->Control
;
1297 SmpPrimarySecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1300 /* Create the symbolic link */
1301 DPRINT("Creating symlink for %wZ to %wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
1302 Status
= NtCreateSymbolicLinkObject(&DirHandle
,
1303 SYMBOLIC_LINK_ALL_ACCESS
,
1306 if (Status
== STATUS_OBJECT_NAME_EXISTS
)
1308 /* Make it temporary and get rid of the handle */
1309 NtMakeTemporaryObject(DirHandle
);
1312 /* Treat this as success, and see if we got a name back */
1313 Status
= STATUS_SUCCESS
;
1314 if (RegEntry
->Value
.Length
)
1316 /* Create it now with this name */
1317 ObjectAttributes
.Attributes
&= ~OBJ_OPENIF
;
1318 Status
= NtCreateSymbolicLinkObject(&DirHandle
,
1319 SYMBOLIC_LINK_ALL_ACCESS
,
1325 /* If we were using a security descriptor, restore the non-defaulted flag */
1326 if (ObjectAttributes
.SecurityDescriptor
)
1328 SmpPrimarySecurityDescriptor
->Control
= OldFlag
;
1331 /* Print a failure if we failed to create the symbolic link */
1332 if (!NT_SUCCESS(Status
))
1334 DPRINT1("SMSS: Unable to create %wZ => %wZ symbolic link object - Status == 0x%lx\n",
1341 /* Close the handle */
1344 /* Free this entry */
1345 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
1346 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
1347 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
1350 /* Return the status */
1356 SmpProcessModuleImports(IN PVOID Unused
,
1357 IN PCHAR ImportName
)
1359 ULONG Length
= 0, Chars
;
1360 WCHAR Buffer
[MAX_PATH
];
1361 PWCHAR DllName
, DllValue
;
1362 ANSI_STRING ImportString
;
1363 UNICODE_STRING ImportUnicodeString
;
1366 /* Skip NTDLL since it's already always mapped */
1367 if (!_stricmp(ImportName
, "ntdll.dll")) return;
1369 /* Initialize our strings */
1370 RtlInitAnsiString(&ImportString
, ImportName
);
1371 RtlInitEmptyUnicodeString(&ImportUnicodeString
, Buffer
, sizeof(Buffer
));
1372 Status
= RtlAnsiStringToUnicodeString(&ImportUnicodeString
, &ImportString
, FALSE
);
1373 if (!NT_SUCCESS(Status
)) return;
1375 /* Loop in case we find a forwarder */
1376 ImportUnicodeString
.MaximumLength
= ImportUnicodeString
.Length
+ sizeof(UNICODE_NULL
);
1377 while (Length
< ImportUnicodeString
.Length
)
1379 if (ImportUnicodeString
.Buffer
[Length
/ sizeof(WCHAR
)] == L
'.') break;
1380 Length
+= sizeof(WCHAR
);
1383 /* Break up the values as needed */
1384 DllValue
= ImportUnicodeString
.Buffer
;
1385 DllName
= &ImportUnicodeString
.Buffer
[ImportUnicodeString
.MaximumLength
/ sizeof(WCHAR
)];
1386 Chars
= Length
>> 1;
1387 wcsncpy(DllName
, ImportUnicodeString
.Buffer
, Chars
);
1390 /* Add the DLL to the list */
1391 SmpSaveRegistryValue(&SmpKnownDllsList
, DllName
, DllValue
, TRUE
);
1396 SmpInitializeKnownDllsInternal(IN PUNICODE_STRING Directory
,
1397 IN PUNICODE_STRING Path
)
1399 HANDLE DirFileHandle
, DirHandle
, SectionHandle
, FileHandle
, LinkHandle
;
1400 UNICODE_STRING NtPath
, DestinationString
;
1401 OBJECT_ATTRIBUTES ObjectAttributes
;
1402 NTSTATUS Status
, Status1
;
1403 PLIST_ENTRY NextEntry
;
1404 PSMP_REGISTRY_VALUE RegEntry
;
1405 //ULONG_PTR ErrorParameters[3];
1406 //UNICODE_STRING ErrorResponse;
1407 IO_STATUS_BLOCK IoStatusBlock
;
1408 SECURITY_DESCRIPTOR_CONTROL OldFlag
= 0;
1409 USHORT ImageCharacteristics
;
1411 /* Initialize to NULL */
1412 DirFileHandle
= NULL
;
1414 NtPath
.Buffer
= NULL
;
1416 /* Create the \KnownDLLs directory */
1417 InitializeObjectAttributes(&ObjectAttributes
,
1419 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1421 SmpKnownDllsSecurityDescriptor
);
1422 Status
= NtCreateDirectoryObject(&DirHandle
,
1423 DIRECTORY_ALL_ACCESS
,
1425 if (!NT_SUCCESS(Status
))
1427 /* Handle failure */
1428 DPRINT1("SMSS: Unable to create %wZ directory - Status == %lx\n",
1433 /* Convert the path to native format */
1434 if (!RtlDosPathNameToNtPathName_U(Path
->Buffer
, &NtPath
, NULL
, NULL
))
1436 /* Fail if this didn't work */
1437 DPRINT1("SMSS: Unable to to convert %wZ to an Nt path\n", Path
);
1438 Status
= STATUS_OBJECT_NAME_INVALID
;
1442 /* Open the path that was specified, which should be a directory */
1443 InitializeObjectAttributes(&ObjectAttributes
,
1445 OBJ_CASE_INSENSITIVE
,
1448 Status
= NtOpenFile(&DirFileHandle
,
1449 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
1452 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1453 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
1454 if (!NT_SUCCESS(Status
))
1456 /* Fail if we couldn't open it */
1457 DPRINT1("SMSS: Unable to open a handle to the KnownDll directory (%wZ)"
1458 "- Status == %lx\n",
1465 /* Temporarily hack the SD to use a default DACL for this symbolic link */
1466 if (SmpPrimarySecurityDescriptor
)
1468 OldFlag
= SmpPrimarySecurityDescriptor
->Control
;
1469 SmpPrimarySecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1472 /* Create a symbolic link to the directory in the object manager */
1473 RtlInitUnicodeString(&DestinationString
, L
"KnownDllPath");
1474 InitializeObjectAttributes(&ObjectAttributes
,
1476 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
1478 SmpPrimarySecurityDescriptor
);
1479 Status
= NtCreateSymbolicLinkObject(&LinkHandle
,
1480 SYMBOLIC_LINK_ALL_ACCESS
,
1485 if (SmpPrimarySecurityDescriptor
) SmpPrimarySecurityDescriptor
->Control
= OldFlag
;
1487 /* Check if the symlink was created */
1488 if (!NT_SUCCESS(Status
))
1490 /* It wasn't, so bail out since the OS needs it to exist */
1491 DPRINT1("SMSS: Unable to create %wZ symbolic link - Status == %lx\n",
1492 &DestinationString
, Status
);
1497 /* We created it permanent, we can go ahead and close the handle now */
1498 Status1
= NtClose(LinkHandle
);
1499 ASSERT(NT_SUCCESS(Status1
));
1501 /* Now loop the known DLLs */
1502 NextEntry
= SmpKnownDllsList
.Flink
;
1503 while (NextEntry
!= &SmpKnownDllsList
)
1505 /* Get the entry and skip it if it's in the exluded list */
1506 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1507 DPRINT("Processing known DLL: %wZ-%wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
1508 if ((SmpFindRegistryValue(&SmpExcludeKnownDllsList
,
1509 RegEntry
->Name
.Buffer
)) ||
1510 (SmpFindRegistryValue(&SmpExcludeKnownDllsList
,
1511 RegEntry
->Value
.Buffer
)))
1516 /* Open the actual file */
1517 InitializeObjectAttributes(&ObjectAttributes
,
1519 OBJ_CASE_INSENSITIVE
,
1522 Status
= NtOpenFile(&FileHandle
,
1523 SYNCHRONIZE
| FILE_EXECUTE
,
1526 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1527 FILE_NON_DIRECTORY_FILE
|
1528 FILE_SYNCHRONOUS_IO_NONALERT
);
1529 if (!NT_SUCCESS(Status
)) break;
1532 Status
= LdrVerifyImageMatchesChecksum((HANDLE
)((ULONG_PTR
)FileHandle
| 1),
1533 SmpProcessModuleImports
,
1535 &ImageCharacteristics
);
1537 if (!NT_SUCCESS(Status
))
1539 /* Checksum failed, so don't even try going further -- kill SMSS */
1540 RtlInitUnicodeString(&ErrorResponse
,
1541 L
"Verification of a KnownDLL failed.");
1542 ErrorParameters
[0] = (ULONG
)&ErrorResponse
;
1543 ErrorParameters
[1] = Status
;
1544 ErrorParameters
[2] = (ULONG
)&RegEntry
->Value
;
1545 SmpTerminate(ErrorParameters
, 5, RTL_NUMBER_OF(ErrorParameters
));
1548 if (!(ImageCharacteristics
& IMAGE_FILE_DLL
))
1550 /* An invalid known DLL entry will also kill SMSS */
1551 RtlInitUnicodeString(&ErrorResponse
,
1552 L
"Non-DLL file included in KnownDLL list.");
1553 ErrorParameters
[0] = (ULONG
)&ErrorResponse
;
1554 ErrorParameters
[1] = STATUS_INVALID_IMPORT_OF_NON_DLL
;
1555 ErrorParameters
[2] = (ULONG
)&RegEntry
->Value
;
1556 SmpTerminate(ErrorParameters
, 5, RTL_NUMBER_OF(ErrorParameters
));
1560 /* Temporarily hack the SD to use a default DACL for this section */
1561 if (SmpLiberalSecurityDescriptor
)
1563 OldFlag
= SmpLiberalSecurityDescriptor
->Control
;
1564 SmpLiberalSecurityDescriptor
->Control
|= SE_DACL_DEFAULTED
;
1567 /* Create the section for this known DLL */
1568 InitializeObjectAttributes(&ObjectAttributes
,
1572 SmpLiberalSecurityDescriptor
)
1573 Status
= NtCreateSection(&SectionHandle
,
1582 if (SmpLiberalSecurityDescriptor
) SmpLiberalSecurityDescriptor
->Control
= OldFlag
;
1584 /* Check if we created the section okay */
1585 if (NT_SUCCESS(Status
))
1587 /* We can close it now, since it's marked permanent */
1588 Status1
= NtClose(SectionHandle
);
1589 ASSERT(NT_SUCCESS(Status1
));
1593 /* If we couldn't make it "known", that's fine and keep going */
1594 DPRINT1("SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n",
1595 &RegEntry
->Value
, Status
);
1598 /* Close the file since we can move on to the next one */
1599 Status1
= NtClose(FileHandle
);
1600 ASSERT(NT_SUCCESS(Status1
));
1602 /* Go to the next entry */
1603 NextEntry
= NextEntry
->Flink
;
1607 /* Close both handles and free the NT path buffer */
1610 Status1
= NtClose(DirHandle
);
1611 ASSERT(NT_SUCCESS(Status1
));
1615 Status1
= NtClose(DirFileHandle
);
1616 ASSERT(NT_SUCCESS(Status1
));
1618 if (NtPath
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath
.Buffer
);
1624 SmpInitializeKnownDlls(VOID
)
1627 PSMP_REGISTRY_VALUE RegEntry
;
1628 UNICODE_STRING DestinationString
;
1629 PLIST_ENTRY Head
, NextEntry
;
1631 /* Call the internal function */
1632 RtlInitUnicodeString(&DestinationString
, L
"\\KnownDlls");
1633 Status
= SmpInitializeKnownDllsInternal(&DestinationString
, &SmpKnownDllPath
);
1635 /* Wipe out the list regardless of success */
1636 Head
= &SmpKnownDllsList
;
1637 while (!IsListEmpty(Head
))
1639 /* Remove this entry */
1640 NextEntry
= RemoveHeadList(Head
);
1643 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
1644 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
1645 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
1646 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
1655 SmpCreateDynamicEnvironmentVariables(VOID
)
1658 SYSTEM_BASIC_INFORMATION BasicInfo
;
1659 SYSTEM_PROCESSOR_INFORMATION ProcessorInfo
;
1660 OBJECT_ATTRIBUTES ObjectAttributes
;
1661 UNICODE_STRING ValueName
, DestinationString
;
1662 HANDLE KeyHandle
, KeyHandle2
;
1665 WCHAR ValueBuffer
[512], ValueBuffer2
[512];
1666 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PVOID
)ValueBuffer
;
1667 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo2
= (PVOID
)ValueBuffer2
;
1669 /* Get system basic information -- we'll need the CPU count */
1670 Status
= NtQuerySystemInformation(SystemBasicInformation
,
1674 if (!NT_SUCCESS(Status
))
1676 /* Bail out on failure */
1677 DPRINT1("SMSS: Unable to query system basic information - %x\n", Status
);
1681 /* Get the processor information, we'll query a bunch of revision info */
1682 Status
= NtQuerySystemInformation(SystemProcessorInformation
,
1684 sizeof(ProcessorInfo
),
1686 if (!NT_SUCCESS(Status
))
1688 /* Bail out on failure */
1689 DPRINT1("SMSS: Unable to query system processor information - %x\n", Status
);
1693 /* We'll be writing all these environment variables over here */
1694 RtlInitUnicodeString(&DestinationString
,
1695 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
1696 L
"Control\\Session Manager\\Environment");
1697 InitializeObjectAttributes(&ObjectAttributes
,
1699 OBJ_CASE_INSENSITIVE
,
1702 Status
= NtOpenKey(&KeyHandle
, GENERIC_WRITE
, &ObjectAttributes
);
1703 if (!NT_SUCCESS(Status
))
1705 /* Bail out on failure */
1706 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString
, Status
);
1710 /* First let's write the OS variable */
1711 RtlInitUnicodeString(&ValueName
, L
"OS");
1712 DPRINT("Setting %wZ to %S\n", &ValueName
, L
"Windows_NT");
1713 Status
= NtSetValueKey(KeyHandle
,
1718 wcslen(L
"Windows_NT") * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1719 if (!NT_SUCCESS(Status
))
1721 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1722 &ValueName
, Status
);
1727 /* Next, let's write the CPU architecture variable */
1728 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_ARCHITECTURE");
1729 switch (ProcessorInfo
.ProcessorArchitecture
)
1731 /* Pick the correct string that matches the architecture */
1732 case PROCESSOR_ARCHITECTURE_INTEL
:
1736 case PROCESSOR_ARCHITECTURE_AMD64
:
1737 ArchName
= L
"AMD64";
1740 case PROCESSOR_ARCHITECTURE_IA64
:
1745 ArchName
= L
"Unknown";
1750 DPRINT("Setting %wZ to %S\n", &ValueName
, ArchName
);
1751 Status
= NtSetValueKey(KeyHandle
,
1756 wcslen(ArchName
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1757 if (!NT_SUCCESS(Status
))
1759 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1760 &ValueName
, Status
);
1765 /* And now let's write the processor level */
1766 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_LEVEL");
1767 swprintf(ValueBuffer
, L
"%u", ProcessorInfo
.ProcessorLevel
);
1768 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1769 Status
= NtSetValueKey(KeyHandle
,
1774 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1775 if (!NT_SUCCESS(Status
))
1777 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1778 &ValueName
, Status
);
1783 /* Now open the hardware CPU key */
1784 RtlInitUnicodeString(&DestinationString
,
1785 L
"\\Registry\\Machine\\Hardware\\Description\\System\\"
1786 L
"CentralProcessor\\0");
1787 InitializeObjectAttributes(&ObjectAttributes
,
1789 OBJ_CASE_INSENSITIVE
,
1792 Status
= NtOpenKey(&KeyHandle2
, KEY_READ
, &ObjectAttributes
);
1793 if (!NT_SUCCESS(Status
))
1795 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString
, Status
);
1800 /* So that we can read the identifier out of it... */
1801 RtlInitUnicodeString(&ValueName
, L
"Identifier");
1802 Status
= NtQueryValueKey(KeyHandle2
,
1804 KeyValuePartialInformation
,
1806 sizeof(ValueBuffer
),
1808 if (!NT_SUCCESS(Status
))
1810 NtClose(KeyHandle2
);
1812 DPRINT1("SMSS: Unable to read %wZ\\%wZ - %x\n",
1813 &DestinationString
, &ValueName
, Status
);
1817 /* As well as the vendor... */
1818 RtlInitUnicodeString(&ValueName
, L
"VendorIdentifier");
1819 Status
= NtQueryValueKey(KeyHandle2
,
1821 KeyValuePartialInformation
,
1823 sizeof(ValueBuffer2
),
1825 NtClose(KeyHandle2
);
1826 if (NT_SUCCESS(Status
))
1828 /* To combine it into a single string */
1829 swprintf((PWCHAR
)PartialInfo
->Data
+ wcslen((PWCHAR
)PartialInfo
->Data
),
1831 PartialInfo2
->Data
);
1834 /* So that we can set this as the PROCESSOR_IDENTIFIER variable */
1835 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_IDENTIFIER");
1836 DPRINT("Setting %wZ to %S\n", &ValueName
, PartialInfo
->Data
);
1837 Status
= NtSetValueKey(KeyHandle
,
1842 wcslen((PWCHAR
)PartialInfo
->Data
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1843 if (!NT_SUCCESS(Status
))
1845 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1846 &ValueName
, Status
);
1851 /* Now let's get the processor architecture */
1852 RtlInitUnicodeString(&ValueName
, L
"PROCESSOR_REVISION");
1853 switch (ProcessorInfo
.ProcessorArchitecture
)
1855 /* Check if this is an older Intel CPU */
1856 case PROCESSOR_ARCHITECTURE_INTEL
:
1857 if ((ProcessorInfo
.ProcessorRevision
>> 8) == 0xFF)
1859 /* These guys used a revision + stepping, so get the rev only */
1860 swprintf(ValueBuffer
, L
"%02x", ProcessorInfo
.ProcessorRevision
& 0xFF);
1861 _wcsupr(ValueBuffer
);
1865 /* Modern Intel, as well as 64-bit CPUs use a revision without stepping */
1866 case PROCESSOR_ARCHITECTURE_IA64
:
1867 case PROCESSOR_ARCHITECTURE_AMD64
:
1868 swprintf(ValueBuffer
, L
"%04x", ProcessorInfo
.ProcessorRevision
);
1871 /* And anything else we'll just read the whole revision identifier */
1873 swprintf(ValueBuffer
, L
"%u", ProcessorInfo
.ProcessorRevision
);
1877 /* Write the revision to the registry */
1878 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1879 Status
= NtSetValueKey(KeyHandle
,
1884 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1885 if (!NT_SUCCESS(Status
))
1887 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1888 &ValueName
, Status
);
1893 /* And finally, write the number of CPUs */
1894 RtlInitUnicodeString(&ValueName
, L
"NUMBER_OF_PROCESSORS");
1895 swprintf(ValueBuffer
, L
"%u", BasicInfo
.NumberOfProcessors
);
1896 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1897 Status
= NtSetValueKey(KeyHandle
,
1902 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1903 if (!NT_SUCCESS(Status
))
1905 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1906 &ValueName
, Status
);
1911 /* Now we need to write the safeboot option key in a different format */
1912 RtlInitUnicodeString(&DestinationString
,
1913 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
1914 L
"Control\\Safeboot\\Option");
1915 InitializeObjectAttributes(&ObjectAttributes
,
1917 OBJ_CASE_INSENSITIVE
,
1920 Status
= NtOpenKey(&KeyHandle2
, KEY_ALL_ACCESS
, &ObjectAttributes
);
1921 if (NT_SUCCESS(Status
))
1923 /* This was indeed a safeboot, so check what kind of safeboot it was */
1924 RtlInitUnicodeString(&ValueName
, L
"OptionValue");
1925 Status
= NtQueryValueKey(KeyHandle2
,
1927 KeyValuePartialInformation
,
1929 sizeof(ValueBuffer
),
1931 NtClose(KeyHandle2
);
1932 if (NT_SUCCESS(Status
))
1934 /* Convert from the integer value to the correct specifier */
1935 RtlInitUnicodeString(&ValueName
, L
"SAFEBOOT_OPTION");
1936 switch (*(PULONG
)PartialInfo
->Data
)
1939 wcscpy(ValueBuffer
, L
"MINIMAL");
1942 wcscpy(ValueBuffer
, L
"NETWORK");
1945 wcscpy(ValueBuffer
, L
"DSREPAIR");
1949 /* And write it in the environment! */
1950 DPRINT("Setting %wZ to %S\n", &ValueName
, ValueBuffer
);
1951 Status
= NtSetValueKey(KeyHandle
,
1956 wcslen(ValueBuffer
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
1957 if (!NT_SUCCESS(Status
))
1959 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1960 &ValueName
, Status
);
1967 DPRINT1("SMSS: Failed querying safeboot option = %x\n", Status
);
1971 /* We are all done now */
1973 return STATUS_SUCCESS
;
1978 SmpProcessFileRenames(VOID
)
1980 BOOLEAN OldState
, HavePrivilege
= FALSE
;
1982 HANDLE FileHandle
, OtherFileHandle
;
1983 FILE_INFORMATION_CLASS InformationClass
;
1984 OBJECT_ATTRIBUTES ObjectAttributes
;
1985 IO_STATUS_BLOCK IoStatusBlock
;
1986 UNICODE_STRING FileString
;
1987 FILE_BASIC_INFORMATION BasicInfo
;
1988 FILE_DISPOSITION_INFORMATION DeleteInformation
;
1989 PFILE_RENAME_INFORMATION Buffer
;
1990 PLIST_ENTRY Head
, NextEntry
;
1991 PSMP_REGISTRY_VALUE RegEntry
;
1993 ULONG ValueLength
, Length
;
1995 /* Give us access to restore any files we want */
1996 Status
= RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, TRUE
, FALSE
, &OldState
);
1997 if (NT_SUCCESS(Status
)) HavePrivilege
= TRUE
;
1999 /* Process pending files to rename */
2000 Head
= &SmpFileRenameList
;
2001 while (!IsListEmpty(Head
))
2003 /* Get this entry */
2004 NextEntry
= RemoveHeadList(Head
);
2005 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2006 DPRINT1("Processing PFRO: %wZ/%wZ\n", &RegEntry
->Value
, &RegEntry
->Name
);
2008 /* Skip past the '@' marker */
2009 if (!(RegEntry
->Value
.Length
) && (*RegEntry
->Name
.Buffer
== L
'@'))
2011 RegEntry
->Name
.Length
-= sizeof(UNICODE_NULL
);
2012 RegEntry
->Name
.Buffer
++;
2015 /* Open the file for delete access */
2016 InitializeObjectAttributes(&ObjectAttributes
,
2018 OBJ_CASE_INSENSITIVE
,
2021 Status
= NtOpenFile(&OtherFileHandle
,
2022 DELETE
| SYNCHRONIZE
,
2025 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2026 FILE_SYNCHRONOUS_IO_NONALERT
);
2027 if (!NT_SUCCESS(Status
)) goto Quickie
;
2029 /* Check if it's a rename or just a delete */
2030 ValueLength
= RegEntry
->Value
.Length
;
2033 /* Just a delete, set up the class, length and buffer */
2034 InformationClass
= FileDispositionInformation
;
2035 Length
= sizeof(DeleteInformation
);
2036 Buffer
= (PFILE_RENAME_INFORMATION
)&DeleteInformation
;
2038 /* Set the delete disposition */
2039 DeleteInformation
.DeleteFile
= TRUE
;
2043 /* This is a rename, setup the class and length */
2044 InformationClass
= FileRenameInformation
;
2045 Length
= ValueLength
+ sizeof(FILE_RENAME_INFORMATION
);
2047 /* Skip past the special markers */
2048 FileName
= RegEntry
->Value
.Buffer
;
2049 if ((*FileName
== L
'!') || (*FileName
== L
'@'))
2052 Length
-= sizeof(UNICODE_NULL
);
2055 /* Now allocate the buffer for the rename information */
2056 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag
, Length
);
2059 /* Setup the buffer to point to the filename, and copy it */
2060 Buffer
->RootDirectory
= NULL
;
2061 Buffer
->FileNameLength
= Length
- sizeof(FILE_RENAME_INFORMATION
);
2062 Buffer
->ReplaceIfExists
= FileName
!= RegEntry
->Value
.Buffer
;
2063 RtlCopyMemory(Buffer
->FileName
, FileName
, Buffer
->FileNameLength
);
2068 Status
= STATUS_NO_MEMORY
;
2072 /* Check if everything is okay till here */
2073 if (NT_SUCCESS(Status
))
2075 /* Now either rename or delete the file as requested */
2076 Status
= NtSetInformationFile(OtherFileHandle
,
2082 /* Check if we seem to have failed because the file was readonly */
2083 if ((NT_SUCCESS(Status
) &&
2084 (InformationClass
== FileRenameInformation
) &&
2085 (Status
== STATUS_OBJECT_NAME_COLLISION
) &&
2086 (Buffer
->ReplaceIfExists
)))
2088 /* Open the file for write attribute access this time... */
2089 DPRINT1("\nSMSS: %wZ => %wZ failed - Status == %x, Possible readonly target\n",
2092 STATUS_OBJECT_NAME_COLLISION
);
2093 FileString
.Length
= RegEntry
->Value
.Length
- sizeof(WCHAR
);
2094 FileString
.MaximumLength
= RegEntry
->Value
.MaximumLength
- sizeof(WCHAR
);
2095 FileString
.Buffer
= FileName
;
2096 InitializeObjectAttributes(&ObjectAttributes
,
2098 OBJ_CASE_INSENSITIVE
,
2101 Status
= NtOpenFile(&FileHandle
,
2102 FILE_WRITE_ATTRIBUTES
| SYNCHRONIZE
,
2105 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2106 FILE_SYNCHRONOUS_IO_NONALERT
);
2107 if (!NT_SUCCESS(Status
))
2109 /* That didn't work, so bail out */
2110 DPRINT1(" SMSS: Open Existing file Failed - Status == %x\n",
2115 /* Now remove the read-only attribute from the file */
2116 DPRINT1(" SMSS: Open Existing Success\n");
2117 RtlZeroMemory(&BasicInfo
, sizeof(BasicInfo
));
2118 BasicInfo
.FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
2119 Status
= NtSetInformationFile(FileHandle
,
2123 FileBasicInformation
);
2124 NtClose(FileHandle
);
2125 if (!NT_SUCCESS(Status
))
2127 /* That didn't work, bail out */
2128 DPRINT1(" SMSS: Set To NORMAL Failed - Status == %x\n",
2133 /* Now that the file is no longer read-only, delete! */
2134 DPRINT1(" SMSS: Set To NORMAL OK\n");
2135 Status
= NtSetInformationFile(OtherFileHandle
,
2139 FileRenameInformation
);
2140 if (!NT_SUCCESS(Status
))
2142 /* That failed too! */
2143 DPRINT1(" SMSS: Re-Rename Failed - Status == %x\n",
2149 DPRINT1(" SMSS: Re-Rename Worked OK\n");
2156 /* Close the file handle and check the operation result */
2157 NtClose(OtherFileHandle
);
2159 if (!NT_SUCCESS(Status
))
2161 /* We totally failed */
2162 DPRINT1("SMSS: %wZ => %wZ failed - Status == %x\n",
2163 &RegEntry
->Name
, &RegEntry
->Value
, Status
);
2165 else if (RegEntry
->Value
.Length
)
2167 /* We succeed with a rename */
2168 DPRINT1("SMSS: %wZ (renamed to) %wZ\n", &RegEntry
->Name
, &RegEntry
->Value
);
2172 /* We suceeded with a delete */
2173 DPRINT1("SMSS: %wZ (deleted)\n", &RegEntry
->Name
);
2176 /* Now free this entry and keep going */
2177 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2178 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2179 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2182 /* Put back the restore privilege if we had requested it, and return */
2183 if (HavePrivilege
) RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, FALSE
, FALSE
, &OldState
);
2189 SmpLoadDataFromRegistry(OUT PUNICODE_STRING InitialCommand
)
2192 PLIST_ENTRY Head
, NextEntry
;
2193 PSMP_REGISTRY_VALUE RegEntry
;
2194 PVOID OriginalEnvironment
;
2195 ULONG MuSessionId
= 0;
2196 OBJECT_ATTRIBUTES ObjectAttributes
;
2198 UNICODE_STRING DestinationString
;
2200 /* Initialize the keywords we'll be looking for */
2201 RtlInitUnicodeString(&SmpDebugKeyword
, L
"debug");
2202 RtlInitUnicodeString(&SmpASyncKeyword
, L
"async");
2203 RtlInitUnicodeString(&SmpAutoChkKeyword
, L
"autocheck");
2205 /* Initialize all the registry-associated list heads */
2206 InitializeListHead(&SmpBootExecuteList
);
2207 InitializeListHead(&SmpSetupExecuteList
);
2208 InitializeListHead(&SmpPagingFileList
);
2209 InitializeListHead(&SmpDosDevicesList
);
2210 InitializeListHead(&SmpFileRenameList
);
2211 InitializeListHead(&SmpKnownDllsList
);
2212 InitializeListHead(&SmpExcludeKnownDllsList
);
2213 InitializeListHead(&SmpSubSystemList
);
2214 InitializeListHead(&SmpSubSystemsToLoad
);
2215 InitializeListHead(&SmpSubSystemsToDefer
);
2216 InitializeListHead(&SmpExecuteList
);
2217 SmpPagingFileInitialize();
2219 /* Initialize the SMSS environment */
2220 Status
= RtlCreateEnvironment(TRUE
, &SmpDefaultEnvironment
);
2221 if (!NT_SUCCESS(Status
))
2223 /* Fail if there was a problem */
2224 DPRINT1("SMSS: Unable to allocate default environment - Status == %X\n",
2226 SMSS_CHECKPOINT(RtlCreateEnvironment
, Status
);
2230 /* Check if we were booted in PE mode (LiveCD should have this) */
2231 RtlInitUnicodeString(&DestinationString
,
2232 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
2233 L
"Control\\MiniNT");
2234 InitializeObjectAttributes(&ObjectAttributes
,
2236 OBJ_CASE_INSENSITIVE
,
2239 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
2240 if (NT_SUCCESS(Status
))
2242 /* If the key exists, we were */
2247 /* Print out if this is the case */
2248 if (MiniNTBoot
) DPRINT1("SMSS: !!! MiniNT Boot !!!\n");
2250 /* Open the environment key to see if we are booted in safe mode */
2251 RtlInitUnicodeString(&DestinationString
,
2252 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
2253 L
"Control\\Session Manager\\Environment");
2254 InitializeObjectAttributes(&ObjectAttributes
,
2256 OBJ_CASE_INSENSITIVE
,
2259 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
2260 if (NT_SUCCESS(Status
))
2262 /* Delete the value if we found it */
2263 RtlInitUnicodeString(&DestinationString
, L
"SAFEBOOT_OPTION");
2264 NtDeleteValueKey(KeyHandle
, &DestinationString
);
2268 /* Switch environments, then query the registry for all needed settings */
2269 OriginalEnvironment
= NtCurrentPeb()->ProcessParameters
->Environment
;
2270 NtCurrentPeb()->ProcessParameters
->Environment
= SmpDefaultEnvironment
;
2271 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
2273 SmpRegistryConfigurationTable
,
2276 SmpDefaultEnvironment
= NtCurrentPeb()->ProcessParameters
->Environment
;
2277 NtCurrentPeb()->ProcessParameters
->Environment
= OriginalEnvironment
;
2278 if (!NT_SUCCESS(Status
))
2280 /* We failed somewhere in registry initialization, which is bad... */
2281 DPRINT1("SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status
);
2282 SMSS_CHECKPOINT(RtlQueryRegistryValues
, Status
);
2286 /* Now we can start acting on the registry settings. First to DOS devices */
2287 Status
= SmpInitializeDosDevices();
2288 if (!NT_SUCCESS(Status
))
2291 DPRINT1("SMSS: Unable to initialize DosDevices configuration - Status == %lx\n",
2293 SMSS_CHECKPOINT(SmpInitializeDosDevices
, Status
);
2297 /* Next create the session directory... */
2298 RtlInitUnicodeString(&DestinationString
, L
"\\Sessions");
2299 InitializeObjectAttributes(&ObjectAttributes
,
2301 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_PERMANENT
,
2303 SmpPrimarySecurityDescriptor
);
2304 Status
= NtCreateDirectoryObject(&SmpSessionsObjectDirectory
,
2305 DIRECTORY_ALL_ACCESS
,
2307 if (!NT_SUCCESS(Status
))
2310 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
2311 &DestinationString
, Status
);
2312 SMSS_CHECKPOINT(NtCreateDirectoryObject
, Status
);
2316 /* Next loop all the boot execute binaries */
2317 Head
= &SmpBootExecuteList
;
2318 while (!IsListEmpty(Head
))
2320 /* Remove each one from the list */
2321 NextEntry
= RemoveHeadList(Head
);
2324 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2325 SmpExecuteCommand(&RegEntry
->Name
, 0, NULL
, 0);
2328 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2329 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2330 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2333 /* Now do any pending file rename operations... */
2334 if (!MiniNTBoot
) SmpProcessFileRenames();
2336 /* And initialize known DLLs... */
2337 Status
= SmpInitializeKnownDlls();
2338 if (!NT_SUCCESS(Status
))
2340 /* Fail if that didn't work */
2341 DPRINT1("SMSS: Unable to initialize KnownDll configuration - Status == %lx\n",
2343 SMSS_CHECKPOINT(SmpInitializeKnownDlls
, Status
);
2347 /* Loop every page file */
2348 Head
= &SmpPagingFileList
;
2349 while (!IsListEmpty(Head
))
2351 /* Remove each one from the list */
2352 NextEntry
= RemoveHeadList(Head
);
2354 /* Create the descriptor for it */
2355 RegEntry
= CONTAINING_RECORD(NextEntry
, SMP_REGISTRY_VALUE
, Entry
);
2356 SmpCreatePagingFileDescriptor(&RegEntry
->Name
);
2359 if (RegEntry
->AnsiValue
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->AnsiValue
);
2360 if (RegEntry
->Value
.Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
->Value
.Buffer
);
2361 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry
);
2364 /* Now create all the paging files for the descriptors that we have */
2365 SmpCreatePagingFiles();
2367 /* Tell Cm it's now safe to fully enable write access to the registry */
2368 NtInitializeRegistry(CM_BOOT_FLAG_SMSS
);
2370 /* Create all the system-based environment variables for later inheriting */
2371 Status
= SmpCreateDynamicEnvironmentVariables();
2372 if (!NT_SUCCESS(Status
))
2374 /* Handle failure */
2375 SMSS_CHECKPOINT(SmpCreateDynamicEnvironmentVariables
, Status
);
2379 /* And finally load all the subsytems for our first session! */
2380 Status
= SmpLoadSubSystemsForMuSession(&MuSessionId
,
2381 &SmpWindowsSubSysProcessId
,
2383 ASSERT(MuSessionId
== 0);
2384 if (!NT_SUCCESS(Status
)) SMSS_CHECKPOINT(SmpLoadSubSystemsForMuSession
, Status
);
2390 SmpInit(IN PUNICODE_STRING InitialCommand
,
2391 OUT PHANDLE ProcessHandle
)
2393 NTSTATUS Status
, Status2
;
2394 OBJECT_ATTRIBUTES ObjectAttributes
;
2395 UNICODE_STRING PortName
, EventName
;
2396 HANDLE EventHandle
, PortHandle
;
2397 ULONG HardErrorMode
;
2399 /* Create the SMSS Heap */
2400 SmBaseTag
= RtlCreateTagHeap(RtlGetProcessHeap(),
2404 SmpHeap
= RtlGetProcessHeap();
2406 /* Enable hard errors */
2407 HardErrorMode
= TRUE
;
2408 NtSetInformationProcess(NtCurrentProcess(),
2409 ProcessDefaultHardErrorMode
,
2411 sizeof(HardErrorMode
));
2413 /* Initialize the subsystem list and the session list, plus their locks */
2414 RtlInitializeCriticalSection(&SmpKnownSubSysLock
);
2415 InitializeListHead(&SmpKnownSubSysHead
);
2416 RtlInitializeCriticalSection(&SmpSessionListLock
);
2417 InitializeListHead(&SmpSessionListHead
);
2419 /* Initialize the process list */
2420 InitializeListHead(&NativeProcessList
);
2422 /* Initialize session parameters */
2423 SmpNextSessionId
= 1;
2424 SmpNextSessionIdScanMode
= 0;
2425 SmpDbgSsLoaded
= FALSE
;
2427 /* Create the initial security descriptors */
2428 Status
= SmpCreateSecurityDescriptors(TRUE
);
2429 if (!NT_SUCCESS(Status
))
2432 SMSS_CHECKPOINT(SmpCreateSecurityDescriptors
, Status
);
2436 /* Initialize subsystem names */
2437 RtlInitUnicodeString(&SmpSubsystemName
, L
"NT-Session Manager");
2438 RtlInitUnicodeString(&PosixName
, L
"POSIX");
2439 RtlInitUnicodeString(&Os2Name
, L
"OS2");
2441 /* Create the SM API Port */
2442 RtlInitUnicodeString(&PortName
, L
"\\SmApiPort2");
2443 InitializeObjectAttributes(&ObjectAttributes
, &PortName
, 0, NULL
, NULL
);
2444 Status
= NtCreatePort(&PortHandle
,
2446 sizeof(SB_CONNECTION_INFO
),
2448 sizeof(SB_API_MSG
) * 32);
2449 ASSERT(NT_SUCCESS(Status
));
2450 SmpDebugPort
= PortHandle
;
2452 /* Create two SM API threads */
2453 Status
= RtlCreateUserThread(NtCurrentProcess(),
2463 ASSERT(NT_SUCCESS(Status
));
2464 Status
= RtlCreateUserThread(NtCurrentProcess(),
2474 ASSERT(NT_SUCCESS(Status
));
2476 /* Create the write event that autochk can set after running */
2477 RtlInitUnicodeString(&EventName
, L
"\\Device\\VolumesSafeForWriteAccess");
2478 InitializeObjectAttributes(&ObjectAttributes
,
2483 Status2
= NtCreateEvent(&EventHandle
,
2488 if (!NT_SUCCESS(Status2
))
2490 /* Should never really fail */
2491 DPRINT1("SMSS: Unable to create %wZ event - Status == %lx\n",
2492 &EventName
, Status2
);
2493 ASSERT(NT_SUCCESS(Status2
));
2496 /* Now initialize everything else based on the registry parameters */
2497 Status
= SmpLoadDataFromRegistry(InitialCommand
);
2498 if (NT_SUCCESS(Status
))
2500 /* Autochk should've run now. Set the event and save the CSRSS handle */
2501 *ProcessHandle
= SmpWindowsSubSysProcess
;
2502 NtSetEvent(EventHandle
, 0);
2503 NtClose(EventHandle
);