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
28 /* INCLUDES *****************************************************************/
33 /* DEFINITIONS AND DATA *****************************************************/
35 #define STATUS_NO_LOG_SPACE ((NTSTATUS)0xC000017D)
36 #define STATUS_CANNOT_DELETE ((NTSTATUS)0xC0000121)
38 typedef struct _REPARSE_POINT
42 HCELL_INDEX SourceKeyCellOffset
;
43 PCMHIVE DestinationHive
;
44 HCELL_INDEX DestinationKeyCellOffset
;
45 } REPARSE_POINT
, *PREPARSE_POINT
;
47 typedef struct _MEMKEY
49 /* Information on hard disk structure */
50 HCELL_INDEX KeyCellOffset
;
54 #define HKEY_TO_MEMKEY(hKey) ((PMEMKEY)(hKey))
55 #define MEMKEY_TO_HKEY(memKey) ((HKEY)(memKey))
57 static CMHIVE RootHive
;
58 static PMEMKEY RootKey
;
60 static CMHIVE SystemHive
; /* \Registry\Machine\SYSTEM */
61 static CMHIVE SoftwareHive
; /* \Registry\Machine\SOFTWARE */
62 static CMHIVE DefaultHive
; /* \Registry\User\.DEFAULT */
63 static CMHIVE SamHive
; /* \Registry\Machine\SAM */
64 static CMHIVE SecurityHive
; /* \Registry\Machine\SECURITY */
65 static CMHIVE BcdHive
; /* \Registry\Machine\BCD00000000 */
68 // TODO: Write these values in a more human-readable form.
69 // See http://amnesia.gtisc.gatech.edu/~moyix/suzibandit.ltd.uk/MSc/Registry%20Structure%20-%20Appendices%20V4.pdf
70 // Appendix 12 "The Registry NT Security Descriptor" for more information.
72 // Those SECURITY_DESCRIPTORs were obtained by dumping the security block "sk"
73 // of registry hives created by setting their permissions to be the same as
74 // the ones of the BCD, SOFTWARE, or SYSTEM, SAM and .DEFAULT system hives.
75 // A cross-check was subsequently done with the system hives to verify that
76 // the security descriptors were the same.
78 static UCHAR BcdSecurity
[] =
80 // SECURITY_DESCRIPTOR_RELATIVE
83 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
84 // SE_DACL_PROTECTED (0x1000) |
85 // SE_DACL_AUTO_INHERITED (0x0400) |
86 // SE_DACL_PRESENT (0x0004)
87 0x48, 0x00, 0x00, 0x00, // Owner
88 0x58, 0x00, 0x00, 0x00, // Group
89 0x00, 0x00, 0x00, 0x00, // Sacl (None)
90 0x14, 0x00, 0x00, 0x00, // Dacl
95 0x34, 0x00, // AclSize
96 0x02, 0x00, // AceCount
100 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
101 0x02, // AceFlags: CONTAINER_INHERIT_ACE
102 0x18, 0x00, // AceSize
103 0x19, 0x00, 0x06, 0x00, // ACCESS_MASK: "Write DAC" (0x00040000) |
104 // "Read Control" (0x00020000) |
105 // "Notify" (0x00000010) |
106 // "Enumerate Subkeys" (0x00000008) |
107 // "Query Value" (0x00000001)
108 // (SidStart: S-1-5-32-544 "Administrators")
109 0x01, 0x02, 0x00, 0x00,
110 0x00, 0x00, 0x00, 0x05,
111 0x20, 0x00, 0x00, 0x00,
112 0x20, 0x02, 0x00, 0x00,
115 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
116 0x02, // AceFlags: CONTAINER_INHERIT_ACE
117 0x14, 0x00, // AceSize
118 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
119 // (SidStart: S-1-5-18 "Local System")
120 0x01, 0x01, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x05,
122 0x12, 0x00, 0x00, 0x00,
124 // Owner SID (S-1-5-32-544 "Administrators")
125 0x01, 0x02, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x05,
127 0x20, 0x00, 0x00, 0x00,
128 0x20, 0x02, 0x00, 0x00,
130 // Group SID (S-1-5-21-domain-513 "Domain Users")
131 0x01, 0x05, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x05,
133 0x15, 0x00, 0x00, 0x00,
134 0xAC, 0xD0, 0x49, 0xCB,
135 0xE6, 0x52, 0x47, 0x9C,
136 0xE4, 0x31, 0xDB, 0x5C,
137 0x01, 0x02, 0x00, 0x00
140 static UCHAR SoftwareSecurity
[] =
142 // SECURITY_DESCRIPTOR_RELATIVE
145 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
146 // SE_DACL_PROTECTED (0x1000) |
147 // SE_DACL_AUTO_INHERITED (0x0400) |
148 // SE_DACL_PRESENT (0x0004)
149 0xA0, 0x00, 0x00, 0x00, // Owner
150 0xB0, 0x00, 0x00, 0x00, // Group
151 0x00, 0x00, 0x00, 0x00, // Sacl (None)
152 0x14, 0x00, 0x00, 0x00, // Dacl
157 0x8C, 0x00, // AclSize
158 0x06, 0x00, // AceCount
162 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
163 0x02, // AceFlags: CONTAINER_INHERIT_ACE
164 0x18, 0x00, // AceSize
165 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
166 // (SidStart: S-1-5-32-544 "Administrators")
167 0x01, 0x02, 0x00, 0x00,
168 0x00, 0x00, 0x00, 0x05,
169 0x20, 0x00, 0x00, 0x00,
170 0x20, 0x02, 0x00, 0x00,
173 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
174 0x0A, // AceFlags: INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE
175 0x14, 0x00, // AceSize
176 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
177 // (SidStart: S-1-3-0 "Creator Owner")
178 0x01, 0x01, 0x00, 0x00,
179 0x00, 0x00, 0x00, 0x03,
180 0x00, 0x00, 0x00, 0x00,
183 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
184 0x02, // AceFlags: CONTAINER_INHERIT_ACE
185 0x14, 0x00, // AceSize
186 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
187 // (SidStart: S-1-5-18 "Local System")
188 0x01, 0x01, 0x00, 0x00,
189 0x00, 0x00, 0x00, 0x05,
190 0x12, 0x00, 0x00, 0x00,
193 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
194 0x02, // AceFlags: CONTAINER_INHERIT_ACE
195 0x14, 0x00, // AceSize
196 0x1F, 0x00, 0x03, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
197 // "Delete" (0x00010000) |
198 // "Notify" (0x00000010) |
199 // "Enumerate Subkeys" (0x00000008) |
200 // "Create Subkey" (0x00000004) |
201 // "Set Value" (0x00000002) |
202 // "Query Value" (0x00000001)
203 // (SidStart: S-1-5-13 "Terminal Server Users")
204 0x01, 0x01, 0x00, 0x00,
205 0x00, 0x00, 0x00, 0x05,
206 0x0D, 0x00, 0x00, 0x00,
209 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
210 0x02, // AceFlags: CONTAINER_INHERIT_ACE
211 0x18, 0x00, // AceSize
212 0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
213 // "Notify" (0x00000010) |
214 // "Enumerate Subkeys" (0x00000008) |
215 // "Query Value" (0x00000001)
216 // (SidStart: S-1-5-32-545 "Users")
217 0x01, 0x02, 0x00, 0x00,
218 0x00, 0x00, 0x00, 0x05,
219 0x20, 0x00, 0x00, 0x00,
220 0x21, 0x02, 0x00, 0x00,
223 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
224 0x02, // AceFlags: CONTAINER_INHERIT_ACE
225 0x18, 0x00, // AceSize
226 0x1F, 0x00, 0x03, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
227 // "Delete" (0x00010000) |
228 // "Notify" (0x00000010) |
229 // "Enumerate Subkeys" (0x00000008) |
230 // "Create Subkey" (0x00000004) |
231 // "Set Value" (0x00000002) |
232 // "Query Value" (0x00000001)
233 // (SidStart: S-1-5-32-547 "Power Users")
234 0x01, 0x02, 0x00, 0x00,
235 0x00, 0x00, 0x00, 0x05,
236 0x20, 0x00, 0x00, 0x00,
237 0x23, 0x02, 0x00, 0x00,
239 // Owner SID (S-1-5-32-544 "Administrators")
240 0x01, 0x02, 0x00, 0x00,
241 0x00, 0x00, 0x00, 0x05,
242 0x20, 0x00, 0x00, 0x00,
243 0x20, 0x02, 0x00, 0x00,
245 // Group SID (S-1-5-21-domain-513 "Domain Users")
246 0x01, 0x05, 0x00, 0x00,
247 0x00, 0x00, 0x00, 0x05,
248 0x15, 0x00, 0x00, 0x00,
249 0xAC, 0xD0, 0x49, 0xCB,
250 0xE6, 0x52, 0x47, 0x9C,
251 0xE4, 0x31, 0xDB, 0x5C,
252 0x01, 0x02, 0x00, 0x00
255 // Same security for SYSTEM, SAM and .DEFAULT
256 static UCHAR SystemSecurity
[] =
258 // SECURITY_DESCRIPTOR_RELATIVE
261 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
262 // SE_DACL_PROTECTED (0x1000) |
263 // SE_DACL_AUTO_INHERITED (0x0400) |
264 // SE_DACL_PRESENT (0x0004)
265 0x8C, 0x00, 0x00, 0x00, // Owner
266 0x9C, 0x00, 0x00, 0x00, // Group
267 0x00, 0x00, 0x00, 0x00, // Sacl (None)
268 0x14, 0x00, 0x00, 0x00, // Dacl
273 0x78, 0x00, // AclSize
274 0x05, 0x00, // AceCount
278 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
279 0x02, // AceFlags: CONTAINER_INHERIT_ACE
280 0x18, 0x00, // AceSize
281 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
282 // (SidStart: S-1-5-32-544 "Administrators")
283 0x01, 0x02, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x05,
285 0x20, 0x00, 0x00, 0x00,
286 0x20, 0x02, 0x00, 0x00,
289 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
290 0x0A, // AceFlags: INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE
291 0x14, 0x00, // AceSize
292 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
293 // (SidStart: S-1-3-0 "Creator Owner")
294 0x01, 0x01, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x03,
296 0x00, 0x00, 0x00, 0x00,
299 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
300 0x02, // AceFlags: CONTAINER_INHERIT_ACE
301 0x14, 0x00, // AceSize
302 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
303 // (SidStart: S-1-5-18 "Local System")
304 0x01, 0x01, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x05,
306 0x12, 0x00, 0x00, 0x00,
309 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
310 0x02, // AceFlags: CONTAINER_INHERIT_ACE
311 0x18, 0x00, // AceSize
312 0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
313 // "Notify" (0x00000010) |
314 // "Enumerate Subkeys" (0x00000008) |
315 // "Query Value" (0x00000001)
316 // (SidStart: S-1-5-32-545 "Users")
317 0x01, 0x02, 0x00, 0x00,
318 0x00, 0x00, 0x00, 0x05,
319 0x20, 0x00, 0x00, 0x00,
320 0x21, 0x02, 0x00, 0x00,
323 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
324 0x02, // AceFlags: CONTAINER_INHERIT_ACE
325 0x18, 0x00, // AceSize
326 0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
327 // "Notify" (0x00000010) |
328 // "Enumerate Subkeys" (0x00000008) |
329 // "Query Value" (0x00000001)
330 // (SidStart: S-1-5-32-547 "Power Users")
331 0x01, 0x02, 0x00, 0x00,
332 0x00, 0x00, 0x00, 0x05,
333 0x20, 0x00, 0x00, 0x00,
334 0x23, 0x02, 0x00, 0x00,
336 // Owner SID (S-1-5-32-544 "Administrators")
337 0x01, 0x02, 0x00, 0x00,
338 0x00, 0x00, 0x00, 0x05,
339 0x20, 0x00, 0x00, 0x00,
340 0x20, 0x02, 0x00, 0x00,
342 // Group SID (S-1-5-21-domain-513 "Domain Users")
343 0x01, 0x05, 0x00, 0x00,
344 0x00, 0x00, 0x00, 0x05,
345 0x15, 0x00, 0x00, 0x00,
346 0xAC, 0xD0, 0x49, 0xCB,
347 0xE6, 0x52, 0x47, 0x9C,
348 0xE4, 0x31, 0xDB, 0x5C,
349 0x01, 0x02, 0x00, 0x00
352 /* GLOBALS ******************************************************************/
354 HIVE_LIST_ENTRY RegistryHives
[/*MAX_NUMBER_OF_REGISTRY_HIVES*/] =
356 /* Special Setup system registry hive */
357 // WARNING: Please *keep* it in first position!
358 { "SETUPREG", L
"Registry\\Machine\\SYSTEM" , &SystemHive
, SystemSecurity
, sizeof(SystemSecurity
) },
360 /* Regular registry hives */
361 { "SYSTEM" , L
"Registry\\Machine\\SYSTEM" , &SystemHive
, SystemSecurity
, sizeof(SystemSecurity
) },
362 { "SOFTWARE", L
"Registry\\Machine\\SOFTWARE" , &SoftwareHive
, SoftwareSecurity
, sizeof(SoftwareSecurity
) },
363 { "DEFAULT" , L
"Registry\\User\\.DEFAULT" , &DefaultHive
, SystemSecurity
, sizeof(SystemSecurity
) },
364 { "SAM" , L
"Registry\\Machine\\SAM" , &SamHive
, SystemSecurity
, sizeof(SystemSecurity
) },
365 { "SECURITY", L
"Registry\\Machine\\SECURITY" , &SecurityHive
, NULL
, 0 },
366 { "BCD" , L
"Registry\\Machine\\BCD00000000", &BcdHive
, BcdSecurity
, sizeof(BcdSecurity
) },
368 C_ASSERT(_countof(RegistryHives
) == MAX_NUMBER_OF_REGISTRY_HIVES
);
370 /* FUNCTIONS ****************************************************************/
373 CreateInMemoryStructure(
374 IN PCMHIVE RegistryHive
,
375 IN HCELL_INDEX KeyCellOffset
)
379 Key
= (PMEMKEY
)malloc(sizeof(MEMKEY
));
383 Key
->RegistryHive
= RegistryHive
;
384 Key
->KeyCellOffset
= KeyCellOffset
;
388 LIST_ENTRY CmiHiveListHead
;
389 LIST_ENTRY CmiReparsePointsHead
;
395 IN BOOL AllowCreation
,
401 UNICODE_STRING KeyString
;
403 PREPARSE_POINT CurrentReparsePoint
;
405 PCMHIVE ParentRegistryHive
;
406 HCELL_INDEX ParentCellOffset
;
407 PCM_KEY_NODE ParentKeyCell
;
409 PCM_KEY_NODE SubKeyCell
;
410 HCELL_INDEX BlockOffset
;
412 DPRINT("RegpCreateOrOpenKey('%S')\n", KeyName
);
414 if (*KeyName
== OBJ_NAME_PATH_SEPARATOR
)
417 ParentRegistryHive
= RootKey
->RegistryHive
;
418 ParentCellOffset
= RootKey
->KeyCellOffset
;
420 else if (hParentKey
== NULL
)
422 ParentRegistryHive
= RootKey
->RegistryHive
;
423 ParentCellOffset
= RootKey
->KeyCellOffset
;
427 ParentRegistryHive
= HKEY_TO_MEMKEY(hParentKey
)->RegistryHive
;
428 ParentCellOffset
= HKEY_TO_MEMKEY(hParentKey
)->KeyCellOffset
;
431 LocalKeyName
= (PWSTR
)KeyName
;
434 End
= (PWSTR
)strchrW(LocalKeyName
, OBJ_NAME_PATH_SEPARATOR
);
437 KeyString
.Buffer
= LocalKeyName
;
438 KeyString
.Length
= KeyString
.MaximumLength
=
439 (USHORT
)((ULONG_PTR
)End
- (ULONG_PTR
)LocalKeyName
);
443 RtlInitUnicodeString(&KeyString
, LocalKeyName
);
444 if (KeyString
.Length
== 0)
446 /* Trailing path separator: we're done */
451 ParentKeyCell
= (PCM_KEY_NODE
)HvGetCell(&ParentRegistryHive
->Hive
, ParentCellOffset
);
453 return STATUS_UNSUCCESSFUL
;
455 VERIFY_KEY_CELL(ParentKeyCell
);
457 BlockOffset
= CmpFindSubKeyByName(&ParentRegistryHive
->Hive
, ParentKeyCell
, &KeyString
);
458 if (BlockOffset
!= HCELL_NIL
)
460 Status
= STATUS_SUCCESS
;
462 /* Search for a possible reparse point */
463 Ptr
= CmiReparsePointsHead
.Flink
;
464 while (Ptr
!= &CmiReparsePointsHead
)
466 CurrentReparsePoint
= CONTAINING_RECORD(Ptr
, REPARSE_POINT
, ListEntry
);
467 if (CurrentReparsePoint
->SourceHive
== ParentRegistryHive
&&
468 CurrentReparsePoint
->SourceKeyCellOffset
== BlockOffset
)
470 ParentRegistryHive
= CurrentReparsePoint
->DestinationHive
;
471 BlockOffset
= CurrentReparsePoint
->DestinationKeyCellOffset
;
477 else if (AllowCreation
) // && (BlockOffset == HCELL_NIL)
479 Status
= CmiAddSubKey(ParentRegistryHive
,
485 else // if (BlockOffset == HCELL_NIL)
487 Status
= STATUS_OBJECT_NAME_NOT_FOUND
; // ERROR_PATH_NOT_FOUND;
490 HvReleaseCell(&ParentRegistryHive
->Hive
, ParentCellOffset
);
492 if (!NT_SUCCESS(Status
))
494 DPRINT("RegpCreateOrOpenKey('%S'): Could not create or open subkey '%wZ'\n", KeyName
, &KeyString
);
495 return ERROR_UNSUCCESSFUL
;
498 ParentCellOffset
= BlockOffset
;
500 LocalKeyName
= End
+ 1;
505 CurrentKey
= CreateInMemoryStructure(ParentRegistryHive
, ParentCellOffset
);
507 return ERROR_OUTOFMEMORY
;
509 *Key
= MEMKEY_TO_HKEY(CurrentKey
);
511 return ERROR_SUCCESS
;
518 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
520 /* Free the object */
523 return ERROR_SUCCESS
;
532 return RegpCreateOrOpenKey(hKey
, lpSubKey
, TRUE
, FALSE
, phkResult
);
540 IN LPWSTR lpClass OPTIONAL
,
542 IN REGSAM samDesired
,
543 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL
,
545 OUT LPDWORD lpdwDisposition OPTIONAL
)
547 return RegpCreateOrOpenKey(hKey
,
550 (dwOptions
& REG_OPTION_VOLATILE
) != 0,
561 PMEMKEY Key
; // ParentKey
563 PCM_KEY_NODE KeyNode
; // ParentNode
565 HCELL_INDEX ParentCell
;
571 rc
= RegOpenKeyW(hKey
, lpSubKey
, &hTargetKey
);
572 if (rc
!= ERROR_SUCCESS
)
580 /* Don't allow deleting the root */
581 if (hTargetKey
== RootKey
)
584 Status
= STATUS_CANNOT_DELETE
;
588 /* Get the hive and node */
589 Key
= HKEY_TO_MEMKEY(hTargetKey
);
590 Hive
= &Key
->RegistryHive
->Hive
;
592 /* Get the key node */
593 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
596 Status
= ERROR_UNSUCCESSFUL
;
600 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
602 /* Check if we don't have any children */
603 if (!(KeyNode
->SubKeyCounts
[Stable
] + KeyNode
->SubKeyCounts
[Volatile
]) &&
604 !(KeyNode
->Flags
& KEY_NO_DELETE
))
606 /* Get the parent and free the cell */
607 ParentCell
= KeyNode
->Parent
;
608 Status
= CmpFreeKeyByCell(Hive
, Key
->KeyCellOffset
, TRUE
);
609 if (NT_SUCCESS(Status
))
611 /* Get the parent node */
612 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentCell
);
615 /* Make sure we're dirty */
616 ASSERT(HvIsCellDirty(Hive
, ParentCell
));
618 /* Update the write time */
619 KeQuerySystemTime(&Parent
->LastWriteTime
);
621 /* Release the cell */
622 HvReleaseCell(Hive
, ParentCell
);
629 Status
= STATUS_CANNOT_DELETE
;
632 /* Release the cell */
633 HvReleaseCell(Hive
, Key
->KeyCellOffset
);
637 RegCloseKey(hTargetKey
);
648 return RegpCreateOrOpenKey(hKey
, lpSubKey
, FALSE
, FALSE
, phkResult
);
654 IN LPCWSTR lpValueName OPTIONAL
,
657 IN
const UCHAR
* lpData
,
660 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
662 PCM_KEY_NODE KeyNode
; // ParentNode
663 PCM_KEY_VALUE ValueCell
;
665 HCELL_INDEX CellIndex
;
666 UNICODE_STRING ValueNameString
;
672 if (dwType
== REG_LINK
)
676 /* Special handling of registry links */
677 if (cbData
!= sizeof(PVOID
))
678 return STATUS_INVALID_PARAMETER
;
680 DestKey
= HKEY_TO_MEMKEY(*(PHKEY
)lpData
);
682 // FIXME: Add additional checks for the validity of DestKey
684 /* Create the link in registry hive (if applicable) */
685 if (Key
->RegistryHive
!= DestKey
->RegistryHive
)
686 return STATUS_SUCCESS
;
688 DPRINT1("Save link to registry\n");
689 return STATUS_NOT_IMPLEMENTED
;
692 if ((cbData
& ~CM_KEY_VALUE_SPECIAL_SIZE
) != cbData
)
693 return STATUS_UNSUCCESSFUL
;
695 Hive
= &Key
->RegistryHive
->Hive
;
697 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
699 return ERROR_UNSUCCESSFUL
;
701 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
703 /* Mark the parent as dirty since we are going to create a new value in it */
704 HvMarkCellDirty(Hive
, Key
->KeyCellOffset
, FALSE
);
706 /* Initialize value name string */
707 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
708 if (!CmpFindNameInList(Hive
,
715 ASSERT(CellIndex
== HCELL_NIL
);
717 // Status = STATUS_INSUFFICIENT_RESOURCES;
718 return ERROR_UNSUCCESSFUL
;
720 if (CellIndex
== HCELL_NIL
)
722 /* The value doesn't exist, create a new one */
723 Status
= CmiAddValueKey(Key
->RegistryHive
,
732 /* The value already exists, use it. Get the value cell. */
733 ValueCell
= HvGetCell(&Key
->RegistryHive
->Hive
, CellIndex
);
734 ASSERT(ValueCell
!= NULL
);
735 Status
= STATUS_SUCCESS
;
738 // /**/HvReleaseCell(Hive, CellIndex);/**/
740 if (!NT_SUCCESS(Status
))
741 return ERROR_UNSUCCESSFUL
;
743 /* Get size of the allocated cell (if any) */
744 if (!(ValueCell
->DataLength
& CM_KEY_VALUE_SPECIAL_SIZE
) &&
745 (ValueCell
->DataLength
& ~CM_KEY_VALUE_SPECIAL_SIZE
) != 0)
747 DataCell
= HvGetCell(Hive
, ValueCell
->Data
);
749 return ERROR_UNSUCCESSFUL
;
751 DataCellSize
= (ULONG
)(-HvGetCellSize(Hive
, DataCell
));
759 if (cbData
<= sizeof(HCELL_INDEX
))
761 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
762 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
764 HvFreeCell(Hive
, ValueCell
->Data
);
766 RtlCopyMemory(&ValueCell
->Data
, lpData
, cbData
);
767 ValueCell
->DataLength
= (cbData
| CM_KEY_VALUE_SPECIAL_SIZE
);
768 ValueCell
->Type
= dwType
;
772 if (cbData
> DataCellSize
)
774 /* New data size is larger than the current, destroy current
775 * data block and allocate a new one. */
776 HCELL_INDEX NewOffset
;
778 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
780 NewOffset
= HvAllocateCell(Hive
, cbData
, Stable
, HCELL_NIL
);
781 if (NewOffset
== HCELL_NIL
)
783 DPRINT("HvAllocateCell() has failed!\n");
784 return ERROR_UNSUCCESSFUL
;
788 HvFreeCell(Hive
, ValueCell
->Data
);
790 ValueCell
->Data
= NewOffset
;
791 DataCell
= (PVOID
)HvGetCell(Hive
, NewOffset
);
794 /* Copy new contents to cell */
795 RtlCopyMemory(DataCell
, lpData
, cbData
);
796 ValueCell
->DataLength
= (cbData
& ~CM_KEY_VALUE_SPECIAL_SIZE
);
797 ValueCell
->Type
= dwType
;
798 HvMarkCellDirty(Hive
, ValueCell
->Data
, FALSE
);
801 HvMarkCellDirty(Hive
, CellIndex
, FALSE
);
803 /* Check if the maximum value name length changed, update it if so */
804 if (KeyNode
->MaxValueNameLen
< ValueNameString
.Length
)
805 KeyNode
->MaxValueNameLen
= ValueNameString
.Length
;
807 /* Check if the maximum data length changed, update it if so */
808 if (KeyNode
->MaxValueDataLen
< cbData
)
809 KeyNode
->MaxValueDataLen
= cbData
;
811 /* Save the write time */
812 KeQuerySystemTime(&KeyNode
->LastWriteTime
);
814 return ERROR_SUCCESS
;
818 // Synced with freeldr/ntldr/registry.c
823 IN PCM_KEY_VALUE ValueCell
,
824 OUT PULONG Type OPTIONAL
,
825 OUT PUCHAR Data OPTIONAL
,
826 IN OUT PULONG DataSize OPTIONAL
)
831 /* Does the caller want the type? */
833 *Type
= ValueCell
->Type
;
835 /* Does the caller provide DataSize? */
836 if (DataSize
!= NULL
)
838 // NOTE: CmpValueToData doesn't support big data (the function will
839 // bugcheck if so), FreeLdr is not supposed to read such data.
840 // If big data is needed, use instead CmpGetValueData.
841 // CmpGetValueData(Hive, ValueCell, DataSize, &DataCell, ...);
842 DataCell
= CmpValueToData(Hive
, ValueCell
, &DataLength
);
844 /* Does the caller want the data? */
845 if ((Data
!= NULL
) && (*DataSize
!= 0))
849 min(*DataSize
, DataLength
));
852 /* Return the actual data length */
853 *DataSize
= DataLength
;
857 // Similar to RegQueryValue in freeldr/ntldr/registry.c
861 IN LPCWSTR lpValueName
,
862 IN PULONG lpReserved
,
863 OUT PULONG lpType OPTIONAL
,
864 OUT PUCHAR lpData OPTIONAL
,
865 IN OUT PULONG lpcbData OPTIONAL
)
867 PMEMKEY ParentKey
= HKEY_TO_MEMKEY(hKey
);
868 PHHIVE Hive
= &ParentKey
->RegistryHive
->Hive
;
869 PCM_KEY_NODE KeyNode
;
870 PCM_KEY_VALUE ValueCell
;
871 HCELL_INDEX CellIndex
;
872 UNICODE_STRING ValueNameString
;
874 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentKey
->KeyCellOffset
);
876 return ERROR_UNSUCCESSFUL
;
878 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
880 /* Initialize value name string */
881 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
882 CellIndex
= CmpFindValueByName(Hive
, KeyNode
, &ValueNameString
);
883 if (CellIndex
== HCELL_NIL
)
884 return ERROR_FILE_NOT_FOUND
;
886 /* Get the value cell */
887 ValueCell
= HvGetCell(Hive
, CellIndex
);
888 ASSERT(ValueCell
!= NULL
);
890 RepGetValueData(Hive
, ValueCell
, lpType
, lpData
, lpcbData
);
892 HvReleaseCell(Hive
, CellIndex
);
894 return ERROR_SUCCESS
;
900 IN LPCWSTR lpValueName OPTIONAL
)
902 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
903 PHHIVE Hive
= &Key
->RegistryHive
->Hive
;
904 PCM_KEY_NODE KeyNode
; // ParentNode
905 PCM_KEY_VALUE ValueCell
;
906 HCELL_INDEX CellIndex
;
908 UNICODE_STRING ValueNameString
;
912 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
914 return ERROR_UNSUCCESSFUL
;
916 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
918 /* Initialize value name string */
919 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
920 if (!CmpFindNameInList(Hive
,
927 ASSERT(CellIndex
== HCELL_NIL
);
929 if (CellIndex
== HCELL_NIL
)
931 Status
= ERROR_FILE_NOT_FOUND
; // STATUS_OBJECT_NAME_NOT_FOUND;
935 /* We found the value, mark all relevant cells dirty */
936 HvMarkCellDirty(Hive
, Key
->KeyCellOffset
, FALSE
);
937 HvMarkCellDirty(Hive
, KeyNode
->ValueList
.List
, FALSE
);
938 HvMarkCellDirty(Hive
, CellIndex
, FALSE
);
940 /* Get the key value */
941 ValueCell
= (PCM_KEY_VALUE
)HvGetCell(Hive
, CellIndex
);
944 /* Mark it and all related data as dirty */
945 if (!CmpMarkValueDataDirty(Hive
, ValueCell
))
947 /* Not enough log space, fail */
948 Status
= STATUS_NO_LOG_SPACE
;
953 ASSERT(HvIsCellDirty(Hive
, KeyNode
->ValueList
.List
));
954 ASSERT(HvIsCellDirty(Hive
, CellIndex
));
956 /* Remove the value from the child list */
957 Status
= CmpRemoveValueFromList(Hive
, ChildIndex
, &KeyNode
->ValueList
);
958 if (!NT_SUCCESS(Status
))
960 /* Set known error */
961 Status
= STATUS_INSUFFICIENT_RESOURCES
;
965 /* Remove the value and its data itself */
966 if (!CmpFreeValue(Hive
, CellIndex
))
968 /* Failed to free the value, fail */
969 Status
= STATUS_INSUFFICIENT_RESOURCES
;
973 /* Set the last write time */
974 KeQuerySystemTime(&KeyNode
->LastWriteTime
);
977 ASSERT(HvIsCellDirty(Hive
, Key
->KeyCellOffset
));
979 /* Check if the value list is empty now */
980 if (!KeyNode
->ValueList
.Count
)
982 /* Then clear key node data */
983 KeyNode
->MaxValueNameLen
= 0;
984 KeyNode
->MaxValueDataLen
= 0;
987 /* Change default Status to success */
988 Status
= STATUS_SUCCESS
;
991 /* Check if we had a value */
994 /* Release the child cell */
995 ASSERT(CellIndex
!= HCELL_NIL
);
996 HvReleaseCell(Hive
, CellIndex
);
999 /* Release the parent cell, if any */
1001 HvReleaseCell(Hive
, Key
->KeyCellOffset
);
1010 IN PCMHIVE HiveToConnect
,
1011 IN PUCHAR SecurityDescriptor
,
1012 IN ULONG SecurityDescriptorLength
,
1017 PREPARSE_POINT ReparsePoint
;
1020 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(*ReparsePoint
));
1025 * Use a dummy root key name:
1026 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
1027 * - On Vista+, this is "CMI-CreateHive{guid}"
1028 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
1029 * for more information.
1031 Status
= CmiInitializeHive(HiveToConnect
, L
"$$$PROTO.HIV");
1032 if (!NT_SUCCESS(Status
))
1034 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status
);
1040 * Add security to the root key.
1041 * NOTE: One can implement this using the lpSecurityAttributes
1042 * parameter of RegCreateKeyExW.
1044 Status
= CmiCreateSecurityKey(&HiveToConnect
->Hive
,
1045 HiveToConnect
->Hive
.BaseBlock
->RootCell
,
1046 SecurityDescriptor
, SecurityDescriptorLength
);
1047 if (!NT_SUCCESS(Status
))
1048 DPRINT1("Failed to add security for root key '%S'\n", Path
);
1050 /* Create the key */
1051 rc
= RegCreateKeyExW(RootKey
,
1055 REG_OPTION_VOLATILE
,
1060 if (rc
!= ERROR_SUCCESS
)
1066 ReparsePoint
->SourceHive
= NewKey
->RegistryHive
;
1067 ReparsePoint
->SourceKeyCellOffset
= NewKey
->KeyCellOffset
;
1068 NewKey
->RegistryHive
= HiveToConnect
;
1069 NewKey
->KeyCellOffset
= HiveToConnect
->Hive
.BaseBlock
->RootCell
;
1070 ReparsePoint
->DestinationHive
= NewKey
->RegistryHive
;
1071 ReparsePoint
->DestinationKeyCellOffset
= NewKey
->KeyCellOffset
;
1072 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
1079 IN PCWSTR LinkKeyPath OPTIONAL
,
1080 IN OUT PHKEY LinkKeyHandle OPTIONAL
,
1081 // IN PCWSTR TargetKeyPath OPTIONAL,
1082 IN HKEY TargetKeyHandle
)
1085 PMEMKEY LinkKey
, TargetKey
;
1086 PREPARSE_POINT ReparsePoint
;
1088 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(*ReparsePoint
));
1092 if (LinkKeyPath
&& !(LinkKeyHandle
&& *LinkKeyHandle
))
1094 /* Create the link key */
1095 rc
= RegCreateKeyExW(NULL
,
1099 REG_OPTION_VOLATILE
,
1104 if (rc
!= ERROR_SUCCESS
)
1110 else if (LinkKeyHandle
)
1112 /* Use the user-provided link key handle */
1113 LinkKey
= HKEY_TO_MEMKEY(*LinkKeyHandle
);
1117 *LinkKeyHandle
= MEMKEY_TO_HKEY(LinkKey
);
1119 TargetKey
= HKEY_TO_MEMKEY(TargetKeyHandle
);
1121 ReparsePoint
->SourceHive
= LinkKey
->RegistryHive
;
1122 ReparsePoint
->SourceKeyCellOffset
= LinkKey
->KeyCellOffset
;
1123 ReparsePoint
->DestinationHive
= TargetKey
->RegistryHive
;
1124 ReparsePoint
->DestinationKeyCellOffset
= TargetKey
->KeyCellOffset
;
1125 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
1131 RegInitializeRegistry(
1138 InitializeListHead(&CmiHiveListHead
);
1139 InitializeListHead(&CmiReparsePointsHead
);
1141 Status
= CmiInitializeHive(&RootHive
, L
"");
1142 if (!NT_SUCCESS(Status
))
1144 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status
);
1148 RootKey
= CreateInMemoryStructure(&RootHive
,
1149 RootHive
.Hive
.BaseBlock
->RootCell
);
1151 for (i
= 0; i
< _countof(RegistryHives
); ++i
)
1153 /* Skip this registry hive if it's not in the list */
1154 if (!strstr(HiveList
, RegistryHives
[i
].HiveName
))
1157 /* Create the registry key */
1158 ConnectRegistry(NULL
,
1159 RegistryHives
[i
].CmHive
,
1160 RegistryHives
[i
].SecurityDescriptor
,
1161 RegistryHives
[i
].SecurityDescriptorLength
,
1162 RegistryHives
[i
].HiveRegistryPath
);
1164 /* If we happen to deal with the special setup registry hive, stop there */
1165 // if (strcmp(RegistryHives[i].HiveName, "SETUPREG") == 0)
1170 /* Create the 'ControlSet001' key */
1172 L
"Registry\\Machine\\SYSTEM\\ControlSet001",
1175 /* Create the 'CurrentControlSet' key as a symlink to 'ControlSet001' */
1176 CreateSymLink(L
"Registry\\Machine\\SYSTEM\\CurrentControlSet",
1177 NULL
, ControlSetKey
);
1179 RegCloseKey(ControlSetKey
);
1182 /* Link SECURITY to SAM */
1183 CmpLinkKeyToHive(L
"\\Registry\\Machine\\Security\\SAM", L
"\\Registry\\Machine\\SAM\\SAM");
1184 /* Link S-1-5-18 to .Default */
1185 CmpLinkKeyToHive(L
"\\Registry\\User\\S-1-5-18", L
"\\Registry\\User\\.Default");
1190 RegShutdownRegistry(VOID
)
1193 PREPARSE_POINT ReparsePoint
;
1195 /* Clean up the reparse points list */
1196 while (!IsListEmpty(&CmiReparsePointsHead
))
1198 Entry
= RemoveHeadList(&CmiReparsePointsHead
);
1199 ReparsePoint
= CONTAINING_RECORD(Entry
, REPARSE_POINT
, ListEntry
);
1203 /* FIXME: clean up the complete hive */