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 /* DATA *********************************************************************/
35 typedef struct _REPARSE_POINT
39 HCELL_INDEX SourceKeyCellOffset
;
40 PCMHIVE DestinationHive
;
41 HCELL_INDEX DestinationKeyCellOffset
;
42 } REPARSE_POINT
, *PREPARSE_POINT
;
44 typedef struct _MEMKEY
46 /* Information on hard disk structure */
47 HCELL_INDEX KeyCellOffset
;
51 #define HKEY_TO_MEMKEY(hKey) ((PMEMKEY)(hKey))
52 #define MEMKEY_TO_HKEY(memKey) ((HKEY)(memKey))
54 static CMHIVE RootHive
;
55 static PMEMKEY RootKey
;
57 static CMHIVE SystemHive
; /* \Registry\Machine\SYSTEM */
58 static CMHIVE SoftwareHive
; /* \Registry\Machine\SOFTWARE */
59 static CMHIVE DefaultHive
; /* \Registry\User\.DEFAULT */
60 static CMHIVE SamHive
; /* \Registry\Machine\SAM */
61 static CMHIVE SecurityHive
; /* \Registry\Machine\SECURITY */
62 static CMHIVE BcdHive
; /* \Registry\Machine\BCD00000000 */
65 // TODO: Write these values in a more human-readable form.
66 // See http://amnesia.gtisc.gatech.edu/~moyix/suzibandit.ltd.uk/MSc/Registry%20Structure%20-%20Appendices%20V4.pdf
67 // Appendix 12 "The Registry NT Security Descriptor" for more information.
69 // Those SECURITY_DESCRIPTORs were obtained by dumping the security block "sk"
70 // of registry hives created by setting their permissions to be the same as
71 // the ones of the BCD, SOFTWARE, or SYSTEM, SAM and .DEFAULT system hives.
72 // A cross-check was subsequently done with the system hives to verify that
73 // the security descriptors were the same.
75 static UCHAR BcdSecurity
[] =
77 // SECURITY_DESCRIPTOR_RELATIVE
80 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
81 // SE_DACL_PROTECTED (0x1000) |
82 // SE_DACL_AUTO_INHERITED (0x0400) |
83 // SE_DACL_PRESENT (0x0004)
84 0x48, 0x00, 0x00, 0x00, // Owner
85 0x58, 0x00, 0x00, 0x00, // Group
86 0x00, 0x00, 0x00, 0x00, // Sacl (None)
87 0x14, 0x00, 0x00, 0x00, // Dacl
92 0x34, 0x00, // AclSize
93 0x02, 0x00, // AceCount
97 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
98 0x02, // AceFlags: CONTAINER_INHERIT_ACE
99 0x18, 0x00, // AceSize
100 0x19, 0x00, 0x06, 0x00, // ACCESS_MASK: "Write DAC" (0x00040000) |
101 // "Read Control" (0x00020000) |
102 // "Notify" (0x00000010) |
103 // "Enumerate Subkeys" (0x00000008) |
104 // "Query Value" (0x00000001)
105 // (SidStart: S-1-5-32-544 "Administrators")
106 0x01, 0x02, 0x00, 0x00,
107 0x00, 0x00, 0x00, 0x05,
108 0x20, 0x00, 0x00, 0x00,
109 0x20, 0x02, 0x00, 0x00,
112 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
113 0x02, // AceFlags: CONTAINER_INHERIT_ACE
114 0x14, 0x00, // AceSize
115 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
116 // (SidStart: S-1-5-18 "Local System")
117 0x01, 0x01, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x05,
119 0x12, 0x00, 0x00, 0x00,
121 // Owner SID (S-1-5-32-544 "Administrators")
122 0x01, 0x02, 0x00, 0x00,
123 0x00, 0x00, 0x00, 0x05,
124 0x20, 0x00, 0x00, 0x00,
125 0x20, 0x02, 0x00, 0x00,
127 // Group SID (S-1-5-21-domain-513 "Domain Users")
128 0x01, 0x05, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x05,
130 0x15, 0x00, 0x00, 0x00,
131 0xAC, 0xD0, 0x49, 0xCB,
132 0xE6, 0x52, 0x47, 0x9C,
133 0xE4, 0x31, 0xDB, 0x5C,
134 0x01, 0x02, 0x00, 0x00
137 static UCHAR SoftwareSecurity
[] =
139 // SECURITY_DESCRIPTOR_RELATIVE
142 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
143 // SE_DACL_PROTECTED (0x1000) |
144 // SE_DACL_AUTO_INHERITED (0x0400) |
145 // SE_DACL_PRESENT (0x0004)
146 0xA0, 0x00, 0x00, 0x00, // Owner
147 0xB0, 0x00, 0x00, 0x00, // Group
148 0x00, 0x00, 0x00, 0x00, // Sacl (None)
149 0x14, 0x00, 0x00, 0x00, // Dacl
154 0x8C, 0x00, // AclSize
155 0x06, 0x00, // AceCount
159 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
160 0x02, // AceFlags: CONTAINER_INHERIT_ACE
161 0x18, 0x00, // AceSize
162 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
163 // (SidStart: S-1-5-32-544 "Administrators")
164 0x01, 0x02, 0x00, 0x00,
165 0x00, 0x00, 0x00, 0x05,
166 0x20, 0x00, 0x00, 0x00,
167 0x20, 0x02, 0x00, 0x00,
170 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
171 0x0A, // AceFlags: INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE
172 0x14, 0x00, // AceSize
173 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
174 // (SidStart: S-1-3-0 "Creator Owner")
175 0x01, 0x01, 0x00, 0x00,
176 0x00, 0x00, 0x00, 0x03,
177 0x00, 0x00, 0x00, 0x00,
180 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
181 0x02, // AceFlags: CONTAINER_INHERIT_ACE
182 0x14, 0x00, // AceSize
183 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
184 // (SidStart: S-1-5-18 "Local System")
185 0x01, 0x01, 0x00, 0x00,
186 0x00, 0x00, 0x00, 0x05,
187 0x12, 0x00, 0x00, 0x00,
190 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
191 0x02, // AceFlags: CONTAINER_INHERIT_ACE
192 0x14, 0x00, // AceSize
193 0x1F, 0x00, 0x03, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
194 // "Delete" (0x00010000) |
195 // "Notify" (0x00000010) |
196 // "Enumerate Subkeys" (0x00000008) |
197 // "Create Subkey" (0x00000004) |
198 // "Set Value" (0x00000002) |
199 // "Query Value" (0x00000001)
200 // (SidStart: S-1-5-13 "Terminal Server Users")
201 0x01, 0x01, 0x00, 0x00,
202 0x00, 0x00, 0x00, 0x05,
203 0x0D, 0x00, 0x00, 0x00,
206 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
207 0x02, // AceFlags: CONTAINER_INHERIT_ACE
208 0x18, 0x00, // AceSize
209 0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
210 // "Notify" (0x00000010) |
211 // "Enumerate Subkeys" (0x00000008) |
212 // "Query Value" (0x00000001)
213 // (SidStart: S-1-5-32-545 "Users")
214 0x01, 0x02, 0x00, 0x00,
215 0x00, 0x00, 0x00, 0x05,
216 0x20, 0x00, 0x00, 0x00,
217 0x21, 0x02, 0x00, 0x00,
220 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
221 0x02, // AceFlags: CONTAINER_INHERIT_ACE
222 0x18, 0x00, // AceSize
223 0x1F, 0x00, 0x03, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
224 // "Delete" (0x00010000) |
225 // "Notify" (0x00000010) |
226 // "Enumerate Subkeys" (0x00000008) |
227 // "Create Subkey" (0x00000004) |
228 // "Set Value" (0x00000002) |
229 // "Query Value" (0x00000001)
230 // (SidStart: S-1-5-32-547 "Power Users")
231 0x01, 0x02, 0x00, 0x00,
232 0x00, 0x00, 0x00, 0x05,
233 0x20, 0x00, 0x00, 0x00,
234 0x23, 0x02, 0x00, 0x00,
236 // Owner SID (S-1-5-32-544 "Administrators")
237 0x01, 0x02, 0x00, 0x00,
238 0x00, 0x00, 0x00, 0x05,
239 0x20, 0x00, 0x00, 0x00,
240 0x20, 0x02, 0x00, 0x00,
242 // Group SID (S-1-5-21-domain-513 "Domain Users")
243 0x01, 0x05, 0x00, 0x00,
244 0x00, 0x00, 0x00, 0x05,
245 0x15, 0x00, 0x00, 0x00,
246 0xAC, 0xD0, 0x49, 0xCB,
247 0xE6, 0x52, 0x47, 0x9C,
248 0xE4, 0x31, 0xDB, 0x5C,
249 0x01, 0x02, 0x00, 0x00
252 // Same security for SYSTEM, SAM and .DEFAULT
253 static UCHAR SystemSecurity
[] =
255 // SECURITY_DESCRIPTOR_RELATIVE
258 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
259 // SE_DACL_PROTECTED (0x1000) |
260 // SE_DACL_AUTO_INHERITED (0x0400) |
261 // SE_DACL_PRESENT (0x0004)
262 0x8C, 0x00, 0x00, 0x00, // Owner
263 0x9C, 0x00, 0x00, 0x00, // Group
264 0x00, 0x00, 0x00, 0x00, // Sacl (None)
265 0x14, 0x00, 0x00, 0x00, // Dacl
270 0x78, 0x00, // AclSize
271 0x05, 0x00, // AceCount
275 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
276 0x02, // AceFlags: CONTAINER_INHERIT_ACE
277 0x18, 0x00, // AceSize
278 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
279 // (SidStart: S-1-5-32-544 "Administrators")
280 0x01, 0x02, 0x00, 0x00,
281 0x00, 0x00, 0x00, 0x05,
282 0x20, 0x00, 0x00, 0x00,
283 0x20, 0x02, 0x00, 0x00,
286 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
287 0x0A, // AceFlags: INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE
288 0x14, 0x00, // AceSize
289 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
290 // (SidStart: S-1-3-0 "Creator Owner")
291 0x01, 0x01, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x03,
293 0x00, 0x00, 0x00, 0x00,
296 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
297 0x02, // AceFlags: CONTAINER_INHERIT_ACE
298 0x14, 0x00, // AceSize
299 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
300 // (SidStart: S-1-5-18 "Local System")
301 0x01, 0x01, 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x05,
303 0x12, 0x00, 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-545 "Users")
314 0x01, 0x02, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x05,
316 0x20, 0x00, 0x00, 0x00,
317 0x21, 0x02, 0x00, 0x00,
320 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
321 0x02, // AceFlags: CONTAINER_INHERIT_ACE
322 0x18, 0x00, // AceSize
323 0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
324 // "Notify" (0x00000010) |
325 // "Enumerate Subkeys" (0x00000008) |
326 // "Query Value" (0x00000001)
327 // (SidStart: S-1-5-32-547 "Power Users")
328 0x01, 0x02, 0x00, 0x00,
329 0x00, 0x00, 0x00, 0x05,
330 0x20, 0x00, 0x00, 0x00,
331 0x23, 0x02, 0x00, 0x00,
333 // Owner SID (S-1-5-32-544 "Administrators")
334 0x01, 0x02, 0x00, 0x00,
335 0x00, 0x00, 0x00, 0x05,
336 0x20, 0x00, 0x00, 0x00,
337 0x20, 0x02, 0x00, 0x00,
339 // Group SID (S-1-5-21-domain-513 "Domain Users")
340 0x01, 0x05, 0x00, 0x00,
341 0x00, 0x00, 0x00, 0x05,
342 0x15, 0x00, 0x00, 0x00,
343 0xAC, 0xD0, 0x49, 0xCB,
344 0xE6, 0x52, 0x47, 0x9C,
345 0xE4, 0x31, 0xDB, 0x5C,
346 0x01, 0x02, 0x00, 0x00
349 /* GLOBALS ******************************************************************/
351 HIVE_LIST_ENTRY RegistryHives
[/*MAX_NUMBER_OF_REGISTRY_HIVES*/] =
353 /* Special Setup system registry hive */
354 // WARNING: Please *keep* it in first position!
355 { "SETUPREG", L
"Registry\\Machine\\SYSTEM" , &SystemHive
, SystemSecurity
, sizeof(SystemSecurity
) },
357 /* Regular registry hives */
358 { "SYSTEM" , L
"Registry\\Machine\\SYSTEM" , &SystemHive
, SystemSecurity
, sizeof(SystemSecurity
) },
359 { "SOFTWARE", L
"Registry\\Machine\\SOFTWARE" , &SoftwareHive
, SoftwareSecurity
, sizeof(SoftwareSecurity
) },
360 { "DEFAULT" , L
"Registry\\User\\.DEFAULT" , &DefaultHive
, SystemSecurity
, sizeof(SystemSecurity
) },
361 { "SAM" , L
"Registry\\Machine\\SAM" , &SamHive
, SystemSecurity
, sizeof(SystemSecurity
) },
362 { "SECURITY", L
"Registry\\Machine\\SECURITY" , &SecurityHive
, NULL
, 0 },
363 { "BCD" , L
"Registry\\Machine\\BCD00000000", &BcdHive
, BcdSecurity
, sizeof(BcdSecurity
) },
365 C_ASSERT(_countof(RegistryHives
) == MAX_NUMBER_OF_REGISTRY_HIVES
);
367 /* FUNCTIONS ****************************************************************/
370 CreateInMemoryStructure(
371 IN PCMHIVE RegistryHive
,
372 IN HCELL_INDEX KeyCellOffset
)
376 Key
= (PMEMKEY
)malloc(sizeof(MEMKEY
));
380 Key
->RegistryHive
= RegistryHive
;
381 Key
->KeyCellOffset
= KeyCellOffset
;
385 LIST_ENTRY CmiHiveListHead
;
386 LIST_ENTRY CmiReparsePointsHead
;
392 IN BOOL AllowCreation
,
399 UNICODE_STRING KeyString
;
400 PREPARSE_POINT CurrentReparsePoint
;
402 PCMHIVE ParentRegistryHive
;
403 HCELL_INDEX ParentCellOffset
;
404 PCM_KEY_NODE ParentKeyCell
;
406 PCM_KEY_NODE SubKeyCell
;
407 HCELL_INDEX BlockOffset
;
409 DPRINT("RegpCreateOrOpenKey('%S')\n", KeyName
);
411 if (*KeyName
== OBJ_NAME_PATH_SEPARATOR
)
414 ParentRegistryHive
= RootKey
->RegistryHive
;
415 ParentCellOffset
= RootKey
->KeyCellOffset
;
417 else if (hParentKey
== NULL
)
419 ParentRegistryHive
= RootKey
->RegistryHive
;
420 ParentCellOffset
= RootKey
->KeyCellOffset
;
424 ParentRegistryHive
= HKEY_TO_MEMKEY(hParentKey
)->RegistryHive
;
425 ParentCellOffset
= HKEY_TO_MEMKEY(hParentKey
)->KeyCellOffset
;
428 LocalKeyName
= (PWSTR
)KeyName
;
431 End
= (PWSTR
)strchrW(LocalKeyName
, OBJ_NAME_PATH_SEPARATOR
);
434 KeyString
.Buffer
= LocalKeyName
;
435 KeyString
.Length
= KeyString
.MaximumLength
=
436 (USHORT
)((ULONG_PTR
)End
- (ULONG_PTR
)LocalKeyName
);
440 RtlInitUnicodeString(&KeyString
, LocalKeyName
);
441 if (KeyString
.Length
== 0)
443 /* Trailing path separator: we're done */
448 ParentKeyCell
= (PCM_KEY_NODE
)HvGetCell(&ParentRegistryHive
->Hive
, ParentCellOffset
);
450 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
452 VERIFY_KEY_CELL(ParentKeyCell
);
454 BlockOffset
= CmpFindSubKeyByName(&ParentRegistryHive
->Hive
, ParentKeyCell
, &KeyString
);
455 if (BlockOffset
!= HCELL_NIL
)
457 Status
= STATUS_SUCCESS
;
459 /* Search for a possible reparse point */
460 Ptr
= CmiReparsePointsHead
.Flink
;
461 while (Ptr
!= &CmiReparsePointsHead
)
463 CurrentReparsePoint
= CONTAINING_RECORD(Ptr
, REPARSE_POINT
, ListEntry
);
464 if (CurrentReparsePoint
->SourceHive
== ParentRegistryHive
&&
465 CurrentReparsePoint
->SourceKeyCellOffset
== BlockOffset
)
467 ParentRegistryHive
= CurrentReparsePoint
->DestinationHive
;
468 BlockOffset
= CurrentReparsePoint
->DestinationKeyCellOffset
;
474 else if (AllowCreation
) // && (BlockOffset == HCELL_NIL)
476 Status
= CmiAddSubKey(ParentRegistryHive
,
482 else // if (BlockOffset == HCELL_NIL)
484 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
487 HvReleaseCell(&ParentRegistryHive
->Hive
, ParentCellOffset
);
489 if (!NT_SUCCESS(Status
))
491 DPRINT("RegpCreateOrOpenKey('%S'): Could not create or open subkey '%.*S', Status 0x%08x\n",
492 KeyName
, (int)(KeyString
.Length
/ sizeof(WCHAR
)), KeyString
.Buffer
, Status
);
493 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
496 ParentCellOffset
= BlockOffset
;
498 LocalKeyName
= End
+ 1;
503 CurrentKey
= CreateInMemoryStructure(ParentRegistryHive
, ParentCellOffset
);
505 return ERROR_NOT_ENOUGH_MEMORY
; // STATUS_NO_MEMORY;
507 *Key
= MEMKEY_TO_HKEY(CurrentKey
);
509 return ERROR_SUCCESS
;
516 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
518 /* Free the object */
521 return ERROR_SUCCESS
;
530 return RegpCreateOrOpenKey(hKey
, lpSubKey
, TRUE
, FALSE
, phkResult
);
538 IN LPWSTR lpClass OPTIONAL
,
540 IN REGSAM samDesired
,
541 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL
,
543 OUT LPDWORD lpdwDisposition OPTIONAL
)
545 return RegpCreateOrOpenKey(hKey
,
548 (dwOptions
& REG_OPTION_VOLATILE
) != 0,
560 PMEMKEY Key
; // ParentKey
562 PCM_KEY_NODE KeyNode
; // ParentNode
564 HCELL_INDEX ParentCell
;
568 rc
= RegOpenKeyW(hKey
, lpSubKey
, &hTargetKey
);
569 if (rc
!= ERROR_SUCCESS
)
577 /* Don't allow deleting the root */
578 if (hTargetKey
== RootKey
)
581 rc
= ERROR_ACCESS_DENIED
; // STATUS_CANNOT_DELETE;
585 /* Get the hive and node */
586 Key
= HKEY_TO_MEMKEY(hTargetKey
);
587 Hive
= &Key
->RegistryHive
->Hive
;
589 /* Get the key node */
590 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
593 rc
= ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
597 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
599 /* Check if we don't have any children */
600 if (!(KeyNode
->SubKeyCounts
[Stable
] + KeyNode
->SubKeyCounts
[Volatile
]) &&
601 !(KeyNode
->Flags
& KEY_NO_DELETE
))
603 /* Get the parent and free the cell */
604 ParentCell
= KeyNode
->Parent
;
605 Status
= CmpFreeKeyByCell(Hive
, Key
->KeyCellOffset
, TRUE
);
606 if (NT_SUCCESS(Status
))
608 /* Get the parent node */
609 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentCell
);
612 /* Make sure we're dirty */
613 ASSERT(HvIsCellDirty(Hive
, ParentCell
));
615 /* Update the write time */
616 KeQuerySystemTime(&Parent
->LastWriteTime
);
618 /* Release the cell */
619 HvReleaseCell(Hive
, ParentCell
);
625 rc
= ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
631 rc
= ERROR_ACCESS_DENIED
; // STATUS_CANNOT_DELETE;
634 /* Release the cell */
635 HvReleaseCell(Hive
, Key
->KeyCellOffset
);
639 RegCloseKey(hTargetKey
);
650 return RegpCreateOrOpenKey(hKey
, lpSubKey
, FALSE
, FALSE
, phkResult
);
656 IN LPCWSTR lpValueName OPTIONAL
,
659 IN
const UCHAR
* lpData
,
662 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
664 PCM_KEY_NODE KeyNode
; // ParentNode
665 PCM_KEY_VALUE ValueCell
;
667 HCELL_INDEX CellIndex
;
668 UNICODE_STRING ValueNameString
;
674 if (dwType
== REG_LINK
)
678 /* Special handling of registry links */
679 if (cbData
!= sizeof(PVOID
))
680 return ERROR_INVALID_PARAMETER
; // STATUS_INVALID_PARAMETER;
682 DestKey
= HKEY_TO_MEMKEY(*(PHKEY
)lpData
);
684 // FIXME: Add additional checks for the validity of DestKey
686 /* Create the link in registry hive (if applicable) */
687 if (Key
->RegistryHive
!= DestKey
->RegistryHive
)
688 return ERROR_SUCCESS
;
690 DPRINT1("Save link to registry\n");
691 return ERROR_INVALID_FUNCTION
; // STATUS_NOT_IMPLEMENTED;
694 if ((cbData
& ~CM_KEY_VALUE_SPECIAL_SIZE
) != cbData
)
695 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
697 Hive
= &Key
->RegistryHive
->Hive
;
699 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
701 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
703 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
705 /* Mark the parent as dirty since we are going to create a new value in it */
706 HvMarkCellDirty(Hive
, Key
->KeyCellOffset
, FALSE
);
708 /* Initialize value name string */
709 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
710 if (!CmpFindNameInList(Hive
,
717 ASSERT(CellIndex
== HCELL_NIL
);
719 Status
= STATUS_INSUFFICIENT_RESOURCES
;
721 if (CellIndex
== HCELL_NIL
)
723 /* The value doesn't exist, create a new one */
724 Status
= CmiAddValueKey(Key
->RegistryHive
,
733 /* The value already exists, use it. Get the value cell. */
734 ValueCell
= HvGetCell(&Key
->RegistryHive
->Hive
, CellIndex
);
735 ASSERT(ValueCell
!= NULL
);
736 Status
= STATUS_SUCCESS
;
739 // /**/HvReleaseCell(Hive, CellIndex);/**/
741 if (!NT_SUCCESS(Status
))
742 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
744 /* Get size of the allocated cell (if any) */
745 if (!(ValueCell
->DataLength
& CM_KEY_VALUE_SPECIAL_SIZE
) &&
746 (ValueCell
->DataLength
& ~CM_KEY_VALUE_SPECIAL_SIZE
) != 0)
748 DataCell
= HvGetCell(Hive
, ValueCell
->Data
);
750 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
752 DataCellSize
= (ULONG
)(-HvGetCellSize(Hive
, DataCell
));
760 if (cbData
<= sizeof(HCELL_INDEX
))
762 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
763 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
765 HvFreeCell(Hive
, ValueCell
->Data
);
767 RtlCopyMemory(&ValueCell
->Data
, lpData
, cbData
);
768 ValueCell
->DataLength
= (cbData
| CM_KEY_VALUE_SPECIAL_SIZE
);
769 ValueCell
->Type
= dwType
;
773 if (cbData
> DataCellSize
)
775 /* New data size is larger than the current, destroy current
776 * data block and allocate a new one. */
777 HCELL_INDEX NewOffset
;
779 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
781 NewOffset
= HvAllocateCell(Hive
, cbData
, Stable
, HCELL_NIL
);
782 if (NewOffset
== HCELL_NIL
)
784 DPRINT("HvAllocateCell() has failed!\n");
785 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
789 HvFreeCell(Hive
, ValueCell
->Data
);
791 ValueCell
->Data
= NewOffset
;
792 DataCell
= (PVOID
)HvGetCell(Hive
, NewOffset
);
795 /* Copy new contents to cell */
796 RtlCopyMemory(DataCell
, lpData
, cbData
);
797 ValueCell
->DataLength
= (cbData
& ~CM_KEY_VALUE_SPECIAL_SIZE
);
798 ValueCell
->Type
= dwType
;
799 HvMarkCellDirty(Hive
, ValueCell
->Data
, FALSE
);
802 HvMarkCellDirty(Hive
, CellIndex
, FALSE
);
804 /* Check if the maximum value name length changed, update it if so */
805 if (KeyNode
->MaxValueNameLen
< ValueNameString
.Length
)
806 KeyNode
->MaxValueNameLen
= ValueNameString
.Length
;
808 /* Check if the maximum data length changed, update it if so */
809 if (KeyNode
->MaxValueDataLen
< cbData
)
810 KeyNode
->MaxValueDataLen
= cbData
;
812 /* Save the write time */
813 KeQuerySystemTime(&KeyNode
->LastWriteTime
);
815 return ERROR_SUCCESS
;
819 // Synced with freeldr/ntldr/registry.c
824 IN PCM_KEY_VALUE ValueCell
,
825 OUT PULONG Type OPTIONAL
,
826 OUT PUCHAR Data OPTIONAL
,
827 IN OUT PULONG DataSize OPTIONAL
)
832 /* Does the caller want the type? */
834 *Type
= ValueCell
->Type
;
836 /* Does the caller provide DataSize? */
837 if (DataSize
!= NULL
)
839 // NOTE: CmpValueToData doesn't support big data (the function will
840 // bugcheck if so), FreeLdr is not supposed to read such data.
841 // If big data is needed, use instead CmpGetValueData.
842 // CmpGetValueData(Hive, ValueCell, DataSize, &DataCell, ...);
843 DataCell
= CmpValueToData(Hive
, ValueCell
, &DataLength
);
845 /* Does the caller want the data? */
846 if ((Data
!= NULL
) && (*DataSize
!= 0))
850 min(*DataSize
, DataLength
));
853 /* Return the actual data length */
854 *DataSize
= DataLength
;
858 // Similar to RegQueryValue in freeldr/ntldr/registry.c
862 IN LPCWSTR lpValueName
,
863 IN PULONG lpReserved
,
864 OUT PULONG lpType OPTIONAL
,
865 OUT PUCHAR lpData OPTIONAL
,
866 IN OUT PULONG lpcbData OPTIONAL
)
868 PMEMKEY ParentKey
= HKEY_TO_MEMKEY(hKey
);
869 PHHIVE Hive
= &ParentKey
->RegistryHive
->Hive
;
870 PCM_KEY_NODE KeyNode
;
871 PCM_KEY_VALUE ValueCell
;
872 HCELL_INDEX CellIndex
;
873 UNICODE_STRING ValueNameString
;
875 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentKey
->KeyCellOffset
);
877 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
879 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
881 /* Initialize value name string */
882 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
883 CellIndex
= CmpFindValueByName(Hive
, KeyNode
, &ValueNameString
);
884 if (CellIndex
== HCELL_NIL
)
885 return ERROR_FILE_NOT_FOUND
; // STATUS_OBJECT_NAME_NOT_FOUND;
887 /* Get the value cell */
888 ValueCell
= HvGetCell(Hive
, CellIndex
);
889 ASSERT(ValueCell
!= NULL
);
891 RepGetValueData(Hive
, ValueCell
, lpType
, lpData
, lpcbData
);
893 HvReleaseCell(Hive
, CellIndex
);
895 return ERROR_SUCCESS
;
901 IN LPCWSTR lpValueName OPTIONAL
)
905 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
906 PHHIVE Hive
= &Key
->RegistryHive
->Hive
;
907 PCM_KEY_NODE KeyNode
; // ParentNode
908 PCM_KEY_VALUE ValueCell
;
909 HCELL_INDEX CellIndex
;
911 UNICODE_STRING ValueNameString
;
913 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
915 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
917 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
919 /* Initialize value name string */
920 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
921 if (!CmpFindNameInList(Hive
,
928 ASSERT(CellIndex
== HCELL_NIL
);
930 if (CellIndex
== HCELL_NIL
)
932 rc
= ERROR_FILE_NOT_FOUND
; // STATUS_OBJECT_NAME_NOT_FOUND;
936 /* We found the value, mark all relevant cells dirty */
937 HvMarkCellDirty(Hive
, Key
->KeyCellOffset
, FALSE
);
938 HvMarkCellDirty(Hive
, KeyNode
->ValueList
.List
, FALSE
);
939 HvMarkCellDirty(Hive
, CellIndex
, FALSE
);
941 /* Get the key value */
942 ValueCell
= (PCM_KEY_VALUE
)HvGetCell(Hive
, CellIndex
);
945 /* Mark it and all related data as dirty */
946 if (!CmpMarkValueDataDirty(Hive
, ValueCell
))
948 /* Not enough log space, fail */
949 rc
= ERROR_NO_LOG_SPACE
; // STATUS_NO_LOG_SPACE;
954 ASSERT(HvIsCellDirty(Hive
, KeyNode
->ValueList
.List
));
955 ASSERT(HvIsCellDirty(Hive
, CellIndex
));
957 /* Remove the value from the child list */
958 Status
= CmpRemoveValueFromList(Hive
, ChildIndex
, &KeyNode
->ValueList
);
959 if (!NT_SUCCESS(Status
))
961 /* Set known error */
962 rc
= ERROR_NO_SYSTEM_RESOURCES
; // STATUS_INSUFFICIENT_RESOURCES;
966 /* Remove the value and its data itself */
967 if (!CmpFreeValue(Hive
, CellIndex
))
969 /* Failed to free the value, fail */
970 rc
= ERROR_NO_SYSTEM_RESOURCES
; // STATUS_INSUFFICIENT_RESOURCES;
974 /* Set the last write time */
975 KeQuerySystemTime(&KeyNode
->LastWriteTime
);
978 ASSERT(HvIsCellDirty(Hive
, Key
->KeyCellOffset
));
980 /* Check if the value list is empty now */
981 if (!KeyNode
->ValueList
.Count
)
983 /* Then clear key node data */
984 KeyNode
->MaxValueNameLen
= 0;
985 KeyNode
->MaxValueDataLen
= 0;
988 /* Change default Status to success */
992 /* Check if we had a value */
995 /* Release the child cell */
996 ASSERT(CellIndex
!= HCELL_NIL
);
997 HvReleaseCell(Hive
, CellIndex
);
1000 /* Release the parent cell, if any */
1002 HvReleaseCell(Hive
, Key
->KeyCellOffset
);
1011 IN PCMHIVE HiveToConnect
,
1012 IN PUCHAR SecurityDescriptor
,
1013 IN ULONG SecurityDescriptorLength
,
1018 PREPARSE_POINT ReparsePoint
;
1021 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(*ReparsePoint
));
1026 * Use a dummy root key name:
1027 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
1028 * - On Vista+, this is "CMI-CreateHive{guid}"
1029 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
1030 * for more information.
1032 Status
= CmiInitializeHive(HiveToConnect
, L
"$$$PROTO.HIV");
1033 if (!NT_SUCCESS(Status
))
1035 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status
);
1041 * Add security to the root key.
1042 * NOTE: One can implement this using the lpSecurityAttributes
1043 * parameter of RegCreateKeyExW.
1045 Status
= CmiCreateSecurityKey(&HiveToConnect
->Hive
,
1046 HiveToConnect
->Hive
.BaseBlock
->RootCell
,
1047 SecurityDescriptor
, SecurityDescriptorLength
);
1048 if (!NT_SUCCESS(Status
))
1049 DPRINT1("Failed to add security for root key '%S'\n", Path
);
1051 /* Create the key */
1052 rc
= RegCreateKeyExW(RootKey
,
1056 REG_OPTION_VOLATILE
,
1061 if (rc
!= ERROR_SUCCESS
)
1067 ReparsePoint
->SourceHive
= NewKey
->RegistryHive
;
1068 ReparsePoint
->SourceKeyCellOffset
= NewKey
->KeyCellOffset
;
1069 NewKey
->RegistryHive
= HiveToConnect
;
1070 NewKey
->KeyCellOffset
= HiveToConnect
->Hive
.BaseBlock
->RootCell
;
1071 ReparsePoint
->DestinationHive
= NewKey
->RegistryHive
;
1072 ReparsePoint
->DestinationKeyCellOffset
= NewKey
->KeyCellOffset
;
1073 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
1080 IN PCWSTR LinkKeyPath OPTIONAL
,
1081 IN OUT PHKEY LinkKeyHandle OPTIONAL
,
1082 // IN PCWSTR TargetKeyPath OPTIONAL,
1083 IN HKEY TargetKeyHandle
)
1086 PMEMKEY LinkKey
, TargetKey
;
1087 PREPARSE_POINT ReparsePoint
;
1089 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(*ReparsePoint
));
1093 if (LinkKeyPath
&& !(LinkKeyHandle
&& *LinkKeyHandle
))
1095 /* Create the link key */
1096 rc
= RegCreateKeyExW(NULL
,
1100 REG_OPTION_VOLATILE
,
1105 if (rc
!= ERROR_SUCCESS
)
1111 else if (LinkKeyHandle
)
1113 /* Use the user-provided link key handle */
1114 LinkKey
= HKEY_TO_MEMKEY(*LinkKeyHandle
);
1118 *LinkKeyHandle
= MEMKEY_TO_HKEY(LinkKey
);
1120 TargetKey
= HKEY_TO_MEMKEY(TargetKeyHandle
);
1122 ReparsePoint
->SourceHive
= LinkKey
->RegistryHive
;
1123 ReparsePoint
->SourceKeyCellOffset
= LinkKey
->KeyCellOffset
;
1124 ReparsePoint
->DestinationHive
= TargetKey
->RegistryHive
;
1125 ReparsePoint
->DestinationKeyCellOffset
= TargetKey
->KeyCellOffset
;
1126 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
1132 RegInitializeRegistry(
1139 InitializeListHead(&CmiHiveListHead
);
1140 InitializeListHead(&CmiReparsePointsHead
);
1142 Status
= CmiInitializeHive(&RootHive
, L
"");
1143 if (!NT_SUCCESS(Status
))
1145 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status
);
1149 RootKey
= CreateInMemoryStructure(&RootHive
,
1150 RootHive
.Hive
.BaseBlock
->RootCell
);
1152 for (i
= 0; i
< _countof(RegistryHives
); ++i
)
1154 /* Skip this registry hive if it's not in the list */
1155 if (!strstr(HiveList
, RegistryHives
[i
].HiveName
))
1158 /* Create the registry key */
1159 ConnectRegistry(NULL
,
1160 RegistryHives
[i
].CmHive
,
1161 RegistryHives
[i
].SecurityDescriptor
,
1162 RegistryHives
[i
].SecurityDescriptorLength
,
1163 RegistryHives
[i
].HiveRegistryPath
);
1165 /* If we happen to deal with the special setup registry hive, stop there */
1166 // if (strcmp(RegistryHives[i].HiveName, "SETUPREG") == 0)
1171 /* Create the 'ControlSet001' key */
1173 L
"Registry\\Machine\\SYSTEM\\ControlSet001",
1176 /* Create the 'CurrentControlSet' key as a symlink to 'ControlSet001' */
1177 CreateSymLink(L
"Registry\\Machine\\SYSTEM\\CurrentControlSet",
1178 NULL
, ControlSetKey
);
1180 RegCloseKey(ControlSetKey
);
1183 /* Link SECURITY to SAM */
1184 CmpLinkKeyToHive(L
"\\Registry\\Machine\\Security\\SAM", L
"\\Registry\\Machine\\SAM\\SAM");
1185 /* Link S-1-5-18 to .Default */
1186 CmpLinkKeyToHive(L
"\\Registry\\User\\S-1-5-18", L
"\\Registry\\User\\.Default");
1191 RegShutdownRegistry(VOID
)
1194 PREPARSE_POINT ReparsePoint
;
1196 /* Clean up the reparse points list */
1197 while (!IsListEmpty(&CmiReparsePointsHead
))
1199 Entry
= RemoveHeadList(&CmiReparsePointsHead
);
1200 ReparsePoint
= CONTAINING_RECORD(Entry
, REPARSE_POINT
, ListEntry
);
1204 /* FIXME: clean up the complete hive */