Synchronize with trunk revision 59781.
[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: %d\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: %d\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 0
1529 if (!NT_SUCCESS(Status))
1530 {
1531 /* Checksum failed, so don't even try going further -- kill SMSS */
1532 RtlInitUnicodeString(&ErrorResponse,
1533 L"Verification of a KnownDLL failed.");
1534 ErrorParameters[0] = (ULONG)&ErrorResponse;
1535 ErrorParameters[1] = Status;
1536 ErrorParameters[2] = (ULONG)&RegEntry->Value;
1537 SmpTerminate(ErrorParameters, 5, RTL_NUMBER_OF(ErrorParameters));
1538 }
1539 else
1540 if (!(ImageCharacteristics & IMAGE_FILE_DLL))
1541 {
1542 /* An invalid known DLL entry will also kill SMSS */
1543 RtlInitUnicodeString(&ErrorResponse,
1544 L"Non-DLL file included in KnownDLL list.");
1545 ErrorParameters[0] = (ULONG)&ErrorResponse;
1546 ErrorParameters[1] = STATUS_INVALID_IMPORT_OF_NON_DLL;
1547 ErrorParameters[2] = (ULONG)&RegEntry->Value;
1548 SmpTerminate(ErrorParameters, 5, RTL_NUMBER_OF(ErrorParameters));
1549 }
1550 #endif
1551
1552 /* Temporarily hack the SD to use a default DACL for this section */
1553 if (SmpLiberalSecurityDescriptor)
1554 {
1555 OldFlag = SmpLiberalSecurityDescriptor->Control;
1556 SmpLiberalSecurityDescriptor->Control |= SE_DACL_DEFAULTED;
1557 }
1558
1559 /* Create the section for this known DLL */
1560 InitializeObjectAttributes(&ObjectAttributes,
1561 &RegEntry->Value,
1562 OBJ_PERMANENT,
1563 DirHandle,
1564 SmpLiberalSecurityDescriptor)
1565 Status = NtCreateSection(&SectionHandle,
1566 SECTION_ALL_ACCESS,
1567 &ObjectAttributes,
1568 0,
1569 PAGE_EXECUTE,
1570 SEC_IMAGE,
1571 FileHandle);
1572
1573 /* Undo the hack */
1574 if (SmpLiberalSecurityDescriptor) SmpLiberalSecurityDescriptor->Control = OldFlag;
1575
1576 /* Check if we created the section okay */
1577 if (NT_SUCCESS(Status))
1578 {
1579 /* We can close it now, since it's marked permanent */
1580 Status1 = NtClose(SectionHandle);
1581 ASSERT(NT_SUCCESS(Status1));
1582 }
1583 else
1584 {
1585 /* If we couldn't make it "known", that's fine and keep going */
1586 DPRINT1("SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n",
1587 &RegEntry->Value, Status);
1588 }
1589
1590 /* Close the file since we can move on to the next one */
1591 Status1 = NtClose(FileHandle);
1592 ASSERT(NT_SUCCESS(Status1));
1593
1594 /* Go to the next entry */
1595 NextEntry = NextEntry->Flink;
1596 }
1597
1598 Quickie:
1599 /* Close both handles and free the NT path buffer */
1600 if (DirHandle)
1601 {
1602 Status1 = NtClose(DirHandle);
1603 ASSERT(NT_SUCCESS(Status1));
1604 }
1605 if (DirFileHandle)
1606 {
1607 Status1 = NtClose(DirFileHandle);
1608 ASSERT(NT_SUCCESS(Status1));
1609 }
1610 if (NtPath.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath.Buffer);
1611 return Status;
1612 }
1613
1614 NTSTATUS
1615 NTAPI
1616 SmpInitializeKnownDlls(VOID)
1617 {
1618 NTSTATUS Status;
1619 PSMP_REGISTRY_VALUE RegEntry;
1620 UNICODE_STRING DestinationString;
1621 PLIST_ENTRY Head, NextEntry;
1622
1623 /* Call the internal function */
1624 RtlInitUnicodeString(&DestinationString, L"\\KnownDlls");
1625 Status = SmpInitializeKnownDllsInternal(&DestinationString, &SmpKnownDllPath);
1626
1627 /* Wipe out the list regardless of success */
1628 Head = &SmpKnownDllsList;
1629 while (!IsListEmpty(Head))
1630 {
1631 /* Remove this entry */
1632 NextEntry = RemoveHeadList(Head);
1633
1634 /* Free it */
1635 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
1636 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
1637 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
1638 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
1639 }
1640
1641 /* All done */
1642 return Status;
1643 }
1644
1645 NTSTATUS
1646 NTAPI
1647 SmpCreateDynamicEnvironmentVariables(VOID)
1648 {
1649 NTSTATUS Status;
1650 SYSTEM_BASIC_INFORMATION BasicInfo;
1651 SYSTEM_PROCESSOR_INFORMATION ProcessorInfo;
1652 OBJECT_ATTRIBUTES ObjectAttributes;
1653 UNICODE_STRING ValueName, DestinationString;
1654 HANDLE KeyHandle, KeyHandle2;
1655 ULONG ResultLength;
1656 PWCHAR ArchName;
1657 WCHAR ValueBuffer[512], ValueBuffer2[512];
1658 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
1659 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo2 = (PVOID)ValueBuffer2;
1660
1661 /* Get system basic information -- we'll need the CPU count */
1662 Status = NtQuerySystemInformation(SystemBasicInformation,
1663 &BasicInfo,
1664 sizeof(BasicInfo),
1665 NULL);
1666 if (!NT_SUCCESS(Status))
1667 {
1668 /* Bail out on failure */
1669 DPRINT1("SMSS: Unable to query system basic information - %x\n", Status);
1670 return Status;
1671 }
1672
1673 /* Get the processor information, we'll query a bunch of revision info */
1674 Status = NtQuerySystemInformation(SystemProcessorInformation,
1675 &ProcessorInfo,
1676 sizeof(ProcessorInfo),
1677 NULL);
1678 if (!NT_SUCCESS(Status))
1679 {
1680 /* Bail out on failure */
1681 DPRINT1("SMSS: Unable to query system processor information - %x\n", Status);
1682 return Status;
1683 }
1684
1685 /* We'll be writing all these environment variables over here */
1686 RtlInitUnicodeString(&DestinationString,
1687 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
1688 L"Control\\Session Manager\\Environment");
1689 InitializeObjectAttributes(&ObjectAttributes,
1690 &DestinationString,
1691 OBJ_CASE_INSENSITIVE,
1692 NULL,
1693 NULL);
1694 Status = NtOpenKey(&KeyHandle, GENERIC_WRITE, &ObjectAttributes);
1695 if (!NT_SUCCESS(Status))
1696 {
1697 /* Bail out on failure */
1698 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString, Status);
1699 return Status;
1700 }
1701
1702 /* First let's write the OS variable */
1703 RtlInitUnicodeString(&ValueName, L"OS");
1704 DPRINT("Setting %wZ to %S\n", &ValueName, L"Windows_NT");
1705 Status = NtSetValueKey(KeyHandle,
1706 &ValueName,
1707 0,
1708 REG_SZ,
1709 L"Windows_NT",
1710 wcslen(L"Windows_NT") * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1711 if (!NT_SUCCESS(Status))
1712 {
1713 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1714 &ValueName, Status);
1715 NtClose(KeyHandle);
1716 return Status;
1717 }
1718
1719 /* Next, let's write the CPU architecture variable */
1720 RtlInitUnicodeString(&ValueName, L"PROCESSOR_ARCHITECTURE");
1721 switch (ProcessorInfo.ProcessorArchitecture)
1722 {
1723 /* Pick the correct string that matches the architecture */
1724 case PROCESSOR_ARCHITECTURE_INTEL:
1725 ArchName = L"x86";
1726 break;
1727
1728 case PROCESSOR_ARCHITECTURE_AMD64:
1729 ArchName = L"AMD64";
1730 break;
1731
1732 case PROCESSOR_ARCHITECTURE_IA64:
1733 ArchName = L"IA64";
1734 break;
1735
1736 default:
1737 ArchName = L"Unknown";
1738 break;
1739 }
1740
1741 /* Set it */
1742 DPRINT("Setting %wZ to %S\n", &ValueName, ArchName);
1743 Status = NtSetValueKey(KeyHandle,
1744 &ValueName,
1745 0,
1746 REG_SZ,
1747 ArchName,
1748 wcslen(ArchName) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1749 if (!NT_SUCCESS(Status))
1750 {
1751 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1752 &ValueName, Status);
1753 NtClose(KeyHandle);
1754 return Status;
1755 }
1756
1757 /* And now let's write the processor level */
1758 RtlInitUnicodeString(&ValueName, L"PROCESSOR_LEVEL");
1759 swprintf(ValueBuffer, L"%u", ProcessorInfo.ProcessorLevel);
1760 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
1761 Status = NtSetValueKey(KeyHandle,
1762 &ValueName,
1763 0,
1764 REG_SZ,
1765 ValueBuffer,
1766 wcslen(ValueBuffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1767 if (!NT_SUCCESS(Status))
1768 {
1769 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1770 &ValueName, Status);
1771 NtClose(KeyHandle);
1772 return Status;
1773 }
1774
1775 /* Now open the hardware CPU key */
1776 RtlInitUnicodeString(&DestinationString,
1777 L"\\Registry\\Machine\\Hardware\\Description\\System\\"
1778 L"CentralProcessor\\0");
1779 InitializeObjectAttributes(&ObjectAttributes,
1780 &DestinationString,
1781 OBJ_CASE_INSENSITIVE,
1782 NULL,
1783 NULL);
1784 Status = NtOpenKey(&KeyHandle2, KEY_READ, &ObjectAttributes);
1785 if (!NT_SUCCESS(Status))
1786 {
1787 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString, Status);
1788 NtClose(KeyHandle);
1789 return Status;
1790 }
1791
1792 /* So that we can read the identifier out of it... */
1793 RtlInitUnicodeString(&ValueName, L"Identifier");
1794 Status = NtQueryValueKey(KeyHandle2,
1795 &ValueName,
1796 KeyValuePartialInformation,
1797 PartialInfo,
1798 sizeof(ValueBuffer),
1799 &ResultLength);
1800 if (!NT_SUCCESS(Status))
1801 {
1802 NtClose(KeyHandle2);
1803 NtClose(KeyHandle);
1804 DPRINT1("SMSS: Unable to read %wZ\\%wZ - %x\n",
1805 &DestinationString, &ValueName, Status);
1806 return Status;
1807 }
1808
1809 /* As well as the vendor... */
1810 RtlInitUnicodeString(&ValueName, L"VendorIdentifier");
1811 Status = NtQueryValueKey(KeyHandle2,
1812 &ValueName,
1813 KeyValuePartialInformation,
1814 PartialInfo2,
1815 sizeof(ValueBuffer2),
1816 &ResultLength);
1817 NtClose(KeyHandle2);
1818 if (NT_SUCCESS(Status))
1819 {
1820 /* To combine it into a single string */
1821 swprintf((PWCHAR)PartialInfo->Data + wcslen((PWCHAR)PartialInfo->Data),
1822 L", %ws",
1823 PartialInfo2->Data);
1824 }
1825
1826 /* So that we can set this as the PROCESSOR_IDENTIFIER variable */
1827 RtlInitUnicodeString(&ValueName, L"PROCESSOR_IDENTIFIER");
1828 DPRINT("Setting %wZ to %S\n", &ValueName, PartialInfo->Data);
1829 Status = NtSetValueKey(KeyHandle,
1830 &ValueName,
1831 0,
1832 REG_SZ,
1833 PartialInfo->Data,
1834 wcslen((PWCHAR)PartialInfo->Data) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1835 if (!NT_SUCCESS(Status))
1836 {
1837 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1838 &ValueName, Status);
1839 NtClose(KeyHandle);
1840 return Status;
1841 }
1842
1843 /* Now let's get the processor architecture */
1844 RtlInitUnicodeString(&ValueName, L"PROCESSOR_REVISION");
1845 switch (ProcessorInfo.ProcessorArchitecture)
1846 {
1847 /* Check if this is an older Intel CPU */
1848 case PROCESSOR_ARCHITECTURE_INTEL:
1849 if ((ProcessorInfo.ProcessorRevision >> 8) == 0xFF)
1850 {
1851 /* These guys used a revision + stepping, so get the rev only */
1852 swprintf(ValueBuffer, L"%02x", ProcessorInfo.ProcessorRevision & 0xFF);
1853 _wcsupr(ValueBuffer);
1854 break;
1855 }
1856
1857 /* Modern Intel, as well as 64-bit CPUs use a revision without stepping */
1858 case PROCESSOR_ARCHITECTURE_IA64:
1859 case PROCESSOR_ARCHITECTURE_AMD64:
1860 swprintf(ValueBuffer, L"%04x", ProcessorInfo.ProcessorRevision);
1861 break;
1862
1863 /* And anything else we'll just read the whole revision identifier */
1864 default:
1865 swprintf(ValueBuffer, L"%u", ProcessorInfo.ProcessorRevision);
1866 break;
1867 }
1868
1869 /* Write the revision to the registry */
1870 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
1871 Status = NtSetValueKey(KeyHandle,
1872 &ValueName,
1873 0,
1874 REG_SZ,
1875 ValueBuffer,
1876 wcslen(ValueBuffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1877 if (!NT_SUCCESS(Status))
1878 {
1879 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1880 &ValueName, Status);
1881 NtClose(KeyHandle);
1882 return Status;
1883 }
1884
1885 /* And finally, write the number of CPUs */
1886 RtlInitUnicodeString(&ValueName, L"NUMBER_OF_PROCESSORS");
1887 swprintf(ValueBuffer, L"%u", BasicInfo.NumberOfProcessors);
1888 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
1889 Status = NtSetValueKey(KeyHandle,
1890 &ValueName,
1891 0,
1892 REG_SZ,
1893 ValueBuffer,
1894 wcslen(ValueBuffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1895 if (!NT_SUCCESS(Status))
1896 {
1897 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1898 &ValueName, Status);
1899 NtClose(KeyHandle);
1900 return Status;
1901 }
1902
1903 /* Now we need to write the safeboot option key in a different format */
1904 RtlInitUnicodeString(&DestinationString,
1905 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
1906 L"Control\\Safeboot\\Option");
1907 InitializeObjectAttributes(&ObjectAttributes,
1908 &DestinationString,
1909 OBJ_CASE_INSENSITIVE,
1910 NULL,
1911 NULL);
1912 Status = NtOpenKey(&KeyHandle2, KEY_ALL_ACCESS, &ObjectAttributes);
1913 if (NT_SUCCESS(Status))
1914 {
1915 /* This was indeed a safeboot, so check what kind of safeboot it was */
1916 RtlInitUnicodeString(&ValueName, L"OptionValue");
1917 Status = NtQueryValueKey(KeyHandle2,
1918 &ValueName,
1919 KeyValuePartialInformation,
1920 PartialInfo,
1921 sizeof(ValueBuffer),
1922 &ResultLength);
1923 NtClose(KeyHandle2);
1924 if (NT_SUCCESS(Status))
1925 {
1926 /* Convert from the integer value to the correct specifier */
1927 RtlInitUnicodeString(&ValueName, L"SAFEBOOT_OPTION");
1928 switch (*(PULONG)PartialInfo->Data)
1929 {
1930 case 1:
1931 wcscpy(ValueBuffer, L"MINIMAL");
1932 break;
1933 case 2:
1934 wcscpy(ValueBuffer, L"NETWORK");
1935 break;
1936 case 3:
1937 wcscpy(ValueBuffer, L"DSREPAIR");
1938 break;
1939 }
1940
1941 /* And write it in the environment! */
1942 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
1943 Status = NtSetValueKey(KeyHandle,
1944 &ValueName,
1945 0,
1946 REG_SZ,
1947 ValueBuffer,
1948 wcslen(ValueBuffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1949 if (!NT_SUCCESS(Status))
1950 {
1951 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1952 &ValueName, Status);
1953 NtClose(KeyHandle);
1954 return Status;
1955 }
1956 }
1957 else
1958 {
1959 DPRINT1("SMSS: Failed querying safeboot option = %x\n", Status);
1960 }
1961 }
1962
1963 /* We are all done now */
1964 NtClose(KeyHandle);
1965 return STATUS_SUCCESS;
1966 }
1967
1968 NTSTATUS
1969 NTAPI
1970 SmpProcessFileRenames(VOID)
1971 {
1972 BOOLEAN OldState, HavePrivilege = FALSE;
1973 NTSTATUS Status;
1974 HANDLE FileHandle, OtherFileHandle;
1975 FILE_INFORMATION_CLASS InformationClass;
1976 OBJECT_ATTRIBUTES ObjectAttributes;
1977 IO_STATUS_BLOCK IoStatusBlock;
1978 UNICODE_STRING FileString;
1979 FILE_BASIC_INFORMATION BasicInfo;
1980 FILE_DISPOSITION_INFORMATION DeleteInformation;
1981 PFILE_RENAME_INFORMATION Buffer;
1982 PLIST_ENTRY Head, NextEntry;
1983 PSMP_REGISTRY_VALUE RegEntry;
1984 PWCHAR FileName;
1985 ULONG ValueLength, Length;
1986
1987 /* Give us access to restore any files we want */
1988 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &OldState);
1989 if (NT_SUCCESS(Status)) HavePrivilege = TRUE;
1990
1991 /* Process pending files to rename */
1992 Head = &SmpFileRenameList;
1993 while (!IsListEmpty(Head))
1994 {
1995 /* Get this entry */
1996 NextEntry = RemoveHeadList(Head);
1997 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
1998 DPRINT1("Processing PFRO: %wZ/%wZ\n", &RegEntry->Value, &RegEntry->Name);
1999
2000 /* Skip past the '@' marker */
2001 if (!(RegEntry->Value.Length) && (*RegEntry->Name.Buffer == L'@'))
2002 {
2003 RegEntry->Name.Length -= sizeof(UNICODE_NULL);
2004 RegEntry->Name.Buffer++;
2005 }
2006
2007 /* Open the file for delete access */
2008 InitializeObjectAttributes(&ObjectAttributes,
2009 &RegEntry->Name,
2010 OBJ_CASE_INSENSITIVE,
2011 NULL,
2012 NULL);
2013 Status = NtOpenFile(&OtherFileHandle,
2014 DELETE | SYNCHRONIZE,
2015 &ObjectAttributes,
2016 &IoStatusBlock,
2017 FILE_SHARE_READ | FILE_SHARE_WRITE,
2018 FILE_SYNCHRONOUS_IO_NONALERT);
2019 if (!NT_SUCCESS(Status)) goto Quickie;
2020
2021 /* Check if it's a rename or just a delete */
2022 ValueLength = RegEntry->Value.Length;
2023 if (!ValueLength)
2024 {
2025 /* Just a delete, set up the class, length and buffer */
2026 InformationClass = FileDispositionInformation;
2027 Length = sizeof(DeleteInformation);
2028 Buffer = (PFILE_RENAME_INFORMATION)&DeleteInformation;
2029
2030 /* Set the delete disposition */
2031 DeleteInformation.DeleteFile = TRUE;
2032 }
2033 else
2034 {
2035 /* This is a rename, setup the class and length */
2036 InformationClass = FileRenameInformation;
2037 Length = ValueLength + sizeof(FILE_RENAME_INFORMATION);
2038
2039 /* Skip past the special markers */
2040 FileName = RegEntry->Value.Buffer;
2041 if ((*FileName == L'!') || (*FileName == L'@'))
2042 {
2043 FileName++;
2044 Length -= sizeof(UNICODE_NULL);
2045 }
2046
2047 /* Now allocate the buffer for the rename information */
2048 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag, Length);
2049 if (Buffer)
2050 {
2051 /* Setup the buffer to point to the filename, and copy it */
2052 Buffer->RootDirectory = NULL;
2053 Buffer->FileNameLength = Length - sizeof(FILE_RENAME_INFORMATION);
2054 Buffer->ReplaceIfExists = FileName != RegEntry->Value.Buffer;
2055 RtlCopyMemory(Buffer->FileName, FileName, Buffer->FileNameLength);
2056 }
2057 else
2058 {
2059 /* Fail */
2060 Status = STATUS_NO_MEMORY;
2061 }
2062 }
2063
2064 /* Check if everything is okay till here */
2065 if (NT_SUCCESS(Status))
2066 {
2067 /* Now either rename or delete the file as requested */
2068 Status = NtSetInformationFile(OtherFileHandle,
2069 &IoStatusBlock,
2070 Buffer,
2071 Length,
2072 InformationClass);
2073
2074 /* Check if we seem to have failed because the file was readonly */
2075 if ((NT_SUCCESS(Status) &&
2076 (InformationClass == FileRenameInformation) &&
2077 (Status == STATUS_OBJECT_NAME_COLLISION) &&
2078 (Buffer->ReplaceIfExists)))
2079 {
2080 /* Open the file for write attribute access this time... */
2081 DPRINT1("\nSMSS: %wZ => %wZ failed - Status == %x, Possible readonly target\n",
2082 &RegEntry->Name,
2083 &RegEntry->Value,
2084 STATUS_OBJECT_NAME_COLLISION);
2085 FileString.Length = RegEntry->Value.Length - sizeof(WCHAR);
2086 FileString.MaximumLength = RegEntry->Value.MaximumLength - sizeof(WCHAR);
2087 FileString.Buffer = FileName;
2088 InitializeObjectAttributes(&ObjectAttributes,
2089 &FileString,
2090 OBJ_CASE_INSENSITIVE,
2091 NULL,
2092 NULL);
2093 Status = NtOpenFile(&FileHandle,
2094 FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
2095 &ObjectAttributes,
2096 &IoStatusBlock,
2097 FILE_SHARE_READ | FILE_SHARE_WRITE,
2098 FILE_SYNCHRONOUS_IO_NONALERT);
2099 if (!NT_SUCCESS(Status))
2100 {
2101 /* That didn't work, so bail out */
2102 DPRINT1(" SMSS: Open Existing file Failed - Status == %x\n",
2103 Status);
2104 }
2105 else
2106 {
2107 /* Now remove the read-only attribute from the file */
2108 DPRINT1(" SMSS: Open Existing Success\n");
2109 RtlZeroMemory(&BasicInfo, sizeof(BasicInfo));
2110 BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
2111 Status = NtSetInformationFile(FileHandle,
2112 &IoStatusBlock,
2113 &BasicInfo,
2114 sizeof(BasicInfo),
2115 FileBasicInformation);
2116 NtClose(FileHandle);
2117 if (!NT_SUCCESS(Status))
2118 {
2119 /* That didn't work, bail out */
2120 DPRINT1(" SMSS: Set To NORMAL Failed - Status == %x\n",
2121 Status);
2122 }
2123 else
2124 {
2125 /* Now that the file is no longer read-only, delete! */
2126 DPRINT1(" SMSS: Set To NORMAL OK\n");
2127 Status = NtSetInformationFile(OtherFileHandle,
2128 &IoStatusBlock,
2129 Buffer,
2130 Length,
2131 FileRenameInformation);
2132 if (!NT_SUCCESS(Status))
2133 {
2134 /* That failed too! */
2135 DPRINT1(" SMSS: Re-Rename Failed - Status == %x\n",
2136 Status);
2137 }
2138 else
2139 {
2140 /* Everything ok */
2141 DPRINT1(" SMSS: Re-Rename Worked OK\n");
2142 }
2143 }
2144 }
2145 }
2146 }
2147
2148 /* Close the file handle and check the operation result */
2149 NtClose(OtherFileHandle);
2150 Quickie:
2151 if (!NT_SUCCESS(Status))
2152 {
2153 /* We totally failed */
2154 DPRINT1("SMSS: %wZ => %wZ failed - Status == %x\n",
2155 &RegEntry->Name, &RegEntry->Value, Status);
2156 }
2157 else if (RegEntry->Value.Length)
2158 {
2159 /* We succeed with a rename */
2160 DPRINT1("SMSS: %wZ (renamed to) %wZ\n", &RegEntry->Name, &RegEntry->Value);
2161 }
2162 else
2163 {
2164 /* We suceeded with a delete */
2165 DPRINT1("SMSS: %wZ (deleted)\n", &RegEntry->Name);
2166 }
2167
2168 /* Now free this entry and keep going */
2169 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
2170 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
2171 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
2172 }
2173
2174 /* Put back the restore privilege if we had requested it, and return */
2175 if (HavePrivilege) RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, FALSE, FALSE, &OldState);
2176 return Status;
2177 }
2178
2179 NTSTATUS
2180 NTAPI
2181 SmpLoadDataFromRegistry(OUT PUNICODE_STRING InitialCommand)
2182 {
2183 NTSTATUS Status;
2184 PLIST_ENTRY Head, NextEntry;
2185 PSMP_REGISTRY_VALUE RegEntry;
2186 PVOID OriginalEnvironment;
2187 ULONG MuSessionId = 0;
2188 OBJECT_ATTRIBUTES ObjectAttributes;
2189 HANDLE KeyHandle;
2190 UNICODE_STRING DestinationString;
2191
2192 /* Initialize the keywords we'll be looking for */
2193 RtlInitUnicodeString(&SmpDebugKeyword, L"debug");
2194 RtlInitUnicodeString(&SmpASyncKeyword, L"async");
2195 RtlInitUnicodeString(&SmpAutoChkKeyword, L"autocheck");
2196
2197 /* Initialize all the registry-associated list heads */
2198 InitializeListHead(&SmpBootExecuteList);
2199 InitializeListHead(&SmpSetupExecuteList);
2200 InitializeListHead(&SmpPagingFileList);
2201 InitializeListHead(&SmpDosDevicesList);
2202 InitializeListHead(&SmpFileRenameList);
2203 InitializeListHead(&SmpKnownDllsList);
2204 InitializeListHead(&SmpExcludeKnownDllsList);
2205 InitializeListHead(&SmpSubSystemList);
2206 InitializeListHead(&SmpSubSystemsToLoad);
2207 InitializeListHead(&SmpSubSystemsToDefer);
2208 InitializeListHead(&SmpExecuteList);
2209 SmpPagingFileInitialize();
2210
2211 /* Initialize the SMSS environment */
2212 Status = RtlCreateEnvironment(TRUE, &SmpDefaultEnvironment);
2213 if (!NT_SUCCESS(Status))
2214 {
2215 /* Fail if there was a problem */
2216 DPRINT1("SMSS: Unable to allocate default environment - Status == %X\n",
2217 Status);
2218 SMSS_CHECKPOINT(RtlCreateEnvironment, Status);
2219 return Status;
2220 }
2221
2222 /* Check if we were booted in PE mode (LiveCD should have this) */
2223 RtlInitUnicodeString(&DestinationString,
2224 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
2225 L"Control\\MiniNT");
2226 InitializeObjectAttributes(&ObjectAttributes,
2227 &DestinationString,
2228 OBJ_CASE_INSENSITIVE,
2229 NULL,
2230 NULL);
2231 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
2232 if (NT_SUCCESS(Status))
2233 {
2234 /* If the key exists, we were */
2235 NtClose(KeyHandle);
2236 MiniNTBoot = TRUE;
2237 }
2238
2239 /* Print out if this is the case */
2240 if (MiniNTBoot) DPRINT1("SMSS: !!! MiniNT Boot !!!\n");
2241
2242 /* Open the environment key to see if we are booted in safe mode */
2243 RtlInitUnicodeString(&DestinationString,
2244 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
2245 L"Control\\Session Manager\\Environment");
2246 InitializeObjectAttributes(&ObjectAttributes,
2247 &DestinationString,
2248 OBJ_CASE_INSENSITIVE,
2249 NULL,
2250 NULL);
2251 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
2252 if (NT_SUCCESS(Status))
2253 {
2254 /* Delete the value if we found it */
2255 RtlInitUnicodeString(&DestinationString, L"SAFEBOOT_OPTION");
2256 NtDeleteValueKey(KeyHandle, &DestinationString);
2257 NtClose(KeyHandle);
2258 }
2259
2260 /* Switch environments, then query the registry for all needed settings */
2261 OriginalEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
2262 NtCurrentPeb()->ProcessParameters->Environment = SmpDefaultEnvironment;
2263 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
2264 L"Session Manager",
2265 SmpRegistryConfigurationTable,
2266 NULL,
2267 NULL);
2268 SmpDefaultEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
2269 NtCurrentPeb()->ProcessParameters->Environment = OriginalEnvironment;
2270 if (!NT_SUCCESS(Status))
2271 {
2272 /* We failed somewhere in registry initialization, which is bad... */
2273 DPRINT1("SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status);
2274 SMSS_CHECKPOINT(RtlQueryRegistryValues, Status);
2275 return Status;
2276 }
2277
2278 /* Now we can start acting on the registry settings. First to DOS devices */
2279 Status = SmpInitializeDosDevices();
2280 if (!NT_SUCCESS(Status))
2281 {
2282 /* Failed */
2283 DPRINT1("SMSS: Unable to initialize DosDevices configuration - Status == %lx\n",
2284 Status);
2285 SMSS_CHECKPOINT(SmpInitializeDosDevices, Status);
2286 return Status;
2287 }
2288
2289 /* Next create the session directory... */
2290 RtlInitUnicodeString(&DestinationString, L"\\Sessions");
2291 InitializeObjectAttributes(&ObjectAttributes,
2292 &DestinationString,
2293 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
2294 NULL,
2295 SmpPrimarySecurityDescriptor);
2296 Status = NtCreateDirectoryObject(&SmpSessionsObjectDirectory,
2297 DIRECTORY_ALL_ACCESS,
2298 &ObjectAttributes);
2299 if (!NT_SUCCESS(Status))
2300 {
2301 /* Fail */
2302 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
2303 &DestinationString, Status);
2304 SMSS_CHECKPOINT(NtCreateDirectoryObject, Status);
2305 return Status;
2306 }
2307
2308 /* Next loop all the boot execute binaries */
2309 Head = &SmpBootExecuteList;
2310 while (!IsListEmpty(Head))
2311 {
2312 /* Remove each one from the list */
2313 NextEntry = RemoveHeadList(Head);
2314
2315 /* Execute it */
2316 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
2317 SmpExecuteCommand(&RegEntry->Name, 0, NULL, 0);
2318
2319 /* And free it */
2320 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
2321 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
2322 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
2323 }
2324
2325 /* Now do any pending file rename operations... */
2326 if (!MiniNTBoot) SmpProcessFileRenames();
2327
2328 /* And initialize known DLLs... */
2329 Status = SmpInitializeKnownDlls();
2330 if (!NT_SUCCESS(Status))
2331 {
2332 /* Fail if that didn't work */
2333 DPRINT1("SMSS: Unable to initialize KnownDll configuration - Status == %lx\n",
2334 Status);
2335 SMSS_CHECKPOINT(SmpInitializeKnownDlls, Status);
2336 return Status;
2337 }
2338
2339 /* Loop every page file */
2340 Head = &SmpPagingFileList;
2341 while (!IsListEmpty(Head))
2342 {
2343 /* Remove each one from the list */
2344 NextEntry = RemoveHeadList(Head);
2345
2346 /* Create the descriptor for it */
2347 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
2348 SmpCreatePagingFileDescriptor(&RegEntry->Name);
2349
2350 /* And free it */
2351 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
2352 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
2353 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
2354 }
2355
2356 /* Now create all the paging files for the descriptors that we have */
2357 SmpCreatePagingFiles();
2358
2359 /* Tell Cm it's now safe to fully enable write access to the registry */
2360 NtInitializeRegistry(CM_BOOT_FLAG_SMSS);
2361
2362 /* Create all the system-based environment variables for later inheriting */
2363 Status = SmpCreateDynamicEnvironmentVariables();
2364 if (!NT_SUCCESS(Status))
2365 {
2366 /* Handle failure */
2367 SMSS_CHECKPOINT(SmpCreateDynamicEnvironmentVariables, Status);
2368 return Status;
2369 }
2370
2371 /* And finally load all the subsytems for our first session! */
2372 Status = SmpLoadSubSystemsForMuSession(&MuSessionId,
2373 &SmpWindowsSubSysProcessId,
2374 InitialCommand);
2375 ASSERT(MuSessionId == 0);
2376 if (!NT_SUCCESS(Status)) SMSS_CHECKPOINT(SmpLoadSubSystemsForMuSession, Status);
2377 return Status;
2378 }
2379
2380 NTSTATUS
2381 NTAPI
2382 SmpInit(IN PUNICODE_STRING InitialCommand,
2383 OUT PHANDLE ProcessHandle)
2384 {
2385 NTSTATUS Status, Status2;
2386 OBJECT_ATTRIBUTES ObjectAttributes;
2387 UNICODE_STRING PortName, EventName;
2388 HANDLE EventHandle, PortHandle;
2389 ULONG HardErrorMode;
2390
2391 /* Create the SMSS Heap */
2392 SmBaseTag = RtlCreateTagHeap(RtlGetProcessHeap(),
2393 0,
2394 L"SMSS!",
2395 L"INIT");
2396 SmpHeap = RtlGetProcessHeap();
2397
2398 /* Enable hard errors */
2399 HardErrorMode = TRUE;
2400 NtSetInformationProcess(NtCurrentProcess(),
2401 ProcessDefaultHardErrorMode,
2402 &HardErrorMode,
2403 sizeof(HardErrorMode));
2404
2405 /* Initialize the subsystem list and the session list, plus their locks */
2406 RtlInitializeCriticalSection(&SmpKnownSubSysLock);
2407 InitializeListHead(&SmpKnownSubSysHead);
2408 RtlInitializeCriticalSection(&SmpSessionListLock);
2409 InitializeListHead(&SmpSessionListHead);
2410
2411 /* Initialize the process list */
2412 InitializeListHead(&NativeProcessList);
2413
2414 /* Initialize session parameters */
2415 SmpNextSessionId = 1;
2416 SmpNextSessionIdScanMode = 0;
2417 SmpDbgSsLoaded = FALSE;
2418
2419 /* Create the initial security descriptors */
2420 Status = SmpCreateSecurityDescriptors(TRUE);
2421 if (!NT_SUCCESS(Status))
2422 {
2423 /* Fail */
2424 SMSS_CHECKPOINT(SmpCreateSecurityDescriptors, Status);
2425 return Status;
2426 }
2427
2428 /* Initialize subsystem names */
2429 RtlInitUnicodeString(&SmpSubsystemName, L"NT-Session Manager");
2430 RtlInitUnicodeString(&PosixName, L"POSIX");
2431 RtlInitUnicodeString(&Os2Name, L"OS2");
2432
2433 /* Create the SM API Port */
2434 RtlInitUnicodeString(&PortName, L"\\SmApiPort2");
2435 InitializeObjectAttributes(&ObjectAttributes, &PortName, 0, NULL, NULL);
2436 Status = NtCreatePort(&PortHandle,
2437 &ObjectAttributes,
2438 sizeof(SB_CONNECTION_INFO),
2439 sizeof(SM_API_MSG),
2440 sizeof(SB_API_MSG) * 32);
2441 ASSERT(NT_SUCCESS(Status));
2442 SmpDebugPort = PortHandle;
2443
2444 /* Create two SM API threads */
2445 Status = RtlCreateUserThread(NtCurrentProcess(),
2446 NULL,
2447 FALSE,
2448 0,
2449 0,
2450 0,
2451 SmpApiLoop,
2452 PortHandle,
2453 NULL,
2454 NULL);
2455 ASSERT(NT_SUCCESS(Status));
2456 Status = RtlCreateUserThread(NtCurrentProcess(),
2457 NULL,
2458 FALSE,
2459 0,
2460 0,
2461 0,
2462 SmpApiLoop,
2463 PortHandle,
2464 NULL,
2465 NULL);
2466 ASSERT(NT_SUCCESS(Status));
2467
2468 /* Create the write event that autochk can set after running */
2469 RtlInitUnicodeString(&EventName, L"\\Device\\VolumesSafeForWriteAccess");
2470 InitializeObjectAttributes(&ObjectAttributes,
2471 &EventName,
2472 OBJ_PERMANENT,
2473 NULL,
2474 NULL);
2475 Status2 = NtCreateEvent(&EventHandle,
2476 EVENT_ALL_ACCESS,
2477 &ObjectAttributes,
2478 0,
2479 0);
2480 if (!NT_SUCCESS(Status2))
2481 {
2482 /* Should never really fail */
2483 DPRINT1("SMSS: Unable to create %wZ event - Status == %lx\n",
2484 &EventName, Status2);
2485 ASSERT(NT_SUCCESS(Status2));
2486 }
2487
2488 /* Now initialize everything else based on the registry parameters */
2489 Status = SmpLoadDataFromRegistry(InitialCommand);
2490 if (NT_SUCCESS(Status))
2491 {
2492 /* Autochk should've run now. Set the event and save the CSRSS handle */
2493 *ProcessHandle = SmpWindowsSubSysProcess;
2494 NtSetEvent(EventHandle, 0);
2495 NtClose(EventHandle);
2496 }
2497
2498 /* All done */
2499 return Status;
2500 }