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 HCELL_INDEX BlockOffset
;
408 DPRINT("RegpCreateOrOpenKey('%S')\n", KeyName
);
410 if (*KeyName
== OBJ_NAME_PATH_SEPARATOR
)
413 ParentRegistryHive
= RootKey
->RegistryHive
;
414 ParentCellOffset
= RootKey
->KeyCellOffset
;
416 else if (hParentKey
== NULL
)
418 ParentRegistryHive
= RootKey
->RegistryHive
;
419 ParentCellOffset
= RootKey
->KeyCellOffset
;
423 ParentRegistryHive
= HKEY_TO_MEMKEY(hParentKey
)->RegistryHive
;
424 ParentCellOffset
= HKEY_TO_MEMKEY(hParentKey
)->KeyCellOffset
;
427 LocalKeyName
= (PWSTR
)KeyName
;
430 End
= (PWSTR
)strchrW(LocalKeyName
, OBJ_NAME_PATH_SEPARATOR
);
433 KeyString
.Buffer
= LocalKeyName
;
434 KeyString
.Length
= KeyString
.MaximumLength
=
435 (USHORT
)((ULONG_PTR
)End
- (ULONG_PTR
)LocalKeyName
);
439 RtlInitUnicodeString(&KeyString
, LocalKeyName
);
440 if (KeyString
.Length
== 0)
442 /* Trailing path separator: we're done */
447 ParentKeyCell
= (PCM_KEY_NODE
)HvGetCell(&ParentRegistryHive
->Hive
, ParentCellOffset
);
449 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
451 VERIFY_KEY_CELL(ParentKeyCell
);
453 BlockOffset
= CmpFindSubKeyByName(&ParentRegistryHive
->Hive
, ParentKeyCell
, &KeyString
);
454 if (BlockOffset
!= HCELL_NIL
)
456 Status
= STATUS_SUCCESS
;
458 /* Search for a possible reparse point */
459 Ptr
= CmiReparsePointsHead
.Flink
;
460 while (Ptr
!= &CmiReparsePointsHead
)
462 CurrentReparsePoint
= CONTAINING_RECORD(Ptr
, REPARSE_POINT
, ListEntry
);
463 if (CurrentReparsePoint
->SourceHive
== ParentRegistryHive
&&
464 CurrentReparsePoint
->SourceKeyCellOffset
== BlockOffset
)
466 ParentRegistryHive
= CurrentReparsePoint
->DestinationHive
;
467 BlockOffset
= CurrentReparsePoint
->DestinationKeyCellOffset
;
473 else if (AllowCreation
) // && (BlockOffset == HCELL_NIL)
475 Status
= CmiAddSubKey(ParentRegistryHive
,
481 else // if (BlockOffset == HCELL_NIL)
483 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
486 HvReleaseCell(&ParentRegistryHive
->Hive
, ParentCellOffset
);
488 if (!NT_SUCCESS(Status
))
490 DPRINT("RegpCreateOrOpenKey('%S'): Could not create or open subkey '%.*S', Status 0x%08x\n",
491 KeyName
, (int)(KeyString
.Length
/ sizeof(WCHAR
)), KeyString
.Buffer
, 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
)
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
);
627 rc
= ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
633 rc
= ERROR_ACCESS_DENIED
; // STATUS_CANNOT_DELETE;
636 /* Release the cell */
637 HvReleaseCell(Hive
, Key
->KeyCellOffset
);
641 RegCloseKey(hTargetKey
);
652 return RegpCreateOrOpenKey(hKey
, lpSubKey
, FALSE
, FALSE
, phkResult
);
658 IN LPCWSTR lpValueName OPTIONAL
,
661 IN
const UCHAR
* lpData
,
664 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
666 PCM_KEY_NODE KeyNode
; // ParentNode
667 PCM_KEY_VALUE ValueCell
;
669 HCELL_INDEX CellIndex
;
670 UNICODE_STRING ValueNameString
;
676 if (dwType
== REG_LINK
)
680 /* Special handling of registry links */
681 if (cbData
!= sizeof(PVOID
))
682 return ERROR_INVALID_PARAMETER
; // STATUS_INVALID_PARAMETER;
684 DestKey
= HKEY_TO_MEMKEY(*(PHKEY
)lpData
);
686 // FIXME: Add additional checks for the validity of DestKey
688 /* Create the link in registry hive (if applicable) */
689 if (Key
->RegistryHive
!= DestKey
->RegistryHive
)
690 return ERROR_SUCCESS
;
692 DPRINT1("Save link to registry\n");
693 return ERROR_INVALID_FUNCTION
; // STATUS_NOT_IMPLEMENTED;
696 if ((cbData
& ~CM_KEY_VALUE_SPECIAL_SIZE
) != cbData
)
697 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
699 Hive
= &Key
->RegistryHive
->Hive
;
701 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
703 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
705 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
707 /* Mark the parent as dirty since we are going to create a new value in it */
708 HvMarkCellDirty(Hive
, Key
->KeyCellOffset
, FALSE
);
710 /* Initialize value name string */
711 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
712 if (!CmpFindNameInList(Hive
,
719 ASSERT(CellIndex
== HCELL_NIL
);
721 Status
= STATUS_INSUFFICIENT_RESOURCES
;
723 if (CellIndex
== HCELL_NIL
)
725 /* The value doesn't exist, create a new one */
726 Status
= CmiAddValueKey(Key
->RegistryHive
,
735 /* The value already exists, use it. Get the value cell. */
736 ValueCell
= HvGetCell(&Key
->RegistryHive
->Hive
, CellIndex
);
737 ASSERT(ValueCell
!= NULL
);
738 Status
= STATUS_SUCCESS
;
741 // /**/HvReleaseCell(Hive, CellIndex);/**/
743 if (!NT_SUCCESS(Status
))
744 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
746 /* Get size of the allocated cell (if any) */
747 if (!(ValueCell
->DataLength
& CM_KEY_VALUE_SPECIAL_SIZE
) &&
748 (ValueCell
->DataLength
& ~CM_KEY_VALUE_SPECIAL_SIZE
) != 0)
750 DataCell
= HvGetCell(Hive
, ValueCell
->Data
);
752 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
754 DataCellSize
= (ULONG
)(-HvGetCellSize(Hive
, DataCell
));
762 if (cbData
<= sizeof(HCELL_INDEX
))
764 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
765 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
767 HvFreeCell(Hive
, ValueCell
->Data
);
769 RtlCopyMemory(&ValueCell
->Data
, lpData
, cbData
);
770 ValueCell
->DataLength
= (cbData
| CM_KEY_VALUE_SPECIAL_SIZE
);
771 ValueCell
->Type
= dwType
;
775 if (cbData
> DataCellSize
)
777 /* New data size is larger than the current, destroy current
778 * data block and allocate a new one. */
779 HCELL_INDEX NewOffset
;
781 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
783 NewOffset
= HvAllocateCell(Hive
, cbData
, Stable
, HCELL_NIL
);
784 if (NewOffset
== HCELL_NIL
)
786 DPRINT("HvAllocateCell() has failed!\n");
787 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
791 HvFreeCell(Hive
, ValueCell
->Data
);
793 ValueCell
->Data
= NewOffset
;
794 DataCell
= (PVOID
)HvGetCell(Hive
, NewOffset
);
797 /* Copy new contents to cell */
798 RtlCopyMemory(DataCell
, lpData
, cbData
);
799 ValueCell
->DataLength
= (cbData
& ~CM_KEY_VALUE_SPECIAL_SIZE
);
800 ValueCell
->Type
= dwType
;
801 HvMarkCellDirty(Hive
, ValueCell
->Data
, FALSE
);
804 HvMarkCellDirty(Hive
, CellIndex
, FALSE
);
806 /* Check if the maximum value name length changed, update it if so */
807 if (KeyNode
->MaxValueNameLen
< ValueNameString
.Length
)
808 KeyNode
->MaxValueNameLen
= ValueNameString
.Length
;
810 /* Check if the maximum data length changed, update it if so */
811 if (KeyNode
->MaxValueDataLen
< cbData
)
812 KeyNode
->MaxValueDataLen
= cbData
;
814 /* Save the write time */
815 KeQuerySystemTime(&KeyNode
->LastWriteTime
);
817 return ERROR_SUCCESS
;
821 // Synced with freeldr/ntldr/registry.c
826 IN PCM_KEY_VALUE ValueCell
,
827 OUT PULONG Type OPTIONAL
,
828 OUT PUCHAR Data OPTIONAL
,
829 IN OUT PULONG DataSize OPTIONAL
)
834 /* Does the caller want the type? */
836 *Type
= ValueCell
->Type
;
838 /* Does the caller provide DataSize? */
839 if (DataSize
!= NULL
)
841 // NOTE: CmpValueToData doesn't support big data (the function will
842 // bugcheck if so), FreeLdr is not supposed to read such data.
843 // If big data is needed, use instead CmpGetValueData.
844 // CmpGetValueData(Hive, ValueCell, DataSize, &DataCell, ...);
845 DataCell
= CmpValueToData(Hive
, ValueCell
, &DataLength
);
847 /* Does the caller want the data? */
848 if ((Data
!= NULL
) && (*DataSize
!= 0))
852 min(*DataSize
, DataLength
));
855 /* Return the actual data length */
856 *DataSize
= DataLength
;
860 // Similar to RegQueryValue in freeldr/ntldr/registry.c
864 IN LPCWSTR lpValueName
,
865 IN PULONG lpReserved
,
866 OUT PULONG lpType OPTIONAL
,
867 OUT PUCHAR lpData OPTIONAL
,
868 IN OUT PULONG lpcbData OPTIONAL
)
870 PMEMKEY ParentKey
= HKEY_TO_MEMKEY(hKey
);
871 PHHIVE Hive
= &ParentKey
->RegistryHive
->Hive
;
872 PCM_KEY_NODE KeyNode
;
873 PCM_KEY_VALUE ValueCell
;
874 HCELL_INDEX CellIndex
;
875 UNICODE_STRING ValueNameString
;
877 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentKey
->KeyCellOffset
);
879 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
881 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
883 /* Initialize value name string */
884 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
885 CellIndex
= CmpFindValueByName(Hive
, KeyNode
, &ValueNameString
);
886 if (CellIndex
== HCELL_NIL
)
887 return ERROR_FILE_NOT_FOUND
; // STATUS_OBJECT_NAME_NOT_FOUND;
889 /* Get the value cell */
890 ValueCell
= HvGetCell(Hive
, CellIndex
);
891 ASSERT(ValueCell
!= NULL
);
893 RepGetValueData(Hive
, ValueCell
, lpType
, lpData
, lpcbData
);
895 HvReleaseCell(Hive
, CellIndex
);
897 return ERROR_SUCCESS
;
903 IN LPCWSTR lpValueName OPTIONAL
)
907 PMEMKEY Key
= HKEY_TO_MEMKEY(hKey
); // ParentKey
908 PHHIVE Hive
= &Key
->RegistryHive
->Hive
;
909 PCM_KEY_NODE KeyNode
; // ParentNode
910 PCM_KEY_VALUE ValueCell
;
911 HCELL_INDEX CellIndex
;
913 UNICODE_STRING ValueNameString
;
915 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Key
->KeyCellOffset
);
917 return ERROR_GEN_FAILURE
; // STATUS_UNSUCCESSFUL;
919 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
921 /* Initialize value name string */
922 RtlInitUnicodeString(&ValueNameString
, lpValueName
);
923 if (!CmpFindNameInList(Hive
,
930 ASSERT(CellIndex
== HCELL_NIL
);
932 if (CellIndex
== HCELL_NIL
)
934 rc
= ERROR_FILE_NOT_FOUND
; // STATUS_OBJECT_NAME_NOT_FOUND;
938 /* We found the value, mark all relevant cells dirty */
939 HvMarkCellDirty(Hive
, Key
->KeyCellOffset
, FALSE
);
940 HvMarkCellDirty(Hive
, KeyNode
->ValueList
.List
, FALSE
);
941 HvMarkCellDirty(Hive
, CellIndex
, FALSE
);
943 /* Get the key value */
944 ValueCell
= (PCM_KEY_VALUE
)HvGetCell(Hive
, CellIndex
);
947 /* Mark it and all related data as dirty */
948 if (!CmpMarkValueDataDirty(Hive
, ValueCell
))
950 /* Not enough log space, fail */
951 rc
= ERROR_NO_LOG_SPACE
; // STATUS_NO_LOG_SPACE;
956 ASSERT(HvIsCellDirty(Hive
, KeyNode
->ValueList
.List
));
957 ASSERT(HvIsCellDirty(Hive
, CellIndex
));
959 /* Remove the value from the child list */
960 Status
= CmpRemoveValueFromList(Hive
, ChildIndex
, &KeyNode
->ValueList
);
961 if (!NT_SUCCESS(Status
))
963 /* Set known error */
964 rc
= ERROR_NO_SYSTEM_RESOURCES
; // STATUS_INSUFFICIENT_RESOURCES;
968 /* Remove the value and its data itself */
969 if (!CmpFreeValue(Hive
, CellIndex
))
971 /* Failed to free the value, fail */
972 rc
= ERROR_NO_SYSTEM_RESOURCES
; // STATUS_INSUFFICIENT_RESOURCES;
976 /* Set the last write time */
977 KeQuerySystemTime(&KeyNode
->LastWriteTime
);
980 ASSERT(HvIsCellDirty(Hive
, Key
->KeyCellOffset
));
982 /* Check if the value list is empty now */
983 if (!KeyNode
->ValueList
.Count
)
985 /* Then clear key node data */
986 KeyNode
->MaxValueNameLen
= 0;
987 KeyNode
->MaxValueDataLen
= 0;
990 /* Change default Status to success */
994 /* Check if we had a value */
997 /* Release the child cell */
998 ASSERT(CellIndex
!= HCELL_NIL
);
999 HvReleaseCell(Hive
, CellIndex
);
1002 /* Release the parent cell, if any */
1004 HvReleaseCell(Hive
, Key
->KeyCellOffset
);
1013 IN PCMHIVE HiveToConnect
,
1014 IN PUCHAR SecurityDescriptor
,
1015 IN ULONG SecurityDescriptorLength
,
1020 PREPARSE_POINT ReparsePoint
;
1023 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(*ReparsePoint
));
1028 * Use a dummy root key name:
1029 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
1030 * - On Vista+, this is "CMI-CreateHive{guid}"
1031 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
1032 * for more information.
1034 Status
= CmiInitializeHive(HiveToConnect
, L
"$$$PROTO.HIV");
1035 if (!NT_SUCCESS(Status
))
1037 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status
);
1043 * Add security to the root key.
1044 * NOTE: One can implement this using the lpSecurityAttributes
1045 * parameter of RegCreateKeyExW.
1047 Status
= CmiCreateSecurityKey(&HiveToConnect
->Hive
,
1048 HiveToConnect
->Hive
.BaseBlock
->RootCell
,
1049 SecurityDescriptor
, SecurityDescriptorLength
);
1050 if (!NT_SUCCESS(Status
))
1051 DPRINT1("Failed to add security for root key '%S'\n", Path
);
1053 /* Create the key */
1054 rc
= RegCreateKeyExW(RootKey
,
1058 REG_OPTION_VOLATILE
,
1063 if (rc
!= ERROR_SUCCESS
)
1069 ReparsePoint
->SourceHive
= NewKey
->RegistryHive
;
1070 ReparsePoint
->SourceKeyCellOffset
= NewKey
->KeyCellOffset
;
1071 NewKey
->RegistryHive
= HiveToConnect
;
1072 NewKey
->KeyCellOffset
= HiveToConnect
->Hive
.BaseBlock
->RootCell
;
1073 ReparsePoint
->DestinationHive
= NewKey
->RegistryHive
;
1074 ReparsePoint
->DestinationKeyCellOffset
= NewKey
->KeyCellOffset
;
1075 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
1082 IN PCWSTR LinkKeyPath OPTIONAL
,
1083 IN OUT PHKEY LinkKeyHandle OPTIONAL
,
1084 // IN PCWSTR TargetKeyPath OPTIONAL,
1085 IN HKEY TargetKeyHandle
)
1088 PMEMKEY LinkKey
, TargetKey
;
1089 PREPARSE_POINT ReparsePoint
;
1091 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(*ReparsePoint
));
1095 if (LinkKeyPath
&& !(LinkKeyHandle
&& *LinkKeyHandle
))
1097 /* Create the link key */
1098 rc
= RegCreateKeyExW(NULL
,
1102 REG_OPTION_VOLATILE
,
1107 if (rc
!= ERROR_SUCCESS
)
1113 else if (LinkKeyHandle
)
1115 /* Use the user-provided link key handle */
1116 LinkKey
= HKEY_TO_MEMKEY(*LinkKeyHandle
);
1120 *LinkKeyHandle
= MEMKEY_TO_HKEY(LinkKey
);
1122 TargetKey
= HKEY_TO_MEMKEY(TargetKeyHandle
);
1124 ReparsePoint
->SourceHive
= LinkKey
->RegistryHive
;
1125 ReparsePoint
->SourceKeyCellOffset
= LinkKey
->KeyCellOffset
;
1126 ReparsePoint
->DestinationHive
= TargetKey
->RegistryHive
;
1127 ReparsePoint
->DestinationKeyCellOffset
= TargetKey
->KeyCellOffset
;
1128 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
1134 RegInitializeRegistry(
1141 InitializeListHead(&CmiHiveListHead
);
1142 InitializeListHead(&CmiReparsePointsHead
);
1144 Status
= CmiInitializeHive(&RootHive
, L
"");
1145 if (!NT_SUCCESS(Status
))
1147 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status
);
1151 RootKey
= CreateInMemoryStructure(&RootHive
,
1152 RootHive
.Hive
.BaseBlock
->RootCell
);
1154 for (i
= 0; i
< _countof(RegistryHives
); ++i
)
1156 /* Skip this registry hive if it's not in the list */
1157 if (!strstr(HiveList
, RegistryHives
[i
].HiveName
))
1160 /* Create the registry key */
1161 ConnectRegistry(NULL
,
1162 RegistryHives
[i
].CmHive
,
1163 RegistryHives
[i
].SecurityDescriptor
,
1164 RegistryHives
[i
].SecurityDescriptorLength
,
1165 RegistryHives
[i
].HiveRegistryPath
);
1167 /* If we happen to deal with the special setup registry hive, stop there */
1168 // if (strcmp(RegistryHives[i].HiveName, "SETUPREG") == 0)
1173 /* Create the 'ControlSet001' key */
1175 L
"Registry\\Machine\\SYSTEM\\ControlSet001",
1178 /* Create the 'CurrentControlSet' key as a symlink to 'ControlSet001' */
1179 CreateSymLink(L
"Registry\\Machine\\SYSTEM\\CurrentControlSet",
1180 NULL
, ControlSetKey
);
1182 RegCloseKey(ControlSetKey
);
1185 /* Link SECURITY to SAM */
1186 CmpLinkKeyToHive(L
"\\Registry\\Machine\\Security\\SAM", L
"\\Registry\\Machine\\SAM\\SAM");
1187 /* Link S-1-5-18 to .Default */
1188 CmpLinkKeyToHive(L
"\\Registry\\User\\S-1-5-18", L
"\\Registry\\User\\.Default");
1193 RegShutdownRegistry(VOID
)
1196 PREPARSE_POINT ReparsePoint
;
1198 /* Clean up the reparse points list */
1199 while (!IsListEmpty(&CmiReparsePointsHead
))
1201 Entry
= RemoveHeadList(&CmiReparsePointsHead
);
1202 ReparsePoint
= CONTAINING_RECORD(Entry
, REPARSE_POINT
, ListEntry
);
1206 /* FIXME: clean up the complete hive */