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