8ee8d36ec8aa7a60c4e69f2161642df3b066068e
[reactos.git] / sdk / tools / mkhive / registry.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2006 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /*
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
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #define NDEBUG
31 #include "mkhive.h"
32
33 /* DATA *********************************************************************/
34
35 typedef struct _REPARSE_POINT
36 {
37 LIST_ENTRY ListEntry;
38 PCMHIVE SourceHive;
39 HCELL_INDEX SourceKeyCellOffset;
40 PCMHIVE DestinationHive;
41 HCELL_INDEX DestinationKeyCellOffset;
42 } REPARSE_POINT, *PREPARSE_POINT;
43
44 typedef struct _MEMKEY
45 {
46 /* Information on hard disk structure */
47 HCELL_INDEX KeyCellOffset;
48 PCMHIVE RegistryHive;
49 } MEMKEY, *PMEMKEY;
50
51 #define HKEY_TO_MEMKEY(hKey) ((PMEMKEY)(hKey))
52 #define MEMKEY_TO_HKEY(memKey) ((HKEY)(memKey))
53
54 static CMHIVE RootHive;
55 static PMEMKEY RootKey;
56
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 */
63
64 //
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.
68 //
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.
74 //
75 static UCHAR BcdSecurity[] =
76 {
77 // SECURITY_DESCRIPTOR_RELATIVE
78 0x01, // Revision
79 0x00, // Sbz1
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
88
89 // DACL
90 0x02, // AclRevision
91 0x00, // Sbz1
92 0x34, 0x00, // AclSize
93 0x02, 0x00, // AceCount
94 0x00, 0x00, // Sbz2
95
96 // (1st ACE)
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,
110
111 // (2nd ACE)
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,
120
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,
126
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
135 };
136
137 static UCHAR SoftwareSecurity[] =
138 {
139 // SECURITY_DESCRIPTOR_RELATIVE
140 0x01, // Revision
141 0x00, // Sbz1
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
150
151 // DACL
152 0x02, // AclRevision
153 0x00, // Sbz1
154 0x8C, 0x00, // AclSize
155 0x06, 0x00, // AceCount
156 0x00, 0x00, // Sbz2
157
158 // (1st ACE)
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,
168
169 // (2nd ACE)
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,
178
179 // (3rd ACE)
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,
188
189 // (4th ACE)
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,
204
205 // (5th ACE)
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,
218
219 // (6th ACE)
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,
235
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,
241
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
250 };
251
252 // Same security for SYSTEM, SAM and .DEFAULT
253 static UCHAR SystemSecurity[] =
254 {
255 // SECURITY_DESCRIPTOR_RELATIVE
256 0x01, // Revision
257 0x00, // Sbz1
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
266
267 // DACL
268 0x02, // AclRevision
269 0x00, // Sbz1
270 0x78, 0x00, // AclSize
271 0x05, 0x00, // AceCount
272 0x00, 0x00, // Sbz2
273
274 // (1st ACE)
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,
284
285 // (2nd ACE)
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,
294
295 // (3rd ACE)
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,
304
305 // (4th ACE)
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,
318
319 // (5th ACE)
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,
332
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,
338
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
347 };
348
349 /* GLOBALS ******************************************************************/
350
351 HIVE_LIST_ENTRY RegistryHives[/*MAX_NUMBER_OF_REGISTRY_HIVES*/] =
352 {
353 /* Special Setup system registry hive */
354 // WARNING: Please *keep* it in first position!
355 { "SETUPREG", L"Registry\\Machine\\SYSTEM" , &SystemHive , SystemSecurity , sizeof(SystemSecurity) },
356
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) },
364 };
365 C_ASSERT(_countof(RegistryHives) == MAX_NUMBER_OF_REGISTRY_HIVES);
366
367 /* FUNCTIONS ****************************************************************/
368
369 static PMEMKEY
370 CreateInMemoryStructure(
371 IN PCMHIVE RegistryHive,
372 IN HCELL_INDEX KeyCellOffset)
373 {
374 PMEMKEY Key;
375
376 Key = (PMEMKEY)malloc(sizeof(MEMKEY));
377 if (!Key)
378 return NULL;
379
380 Key->RegistryHive = RegistryHive;
381 Key->KeyCellOffset = KeyCellOffset;
382 return Key;
383 }
384
385 LIST_ENTRY CmiHiveListHead;
386 LIST_ENTRY CmiReparsePointsHead;
387
388 static LONG
389 RegpCreateOrOpenKey(
390 IN HKEY hParentKey,
391 IN PCWSTR KeyName,
392 IN BOOL AllowCreation,
393 IN BOOL Volatile,
394 OUT PHKEY Key)
395 {
396 NTSTATUS Status;
397 PWSTR LocalKeyName;
398 PWSTR End;
399 UNICODE_STRING KeyString;
400 PREPARSE_POINT CurrentReparsePoint;
401 PMEMKEY CurrentKey;
402 PCMHIVE ParentRegistryHive;
403 HCELL_INDEX ParentCellOffset;
404 PCM_KEY_NODE ParentKeyCell;
405 PLIST_ENTRY Ptr;
406 HCELL_INDEX BlockOffset;
407
408 DPRINT("RegpCreateOrOpenKey('%S')\n", KeyName);
409
410 if (*KeyName == OBJ_NAME_PATH_SEPARATOR)
411 {
412 KeyName++;
413 ParentRegistryHive = RootKey->RegistryHive;
414 ParentCellOffset = RootKey->KeyCellOffset;
415 }
416 else if (hParentKey == NULL)
417 {
418 ParentRegistryHive = RootKey->RegistryHive;
419 ParentCellOffset = RootKey->KeyCellOffset;
420 }
421 else
422 {
423 ParentRegistryHive = HKEY_TO_MEMKEY(hParentKey)->RegistryHive;
424 ParentCellOffset = HKEY_TO_MEMKEY(hParentKey)->KeyCellOffset;
425 }
426
427 LocalKeyName = (PWSTR)KeyName;
428 for (;;)
429 {
430 End = (PWSTR)strchrW(LocalKeyName, OBJ_NAME_PATH_SEPARATOR);
431 if (End)
432 {
433 KeyString.Buffer = LocalKeyName;
434 KeyString.Length = KeyString.MaximumLength =
435 (USHORT)((ULONG_PTR)End - (ULONG_PTR)LocalKeyName);
436 }
437 else
438 {
439 RtlInitUnicodeString(&KeyString, LocalKeyName);
440 if (KeyString.Length == 0)
441 {
442 /* Trailing path separator: we're done */
443 break;
444 }
445 }
446
447 ParentKeyCell = (PCM_KEY_NODE)HvGetCell(&ParentRegistryHive->Hive, ParentCellOffset);
448 if (!ParentKeyCell)
449 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
450
451 VERIFY_KEY_CELL(ParentKeyCell);
452
453 BlockOffset = CmpFindSubKeyByName(&ParentRegistryHive->Hive, ParentKeyCell, &KeyString);
454 if (BlockOffset != HCELL_NIL)
455 {
456 Status = STATUS_SUCCESS;
457
458 /* Search for a possible reparse point */
459 Ptr = CmiReparsePointsHead.Flink;
460 while (Ptr != &CmiReparsePointsHead)
461 {
462 CurrentReparsePoint = CONTAINING_RECORD(Ptr, REPARSE_POINT, ListEntry);
463 if (CurrentReparsePoint->SourceHive == ParentRegistryHive &&
464 CurrentReparsePoint->SourceKeyCellOffset == BlockOffset)
465 {
466 ParentRegistryHive = CurrentReparsePoint->DestinationHive;
467 BlockOffset = CurrentReparsePoint->DestinationKeyCellOffset;
468 break;
469 }
470 Ptr = Ptr->Flink;
471 }
472 }
473 else if (AllowCreation) // && (BlockOffset == HCELL_NIL)
474 {
475 Status = CmiAddSubKey(ParentRegistryHive,
476 ParentCellOffset,
477 &KeyString,
478 Volatile,
479 &BlockOffset);
480 }
481 else // if (BlockOffset == HCELL_NIL)
482 {
483 Status = STATUS_OBJECT_NAME_NOT_FOUND;
484 }
485
486 HvReleaseCell(&ParentRegistryHive->Hive, ParentCellOffset);
487
488 if (!NT_SUCCESS(Status))
489 {
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;
493 }
494
495 ParentCellOffset = BlockOffset;
496 if (End)
497 LocalKeyName = End + 1;
498 else
499 break;
500 }
501
502 CurrentKey = CreateInMemoryStructure(ParentRegistryHive, ParentCellOffset);
503 if (!CurrentKey)
504 return ERROR_NOT_ENOUGH_MEMORY; // STATUS_NO_MEMORY;
505
506 *Key = MEMKEY_TO_HKEY(CurrentKey);
507
508 return ERROR_SUCCESS;
509 }
510
511 LONG WINAPI
512 RegCloseKey(
513 IN HKEY hKey)
514 {
515 PMEMKEY Key = HKEY_TO_MEMKEY(hKey); // ParentKey
516
517 /* Free the object */
518 free(Key);
519
520 return ERROR_SUCCESS;
521 }
522
523 LONG WINAPI
524 RegCreateKeyW(
525 IN HKEY hKey,
526 IN LPCWSTR lpSubKey,
527 OUT PHKEY phkResult)
528 {
529 return RegpCreateOrOpenKey(hKey, lpSubKey, TRUE, FALSE, phkResult);
530 }
531
532 LONG WINAPI
533 RegCreateKeyExW(
534 IN HKEY hKey,
535 IN LPCWSTR lpSubKey,
536 IN DWORD Reserved,
537 IN LPWSTR lpClass OPTIONAL,
538 IN DWORD dwOptions,
539 IN REGSAM samDesired,
540 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL,
541 OUT PHKEY phkResult,
542 OUT LPDWORD lpdwDisposition OPTIONAL)
543 {
544 return RegpCreateOrOpenKey(hKey,
545 lpSubKey,
546 TRUE,
547 (dwOptions & REG_OPTION_VOLATILE) != 0,
548 phkResult);
549 }
550
551 LONG WINAPI
552 RegDeleteKeyW(
553 IN HKEY hKey,
554 IN LPCWSTR lpSubKey)
555 {
556 LONG rc;
557 NTSTATUS Status;
558 HKEY hTargetKey;
559 PMEMKEY Key; // ParentKey
560 PHHIVE Hive;
561 PCM_KEY_NODE KeyNode; // ParentNode
562 PCM_KEY_NODE Parent;
563 HCELL_INDEX ParentCell;
564
565 if (lpSubKey)
566 {
567 rc = RegOpenKeyW(hKey, lpSubKey, &hTargetKey);
568 if (rc != ERROR_SUCCESS)
569 return rc;
570 }
571 else
572 {
573 hTargetKey = hKey;
574 rc = ERROR_SUCCESS;
575 }
576
577 /* Don't allow deleting the root */
578 if (hTargetKey == RootKey)
579 {
580 /* Fail */
581 rc = ERROR_ACCESS_DENIED; // STATUS_CANNOT_DELETE;
582 goto Quit;
583 }
584
585 /* Get the hive and node */
586 Key = HKEY_TO_MEMKEY(hTargetKey);
587 Hive = &Key->RegistryHive->Hive;
588
589 /* Get the key node */
590 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Key->KeyCellOffset);
591 if (!KeyNode)
592 {
593 rc = ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
594 goto Quit;
595 }
596
597 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
598
599 /* Check if we don't have any children */
600 if (!(KeyNode->SubKeyCounts[Stable] + KeyNode->SubKeyCounts[Volatile]) &&
601 !(KeyNode->Flags & KEY_NO_DELETE))
602 {
603 /* Get the parent and free the cell */
604 ParentCell = KeyNode->Parent;
605 Status = CmpFreeKeyByCell(Hive, Key->KeyCellOffset, TRUE);
606 if (NT_SUCCESS(Status))
607 {
608 /* Get the parent node */
609 Parent = (PCM_KEY_NODE)HvGetCell(Hive, ParentCell);
610 if (Parent)
611 {
612 /* Make sure we're dirty */
613 ASSERT(HvIsCellDirty(Hive, ParentCell));
614
615 /* Update the write time */
616 KeQuerySystemTime(&Parent->LastWriteTime);
617
618 /* Release the cell */
619 HvReleaseCell(Hive, ParentCell);
620 }
621
622 rc = ERROR_SUCCESS;
623 }
624 else
625 {
626 /* Fail */
627 rc = ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
628 }
629 }
630 else
631 {
632 /* Fail */
633 rc = ERROR_ACCESS_DENIED; // STATUS_CANNOT_DELETE;
634 }
635
636 /* Release the cell */
637 HvReleaseCell(Hive, Key->KeyCellOffset);
638
639 Quit:
640 if (lpSubKey)
641 RegCloseKey(hTargetKey);
642
643 return rc;
644 }
645
646 LONG WINAPI
647 RegOpenKeyW(
648 IN HKEY hKey,
649 IN LPCWSTR lpSubKey,
650 OUT PHKEY phkResult)
651 {
652 return RegpCreateOrOpenKey(hKey, lpSubKey, FALSE, FALSE, phkResult);
653 }
654
655 LONG WINAPI
656 RegSetValueExW(
657 IN HKEY hKey,
658 IN LPCWSTR lpValueName OPTIONAL,
659 IN ULONG Reserved,
660 IN ULONG dwType,
661 IN const UCHAR* lpData,
662 IN ULONG cbData)
663 {
664 PMEMKEY Key = HKEY_TO_MEMKEY(hKey); // ParentKey
665 PHHIVE Hive;
666 PCM_KEY_NODE KeyNode; // ParentNode
667 PCM_KEY_VALUE ValueCell;
668 ULONG ChildIndex;
669 HCELL_INDEX CellIndex;
670 UNICODE_STRING ValueNameString;
671
672 PVOID DataCell;
673 ULONG DataCellSize;
674 NTSTATUS Status;
675
676 if (dwType == REG_LINK)
677 {
678 PMEMKEY DestKey;
679
680 /* Special handling of registry links */
681 if (cbData != sizeof(PVOID))
682 return ERROR_INVALID_PARAMETER; // STATUS_INVALID_PARAMETER;
683
684 DestKey = HKEY_TO_MEMKEY(*(PHKEY)lpData);
685
686 // FIXME: Add additional checks for the validity of DestKey
687
688 /* Create the link in registry hive (if applicable) */
689 if (Key->RegistryHive != DestKey->RegistryHive)
690 return ERROR_SUCCESS;
691
692 DPRINT1("Save link to registry\n");
693 return ERROR_INVALID_FUNCTION; // STATUS_NOT_IMPLEMENTED;
694 }
695
696 if ((cbData & ~CM_KEY_VALUE_SPECIAL_SIZE) != cbData)
697 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
698
699 Hive = &Key->RegistryHive->Hive;
700
701 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Key->KeyCellOffset);
702 if (!KeyNode)
703 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
704
705 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
706
707 /* Mark the parent as dirty since we are going to create a new value in it */
708 HvMarkCellDirty(Hive, Key->KeyCellOffset, FALSE);
709
710 /* Initialize value name string */
711 RtlInitUnicodeString(&ValueNameString, lpValueName);
712 if (!CmpFindNameInList(Hive,
713 &KeyNode->ValueList,
714 &ValueNameString,
715 &ChildIndex,
716 &CellIndex))
717 {
718 /* Sanity check */
719 ASSERT(CellIndex == HCELL_NIL);
720 /* Fail */
721 Status = STATUS_INSUFFICIENT_RESOURCES;
722 }
723 if (CellIndex == HCELL_NIL)
724 {
725 /* The value doesn't exist, create a new one */
726 Status = CmiAddValueKey(Key->RegistryHive,
727 KeyNode,
728 ChildIndex,
729 &ValueNameString,
730 &ValueCell,
731 &CellIndex);
732 }
733 else
734 {
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;
739 }
740
741 // /**/HvReleaseCell(Hive, CellIndex);/**/
742
743 if (!NT_SUCCESS(Status))
744 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
745
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)
749 {
750 DataCell = HvGetCell(Hive, ValueCell->Data);
751 if (!DataCell)
752 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
753
754 DataCellSize = (ULONG)(-HvGetCellSize(Hive, DataCell));
755 }
756 else
757 {
758 DataCell = NULL;
759 DataCellSize = 0;
760 }
761
762 if (cbData <= sizeof(HCELL_INDEX))
763 {
764 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
765 DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
766 if (DataCell)
767 HvFreeCell(Hive, ValueCell->Data);
768
769 RtlCopyMemory(&ValueCell->Data, lpData, cbData);
770 ValueCell->DataLength = (cbData | CM_KEY_VALUE_SPECIAL_SIZE);
771 ValueCell->Type = dwType;
772 }
773 else
774 {
775 if (cbData > DataCellSize)
776 {
777 /* New data size is larger than the current, destroy current
778 * data block and allocate a new one. */
779 HCELL_INDEX NewOffset;
780
781 DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
782
783 NewOffset = HvAllocateCell(Hive, cbData, Stable, HCELL_NIL);
784 if (NewOffset == HCELL_NIL)
785 {
786 DPRINT("HvAllocateCell() has failed!\n");
787 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
788 }
789
790 if (DataCell)
791 HvFreeCell(Hive, ValueCell->Data);
792
793 ValueCell->Data = NewOffset;
794 DataCell = (PVOID)HvGetCell(Hive, NewOffset);
795 }
796
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);
802 }
803
804 HvMarkCellDirty(Hive, CellIndex, FALSE);
805
806 /* Check if the maximum value name length changed, update it if so */
807 if (KeyNode->MaxValueNameLen < ValueNameString.Length)
808 KeyNode->MaxValueNameLen = ValueNameString.Length;
809
810 /* Check if the maximum data length changed, update it if so */
811 if (KeyNode->MaxValueDataLen < cbData)
812 KeyNode->MaxValueDataLen = cbData;
813
814 /* Save the write time */
815 KeQuerySystemTime(&KeyNode->LastWriteTime);
816
817 return ERROR_SUCCESS;
818 }
819
820
821 // Synced with freeldr/ntldr/registry.c
822 static
823 VOID
824 RepGetValueData(
825 IN PHHIVE Hive,
826 IN PCM_KEY_VALUE ValueCell,
827 OUT PULONG Type OPTIONAL,
828 OUT PUCHAR Data OPTIONAL,
829 IN OUT PULONG DataSize OPTIONAL)
830 {
831 ULONG DataLength;
832 PVOID DataCell;
833
834 /* Does the caller want the type? */
835 if (Type != NULL)
836 *Type = ValueCell->Type;
837
838 /* Does the caller provide DataSize? */
839 if (DataSize != NULL)
840 {
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);
846
847 /* Does the caller want the data? */
848 if ((Data != NULL) && (*DataSize != 0))
849 {
850 RtlCopyMemory(Data,
851 DataCell,
852 min(*DataSize, DataLength));
853 }
854
855 /* Return the actual data length */
856 *DataSize = DataLength;
857 }
858 }
859
860 // Similar to RegQueryValue in freeldr/ntldr/registry.c
861 LONG WINAPI
862 RegQueryValueExW(
863 IN HKEY hKey,
864 IN LPCWSTR lpValueName,
865 IN PULONG lpReserved,
866 OUT PULONG lpType OPTIONAL,
867 OUT PUCHAR lpData OPTIONAL,
868 IN OUT PULONG lpcbData OPTIONAL)
869 {
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;
876
877 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey->KeyCellOffset);
878 if (!KeyNode)
879 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
880
881 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
882
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;
888
889 /* Get the value cell */
890 ValueCell = HvGetCell(Hive, CellIndex);
891 ASSERT(ValueCell != NULL);
892
893 RepGetValueData(Hive, ValueCell, lpType, lpData, lpcbData);
894
895 HvReleaseCell(Hive, CellIndex);
896
897 return ERROR_SUCCESS;
898 }
899
900 LONG WINAPI
901 RegDeleteValueW(
902 IN HKEY hKey,
903 IN LPCWSTR lpValueName OPTIONAL)
904 {
905 LONG rc;
906 NTSTATUS Status;
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;
912 ULONG ChildIndex;
913 UNICODE_STRING ValueNameString;
914
915 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Key->KeyCellOffset);
916 if (!KeyNode)
917 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
918
919 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
920
921 /* Initialize value name string */
922 RtlInitUnicodeString(&ValueNameString, lpValueName);
923 if (!CmpFindNameInList(Hive,
924 &KeyNode->ValueList,
925 &ValueNameString,
926 &ChildIndex,
927 &CellIndex))
928 {
929 /* Sanity check */
930 ASSERT(CellIndex == HCELL_NIL);
931 }
932 if (CellIndex == HCELL_NIL)
933 {
934 rc = ERROR_FILE_NOT_FOUND; // STATUS_OBJECT_NAME_NOT_FOUND;
935 goto Quit;
936 }
937
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);
942
943 /* Get the key value */
944 ValueCell = (PCM_KEY_VALUE)HvGetCell(Hive, CellIndex);
945 ASSERT(ValueCell);
946
947 /* Mark it and all related data as dirty */
948 if (!CmpMarkValueDataDirty(Hive, ValueCell))
949 {
950 /* Not enough log space, fail */
951 rc = ERROR_NO_LOG_SPACE; // STATUS_NO_LOG_SPACE;
952 goto Quit;
953 }
954
955 /* Sanity checks */
956 ASSERT(HvIsCellDirty(Hive, KeyNode->ValueList.List));
957 ASSERT(HvIsCellDirty(Hive, CellIndex));
958
959 /* Remove the value from the child list */
960 Status = CmpRemoveValueFromList(Hive, ChildIndex, &KeyNode->ValueList);
961 if (!NT_SUCCESS(Status))
962 {
963 /* Set known error */
964 rc = ERROR_NO_SYSTEM_RESOURCES; // STATUS_INSUFFICIENT_RESOURCES;
965 goto Quit;
966 }
967
968 /* Remove the value and its data itself */
969 if (!CmpFreeValue(Hive, CellIndex))
970 {
971 /* Failed to free the value, fail */
972 rc = ERROR_NO_SYSTEM_RESOURCES; // STATUS_INSUFFICIENT_RESOURCES;
973 goto Quit;
974 }
975
976 /* Set the last write time */
977 KeQuerySystemTime(&KeyNode->LastWriteTime);
978
979 /* Sanity check */
980 ASSERT(HvIsCellDirty(Hive, Key->KeyCellOffset));
981
982 /* Check if the value list is empty now */
983 if (!KeyNode->ValueList.Count)
984 {
985 /* Then clear key node data */
986 KeyNode->MaxValueNameLen = 0;
987 KeyNode->MaxValueDataLen = 0;
988 }
989
990 /* Change default Status to success */
991 rc = ERROR_SUCCESS;
992
993 Quit:
994 /* Check if we had a value */
995 if (ValueCell)
996 {
997 /* Release the child cell */
998 ASSERT(CellIndex != HCELL_NIL);
999 HvReleaseCell(Hive, CellIndex);
1000 }
1001
1002 /* Release the parent cell, if any */
1003 if (KeyNode)
1004 HvReleaseCell(Hive, Key->KeyCellOffset);
1005
1006 return rc;
1007 }
1008
1009
1010 static BOOL
1011 ConnectRegistry(
1012 IN HKEY RootKey,
1013 IN PCMHIVE HiveToConnect,
1014 IN PUCHAR SecurityDescriptor,
1015 IN ULONG SecurityDescriptorLength,
1016 IN PCWSTR Path)
1017 {
1018 NTSTATUS Status;
1019 LONG rc;
1020 PREPARSE_POINT ReparsePoint;
1021 PMEMKEY NewKey;
1022
1023 ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
1024 if (!ReparsePoint)
1025 return FALSE;
1026
1027 /*
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.
1033 */
1034 Status = CmiInitializeHive(HiveToConnect, L"$$$PROTO.HIV");
1035 if (!NT_SUCCESS(Status))
1036 {
1037 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status);
1038 free(ReparsePoint);
1039 return FALSE;
1040 }
1041
1042 /*
1043 * Add security to the root key.
1044 * NOTE: One can implement this using the lpSecurityAttributes
1045 * parameter of RegCreateKeyExW.
1046 */
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);
1052
1053 /* Create the key */
1054 rc = RegCreateKeyExW(RootKey,
1055 Path,
1056 0,
1057 NULL,
1058 REG_OPTION_VOLATILE,
1059 0,
1060 NULL,
1061 (PHKEY)&NewKey,
1062 NULL);
1063 if (rc != ERROR_SUCCESS)
1064 {
1065 free(ReparsePoint);
1066 return FALSE;
1067 }
1068
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);
1076
1077 return TRUE;
1078 }
1079
1080 static BOOL
1081 CreateSymLink(
1082 IN PCWSTR LinkKeyPath OPTIONAL,
1083 IN OUT PHKEY LinkKeyHandle OPTIONAL,
1084 // IN PCWSTR TargetKeyPath OPTIONAL,
1085 IN HKEY TargetKeyHandle)
1086 {
1087 LONG rc;
1088 PMEMKEY LinkKey, TargetKey;
1089 PREPARSE_POINT ReparsePoint;
1090
1091 ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
1092 if (!ReparsePoint)
1093 return FALSE;
1094
1095 if (LinkKeyPath && !(LinkKeyHandle && *LinkKeyHandle))
1096 {
1097 /* Create the link key */
1098 rc = RegCreateKeyExW(NULL,
1099 LinkKeyPath,
1100 0,
1101 NULL,
1102 REG_OPTION_VOLATILE,
1103 0,
1104 NULL,
1105 (PHKEY)&LinkKey,
1106 NULL);
1107 if (rc != ERROR_SUCCESS)
1108 {
1109 free(ReparsePoint);
1110 return FALSE;
1111 }
1112 }
1113 else if (LinkKeyHandle)
1114 {
1115 /* Use the user-provided link key handle */
1116 LinkKey = HKEY_TO_MEMKEY(*LinkKeyHandle);
1117 }
1118
1119 if (LinkKeyHandle)
1120 *LinkKeyHandle = MEMKEY_TO_HKEY(LinkKey);
1121
1122 TargetKey = HKEY_TO_MEMKEY(TargetKeyHandle);
1123
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);
1129
1130 return TRUE;
1131 }
1132
1133 VOID
1134 RegInitializeRegistry(
1135 IN PCSTR HiveList)
1136 {
1137 NTSTATUS Status;
1138 UINT i;
1139 HKEY ControlSetKey;
1140
1141 InitializeListHead(&CmiHiveListHead);
1142 InitializeListHead(&CmiReparsePointsHead);
1143
1144 Status = CmiInitializeHive(&RootHive, L"");
1145 if (!NT_SUCCESS(Status))
1146 {
1147 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status);
1148 return;
1149 }
1150
1151 RootKey = CreateInMemoryStructure(&RootHive,
1152 RootHive.Hive.BaseBlock->RootCell);
1153
1154 for (i = 0; i < _countof(RegistryHives); ++i)
1155 {
1156 /* Skip this registry hive if it's not in the list */
1157 if (!strstr(HiveList, RegistryHives[i].HiveName))
1158 continue;
1159
1160 /* Create the registry key */
1161 ConnectRegistry(NULL,
1162 RegistryHives[i].CmHive,
1163 RegistryHives[i].SecurityDescriptor,
1164 RegistryHives[i].SecurityDescriptorLength,
1165 RegistryHives[i].HiveRegistryPath);
1166
1167 /* If we happen to deal with the special setup registry hive, stop there */
1168 // if (strcmp(RegistryHives[i].HiveName, "SETUPREG") == 0)
1169 if (i == 0)
1170 break;
1171 }
1172
1173 /* Create the 'ControlSet001' key */
1174 RegCreateKeyW(NULL,
1175 L"Registry\\Machine\\SYSTEM\\ControlSet001",
1176 &ControlSetKey);
1177
1178 /* Create the 'CurrentControlSet' key as a symlink to 'ControlSet001' */
1179 CreateSymLink(L"Registry\\Machine\\SYSTEM\\CurrentControlSet",
1180 NULL, ControlSetKey);
1181
1182 RegCloseKey(ControlSetKey);
1183
1184 #if 0
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");
1189 #endif
1190 }
1191
1192 VOID
1193 RegShutdownRegistry(VOID)
1194 {
1195 PLIST_ENTRY Entry;
1196 PREPARSE_POINT ReparsePoint;
1197
1198 /* Clean up the reparse points list */
1199 while (!IsListEmpty(&CmiReparsePointsHead))
1200 {
1201 Entry = RemoveHeadList(&CmiReparsePointsHead);
1202 ReparsePoint = CONTAINING_RECORD(Entry, REPARSE_POINT, ListEntry);
1203 free(ReparsePoint);
1204 }
1205
1206 /* FIXME: clean up the complete hive */
1207
1208 free(RootKey);
1209 }
1210
1211 /* EOF */