* Sync up to trunk head (r60691).
[reactos.git] / base / system / smss / sminit.c
1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "smss.h"
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
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;
22
23 PVOID SmpHeap;
24 ULONG SmBaseTag;
25 HANDLE SmpDebugPort, SmpDosDevicesObjectDirectory;
26 PWCHAR SmpDefaultEnvironment, SmpDefaultLibPathBuffer;
27 UNICODE_STRING SmpKnownDllPath, SmpDefaultLibPath;
28 ULONG SmpCalledConfigEnv;
29
30 ULONG SmpInitProgressByLine;
31 NTSTATUS SmpInitReturnStatus;
32 PVOID SmpInitLastCall;
33
34 SECURITY_DESCRIPTOR SmpPrimarySDBody, SmpLiberalSDBody, SmpKnownDllsSDBody;
35 SECURITY_DESCRIPTOR SmpApiPortSDBody;
36 PISECURITY_DESCRIPTOR SmpPrimarySecurityDescriptor, SmpLiberalSecurityDescriptor;
37 PISECURITY_DESCRIPTOR SmpKnownDllsSecurityDescriptor, SmpApiPortSecurityDescriptor;
38
39 ULONG SmpAllowProtectedRenames, SmpProtectionMode = 1;
40 BOOLEAN MiniNTBoot;
41
42 #define SMSS_CHECKPOINT(x, y) \
43 { \
44 SmpInitProgressByLine = __LINE__; \
45 SmpInitReturnStatus = (y); \
46 SmpInitLastCall = (x); \
47 }
48
49 /* REGISTRY CONFIGURATION *****************************************************/
50
51 NTSTATUS
52 NTAPI
53 SmpSaveRegistryValue(IN PLIST_ENTRY ListAddress,
54 IN PWSTR Name,
55 IN PWCHAR Value,
56 IN BOOLEAN Flags)
57 {
58 PSMP_REGISTRY_VALUE RegEntry;
59 UNICODE_STRING NameString, ValueString;
60 ANSI_STRING AnsiValueString;
61 PLIST_ENTRY NextEntry;
62
63 /* Convert to unicode strings */
64 RtlInitUnicodeString(&NameString, Name);
65 RtlInitUnicodeString(&ValueString, Value);
66
67 /* In case this is the first value, initialize a new list/structure */
68 RegEntry = NULL;
69
70 /* Check if we should do a duplicate check */
71 if (Flags)
72 {
73 /* Loop the current list */
74 NextEntry = ListAddress->Flink;
75 while (NextEntry != ListAddress)
76 {
77 /* Get each entry */
78 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
79
80 /* Check if the value name matches */
81 if (!RtlCompareUnicodeString(&RegEntry->Name, &NameString, TRUE))
82 {
83 /* Check if the value is the exact same thing */
84 if (!RtlCompareUnicodeString(&RegEntry->Value, &ValueString, TRUE))
85 {
86 /* Fail -- the same setting is being set twice */
87 return STATUS_OBJECT_NAME_EXISTS;
88 }
89
90 /* We found the list, and this isn't a duplicate value */
91 break;
92 }
93
94 /* This wasn't a match, keep going */
95 NextEntry = NextEntry->Flink;
96 RegEntry = NULL;
97 }
98 }
99
100 /* Are we adding on, or creating a new entry */
101 if (!RegEntry)
102 {
103 /* A new entry -- allocate it */
104 RegEntry = RtlAllocateHeap(RtlGetProcessHeap(),
105 SmBaseTag,
106 NameString.MaximumLength +
107 sizeof(SMP_REGISTRY_VALUE));
108 if (!RegEntry) return STATUS_NO_MEMORY;
109
110 /* Initialize the list and set all values to NULL */
111 InitializeListHead(&RegEntry->Entry);
112 RegEntry->AnsiValue = NULL;
113 RegEntry->Value.Buffer = NULL;
114
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,
120 NameString.Buffer,
121 NameString.MaximumLength);
122
123 /* Add this entry into the list */
124 InsertTailList(ListAddress, &RegEntry->Entry);
125 }
126
127 /* Did we have an old value buffer? */
128 if (RegEntry->Value.Buffer)
129 {
130 /* Free it */
131 ASSERT(RegEntry->Value.Length != 0);
132 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
133 }
134
135 /* Is there no value associated? */
136 if (!Value)
137 {
138 /* We're done here */
139 RtlInitUnicodeString(&RegEntry->Value, NULL);
140 return STATUS_SUCCESS;
141 }
142
143 /* There is a value, so allocate a buffer for it */
144 RegEntry->Value.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
145 SmBaseTag,
146 ValueString.MaximumLength);
147 if (!RegEntry->Value.Buffer)
148 {
149 /* Out of memory, undo */
150 RemoveEntryList(&RegEntry->Entry);
151 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
152 return STATUS_NO_MEMORY;
153 }
154
155 /* Copy the value into the entry */
156 RegEntry->Value.Length = ValueString.Length;
157 RegEntry->Value.MaximumLength = ValueString.MaximumLength;
158 RtlCopyMemory(RegEntry->Value.Buffer,
159 ValueString.Buffer,
160 ValueString.MaximumLength);
161
162 /* Now allocate memory for an ANSI copy of it */
163 RegEntry->AnsiValue = RtlAllocateHeap(RtlGetProcessHeap(),
164 SmBaseTag,
165 (ValueString.Length / sizeof(WCHAR)) +
166 sizeof(ANSI_NULL));
167 if (!RegEntry->AnsiValue)
168 {
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;
174 }
175
176 /* Convert the Unicode value string and return success */
177 RtlInitEmptyAnsiString(&AnsiValueString,
178 RegEntry->AnsiValue,
179 (ValueString.Length / sizeof(WCHAR)) +
180 sizeof(ANSI_NULL));
181 RtlUnicodeStringToAnsiString(&AnsiValueString, &ValueString, FALSE);
182 return STATUS_SUCCESS;
183 }
184
185 PSMP_REGISTRY_VALUE
186 NTAPI
187 SmpFindRegistryValue(IN PLIST_ENTRY List,
188 IN PWSTR ValueName)
189 {
190 PSMP_REGISTRY_VALUE RegEntry;
191 UNICODE_STRING ValueString;
192 PLIST_ENTRY NextEntry;
193
194 /* Initialize the value name sting */
195 RtlInitUnicodeString(&ValueString, ValueName);
196
197 /* Loop the list */
198 NextEntry = List->Flink;
199 while (NextEntry != List)
200 {
201 /* Get each entry */
202 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
203
204 /* Check if the value name matches */
205 if (!RtlCompareUnicodeString(&RegEntry->Name, &ValueString, TRUE)) break;
206
207 /* It doesn't, move on */
208 NextEntry = NextEntry->Flink;
209 }
210
211 /* If we looped back, return NULL, otherwise return the entry we found */
212 if (NextEntry == List) RegEntry = NULL;
213 return RegEntry;
214 }
215
216 NTSTATUS
217 NTAPI
218 SmpConfigureProtectionMode(IN PWSTR ValueName,
219 IN ULONG ValueType,
220 IN PVOID ValueData,
221 IN ULONG ValueLength,
222 IN PVOID Context,
223 IN PVOID EntryContext)
224 {
225 /* Make sure the value is valid */
226 if (ValueLength == sizeof(ULONG))
227 {
228 /* Read it */
229 SmpProtectionMode = *(PULONG)ValueData;
230 }
231 else
232 {
233 /* Default is to protect stuff */
234 SmpProtectionMode = 1;
235 }
236
237 /* Recreate the security descriptors to take into account security mode */
238 SmpCreateSecurityDescriptors(FALSE);
239 DPRINT("SmpProtectionMode: %lu\n", SmpProtectionMode);
240 return STATUS_SUCCESS;
241 }
242
243 NTSTATUS
244 NTAPI
245 SmpConfigureAllowProtectedRenames(IN PWSTR ValueName,
246 IN ULONG ValueType,
247 IN PVOID ValueData,
248 IN ULONG ValueLength,
249 IN PVOID Context,
250 IN PVOID EntryContext)
251 {
252 /* Make sure the value is valid */
253 if (ValueLength == sizeof(ULONG))
254 {
255 /* Read it */
256 SmpAllowProtectedRenames = *(PULONG)ValueData;
257 }
258 else
259 {
260 /* Default is to not allow protected renames */
261 SmpAllowProtectedRenames = 0;
262 }
263
264 DPRINT("SmpAllowProtectedRenames: %lu\n", SmpAllowProtectedRenames);
265 return STATUS_SUCCESS;
266 }
267
268 NTSTATUS
269 NTAPI
270 SmpConfigureObjectDirectories(IN PWSTR ValueName,
271 IN ULONG ValueType,
272 IN PVOID ValueData,
273 IN ULONG ValueLength,
274 IN PVOID Context,
275 IN PVOID EntryContext)
276 {
277 PISECURITY_DESCRIPTOR SecDescriptor;
278 NTSTATUS Status;
279 OBJECT_ATTRIBUTES ObjectAttributes;
280 HANDLE DirHandle;
281 UNICODE_STRING RpcString, WindowsString, SearchString;
282 PWCHAR SourceString = ValueData;
283
284 /* Initialize the two strings we will be looking for */
285 RtlInitUnicodeString(&RpcString, L"\\RPC Control");
286 RtlInitUnicodeString(&WindowsString, L"\\Windows");
287
288 /* Loop the registry data we received */
289 while (*SourceString)
290 {
291 /* Assume primary SD for most objects */
292 RtlInitUnicodeString(&SearchString, SourceString);
293 SecDescriptor = SmpPrimarySecurityDescriptor;
294
295 /* But for these two always set the liberal descriptor */
296 if ((RtlEqualUnicodeString(&SearchString, &RpcString, TRUE)) ||
297 (RtlEqualUnicodeString(&SearchString, &WindowsString, TRUE)))
298 {
299 SecDescriptor = SmpLiberalSecurityDescriptor;
300 }
301
302 /* Create the requested directory with the requested descriptor */
303 InitializeObjectAttributes(&ObjectAttributes,
304 &SearchString,
305 OBJ_CASE_INSENSITIVE |
306 OBJ_OPENIF |
307 OBJ_PERMANENT,
308 NULL,
309 SecDescriptor);
310 DPRINT("Creating: %wZ directory\n", &SearchString);
311 Status = NtCreateDirectoryObject(&DirHandle,
312 DIRECTORY_ALL_ACCESS,
313 &ObjectAttributes);
314 if (!NT_SUCCESS(Status))
315 {
316 /* Failure case */
317 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
318 &SearchString, Status);
319 }
320 else
321 {
322 /* It worked, now close the handle */
323 NtClose(DirHandle);
324 }
325
326 /* Move to the next requested object */
327 while (*SourceString++);
328 }
329
330 /* All done */
331 return STATUS_SUCCESS;
332 }
333
334 NTSTATUS
335 NTAPI
336 SmpConfigureMemoryMgmt(IN PWSTR ValueName,
337 IN ULONG ValueType,
338 IN PVOID ValueData,
339 IN ULONG ValueLength,
340 IN PVOID Context,
341 IN PVOID EntryContext)
342 {
343 /* Save this is into a list */
344 return SmpSaveRegistryValue(EntryContext, ValueData, NULL, TRUE);
345 }
346
347 NTSTATUS
348 NTAPI
349 SmpConfigureFileRenames(IN PWSTR ValueName,
350 IN ULONG ValueType,
351 IN PVOID ValueData,
352 IN ULONG ValueLength,
353 IN PVOID Context,
354 IN PVOID EntryContext)
355 {
356 NTSTATUS Status;
357 static PWCHAR Canary;
358
359 /* Check if this is the second call */
360 if (Canary)
361 {
362 /* Save the data into the list */
363 DPRINT1("Renamed file: %S-%S\n", Canary, ValueData);
364 Status = SmpSaveRegistryValue(EntryContext, Canary, ValueData, FALSE);
365 Canary = 0;
366 }
367 else
368 {
369 /* This it the first call, do nothing until we get the second call */
370 Canary = ValueData;
371 Status = STATUS_SUCCESS;
372 }
373
374 /* Return the status */
375 return Status;
376 }
377
378 NTSTATUS
379 NTAPI
380 SmpConfigureExcludeKnownDlls(IN PWSTR ValueName,
381 IN ULONG ValueType,
382 IN PVOID ValueData,
383 IN ULONG ValueLength,
384 IN PVOID Context,
385 IN PVOID EntryContext)
386 {
387 PWCHAR DllName;
388 NTSTATUS Status;
389
390 /* Make sure the value type is valid */
391 if ((ValueType == REG_MULTI_SZ) || (ValueType == REG_SZ))
392 {
393 /* Keep going for each DLL in the list */
394 DllName = ValueData;
395 while (*DllName)
396 {
397 /* Add this to the linked list */
398 DPRINT("Excluded DLL: %S\n", DllName);
399 Status = SmpSaveRegistryValue(EntryContext, DllName, NULL, TRUE);
400
401 /* Bail out on failure or if only one DLL name was present */
402 if (!(NT_SUCCESS(Status)) || (ValueType == REG_SZ)) return Status;
403
404 /* Otherwise, move to the next DLL name */
405 while (*DllName++);
406 }
407 }
408
409 /* All done */
410 return STATUS_SUCCESS;
411 }
412
413 NTSTATUS
414 NTAPI
415 SmpConfigureDosDevices(IN PWSTR ValueName,
416 IN ULONG ValueType,
417 IN PVOID ValueData,
418 IN ULONG ValueLength,
419 IN PVOID Context,
420 IN PVOID EntryContext)
421 {
422 /* Save into linked list */
423 return SmpSaveRegistryValue(EntryContext, ValueName, ValueData, TRUE);
424 }
425
426 NTSTATUS
427 NTAPI
428 SmpInitializeKnownDllPath(IN PUNICODE_STRING DllPath,
429 IN PWCHAR Buffer,
430 IN ULONG Length)
431 {
432 NTSTATUS Status;
433
434 /* Allocate the buffer */
435 DllPath->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag, Length);
436 if (DllPath->Buffer)
437 {
438 /* Fill out the rest of the string */
439 DllPath->MaximumLength = (USHORT)Length;
440 DllPath->Length = (USHORT)Length - sizeof(UNICODE_NULL);
441
442 /* Copy the actual path and return success */
443 RtlCopyMemory(DllPath->Buffer, Buffer, Length);
444 Status = STATUS_SUCCESS;
445 }
446 else
447 {
448 /* Fail with out of memory code */
449 Status = STATUS_NO_MEMORY;
450 }
451
452 /* Return result */
453 return Status;
454 }
455
456 NTSTATUS
457 NTAPI
458 SmpConfigureKnownDlls(IN PWSTR ValueName,
459 IN ULONG ValueType,
460 IN PVOID ValueData,
461 IN ULONG ValueLength,
462 IN PVOID Context,
463 IN PVOID EntryContext)
464 {
465 /* Check which value is being set */
466 if (_wcsicmp(ValueName, L"DllDirectory") == 0)
467 {
468 /* This is the directory, initialize it */
469 DPRINT("KnownDll Path: %S\n", ValueData);
470 return SmpInitializeKnownDllPath(&SmpKnownDllPath, ValueData, ValueLength);
471 }
472 else
473 {
474 /* Add to the linked list -- this is a file */
475 return SmpSaveRegistryValue(EntryContext, ValueName, ValueData, TRUE);
476 }
477 }
478
479 NTSTATUS
480 NTAPI
481 SmpConfigureEnvironment(IN PWSTR ValueName,
482 IN ULONG ValueType,
483 IN PVOID ValueData,
484 IN ULONG ValueLength,
485 IN PVOID Context,
486 IN PVOID EntryContext)
487 {
488 NTSTATUS Status;
489 UNICODE_STRING ValueString, DataString;
490
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))
497 {
498 DPRINT1("SMSS: 'SET %wZ = %wZ' failed - Status == %lx\n",
499 &ValueString, &DataString, Status);
500 return Status;
501 }
502
503 /* Check if the path is being set, and wait for the second instantiation */
504 if ((_wcsicmp(ValueName, L"Path") == 0) && (++SmpCalledConfigEnv == 2))
505 {
506 /* Allocate the path buffer */
507 SmpDefaultLibPathBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
508 SmBaseTag,
509 ValueLength);
510 if (!SmpDefaultLibPathBuffer) return STATUS_NO_MEMORY;
511
512 /* Copy the data into it and create the UNICODE_STRING to hold it */
513 RtlCopyMemory(SmpDefaultLibPathBuffer, ValueData, ValueLength);
514 RtlInitUnicodeString(&SmpDefaultLibPath, SmpDefaultLibPathBuffer);
515 }
516
517 /* All good */
518 return STATUS_SUCCESS;
519 }
520
521 NTSTATUS
522 NTAPI
523 SmpConfigureSubSystems(IN PWSTR ValueName,
524 IN ULONG ValueType,
525 IN PVOID ValueData,
526 IN ULONG ValueLength,
527 IN PVOID Context,
528 IN PVOID EntryContext)
529 {
530 PSMP_REGISTRY_VALUE RegEntry;
531 PWCHAR SubsystemName;
532
533 /* Is this a required or optional subsystem? */
534 if ((_wcsicmp(ValueName, L"Required") != 0) &&
535 (_wcsicmp(ValueName, L"Optional") != 0))
536 {
537 /* It isn't, is this the PSI flag? */
538 if ((_wcsicmp(ValueName, L"PosixSingleInstance") != 0) ||
539 (ValueType != REG_DWORD))
540 {
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);
544 }
545
546 /* This was the PSI flag, save it and exit */
547 RegPosixSingleInstance = TRUE;
548 return STATUS_SUCCESS;
549 }
550
551 /* This should be one of the required/optional lists. Is the type valid? */
552 if (ValueType == REG_MULTI_SZ)
553 {
554 /* It is, get the first subsystem */
555 SubsystemName = ValueData;
556 while (*SubsystemName)
557 {
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);
561 if (!RegEntry)
562 {
563 /* This subsystem doesn't exist, so skip it */
564 DPRINT1("SMSS: Invalid subsystem name - %ws\n", SubsystemName);
565 }
566 else
567 {
568 /* Found it -- remove it from the main list */
569 RemoveEntryList(&RegEntry->Entry);
570
571 /* Figure out which list to put it in */
572 if (_wcsicmp(ValueName, L"Required") == 0)
573 {
574 /* Put it into the required list */
575 DPRINT("Required\n");
576 InsertTailList(&SmpSubSystemsToLoad, &RegEntry->Entry);
577 }
578 else
579 {
580 /* Put it into the optional list */
581 DPRINT("Optional\n");
582 InsertTailList(&SmpSubSystemsToDefer, &RegEntry->Entry);
583 }
584 }
585
586 /* Move to the next name */
587 while (*SubsystemName++);
588 }
589 }
590
591 /* All done! */
592 return STATUS_SUCCESS;
593 }
594
595 RTL_QUERY_REGISTRY_TABLE
596 SmpRegistryConfigurationTable[] =
597 {
598 {
599 SmpConfigureProtectionMode,
600 0,
601 L"ProtectionMode",
602 NULL,
603 REG_DWORD,
604 NULL,
605 0
606 },
607
608 {
609 SmpConfigureAllowProtectedRenames,
610 0, //RTL_QUERY_REGISTRY_DELETE,
611 L"AllowProtectedRenames",
612 NULL,
613 REG_DWORD,
614 NULL,
615 0
616 },
617
618 {
619 SmpConfigureObjectDirectories,
620 0,
621 L"ObjectDirectories",
622 NULL,
623 REG_MULTI_SZ,
624 L"\\Windows\0\\RPC Control\0",
625 0
626 },
627
628 {
629 SmpConfigureMemoryMgmt,
630 0,
631 L"BootExecute",
632 &SmpBootExecuteList,
633 REG_MULTI_SZ,
634 L"autocheck AutoChk.exe *\0",
635 0
636 },
637
638 {
639 SmpConfigureMemoryMgmt,
640 RTL_QUERY_REGISTRY_TOPKEY,
641 L"SetupExecute",
642 &SmpSetupExecuteList,
643 REG_NONE,
644 NULL,
645 0
646 },
647
648 {
649 SmpConfigureFileRenames,
650 0, //RTL_QUERY_REGISTRY_DELETE,
651 L"PendingFileRenameOperations",
652 &SmpFileRenameList,
653 REG_NONE,
654 NULL,
655 0
656 },
657
658 {
659 SmpConfigureFileRenames,
660 0, //RTL_QUERY_REGISTRY_DELETE,
661 L"PendingFileRenameOperations2",
662 &SmpFileRenameList,
663 REG_NONE,
664 NULL,
665 0
666 },
667
668 {
669 SmpConfigureExcludeKnownDlls,
670 0,
671 L"ExcludeFromKnownDlls",
672 &SmpExcludeKnownDllsList,
673 REG_MULTI_SZ,
674 L"\0",
675 0
676 },
677
678 {
679 NULL,
680 RTL_QUERY_REGISTRY_SUBKEY,
681 L"Memory Management",
682 NULL,
683 REG_NONE,
684 NULL,
685 0
686 },
687
688 {
689 SmpConfigureMemoryMgmt,
690 0,
691 L"PagingFiles",
692 &SmpPagingFileList,
693 REG_MULTI_SZ,
694 L"?:\\pagefile.sys\0",
695 0
696 },
697
698 {
699 SmpConfigureDosDevices,
700 RTL_QUERY_REGISTRY_SUBKEY,
701 L"DOS Devices",
702 &SmpDosDevicesList,
703 REG_NONE,
704 NULL,
705 0
706 },
707
708 {
709 SmpConfigureKnownDlls,
710 RTL_QUERY_REGISTRY_SUBKEY,
711 L"KnownDlls",
712 &SmpKnownDllsList,
713 REG_NONE,
714 NULL,
715 0
716 },
717
718 {
719 SmpConfigureEnvironment,
720 RTL_QUERY_REGISTRY_SUBKEY,
721 L"Environment",
722 NULL,
723 REG_NONE,
724 NULL,
725 0
726 },
727
728 {
729 SmpConfigureSubSystems,
730 RTL_QUERY_REGISTRY_SUBKEY,
731 L"SubSystems",
732 &SmpSubSystemList,
733 REG_NONE,
734 NULL,
735 0
736 },
737
738 {
739 SmpConfigureSubSystems,
740 RTL_QUERY_REGISTRY_NOEXPAND,
741 L"Required",
742 &SmpSubSystemList,
743 REG_MULTI_SZ,
744 L"Debug\0Windows\0",
745 0
746 },
747
748 {
749 SmpConfigureSubSystems,
750 RTL_QUERY_REGISTRY_NOEXPAND,
751 L"Optional",
752 &SmpSubSystemList,
753 REG_NONE,
754 NULL,
755 0
756 },
757
758 {
759 SmpConfigureSubSystems,
760 0,
761 L"Kmode",
762 &SmpSubSystemList,
763 REG_NONE,
764 NULL,
765 0
766 },
767
768 {
769 SmpConfigureMemoryMgmt,
770 RTL_QUERY_REGISTRY_TOPKEY,
771 L"Execute",
772 &SmpExecuteList,
773 REG_NONE,
774 NULL,
775 0
776 },
777
778 {0},
779 };
780
781 /* FUNCTIONS ******************************************************************/
782
783 VOID
784 NTAPI
785 SmpTranslateSystemPartitionInformation(VOID)
786 {
787 NTSTATUS Status;
788 UNICODE_STRING UnicodeString, LinkTarget, SearchString, SystemPartition;
789 OBJECT_ATTRIBUTES ObjectAttributes;
790 HANDLE KeyHandle, LinkHandle;
791 CHAR ValueBuffer[512 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
792 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
793 ULONG Length, Context;
794 CHAR DirInfoBuffer[512 + sizeof(OBJECT_DIRECTORY_INFORMATION)];
795 POBJECT_DIRECTORY_INFORMATION DirInfo = (PVOID)DirInfoBuffer;
796 WCHAR LinkBuffer[MAX_PATH];
797
798 /* Open the setup key */
799 RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\Setup");
800 InitializeObjectAttributes(&ObjectAttributes,
801 &UnicodeString,
802 OBJ_CASE_INSENSITIVE,
803 NULL,
804 NULL);
805 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
806 if (!NT_SUCCESS(Status))
807 {
808 DPRINT1("SMSS: can't open system setup key for reading: 0x%x\n", Status);
809 return;
810 }
811
812 /* Query the system partition */
813 RtlInitUnicodeString(&UnicodeString, L"SystemPartition");
814 Status = NtQueryValueKey(KeyHandle,
815 &UnicodeString,
816 KeyValuePartialInformation,
817 PartialInfo,
818 sizeof(ValueBuffer),
819 &Length);
820 NtClose(KeyHandle);
821 if (!NT_SUCCESS(Status))
822 {
823 DPRINT1("SMSS: can't query SystemPartition value: 0x%x\n", Status);
824 return;
825 }
826
827 /* Initialize the system partition string string */
828 RtlInitUnicodeString(&SystemPartition, (PWCHAR)PartialInfo->Data);
829
830 /* Enumerate the directory looking for the symbolic link string */
831 RtlInitUnicodeString(&SearchString, L"SymbolicLink");
832 RtlInitEmptyUnicodeString(&LinkTarget, LinkBuffer, sizeof(LinkBuffer));
833 Status = NtQueryDirectoryObject(SmpDosDevicesObjectDirectory,
834 DirInfo,
835 sizeof(DirInfoBuffer),
836 TRUE,
837 TRUE,
838 &Context,
839 NULL);
840 if (!NT_SUCCESS(Status))
841 {
842 DPRINT1("SMSS: can't find drive letter for system partition\n");
843 return;
844 }
845
846 /* Keep searching until we find it */
847 do
848 {
849 /* Is this it? */
850 if ((RtlEqualUnicodeString(&DirInfo->TypeName, &SearchString, TRUE)) &&
851 (DirInfo->Name.Length == 2 * sizeof(WCHAR)) &&
852 (DirInfo->Name.Buffer[1] == L':'))
853 {
854 /* Looks like we found it, open the link to get its target */
855 InitializeObjectAttributes(&ObjectAttributes,
856 &DirInfo->Name,
857 OBJ_CASE_INSENSITIVE,
858 SmpDosDevicesObjectDirectory,
859 NULL);
860 Status = NtOpenSymbolicLinkObject(&LinkHandle,
861 SYMBOLIC_LINK_ALL_ACCESS,
862 &ObjectAttributes);
863 if (NT_SUCCESS(Status))
864 {
865 /* Open worked, query the target now */
866 Status = NtQuerySymbolicLinkObject(LinkHandle,
867 &LinkTarget,
868 NULL);
869 NtClose(LinkHandle);
870
871 /* Check if it matches the string we had found earlier */
872 if ((NT_SUCCESS(Status)) &&
873 ((RtlEqualUnicodeString(&SystemPartition,
874 &LinkTarget,
875 TRUE)) ||
876 ((RtlPrefixUnicodeString(&SystemPartition,
877 &LinkTarget,
878 TRUE)) &&
879 (LinkTarget.Buffer[SystemPartition.Length / sizeof(WCHAR)] == L'\\'))))
880 {
881 /* All done */
882 break;
883 }
884 }
885 }
886
887 /* Couldn't find it, try again */
888 Status = NtQueryDirectoryObject(SmpDosDevicesObjectDirectory,
889 DirInfo,
890 sizeof(DirInfoBuffer),
891 TRUE,
892 FALSE,
893 &Context,
894 NULL);
895 } while (NT_SUCCESS(Status));
896 if (!NT_SUCCESS(Status))
897 {
898 DPRINT1("SMSS: can't find drive letter for system partition\n");
899 return;
900 }
901
902 /* Open the setup key again, for full access this time */
903 RtlInitUnicodeString(&UnicodeString,
904 L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup");
905 InitializeObjectAttributes(&ObjectAttributes,
906 &UnicodeString,
907 OBJ_CASE_INSENSITIVE,
908 NULL,
909 NULL);
910 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
911 if (!NT_SUCCESS(Status))
912 {
913 DPRINT1("SMSS: can't open software setup key for writing: 0x%x\n",
914 Status);
915 return;
916 }
917
918 /* Wrap up the end of the link buffer */
919 wcsncpy(LinkBuffer, DirInfo->Name.Buffer, 2);
920 LinkBuffer[2] = L'\\';
921 LinkBuffer[3] = L'\0';
922
923 /* Now set this as the "BootDir" */
924 RtlInitUnicodeString(&UnicodeString, L"BootDir");
925 Status = NtSetValueKey(KeyHandle,
926 &UnicodeString,
927 0,
928 REG_SZ,
929 LinkBuffer,
930 4 * sizeof(WCHAR));
931 if (!NT_SUCCESS(Status))
932 {
933 DPRINT1("SMSS: couldn't write BootDir value: 0x%x\n", Status);
934 }
935 NtClose(KeyHandle);
936 }
937
938 NTSTATUS
939 NTAPI
940 SmpCreateSecurityDescriptors(IN BOOLEAN InitialCall)
941 {
942 NTSTATUS Status;
943 PSID WorldSid = NULL, AdminSid = NULL, SystemSid = NULL;
944 PSID RestrictedSid = NULL, OwnerSid = NULL;
945 SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
946 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
947 SID_IDENTIFIER_AUTHORITY CreatorAuthority = {SECURITY_CREATOR_SID_AUTHORITY};
948 ULONG AclLength, SidLength;
949 PACL Acl;
950 PACE_HEADER Ace;
951 BOOLEAN ProtectionRequired = FALSE;
952
953 /* Check if this is the first call */
954 if (InitialCall)
955 {
956 /* Create and set the primary descriptor */
957 SmpPrimarySecurityDescriptor = &SmpPrimarySDBody;
958 Status = RtlCreateSecurityDescriptor(SmpPrimarySecurityDescriptor,
959 SECURITY_DESCRIPTOR_REVISION);
960 ASSERT(NT_SUCCESS(Status));
961 Status = RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor,
962 TRUE,
963 NULL,
964 FALSE);
965 ASSERT(NT_SUCCESS(Status));
966
967 /* Create and set the liberal descriptor */
968 SmpLiberalSecurityDescriptor = &SmpLiberalSDBody;
969 Status = RtlCreateSecurityDescriptor(SmpLiberalSecurityDescriptor,
970 SECURITY_DESCRIPTOR_REVISION);
971 ASSERT(NT_SUCCESS(Status));
972 Status = RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor,
973 TRUE,
974 NULL,
975 FALSE);
976 ASSERT(NT_SUCCESS(Status));
977
978 /* Create and set the \KnownDlls descriptor */
979 SmpKnownDllsSecurityDescriptor = &SmpKnownDllsSDBody;
980 Status = RtlCreateSecurityDescriptor(SmpKnownDllsSecurityDescriptor,
981 SECURITY_DESCRIPTOR_REVISION);
982 ASSERT(NT_SUCCESS(Status));
983 Status = RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor,
984 TRUE,
985 NULL,
986 FALSE);
987 ASSERT(NT_SUCCESS(Status));
988
989 /* Create and Set the \ApiPort descriptor */
990 SmpApiPortSecurityDescriptor = &SmpApiPortSDBody;
991 Status = RtlCreateSecurityDescriptor(SmpApiPortSecurityDescriptor,
992 SECURITY_DESCRIPTOR_REVISION);
993 ASSERT(NT_SUCCESS(Status));
994 Status = RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor,
995 TRUE,
996 NULL,
997 FALSE);
998 ASSERT(NT_SUCCESS(Status));
999 }
1000
1001 /* Check if protection was requested in the registry (on by default) */
1002 if (SmpProtectionMode & 1) ProtectionRequired = TRUE;
1003
1004 /* Exit if there's nothing to do */
1005 if (!(InitialCall || ProtectionRequired)) return STATUS_SUCCESS;
1006
1007 /* Build the world SID */
1008 Status = RtlAllocateAndInitializeSid(&WorldAuthority, 1,
1009 SECURITY_WORLD_RID,
1010 0, 0, 0, 0, 0, 0, 0,
1011 &WorldSid);
1012 if (!NT_SUCCESS(Status))
1013 {
1014 WorldSid = NULL;
1015 goto Quickie;
1016 }
1017
1018 /* Build the admin SID */
1019 Status = RtlAllocateAndInitializeSid(&NtAuthority, 2,
1020 SECURITY_BUILTIN_DOMAIN_RID,
1021 DOMAIN_ALIAS_RID_ADMINS,
1022 0, 0, 0, 0, 0, 0,
1023 &AdminSid);
1024 if (!NT_SUCCESS(Status))
1025 {
1026 AdminSid = NULL;
1027 goto Quickie;
1028 }
1029
1030 /* Build the owner SID */
1031 Status = RtlAllocateAndInitializeSid(&CreatorAuthority, 1,
1032 SECURITY_CREATOR_OWNER_RID,
1033 0, 0, 0, 0, 0, 0, 0,
1034 &OwnerSid);
1035 if (!NT_SUCCESS(Status))
1036 {
1037 OwnerSid = NULL;
1038 goto Quickie;
1039 }
1040
1041 /* Build the restricted SID */
1042 Status = RtlAllocateAndInitializeSid(&NtAuthority, 1,
1043 SECURITY_RESTRICTED_CODE_RID,
1044 0, 0, 0, 0, 0, 0, 0,
1045 &RestrictedSid);
1046 if (!NT_SUCCESS(Status))
1047 {
1048 RestrictedSid = NULL;
1049 goto Quickie;
1050 }
1051
1052 /* Build the system SID */
1053 Status = RtlAllocateAndInitializeSid(&NtAuthority, 1,
1054 SECURITY_LOCAL_SYSTEM_RID,
1055 0, 0, 0, 0, 0, 0, 0,
1056 &SystemSid);
1057 if (!NT_SUCCESS(Status))
1058 {
1059 SystemSid = NULL;
1060 goto Quickie;
1061 }
1062
1063 /* Now check if we're creating the core descriptors */
1064 if (!InitialCall)
1065 {
1066 /* We're skipping NextAcl so we have to do this here */
1067 SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(RestrictedSid) + RtlLengthSid(AdminSid);
1068 SidLength *= 2;
1069 goto NotInitial;
1070 }
1071
1072 /* Allocate an ACL with two ACEs with two SIDs each */
1073 SidLength = RtlLengthSid(SystemSid) + RtlLengthSid(AdminSid);
1074 AclLength = sizeof(ACL) + 2 * sizeof(ACCESS_ALLOWED_ACE) + SidLength;
1075 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength);
1076 if (!Acl) Status = STATUS_NO_MEMORY;
1077 if (!NT_SUCCESS(Status)) goto NextAcl;
1078
1079 /* Now build the ACL and add the two ACEs */
1080 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2);
1081 ASSERT(NT_SUCCESS(Status));
1082 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1083 ASSERT(NT_SUCCESS(Status));
1084 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, SystemSid);
1085 ASSERT(NT_SUCCESS(Status));
1086
1087 /* Set this as the DACL */
1088 Status = RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor,
1089 TRUE,
1090 Acl,
1091 FALSE);
1092 ASSERT(NT_SUCCESS(Status));
1093
1094 NextAcl:
1095 /* Allocate an ACL with 6 ACEs, two ACEs per SID */
1096 SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(RestrictedSid) + RtlLengthSid(AdminSid);
1097 SidLength *= 2;
1098 AclLength = sizeof(ACL) + 6 * sizeof(ACCESS_ALLOWED_ACE) + SidLength;
1099 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength);
1100 if (!Acl) Status = STATUS_NO_MEMORY;
1101 if (!NT_SUCCESS(Status)) goto NotInitial;
1102
1103 /* Now build the ACL and add the six ACEs */
1104 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2);
1105 ASSERT(NT_SUCCESS(Status));
1106 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE, WorldSid);
1107 ASSERT(NT_SUCCESS(Status));
1108 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE, RestrictedSid);
1109 ASSERT(NT_SUCCESS(Status));
1110 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1111 ASSERT(NT_SUCCESS(Status));
1112 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid);
1113 ASSERT(NT_SUCCESS(Status));
1114 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid);
1115 ASSERT(NT_SUCCESS(Status));
1116 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1117 ASSERT(NT_SUCCESS(Status));
1118
1119 /* Now edit the last three ACEs and make them inheritable */
1120 Status = RtlGetAce(Acl, 3, (PVOID)&Ace);
1121 ASSERT(NT_SUCCESS(Status));
1122 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1123 Status = RtlGetAce(Acl, 4, (PVOID)&Ace);
1124 ASSERT(NT_SUCCESS(Status));
1125 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1126 Status = RtlGetAce(Acl, 5, (PVOID)&Ace);
1127 ASSERT(NT_SUCCESS(Status));
1128 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1129
1130 /* Set this as the DACL */
1131 Status = RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor,
1132 TRUE,
1133 Acl,
1134 FALSE);
1135 ASSERT(NT_SUCCESS(Status));
1136
1137 NotInitial:
1138 /* The initial ACLs have been created, are we also protecting objects? */
1139 if (!ProtectionRequired) goto Quickie;
1140
1141 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
1142 SidLength += RtlLengthSid(OwnerSid);
1143 AclLength = sizeof(ACL) + 7 * sizeof (ACCESS_ALLOWED_ACE) + 2 * SidLength;
1144 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength);
1145 if (!Acl) Status = STATUS_NO_MEMORY;
1146 if (!NT_SUCCESS(Status)) goto Quickie;
1147
1148 /* Build the ACL and add the seven ACEs */
1149 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2);
1150 ASSERT(NT_SUCCESS(Status));
1151 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, WorldSid);
1152 ASSERT(NT_SUCCESS(Status));
1153 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, RestrictedSid);
1154 ASSERT(NT_SUCCESS(Status));
1155 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1156 ASSERT(NT_SUCCESS(Status));
1157 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, WorldSid);
1158 ASSERT(NT_SUCCESS(Status));
1159 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, RestrictedSid);
1160 ASSERT(NT_SUCCESS(Status));
1161 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1162 ASSERT(NT_SUCCESS(Status));
1163 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, OwnerSid);
1164 ASSERT(NT_SUCCESS(Status));
1165
1166 /* Edit the last 4 ACEs to make then inheritable */
1167 Status = RtlGetAce(Acl, 3, (PVOID)&Ace);
1168 ASSERT(NT_SUCCESS(Status));
1169 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1170 Status = RtlGetAce(Acl, 4, (PVOID)&Ace);
1171 ASSERT(NT_SUCCESS(Status));
1172 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1173 Status = RtlGetAce(Acl, 5, (PVOID)&Ace);
1174 ASSERT(NT_SUCCESS(Status));
1175 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1176 Status = RtlGetAce(Acl, 6, (PVOID)&Ace);
1177 ASSERT(NT_SUCCESS(Status));
1178 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1179
1180 /* Set this as the DACL for the primary SD */
1181 Status = RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor,
1182 TRUE,
1183 Acl,
1184 FALSE);
1185 ASSERT(NT_SUCCESS(Status));
1186
1187 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
1188 AclLength = sizeof(ACL) + 7 * sizeof (ACCESS_ALLOWED_ACE) + 2 * SidLength;
1189 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength);
1190 if (!Acl) Status = STATUS_NO_MEMORY;
1191 if (!NT_SUCCESS(Status)) goto Quickie;
1192
1193 /* Build the ACL and add the seven ACEs */
1194 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2);
1195 ASSERT(NT_SUCCESS(Status));
1196 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid);
1197 ASSERT(NT_SUCCESS(Status));
1198 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid);
1199 ASSERT(NT_SUCCESS(Status));
1200 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1201 ASSERT(NT_SUCCESS(Status));
1202 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid);
1203 ASSERT(NT_SUCCESS(Status));
1204 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid);
1205 ASSERT(NT_SUCCESS(Status));
1206 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1207 ASSERT(NT_SUCCESS(Status));
1208 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, OwnerSid);
1209 ASSERT(NT_SUCCESS(Status));
1210
1211 /* Edit the last 4 ACEs to make then inheritable */
1212 Status = RtlGetAce(Acl, 3, (PVOID)&Ace);
1213 ASSERT(NT_SUCCESS(Status));
1214 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1215 Status = RtlGetAce(Acl, 4, (PVOID)&Ace);
1216 ASSERT(NT_SUCCESS(Status));
1217 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1218 Status = RtlGetAce(Acl, 5, (PVOID)&Ace);
1219 ASSERT(NT_SUCCESS(Status));
1220 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1221 Status = RtlGetAce(Acl, 6, (PVOID)&Ace);
1222 ASSERT(NT_SUCCESS(Status));
1223 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1224
1225 /* Now set this as the DACL for the liberal SD */
1226 Status = RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor,
1227 TRUE,
1228 Acl,
1229 FALSE);
1230 ASSERT(NT_SUCCESS(Status));
1231
1232 Quickie:
1233 /* Cleanup the SIDs */
1234 if (OwnerSid) RtlFreeHeap(RtlGetProcessHeap(), 0, OwnerSid);
1235 if (AdminSid) RtlFreeHeap(RtlGetProcessHeap(), 0, AdminSid);
1236 if (WorldSid) RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid);
1237 if (SystemSid) RtlFreeHeap(RtlGetProcessHeap(), 0, SystemSid);
1238 if (RestrictedSid) RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSid);
1239 return Status;
1240 }
1241
1242 NTSTATUS
1243 NTAPI
1244 SmpInitializeDosDevices(VOID)
1245 {
1246 NTSTATUS Status;
1247 PSMP_REGISTRY_VALUE RegEntry;
1248 SECURITY_DESCRIPTOR_CONTROL OldFlag = 0;
1249 OBJECT_ATTRIBUTES ObjectAttributes;
1250 UNICODE_STRING DestinationString;
1251 HANDLE DirHandle;
1252 PLIST_ENTRY NextEntry, Head;
1253
1254 /* Open the GLOBAL?? directory */
1255 RtlInitUnicodeString(&DestinationString, L"\\??");
1256 InitializeObjectAttributes(&ObjectAttributes,
1257 &DestinationString,
1258 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
1259 NULL,
1260 NULL);
1261 Status = NtOpenDirectoryObject(&SmpDosDevicesObjectDirectory,
1262 DIRECTORY_ALL_ACCESS,
1263 &ObjectAttributes);
1264 if (!NT_SUCCESS(Status))
1265 {
1266 DPRINT1("SMSS: Unable to open %wZ directory - Status == %lx\n",
1267 &DestinationString, Status);
1268 return Status;
1269 }
1270
1271 /* Loop the DOS devices */
1272 Head = &SmpDosDevicesList;
1273 while (!IsListEmpty(Head))
1274 {
1275 /* Get the entry and remove it */
1276 NextEntry = RemoveHeadList(Head);
1277 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
1278
1279 /* Initialize the attributes, and see which descriptor is being used */
1280 InitializeObjectAttributes(&ObjectAttributes,
1281 &RegEntry->Name,
1282 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
1283 SmpDosDevicesObjectDirectory,
1284 SmpPrimarySecurityDescriptor);
1285 if (SmpPrimarySecurityDescriptor)
1286 {
1287 /* Save the old flag and set it while we create this link */
1288 OldFlag = SmpPrimarySecurityDescriptor->Control;
1289 SmpPrimarySecurityDescriptor->Control |= SE_DACL_DEFAULTED;
1290 }
1291
1292 /* Create the symbolic link */
1293 DPRINT("Creating symlink for %wZ to %wZ\n", &RegEntry->Name, &RegEntry->Value);
1294 Status = NtCreateSymbolicLinkObject(&DirHandle,
1295 SYMBOLIC_LINK_ALL_ACCESS,
1296 &ObjectAttributes,
1297 &RegEntry->Value);
1298 if (Status == STATUS_OBJECT_NAME_EXISTS)
1299 {
1300 /* Make it temporary and get rid of the handle */
1301 NtMakeTemporaryObject(DirHandle);
1302 NtClose(DirHandle);
1303
1304 /* Treat this as success, and see if we got a name back */
1305 Status = STATUS_SUCCESS;
1306 if (RegEntry->Value.Length)
1307 {
1308 /* Create it now with this name */
1309 ObjectAttributes.Attributes &= ~OBJ_OPENIF;
1310 Status = NtCreateSymbolicLinkObject(&DirHandle,
1311 SYMBOLIC_LINK_ALL_ACCESS,
1312 &ObjectAttributes,
1313 &RegEntry->Value);
1314 }
1315 }
1316
1317 /* If we were using a security descriptor, restore the non-defaulted flag */
1318 if (ObjectAttributes.SecurityDescriptor)
1319 {
1320 SmpPrimarySecurityDescriptor->Control = OldFlag;
1321 }
1322
1323 /* Print a failure if we failed to create the symbolic link */
1324 if (!NT_SUCCESS(Status))
1325 {
1326 DPRINT1("SMSS: Unable to create %wZ => %wZ symbolic link object - Status == 0x%lx\n",
1327 &RegEntry->Name,
1328 &RegEntry->Value,
1329 Status);
1330 break;
1331 }
1332
1333 /* Close the handle */
1334 NtClose(DirHandle);
1335
1336 /* Free this entry */
1337 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
1338 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
1339 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
1340 }
1341
1342 /* Return the status */
1343 return Status;
1344 }
1345
1346 VOID
1347 NTAPI
1348 SmpProcessModuleImports(IN PVOID Unused,
1349 IN PCHAR ImportName)
1350 {
1351 ULONG Length = 0, Chars;
1352 WCHAR Buffer[MAX_PATH];
1353 PWCHAR DllName, DllValue;
1354 ANSI_STRING ImportString;
1355 UNICODE_STRING ImportUnicodeString;
1356 NTSTATUS Status;
1357
1358 /* Skip NTDLL since it's already always mapped */
1359 if (!_stricmp(ImportName, "ntdll.dll")) return;
1360
1361 /* Initialize our strings */
1362 RtlInitAnsiString(&ImportString, ImportName);
1363 RtlInitEmptyUnicodeString(&ImportUnicodeString, Buffer, sizeof(Buffer));
1364 Status = RtlAnsiStringToUnicodeString(&ImportUnicodeString, &ImportString, FALSE);
1365 if (!NT_SUCCESS(Status)) return;
1366
1367 /* Loop in case we find a forwarder */
1368 ImportUnicodeString.MaximumLength = ImportUnicodeString.Length + sizeof(UNICODE_NULL);
1369 while (Length < ImportUnicodeString.Length)
1370 {
1371 if (ImportUnicodeString.Buffer[Length / sizeof(WCHAR)] == L'.') break;
1372 Length += sizeof(WCHAR);
1373 }
1374
1375 /* Break up the values as needed */
1376 DllValue = ImportUnicodeString.Buffer;
1377 DllName = &ImportUnicodeString.Buffer[ImportUnicodeString.MaximumLength / sizeof(WCHAR)];
1378 Chars = Length >> 1;
1379 wcsncpy(DllName, ImportUnicodeString.Buffer, Chars);
1380 DllName[Chars] = 0;
1381
1382 /* Add the DLL to the list */
1383 SmpSaveRegistryValue(&SmpKnownDllsList, DllName, DllValue, TRUE);
1384 }
1385
1386 NTSTATUS
1387 NTAPI
1388 SmpInitializeKnownDllsInternal(IN PUNICODE_STRING Directory,
1389 IN PUNICODE_STRING Path)
1390 {
1391 HANDLE DirFileHandle, DirHandle, SectionHandle, FileHandle, LinkHandle;
1392 UNICODE_STRING NtPath, DestinationString;
1393 OBJECT_ATTRIBUTES ObjectAttributes;
1394 NTSTATUS Status, Status1;
1395 PLIST_ENTRY NextEntry;
1396 PSMP_REGISTRY_VALUE RegEntry;
1397 ULONG_PTR ErrorParameters[3];
1398 UNICODE_STRING ErrorResponse;
1399 IO_STATUS_BLOCK IoStatusBlock;
1400 SECURITY_DESCRIPTOR_CONTROL OldFlag = 0;
1401 USHORT ImageCharacteristics;
1402
1403 /* Initialize to NULL */
1404 DirFileHandle = NULL;
1405 DirHandle = NULL;
1406 NtPath.Buffer = NULL;
1407
1408 /* Create the \KnownDLLs directory */
1409 InitializeObjectAttributes(&ObjectAttributes,
1410 Directory,
1411 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
1412 NULL,
1413 SmpKnownDllsSecurityDescriptor);
1414 Status = NtCreateDirectoryObject(&DirHandle,
1415 DIRECTORY_ALL_ACCESS,
1416 &ObjectAttributes);
1417 if (!NT_SUCCESS(Status))
1418 {
1419 /* Handle failure */
1420 DPRINT1("SMSS: Unable to create %wZ directory - Status == %lx\n",
1421 Directory, Status);
1422 return Status;
1423 }
1424
1425 /* Convert the path to native format */
1426 if (!RtlDosPathNameToNtPathName_U(Path->Buffer, &NtPath, NULL, NULL))
1427 {
1428 /* Fail if this didn't work */
1429 DPRINT1("SMSS: Unable to to convert %wZ to an Nt path\n", Path);
1430 Status = STATUS_OBJECT_NAME_INVALID;
1431 goto Quickie;
1432 }
1433
1434 /* Open the path that was specified, which should be a directory */
1435 InitializeObjectAttributes(&ObjectAttributes,
1436 &NtPath,
1437 OBJ_CASE_INSENSITIVE,
1438 NULL,
1439 NULL);
1440 Status = NtOpenFile(&DirFileHandle,
1441 FILE_LIST_DIRECTORY | SYNCHRONIZE,
1442 &ObjectAttributes,
1443 &IoStatusBlock,
1444 FILE_SHARE_READ | FILE_SHARE_WRITE,
1445 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
1446 if (!NT_SUCCESS(Status))
1447 {
1448 /* Fail if we couldn't open it */
1449 DPRINT1("SMSS: Unable to open a handle to the KnownDll directory (%wZ)"
1450 "- Status == %lx\n",
1451 Path,
1452 Status);
1453 FileHandle = NULL;
1454 goto Quickie;
1455 }
1456
1457 /* Temporarily hack the SD to use a default DACL for this symbolic link */
1458 if (SmpPrimarySecurityDescriptor)
1459 {
1460 OldFlag = SmpPrimarySecurityDescriptor->Control;
1461 SmpPrimarySecurityDescriptor->Control |= SE_DACL_DEFAULTED;
1462 }
1463
1464 /* Create a symbolic link to the directory in the object manager */
1465 RtlInitUnicodeString(&DestinationString, L"KnownDllPath");
1466 InitializeObjectAttributes(&ObjectAttributes,
1467 &DestinationString,
1468 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
1469 DirHandle,
1470 SmpPrimarySecurityDescriptor);
1471 Status = NtCreateSymbolicLinkObject(&LinkHandle,
1472 SYMBOLIC_LINK_ALL_ACCESS,
1473 &ObjectAttributes,
1474 Path);
1475
1476 /* Undo the hack */
1477 if (SmpPrimarySecurityDescriptor) SmpPrimarySecurityDescriptor->Control = OldFlag;
1478
1479 /* Check if the symlink was created */
1480 if (!NT_SUCCESS(Status))
1481 {
1482 /* It wasn't, so bail out since the OS needs it to exist */
1483 DPRINT1("SMSS: Unable to create %wZ symbolic link - Status == %lx\n",
1484 &DestinationString, Status);
1485 LinkHandle = NULL;
1486 goto Quickie;
1487 }
1488
1489 /* We created it permanent, we can go ahead and close the handle now */
1490 Status1 = NtClose(LinkHandle);
1491 ASSERT(NT_SUCCESS(Status1));
1492
1493 /* Now loop the known DLLs */
1494 NextEntry = SmpKnownDllsList.Flink;
1495 while (NextEntry != &SmpKnownDllsList)
1496 {
1497 /* Get the entry and skip it if it's in the exluded list */
1498 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
1499 DPRINT("Processing known DLL: %wZ-%wZ\n", &RegEntry->Name, &RegEntry->Value);
1500 if ((SmpFindRegistryValue(&SmpExcludeKnownDllsList,
1501 RegEntry->Name.Buffer)) ||
1502 (SmpFindRegistryValue(&SmpExcludeKnownDllsList,
1503 RegEntry->Value.Buffer)))
1504 {
1505 continue;
1506 }
1507
1508 /* Open the actual file */
1509 InitializeObjectAttributes(&ObjectAttributes,
1510 &RegEntry->Value,
1511 OBJ_CASE_INSENSITIVE,
1512 DirFileHandle,
1513 NULL);
1514 Status = NtOpenFile(&FileHandle,
1515 SYNCHRONIZE | FILE_EXECUTE,
1516 &ObjectAttributes,
1517 &IoStatusBlock,
1518 FILE_SHARE_READ | FILE_SHARE_DELETE,
1519 FILE_NON_DIRECTORY_FILE |
1520 FILE_SYNCHRONOUS_IO_NONALERT);
1521 if (!NT_SUCCESS(Status)) break;
1522
1523 /* Checksum it */
1524 Status = LdrVerifyImageMatchesChecksum((HANDLE)((ULONG_PTR)FileHandle | 1),
1525 SmpProcessModuleImports,
1526 RegEntry,
1527 &ImageCharacteristics);
1528 if (!NT_SUCCESS(Status))
1529 {
1530 /* Checksum failed, so don't even try going further -- kill SMSS */
1531 RtlInitUnicodeString(&ErrorResponse,
1532 L"Verification of a KnownDLL failed.");
1533 ErrorParameters[0] = (ULONG)&ErrorResponse;
1534 ErrorParameters[1] = Status;
1535 ErrorParameters[2] = (ULONG)&RegEntry->Value;
1536 SmpTerminate(ErrorParameters, 5, RTL_NUMBER_OF(ErrorParameters));
1537 }
1538 else
1539 if (!(ImageCharacteristics & IMAGE_FILE_DLL))
1540 {
1541 /* An invalid known DLL entry will also kill SMSS */
1542 RtlInitUnicodeString(&ErrorResponse,
1543 L"Non-DLL file included in KnownDLL list.");
1544 ErrorParameters[0] = (ULONG)&ErrorResponse;
1545 ErrorParameters[1] = STATUS_INVALID_IMPORT_OF_NON_DLL;
1546 ErrorParameters[2] = (ULONG)&RegEntry->Value;
1547 SmpTerminate(ErrorParameters, 5, RTL_NUMBER_OF(ErrorParameters));
1548 }
1549
1550 /* Temporarily hack the SD to use a default DACL for this section */
1551 if (SmpLiberalSecurityDescriptor)
1552 {
1553 OldFlag = SmpLiberalSecurityDescriptor->Control;
1554 SmpLiberalSecurityDescriptor->Control |= SE_DACL_DEFAULTED;
1555 }
1556
1557 /* Create the section for this known DLL */
1558 InitializeObjectAttributes(&ObjectAttributes,
1559 &RegEntry->Value,
1560 OBJ_PERMANENT,
1561 DirHandle,
1562 SmpLiberalSecurityDescriptor)
1563 Status = NtCreateSection(&SectionHandle,
1564 SECTION_ALL_ACCESS,
1565 &ObjectAttributes,
1566 0,
1567 PAGE_EXECUTE,
1568 SEC_IMAGE,
1569 FileHandle);
1570
1571 /* Undo the hack */
1572 if (SmpLiberalSecurityDescriptor) SmpLiberalSecurityDescriptor->Control = OldFlag;
1573
1574 /* Check if we created the section okay */
1575 if (NT_SUCCESS(Status))
1576 {
1577 /* We can close it now, since it's marked permanent */
1578 Status1 = NtClose(SectionHandle);
1579 ASSERT(NT_SUCCESS(Status1));
1580 }
1581 else
1582 {
1583 /* If we couldn't make it "known", that's fine and keep going */
1584 DPRINT1("SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n",
1585 &RegEntry->Value, Status);
1586 }
1587
1588 /* Close the file since we can move on to the next one */
1589 Status1 = NtClose(FileHandle);
1590 ASSERT(NT_SUCCESS(Status1));
1591
1592 /* Go to the next entry */
1593 NextEntry = NextEntry->Flink;
1594 }
1595
1596 Quickie:
1597 /* Close both handles and free the NT path buffer */
1598 if (DirHandle)
1599 {
1600 Status1 = NtClose(DirHandle);
1601 ASSERT(NT_SUCCESS(Status1));
1602 }
1603 if (DirFileHandle)
1604 {
1605 Status1 = NtClose(DirFileHandle);
1606 ASSERT(NT_SUCCESS(Status1));
1607 }
1608 if (NtPath.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath.Buffer);
1609 return Status;
1610 }
1611
1612 NTSTATUS
1613 NTAPI
1614 SmpInitializeKnownDlls(VOID)
1615 {
1616 NTSTATUS Status;
1617 PSMP_REGISTRY_VALUE RegEntry;
1618 UNICODE_STRING DestinationString;
1619 PLIST_ENTRY Head, NextEntry;
1620
1621 /* Call the internal function */
1622 RtlInitUnicodeString(&DestinationString, L"\\KnownDlls");
1623 Status = SmpInitializeKnownDllsInternal(&DestinationString, &SmpKnownDllPath);
1624
1625 /* Wipe out the list regardless of success */
1626 Head = &SmpKnownDllsList;
1627 while (!IsListEmpty(Head))
1628 {
1629 /* Remove this entry */
1630 NextEntry = RemoveHeadList(Head);
1631
1632 /* Free it */
1633 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
1634 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
1635 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
1636 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
1637 }
1638
1639 /* All done */
1640 return Status;
1641 }
1642
1643 NTSTATUS
1644 NTAPI
1645 SmpCreateDynamicEnvironmentVariables(VOID)
1646 {
1647 NTSTATUS Status;
1648 SYSTEM_BASIC_INFORMATION BasicInfo;
1649 SYSTEM_PROCESSOR_INFORMATION ProcessorInfo;
1650 OBJECT_ATTRIBUTES ObjectAttributes;
1651 UNICODE_STRING ValueName, DestinationString;
1652 HANDLE KeyHandle, KeyHandle2;
1653 ULONG ResultLength;
1654 PWCHAR ArchName;
1655 WCHAR ValueBuffer[512], ValueBuffer2[512];
1656 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
1657 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo2 = (PVOID)ValueBuffer2;
1658
1659 /* Get system basic information -- we'll need the CPU count */
1660 Status = NtQuerySystemInformation(SystemBasicInformation,
1661 &BasicInfo,
1662 sizeof(BasicInfo),
1663 NULL);
1664 if (!NT_SUCCESS(Status))
1665 {
1666 /* Bail out on failure */
1667 DPRINT1("SMSS: Unable to query system basic information - %x\n", Status);
1668 return Status;
1669 }
1670
1671 /* Get the processor information, we'll query a bunch of revision info */
1672 Status = NtQuerySystemInformation(SystemProcessorInformation,
1673 &ProcessorInfo,
1674 sizeof(ProcessorInfo),
1675 NULL);
1676 if (!NT_SUCCESS(Status))
1677 {
1678 /* Bail out on failure */
1679 DPRINT1("SMSS: Unable to query system processor information - %x\n", Status);
1680 return Status;
1681 }
1682
1683 /* We'll be writing all these environment variables over here */
1684 RtlInitUnicodeString(&DestinationString,
1685 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
1686 L"Control\\Session Manager\\Environment");
1687 InitializeObjectAttributes(&ObjectAttributes,
1688 &DestinationString,
1689 OBJ_CASE_INSENSITIVE,
1690 NULL,
1691 NULL);
1692 Status = NtOpenKey(&KeyHandle, GENERIC_WRITE, &ObjectAttributes);
1693 if (!NT_SUCCESS(Status))
1694 {
1695 /* Bail out on failure */
1696 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString, Status);
1697 return Status;
1698 }
1699
1700 /* First let's write the OS variable */
1701 RtlInitUnicodeString(&ValueName, L"OS");
1702 DPRINT("Setting %wZ to %S\n", &ValueName, L"Windows_NT");
1703 Status = NtSetValueKey(KeyHandle,
1704 &ValueName,
1705 0,
1706 REG_SZ,
1707 L"Windows_NT",
1708 wcslen(L"Windows_NT") * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1709 if (!NT_SUCCESS(Status))
1710 {
1711 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1712 &ValueName, Status);
1713 NtClose(KeyHandle);
1714 return Status;
1715 }
1716
1717 /* Next, let's write the CPU architecture variable */
1718 RtlInitUnicodeString(&ValueName, L"PROCESSOR_ARCHITECTURE");
1719 switch (ProcessorInfo.ProcessorArchitecture)
1720 {
1721 /* Pick the correct string that matches the architecture */
1722 case PROCESSOR_ARCHITECTURE_INTEL:
1723 ArchName = L"x86";
1724 break;
1725
1726 case PROCESSOR_ARCHITECTURE_AMD64:
1727 ArchName = L"AMD64";
1728 break;
1729
1730 case PROCESSOR_ARCHITECTURE_IA64:
1731 ArchName = L"IA64";
1732 break;
1733
1734 default:
1735 ArchName = L"Unknown";
1736 break;
1737 }
1738
1739 /* Set it */
1740 DPRINT("Setting %wZ to %S\n", &ValueName, ArchName);
1741 Status = NtSetValueKey(KeyHandle,
1742 &ValueName,
1743 0,
1744 REG_SZ,
1745 ArchName,
1746 wcslen(ArchName) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1747 if (!NT_SUCCESS(Status))
1748 {
1749 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1750 &ValueName, Status);
1751 NtClose(KeyHandle);
1752 return Status;
1753 }
1754
1755 /* And now let's write the processor level */
1756 RtlInitUnicodeString(&ValueName, L"PROCESSOR_LEVEL");
1757 swprintf(ValueBuffer, L"%u", ProcessorInfo.ProcessorLevel);
1758 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
1759 Status = NtSetValueKey(KeyHandle,
1760 &ValueName,
1761 0,
1762 REG_SZ,
1763 ValueBuffer,
1764 wcslen(ValueBuffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1765 if (!NT_SUCCESS(Status))
1766 {
1767 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1768 &ValueName, Status);
1769 NtClose(KeyHandle);
1770 return Status;
1771 }
1772
1773 /* Now open the hardware CPU key */
1774 RtlInitUnicodeString(&DestinationString,
1775 L"\\Registry\\Machine\\Hardware\\Description\\System\\"
1776 L"CentralProcessor\\0");
1777 InitializeObjectAttributes(&ObjectAttributes,
1778 &DestinationString,
1779 OBJ_CASE_INSENSITIVE,
1780 NULL,
1781 NULL);
1782 Status = NtOpenKey(&KeyHandle2, KEY_READ, &ObjectAttributes);
1783 if (!NT_SUCCESS(Status))
1784 {
1785 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString, Status);
1786 NtClose(KeyHandle);
1787 return Status;
1788 }
1789
1790 /* So that we can read the identifier out of it... */
1791 RtlInitUnicodeString(&ValueName, L"Identifier");
1792 Status = NtQueryValueKey(KeyHandle2,
1793 &ValueName,
1794 KeyValuePartialInformation,
1795 PartialInfo,
1796 sizeof(ValueBuffer),
1797 &ResultLength);
1798 if (!NT_SUCCESS(Status))
1799 {
1800 NtClose(KeyHandle2);
1801 NtClose(KeyHandle);
1802 DPRINT1("SMSS: Unable to read %wZ\\%wZ - %x\n",
1803 &DestinationString, &ValueName, Status);
1804 return Status;
1805 }
1806
1807 /* As well as the vendor... */
1808 RtlInitUnicodeString(&ValueName, L"VendorIdentifier");
1809 Status = NtQueryValueKey(KeyHandle2,
1810 &ValueName,
1811 KeyValuePartialInformation,
1812 PartialInfo2,
1813 sizeof(ValueBuffer2),
1814 &ResultLength);
1815 NtClose(KeyHandle2);
1816 if (NT_SUCCESS(Status))
1817 {
1818 /* To combine it into a single string */
1819 swprintf((PWCHAR)PartialInfo->Data + wcslen((PWCHAR)PartialInfo->Data),
1820 L", %S",
1821 PartialInfo2->Data);
1822 }
1823
1824 /* So that we can set this as the PROCESSOR_IDENTIFIER variable */
1825 RtlInitUnicodeString(&ValueName, L"PROCESSOR_IDENTIFIER");
1826 DPRINT("Setting %wZ to %s\n", &ValueName, PartialInfo->Data);
1827 Status = NtSetValueKey(KeyHandle,
1828 &ValueName,
1829 0,
1830 REG_SZ,
1831 PartialInfo->Data,
1832 wcslen((PWCHAR)PartialInfo->Data) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1833 if (!NT_SUCCESS(Status))
1834 {
1835 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1836 &ValueName, Status);
1837 NtClose(KeyHandle);
1838 return Status;
1839 }
1840
1841 /* Now let's get the processor architecture */
1842 RtlInitUnicodeString(&ValueName, L"PROCESSOR_REVISION");
1843 switch (ProcessorInfo.ProcessorArchitecture)
1844 {
1845 /* Check if this is an older Intel CPU */
1846 case PROCESSOR_ARCHITECTURE_INTEL:
1847 if ((ProcessorInfo.ProcessorRevision >> 8) == 0xFF)
1848 {
1849 /* These guys used a revision + stepping, so get the rev only */
1850 swprintf(ValueBuffer, L"%02x", ProcessorInfo.ProcessorRevision & 0xFF);
1851 _wcsupr(ValueBuffer);
1852 break;
1853 }
1854
1855 /* Modern Intel, as well as 64-bit CPUs use a revision without stepping */
1856 case PROCESSOR_ARCHITECTURE_IA64:
1857 case PROCESSOR_ARCHITECTURE_AMD64:
1858 swprintf(ValueBuffer, L"%04x", ProcessorInfo.ProcessorRevision);
1859 break;
1860
1861 /* And anything else we'll just read the whole revision identifier */
1862 default:
1863 swprintf(ValueBuffer, L"%u", ProcessorInfo.ProcessorRevision);
1864 break;
1865 }
1866
1867 /* Write the revision to the registry */
1868 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
1869 Status = NtSetValueKey(KeyHandle,
1870 &ValueName,
1871 0,
1872 REG_SZ,
1873 ValueBuffer,
1874 wcslen(ValueBuffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1875 if (!NT_SUCCESS(Status))
1876 {
1877 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1878 &ValueName, Status);
1879 NtClose(KeyHandle);
1880 return Status;
1881 }
1882
1883 /* And finally, write the number of CPUs */
1884 RtlInitUnicodeString(&ValueName, L"NUMBER_OF_PROCESSORS");
1885 swprintf(ValueBuffer, L"%d", BasicInfo.NumberOfProcessors);
1886 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
1887 Status = NtSetValueKey(KeyHandle,
1888 &ValueName,
1889 0,
1890 REG_SZ,
1891 ValueBuffer,
1892 wcslen(ValueBuffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1893 if (!NT_SUCCESS(Status))
1894 {
1895 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1896 &ValueName, Status);
1897 NtClose(KeyHandle);
1898 return Status;
1899 }
1900
1901 /* Now we need to write the safeboot option key in a different format */
1902 RtlInitUnicodeString(&DestinationString,
1903 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
1904 L"Control\\Safeboot\\Option");
1905 InitializeObjectAttributes(&ObjectAttributes,
1906 &DestinationString,
1907 OBJ_CASE_INSENSITIVE,
1908 NULL,
1909 NULL);
1910 Status = NtOpenKey(&KeyHandle2, KEY_ALL_ACCESS, &ObjectAttributes);
1911 if (NT_SUCCESS(Status))
1912 {
1913 /* This was indeed a safeboot, so check what kind of safeboot it was */
1914 RtlInitUnicodeString(&ValueName, L"OptionValue");
1915 Status = NtQueryValueKey(KeyHandle2,
1916 &ValueName,
1917 KeyValuePartialInformation,
1918 PartialInfo,
1919 sizeof(ValueBuffer),
1920 &ResultLength);
1921 NtClose(KeyHandle2);
1922 if (NT_SUCCESS(Status))
1923 {
1924 /* Convert from the integer value to the correct specifier */
1925 RtlInitUnicodeString(&ValueName, L"SAFEBOOT_OPTION");
1926 switch (*(PULONG)PartialInfo->Data)
1927 {
1928 case 1:
1929 wcscpy(ValueBuffer, L"MINIMAL");
1930 break;
1931 case 2:
1932 wcscpy(ValueBuffer, L"NETWORK");
1933 break;
1934 case 3:
1935 wcscpy(ValueBuffer, L"DSREPAIR");
1936 break;
1937 }
1938
1939 /* And write it in the environment! */
1940 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
1941 Status = NtSetValueKey(KeyHandle,
1942 &ValueName,
1943 0,
1944 REG_SZ,
1945 ValueBuffer,
1946 wcslen(ValueBuffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1947 if (!NT_SUCCESS(Status))
1948 {
1949 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1950 &ValueName, Status);
1951 NtClose(KeyHandle);
1952 return Status;
1953 }
1954 }
1955 else
1956 {
1957 DPRINT1("SMSS: Failed querying safeboot option = %x\n", Status);
1958 }
1959 }
1960
1961 /* We are all done now */
1962 NtClose(KeyHandle);
1963 return STATUS_SUCCESS;
1964 }
1965
1966 NTSTATUS
1967 NTAPI
1968 SmpProcessFileRenames(VOID)
1969 {
1970 BOOLEAN OldState, HavePrivilege = FALSE;
1971 NTSTATUS Status;
1972 HANDLE FileHandle, OtherFileHandle;
1973 FILE_INFORMATION_CLASS InformationClass;
1974 OBJECT_ATTRIBUTES ObjectAttributes;
1975 IO_STATUS_BLOCK IoStatusBlock;
1976 UNICODE_STRING FileString;
1977 FILE_BASIC_INFORMATION BasicInfo;
1978 FILE_DISPOSITION_INFORMATION DeleteInformation;
1979 PFILE_RENAME_INFORMATION Buffer;
1980 PLIST_ENTRY Head, NextEntry;
1981 PSMP_REGISTRY_VALUE RegEntry;
1982 PWCHAR FileName;
1983 ULONG ValueLength, Length;
1984
1985 /* Give us access to restore any files we want */
1986 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &OldState);
1987 if (NT_SUCCESS(Status)) HavePrivilege = TRUE;
1988
1989 /* Process pending files to rename */
1990 Head = &SmpFileRenameList;
1991 while (!IsListEmpty(Head))
1992 {
1993 /* Get this entry */
1994 NextEntry = RemoveHeadList(Head);
1995 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
1996 DPRINT1("Processing PFRO: %wZ/%wZ\n", &RegEntry->Value, &RegEntry->Name);
1997
1998 /* Skip past the '@' marker */
1999 if (!(RegEntry->Value.Length) && (*RegEntry->Name.Buffer == L'@'))
2000 {
2001 RegEntry->Name.Length -= sizeof(UNICODE_NULL);
2002 RegEntry->Name.Buffer++;
2003 }
2004
2005 /* Open the file for delete access */
2006 InitializeObjectAttributes(&ObjectAttributes,
2007 &RegEntry->Name,
2008 OBJ_CASE_INSENSITIVE,
2009 NULL,
2010 NULL);
2011 Status = NtOpenFile(&OtherFileHandle,
2012 DELETE | SYNCHRONIZE,
2013 &ObjectAttributes,
2014 &IoStatusBlock,
2015 FILE_SHARE_READ | FILE_SHARE_WRITE,
2016 FILE_SYNCHRONOUS_IO_NONALERT);
2017 if (!NT_SUCCESS(Status)) goto Quickie;
2018
2019 /* Check if it's a rename or just a delete */
2020 ValueLength = RegEntry->Value.Length;
2021 if (!ValueLength)
2022 {
2023 /* Just a delete, set up the class, length and buffer */
2024 InformationClass = FileDispositionInformation;
2025 Length = sizeof(DeleteInformation);
2026 Buffer = (PFILE_RENAME_INFORMATION)&DeleteInformation;
2027
2028 /* Set the delete disposition */
2029 DeleteInformation.DeleteFile = TRUE;
2030 }
2031 else
2032 {
2033 /* This is a rename, setup the class and length */
2034 InformationClass = FileRenameInformation;
2035 Length = ValueLength + sizeof(FILE_RENAME_INFORMATION);
2036
2037 /* Skip past the special markers */
2038 FileName = RegEntry->Value.Buffer;
2039 if ((*FileName == L'!') || (*FileName == L'@'))
2040 {
2041 FileName++;
2042 Length -= sizeof(UNICODE_NULL);
2043 }
2044
2045 /* Now allocate the buffer for the rename information */
2046 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag, Length);
2047 if (Buffer)
2048 {
2049 /* Setup the buffer to point to the filename, and copy it */
2050 Buffer->RootDirectory = NULL;
2051 Buffer->FileNameLength = Length - sizeof(FILE_RENAME_INFORMATION);
2052 Buffer->ReplaceIfExists = FileName != RegEntry->Value.Buffer;
2053 RtlCopyMemory(Buffer->FileName, FileName, Buffer->FileNameLength);
2054 }
2055 else
2056 {
2057 /* Fail */
2058 Status = STATUS_NO_MEMORY;
2059 }
2060 }
2061
2062 /* Check if everything is okay till here */
2063 if (NT_SUCCESS(Status))
2064 {
2065 /* Now either rename or delete the file as requested */
2066 Status = NtSetInformationFile(OtherFileHandle,
2067 &IoStatusBlock,
2068 Buffer,
2069 Length,
2070 InformationClass);
2071
2072 /* Check if we seem to have failed because the file was readonly */
2073 if ((NT_SUCCESS(Status) &&
2074 (InformationClass == FileRenameInformation) &&
2075 (Status == STATUS_OBJECT_NAME_COLLISION) &&
2076 (Buffer->ReplaceIfExists)))
2077 {
2078 /* Open the file for write attribute access this time... */
2079 DPRINT1("\nSMSS: %wZ => %wZ failed - Status == %x, Possible readonly target\n",
2080 &RegEntry->Name,
2081 &RegEntry->Value,
2082 STATUS_OBJECT_NAME_COLLISION);
2083 FileString.Length = RegEntry->Value.Length - sizeof(WCHAR);
2084 FileString.MaximumLength = RegEntry->Value.MaximumLength - sizeof(WCHAR);
2085 FileString.Buffer = FileName;
2086 InitializeObjectAttributes(&ObjectAttributes,
2087 &FileString,
2088 OBJ_CASE_INSENSITIVE,
2089 NULL,
2090 NULL);
2091 Status = NtOpenFile(&FileHandle,
2092 FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
2093 &ObjectAttributes,
2094 &IoStatusBlock,
2095 FILE_SHARE_READ | FILE_SHARE_WRITE,
2096 FILE_SYNCHRONOUS_IO_NONALERT);
2097 if (!NT_SUCCESS(Status))
2098 {
2099 /* That didn't work, so bail out */
2100 DPRINT1(" SMSS: Open Existing file Failed - Status == %x\n",
2101 Status);
2102 }
2103 else
2104 {
2105 /* Now remove the read-only attribute from the file */
2106 DPRINT1(" SMSS: Open Existing Success\n");
2107 RtlZeroMemory(&BasicInfo, sizeof(BasicInfo));
2108 BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
2109 Status = NtSetInformationFile(FileHandle,
2110 &IoStatusBlock,
2111 &BasicInfo,
2112 sizeof(BasicInfo),
2113 FileBasicInformation);
2114 NtClose(FileHandle);
2115 if (!NT_SUCCESS(Status))
2116 {
2117 /* That didn't work, bail out */
2118 DPRINT1(" SMSS: Set To NORMAL Failed - Status == %x\n",
2119 Status);
2120 }
2121 else
2122 {
2123 /* Now that the file is no longer read-only, delete! */
2124 DPRINT1(" SMSS: Set To NORMAL OK\n");
2125 Status = NtSetInformationFile(OtherFileHandle,
2126 &IoStatusBlock,
2127 Buffer,
2128 Length,
2129 FileRenameInformation);
2130 if (!NT_SUCCESS(Status))
2131 {
2132 /* That failed too! */
2133 DPRINT1(" SMSS: Re-Rename Failed - Status == %x\n",
2134 Status);
2135 }
2136 else
2137 {
2138 /* Everything ok */
2139 DPRINT1(" SMSS: Re-Rename Worked OK\n");
2140 }
2141 }
2142 }
2143 }
2144 }
2145
2146 /* Close the file handle and check the operation result */
2147 NtClose(OtherFileHandle);
2148 Quickie:
2149 if (!NT_SUCCESS(Status))
2150 {
2151 /* We totally failed */
2152 DPRINT1("SMSS: %wZ => %wZ failed - Status == %x\n",
2153 &RegEntry->Name, &RegEntry->Value, Status);
2154 }
2155 else if (RegEntry->Value.Length)
2156 {
2157 /* We succeed with a rename */
2158 DPRINT1("SMSS: %wZ (renamed to) %wZ\n", &RegEntry->Name, &RegEntry->Value);
2159 }
2160 else
2161 {
2162 /* We suceeded with a delete */
2163 DPRINT1("SMSS: %wZ (deleted)\n", &RegEntry->Name);
2164 }
2165
2166 /* Now free this entry and keep going */
2167 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
2168 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
2169 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
2170 }
2171
2172 /* Put back the restore privilege if we had requested it, and return */
2173 if (HavePrivilege) RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, FALSE, FALSE, &OldState);
2174 return Status;
2175 }
2176
2177 NTSTATUS
2178 NTAPI
2179 SmpLoadDataFromRegistry(OUT PUNICODE_STRING InitialCommand)
2180 {
2181 NTSTATUS Status;
2182 PLIST_ENTRY Head, NextEntry;
2183 PSMP_REGISTRY_VALUE RegEntry;
2184 PVOID OriginalEnvironment;
2185 ULONG MuSessionId = 0;
2186 OBJECT_ATTRIBUTES ObjectAttributes;
2187 HANDLE KeyHandle;
2188 UNICODE_STRING DestinationString;
2189
2190 /* Initialize the keywords we'll be looking for */
2191 RtlInitUnicodeString(&SmpDebugKeyword, L"debug");
2192 RtlInitUnicodeString(&SmpASyncKeyword, L"async");
2193 RtlInitUnicodeString(&SmpAutoChkKeyword, L"autocheck");
2194
2195 /* Initialize all the registry-associated list heads */
2196 InitializeListHead(&SmpBootExecuteList);
2197 InitializeListHead(&SmpSetupExecuteList);
2198 InitializeListHead(&SmpPagingFileList);
2199 InitializeListHead(&SmpDosDevicesList);
2200 InitializeListHead(&SmpFileRenameList);
2201 InitializeListHead(&SmpKnownDllsList);
2202 InitializeListHead(&SmpExcludeKnownDllsList);
2203 InitializeListHead(&SmpSubSystemList);
2204 InitializeListHead(&SmpSubSystemsToLoad);
2205 InitializeListHead(&SmpSubSystemsToDefer);
2206 InitializeListHead(&SmpExecuteList);
2207 SmpPagingFileInitialize();
2208
2209 /* Initialize the SMSS environment */
2210 Status = RtlCreateEnvironment(TRUE, &SmpDefaultEnvironment);
2211 if (!NT_SUCCESS(Status))
2212 {
2213 /* Fail if there was a problem */
2214 DPRINT1("SMSS: Unable to allocate default environment - Status == %X\n",
2215 Status);
2216 SMSS_CHECKPOINT(RtlCreateEnvironment, Status);
2217 return Status;
2218 }
2219
2220 /* Check if we were booted in PE mode (LiveCD should have this) */
2221 RtlInitUnicodeString(&DestinationString,
2222 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
2223 L"Control\\MiniNT");
2224 InitializeObjectAttributes(&ObjectAttributes,
2225 &DestinationString,
2226 OBJ_CASE_INSENSITIVE,
2227 NULL,
2228 NULL);
2229 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
2230 if (NT_SUCCESS(Status))
2231 {
2232 /* If the key exists, we were */
2233 NtClose(KeyHandle);
2234 MiniNTBoot = TRUE;
2235 }
2236
2237 /* Print out if this is the case */
2238 if (MiniNTBoot) DPRINT1("SMSS: !!! MiniNT Boot !!!\n");
2239
2240 /* Open the environment key to see if we are booted in safe mode */
2241 RtlInitUnicodeString(&DestinationString,
2242 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
2243 L"Control\\Session Manager\\Environment");
2244 InitializeObjectAttributes(&ObjectAttributes,
2245 &DestinationString,
2246 OBJ_CASE_INSENSITIVE,
2247 NULL,
2248 NULL);
2249 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
2250 if (NT_SUCCESS(Status))
2251 {
2252 /* Delete the value if we found it */
2253 RtlInitUnicodeString(&DestinationString, L"SAFEBOOT_OPTION");
2254 NtDeleteValueKey(KeyHandle, &DestinationString);
2255 NtClose(KeyHandle);
2256 }
2257
2258 /* Switch environments, then query the registry for all needed settings */
2259 OriginalEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
2260 NtCurrentPeb()->ProcessParameters->Environment = SmpDefaultEnvironment;
2261 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
2262 L"Session Manager",
2263 SmpRegistryConfigurationTable,
2264 NULL,
2265 NULL);
2266 SmpDefaultEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
2267 NtCurrentPeb()->ProcessParameters->Environment = OriginalEnvironment;
2268 if (!NT_SUCCESS(Status))
2269 {
2270 /* We failed somewhere in registry initialization, which is bad... */
2271 DPRINT1("SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status);
2272 SMSS_CHECKPOINT(RtlQueryRegistryValues, Status);
2273 return Status;
2274 }
2275
2276 /* Now we can start acting on the registry settings. First to DOS devices */
2277 Status = SmpInitializeDosDevices();
2278 if (!NT_SUCCESS(Status))
2279 {
2280 /* Failed */
2281 DPRINT1("SMSS: Unable to initialize DosDevices configuration - Status == %lx\n",
2282 Status);
2283 SMSS_CHECKPOINT(SmpInitializeDosDevices, Status);
2284 return Status;
2285 }
2286
2287 /* Next create the session directory... */
2288 RtlInitUnicodeString(&DestinationString, L"\\Sessions");
2289 InitializeObjectAttributes(&ObjectAttributes,
2290 &DestinationString,
2291 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
2292 NULL,
2293 SmpPrimarySecurityDescriptor);
2294 Status = NtCreateDirectoryObject(&SmpSessionsObjectDirectory,
2295 DIRECTORY_ALL_ACCESS,
2296 &ObjectAttributes);
2297 if (!NT_SUCCESS(Status))
2298 {
2299 /* Fail */
2300 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
2301 &DestinationString, Status);
2302 SMSS_CHECKPOINT(NtCreateDirectoryObject, Status);
2303 return Status;
2304 }
2305
2306 /* Next loop all the boot execute binaries */
2307 Head = &SmpBootExecuteList;
2308 while (!IsListEmpty(Head))
2309 {
2310 /* Remove each one from the list */
2311 NextEntry = RemoveHeadList(Head);
2312
2313 /* Execute it */
2314 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
2315 SmpExecuteCommand(&RegEntry->Name, 0, NULL, 0);
2316
2317 /* And free it */
2318 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
2319 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
2320 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
2321 }
2322
2323 /* Now do any pending file rename operations... */
2324 if (!MiniNTBoot) SmpProcessFileRenames();
2325
2326 /* And initialize known DLLs... */
2327 Status = SmpInitializeKnownDlls();
2328 if (!NT_SUCCESS(Status))
2329 {
2330 /* Fail if that didn't work */
2331 DPRINT1("SMSS: Unable to initialize KnownDll configuration - Status == %lx\n",
2332 Status);
2333 SMSS_CHECKPOINT(SmpInitializeKnownDlls, Status);
2334 return Status;
2335 }
2336
2337 /* Loop every page file */
2338 Head = &SmpPagingFileList;
2339 while (!IsListEmpty(Head))
2340 {
2341 /* Remove each one from the list */
2342 NextEntry = RemoveHeadList(Head);
2343
2344 /* Create the descriptor for it */
2345 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
2346 SmpCreatePagingFileDescriptor(&RegEntry->Name);
2347
2348 /* And free it */
2349 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
2350 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
2351 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
2352 }
2353
2354 /* Now create all the paging files for the descriptors that we have */
2355 SmpCreatePagingFiles();
2356
2357 /* Tell Cm it's now safe to fully enable write access to the registry */
2358 NtInitializeRegistry(CM_BOOT_FLAG_SMSS);
2359
2360 /* Create all the system-based environment variables for later inheriting */
2361 Status = SmpCreateDynamicEnvironmentVariables();
2362 if (!NT_SUCCESS(Status))
2363 {
2364 /* Handle failure */
2365 SMSS_CHECKPOINT(SmpCreateDynamicEnvironmentVariables, Status);
2366 return Status;
2367 }
2368
2369 /* And finally load all the subsytems for our first session! */
2370 Status = SmpLoadSubSystemsForMuSession(&MuSessionId,
2371 &SmpWindowsSubSysProcessId,
2372 InitialCommand);
2373 ASSERT(MuSessionId == 0);
2374 if (!NT_SUCCESS(Status)) SMSS_CHECKPOINT(SmpLoadSubSystemsForMuSession, Status);
2375 return Status;
2376 }
2377
2378 NTSTATUS
2379 NTAPI
2380 SmpInit(IN PUNICODE_STRING InitialCommand,
2381 OUT PHANDLE ProcessHandle)
2382 {
2383 NTSTATUS Status, Status2;
2384 OBJECT_ATTRIBUTES ObjectAttributes;
2385 UNICODE_STRING PortName, EventName;
2386 HANDLE EventHandle, PortHandle;
2387 ULONG HardErrorMode;
2388
2389 /* Create the SMSS Heap */
2390 SmBaseTag = RtlCreateTagHeap(RtlGetProcessHeap(),
2391 0,
2392 L"SMSS!",
2393 L"INIT");
2394 SmpHeap = RtlGetProcessHeap();
2395
2396 /* Enable hard errors */
2397 HardErrorMode = TRUE;
2398 NtSetInformationProcess(NtCurrentProcess(),
2399 ProcessDefaultHardErrorMode,
2400 &HardErrorMode,
2401 sizeof(HardErrorMode));
2402
2403 /* Initialize the subsystem list and the session list, plus their locks */
2404 RtlInitializeCriticalSection(&SmpKnownSubSysLock);
2405 InitializeListHead(&SmpKnownSubSysHead);
2406 RtlInitializeCriticalSection(&SmpSessionListLock);
2407 InitializeListHead(&SmpSessionListHead);
2408
2409 /* Initialize the process list */
2410 InitializeListHead(&NativeProcessList);
2411
2412 /* Initialize session parameters */
2413 SmpNextSessionId = 1;
2414 SmpNextSessionIdScanMode = 0;
2415 SmpDbgSsLoaded = FALSE;
2416
2417 /* Create the initial security descriptors */
2418 Status = SmpCreateSecurityDescriptors(TRUE);
2419 if (!NT_SUCCESS(Status))
2420 {
2421 /* Fail */
2422 SMSS_CHECKPOINT(SmpCreateSecurityDescriptors, Status);
2423 return Status;
2424 }
2425
2426 /* Initialize subsystem names */
2427 RtlInitUnicodeString(&SmpSubsystemName, L"NT-Session Manager");
2428 RtlInitUnicodeString(&PosixName, L"POSIX");
2429 RtlInitUnicodeString(&Os2Name, L"OS2");
2430
2431 /* Create the SM API Port */
2432 RtlInitUnicodeString(&PortName, L"\\SmApiPort");
2433 InitializeObjectAttributes(&ObjectAttributes, &PortName, 0, NULL, NULL);
2434 Status = NtCreatePort(&PortHandle,
2435 &ObjectAttributes,
2436 sizeof(SB_CONNECTION_INFO),
2437 sizeof(SM_API_MSG),
2438 sizeof(SB_API_MSG) * 32);
2439 ASSERT(NT_SUCCESS(Status));
2440 SmpDebugPort = PortHandle;
2441
2442 /* Create two SM API threads */
2443 Status = RtlCreateUserThread(NtCurrentProcess(),
2444 NULL,
2445 FALSE,
2446 0,
2447 0,
2448 0,
2449 SmpApiLoop,
2450 PortHandle,
2451 NULL,
2452 NULL);
2453 ASSERT(NT_SUCCESS(Status));
2454 Status = RtlCreateUserThread(NtCurrentProcess(),
2455 NULL,
2456 FALSE,
2457 0,
2458 0,
2459 0,
2460 SmpApiLoop,
2461 PortHandle,
2462 NULL,
2463 NULL);
2464 ASSERT(NT_SUCCESS(Status));
2465
2466 /* Create the write event that autochk can set after running */
2467 RtlInitUnicodeString(&EventName, L"\\Device\\VolumesSafeForWriteAccess");
2468 InitializeObjectAttributes(&ObjectAttributes,
2469 &EventName,
2470 OBJ_PERMANENT,
2471 NULL,
2472 NULL);
2473 Status2 = NtCreateEvent(&EventHandle,
2474 EVENT_ALL_ACCESS,
2475 &ObjectAttributes,
2476 0,
2477 0);
2478 if (!NT_SUCCESS(Status2))
2479 {
2480 /* Should never really fail */
2481 DPRINT1("SMSS: Unable to create %wZ event - Status == %lx\n",
2482 &EventName, Status2);
2483 ASSERT(NT_SUCCESS(Status2));
2484 }
2485
2486 /* Now initialize everything else based on the registry parameters */
2487 Status = SmpLoadDataFromRegistry(InitialCommand);
2488 if (NT_SUCCESS(Status))
2489 {
2490 /* Autochk should've run now. Set the event and save the CSRSS handle */
2491 *ProcessHandle = SmpWindowsSubSysProcess;
2492 NtSetEvent(EventHandle, 0);
2493 NtClose(EventHandle);
2494 }
2495
2496 /* All done */
2497 return Status;
2498 }