2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmsysini.c
5 * PURPOSE: Configuration Manager - System Initialization Code
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 HIVE_LIST_ENTRY CmpMachineHiveList
[5];
20 UNICODE_STRING CmSymbolicLinkValueName
=
21 RTL_CONSTANT_STRING(L
"SymbolicLinkValue");
23 UNICODE_STRING CmpSystemStartOptions
;
24 UNICODE_STRING CmpLoadOptions
;
26 BOOLEAN CmpShareSystemHives
;
27 BOOLEAN CmSelfHeal
= TRUE
;
28 BOOLEAN CmpSelfHeal
= TRUE
;
31 HANDLE CmpRegistryRootHandle
;
33 extern BOOLEAN ExpInTextModeSetup
;
35 /* FUNCTIONS *****************************************************************/
39 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
41 OBJECT_ATTRIBUTES ObjectAttributes
;
42 UNICODE_STRING KeyName
, ValueName
;
45 ASSERT(LoaderBlock
!= NULL
);
46 if (ExpInTextModeSetup
) return STATUS_SUCCESS
;
48 /* Setup attributes for loader options */
49 RtlInitUnicodeString(&KeyName
,
50 L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
52 InitializeObjectAttributes(&ObjectAttributes
,
57 Status
= NtOpenKey(&KeyHandle
, KEY_WRITE
, &ObjectAttributes
);
58 if (!NT_SUCCESS(Status
)) goto Quickie
;
60 /* Key opened, now write to the key */
61 RtlInitUnicodeString(&KeyName
, L
"SystemStartOptions");
62 Status
= NtSetValueKey(KeyHandle
,
66 CmpSystemStartOptions
.Buffer
,
67 CmpSystemStartOptions
.Length
);
68 if (!NT_SUCCESS(Status
)) goto Quickie
;
70 /* Free the options now */
71 ExFreePool(CmpSystemStartOptions
.Buffer
);
73 /* Setup value name for system boot device */
74 RtlInitUnicodeString(&KeyName
, L
"SystemBootDevice");
75 RtlCreateUnicodeStringFromAsciiz(&ValueName
, LoaderBlock
->NtBootPathName
);
76 Status
= NtSetValueKey(KeyHandle
,
84 /* Free the buffers */
85 RtlFreeUnicodeString(&ValueName
);
87 /* Close the key and return */
90 /* Return the status */
96 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
98 UNICODE_STRING ConfigName
= RTL_CONSTANT_STRING(L
"Control\\IDConfigDB");
99 UNICODE_STRING SelectName
=
100 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\Select");
101 UNICODE_STRING KeyName
;
102 OBJECT_ATTRIBUTES ObjectAttributes
;
103 CHAR ValueInfoBuffer
[128];
104 PKEY_VALUE_FULL_INFORMATION ValueInfo
;
106 WCHAR UnicodeBuffer
[128];
107 HANDLE SelectHandle
, KeyHandle
, ConfigHandle
= NULL
, ProfileHandle
= NULL
;
108 HANDLE ParentHandle
= NULL
;
109 ULONG ControlSet
, HwProfile
;
110 ANSI_STRING TempString
;
112 ULONG ResultLength
, Disposition
;
113 PLOADER_PARAMETER_EXTENSION LoaderExtension
;
115 if (ExpInTextModeSetup
) return STATUS_SUCCESS
;
117 /* Open the select key */
118 InitializeObjectAttributes(&ObjectAttributes
,
120 OBJ_CASE_INSENSITIVE
,
123 Status
= NtOpenKey(&SelectHandle
, KEY_READ
, &ObjectAttributes
);
124 if (!NT_SUCCESS(Status
)) return(Status
);
126 /* Open the current value */
127 RtlInitUnicodeString(&KeyName
, L
"Current");
128 Status
= NtQueryValueKey(SelectHandle
,
130 KeyValueFullInformation
,
132 sizeof(ValueInfoBuffer
),
134 NtClose(SelectHandle
);
135 if (!NT_SUCCESS(Status
)) return Status
;
137 /* Get the actual value pointer, and get the control set ID */
138 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
139 ControlSet
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
141 /* Create the current control set key */
142 RtlInitUnicodeString(&KeyName
,
143 L
"\\Registry\\Machine\\System\\CurrentControlSet");
144 InitializeObjectAttributes(&ObjectAttributes
,
146 OBJ_CASE_INSENSITIVE
,
149 Status
= NtCreateKey(&KeyHandle
,
154 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
156 if (!NT_SUCCESS(Status
)) return Status
;
159 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
161 /* Initialize the symbolic link name */
163 "\\Registry\\Machine\\System\\ControlSet%03ld",
165 RtlInitAnsiString(&TempString
, Buffer
);
167 /* Create a Unicode string out of it */
168 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
169 KeyName
.Buffer
= UnicodeBuffer
;
170 Status
= RtlAnsiStringToUnicodeString(&KeyName
, &TempString
, FALSE
);
173 Status
= NtSetValueKey(KeyHandle
,
174 &CmSymbolicLinkValueName
,
179 if (!NT_SUCCESS(Status
)) return Status
;
181 /* Get the configuration database key */
182 InitializeObjectAttributes(&ObjectAttributes
,
184 OBJ_CASE_INSENSITIVE
,
187 Status
= NtOpenKey(&ConfigHandle
, KEY_READ
, &ObjectAttributes
);
190 /* Check if we don't have one */
191 if (!NT_SUCCESS(Status
))
193 /* Cleanup and exit */
198 /* Now get the current config */
199 RtlInitUnicodeString(&KeyName
, L
"CurrentConfig");
200 Status
= NtQueryValueKey(ConfigHandle
,
202 KeyValueFullInformation
,
204 sizeof(ValueInfoBuffer
),
207 /* Set pointer to buffer */
208 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
210 /* Check if we failed or got a non DWORD-value */
211 if (!(NT_SUCCESS(Status
)) || (ValueInfo
->Type
!= REG_DWORD
)) goto Cleanup
;
213 /* Get the hadware profile */
214 HwProfile
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
216 /* Open the hardware profile key */
217 RtlInitUnicodeString(&KeyName
,
218 L
"\\Registry\\Machine\\System\\CurrentControlSet"
219 L
"\\Hardware Profiles");
220 InitializeObjectAttributes(&ObjectAttributes
,
222 OBJ_CASE_INSENSITIVE
,
225 Status
= NtOpenKey(&ParentHandle
, KEY_READ
, &ObjectAttributes
);
226 if (!NT_SUCCESS(Status
))
228 /* Exit and clean up */
233 /* Build the profile name */
234 sprintf(Buffer
, "%04ld", HwProfile
);
235 RtlInitAnsiString(&TempString
, Buffer
);
237 /* Convert it to Unicode */
238 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
239 KeyName
.Buffer
= UnicodeBuffer
;
240 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
243 ASSERT(Status
== STATUS_SUCCESS
);
245 /* Open the associated key */
246 InitializeObjectAttributes(&ObjectAttributes
,
248 OBJ_CASE_INSENSITIVE
,
251 Status
= NtOpenKey(&ProfileHandle
,
252 KEY_READ
| KEY_WRITE
,
254 if (!NT_SUCCESS (Status
))
256 /* Cleanup and exit */
261 /* Check if we have a loader block extension */
262 LoaderExtension
= LoaderBlock
->Extension
;
265 ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE
);
268 /* Create the current hardware profile key */
269 RtlInitUnicodeString(&KeyName
,
270 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
271 L
"Hardware Profiles\\Current");
272 InitializeObjectAttributes(&ObjectAttributes
,
274 OBJ_CASE_INSENSITIVE
,
277 Status
= NtCreateKey(&KeyHandle
,
282 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
284 if (NT_SUCCESS(Status
))
287 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
289 /* Create the profile name */
291 "\\Registry\\Machine\\System\\CurrentControlSet\\"
292 "Hardware Profiles\\%04ld",
294 RtlInitAnsiString(&TempString
, Buffer
);
296 /* Convert it to Unicode */
297 KeyName
.MaximumLength
= sizeof(UnicodeBuffer
);
298 KeyName
.Buffer
= UnicodeBuffer
;
299 Status
= RtlAnsiStringToUnicodeString(&KeyName
,
302 ASSERT(STATUS_SUCCESS
== Status
);
305 Status
= NtSetValueKey(KeyHandle
,
306 &CmSymbolicLinkValueName
,
314 /* Close every opened handle */
316 if (ConfigHandle
) NtClose(ConfigHandle
);
317 if (ProfileHandle
) NtClose(ProfileHandle
);
318 if (ParentHandle
) NtClose(ParentHandle
);
321 return STATUS_SUCCESS
;
326 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
329 ANSI_STRING LoadString
;
334 UNICODE_STRING KeyName
;
335 PEREGISTRY_HIVE SystemHive
= NULL
;
336 UNICODE_STRING HiveName
= RTL_CONSTANT_STRING(L
"SYSTEM");
337 PSECURITY_DESCRIPTOR SecurityDescriptor
;
340 /* Setup the ansi string */
341 RtlInitAnsiString(&LoadString
, LoaderBlock
->LoadOptions
);
343 /* Allocate the unicode buffer */
344 Length
= LoadString
.Length
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
345 Buffer
= ExAllocatePoolWithTag(PagedPool
, Length
, 0);
349 KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO
, 3, 1, (ULONG_PTR
)LoaderBlock
, 0);
352 /* Setup the unicode string */
353 RtlInitEmptyUnicodeString(&CmpLoadOptions
, Buffer
, Length
);
355 /* Add the load options and null-terminate */
356 RtlAnsiStringToUnicodeString(&CmpLoadOptions
, &LoadString
, FALSE
);
357 CmpLoadOptions
.Buffer
[LoadString
.Length
] = UNICODE_NULL
;
358 CmpLoadOptions
.Length
+= sizeof(WCHAR
);
360 /* Get the System Hive base address */
361 HiveBase
= LoaderBlock
->RegistryBase
;
365 ((PHBASE_BLOCK
)HiveBase
)->Length
= LoaderBlock
->RegistryLength
;
366 Status
= CmpInitializeHive((PCMHIVE
*)&SystemHive
,
368 0, //HIVE_NOLAZYFLUSH,
376 if (!NT_SUCCESS(Status
)) return FALSE
;
377 CmPrepareHive(&SystemHive
->Hive
);
379 /* Set the hive filename */
380 RtlCreateUnicodeString(&SystemHive
->HiveFileName
, SYSTEM_REG_FILE
);
382 /* Set the log filename */
383 RtlCreateUnicodeString(&SystemHive
->LogFileName
, SYSTEM_LOG_FILE
);
385 /* We imported, no need to create a new hive */
388 /* Manually set the hive as volatile, if in Live CD mode */
389 if (CmpShareSystemHives
) SystemHive
->Hive
.HiveFlags
= HIVE_VOLATILE
;
395 Status
= CmpInitializeHive((PCMHIVE
*)&SystemHive
,
405 if (!NT_SUCCESS(Status
)) return FALSE
;
408 /* Tell CmpLinkHiveToMaster to allocate a hive */
412 /* Save the boot type */
413 if (SystemHive
) CmpBootType
= SystemHive
->Hive
.HiveHeader
->BootType
;
415 /* Are we in self-healing mode? */
418 /* Disable self-healing internally and check if boot type wanted it */
422 /* We're disabled, so bugcheck */
423 KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO
,
426 (ULONG_PTR
)SystemHive
,
431 /* Create the default security descriptor */
432 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
434 /* Attach it to the system key */
435 RtlInitUnicodeString(&KeyName
, REG_SYSTEM_KEY_NAME
);
436 Status
= CmpLinkHiveToMaster(&KeyName
,
442 /* Free the security descriptor */
443 ExFreePool(SecurityDescriptor
);
444 if (!NT_SUCCESS(Status
)) return FALSE
;
446 /* Add the hive to the hive list */
447 CmpMachineHiveList
[3].CmHive
= (PCMHIVE
)SystemHive
;
455 CmpCreateObjectTypes(VOID
)
457 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
459 GENERIC_MAPPING CmpKeyMapping
= {KEY_READ
,
465 /* Initialize the Key object type */
466 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
467 RtlInitUnicodeString(&Name
, L
"Key");
468 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
469 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(CM_KEY_BODY
);
470 ObjectTypeInitializer
.GenericMapping
= CmpKeyMapping
;
471 ObjectTypeInitializer
.PoolType
= PagedPool
;
472 ObjectTypeInitializer
.ValidAccessMask
= KEY_ALL_ACCESS
;
473 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
474 ObjectTypeInitializer
.DeleteProcedure
= CmpDeleteKeyObject
;
475 ObjectTypeInitializer
.ParseProcedure
= CmpParseKey
;
476 ObjectTypeInitializer
.SecurityProcedure
= CmpSecurityMethod
;
477 ObjectTypeInitializer
.QueryNameProcedure
= CmpQueryKeyName
;
478 //ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;
479 ObjectTypeInitializer
.SecurityRequired
= TRUE
;
482 return ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &CmpKeyObjectType
);
487 CmpCreateRootNode(IN PHHIVE Hive
,
489 OUT PHCELL_INDEX Index
)
491 UNICODE_STRING KeyName
;
492 PCM_KEY_NODE KeyCell
;
493 LARGE_INTEGER SystemTime
;
496 /* Initialize the node name and allocate it */
497 RtlInitUnicodeString(&KeyName
, Name
);
498 *Index
= HvAllocateCell(Hive
,
499 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
500 CmpNameSize(Hive
, &KeyName
),
501 HvStable
); // FIXME: , HCELL_NIL);
502 if (*Index
== HCELL_NIL
) return FALSE
;
504 /* Set the cell index and get the data */
505 Hive
->HiveHeader
->RootCell
= *Index
;
506 KeyCell
= (PCM_KEY_NODE
)HvGetCell(Hive
, *Index
);
507 if (!KeyCell
) return FALSE
;
510 KeyCell
->Signature
= (USHORT
)CM_KEY_NODE_SIGNATURE
;;
511 KeyCell
->Flags
= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
512 KeQuerySystemTime(&SystemTime
);
513 KeyCell
->LastWriteTime
= SystemTime
;
514 KeyCell
->Parent
= HCELL_NIL
;
515 KeyCell
->SubKeyCounts
[HvStable
] = 0;
516 KeyCell
->SubKeyCounts
[HvVolatile
] = 0;
517 KeyCell
->SubKeyLists
[HvStable
] = HCELL_NIL
;
518 KeyCell
->SubKeyLists
[HvVolatile
] = HCELL_NIL
;
519 KeyCell
->ValueList
.Count
= 0;
520 KeyCell
->ValueList
.List
= HCELL_NIL
;
521 KeyCell
->Security
= HCELL_NIL
;
522 KeyCell
->Class
= HCELL_NIL
;
523 KeyCell
->ClassLength
= 0;
524 KeyCell
->MaxNameLen
= 0;
525 KeyCell
->MaxClassLen
= 0;
526 KeyCell
->MaxValueNameLen
= 0;
527 KeyCell
->MaxValueDataLen
= 0;
529 /* Copy the name (this will also set the length) */
530 KeyCell
->NameLength
= CmpCopyName(Hive
, (PWCHAR
)KeyCell
->Name
, &KeyName
);
532 /* Check if the name was compressed */
533 if (KeyCell
->NameLength
< KeyName
.Length
)
536 KeyCell
->Flags
|= KEY_COMP_NAME
;
540 HvReleaseCell(Hive
, *Index
);
546 CmpCreateRegistryRoot(VOID
)
548 UNICODE_STRING KeyName
;
549 OBJECT_ATTRIBUTES ObjectAttributes
;
551 PCM_KEY_BODY RootKey
;
555 HCELL_INDEX RootIndex
;
557 PCM_KEY_NODE KeyCell
;
558 PSECURITY_DESCRIPTOR SecurityDescriptor
;
559 PCM_KEY_CONTROL_BLOCK Kcb
;
562 /* Setup the root node */
563 if (!CmpCreateRootNode(&CmiVolatileHive
->Hive
, L
"REGISTRY", &RootIndex
))
569 /* Create '\Registry' key. */
570 RtlInitUnicodeString(&KeyName
, L
"\\Registry");
571 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
572 InitializeObjectAttributes(&ObjectAttributes
,
574 OBJ_CASE_INSENSITIVE
,
577 Status
= ObCreateObject(KernelMode
,
586 ExFreePool(SecurityDescriptor
);
587 if (!NT_SUCCESS(Status
)) return FALSE
;
589 /* Sanity check, and get the key cell */
590 ASSERT((&CmiVolatileHive
->Hive
)->ReleaseCellRoutine
== NULL
);
591 KeyCell
= (PCM_KEY_NODE
)HvGetCell(&CmiVolatileHive
->Hive
, RootIndex
);
592 if (!KeyCell
) return FALSE
;
595 RtlInitUnicodeString(&KeyName
, L
"Registry");
596 Kcb
= CmpCreateKeyControlBlock(&CmiVolatileHive
->Hive
,
602 if (!Kcb
) return FALSE
;
604 /* Initialize the object */
606 RootKey
->Type
= TAG('k', 'v', '0', '2';
607 RootKey
->KeyControlBlock
= Kcb
;
608 RootKey
->NotifyBlock
= NULL
;
609 RootKey
->ProcessID
= PsGetCurrentProcessId();
611 RtlpCreateUnicodeString(&RootKey
->Name
, L
"Registry", NonPagedPool
);
612 RootKey
->RegistryHive
= CmiVolatileHive
;
613 RootKey
->KeyCellOffset
= RootIndex
;
614 RootKey
->KeyCell
= KeyCell
;
615 RootKey
->ParentKey
= RootKey
;
617 RootKey
->SubKeyCounts
= 0;
618 RootKey
->SubKeys
= NULL
;
619 RootKey
->SizeOfSubKeys
= 0;
622 /* Insert it into the object list head */
623 EnlistKeyBodyWithKCB(RootKey
, 0);
625 /* Insert the key into the namespace */
626 Status
= ObInsertObject(RootKey
,
631 &CmpRegistryRootHandle
);
632 if (!NT_SUCCESS(Status
)) return FALSE
;
634 /* Reference the key again so that we never lose it */
635 Status
= ObReferenceObjectByHandle(CmpRegistryRootHandle
,
641 if (!NT_SUCCESS(Status
)) return FALSE
;
643 /* Completely sucessful */