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