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
;
494 return RegpCreateOrOpenKey(hKey
, lpSubKey
, TRUE
, FALSE
, phkResult
);
502 IN LPWSTR lpClass OPTIONAL
,
504 IN REGSAM samDesired
,
505 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL
,
507 OUT LPDWORD lpdwDisposition OPTIONAL
)
509 return RegpCreateOrOpenKey(hKey
,
512 (dwOptions
& REG_OPTION_VOLATILE
) != 0,
521 DPRINT1("RegDeleteKeyW(0x%p, '%S') is UNIMPLEMENTED!\n",
522 hKey
, (lpSubKey
? lpSubKey
: L
""));
523 return ERROR_SUCCESS
;
532 return RegpCreateOrOpenKey(hKey
, lpSubKey
, FALSE
, FALSE
, phkResult
);
538 IN LPCWSTR lpValueName OPTIONAL
,
541 IN
const UCHAR
* lpData
,
544 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
546 PCM_KEY_NODE KeyNode
; // ParentNode
547 PCM_KEY_VALUE ValueCell
;
548 HCELL_INDEX CellIndex
;
549 UNICODE_STRING ValueNameString
;
555 if (dwType
== REG_LINK
)
559 /* Special handling of registry links */
560 if (cbData
!= sizeof(PVOID
))
561 return STATUS_INVALID_PARAMETER
;
563 DestKey
= HKEY_TO_MEMKEY(*(PHKEY
)lpData
);
565 // FIXME: Add additional checks for the validity of DestKey
567 /* Create the link in registry hive (if applicable) */
568 if (Key
->RegistryHive
!= DestKey
->RegistryHive
)
569 return STATUS_SUCCESS
;
571 DPRINT1("Save link to registry\n");
572 return STATUS_NOT_IMPLEMENTED
;
575 if ((cbData
& ~CM_KEY_VALUE_SPECIAL_SIZE
) != cbData
)
576 return STATUS_UNSUCCESSFUL
;
578 Hive
= &Key
->RegistryHive
->Hive
;
580 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
582 return ERROR_UNSUCCESSFUL
;
584 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
586 /* Mark the parent as dirty since we are going to create a new value in it */
587 HvMarkCellDirty(Hive
, Key
->KeyCellOffset
, FALSE
);
589 /* Initialize value name string */
590 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
591 CellIndex
= CmpFindValueByName(Hive
, KeyNode
, &ValueNameString
);
592 if (CellIndex
== HCELL_NIL
)
594 /* The value doesn't exist, create a new one */
595 Status
= CmiAddValueKey(Key
->RegistryHive
,
603 /* The value already exists, use it. Get the value cell. */
604 ValueCell
= HvGetCell(&Key
->RegistryHive
->Hive
, CellIndex
);
605 ASSERT(ValueCell
!= NULL
);
606 Status
= STATUS_SUCCESS
;
609 // /**/HvReleaseCell(Hive, CellIndex);/**/
611 if (!NT_SUCCESS(Status
))
612 return ERROR_UNSUCCESSFUL
;
614 /* Get size of the allocated cell (if any) */
615 if (!(ValueCell
->DataLength
& CM_KEY_VALUE_SPECIAL_SIZE
) &&
616 (ValueCell
->DataLength
& ~CM_KEY_VALUE_SPECIAL_SIZE
) != 0)
618 DataCell
= HvGetCell(Hive
, ValueCell
->Data
);
620 return ERROR_UNSUCCESSFUL
;
622 DataCellSize
= (ULONG
)(-HvGetCellSize(Hive
, DataCell
));
630 if (cbData
<= sizeof(HCELL_INDEX
))
632 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
633 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
635 HvFreeCell(Hive
, ValueCell
->Data
);
637 RtlCopyMemory(&ValueCell
->Data
, lpData
, cbData
);
638 ValueCell
->DataLength
= (cbData
| CM_KEY_VALUE_SPECIAL_SIZE
);
639 ValueCell
->Type
= dwType
;
643 if (cbData
> DataCellSize
)
645 /* New data size is larger than the current, destroy current
646 * data block and allocate a new one. */
647 HCELL_INDEX NewOffset
;
649 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
651 NewOffset
= HvAllocateCell(Hive
, cbData
, Stable
, HCELL_NIL
);
652 if (NewOffset
== HCELL_NIL
)
654 DPRINT("HvAllocateCell() has failed!\n");
655 return ERROR_UNSUCCESSFUL
;
659 HvFreeCell(Hive
, ValueCell
->Data
);
661 ValueCell
->Data
= NewOffset
;
662 DataCell
= (PVOID
)HvGetCell(Hive
, NewOffset
);
665 /* Copy new contents to cell */
666 RtlCopyMemory(DataCell
, lpData
, cbData
);
667 ValueCell
->DataLength
= (cbData
& ~CM_KEY_VALUE_SPECIAL_SIZE
);
668 ValueCell
->Type
= dwType
;
669 HvMarkCellDirty(Hive
, ValueCell
->Data
, FALSE
);
672 HvMarkCellDirty(Hive
, CellIndex
, FALSE
);
674 /* Check if the maximum value name length changed, update it if so */
675 if (KeyNode
->MaxValueNameLen
< ValueNameString
.Length
)
676 KeyNode
->MaxValueNameLen
= ValueNameString
.Length
;
678 /* Check if the maximum data length changed, update it if so */
679 if (KeyNode
->MaxValueDataLen
< cbData
)
680 KeyNode
->MaxValueDataLen
= cbData
;
682 /* Save the write time */
683 KeQuerySystemTime(&KeyNode
->LastWriteTime
);
685 return ERROR_SUCCESS
;
689 // Synced with freeldr/windows/registry.c
694 IN PCM_KEY_VALUE ValueCell
,
695 OUT PULONG Type OPTIONAL
,
696 OUT PUCHAR Data OPTIONAL
,
697 IN OUT PULONG DataSize OPTIONAL
)
702 /* Does the caller want the type? */
704 *Type
= ValueCell
->Type
;
706 /* Does the caller provide DataSize? */
707 if (DataSize
!= NULL
)
709 // NOTE: CmpValueToData doesn't support big data (the function will
710 // bugcheck if so), FreeLdr is not supposed to read such data.
711 // If big data is needed, use instead CmpGetValueData.
712 // CmpGetValueData(Hive, ValueCell, DataSize, &DataCell, ...);
713 DataCell
= CmpValueToData(Hive
, ValueCell
, &DataLength
);
715 /* Does the caller want the data? */
716 if ((Data
!= NULL
) && (*DataSize
!= 0))
720 min(*DataSize
, DataLength
));
723 /* Return the actual data length */
724 *DataSize
= DataLength
;
728 // Similar to RegQueryValue in freeldr/windows/registry.c
732 IN LPCWSTR lpValueName
,
733 IN PULONG lpReserved
,
734 OUT PULONG lpType OPTIONAL
,
735 OUT PUCHAR lpData OPTIONAL
,
736 IN OUT PULONG lpcbData OPTIONAL
)
738 PMEMKEY ParentKey
= HKEY_TO_MEMKEY(hKey
);
739 PHHIVE Hive
= &ParentKey
->RegistryHive
->Hive
;
740 PCM_KEY_NODE KeyNode
;
741 PCM_KEY_VALUE ValueCell
;
742 HCELL_INDEX CellIndex
;
743 UNICODE_STRING ValueNameString
;
745 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentKey
->KeyCellOffset
);
747 return ERROR_UNSUCCESSFUL
;
749 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
751 /* Initialize value name string */
752 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
753 CellIndex
= CmpFindValueByName(Hive
, KeyNode
, &ValueNameString
);
754 if (CellIndex
== HCELL_NIL
)
755 return ERROR_FILE_NOT_FOUND
;
757 /* Get the value cell */
758 ValueCell
= HvGetCell(Hive
, CellIndex
);
759 ASSERT(ValueCell
!= NULL
);
761 RepGetValueData(Hive
, ValueCell
, lpType
, lpData
, lpcbData
);
763 HvReleaseCell(Hive
, CellIndex
);
765 return ERROR_SUCCESS
;
771 IN LPCWSTR lpValueName OPTIONAL
)
773 DPRINT1("RegDeleteValueW(0x%p, '%S') is UNIMPLEMENTED!\n",
774 hKey
, (lpValueName
? lpValueName
: L
""));
775 return ERROR_UNSUCCESSFUL
;
782 IN PCMHIVE HiveToConnect
,
783 IN PUCHAR SecurityDescriptor
,
784 IN ULONG SecurityDescriptorLength
,
789 PREPARSE_POINT ReparsePoint
;
792 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(*ReparsePoint
));
797 * Use a dummy root key name:
798 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
799 * - On Vista+, this is "CMI-CreateHive{guid}"
800 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
801 * for more information.
803 Status
= CmiInitializeHive(HiveToConnect
, L
"$$$PROTO.HIV");
804 if (!NT_SUCCESS(Status
))
806 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status
);
812 * Add security to the root key.
813 * NOTE: One can implement this using the lpSecurityAttributes
814 * parameter of RegCreateKeyExW.
816 Status
= CmiCreateSecurityKey(&HiveToConnect
->Hive
,
817 HiveToConnect
->Hive
.BaseBlock
->RootCell
,
818 SecurityDescriptor
, SecurityDescriptorLength
);
819 if (!NT_SUCCESS(Status
))
820 DPRINT1("Failed to add security for root key '%S'\n", Path
);
823 rc
= RegCreateKeyExW(RootKey
,
832 if (rc
!= ERROR_SUCCESS
)
838 ReparsePoint
->SourceHive
= NewKey
->RegistryHive
;
839 ReparsePoint
->SourceKeyCellOffset
= NewKey
->KeyCellOffset
;
840 NewKey
->RegistryHive
= HiveToConnect
;
841 NewKey
->KeyCellOffset
= HiveToConnect
->Hive
.BaseBlock
->RootCell
;
842 ReparsePoint
->DestinationHive
= NewKey
->RegistryHive
;
843 ReparsePoint
->DestinationKeyCellOffset
= NewKey
->KeyCellOffset
;
844 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
851 IN PCWSTR LinkKeyPath OPTIONAL
,
852 IN OUT PHKEY LinkKeyHandle OPTIONAL
,
853 // IN PCWSTR TargetKeyPath OPTIONAL,
854 IN HKEY TargetKeyHandle
)
856 PMEMKEY LinkKey
, TargetKey
;
857 PREPARSE_POINT ReparsePoint
;
859 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(*ReparsePoint
));
863 if (LinkKeyPath
&& !(LinkKeyHandle
&& *LinkKeyHandle
))
865 /* Create the link key */
866 RegCreateKeyExW(NULL
,
876 else if (LinkKeyHandle
)
878 /* Use the user-provided link key handle */
879 LinkKey
= HKEY_TO_MEMKEY(*LinkKeyHandle
);
883 *LinkKeyHandle
= MEMKEY_TO_HKEY(LinkKey
);
885 TargetKey
= HKEY_TO_MEMKEY(TargetKeyHandle
);
887 ReparsePoint
->SourceHive
= LinkKey
->RegistryHive
;
888 ReparsePoint
->SourceKeyCellOffset
= LinkKey
->KeyCellOffset
;
889 ReparsePoint
->DestinationHive
= TargetKey
->RegistryHive
;
890 ReparsePoint
->DestinationKeyCellOffset
= TargetKey
->KeyCellOffset
;
891 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
897 RegInitializeRegistry(
904 InitializeListHead(&CmiHiveListHead
);
905 InitializeListHead(&CmiReparsePointsHead
);
907 Status
= CmiInitializeHive(&RootHive
, L
"");
908 if (!NT_SUCCESS(Status
))
910 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status
);
914 RootKey
= CreateInMemoryStructure(&RootHive
,
915 RootHive
.Hive
.BaseBlock
->RootCell
);
917 for (i
= 0; i
< _countof(RegistryHives
); ++i
)
919 /* Skip this registry hive if it's not in the list */
920 if (!strstr(HiveList
, RegistryHives
[i
].HiveName
))
923 /* Create the registry key */
924 ConnectRegistry(NULL
,
925 RegistryHives
[i
].CmHive
,
926 RegistryHives
[i
].SecurityDescriptor
,
927 RegistryHives
[i
].SecurityDescriptorLength
,
928 RegistryHives
[i
].HiveRegistryPath
);
930 /* If we happen to deal with the special setup registry hive, stop there */
931 // if (strcmp(RegistryHives[i].HiveName, "SETUPREG") == 0)
936 /* Create the 'ControlSet001' key */
938 L
"Registry\\Machine\\SYSTEM\\ControlSet001",
941 /* Create the 'CurrentControlSet' key as a symlink to 'ControlSet001' */
942 CreateSymLink(L
"Registry\\Machine\\SYSTEM\\CurrentControlSet",
943 NULL
, ControlSetKey
);
946 /* Link SECURITY to SAM */
947 CmpLinkKeyToHive(L
"\\Registry\\Machine\\Security\\SAM", L
"\\Registry\\Machine\\SAM\\SAM");
948 /* Link S-1-5-18 to .Default */
949 CmpLinkKeyToHive(L
"\\Registry\\User\\S-1-5-18", L
"\\Registry\\User\\.Default");
954 RegShutdownRegistry(VOID
)
957 PREPARSE_POINT ReparsePoint
;
959 /* Clean up the reparse points list */
960 while (!IsListEmpty(&CmiReparsePointsHead
))
962 Entry
= RemoveHeadList(&CmiReparsePointsHead
);
963 ReparsePoint
= CONTAINING_RECORD(Entry
, REPARSE_POINT
, ListEntry
);
967 /* FIXME: clean up the complete hive */