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