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