3 * Copyright (C) 2006 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS hive maker
22 * FILE: tools/mkhive/registry.c
23 * PURPOSE: Registry code
24 * PROGRAMMERS: Hervé Poussineau
25 * Hermès Bélusca-Maïto
30 * - Implement RegDeleteKeyW() and RegDeleteValueW()
36 static CMHIVE RootHive
;
37 static PMEMKEY RootKey
;
39 static CMHIVE SystemHive
; /* \Registry\Machine\SYSTEM */
40 static CMHIVE SoftwareHive
; /* \Registry\Machine\SOFTWARE */
41 static CMHIVE DefaultHive
; /* \Registry\User\.DEFAULT */
42 static CMHIVE SamHive
; /* \Registry\Machine\SAM */
43 static CMHIVE SecurityHive
; /* \Registry\Machine\SECURITY */
44 static CMHIVE BcdHive
; /* \Registry\Machine\BCD00000000 */
47 // TODO: Write these values in a more human-readable form.
48 // See http://amnesia.gtisc.gatech.edu/~moyix/suzibandit.ltd.uk/MSc/Registry%20Structure%20-%20Appendices%20V4.pdf
49 // Appendix 12 "The Registry NT Security Descriptor" for more information.
51 // Those SECURITY_DESCRIPTORs were obtained by dumping the security block "sk"
52 // of registry hives created by setting their permissions to be the same as
53 // the ones of the BCD, SOFTWARE, or SYSTEM, SAM and .DEFAULT system hives.
54 // A cross-check was subsequently done with the system hives to verify that
55 // the security descriptors were the same.
57 static UCHAR BcdSecurity
[] =
59 // SECURITY_DESCRIPTOR_RELATIVE
62 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
63 // SE_DACL_PROTECTED (0x1000) |
64 // SE_DACL_AUTO_INHERITED (0x0400) |
65 // SE_DACL_PRESENT (0x0004)
66 0x48, 0x00, 0x00, 0x00, // Owner
67 0x58, 0x00, 0x00, 0x00, // Group
68 0x00, 0x00, 0x00, 0x00, // Sacl (None)
69 0x14, 0x00, 0x00, 0x00, // Dacl
74 0x34, 0x00, // AclSize
75 0x02, 0x00, // AceCount
79 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
80 0x02, // AceFlags: CONTAINER_INHERIT_ACE
81 0x18, 0x00, // AceSize
82 0x19, 0x00, 0x06, 0x00, // ACCESS_MASK: "Write DAC" (0x00040000) |
83 // "Read Control" (0x00020000) |
84 // "Notify" (0x00000010) |
85 // "Enumerate Subkeys" (0x00000008) |
86 // "Query Value" (0x00000001)
87 // (SidStart: S-1-5-32-544 "Administrators")
88 0x01, 0x02, 0x00, 0x00,
89 0x00, 0x00, 0x00, 0x05,
90 0x20, 0x00, 0x00, 0x00,
91 0x20, 0x02, 0x00, 0x00,
94 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
95 0x02, // AceFlags: CONTAINER_INHERIT_ACE
96 0x14, 0x00, // AceSize
97 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
98 // (SidStart: S-1-5-18 "Local System")
99 0x01, 0x01, 0x00, 0x00,
100 0x00, 0x00, 0x00, 0x05,
101 0x12, 0x00, 0x00, 0x00,
103 // Owner SID (S-1-5-32-544 "Administrators")
104 0x01, 0x02, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x05,
106 0x20, 0x00, 0x00, 0x00,
107 0x20, 0x02, 0x00, 0x00,
109 // Group SID (S-1-5-21-domain-513 "Domain Users")
110 0x01, 0x05, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x05,
112 0x15, 0x00, 0x00, 0x00,
113 0xAC, 0xD0, 0x49, 0xCB,
114 0xE6, 0x52, 0x47, 0x9C,
115 0xE4, 0x31, 0xDB, 0x5C,
116 0x01, 0x02, 0x00, 0x00
119 static UCHAR SoftwareSecurity
[] =
121 // SECURITY_DESCRIPTOR_RELATIVE
124 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
125 // SE_DACL_PROTECTED (0x1000) |
126 // SE_DACL_AUTO_INHERITED (0x0400) |
127 // SE_DACL_PRESENT (0x0004)
128 0xA0, 0x00, 0x00, 0x00, // Owner
129 0xB0, 0x00, 0x00, 0x00, // Group
130 0x00, 0x00, 0x00, 0x00, // Sacl (None)
131 0x14, 0x00, 0x00, 0x00, // Dacl
136 0x8C, 0x00, // AclSize
137 0x06, 0x00, // AceCount
141 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
142 0x02, // AceFlags: CONTAINER_INHERIT_ACE
143 0x18, 0x00, // AceSize
144 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
145 // (SidStart: S-1-5-32-544 "Administrators")
146 0x01, 0x02, 0x00, 0x00,
147 0x00, 0x00, 0x00, 0x05,
148 0x20, 0x00, 0x00, 0x00,
149 0x20, 0x02, 0x00, 0x00,
152 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
153 0x0A, // AceFlags: INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE
154 0x14, 0x00, // AceSize
155 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
156 // (SidStart: S-1-3-0 "Creator Owner")
157 0x01, 0x01, 0x00, 0x00,
158 0x00, 0x00, 0x00, 0x03,
159 0x00, 0x00, 0x00, 0x00,
162 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
163 0x02, // AceFlags: CONTAINER_INHERIT_ACE
164 0x14, 0x00, // AceSize
165 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
166 // (SidStart: S-1-5-18 "Local System")
167 0x01, 0x01, 0x00, 0x00,
168 0x00, 0x00, 0x00, 0x05,
169 0x12, 0x00, 0x00, 0x00,
172 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
173 0x02, // AceFlags: CONTAINER_INHERIT_ACE
174 0x14, 0x00, // AceSize
175 0x1F, 0x00, 0x03, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
176 // "Delete" (0x00010000) |
177 // "Notify" (0x00000010) |
178 // "Enumerate Subkeys" (0x00000008) |
179 // "Create Subkey" (0x00000004) |
180 // "Set Value" (0x00000002) |
181 // "Query Value" (0x00000001)
182 // (SidStart: S-1-5-13 "Terminal Server Users")
183 0x01, 0x01, 0x00, 0x00,
184 0x00, 0x00, 0x00, 0x05,
185 0x0D, 0x00, 0x00, 0x00,
188 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
189 0x02, // AceFlags: CONTAINER_INHERIT_ACE
190 0x18, 0x00, // AceSize
191 0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
192 // "Notify" (0x00000010) |
193 // "Enumerate Subkeys" (0x00000008) |
194 // "Query Value" (0x00000001)
195 // (SidStart: S-1-5-32-545 "Users")
196 0x01, 0x02, 0x00, 0x00,
197 0x00, 0x00, 0x00, 0x05,
198 0x20, 0x00, 0x00, 0x00,
199 0x21, 0x02, 0x00, 0x00,
202 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
203 0x02, // AceFlags: CONTAINER_INHERIT_ACE
204 0x18, 0x00, // AceSize
205 0x1F, 0x00, 0x03, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
206 // "Delete" (0x00010000) |
207 // "Notify" (0x00000010) |
208 // "Enumerate Subkeys" (0x00000008) |
209 // "Create Subkey" (0x00000004) |
210 // "Set Value" (0x00000002) |
211 // "Query Value" (0x00000001)
212 // (SidStart: S-1-5-32-547 "Power Users")
213 0x01, 0x02, 0x00, 0x00,
214 0x00, 0x00, 0x00, 0x05,
215 0x20, 0x00, 0x00, 0x00,
216 0x23, 0x02, 0x00, 0x00,
218 // Owner SID (S-1-5-32-544 "Administrators")
219 0x01, 0x02, 0x00, 0x00,
220 0x00, 0x00, 0x00, 0x05,
221 0x20, 0x00, 0x00, 0x00,
222 0x20, 0x02, 0x00, 0x00,
224 // Group SID (S-1-5-21-domain-513 "Domain Users")
225 0x01, 0x05, 0x00, 0x00,
226 0x00, 0x00, 0x00, 0x05,
227 0x15, 0x00, 0x00, 0x00,
228 0xAC, 0xD0, 0x49, 0xCB,
229 0xE6, 0x52, 0x47, 0x9C,
230 0xE4, 0x31, 0xDB, 0x5C,
231 0x01, 0x02, 0x00, 0x00
234 // Same security for SYSTEM, SAM and .DEFAULT
235 static UCHAR SystemSecurity
[] =
237 // SECURITY_DESCRIPTOR_RELATIVE
240 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
241 // SE_DACL_PROTECTED (0x1000) |
242 // SE_DACL_AUTO_INHERITED (0x0400) |
243 // SE_DACL_PRESENT (0x0004)
244 0x8C, 0x00, 0x00, 0x00, // Owner
245 0x9C, 0x00, 0x00, 0x00, // Group
246 0x00, 0x00, 0x00, 0x00, // Sacl (None)
247 0x14, 0x00, 0x00, 0x00, // Dacl
252 0x78, 0x00, // AclSize
253 0x05, 0x00, // AceCount
257 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
258 0x02, // AceFlags: CONTAINER_INHERIT_ACE
259 0x18, 0x00, // AceSize
260 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
261 // (SidStart: S-1-5-32-544 "Administrators")
262 0x01, 0x02, 0x00, 0x00,
263 0x00, 0x00, 0x00, 0x05,
264 0x20, 0x00, 0x00, 0x00,
265 0x20, 0x02, 0x00, 0x00,
268 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
269 0x0A, // AceFlags: INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE
270 0x14, 0x00, // AceSize
271 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
272 // (SidStart: S-1-3-0 "Creator Owner")
273 0x01, 0x01, 0x00, 0x00,
274 0x00, 0x00, 0x00, 0x03,
275 0x00, 0x00, 0x00, 0x00,
278 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
279 0x02, // AceFlags: CONTAINER_INHERIT_ACE
280 0x14, 0x00, // AceSize
281 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
282 // (SidStart: S-1-5-18 "Local System")
283 0x01, 0x01, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x05,
285 0x12, 0x00, 0x00, 0x00,
288 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
289 0x02, // AceFlags: CONTAINER_INHERIT_ACE
290 0x18, 0x00, // AceSize
291 0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
292 // "Notify" (0x00000010) |
293 // "Enumerate Subkeys" (0x00000008) |
294 // "Query Value" (0x00000001)
295 // (SidStart: S-1-5-32-545 "Users")
296 0x01, 0x02, 0x00, 0x00,
297 0x00, 0x00, 0x00, 0x05,
298 0x20, 0x00, 0x00, 0x00,
299 0x21, 0x02, 0x00, 0x00,
302 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
303 0x02, // AceFlags: CONTAINER_INHERIT_ACE
304 0x18, 0x00, // AceSize
305 0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
306 // "Notify" (0x00000010) |
307 // "Enumerate Subkeys" (0x00000008) |
308 // "Query Value" (0x00000001)
309 // (SidStart: S-1-5-32-547 "Power Users")
310 0x01, 0x02, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x05,
312 0x20, 0x00, 0x00, 0x00,
313 0x23, 0x02, 0x00, 0x00,
315 // Owner SID (S-1-5-32-544 "Administrators")
316 0x01, 0x02, 0x00, 0x00,
317 0x00, 0x00, 0x00, 0x05,
318 0x20, 0x00, 0x00, 0x00,
319 0x20, 0x02, 0x00, 0x00,
321 // Group SID (S-1-5-21-domain-513 "Domain Users")
322 0x01, 0x05, 0x00, 0x00,
323 0x00, 0x00, 0x00, 0x05,
324 0x15, 0x00, 0x00, 0x00,
325 0xAC, 0xD0, 0x49, 0xCB,
326 0xE6, 0x52, 0x47, 0x9C,
327 0xE4, 0x31, 0xDB, 0x5C,
328 0x01, 0x02, 0x00, 0x00
332 HIVE_LIST_ENTRY RegistryHives
[/*MAX_NUMBER_OF_REGISTRY_HIVES*/] =
334 /* Special Setup system registry hive */
335 // WARNING: Please *keep* it in first position!
336 { "SETUPREG", L
"Registry\\Machine\\SYSTEM" , &SystemHive
, SystemSecurity
, sizeof(SystemSecurity
) },
338 /* Regular registry hives */
339 { "SYSTEM" , L
"Registry\\Machine\\SYSTEM" , &SystemHive
, SystemSecurity
, sizeof(SystemSecurity
) },
340 { "SOFTWARE", L
"Registry\\Machine\\SOFTWARE" , &SoftwareHive
, SoftwareSecurity
, sizeof(SoftwareSecurity
) },
341 { "DEFAULT" , L
"Registry\\User\\.DEFAULT" , &DefaultHive
, SystemSecurity
, sizeof(SystemSecurity
) },
342 { "SAM" , L
"Registry\\Machine\\SAM" , &SamHive
, SystemSecurity
, sizeof(SystemSecurity
) },
343 { "SECURITY", L
"Registry\\Machine\\SECURITY" , &SecurityHive
, NULL
, 0 },
344 { "BCD" , L
"Registry\\Machine\\BCD00000000", &BcdHive
, BcdSecurity
, sizeof(BcdSecurity
) },
346 C_ASSERT(_countof(RegistryHives
) == MAX_NUMBER_OF_REGISTRY_HIVES
);
350 CreateInMemoryStructure(
351 IN PCMHIVE RegistryHive
,
352 IN HCELL_INDEX KeyCellOffset
)
356 Key
= (PMEMKEY
)malloc(sizeof(MEMKEY
));
360 Key
->RegistryHive
= RegistryHive
;
361 Key
->KeyCellOffset
= KeyCellOffset
;
365 LIST_ENTRY CmiHiveListHead
;
366 LIST_ENTRY CmiReparsePointsHead
;
372 IN BOOL AllowCreation
,
378 UNICODE_STRING KeyString
;
380 PREPARSE_POINT CurrentReparsePoint
;
382 PCMHIVE ParentRegistryHive
;
383 HCELL_INDEX ParentCellOffset
;
384 PCM_KEY_NODE ParentKeyCell
;
386 PCM_KEY_NODE SubKeyCell
;
387 HCELL_INDEX BlockOffset
;
389 DPRINT("RegpCreateOrOpenKey('%S')\n", KeyName
);
391 if (*KeyName
== OBJ_NAME_PATH_SEPARATOR
)
394 ParentRegistryHive
= RootKey
->RegistryHive
;
395 ParentCellOffset
= RootKey
->KeyCellOffset
;
397 else if (hParentKey
== NULL
)
399 ParentRegistryHive
= RootKey
->RegistryHive
;
400 ParentCellOffset
= RootKey
->KeyCellOffset
;
404 ParentRegistryHive
= HKEY_TO_MEMKEY(hParentKey
)->RegistryHive
;
405 ParentCellOffset
= HKEY_TO_MEMKEY(hParentKey
)->KeyCellOffset
;
408 LocalKeyName
= (PWSTR
)KeyName
;
411 End
= (PWSTR
)strchrW(LocalKeyName
, OBJ_NAME_PATH_SEPARATOR
);
414 KeyString
.Buffer
= LocalKeyName
;
415 KeyString
.Length
= KeyString
.MaximumLength
=
416 (USHORT
)((ULONG_PTR
)End
- (ULONG_PTR
)LocalKeyName
);
420 RtlInitUnicodeString(&KeyString
, LocalKeyName
);
421 if (KeyString
.Length
== 0)
423 /* Trailing path separator: we're done */
428 ParentKeyCell
= (PCM_KEY_NODE
)HvGetCell(&ParentRegistryHive
->Hive
, ParentCellOffset
);
430 return STATUS_UNSUCCESSFUL
;
432 VERIFY_KEY_CELL(ParentKeyCell
);
434 BlockOffset
= CmpFindSubKeyByName(&ParentRegistryHive
->Hive
, ParentKeyCell
, &KeyString
);
435 if (BlockOffset
!= HCELL_NIL
)
437 Status
= STATUS_SUCCESS
;
439 /* Search for a possible reparse point */
440 Ptr
= CmiReparsePointsHead
.Flink
;
441 while (Ptr
!= &CmiReparsePointsHead
)
443 CurrentReparsePoint
= CONTAINING_RECORD(Ptr
, REPARSE_POINT
, ListEntry
);
444 if (CurrentReparsePoint
->SourceHive
== ParentRegistryHive
&&
445 CurrentReparsePoint
->SourceKeyCellOffset
== BlockOffset
)
447 ParentRegistryHive
= CurrentReparsePoint
->DestinationHive
;
448 BlockOffset
= CurrentReparsePoint
->DestinationKeyCellOffset
;
454 else if (AllowCreation
) // && (BlockOffset == HCELL_NIL)
456 Status
= CmiAddSubKey(ParentRegistryHive
,
462 else // if (BlockOffset == HCELL_NIL)
464 Status
= STATUS_OBJECT_NAME_NOT_FOUND
; // ERROR_PATH_NOT_FOUND;
467 HvReleaseCell(&ParentRegistryHive
->Hive
, ParentCellOffset
);
469 if (!NT_SUCCESS(Status
))
471 DPRINT("RegpCreateOrOpenKey('%S'): Could not create or open subkey '%wZ'\n", KeyName
, &KeyString
);
472 return ERROR_UNSUCCESSFUL
;
475 ParentCellOffset
= BlockOffset
;
477 LocalKeyName
= End
+ 1;
482 CurrentKey
= CreateInMemoryStructure(ParentRegistryHive
, ParentCellOffset
);
484 return ERROR_OUTOFMEMORY
;
486 *Key
= MEMKEY_TO_HKEY(CurrentKey
);
488 return ERROR_SUCCESS
;
495 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
497 /* Free the object */
500 return ERROR_SUCCESS
;
509 return RegpCreateOrOpenKey(hKey
, lpSubKey
, TRUE
, FALSE
, phkResult
);
517 IN LPWSTR lpClass OPTIONAL
,
519 IN REGSAM samDesired
,
520 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL
,
522 OUT LPDWORD lpdwDisposition OPTIONAL
)
524 return RegpCreateOrOpenKey(hKey
,
527 (dwOptions
& REG_OPTION_VOLATILE
) != 0,
536 DPRINT1("RegDeleteKeyW(0x%p, '%S') is UNIMPLEMENTED!\n",
537 hKey
, (lpSubKey
? lpSubKey
: L
""));
538 return ERROR_SUCCESS
;
547 return RegpCreateOrOpenKey(hKey
, lpSubKey
, FALSE
, FALSE
, phkResult
);
553 IN LPCWSTR lpValueName OPTIONAL
,
556 IN
const UCHAR
* lpData
,
559 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
561 PCM_KEY_NODE KeyNode
; // ParentNode
562 PCM_KEY_VALUE ValueCell
;
564 HCELL_INDEX CellIndex
;
565 UNICODE_STRING ValueNameString
;
571 if (dwType
== REG_LINK
)
575 /* Special handling of registry links */
576 if (cbData
!= sizeof(PVOID
))
577 return STATUS_INVALID_PARAMETER
;
579 DestKey
= HKEY_TO_MEMKEY(*(PHKEY
)lpData
);
581 // FIXME: Add additional checks for the validity of DestKey
583 /* Create the link in registry hive (if applicable) */
584 if (Key
->RegistryHive
!= DestKey
->RegistryHive
)
585 return STATUS_SUCCESS
;
587 DPRINT1("Save link to registry\n");
588 return STATUS_NOT_IMPLEMENTED
;
591 if ((cbData
& ~CM_KEY_VALUE_SPECIAL_SIZE
) != cbData
)
592 return STATUS_UNSUCCESSFUL
;
594 Hive
= &Key
->RegistryHive
->Hive
;
596 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
598 return ERROR_UNSUCCESSFUL
;
600 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
602 /* Mark the parent as dirty since we are going to create a new value in it */
603 HvMarkCellDirty(Hive
, Key
->KeyCellOffset
, FALSE
);
605 /* Initialize value name string */
606 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
607 if (!CmpFindNameInList(Hive
,
614 ASSERT(CellIndex
== HCELL_NIL
);
616 // Status = STATUS_INSUFFICIENT_RESOURCES;
617 return ERROR_UNSUCCESSFUL
;
619 if (CellIndex
== HCELL_NIL
)
621 /* The value doesn't exist, create a new one */
622 Status
= CmiAddValueKey(Key
->RegistryHive
,
631 /* The value already exists, use it. Get the value cell. */
632 ValueCell
= HvGetCell(&Key
->RegistryHive
->Hive
, CellIndex
);
633 ASSERT(ValueCell
!= NULL
);
634 Status
= STATUS_SUCCESS
;
637 // /**/HvReleaseCell(Hive, CellIndex);/**/
639 if (!NT_SUCCESS(Status
))
640 return ERROR_UNSUCCESSFUL
;
642 /* Get size of the allocated cell (if any) */
643 if (!(ValueCell
->DataLength
& CM_KEY_VALUE_SPECIAL_SIZE
) &&
644 (ValueCell
->DataLength
& ~CM_KEY_VALUE_SPECIAL_SIZE
) != 0)
646 DataCell
= HvGetCell(Hive
, ValueCell
->Data
);
648 return ERROR_UNSUCCESSFUL
;
650 DataCellSize
= (ULONG
)(-HvGetCellSize(Hive
, DataCell
));
658 if (cbData
<= sizeof(HCELL_INDEX
))
660 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
661 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
663 HvFreeCell(Hive
, ValueCell
->Data
);
665 RtlCopyMemory(&ValueCell
->Data
, lpData
, cbData
);
666 ValueCell
->DataLength
= (cbData
| CM_KEY_VALUE_SPECIAL_SIZE
);
667 ValueCell
->Type
= dwType
;
671 if (cbData
> DataCellSize
)
673 /* New data size is larger than the current, destroy current
674 * data block and allocate a new one. */
675 HCELL_INDEX NewOffset
;
677 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
679 NewOffset
= HvAllocateCell(Hive
, cbData
, Stable
, HCELL_NIL
);
680 if (NewOffset
== HCELL_NIL
)
682 DPRINT("HvAllocateCell() has failed!\n");
683 return ERROR_UNSUCCESSFUL
;
687 HvFreeCell(Hive
, ValueCell
->Data
);
689 ValueCell
->Data
= NewOffset
;
690 DataCell
= (PVOID
)HvGetCell(Hive
, NewOffset
);
693 /* Copy new contents to cell */
694 RtlCopyMemory(DataCell
, lpData
, cbData
);
695 ValueCell
->DataLength
= (cbData
& ~CM_KEY_VALUE_SPECIAL_SIZE
);
696 ValueCell
->Type
= dwType
;
697 HvMarkCellDirty(Hive
, ValueCell
->Data
, FALSE
);
700 HvMarkCellDirty(Hive
, CellIndex
, FALSE
);
702 /* Check if the maximum value name length changed, update it if so */
703 if (KeyNode
->MaxValueNameLen
< ValueNameString
.Length
)
704 KeyNode
->MaxValueNameLen
= ValueNameString
.Length
;
706 /* Check if the maximum data length changed, update it if so */
707 if (KeyNode
->MaxValueDataLen
< cbData
)
708 KeyNode
->MaxValueDataLen
= cbData
;
710 /* Save the write time */
711 KeQuerySystemTime(&KeyNode
->LastWriteTime
);
713 return ERROR_SUCCESS
;
717 // Synced with freeldr/ntldr/registry.c
722 IN PCM_KEY_VALUE ValueCell
,
723 OUT PULONG Type OPTIONAL
,
724 OUT PUCHAR Data OPTIONAL
,
725 IN OUT PULONG DataSize OPTIONAL
)
730 /* Does the caller want the type? */
732 *Type
= ValueCell
->Type
;
734 /* Does the caller provide DataSize? */
735 if (DataSize
!= NULL
)
737 // NOTE: CmpValueToData doesn't support big data (the function will
738 // bugcheck if so), FreeLdr is not supposed to read such data.
739 // If big data is needed, use instead CmpGetValueData.
740 // CmpGetValueData(Hive, ValueCell, DataSize, &DataCell, ...);
741 DataCell
= CmpValueToData(Hive
, ValueCell
, &DataLength
);
743 /* Does the caller want the data? */
744 if ((Data
!= NULL
) && (*DataSize
!= 0))
748 min(*DataSize
, DataLength
));
751 /* Return the actual data length */
752 *DataSize
= DataLength
;
756 // Similar to RegQueryValue in freeldr/ntldr/registry.c
760 IN LPCWSTR lpValueName
,
761 IN PULONG lpReserved
,
762 OUT PULONG lpType OPTIONAL
,
763 OUT PUCHAR lpData OPTIONAL
,
764 IN OUT PULONG lpcbData OPTIONAL
)
766 PMEMKEY ParentKey
= HKEY_TO_MEMKEY(hKey
);
767 PHHIVE Hive
= &ParentKey
->RegistryHive
->Hive
;
768 PCM_KEY_NODE KeyNode
;
769 PCM_KEY_VALUE ValueCell
;
770 HCELL_INDEX CellIndex
;
771 UNICODE_STRING ValueNameString
;
773 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentKey
->KeyCellOffset
);
775 return ERROR_UNSUCCESSFUL
;
777 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
779 /* Initialize value name string */
780 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
781 CellIndex
= CmpFindValueByName(Hive
, KeyNode
, &ValueNameString
);
782 if (CellIndex
== HCELL_NIL
)
783 return ERROR_FILE_NOT_FOUND
;
785 /* Get the value cell */
786 ValueCell
= HvGetCell(Hive
, CellIndex
);
787 ASSERT(ValueCell
!= NULL
);
789 RepGetValueData(Hive
, ValueCell
, lpType
, lpData
, lpcbData
);
791 HvReleaseCell(Hive
, CellIndex
);
793 return ERROR_SUCCESS
;
799 IN LPCWSTR lpValueName OPTIONAL
)
801 DPRINT1("RegDeleteValueW(0x%p, '%S') is UNIMPLEMENTED!\n",
802 hKey
, (lpValueName
? lpValueName
: L
""));
803 return ERROR_UNSUCCESSFUL
;
810 IN PCMHIVE HiveToConnect
,
811 IN PUCHAR SecurityDescriptor
,
812 IN ULONG SecurityDescriptorLength
,
817 PREPARSE_POINT ReparsePoint
;
820 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(*ReparsePoint
));
825 * Use a dummy root key name:
826 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
827 * - On Vista+, this is "CMI-CreateHive{guid}"
828 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
829 * for more information.
831 Status
= CmiInitializeHive(HiveToConnect
, L
"$$$PROTO.HIV");
832 if (!NT_SUCCESS(Status
))
834 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status
);
840 * Add security to the root key.
841 * NOTE: One can implement this using the lpSecurityAttributes
842 * parameter of RegCreateKeyExW.
844 Status
= CmiCreateSecurityKey(&HiveToConnect
->Hive
,
845 HiveToConnect
->Hive
.BaseBlock
->RootCell
,
846 SecurityDescriptor
, SecurityDescriptorLength
);
847 if (!NT_SUCCESS(Status
))
848 DPRINT1("Failed to add security for root key '%S'\n", Path
);
851 rc
= RegCreateKeyExW(RootKey
,
860 if (rc
!= ERROR_SUCCESS
)
866 ReparsePoint
->SourceHive
= NewKey
->RegistryHive
;
867 ReparsePoint
->SourceKeyCellOffset
= NewKey
->KeyCellOffset
;
868 NewKey
->RegistryHive
= HiveToConnect
;
869 NewKey
->KeyCellOffset
= HiveToConnect
->Hive
.BaseBlock
->RootCell
;
870 ReparsePoint
->DestinationHive
= NewKey
->RegistryHive
;
871 ReparsePoint
->DestinationKeyCellOffset
= NewKey
->KeyCellOffset
;
872 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
879 IN PCWSTR LinkKeyPath OPTIONAL
,
880 IN OUT PHKEY LinkKeyHandle OPTIONAL
,
881 // IN PCWSTR TargetKeyPath OPTIONAL,
882 IN HKEY TargetKeyHandle
)
885 PMEMKEY LinkKey
, TargetKey
;
886 PREPARSE_POINT ReparsePoint
;
888 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(*ReparsePoint
));
892 if (LinkKeyPath
&& !(LinkKeyHandle
&& *LinkKeyHandle
))
894 /* Create the link key */
895 rc
= RegCreateKeyExW(NULL
,
904 if (rc
!= ERROR_SUCCESS
)
910 else if (LinkKeyHandle
)
912 /* Use the user-provided link key handle */
913 LinkKey
= HKEY_TO_MEMKEY(*LinkKeyHandle
);
917 *LinkKeyHandle
= MEMKEY_TO_HKEY(LinkKey
);
919 TargetKey
= HKEY_TO_MEMKEY(TargetKeyHandle
);
921 ReparsePoint
->SourceHive
= LinkKey
->RegistryHive
;
922 ReparsePoint
->SourceKeyCellOffset
= LinkKey
->KeyCellOffset
;
923 ReparsePoint
->DestinationHive
= TargetKey
->RegistryHive
;
924 ReparsePoint
->DestinationKeyCellOffset
= TargetKey
->KeyCellOffset
;
925 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
931 RegInitializeRegistry(
938 InitializeListHead(&CmiHiveListHead
);
939 InitializeListHead(&CmiReparsePointsHead
);
941 Status
= CmiInitializeHive(&RootHive
, L
"");
942 if (!NT_SUCCESS(Status
))
944 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status
);
948 RootKey
= CreateInMemoryStructure(&RootHive
,
949 RootHive
.Hive
.BaseBlock
->RootCell
);
951 for (i
= 0; i
< _countof(RegistryHives
); ++i
)
953 /* Skip this registry hive if it's not in the list */
954 if (!strstr(HiveList
, RegistryHives
[i
].HiveName
))
957 /* Create the registry key */
958 ConnectRegistry(NULL
,
959 RegistryHives
[i
].CmHive
,
960 RegistryHives
[i
].SecurityDescriptor
,
961 RegistryHives
[i
].SecurityDescriptorLength
,
962 RegistryHives
[i
].HiveRegistryPath
);
964 /* If we happen to deal with the special setup registry hive, stop there */
965 // if (strcmp(RegistryHives[i].HiveName, "SETUPREG") == 0)
970 /* Create the 'ControlSet001' key */
972 L
"Registry\\Machine\\SYSTEM\\ControlSet001",
975 /* Create the 'CurrentControlSet' key as a symlink to 'ControlSet001' */
976 CreateSymLink(L
"Registry\\Machine\\SYSTEM\\CurrentControlSet",
977 NULL
, ControlSetKey
);
979 RegCloseKey(ControlSetKey
);
982 /* Link SECURITY to SAM */
983 CmpLinkKeyToHive(L
"\\Registry\\Machine\\Security\\SAM", L
"\\Registry\\Machine\\SAM\\SAM");
984 /* Link S-1-5-18 to .Default */
985 CmpLinkKeyToHive(L
"\\Registry\\User\\S-1-5-18", L
"\\Registry\\User\\.Default");
990 RegShutdownRegistry(VOID
)
993 PREPARSE_POINT ReparsePoint
;
995 /* Clean up the reparse points list */
996 while (!IsListEmpty(&CmiReparsePointsHead
))
998 Entry
= RemoveHeadList(&CmiReparsePointsHead
);
999 ReparsePoint
= CONTAINING_RECORD(Entry
, REPARSE_POINT
, ListEntry
);
1003 /* FIXME: clean up the complete hive */