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 '%wZ', Status 0x%08x\n", KeyName
, &KeyString
, Status
);
492 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
495 ParentCellOffset
= BlockOffset
;
497 LocalKeyName
= End
+ 1;
502 CurrentKey
= CreateInMemoryStructure(ParentRegistryHive
, ParentCellOffset
);
504 return ERROR_NOT_ENOUGH_MEMORY
; // STATUS_NO_MEMORY;
506 *Key
= MEMKEY_TO_HKEY(CurrentKey
);
508 return ERROR_SUCCESS
;
515 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
517 /* Free the object */
520 return ERROR_SUCCESS
;
529 return RegpCreateOrOpenKey(hKey
, lpSubKey
, TRUE
, FALSE
, phkResult
);
537 IN LPWSTR lpClass OPTIONAL
,
539 IN REGSAM samDesired
,
540 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL
,
542 OUT LPDWORD lpdwDisposition OPTIONAL
)
544 return RegpCreateOrOpenKey(hKey
,
547 (dwOptions
& REG_OPTION_VOLATILE
) != 0,
559 PMEMKEY Key
; // ParentKey
561 PCM_KEY_NODE KeyNode
; // ParentNode
563 HCELL_INDEX ParentCell
;
567 rc
= RegOpenKeyW(hKey
, lpSubKey
, &hTargetKey
);
568 if (rc
!= ERROR_SUCCESS
)
576 /* Don't allow deleting the root */
577 if (hTargetKey
== RootKey
)
580 rc
= ERROR_ACCESS_DENIED
; // STATUS_CANNOT_DELETE;
584 /* Get the hive and node */
585 Key
= HKEY_TO_MEMKEY(hTargetKey
);
586 Hive
= &Key
->RegistryHive
->Hive
;
588 /* Get the key node */
589 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
592 rc
= ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
596 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
598 /* Check if we don't have any children */
599 if (!(KeyNode
->SubKeyCounts
[Stable
] + KeyNode
->SubKeyCounts
[Volatile
]) &&
600 !(KeyNode
->Flags
& KEY_NO_DELETE
))
602 /* Get the parent and free the cell */
603 ParentCell
= KeyNode
->Parent
;
604 Status
= CmpFreeKeyByCell(Hive
, Key
->KeyCellOffset
, TRUE
);
605 if (NT_SUCCESS(Status
))
607 /* Get the parent node */
608 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentCell
);
611 /* Make sure we're dirty */
612 ASSERT(HvIsCellDirty(Hive
, ParentCell
));
614 /* Update the write time */
615 KeQuerySystemTime(&Parent
->LastWriteTime
);
617 /* Release the cell */
618 HvReleaseCell(Hive
, ParentCell
);
624 rc
= ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
630 rc
= ERROR_ACCESS_DENIED
; // STATUS_CANNOT_DELETE;
633 /* Release the cell */
634 HvReleaseCell(Hive
, Key
->KeyCellOffset
);
638 RegCloseKey(hTargetKey
);
649 return RegpCreateOrOpenKey(hKey
, lpSubKey
, FALSE
, FALSE
, phkResult
);
655 IN LPCWSTR lpValueName OPTIONAL
,
658 IN
const UCHAR
* lpData
,
661 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
663 PCM_KEY_NODE KeyNode
; // ParentNode
664 PCM_KEY_VALUE ValueCell
;
666 HCELL_INDEX CellIndex
;
667 UNICODE_STRING ValueNameString
;
673 if (dwType
== REG_LINK
)
677 /* Special handling of registry links */
678 if (cbData
!= sizeof(PVOID
))
679 return ERROR_INVALID_PARAMETER
; // STATUS_INVALID_PARAMETER;
681 DestKey
= HKEY_TO_MEMKEY(*(PHKEY
)lpData
);
683 // FIXME: Add additional checks for the validity of DestKey
685 /* Create the link in registry hive (if applicable) */
686 if (Key
->RegistryHive
!= DestKey
->RegistryHive
)
687 return ERROR_SUCCESS
;
689 DPRINT1("Save link to registry\n");
690 return ERROR_INVALID_FUNCTION
; // STATUS_NOT_IMPLEMENTED;
693 if ((cbData
& ~CM_KEY_VALUE_SPECIAL_SIZE
) != cbData
)
694 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
696 Hive
= &Key
->RegistryHive
->Hive
;
698 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
700 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
702 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
704 /* Mark the parent as dirty since we are going to create a new value in it */
705 HvMarkCellDirty(Hive
, Key
->KeyCellOffset
, FALSE
);
707 /* Initialize value name string */
708 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
709 if (!CmpFindNameInList(Hive
,
716 ASSERT(CellIndex
== HCELL_NIL
);
718 Status
= STATUS_INSUFFICIENT_RESOURCES
;
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_GEN_FAILURE
; // STATUS_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_GEN_FAILURE
; // STATUS_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_GEN_FAILURE
; // STATUS_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_GEN_FAILURE
; // STATUS_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
; // STATUS_OBJECT_NAME_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
)
904 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
905 PHHIVE Hive
= &Key
->RegistryHive
->Hive
;
906 PCM_KEY_NODE KeyNode
; // ParentNode
907 PCM_KEY_VALUE ValueCell
;
908 HCELL_INDEX CellIndex
;
910 UNICODE_STRING ValueNameString
;
912 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
914 return ERROR_GEN_FAILURE
; // STATUS_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 rc
= 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 rc
= ERROR_NO_LOG_SPACE
; // 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 rc
= ERROR_NO_SYSTEM_RESOURCES
; // STATUS_INSUFFICIENT_RESOURCES;
965 /* Remove the value and its data itself */
966 if (!CmpFreeValue(Hive
, CellIndex
))
968 /* Failed to free the value, fail */
969 rc
= ERROR_NO_SYSTEM_RESOURCES
; // 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 */
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 */