Synchronize with trunk r58528.
[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_NONE,
634 NULL,
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 SmpConfigureEnvironment,
730 RTL_QUERY_REGISTRY_SUBKEY,
731 L"Environment",
732 NULL,
733 REG_NONE,
734 NULL,
735 0
736 },
737
738 {
739 SmpConfigureSubSystems,
740 RTL_QUERY_REGISTRY_SUBKEY,
741 L"SubSystems",
742 &SmpSubSystemList,
743 REG_NONE,
744 NULL,
745 0
746 },
747
748 {
749 SmpConfigureSubSystems,
750 RTL_QUERY_REGISTRY_NOEXPAND,
751 L"Required",
752 &SmpSubSystemList,
753 REG_MULTI_SZ,
754 L"Debug\0Windows\0",
755 0
756 },
757
758 {
759 SmpConfigureSubSystems,
760 RTL_QUERY_REGISTRY_NOEXPAND,
761 L"Optional",
762 &SmpSubSystemList,
763 REG_NONE,
764 NULL,
765 0
766 },
767
768 {
769 SmpConfigureSubSystems,
770 0,
771 L"Kmode",
772 &SmpSubSystemList,
773 REG_NONE,
774 NULL,
775 0
776 },
777
778 {
779 SmpConfigureMemoryMgmt,
780 RTL_QUERY_REGISTRY_TOPKEY,
781 L"Execute",
782 &SmpExecuteList,
783 REG_NONE,
784 NULL,
785 0
786 },
787
788 {0},
789 };
790
791 /* FUNCTIONS ******************************************************************/
792
793 VOID
794 NTAPI
795 SmpTranslateSystemPartitionInformation(VOID)
796 {
797 NTSTATUS Status;
798 UNICODE_STRING UnicodeString, LinkTarget, SearchString, SystemPartition;
799 OBJECT_ATTRIBUTES ObjectAttributes;
800 HANDLE KeyHandle, LinkHandle;
801 CHAR ValueBuffer[512 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
802 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
803 ULONG Length, Context;
804 CHAR DirInfoBuffer[512 + sizeof(OBJECT_DIRECTORY_INFORMATION)];
805 POBJECT_DIRECTORY_INFORMATION DirInfo = (PVOID)DirInfoBuffer;
806 WCHAR LinkBuffer[MAX_PATH];
807
808 /* Open the setup key */
809 RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\Setup");
810 InitializeObjectAttributes(&ObjectAttributes,
811 &UnicodeString,
812 OBJ_CASE_INSENSITIVE,
813 NULL,
814 NULL);
815 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
816 if (!NT_SUCCESS(Status))
817 {
818 DPRINT1("SMSS: can't open system setup key for reading: 0x%x\n", Status);
819 return;
820 }
821
822 /* Query the system partition */
823 RtlInitUnicodeString(&UnicodeString, L"SystemPartition");
824 Status = NtQueryValueKey(KeyHandle,
825 &UnicodeString,
826 KeyValuePartialInformation,
827 PartialInfo,
828 sizeof(ValueBuffer),
829 &Length);
830 NtClose(KeyHandle);
831 if (!NT_SUCCESS(Status))
832 {
833 DPRINT1("SMSS: can't query SystemPartition value: 0x%x\n", Status);
834 return;
835 }
836
837 /* Initialize the system partition string string */
838 RtlInitUnicodeString(&SystemPartition, (PWCHAR)PartialInfo->Data);
839
840 /* Enumerate the directory looking for the symbolic link string */
841 RtlInitUnicodeString(&SearchString, L"SymbolicLink");
842 RtlInitEmptyUnicodeString(&LinkTarget, LinkBuffer, sizeof(LinkBuffer));
843 Status = NtQueryDirectoryObject(SmpDosDevicesObjectDirectory,
844 DirInfo,
845 sizeof(DirInfoBuffer),
846 TRUE,
847 TRUE,
848 &Context,
849 NULL);
850 if (!NT_SUCCESS(Status))
851 {
852 DPRINT1("SMSS: can't find drive letter for system partition\n");
853 return;
854 }
855
856 /* Keep searching until we find it */
857 do
858 {
859 /* Is this it? */
860 if ((RtlEqualUnicodeString(&DirInfo->TypeName, &SearchString, TRUE)) &&
861 (DirInfo->Name.Length == 2 * sizeof(WCHAR)) &&
862 (DirInfo->Name.Buffer[1] == L':'))
863 {
864 /* Looks like we found it, open the link to get its target */
865 InitializeObjectAttributes(&ObjectAttributes,
866 &DirInfo->Name,
867 OBJ_CASE_INSENSITIVE,
868 SmpDosDevicesObjectDirectory,
869 NULL);
870 Status = NtOpenSymbolicLinkObject(&LinkHandle,
871 SYMBOLIC_LINK_ALL_ACCESS,
872 &ObjectAttributes);
873 if (NT_SUCCESS(Status))
874 {
875 /* Open worked, query the target now */
876 Status = NtQuerySymbolicLinkObject(LinkHandle,
877 &LinkTarget,
878 NULL);
879 NtClose(LinkHandle);
880
881 /* Check if it matches the string we had found earlier */
882 if ((NT_SUCCESS(Status)) &&
883 ((RtlEqualUnicodeString(&SystemPartition,
884 &LinkTarget,
885 TRUE)) ||
886 ((RtlPrefixUnicodeString(&SystemPartition,
887 &LinkTarget,
888 TRUE)) &&
889 (LinkTarget.Buffer[SystemPartition.Length / sizeof(WCHAR)] == L'\\'))))
890 {
891 /* All done */
892 break;
893 }
894 }
895 }
896
897 /* Couldn't find it, try again */
898 Status = NtQueryDirectoryObject(SmpDosDevicesObjectDirectory,
899 DirInfo,
900 sizeof(DirInfoBuffer),
901 TRUE,
902 FALSE,
903 &Context,
904 NULL);
905 } while (NT_SUCCESS(Status));
906 if (!NT_SUCCESS(Status))
907 {
908 DPRINT1("SMSS: can't find drive letter for system partition\n");
909 return;
910 }
911
912 /* Open the setup key again, for full access this time */
913 RtlInitUnicodeString(&UnicodeString,
914 L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup");
915 InitializeObjectAttributes(&ObjectAttributes,
916 &UnicodeString,
917 OBJ_CASE_INSENSITIVE,
918 NULL,
919 NULL);
920 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
921 if (!NT_SUCCESS(Status))
922 {
923 DPRINT1("SMSS: can't open software setup key for writing: 0x%x\n",
924 Status);
925 return;
926 }
927
928 /* Wrap up the end of the link buffer */
929 wcsncpy(LinkBuffer, DirInfo->Name.Buffer, 2);
930 LinkBuffer[2] = L'\\';
931 LinkBuffer[3] = L'\0';
932
933 /* Now set this as the "BootDir" */
934 RtlInitUnicodeString(&UnicodeString, L"BootDir");
935 Status = NtSetValueKey(KeyHandle,
936 &UnicodeString,
937 0,
938 REG_SZ,
939 LinkBuffer,
940 4 * sizeof(WCHAR));
941 if (!NT_SUCCESS(Status))
942 {
943 DPRINT1("SMSS: couldn't write BootDir value: 0x%x\n", Status);
944 }
945 NtClose(KeyHandle);
946 }
947
948 NTSTATUS
949 NTAPI
950 SmpCreateSecurityDescriptors(IN BOOLEAN InitialCall)
951 {
952 NTSTATUS Status;
953 PSID WorldSid = NULL, AdminSid = NULL, SystemSid = NULL;
954 PSID RestrictedSid = NULL, OwnerSid = NULL;
955 SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
956 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
957 SID_IDENTIFIER_AUTHORITY CreatorAuthority = {SECURITY_CREATOR_SID_AUTHORITY};
958 ULONG AclLength, SidLength;
959 PACL Acl;
960 PACE_HEADER Ace;
961 BOOLEAN ProtectionRequired = FALSE;
962
963 /* Check if this is the first call */
964 if (InitialCall)
965 {
966 /* Create and set the primary descriptor */
967 SmpPrimarySecurityDescriptor = &SmpPrimarySDBody;
968 Status = RtlCreateSecurityDescriptor(SmpPrimarySecurityDescriptor,
969 SECURITY_DESCRIPTOR_REVISION);
970 ASSERT(NT_SUCCESS(Status));
971 Status = RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor,
972 TRUE,
973 NULL,
974 FALSE);
975 ASSERT(NT_SUCCESS(Status));
976
977 /* Create and set the liberal descriptor */
978 SmpLiberalSecurityDescriptor = &SmpLiberalSDBody;
979 Status = RtlCreateSecurityDescriptor(SmpLiberalSecurityDescriptor,
980 SECURITY_DESCRIPTOR_REVISION);
981 ASSERT(NT_SUCCESS(Status));
982 Status = RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor,
983 TRUE,
984 NULL,
985 FALSE);
986 ASSERT(NT_SUCCESS(Status));
987
988 /* Create and set the \KnownDlls descriptor */
989 SmpKnownDllsSecurityDescriptor = &SmpKnownDllsSDBody;
990 Status = RtlCreateSecurityDescriptor(SmpKnownDllsSecurityDescriptor,
991 SECURITY_DESCRIPTOR_REVISION);
992 ASSERT(NT_SUCCESS(Status));
993 Status = RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor,
994 TRUE,
995 NULL,
996 FALSE);
997 ASSERT(NT_SUCCESS(Status));
998
999 /* Create and Set the \ApiPort descriptor */
1000 SmpApiPortSecurityDescriptor = &SmpApiPortSDBody;
1001 Status = RtlCreateSecurityDescriptor(SmpApiPortSecurityDescriptor,
1002 SECURITY_DESCRIPTOR_REVISION);
1003 ASSERT(NT_SUCCESS(Status));
1004 Status = RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor,
1005 TRUE,
1006 NULL,
1007 FALSE);
1008 ASSERT(NT_SUCCESS(Status));
1009 }
1010
1011 /* Check if protection was requested in the registry (on by default) */
1012 if (SmpProtectionMode & 1) ProtectionRequired = TRUE;
1013
1014 /* Exit if there's nothing to do */
1015 if (!(InitialCall || ProtectionRequired)) return STATUS_SUCCESS;
1016
1017 /* Build the world SID */
1018 Status = RtlAllocateAndInitializeSid(&WorldAuthority, 1,
1019 SECURITY_WORLD_RID,
1020 0, 0, 0, 0, 0, 0, 0,
1021 &WorldSid);
1022 if (!NT_SUCCESS(Status))
1023 {
1024 WorldSid = NULL;
1025 goto Quickie;
1026 }
1027
1028 /* Build the admin SID */
1029 Status = RtlAllocateAndInitializeSid(&NtAuthority, 2,
1030 SECURITY_BUILTIN_DOMAIN_RID,
1031 DOMAIN_ALIAS_RID_ADMINS,
1032 0, 0, 0, 0, 0, 0,
1033 &AdminSid);
1034 if (!NT_SUCCESS(Status))
1035 {
1036 AdminSid = NULL;
1037 goto Quickie;
1038 }
1039
1040 /* Build the owner SID */
1041 Status = RtlAllocateAndInitializeSid(&CreatorAuthority, 1,
1042 SECURITY_CREATOR_OWNER_RID,
1043 0, 0, 0, 0, 0, 0, 0,
1044 &OwnerSid);
1045 if (!NT_SUCCESS(Status))
1046 {
1047 OwnerSid = NULL;
1048 goto Quickie;
1049 }
1050
1051 /* Build the restricted SID */
1052 Status = RtlAllocateAndInitializeSid(&NtAuthority, 1,
1053 SECURITY_RESTRICTED_CODE_RID,
1054 0, 0, 0, 0, 0, 0, 0,
1055 &RestrictedSid);
1056 if (!NT_SUCCESS(Status))
1057 {
1058 RestrictedSid = NULL;
1059 goto Quickie;
1060 }
1061
1062 /* Build the system SID */
1063 Status = RtlAllocateAndInitializeSid(&NtAuthority, 1,
1064 SECURITY_LOCAL_SYSTEM_RID,
1065 0, 0, 0, 0, 0, 0, 0,
1066 &SystemSid);
1067 if (!NT_SUCCESS(Status))
1068 {
1069 SystemSid = NULL;
1070 goto Quickie;
1071 }
1072
1073 /* Now check if we're creating the core descriptors */
1074 if (!InitialCall)
1075 {
1076 /* We're skipping NextAcl so we have to do this here */
1077 SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(RestrictedSid) + RtlLengthSid(AdminSid);
1078 SidLength *= 2;
1079 goto NotInitial;
1080 }
1081
1082 /* Allocate an ACL with two ACEs with two SIDs each */
1083 SidLength = RtlLengthSid(SystemSid) + RtlLengthSid(AdminSid);
1084 AclLength = sizeof(ACL) + 2 * sizeof(ACCESS_ALLOWED_ACE) + SidLength;
1085 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength);
1086 if (!Acl) Status = STATUS_NO_MEMORY;
1087 if (!NT_SUCCESS(Status)) goto NextAcl;
1088
1089 /* Now build the ACL and add the two ACEs */
1090 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2);
1091 ASSERT(NT_SUCCESS(Status));
1092 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1093 ASSERT(NT_SUCCESS(Status));
1094 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, SystemSid);
1095 ASSERT(NT_SUCCESS(Status));
1096
1097 /* Set this as the DACL */
1098 Status = RtlSetDaclSecurityDescriptor(SmpApiPortSecurityDescriptor,
1099 TRUE,
1100 Acl,
1101 FALSE);
1102 ASSERT(NT_SUCCESS(Status));
1103
1104 NextAcl:
1105 /* Allocate an ACL with 6 ACEs, two ACEs per SID */
1106 SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(RestrictedSid) + RtlLengthSid(AdminSid);
1107 SidLength *= 2;
1108 AclLength = sizeof(ACL) + 6 * sizeof(ACCESS_ALLOWED_ACE) + SidLength;
1109 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength);
1110 if (!Acl) Status = STATUS_NO_MEMORY;
1111 if (!NT_SUCCESS(Status)) goto NotInitial;
1112
1113 /* Now build the ACL and add the six ACEs */
1114 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2);
1115 ASSERT(NT_SUCCESS(Status));
1116 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE, WorldSid);
1117 ASSERT(NT_SUCCESS(Status));
1118 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE, RestrictedSid);
1119 ASSERT(NT_SUCCESS(Status));
1120 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1121 ASSERT(NT_SUCCESS(Status));
1122 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid);
1123 ASSERT(NT_SUCCESS(Status));
1124 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid);
1125 ASSERT(NT_SUCCESS(Status));
1126 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1127 ASSERT(NT_SUCCESS(Status));
1128
1129 /* Now edit the last three ACEs and make them inheritable */
1130 Status = RtlGetAce(Acl, 3, (PVOID)&Ace);
1131 ASSERT(NT_SUCCESS(Status));
1132 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1133 Status = RtlGetAce(Acl, 4, (PVOID)&Ace);
1134 ASSERT(NT_SUCCESS(Status));
1135 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1136 Status = RtlGetAce(Acl, 5, (PVOID)&Ace);
1137 ASSERT(NT_SUCCESS(Status));
1138 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1139
1140 /* Set this as the DACL */
1141 Status = RtlSetDaclSecurityDescriptor(SmpKnownDllsSecurityDescriptor,
1142 TRUE,
1143 Acl,
1144 FALSE);
1145 ASSERT(NT_SUCCESS(Status));
1146
1147 NotInitial:
1148 /* The initial ACLs have been created, are we also protecting objects? */
1149 if (!ProtectionRequired) goto Quickie;
1150
1151 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
1152 SidLength += RtlLengthSid(OwnerSid);
1153 AclLength = sizeof(ACL) + 7 * sizeof (ACCESS_ALLOWED_ACE) + 2 * SidLength;
1154 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength);
1155 if (!Acl) Status = STATUS_NO_MEMORY;
1156 if (!NT_SUCCESS(Status)) goto Quickie;
1157
1158 /* Build the ACL and add the seven ACEs */
1159 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2);
1160 ASSERT(NT_SUCCESS(Status));
1161 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, WorldSid);
1162 ASSERT(NT_SUCCESS(Status));
1163 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, RestrictedSid);
1164 ASSERT(NT_SUCCESS(Status));
1165 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1166 ASSERT(NT_SUCCESS(Status));
1167 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, WorldSid);
1168 ASSERT(NT_SUCCESS(Status));
1169 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ, RestrictedSid);
1170 ASSERT(NT_SUCCESS(Status));
1171 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1172 ASSERT(NT_SUCCESS(Status));
1173 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, OwnerSid);
1174 ASSERT(NT_SUCCESS(Status));
1175
1176 /* Edit the last 4 ACEs to make then inheritable */
1177 Status = RtlGetAce(Acl, 3, (PVOID)&Ace);
1178 ASSERT(NT_SUCCESS(Status));
1179 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1180 Status = RtlGetAce(Acl, 4, (PVOID)&Ace);
1181 ASSERT(NT_SUCCESS(Status));
1182 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1183 Status = RtlGetAce(Acl, 5, (PVOID)&Ace);
1184 ASSERT(NT_SUCCESS(Status));
1185 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1186 Status = RtlGetAce(Acl, 6, (PVOID)&Ace);
1187 ASSERT(NT_SUCCESS(Status));
1188 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1189
1190 /* Set this as the DACL for the primary SD */
1191 Status = RtlSetDaclSecurityDescriptor(SmpPrimarySecurityDescriptor,
1192 TRUE,
1193 Acl,
1194 FALSE);
1195 ASSERT(NT_SUCCESS(Status));
1196
1197 /* Allocate an ACL with 7 ACEs, two ACEs per SID, and one final owner ACE */
1198 AclLength = sizeof(ACL) + 7 * sizeof (ACCESS_ALLOWED_ACE) + 2 * SidLength;
1199 Acl = RtlAllocateHeap(RtlGetProcessHeap(), 0, AclLength);
1200 if (!Acl) Status = STATUS_NO_MEMORY;
1201 if (!NT_SUCCESS(Status)) goto Quickie;
1202
1203 /* Build the ACL and add the seven ACEs */
1204 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION2);
1205 ASSERT(NT_SUCCESS(Status));
1206 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid);
1207 ASSERT(NT_SUCCESS(Status));
1208 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid);
1209 ASSERT(NT_SUCCESS(Status));
1210 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1211 ASSERT(NT_SUCCESS(Status));
1212 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, WorldSid);
1213 ASSERT(NT_SUCCESS(Status));
1214 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, RestrictedSid);
1215 ASSERT(NT_SUCCESS(Status));
1216 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, AdminSid);
1217 ASSERT(NT_SUCCESS(Status));
1218 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION2, GENERIC_ALL, OwnerSid);
1219 ASSERT(NT_SUCCESS(Status));
1220
1221 /* Edit the last 4 ACEs to make then inheritable */
1222 Status = RtlGetAce(Acl, 3, (PVOID)&Ace);
1223 ASSERT(NT_SUCCESS(Status));
1224 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1225 Status = RtlGetAce(Acl, 4, (PVOID)&Ace);
1226 ASSERT(NT_SUCCESS(Status));
1227 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1228 Status = RtlGetAce(Acl, 5, (PVOID)&Ace);
1229 ASSERT(NT_SUCCESS(Status));
1230 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1231 Status = RtlGetAce(Acl, 6, (PVOID)&Ace);
1232 ASSERT(NT_SUCCESS(Status));
1233 Ace->AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
1234
1235 /* Now set this as the DACL for the liberal SD */
1236 Status = RtlSetDaclSecurityDescriptor(SmpLiberalSecurityDescriptor,
1237 TRUE,
1238 Acl,
1239 FALSE);
1240 ASSERT(NT_SUCCESS(Status));
1241
1242 Quickie:
1243 /* Cleanup the SIDs */
1244 if (OwnerSid) RtlFreeHeap(RtlGetProcessHeap(), 0, OwnerSid);
1245 if (AdminSid) RtlFreeHeap(RtlGetProcessHeap(), 0, AdminSid);
1246 if (WorldSid) RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid);
1247 if (SystemSid) RtlFreeHeap(RtlGetProcessHeap(), 0, SystemSid);
1248 if (RestrictedSid) RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSid);
1249 return Status;
1250 }
1251
1252 NTSTATUS
1253 NTAPI
1254 SmpInitializeDosDevices(VOID)
1255 {
1256 NTSTATUS Status;
1257 PSMP_REGISTRY_VALUE RegEntry;
1258 SECURITY_DESCRIPTOR_CONTROL OldFlag = 0;
1259 OBJECT_ATTRIBUTES ObjectAttributes;
1260 UNICODE_STRING DestinationString;
1261 HANDLE DirHandle;
1262 PLIST_ENTRY NextEntry, Head;
1263
1264 /* Open the GLOBAL?? directory */
1265 RtlInitUnicodeString(&DestinationString, L"\\??");
1266 InitializeObjectAttributes(&ObjectAttributes,
1267 &DestinationString,
1268 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
1269 NULL,
1270 NULL);
1271 Status = NtOpenDirectoryObject(&SmpDosDevicesObjectDirectory,
1272 DIRECTORY_ALL_ACCESS,
1273 &ObjectAttributes);
1274 if (!NT_SUCCESS(Status))
1275 {
1276 DPRINT1("SMSS: Unable to open %wZ directory - Status == %lx\n",
1277 &DestinationString, Status);
1278 return Status;
1279 }
1280
1281 /* Loop the DOS devices */
1282 Head = &SmpDosDevicesList;
1283 while (!IsListEmpty(Head))
1284 {
1285 /* Get the entry and remove it */
1286 NextEntry = RemoveHeadList(Head);
1287 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
1288
1289 /* Initialize the attributes, and see which descriptor is being used */
1290 InitializeObjectAttributes(&ObjectAttributes,
1291 &RegEntry->Name,
1292 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
1293 SmpDosDevicesObjectDirectory,
1294 SmpPrimarySecurityDescriptor);
1295 if (SmpPrimarySecurityDescriptor)
1296 {
1297 /* Save the old flag and set it while we create this link */
1298 OldFlag = SmpPrimarySecurityDescriptor->Control;
1299 SmpPrimarySecurityDescriptor->Control |= SE_DACL_DEFAULTED;
1300 }
1301
1302 /* Create the symbolic link */
1303 DPRINT("Creating symlink for %wZ to %wZ\n", &RegEntry->Name, &RegEntry->Value);
1304 Status = NtCreateSymbolicLinkObject(&DirHandle,
1305 SYMBOLIC_LINK_ALL_ACCESS,
1306 &ObjectAttributes,
1307 &RegEntry->Value);
1308 if (Status == STATUS_OBJECT_NAME_EXISTS)
1309 {
1310 /* Make it temporary and get rid of the handle */
1311 NtMakeTemporaryObject(DirHandle);
1312 NtClose(DirHandle);
1313
1314 /* Treat this as success, and see if we got a name back */
1315 Status = STATUS_SUCCESS;
1316 if (RegEntry->Value.Length)
1317 {
1318 /* Create it now with this name */
1319 ObjectAttributes.Attributes &= ~OBJ_OPENIF;
1320 Status = NtCreateSymbolicLinkObject(&DirHandle,
1321 SYMBOLIC_LINK_ALL_ACCESS,
1322 &ObjectAttributes,
1323 &RegEntry->Value);
1324 }
1325 }
1326
1327 /* If we were using a security descriptor, restore the non-defaulted flag */
1328 if (ObjectAttributes.SecurityDescriptor)
1329 {
1330 SmpPrimarySecurityDescriptor->Control = OldFlag;
1331 }
1332
1333 /* Print a failure if we failed to create the symbolic link */
1334 if (!NT_SUCCESS(Status))
1335 {
1336 DPRINT1("SMSS: Unable to create %wZ => %wZ symbolic link object - Status == 0x%lx\n",
1337 &RegEntry->Name,
1338 &RegEntry->Value,
1339 Status);
1340 break;
1341 }
1342
1343 /* Close the handle */
1344 NtClose(DirHandle);
1345
1346 /* Free this entry */
1347 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
1348 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
1349 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
1350 }
1351
1352 /* Return the status */
1353 return Status;
1354 }
1355
1356 VOID
1357 NTAPI
1358 SmpProcessModuleImports(IN PVOID Unused,
1359 IN PCHAR ImportName)
1360 {
1361 ULONG Length = 0, Chars;
1362 WCHAR Buffer[MAX_PATH];
1363 PWCHAR DllName, DllValue;
1364 ANSI_STRING ImportString;
1365 UNICODE_STRING ImportUnicodeString;
1366 NTSTATUS Status;
1367
1368 /* Skip NTDLL since it's already always mapped */
1369 if (!_stricmp(ImportName, "ntdll.dll")) return;
1370
1371 /* Initialize our strings */
1372 RtlInitAnsiString(&ImportString, ImportName);
1373 RtlInitEmptyUnicodeString(&ImportUnicodeString, Buffer, sizeof(Buffer));
1374 Status = RtlAnsiStringToUnicodeString(&ImportUnicodeString, &ImportString, FALSE);
1375 if (!NT_SUCCESS(Status)) return;
1376
1377 /* Loop in case we find a forwarder */
1378 ImportUnicodeString.MaximumLength = ImportUnicodeString.Length + sizeof(UNICODE_NULL);
1379 while (Length < ImportUnicodeString.Length)
1380 {
1381 if (ImportUnicodeString.Buffer[Length / sizeof(WCHAR)] == L'.') break;
1382 Length += sizeof(WCHAR);
1383 }
1384
1385 /* Break up the values as needed */
1386 DllValue = ImportUnicodeString.Buffer;
1387 DllName = &ImportUnicodeString.Buffer[ImportUnicodeString.MaximumLength / sizeof(WCHAR)];
1388 Chars = Length >> 1;
1389 wcsncpy(DllName, ImportUnicodeString.Buffer, Chars);
1390 DllName[Chars] = 0;
1391
1392 /* Add the DLL to the list */
1393 SmpSaveRegistryValue(&SmpKnownDllsList, DllName, DllValue, TRUE);
1394 }
1395
1396 NTSTATUS
1397 NTAPI
1398 SmpInitializeKnownDllsInternal(IN PUNICODE_STRING Directory,
1399 IN PUNICODE_STRING Path)
1400 {
1401 HANDLE DirFileHandle, DirHandle, SectionHandle, FileHandle, LinkHandle;
1402 UNICODE_STRING NtPath, DestinationString;
1403 OBJECT_ATTRIBUTES ObjectAttributes;
1404 NTSTATUS Status, Status1;
1405 PLIST_ENTRY NextEntry;
1406 PSMP_REGISTRY_VALUE RegEntry;
1407 //ULONG_PTR ErrorParameters[3];
1408 //UNICODE_STRING ErrorResponse;
1409 IO_STATUS_BLOCK IoStatusBlock;
1410 SECURITY_DESCRIPTOR_CONTROL OldFlag = 0;
1411 USHORT ImageCharacteristics;
1412
1413 /* Initialize to NULL */
1414 DirFileHandle = NULL;
1415 DirHandle = NULL;
1416 NtPath.Buffer = NULL;
1417
1418 /* Create the \KnownDLLs directory */
1419 InitializeObjectAttributes(&ObjectAttributes,
1420 Directory,
1421 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
1422 NULL,
1423 SmpKnownDllsSecurityDescriptor);
1424 Status = NtCreateDirectoryObject(&DirHandle,
1425 DIRECTORY_ALL_ACCESS,
1426 &ObjectAttributes);
1427 if (!NT_SUCCESS(Status))
1428 {
1429 /* Handle failure */
1430 DPRINT1("SMSS: Unable to create %wZ directory - Status == %lx\n",
1431 Directory, Status);
1432 return Status;
1433 }
1434
1435 /* Convert the path to native format */
1436 if (!RtlDosPathNameToNtPathName_U(Path->Buffer, &NtPath, NULL, NULL))
1437 {
1438 /* Fail if this didn't work */
1439 DPRINT1("SMSS: Unable to to convert %wZ to an Nt path\n", Path);
1440 Status = STATUS_OBJECT_NAME_INVALID;
1441 goto Quickie;
1442 }
1443
1444 /* Open the path that was specified, which should be a directory */
1445 InitializeObjectAttributes(&ObjectAttributes,
1446 &NtPath,
1447 OBJ_CASE_INSENSITIVE,
1448 NULL,
1449 NULL);
1450 Status = NtOpenFile(&DirFileHandle,
1451 FILE_LIST_DIRECTORY | SYNCHRONIZE,
1452 &ObjectAttributes,
1453 &IoStatusBlock,
1454 FILE_SHARE_READ | FILE_SHARE_WRITE,
1455 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
1456 if (!NT_SUCCESS(Status))
1457 {
1458 /* Fail if we couldn't open it */
1459 DPRINT1("SMSS: Unable to open a handle to the KnownDll directory (%wZ)"
1460 "- Status == %lx\n",
1461 Path,
1462 Status);
1463 FileHandle = NULL;
1464 goto Quickie;
1465 }
1466
1467 /* Temporarily hack the SD to use a default DACL for this symbolic link */
1468 if (SmpPrimarySecurityDescriptor)
1469 {
1470 OldFlag = SmpPrimarySecurityDescriptor->Control;
1471 SmpPrimarySecurityDescriptor->Control |= SE_DACL_DEFAULTED;
1472 }
1473
1474 /* Create a symbolic link to the directory in the object manager */
1475 RtlInitUnicodeString(&DestinationString, L"KnownDllPath");
1476 InitializeObjectAttributes(&ObjectAttributes,
1477 &DestinationString,
1478 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
1479 DirHandle,
1480 SmpPrimarySecurityDescriptor);
1481 Status = NtCreateSymbolicLinkObject(&LinkHandle,
1482 SYMBOLIC_LINK_ALL_ACCESS,
1483 &ObjectAttributes,
1484 Path);
1485
1486 /* Undo the hack */
1487 if (SmpPrimarySecurityDescriptor) SmpPrimarySecurityDescriptor->Control = OldFlag;
1488
1489 /* Check if the symlink was created */
1490 if (!NT_SUCCESS(Status))
1491 {
1492 /* It wasn't, so bail out since the OS needs it to exist */
1493 DPRINT1("SMSS: Unable to create %wZ symbolic link - Status == %lx\n",
1494 &DestinationString, Status);
1495 LinkHandle = NULL;
1496 goto Quickie;
1497 }
1498
1499 /* We created it permanent, we can go ahead and close the handle now */
1500 Status1 = NtClose(LinkHandle);
1501 ASSERT(NT_SUCCESS(Status1));
1502
1503 /* Now loop the known DLLs */
1504 NextEntry = SmpKnownDllsList.Flink;
1505 while (NextEntry != &SmpKnownDllsList)
1506 {
1507 /* Get the entry and skip it if it's in the exluded list */
1508 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
1509 DPRINT("Processing known DLL: %wZ-%wZ\n", &RegEntry->Name, &RegEntry->Value);
1510 if ((SmpFindRegistryValue(&SmpExcludeKnownDllsList,
1511 RegEntry->Name.Buffer)) ||
1512 (SmpFindRegistryValue(&SmpExcludeKnownDllsList,
1513 RegEntry->Value.Buffer)))
1514 {
1515 continue;
1516 }
1517
1518 /* Open the actual file */
1519 InitializeObjectAttributes(&ObjectAttributes,
1520 &RegEntry->Value,
1521 OBJ_CASE_INSENSITIVE,
1522 DirFileHandle,
1523 NULL);
1524 Status = NtOpenFile(&FileHandle,
1525 SYNCHRONIZE | FILE_EXECUTE,
1526 &ObjectAttributes,
1527 &IoStatusBlock,
1528 FILE_SHARE_READ | FILE_SHARE_DELETE,
1529 FILE_NON_DIRECTORY_FILE |
1530 FILE_SYNCHRONOUS_IO_NONALERT);
1531 if (!NT_SUCCESS(Status)) break;
1532
1533 /* Checksum it */
1534 Status = LdrVerifyImageMatchesChecksum((HANDLE)((ULONG_PTR)FileHandle | 1),
1535 SmpProcessModuleImports,
1536 RegEntry,
1537 &ImageCharacteristics);
1538 #if 0
1539 if (!NT_SUCCESS(Status))
1540 {
1541 /* Checksum failed, so don't even try going further -- kill SMSS */
1542 RtlInitUnicodeString(&ErrorResponse,
1543 L"Verification of a KnownDLL failed.");
1544 ErrorParameters[0] = (ULONG)&ErrorResponse;
1545 ErrorParameters[1] = Status;
1546 ErrorParameters[2] = (ULONG)&RegEntry->Value;
1547 SmpTerminate(ErrorParameters, 5, RTL_NUMBER_OF(ErrorParameters));
1548 }
1549 else
1550 if (!(ImageCharacteristics & IMAGE_FILE_DLL))
1551 {
1552 /* An invalid known DLL entry will also kill SMSS */
1553 RtlInitUnicodeString(&ErrorResponse,
1554 L"Non-DLL file included in KnownDLL list.");
1555 ErrorParameters[0] = (ULONG)&ErrorResponse;
1556 ErrorParameters[1] = STATUS_INVALID_IMPORT_OF_NON_DLL;
1557 ErrorParameters[2] = (ULONG)&RegEntry->Value;
1558 SmpTerminate(ErrorParameters, 5, RTL_NUMBER_OF(ErrorParameters));
1559 }
1560 #endif
1561
1562 /* Temporarily hack the SD to use a default DACL for this section */
1563 if (SmpLiberalSecurityDescriptor)
1564 {
1565 OldFlag = SmpLiberalSecurityDescriptor->Control;
1566 SmpLiberalSecurityDescriptor->Control |= SE_DACL_DEFAULTED;
1567 }
1568
1569 /* Create the section for this known DLL */
1570 InitializeObjectAttributes(&ObjectAttributes,
1571 &RegEntry->Value,
1572 OBJ_PERMANENT,
1573 DirHandle,
1574 SmpLiberalSecurityDescriptor)
1575 Status = NtCreateSection(&SectionHandle,
1576 SECTION_ALL_ACCESS,
1577 &ObjectAttributes,
1578 0,
1579 PAGE_EXECUTE,
1580 SEC_IMAGE,
1581 FileHandle);
1582
1583 /* Undo the hack */
1584 if (SmpLiberalSecurityDescriptor) SmpLiberalSecurityDescriptor->Control = OldFlag;
1585
1586 /* Check if we created the section okay */
1587 if (NT_SUCCESS(Status))
1588 {
1589 /* We can close it now, since it's marked permanent */
1590 Status1 = NtClose(SectionHandle);
1591 ASSERT(NT_SUCCESS(Status1));
1592 }
1593 else
1594 {
1595 /* If we couldn't make it "known", that's fine and keep going */
1596 DPRINT1("SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n",
1597 &RegEntry->Value, Status);
1598 }
1599
1600 /* Close the file since we can move on to the next one */
1601 Status1 = NtClose(FileHandle);
1602 ASSERT(NT_SUCCESS(Status1));
1603
1604 /* Go to the next entry */
1605 NextEntry = NextEntry->Flink;
1606 }
1607
1608 Quickie:
1609 /* Close both handles and free the NT path buffer */
1610 if (DirHandle)
1611 {
1612 Status1 = NtClose(DirHandle);
1613 ASSERT(NT_SUCCESS(Status1));
1614 }
1615 if (DirFileHandle)
1616 {
1617 Status1 = NtClose(DirFileHandle);
1618 ASSERT(NT_SUCCESS(Status1));
1619 }
1620 if (NtPath.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, NtPath.Buffer);
1621 return Status;
1622 }
1623
1624 NTSTATUS
1625 NTAPI
1626 SmpInitializeKnownDlls(VOID)
1627 {
1628 NTSTATUS Status;
1629 PSMP_REGISTRY_VALUE RegEntry;
1630 UNICODE_STRING DestinationString;
1631 PLIST_ENTRY Head, NextEntry;
1632
1633 /* Call the internal function */
1634 RtlInitUnicodeString(&DestinationString, L"\\KnownDlls");
1635 Status = SmpInitializeKnownDllsInternal(&DestinationString, &SmpKnownDllPath);
1636
1637 /* Wipe out the list regardless of success */
1638 Head = &SmpKnownDllsList;
1639 while (!IsListEmpty(Head))
1640 {
1641 /* Remove this entry */
1642 NextEntry = RemoveHeadList(Head);
1643
1644 /* Free it */
1645 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
1646 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
1647 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
1648 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
1649 }
1650
1651 /* All done */
1652 return Status;
1653 }
1654
1655 NTSTATUS
1656 NTAPI
1657 SmpCreateDynamicEnvironmentVariables(VOID)
1658 {
1659 NTSTATUS Status;
1660 SYSTEM_BASIC_INFORMATION BasicInfo;
1661 SYSTEM_PROCESSOR_INFORMATION ProcessorInfo;
1662 OBJECT_ATTRIBUTES ObjectAttributes;
1663 UNICODE_STRING ValueName, DestinationString;
1664 HANDLE KeyHandle, KeyHandle2;
1665 ULONG ResultLength;
1666 PWCHAR ArchName;
1667 WCHAR ValueBuffer[512], ValueBuffer2[512];
1668 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
1669 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo2 = (PVOID)ValueBuffer2;
1670
1671 /* Get system basic information -- we'll need the CPU count */
1672 Status = NtQuerySystemInformation(SystemBasicInformation,
1673 &BasicInfo,
1674 sizeof(BasicInfo),
1675 NULL);
1676 if (!NT_SUCCESS(Status))
1677 {
1678 /* Bail out on failure */
1679 DPRINT1("SMSS: Unable to query system basic information - %x\n", Status);
1680 return Status;
1681 }
1682
1683 /* Get the processor information, we'll query a bunch of revision info */
1684 Status = NtQuerySystemInformation(SystemProcessorInformation,
1685 &ProcessorInfo,
1686 sizeof(ProcessorInfo),
1687 NULL);
1688 if (!NT_SUCCESS(Status))
1689 {
1690 /* Bail out on failure */
1691 DPRINT1("SMSS: Unable to query system processor information - %x\n", Status);
1692 return Status;
1693 }
1694
1695 /* We'll be writing all these environment variables over here */
1696 RtlInitUnicodeString(&DestinationString,
1697 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
1698 L"Control\\Session Manager\\Environment");
1699 InitializeObjectAttributes(&ObjectAttributes,
1700 &DestinationString,
1701 OBJ_CASE_INSENSITIVE,
1702 NULL,
1703 NULL);
1704 Status = NtOpenKey(&KeyHandle, GENERIC_WRITE, &ObjectAttributes);
1705 if (!NT_SUCCESS(Status))
1706 {
1707 /* Bail out on failure */
1708 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString, Status);
1709 return Status;
1710 }
1711
1712 /* First let's write the OS variable */
1713 RtlInitUnicodeString(&ValueName, L"OS");
1714 DPRINT("Setting %wZ to %S\n", &ValueName, L"Windows_NT");
1715 Status = NtSetValueKey(KeyHandle,
1716 &ValueName,
1717 0,
1718 REG_SZ,
1719 L"Windows_NT",
1720 wcslen(L"Windows_NT") * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1721 if (!NT_SUCCESS(Status))
1722 {
1723 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1724 &ValueName, Status);
1725 NtClose(KeyHandle);
1726 return Status;
1727 }
1728
1729 /* Next, let's write the CPU architecture variable */
1730 RtlInitUnicodeString(&ValueName, L"PROCESSOR_ARCHITECTURE");
1731 switch (ProcessorInfo.ProcessorArchitecture)
1732 {
1733 /* Pick the correct string that matches the architecture */
1734 case PROCESSOR_ARCHITECTURE_INTEL:
1735 ArchName = L"x86";
1736 break;
1737
1738 case PROCESSOR_ARCHITECTURE_AMD64:
1739 ArchName = L"AMD64";
1740 break;
1741
1742 case PROCESSOR_ARCHITECTURE_IA64:
1743 ArchName = L"IA64";
1744 break;
1745
1746 default:
1747 ArchName = L"Unknown";
1748 break;
1749 }
1750
1751 /* Set it */
1752 DPRINT("Setting %wZ to %S\n", &ValueName, ArchName);
1753 Status = NtSetValueKey(KeyHandle,
1754 &ValueName,
1755 0,
1756 REG_SZ,
1757 ArchName,
1758 wcslen(ArchName) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1759 if (!NT_SUCCESS(Status))
1760 {
1761 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1762 &ValueName, Status);
1763 NtClose(KeyHandle);
1764 return Status;
1765 }
1766
1767 /* And now let's write the processor level */
1768 RtlInitUnicodeString(&ValueName, L"PROCESSOR_LEVEL");
1769 swprintf(ValueBuffer, L"%u", ProcessorInfo.ProcessorLevel);
1770 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
1771 Status = NtSetValueKey(KeyHandle,
1772 &ValueName,
1773 0,
1774 REG_SZ,
1775 ValueBuffer,
1776 wcslen(ValueBuffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1777 if (!NT_SUCCESS(Status))
1778 {
1779 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1780 &ValueName, Status);
1781 NtClose(KeyHandle);
1782 return Status;
1783 }
1784
1785 /* Now open the hardware CPU key */
1786 RtlInitUnicodeString(&DestinationString,
1787 L"\\Registry\\Machine\\Hardware\\Description\\System\\"
1788 L"CentralProcessor\\0");
1789 InitializeObjectAttributes(&ObjectAttributes,
1790 &DestinationString,
1791 OBJ_CASE_INSENSITIVE,
1792 NULL,
1793 NULL);
1794 Status = NtOpenKey(&KeyHandle2, KEY_READ, &ObjectAttributes);
1795 if (!NT_SUCCESS(Status))
1796 {
1797 DPRINT1("SMSS: Unable to open %wZ - %x\n", &DestinationString, Status);
1798 NtClose(KeyHandle);
1799 return Status;
1800 }
1801
1802 /* So that we can read the identifier out of it... */
1803 RtlInitUnicodeString(&ValueName, L"Identifier");
1804 Status = NtQueryValueKey(KeyHandle2,
1805 &ValueName,
1806 KeyValuePartialInformation,
1807 PartialInfo,
1808 sizeof(ValueBuffer),
1809 &ResultLength);
1810 if (!NT_SUCCESS(Status))
1811 {
1812 NtClose(KeyHandle2);
1813 NtClose(KeyHandle);
1814 DPRINT1("SMSS: Unable to read %wZ\\%wZ - %x\n",
1815 &DestinationString, &ValueName, Status);
1816 return Status;
1817 }
1818
1819 /* As well as the vendor... */
1820 RtlInitUnicodeString(&ValueName, L"VendorIdentifier");
1821 Status = NtQueryValueKey(KeyHandle2,
1822 &ValueName,
1823 KeyValuePartialInformation,
1824 PartialInfo2,
1825 sizeof(ValueBuffer2),
1826 &ResultLength);
1827 NtClose(KeyHandle2);
1828 if (NT_SUCCESS(Status))
1829 {
1830 /* To combine it into a single string */
1831 swprintf((PWCHAR)PartialInfo->Data + wcslen((PWCHAR)PartialInfo->Data),
1832 L", %ws",
1833 PartialInfo2->Data);
1834 }
1835
1836 /* So that we can set this as the PROCESSOR_IDENTIFIER variable */
1837 RtlInitUnicodeString(&ValueName, L"PROCESSOR_IDENTIFIER");
1838 DPRINT("Setting %wZ to %S\n", &ValueName, PartialInfo->Data);
1839 Status = NtSetValueKey(KeyHandle,
1840 &ValueName,
1841 0,
1842 REG_SZ,
1843 PartialInfo->Data,
1844 wcslen((PWCHAR)PartialInfo->Data) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1845 if (!NT_SUCCESS(Status))
1846 {
1847 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1848 &ValueName, Status);
1849 NtClose(KeyHandle);
1850 return Status;
1851 }
1852
1853 /* Now let's get the processor architecture */
1854 RtlInitUnicodeString(&ValueName, L"PROCESSOR_REVISION");
1855 switch (ProcessorInfo.ProcessorArchitecture)
1856 {
1857 /* Check if this is an older Intel CPU */
1858 case PROCESSOR_ARCHITECTURE_INTEL:
1859 if ((ProcessorInfo.ProcessorRevision >> 8) == 0xFF)
1860 {
1861 /* These guys used a revision + stepping, so get the rev only */
1862 swprintf(ValueBuffer, L"%02x", ProcessorInfo.ProcessorRevision & 0xFF);
1863 _wcsupr(ValueBuffer);
1864 break;
1865 }
1866
1867 /* Modern Intel, as well as 64-bit CPUs use a revision without stepping */
1868 case PROCESSOR_ARCHITECTURE_IA64:
1869 case PROCESSOR_ARCHITECTURE_AMD64:
1870 swprintf(ValueBuffer, L"%04x", ProcessorInfo.ProcessorRevision);
1871 break;
1872
1873 /* And anything else we'll just read the whole revision identifier */
1874 default:
1875 swprintf(ValueBuffer, L"%u", ProcessorInfo.ProcessorRevision);
1876 break;
1877 }
1878
1879 /* Write the revision to the registry */
1880 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
1881 Status = NtSetValueKey(KeyHandle,
1882 &ValueName,
1883 0,
1884 REG_SZ,
1885 ValueBuffer,
1886 wcslen(ValueBuffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1887 if (!NT_SUCCESS(Status))
1888 {
1889 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1890 &ValueName, Status);
1891 NtClose(KeyHandle);
1892 return Status;
1893 }
1894
1895 /* And finally, write the number of CPUs */
1896 RtlInitUnicodeString(&ValueName, L"NUMBER_OF_PROCESSORS");
1897 swprintf(ValueBuffer, L"%u", BasicInfo.NumberOfProcessors);
1898 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
1899 Status = NtSetValueKey(KeyHandle,
1900 &ValueName,
1901 0,
1902 REG_SZ,
1903 ValueBuffer,
1904 wcslen(ValueBuffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1905 if (!NT_SUCCESS(Status))
1906 {
1907 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1908 &ValueName, Status);
1909 NtClose(KeyHandle);
1910 return Status;
1911 }
1912
1913 /* Now we need to write the safeboot option key in a different format */
1914 RtlInitUnicodeString(&DestinationString,
1915 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
1916 L"Control\\Safeboot\\Option");
1917 InitializeObjectAttributes(&ObjectAttributes,
1918 &DestinationString,
1919 OBJ_CASE_INSENSITIVE,
1920 NULL,
1921 NULL);
1922 Status = NtOpenKey(&KeyHandle2, KEY_ALL_ACCESS, &ObjectAttributes);
1923 if (NT_SUCCESS(Status))
1924 {
1925 /* This was indeed a safeboot, so check what kind of safeboot it was */
1926 RtlInitUnicodeString(&ValueName, L"OptionValue");
1927 Status = NtQueryValueKey(KeyHandle2,
1928 &ValueName,
1929 KeyValuePartialInformation,
1930 PartialInfo,
1931 sizeof(ValueBuffer),
1932 &ResultLength);
1933 NtClose(KeyHandle2);
1934 if (NT_SUCCESS(Status))
1935 {
1936 /* Convert from the integer value to the correct specifier */
1937 RtlInitUnicodeString(&ValueName, L"SAFEBOOT_OPTION");
1938 switch (*(PULONG)PartialInfo->Data)
1939 {
1940 case 1:
1941 wcscpy(ValueBuffer, L"MINIMAL");
1942 break;
1943 case 2:
1944 wcscpy(ValueBuffer, L"NETWORK");
1945 break;
1946 case 3:
1947 wcscpy(ValueBuffer, L"DSREPAIR");
1948 break;
1949 }
1950
1951 /* And write it in the environment! */
1952 DPRINT("Setting %wZ to %S\n", &ValueName, ValueBuffer);
1953 Status = NtSetValueKey(KeyHandle,
1954 &ValueName,
1955 0,
1956 REG_SZ,
1957 ValueBuffer,
1958 wcslen(ValueBuffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1959 if (!NT_SUCCESS(Status))
1960 {
1961 DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
1962 &ValueName, Status);
1963 NtClose(KeyHandle);
1964 return Status;
1965 }
1966 }
1967 else
1968 {
1969 DPRINT1("SMSS: Failed querying safeboot option = %x\n", Status);
1970 }
1971 }
1972
1973 /* We are all done now */
1974 NtClose(KeyHandle);
1975 return STATUS_SUCCESS;
1976 }
1977
1978 NTSTATUS
1979 NTAPI
1980 SmpProcessFileRenames(VOID)
1981 {
1982 BOOLEAN OldState, HavePrivilege = FALSE;
1983 NTSTATUS Status;
1984 HANDLE FileHandle, OtherFileHandle;
1985 FILE_INFORMATION_CLASS InformationClass;
1986 OBJECT_ATTRIBUTES ObjectAttributes;
1987 IO_STATUS_BLOCK IoStatusBlock;
1988 UNICODE_STRING FileString;
1989 FILE_BASIC_INFORMATION BasicInfo;
1990 FILE_DISPOSITION_INFORMATION DeleteInformation;
1991 PFILE_RENAME_INFORMATION Buffer;
1992 PLIST_ENTRY Head, NextEntry;
1993 PSMP_REGISTRY_VALUE RegEntry;
1994 PWCHAR FileName;
1995 ULONG ValueLength, Length;
1996
1997 /* Give us access to restore any files we want */
1998 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &OldState);
1999 if (NT_SUCCESS(Status)) HavePrivilege = TRUE;
2000
2001 /* Process pending files to rename */
2002 Head = &SmpFileRenameList;
2003 while (!IsListEmpty(Head))
2004 {
2005 /* Get this entry */
2006 NextEntry = RemoveHeadList(Head);
2007 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
2008 DPRINT1("Processing PFRO: %wZ/%wZ\n", &RegEntry->Value, &RegEntry->Name);
2009
2010 /* Skip past the '@' marker */
2011 if (!(RegEntry->Value.Length) && (*RegEntry->Name.Buffer == L'@'))
2012 {
2013 RegEntry->Name.Length -= sizeof(UNICODE_NULL);
2014 RegEntry->Name.Buffer++;
2015 }
2016
2017 /* Open the file for delete access */
2018 InitializeObjectAttributes(&ObjectAttributes,
2019 &RegEntry->Name,
2020 OBJ_CASE_INSENSITIVE,
2021 NULL,
2022 NULL);
2023 Status = NtOpenFile(&OtherFileHandle,
2024 DELETE | SYNCHRONIZE,
2025 &ObjectAttributes,
2026 &IoStatusBlock,
2027 FILE_SHARE_READ | FILE_SHARE_WRITE,
2028 FILE_SYNCHRONOUS_IO_NONALERT);
2029 if (!NT_SUCCESS(Status)) goto Quickie;
2030
2031 /* Check if it's a rename or just a delete */
2032 ValueLength = RegEntry->Value.Length;
2033 if (!ValueLength)
2034 {
2035 /* Just a delete, set up the class, length and buffer */
2036 InformationClass = FileDispositionInformation;
2037 Length = sizeof(DeleteInformation);
2038 Buffer = (PFILE_RENAME_INFORMATION)&DeleteInformation;
2039
2040 /* Set the delete disposition */
2041 DeleteInformation.DeleteFile = TRUE;
2042 }
2043 else
2044 {
2045 /* This is a rename, setup the class and length */
2046 InformationClass = FileRenameInformation;
2047 Length = ValueLength + sizeof(FILE_RENAME_INFORMATION);
2048
2049 /* Skip past the special markers */
2050 FileName = RegEntry->Value.Buffer;
2051 if ((*FileName == L'!') || (*FileName == L'@'))
2052 {
2053 FileName++;
2054 Length -= sizeof(UNICODE_NULL);
2055 }
2056
2057 /* Now allocate the buffer for the rename information */
2058 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), SmBaseTag, Length);
2059 if (Buffer)
2060 {
2061 /* Setup the buffer to point to the filename, and copy it */
2062 Buffer->RootDirectory = NULL;
2063 Buffer->FileNameLength = Length - sizeof(FILE_RENAME_INFORMATION);
2064 Buffer->ReplaceIfExists = FileName != RegEntry->Value.Buffer;
2065 RtlCopyMemory(Buffer->FileName, FileName, Buffer->FileNameLength);
2066 }
2067 else
2068 {
2069 /* Fail */
2070 Status = STATUS_NO_MEMORY;
2071 }
2072 }
2073
2074 /* Check if everything is okay till here */
2075 if (NT_SUCCESS(Status))
2076 {
2077 /* Now either rename or delete the file as requested */
2078 Status = NtSetInformationFile(OtherFileHandle,
2079 &IoStatusBlock,
2080 Buffer,
2081 Length,
2082 InformationClass);
2083
2084 /* Check if we seem to have failed because the file was readonly */
2085 if ((NT_SUCCESS(Status) &&
2086 (InformationClass == FileRenameInformation) &&
2087 (Status == STATUS_OBJECT_NAME_COLLISION) &&
2088 (Buffer->ReplaceIfExists)))
2089 {
2090 /* Open the file for write attribute access this time... */
2091 DPRINT1("\nSMSS: %wZ => %wZ failed - Status == %x, Possible readonly target\n",
2092 &RegEntry->Name,
2093 &RegEntry->Value,
2094 STATUS_OBJECT_NAME_COLLISION);
2095 FileString.Length = RegEntry->Value.Length - sizeof(WCHAR);
2096 FileString.MaximumLength = RegEntry->Value.MaximumLength - sizeof(WCHAR);
2097 FileString.Buffer = FileName;
2098 InitializeObjectAttributes(&ObjectAttributes,
2099 &FileString,
2100 OBJ_CASE_INSENSITIVE,
2101 NULL,
2102 NULL);
2103 Status = NtOpenFile(&FileHandle,
2104 FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
2105 &ObjectAttributes,
2106 &IoStatusBlock,
2107 FILE_SHARE_READ | FILE_SHARE_WRITE,
2108 FILE_SYNCHRONOUS_IO_NONALERT);
2109 if (!NT_SUCCESS(Status))
2110 {
2111 /* That didn't work, so bail out */
2112 DPRINT1(" SMSS: Open Existing file Failed - Status == %x\n",
2113 Status);
2114 }
2115 else
2116 {
2117 /* Now remove the read-only attribute from the file */
2118 DPRINT1(" SMSS: Open Existing Success\n");
2119 RtlZeroMemory(&BasicInfo, sizeof(BasicInfo));
2120 BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
2121 Status = NtSetInformationFile(FileHandle,
2122 &IoStatusBlock,
2123 &BasicInfo,
2124 sizeof(BasicInfo),
2125 FileBasicInformation);
2126 NtClose(FileHandle);
2127 if (!NT_SUCCESS(Status))
2128 {
2129 /* That didn't work, bail out */
2130 DPRINT1(" SMSS: Set To NORMAL Failed - Status == %x\n",
2131 Status);
2132 }
2133 else
2134 {
2135 /* Now that the file is no longer read-only, delete! */
2136 DPRINT1(" SMSS: Set To NORMAL OK\n");
2137 Status = NtSetInformationFile(OtherFileHandle,
2138 &IoStatusBlock,
2139 Buffer,
2140 Length,
2141 FileRenameInformation);
2142 if (!NT_SUCCESS(Status))
2143 {
2144 /* That failed too! */
2145 DPRINT1(" SMSS: Re-Rename Failed - Status == %x\n",
2146 Status);
2147 }
2148 else
2149 {
2150 /* Everything ok */
2151 DPRINT1(" SMSS: Re-Rename Worked OK\n");
2152 }
2153 }
2154 }
2155 }
2156 }
2157
2158 /* Close the file handle and check the operation result */
2159 NtClose(OtherFileHandle);
2160 Quickie:
2161 if (!NT_SUCCESS(Status))
2162 {
2163 /* We totally failed */
2164 DPRINT1("SMSS: %wZ => %wZ failed - Status == %x\n",
2165 &RegEntry->Name, &RegEntry->Value, Status);
2166 }
2167 else if (RegEntry->Value.Length)
2168 {
2169 /* We succeed with a rename */
2170 DPRINT1("SMSS: %wZ (renamed to) %wZ\n", &RegEntry->Name, &RegEntry->Value);
2171 }
2172 else
2173 {
2174 /* We suceeded with a delete */
2175 DPRINT1("SMSS: %wZ (deleted)\n", &RegEntry->Name);
2176 }
2177
2178 /* Now free this entry and keep going */
2179 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
2180 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
2181 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
2182 }
2183
2184 /* Put back the restore privilege if we had requested it, and return */
2185 if (HavePrivilege) RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, FALSE, FALSE, &OldState);
2186 return Status;
2187 }
2188
2189 NTSTATUS
2190 NTAPI
2191 SmpLoadDataFromRegistry(OUT PUNICODE_STRING InitialCommand)
2192 {
2193 NTSTATUS Status;
2194 PLIST_ENTRY Head, NextEntry;
2195 PSMP_REGISTRY_VALUE RegEntry;
2196 PVOID OriginalEnvironment;
2197 ULONG MuSessionId = 0;
2198 OBJECT_ATTRIBUTES ObjectAttributes;
2199 HANDLE KeyHandle;
2200 UNICODE_STRING DestinationString;
2201
2202 /* Initialize the keywords we'll be looking for */
2203 RtlInitUnicodeString(&SmpDebugKeyword, L"debug");
2204 RtlInitUnicodeString(&SmpASyncKeyword, L"async");
2205 RtlInitUnicodeString(&SmpAutoChkKeyword, L"autocheck");
2206
2207 /* Initialize all the registry-associated list heads */
2208 InitializeListHead(&SmpBootExecuteList);
2209 InitializeListHead(&SmpSetupExecuteList);
2210 InitializeListHead(&SmpPagingFileList);
2211 InitializeListHead(&SmpDosDevicesList);
2212 InitializeListHead(&SmpFileRenameList);
2213 InitializeListHead(&SmpKnownDllsList);
2214 InitializeListHead(&SmpExcludeKnownDllsList);
2215 InitializeListHead(&SmpSubSystemList);
2216 InitializeListHead(&SmpSubSystemsToLoad);
2217 InitializeListHead(&SmpSubSystemsToDefer);
2218 InitializeListHead(&SmpExecuteList);
2219 SmpPagingFileInitialize();
2220
2221 /* Initialize the SMSS environment */
2222 Status = RtlCreateEnvironment(TRUE, &SmpDefaultEnvironment);
2223 if (!NT_SUCCESS(Status))
2224 {
2225 /* Fail if there was a problem */
2226 DPRINT1("SMSS: Unable to allocate default environment - Status == %X\n",
2227 Status);
2228 SMSS_CHECKPOINT(RtlCreateEnvironment, Status);
2229 return Status;
2230 }
2231
2232 /* Check if we were booted in PE mode (LiveCD should have this) */
2233 RtlInitUnicodeString(&DestinationString,
2234 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
2235 L"Control\\MiniNT");
2236 InitializeObjectAttributes(&ObjectAttributes,
2237 &DestinationString,
2238 OBJ_CASE_INSENSITIVE,
2239 NULL,
2240 NULL);
2241 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
2242 if (NT_SUCCESS(Status))
2243 {
2244 /* If the key exists, we were */
2245 NtClose(KeyHandle);
2246 MiniNTBoot = TRUE;
2247 }
2248
2249 /* Print out if this is the case */
2250 if (MiniNTBoot) DPRINT1("SMSS: !!! MiniNT Boot !!!\n");
2251
2252 /* Open the environment key to see if we are booted in safe mode */
2253 RtlInitUnicodeString(&DestinationString,
2254 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
2255 L"Control\\Session Manager\\Environment");
2256 InitializeObjectAttributes(&ObjectAttributes,
2257 &DestinationString,
2258 OBJ_CASE_INSENSITIVE,
2259 NULL,
2260 NULL);
2261 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
2262 if (NT_SUCCESS(Status))
2263 {
2264 /* Delete the value if we found it */
2265 RtlInitUnicodeString(&DestinationString, L"SAFEBOOT_OPTION");
2266 NtDeleteValueKey(KeyHandle, &DestinationString);
2267 NtClose(KeyHandle);
2268 }
2269
2270 /* Switch environments, then query the registry for all needed settings */
2271 OriginalEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
2272 NtCurrentPeb()->ProcessParameters->Environment = SmpDefaultEnvironment;
2273 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
2274 L"Session Manager",
2275 SmpRegistryConfigurationTable,
2276 NULL,
2277 NULL);
2278 SmpDefaultEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
2279 NtCurrentPeb()->ProcessParameters->Environment = OriginalEnvironment;
2280 if (!NT_SUCCESS(Status))
2281 {
2282 /* We failed somewhere in registry initialization, which is bad... */
2283 DPRINT1("SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status);
2284 SMSS_CHECKPOINT(RtlQueryRegistryValues, Status);
2285 return Status;
2286 }
2287
2288 /* Now we can start acting on the registry settings. First to DOS devices */
2289 Status = SmpInitializeDosDevices();
2290 if (!NT_SUCCESS(Status))
2291 {
2292 /* Failed */
2293 DPRINT1("SMSS: Unable to initialize DosDevices configuration - Status == %lx\n",
2294 Status);
2295 SMSS_CHECKPOINT(SmpInitializeDosDevices, Status);
2296 return Status;
2297 }
2298
2299 /* Next create the session directory... */
2300 RtlInitUnicodeString(&DestinationString, L"\\Sessions");
2301 InitializeObjectAttributes(&ObjectAttributes,
2302 &DestinationString,
2303 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
2304 NULL,
2305 SmpPrimarySecurityDescriptor);
2306 Status = NtCreateDirectoryObject(&SmpSessionsObjectDirectory,
2307 DIRECTORY_ALL_ACCESS,
2308 &ObjectAttributes);
2309 if (!NT_SUCCESS(Status))
2310 {
2311 /* Fail */
2312 DPRINT1("SMSS: Unable to create %wZ object directory - Status == %lx\n",
2313 &DestinationString, Status);
2314 SMSS_CHECKPOINT(NtCreateDirectoryObject, Status);
2315 return Status;
2316 }
2317
2318 /* Next loop all the boot execute binaries */
2319 Head = &SmpBootExecuteList;
2320 while (!IsListEmpty(Head))
2321 {
2322 /* Remove each one from the list */
2323 NextEntry = RemoveHeadList(Head);
2324
2325 /* Execute it */
2326 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
2327 SmpExecuteCommand(&RegEntry->Name, 0, NULL, 0);
2328
2329 /* And free it */
2330 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
2331 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
2332 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
2333 }
2334
2335 /* Now do any pending file rename operations... */
2336 if (!MiniNTBoot) SmpProcessFileRenames();
2337
2338 /* And initialize known DLLs... */
2339 Status = SmpInitializeKnownDlls();
2340 if (!NT_SUCCESS(Status))
2341 {
2342 /* Fail if that didn't work */
2343 DPRINT1("SMSS: Unable to initialize KnownDll configuration - Status == %lx\n",
2344 Status);
2345 SMSS_CHECKPOINT(SmpInitializeKnownDlls, Status);
2346 return Status;
2347 }
2348
2349 /* Loop every page file */
2350 Head = &SmpPagingFileList;
2351 while (!IsListEmpty(Head))
2352 {
2353 /* Remove each one from the list */
2354 NextEntry = RemoveHeadList(Head);
2355
2356 /* Create the descriptor for it */
2357 RegEntry = CONTAINING_RECORD(NextEntry, SMP_REGISTRY_VALUE, Entry);
2358 SmpCreatePagingFileDescriptor(&RegEntry->Name);
2359
2360 /* And free it */
2361 if (RegEntry->AnsiValue) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->AnsiValue);
2362 if (RegEntry->Value.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry->Value.Buffer);
2363 RtlFreeHeap(RtlGetProcessHeap(), 0, RegEntry);
2364 }
2365
2366 /* Now create all the paging files for the descriptors that we have */
2367 SmpCreatePagingFiles();
2368
2369 /* Tell Cm it's now safe to fully enable write access to the registry */
2370 NtInitializeRegistry(CM_BOOT_FLAG_SMSS);
2371
2372 /* Create all the system-based environment variables for later inheriting */
2373 Status = SmpCreateDynamicEnvironmentVariables();
2374 if (!NT_SUCCESS(Status))
2375 {
2376 /* Handle failure */
2377 SMSS_CHECKPOINT(SmpCreateDynamicEnvironmentVariables, Status);
2378 return Status;
2379 }
2380
2381 /* And finally load all the subsytems for our first session! */
2382 Status = SmpLoadSubSystemsForMuSession(&MuSessionId,
2383 &SmpWindowsSubSysProcessId,
2384 InitialCommand);
2385 ASSERT(MuSessionId == 0);
2386 if (!NT_SUCCESS(Status)) SMSS_CHECKPOINT(SmpLoadSubSystemsForMuSession, Status);
2387 return Status;
2388 }
2389
2390 NTSTATUS
2391 NTAPI
2392 SmpInit(IN PUNICODE_STRING InitialCommand,
2393 OUT PHANDLE ProcessHandle)
2394 {
2395 NTSTATUS Status, Status2;
2396 OBJECT_ATTRIBUTES ObjectAttributes;
2397 UNICODE_STRING PortName, EventName;
2398 HANDLE EventHandle, PortHandle;
2399 ULONG HardErrorMode;
2400
2401 /* Create the SMSS Heap */
2402 SmBaseTag = RtlCreateTagHeap(RtlGetProcessHeap(),
2403 0,
2404 L"SMSS!",
2405 L"INIT");
2406 SmpHeap = RtlGetProcessHeap();
2407
2408 /* Enable hard errors */
2409 HardErrorMode = TRUE;
2410 NtSetInformationProcess(NtCurrentProcess(),
2411 ProcessDefaultHardErrorMode,
2412 &HardErrorMode,
2413 sizeof(HardErrorMode));
2414
2415 /* Initialize the subsystem list and the session list, plus their locks */
2416 RtlInitializeCriticalSection(&SmpKnownSubSysLock);
2417 InitializeListHead(&SmpKnownSubSysHead);
2418 RtlInitializeCriticalSection(&SmpSessionListLock);
2419 InitializeListHead(&SmpSessionListHead);
2420
2421 /* Initialize the process list */
2422 InitializeListHead(&NativeProcessList);
2423
2424 /* Initialize session parameters */
2425 SmpNextSessionId = 1;
2426 SmpNextSessionIdScanMode = 0;
2427 SmpDbgSsLoaded = FALSE;
2428
2429 /* Create the initial security descriptors */
2430 Status = SmpCreateSecurityDescriptors(TRUE);
2431 if (!NT_SUCCESS(Status))
2432 {
2433 /* Fail */
2434 SMSS_CHECKPOINT(SmpCreateSecurityDescriptors, Status);
2435 return Status;
2436 }
2437
2438 /* Initialize subsystem names */
2439 RtlInitUnicodeString(&SmpSubsystemName, L"NT-Session Manager");
2440 RtlInitUnicodeString(&PosixName, L"POSIX");
2441 RtlInitUnicodeString(&Os2Name, L"OS2");
2442
2443 /* Create the SM API Port */
2444 RtlInitUnicodeString(&PortName, L"\\SmApiPort2");
2445 InitializeObjectAttributes(&ObjectAttributes, &PortName, 0, NULL, NULL);
2446 Status = NtCreatePort(&PortHandle,
2447 &ObjectAttributes,
2448 sizeof(SB_CONNECTION_INFO),
2449 sizeof(SM_API_MSG),
2450 sizeof(SB_API_MSG) * 32);
2451 ASSERT(NT_SUCCESS(Status));
2452 SmpDebugPort = PortHandle;
2453
2454 /* Create two SM API threads */
2455 Status = RtlCreateUserThread(NtCurrentProcess(),
2456 NULL,
2457 FALSE,
2458 0,
2459 0,
2460 0,
2461 SmpApiLoop,
2462 PortHandle,
2463 NULL,
2464 NULL);
2465 ASSERT(NT_SUCCESS(Status));
2466 Status = RtlCreateUserThread(NtCurrentProcess(),
2467 NULL,
2468 FALSE,
2469 0,
2470 0,
2471 0,
2472 SmpApiLoop,
2473 PortHandle,
2474 NULL,
2475 NULL);
2476 ASSERT(NT_SUCCESS(Status));
2477
2478 /* Create the write event that autochk can set after running */
2479 RtlInitUnicodeString(&EventName, L"\\Device\\VolumesSafeForWriteAccess");
2480 InitializeObjectAttributes(&ObjectAttributes,
2481 &EventName,
2482 OBJ_PERMANENT,
2483 NULL,
2484 NULL);
2485 Status2 = NtCreateEvent(&EventHandle,
2486 EVENT_ALL_ACCESS,
2487 &ObjectAttributes,
2488 0,
2489 0);
2490 if (!NT_SUCCESS(Status2))
2491 {
2492 /* Should never really fail */
2493 DPRINT1("SMSS: Unable to create %wZ event - Status == %lx\n",
2494 &EventName, Status2);
2495 ASSERT(NT_SUCCESS(Status2));
2496 }
2497
2498 /* Now initialize everything else based on the registry parameters */
2499 Status = SmpLoadDataFromRegistry(InitialCommand);
2500 if (NT_SUCCESS(Status))
2501 {
2502 /* Autochk should've run now. Set the event and save the CSRSS handle */
2503 *ProcessHandle = SmpWindowsSubSysProcess;
2504 NtSetEvent(EventHandle, 0);
2505 NtClose(EventHandle);
2506 }
2507
2508 /* All done */
2509 return Status;
2510 }