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()
40 static CMHIVE RootHive
;
41 static PMEMKEY RootKey
;
43 static CMHIVE SystemHive
; /* \Registry\Machine\SYSTEM */
44 static CMHIVE SoftwareHive
; /* \Registry\Machine\SOFTWARE */
45 static CMHIVE DefaultHive
; /* \Registry\User\.DEFAULT */
46 static CMHIVE SamHive
; /* \Registry\Machine\SAM */
47 static CMHIVE SecurityHive
; /* \Registry\Machine\SECURITY */
48 static CMHIVE BcdHive
; /* \Registry\Machine\BCD00000000 */
51 // TODO: Write these values in a more human-readable form.
52 // See http://amnesia.gtisc.gatech.edu/~moyix/suzibandit.ltd.uk/MSc/Registry%20Structure%20-%20Appendices%20V4.pdf
53 // Appendix 12 "The Registry NT Security Descriptor" for more information.
55 // Those SECURITY_DESCRIPTORs were obtained by dumping the security block "sk"
56 // of registry hives created by setting their permissions to be the same as
57 // the ones of the BCD, SOFTWARE, or SYSTEM, SAM and .DEFAULT system hives.
58 // A cross-check was subsequently done with the system hives to verify that
59 // the security descriptors were the same.
61 static UCHAR BcdSecurity
[] =
63 // SECURITY_DESCRIPTOR_RELATIVE
66 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
67 // SE_DACL_PROTECTED (0x1000) |
68 // SE_DACL_AUTO_INHERITED (0x0400) |
69 // SE_DACL_PRESENT (0x0004)
70 0x48, 0x00, 0x00, 0x00, // Owner
71 0x58, 0x00, 0x00, 0x00, // Group
72 0x00, 0x00, 0x00, 0x00, // Sacl (None)
73 0x14, 0x00, 0x00, 0x00, // Dacl
78 0x34, 0x00, // AclSize
79 0x02, 0x00, // AceCount
83 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
84 0x02, // AceFlags: CONTAINER_INHERIT_ACE
85 0x18, 0x00, // AceSize
86 0x19, 0x00, 0x06, 0x00, // ACCESS_MASK: "Write DAC" (0x00040000) |
87 // "Read Control" (0x00020000) |
88 // "Notify" (0x00000010) |
89 // "Enumerate Subkeys" (0x00000008) |
90 // "Query Value" (0x00000001)
91 // (SidStart: S-1-5-32-544 "Administrators")
92 0x01, 0x02, 0x00, 0x00,
93 0x00, 0x00, 0x00, 0x05,
94 0x20, 0x00, 0x00, 0x00,
95 0x20, 0x02, 0x00, 0x00,
98 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
99 0x02, // AceFlags: CONTAINER_INHERIT_ACE
100 0x14, 0x00, // AceSize
101 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
102 // (SidStart: S-1-5-18 "Local System")
103 0x01, 0x01, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x05,
105 0x12, 0x00, 0x00, 0x00,
107 // Owner SID (S-1-5-32-544 "Administrators")
108 0x01, 0x02, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x05,
110 0x20, 0x00, 0x00, 0x00,
111 0x20, 0x02, 0x00, 0x00,
113 // Group SID (S-1-5-21-domain-513 "Domain Users")
114 0x01, 0x05, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x05,
116 0x15, 0x00, 0x00, 0x00,
117 0xAC, 0xD0, 0x49, 0xCB,
118 0xE6, 0x52, 0x47, 0x9C,
119 0xE4, 0x31, 0xDB, 0x5C,
120 0x01, 0x02, 0x00, 0x00
123 static UCHAR SoftwareSecurity
[] =
125 // SECURITY_DESCRIPTOR_RELATIVE
128 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
129 // SE_DACL_PROTECTED (0x1000) |
130 // SE_DACL_AUTO_INHERITED (0x0400) |
131 // SE_DACL_PRESENT (0x0004)
132 0xA0, 0x00, 0x00, 0x00, // Owner
133 0xB0, 0x00, 0x00, 0x00, // Group
134 0x00, 0x00, 0x00, 0x00, // Sacl (None)
135 0x14, 0x00, 0x00, 0x00, // Dacl
140 0x8C, 0x00, // AclSize
141 0x06, 0x00, // AceCount
145 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
146 0x02, // AceFlags: CONTAINER_INHERIT_ACE
147 0x18, 0x00, // AceSize
148 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
149 // (SidStart: S-1-5-32-544 "Administrators")
150 0x01, 0x02, 0x00, 0x00,
151 0x00, 0x00, 0x00, 0x05,
152 0x20, 0x00, 0x00, 0x00,
153 0x20, 0x02, 0x00, 0x00,
156 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
157 0x0A, // AceFlags: INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE
158 0x14, 0x00, // AceSize
159 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
160 // (SidStart: S-1-3-0 "Creator Owner")
161 0x01, 0x01, 0x00, 0x00,
162 0x00, 0x00, 0x00, 0x03,
163 0x00, 0x00, 0x00, 0x00,
166 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
167 0x02, // AceFlags: CONTAINER_INHERIT_ACE
168 0x14, 0x00, // AceSize
169 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
170 // (SidStart: S-1-5-18 "Local System")
171 0x01, 0x01, 0x00, 0x00,
172 0x00, 0x00, 0x00, 0x05,
173 0x12, 0x00, 0x00, 0x00,
176 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
177 0x02, // AceFlags: CONTAINER_INHERIT_ACE
178 0x14, 0x00, // AceSize
179 0x1F, 0x00, 0x03, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
180 // "Delete" (0x00010000) |
181 // "Notify" (0x00000010) |
182 // "Enumerate Subkeys" (0x00000008) |
183 // "Create Subkey" (0x00000004) |
184 // "Set Value" (0x00000002) |
185 // "Query Value" (0x00000001)
186 // (SidStart: S-1-5-13 "Terminal Server Users")
187 0x01, 0x01, 0x00, 0x00,
188 0x00, 0x00, 0x00, 0x05,
189 0x0D, 0x00, 0x00, 0x00,
192 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
193 0x02, // AceFlags: CONTAINER_INHERIT_ACE
194 0x18, 0x00, // AceSize
195 0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
196 // "Notify" (0x00000010) |
197 // "Enumerate Subkeys" (0x00000008) |
198 // "Query Value" (0x00000001)
199 // (SidStart: S-1-5-32-545 "Users")
200 0x01, 0x02, 0x00, 0x00,
201 0x00, 0x00, 0x00, 0x05,
202 0x20, 0x00, 0x00, 0x00,
203 0x21, 0x02, 0x00, 0x00,
206 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
207 0x02, // AceFlags: CONTAINER_INHERIT_ACE
208 0x18, 0x00, // AceSize
209 0x1F, 0x00, 0x03, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
210 // "Delete" (0x00010000) |
211 // "Notify" (0x00000010) |
212 // "Enumerate Subkeys" (0x00000008) |
213 // "Create Subkey" (0x00000004) |
214 // "Set Value" (0x00000002) |
215 // "Query Value" (0x00000001)
216 // (SidStart: S-1-5-32-547 "Power Users")
217 0x01, 0x02, 0x00, 0x00,
218 0x00, 0x00, 0x00, 0x05,
219 0x20, 0x00, 0x00, 0x00,
220 0x23, 0x02, 0x00, 0x00,
222 // Owner SID (S-1-5-32-544 "Administrators")
223 0x01, 0x02, 0x00, 0x00,
224 0x00, 0x00, 0x00, 0x05,
225 0x20, 0x00, 0x00, 0x00,
226 0x20, 0x02, 0x00, 0x00,
228 // Group SID (S-1-5-21-domain-513 "Domain Users")
229 0x01, 0x05, 0x00, 0x00,
230 0x00, 0x00, 0x00, 0x05,
231 0x15, 0x00, 0x00, 0x00,
232 0xAC, 0xD0, 0x49, 0xCB,
233 0xE6, 0x52, 0x47, 0x9C,
234 0xE4, 0x31, 0xDB, 0x5C,
235 0x01, 0x02, 0x00, 0x00
238 // Same security for SYSTEM, SAM and .DEFAULT
239 static UCHAR SystemSecurity
[] =
241 // SECURITY_DESCRIPTOR_RELATIVE
244 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
245 // SE_DACL_PROTECTED (0x1000) |
246 // SE_DACL_AUTO_INHERITED (0x0400) |
247 // SE_DACL_PRESENT (0x0004)
248 0x8C, 0x00, 0x00, 0x00, // Owner
249 0x9C, 0x00, 0x00, 0x00, // Group
250 0x00, 0x00, 0x00, 0x00, // Sacl (None)
251 0x14, 0x00, 0x00, 0x00, // Dacl
256 0x78, 0x00, // AclSize
257 0x05, 0x00, // AceCount
261 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
262 0x02, // AceFlags: CONTAINER_INHERIT_ACE
263 0x18, 0x00, // AceSize
264 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
265 // (SidStart: S-1-5-32-544 "Administrators")
266 0x01, 0x02, 0x00, 0x00,
267 0x00, 0x00, 0x00, 0x05,
268 0x20, 0x00, 0x00, 0x00,
269 0x20, 0x02, 0x00, 0x00,
272 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
273 0x0A, // AceFlags: INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE
274 0x14, 0x00, // AceSize
275 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
276 // (SidStart: S-1-3-0 "Creator Owner")
277 0x01, 0x01, 0x00, 0x00,
278 0x00, 0x00, 0x00, 0x03,
279 0x00, 0x00, 0x00, 0x00,
282 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
283 0x02, // AceFlags: CONTAINER_INHERIT_ACE
284 0x14, 0x00, // AceSize
285 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
286 // (SidStart: S-1-5-18 "Local System")
287 0x01, 0x01, 0x00, 0x00,
288 0x00, 0x00, 0x00, 0x05,
289 0x12, 0x00, 0x00, 0x00,
292 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
293 0x02, // AceFlags: CONTAINER_INHERIT_ACE
294 0x18, 0x00, // AceSize
295 0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
296 // "Notify" (0x00000010) |
297 // "Enumerate Subkeys" (0x00000008) |
298 // "Query Value" (0x00000001)
299 // (SidStart: S-1-5-32-545 "Users")
300 0x01, 0x02, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x05,
302 0x20, 0x00, 0x00, 0x00,
303 0x21, 0x02, 0x00, 0x00,
306 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
307 0x02, // AceFlags: CONTAINER_INHERIT_ACE
308 0x18, 0x00, // AceSize
309 0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
310 // "Notify" (0x00000010) |
311 // "Enumerate Subkeys" (0x00000008) |
312 // "Query Value" (0x00000001)
313 // (SidStart: S-1-5-32-547 "Power Users")
314 0x01, 0x02, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x05,
316 0x20, 0x00, 0x00, 0x00,
317 0x23, 0x02, 0x00, 0x00,
319 // Owner SID (S-1-5-32-544 "Administrators")
320 0x01, 0x02, 0x00, 0x00,
321 0x00, 0x00, 0x00, 0x05,
322 0x20, 0x00, 0x00, 0x00,
323 0x20, 0x02, 0x00, 0x00,
325 // Group SID (S-1-5-21-domain-513 "Domain Users")
326 0x01, 0x05, 0x00, 0x00,
327 0x00, 0x00, 0x00, 0x05,
328 0x15, 0x00, 0x00, 0x00,
329 0xAC, 0xD0, 0x49, 0xCB,
330 0xE6, 0x52, 0x47, 0x9C,
331 0xE4, 0x31, 0xDB, 0x5C,
332 0x01, 0x02, 0x00, 0x00
336 HIVE_LIST_ENTRY RegistryHives
[/*MAX_NUMBER_OF_REGISTRY_HIVES*/] =
338 /* Special Setup system registry hive */
339 // WARNING: Please *keep* it in first position!
340 { "SETUPREG", L
"Registry\\Machine\\SYSTEM" , &SystemHive
, SystemSecurity
, sizeof(SystemSecurity
) },
342 /* Regular registry hives */
343 { "SYSTEM" , L
"Registry\\Machine\\SYSTEM" , &SystemHive
, SystemSecurity
, sizeof(SystemSecurity
) },
344 { "SOFTWARE", L
"Registry\\Machine\\SOFTWARE" , &SoftwareHive
, SoftwareSecurity
, sizeof(SoftwareSecurity
) },
345 { "DEFAULT" , L
"Registry\\User\\.DEFAULT" , &DefaultHive
, SystemSecurity
, sizeof(SystemSecurity
) },
346 { "SAM" , L
"Registry\\Machine\\SAM" , &SamHive
, SystemSecurity
, sizeof(SystemSecurity
) },
347 { "SECURITY", L
"Registry\\Machine\\SECURITY" , &SecurityHive
, NULL
, 0 },
348 { "BCD" , L
"Registry\\Machine\\BCD00000000", &BcdHive
, BcdSecurity
, sizeof(BcdSecurity
) },
350 C_ASSERT(_countof(RegistryHives
) == MAX_NUMBER_OF_REGISTRY_HIVES
);
354 CreateInMemoryStructure(
355 IN PCMHIVE RegistryHive
,
356 IN HCELL_INDEX KeyCellOffset
)
360 Key
= (PMEMKEY
)malloc(sizeof(MEMKEY
));
364 Key
->RegistryHive
= RegistryHive
;
365 Key
->KeyCellOffset
= KeyCellOffset
;
369 LIST_ENTRY CmiHiveListHead
;
370 LIST_ENTRY CmiReparsePointsHead
;
376 IN BOOL AllowCreation
,
382 UNICODE_STRING KeyString
;
384 PREPARSE_POINT CurrentReparsePoint
;
386 PCMHIVE ParentRegistryHive
;
387 HCELL_INDEX ParentCellOffset
;
388 PCM_KEY_NODE ParentKeyCell
;
390 PCM_KEY_NODE SubKeyCell
;
391 HCELL_INDEX BlockOffset
;
393 DPRINT("RegpCreateOrOpenKey('%S')\n", KeyName
);
395 if (*KeyName
== OBJ_NAME_PATH_SEPARATOR
)
398 ParentRegistryHive
= RootKey
->RegistryHive
;
399 ParentCellOffset
= RootKey
->KeyCellOffset
;
401 else if (hParentKey
== NULL
)
403 ParentRegistryHive
= RootKey
->RegistryHive
;
404 ParentCellOffset
= RootKey
->KeyCellOffset
;
408 ParentRegistryHive
= HKEY_TO_MEMKEY(hParentKey
)->RegistryHive
;
409 ParentCellOffset
= HKEY_TO_MEMKEY(hParentKey
)->KeyCellOffset
;
412 LocalKeyName
= (PWSTR
)KeyName
;
415 End
= (PWSTR
)strchrW(LocalKeyName
, OBJ_NAME_PATH_SEPARATOR
);
418 KeyString
.Buffer
= LocalKeyName
;
419 KeyString
.Length
= KeyString
.MaximumLength
=
420 (USHORT
)((ULONG_PTR
)End
- (ULONG_PTR
)LocalKeyName
);
424 RtlInitUnicodeString(&KeyString
, LocalKeyName
);
425 if (KeyString
.Length
== 0)
427 /* Trailing path separator: we're done */
432 ParentKeyCell
= (PCM_KEY_NODE
)HvGetCell(&ParentRegistryHive
->Hive
, ParentCellOffset
);
434 return STATUS_UNSUCCESSFUL
;
436 VERIFY_KEY_CELL(ParentKeyCell
);
438 BlockOffset
= CmpFindSubKeyByName(&ParentRegistryHive
->Hive
, ParentKeyCell
, &KeyString
);
439 if (BlockOffset
!= HCELL_NIL
)
441 Status
= STATUS_SUCCESS
;
443 /* Search for a possible reparse point */
444 Ptr
= CmiReparsePointsHead
.Flink
;
445 while (Ptr
!= &CmiReparsePointsHead
)
447 CurrentReparsePoint
= CONTAINING_RECORD(Ptr
, REPARSE_POINT
, ListEntry
);
448 if (CurrentReparsePoint
->SourceHive
== ParentRegistryHive
&&
449 CurrentReparsePoint
->SourceKeyCellOffset
== BlockOffset
)
451 ParentRegistryHive
= CurrentReparsePoint
->DestinationHive
;
452 BlockOffset
= CurrentReparsePoint
->DestinationKeyCellOffset
;
458 else if (AllowCreation
) // && (BlockOffset == HCELL_NIL)
460 Status
= CmiAddSubKey(ParentRegistryHive
,
467 HvReleaseCell(&ParentRegistryHive
->Hive
, ParentCellOffset
);
469 if (!NT_SUCCESS(Status
))
470 return ERROR_UNSUCCESSFUL
;
472 ParentCellOffset
= BlockOffset
;
474 LocalKeyName
= End
+ 1;
479 CurrentKey
= CreateInMemoryStructure(ParentRegistryHive
, ParentCellOffset
);
481 return ERROR_OUTOFMEMORY
;
483 *Key
= MEMKEY_TO_HKEY(CurrentKey
);
485 return ERROR_SUCCESS
;
492 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
494 /* Free the object */
497 return ERROR_SUCCESS
;
506 return RegpCreateOrOpenKey(hKey
, lpSubKey
, TRUE
, FALSE
, phkResult
);
514 IN LPWSTR lpClass OPTIONAL
,
516 IN REGSAM samDesired
,
517 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL
,
519 OUT LPDWORD lpdwDisposition OPTIONAL
)
521 return RegpCreateOrOpenKey(hKey
,
524 (dwOptions
& REG_OPTION_VOLATILE
) != 0,
533 DPRINT1("RegDeleteKeyW(0x%p, '%S') is UNIMPLEMENTED!\n",
534 hKey
, (lpSubKey
? lpSubKey
: L
""));
535 return ERROR_SUCCESS
;
544 return RegpCreateOrOpenKey(hKey
, lpSubKey
, FALSE
, FALSE
, phkResult
);
550 IN LPCWSTR lpValueName OPTIONAL
,
553 IN
const UCHAR
* lpData
,
556 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
558 PCM_KEY_NODE KeyNode
; // ParentNode
559 PCM_KEY_VALUE ValueCell
;
561 HCELL_INDEX CellIndex
;
562 UNICODE_STRING ValueNameString
;
568 if (dwType
== REG_LINK
)
572 /* Special handling of registry links */
573 if (cbData
!= sizeof(PVOID
))
574 return STATUS_INVALID_PARAMETER
;
576 DestKey
= HKEY_TO_MEMKEY(*(PHKEY
)lpData
);
578 // FIXME: Add additional checks for the validity of DestKey
580 /* Create the link in registry hive (if applicable) */
581 if (Key
->RegistryHive
!= DestKey
->RegistryHive
)
582 return STATUS_SUCCESS
;
584 DPRINT1("Save link to registry\n");
585 return STATUS_NOT_IMPLEMENTED
;
588 if ((cbData
& ~CM_KEY_VALUE_SPECIAL_SIZE
) != cbData
)
589 return STATUS_UNSUCCESSFUL
;
591 Hive
= &Key
->RegistryHive
->Hive
;
593 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
595 return ERROR_UNSUCCESSFUL
;
597 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
599 /* Mark the parent as dirty since we are going to create a new value in it */
600 HvMarkCellDirty(Hive
, Key
->KeyCellOffset
, FALSE
);
602 /* Initialize value name string */
603 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
604 if (!CmpFindNameInList(Hive
,
611 ASSERT(CellIndex
== HCELL_NIL
);
613 // Status = STATUS_INSUFFICIENT_RESOURCES;
614 return ERROR_UNSUCCESSFUL
;
616 if (CellIndex
== HCELL_NIL
)
618 /* The value doesn't exist, create a new one */
619 Status
= CmiAddValueKey(Key
->RegistryHive
,
628 /* The value already exists, use it. Get the value cell. */
629 ValueCell
= HvGetCell(&Key
->RegistryHive
->Hive
, CellIndex
);
630 ASSERT(ValueCell
!= NULL
);
631 Status
= STATUS_SUCCESS
;
634 // /**/HvReleaseCell(Hive, CellIndex);/**/
636 if (!NT_SUCCESS(Status
))
637 return ERROR_UNSUCCESSFUL
;
639 /* Get size of the allocated cell (if any) */
640 if (!(ValueCell
->DataLength
& CM_KEY_VALUE_SPECIAL_SIZE
) &&
641 (ValueCell
->DataLength
& ~CM_KEY_VALUE_SPECIAL_SIZE
) != 0)
643 DataCell
= HvGetCell(Hive
, ValueCell
->Data
);
645 return ERROR_UNSUCCESSFUL
;
647 DataCellSize
= (ULONG
)(-HvGetCellSize(Hive
, DataCell
));
655 if (cbData
<= sizeof(HCELL_INDEX
))
657 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
658 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
660 HvFreeCell(Hive
, ValueCell
->Data
);
662 RtlCopyMemory(&ValueCell
->Data
, lpData
, cbData
);
663 ValueCell
->DataLength
= (cbData
| CM_KEY_VALUE_SPECIAL_SIZE
);
664 ValueCell
->Type
= dwType
;
668 if (cbData
> DataCellSize
)
670 /* New data size is larger than the current, destroy current
671 * data block and allocate a new one. */
672 HCELL_INDEX NewOffset
;
674 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
676 NewOffset
= HvAllocateCell(Hive
, cbData
, Stable
, HCELL_NIL
);
677 if (NewOffset
== HCELL_NIL
)
679 DPRINT("HvAllocateCell() has failed!\n");
680 return ERROR_UNSUCCESSFUL
;
684 HvFreeCell(Hive
, ValueCell
->Data
);
686 ValueCell
->Data
= NewOffset
;
687 DataCell
= (PVOID
)HvGetCell(Hive
, NewOffset
);
690 /* Copy new contents to cell */
691 RtlCopyMemory(DataCell
, lpData
, cbData
);
692 ValueCell
->DataLength
= (cbData
& ~CM_KEY_VALUE_SPECIAL_SIZE
);
693 ValueCell
->Type
= dwType
;
694 HvMarkCellDirty(Hive
, ValueCell
->Data
, FALSE
);
697 HvMarkCellDirty(Hive
, CellIndex
, FALSE
);
699 /* Check if the maximum value name length changed, update it if so */
700 if (KeyNode
->MaxValueNameLen
< ValueNameString
.Length
)
701 KeyNode
->MaxValueNameLen
= ValueNameString
.Length
;
703 /* Check if the maximum data length changed, update it if so */
704 if (KeyNode
->MaxValueDataLen
< cbData
)
705 KeyNode
->MaxValueDataLen
= cbData
;
707 /* Save the write time */
708 KeQuerySystemTime(&KeyNode
->LastWriteTime
);
710 return ERROR_SUCCESS
;
714 // Synced with freeldr/windows/registry.c
719 IN PCM_KEY_VALUE ValueCell
,
720 OUT PULONG Type OPTIONAL
,
721 OUT PUCHAR Data OPTIONAL
,
722 IN OUT PULONG DataSize OPTIONAL
)
727 /* Does the caller want the type? */
729 *Type
= ValueCell
->Type
;
731 /* Does the caller provide DataSize? */
732 if (DataSize
!= NULL
)
734 // NOTE: CmpValueToData doesn't support big data (the function will
735 // bugcheck if so), FreeLdr is not supposed to read such data.
736 // If big data is needed, use instead CmpGetValueData.
737 // CmpGetValueData(Hive, ValueCell, DataSize, &DataCell, ...);
738 DataCell
= CmpValueToData(Hive
, ValueCell
, &DataLength
);
740 /* Does the caller want the data? */
741 if ((Data
!= NULL
) && (*DataSize
!= 0))
745 min(*DataSize
, DataLength
));
748 /* Return the actual data length */
749 *DataSize
= DataLength
;
753 // Similar to RegQueryValue in freeldr/windows/registry.c
757 IN LPCWSTR lpValueName
,
758 IN PULONG lpReserved
,
759 OUT PULONG lpType OPTIONAL
,
760 OUT PUCHAR lpData OPTIONAL
,
761 IN OUT PULONG lpcbData OPTIONAL
)
763 PMEMKEY ParentKey
= HKEY_TO_MEMKEY(hKey
);
764 PHHIVE Hive
= &ParentKey
->RegistryHive
->Hive
;
765 PCM_KEY_NODE KeyNode
;
766 PCM_KEY_VALUE ValueCell
;
767 HCELL_INDEX CellIndex
;
768 UNICODE_STRING ValueNameString
;
770 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentKey
->KeyCellOffset
);
772 return ERROR_UNSUCCESSFUL
;
774 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
776 /* Initialize value name string */
777 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
778 CellIndex
= CmpFindValueByName(Hive
, KeyNode
, &ValueNameString
);
779 if (CellIndex
== HCELL_NIL
)
780 return ERROR_FILE_NOT_FOUND
;
782 /* Get the value cell */
783 ValueCell
= HvGetCell(Hive
, CellIndex
);
784 ASSERT(ValueCell
!= NULL
);
786 RepGetValueData(Hive
, ValueCell
, lpType
, lpData
, lpcbData
);
788 HvReleaseCell(Hive
, CellIndex
);
790 return ERROR_SUCCESS
;
796 IN LPCWSTR lpValueName OPTIONAL
)
798 DPRINT1("RegDeleteValueW(0x%p, '%S') is UNIMPLEMENTED!\n",
799 hKey
, (lpValueName
? lpValueName
: L
""));
800 return ERROR_UNSUCCESSFUL
;
807 IN PCMHIVE HiveToConnect
,
808 IN PUCHAR SecurityDescriptor
,
809 IN ULONG SecurityDescriptorLength
,
814 PREPARSE_POINT ReparsePoint
;
817 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(*ReparsePoint
));
822 * Use a dummy root key name:
823 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
824 * - On Vista+, this is "CMI-CreateHive{guid}"
825 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
826 * for more information.
828 Status
= CmiInitializeHive(HiveToConnect
, L
"$$$PROTO.HIV");
829 if (!NT_SUCCESS(Status
))
831 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status
);
837 * Add security to the root key.
838 * NOTE: One can implement this using the lpSecurityAttributes
839 * parameter of RegCreateKeyExW.
841 Status
= CmiCreateSecurityKey(&HiveToConnect
->Hive
,
842 HiveToConnect
->Hive
.BaseBlock
->RootCell
,
843 SecurityDescriptor
, SecurityDescriptorLength
);
844 if (!NT_SUCCESS(Status
))
845 DPRINT1("Failed to add security for root key '%S'\n", Path
);
848 rc
= RegCreateKeyExW(RootKey
,
857 if (rc
!= ERROR_SUCCESS
)
863 ReparsePoint
->SourceHive
= NewKey
->RegistryHive
;
864 ReparsePoint
->SourceKeyCellOffset
= NewKey
->KeyCellOffset
;
865 NewKey
->RegistryHive
= HiveToConnect
;
866 NewKey
->KeyCellOffset
= HiveToConnect
->Hive
.BaseBlock
->RootCell
;
867 ReparsePoint
->DestinationHive
= NewKey
->RegistryHive
;
868 ReparsePoint
->DestinationKeyCellOffset
= NewKey
->KeyCellOffset
;
869 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
876 IN PCWSTR LinkKeyPath OPTIONAL
,
877 IN OUT PHKEY LinkKeyHandle OPTIONAL
,
878 // IN PCWSTR TargetKeyPath OPTIONAL,
879 IN HKEY TargetKeyHandle
)
881 PMEMKEY LinkKey
, TargetKey
;
882 PREPARSE_POINT ReparsePoint
;
884 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(*ReparsePoint
));
888 if (LinkKeyPath
&& !(LinkKeyHandle
&& *LinkKeyHandle
))
890 /* Create the link key */
891 RegCreateKeyExW(NULL
,
901 else if (LinkKeyHandle
)
903 /* Use the user-provided link key handle */
904 LinkKey
= HKEY_TO_MEMKEY(*LinkKeyHandle
);
908 *LinkKeyHandle
= MEMKEY_TO_HKEY(LinkKey
);
910 TargetKey
= HKEY_TO_MEMKEY(TargetKeyHandle
);
912 ReparsePoint
->SourceHive
= LinkKey
->RegistryHive
;
913 ReparsePoint
->SourceKeyCellOffset
= LinkKey
->KeyCellOffset
;
914 ReparsePoint
->DestinationHive
= TargetKey
->RegistryHive
;
915 ReparsePoint
->DestinationKeyCellOffset
= TargetKey
->KeyCellOffset
;
916 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
922 RegInitializeRegistry(
929 InitializeListHead(&CmiHiveListHead
);
930 InitializeListHead(&CmiReparsePointsHead
);
932 Status
= CmiInitializeHive(&RootHive
, L
"");
933 if (!NT_SUCCESS(Status
))
935 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status
);
939 RootKey
= CreateInMemoryStructure(&RootHive
,
940 RootHive
.Hive
.BaseBlock
->RootCell
);
942 for (i
= 0; i
< _countof(RegistryHives
); ++i
)
944 /* Skip this registry hive if it's not in the list */
945 if (!strstr(HiveList
, RegistryHives
[i
].HiveName
))
948 /* Create the registry key */
949 ConnectRegistry(NULL
,
950 RegistryHives
[i
].CmHive
,
951 RegistryHives
[i
].SecurityDescriptor
,
952 RegistryHives
[i
].SecurityDescriptorLength
,
953 RegistryHives
[i
].HiveRegistryPath
);
955 /* If we happen to deal with the special setup registry hive, stop there */
956 // if (strcmp(RegistryHives[i].HiveName, "SETUPREG") == 0)
961 /* Create the 'ControlSet001' key */
963 L
"Registry\\Machine\\SYSTEM\\ControlSet001",
966 /* Create the 'CurrentControlSet' key as a symlink to 'ControlSet001' */
967 CreateSymLink(L
"Registry\\Machine\\SYSTEM\\CurrentControlSet",
968 NULL
, ControlSetKey
);
970 RegCloseKey(ControlSetKey
);
973 /* Link SECURITY to SAM */
974 CmpLinkKeyToHive(L
"\\Registry\\Machine\\Security\\SAM", L
"\\Registry\\Machine\\SAM\\SAM");
975 /* Link S-1-5-18 to .Default */
976 CmpLinkKeyToHive(L
"\\Registry\\User\\S-1-5-18", L
"\\Registry\\User\\.Default");
981 RegShutdownRegistry(VOID
)
984 PREPARSE_POINT ReparsePoint
;
986 /* Clean up the reparse points list */
987 while (!IsListEmpty(&CmiReparsePointsHead
))
989 Entry
= RemoveHeadList(&CmiReparsePointsHead
);
990 ReparsePoint
= CONTAINING_RECORD(Entry
, REPARSE_POINT
, ListEntry
);
994 /* FIXME: clean up the complete hive */