ad0aafc59c5f93a678d44e300c8313953c2d5c5b
[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 PCM_KEY_NODE SubKeyCell;
407 HCELL_INDEX BlockOffset;
408
409 DPRINT("RegpCreateOrOpenKey('%S')\n", KeyName);
410
411 if (*KeyName == OBJ_NAME_PATH_SEPARATOR)
412 {
413 KeyName++;
414 ParentRegistryHive = RootKey->RegistryHive;
415 ParentCellOffset = RootKey->KeyCellOffset;
416 }
417 else if (hParentKey == NULL)
418 {
419 ParentRegistryHive = RootKey->RegistryHive;
420 ParentCellOffset = RootKey->KeyCellOffset;
421 }
422 else
423 {
424 ParentRegistryHive = HKEY_TO_MEMKEY(hParentKey)->RegistryHive;
425 ParentCellOffset = HKEY_TO_MEMKEY(hParentKey)->KeyCellOffset;
426 }
427
428 LocalKeyName = (PWSTR)KeyName;
429 for (;;)
430 {
431 End = (PWSTR)strchrW(LocalKeyName, OBJ_NAME_PATH_SEPARATOR);
432 if (End)
433 {
434 KeyString.Buffer = LocalKeyName;
435 KeyString.Length = KeyString.MaximumLength =
436 (USHORT)((ULONG_PTR)End - (ULONG_PTR)LocalKeyName);
437 }
438 else
439 {
440 RtlInitUnicodeString(&KeyString, LocalKeyName);
441 if (KeyString.Length == 0)
442 {
443 /* Trailing path separator: we're done */
444 break;
445 }
446 }
447
448 ParentKeyCell = (PCM_KEY_NODE)HvGetCell(&ParentRegistryHive->Hive, ParentCellOffset);
449 if (!ParentKeyCell)
450 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
451
452 VERIFY_KEY_CELL(ParentKeyCell);
453
454 BlockOffset = CmpFindSubKeyByName(&ParentRegistryHive->Hive, ParentKeyCell, &KeyString);
455 if (BlockOffset != HCELL_NIL)
456 {
457 Status = STATUS_SUCCESS;
458
459 /* Search for a possible reparse point */
460 Ptr = CmiReparsePointsHead.Flink;
461 while (Ptr != &CmiReparsePointsHead)
462 {
463 CurrentReparsePoint = CONTAINING_RECORD(Ptr, REPARSE_POINT, ListEntry);
464 if (CurrentReparsePoint->SourceHive == ParentRegistryHive &&
465 CurrentReparsePoint->SourceKeyCellOffset == BlockOffset)
466 {
467 ParentRegistryHive = CurrentReparsePoint->DestinationHive;
468 BlockOffset = CurrentReparsePoint->DestinationKeyCellOffset;
469 break;
470 }
471 Ptr = Ptr->Flink;
472 }
473 }
474 else if (AllowCreation) // && (BlockOffset == HCELL_NIL)
475 {
476 Status = CmiAddSubKey(ParentRegistryHive,
477 ParentCellOffset,
478 &KeyString,
479 Volatile,
480 &BlockOffset);
481 }
482 else // if (BlockOffset == HCELL_NIL)
483 {
484 Status = STATUS_OBJECT_NAME_NOT_FOUND;
485 }
486
487 HvReleaseCell(&ParentRegistryHive->Hive, ParentCellOffset);
488
489 if (!NT_SUCCESS(Status))
490 {
491 DPRINT("RegpCreateOrOpenKey('%S'): Could not create or open subkey '%.*S', Status 0x%08x\n",
492 KeyName, (int)(KeyString.Length / sizeof(WCHAR)), KeyString.Buffer, Status);
493 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
494 }
495
496 ParentCellOffset = BlockOffset;
497 if (End)
498 LocalKeyName = End + 1;
499 else
500 break;
501 }
502
503 CurrentKey = CreateInMemoryStructure(ParentRegistryHive, ParentCellOffset);
504 if (!CurrentKey)
505 return ERROR_NOT_ENOUGH_MEMORY; // STATUS_NO_MEMORY;
506
507 *Key = MEMKEY_TO_HKEY(CurrentKey);
508
509 return ERROR_SUCCESS;
510 }
511
512 LONG WINAPI
513 RegCloseKey(
514 IN HKEY hKey)
515 {
516 PMEMKEY Key = HKEY_TO_MEMKEY(hKey); // ParentKey
517
518 /* Free the object */
519 free(Key);
520
521 return ERROR_SUCCESS;
522 }
523
524 LONG WINAPI
525 RegCreateKeyW(
526 IN HKEY hKey,
527 IN LPCWSTR lpSubKey,
528 OUT PHKEY phkResult)
529 {
530 return RegpCreateOrOpenKey(hKey, lpSubKey, TRUE, FALSE, phkResult);
531 }
532
533 LONG WINAPI
534 RegCreateKeyExW(
535 IN HKEY hKey,
536 IN LPCWSTR lpSubKey,
537 IN DWORD Reserved,
538 IN LPWSTR lpClass OPTIONAL,
539 IN DWORD dwOptions,
540 IN REGSAM samDesired,
541 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL,
542 OUT PHKEY phkResult,
543 OUT LPDWORD lpdwDisposition OPTIONAL)
544 {
545 return RegpCreateOrOpenKey(hKey,
546 lpSubKey,
547 TRUE,
548 (dwOptions & REG_OPTION_VOLATILE) != 0,
549 phkResult);
550 }
551
552 LONG WINAPI
553 RegDeleteKeyW(
554 IN HKEY hKey,
555 IN LPCWSTR lpSubKey)
556 {
557 LONG rc;
558 NTSTATUS Status;
559 HKEY hTargetKey;
560 PMEMKEY Key; // ParentKey
561 PHHIVE Hive;
562 PCM_KEY_NODE KeyNode; // ParentNode
563 PCM_KEY_NODE Parent;
564 HCELL_INDEX ParentCell;
565
566 if (lpSubKey)
567 {
568 rc = RegOpenKeyW(hKey, lpSubKey, &hTargetKey);
569 if (rc != ERROR_SUCCESS)
570 return rc;
571 }
572 else
573 {
574 hTargetKey = hKey;
575 rc = ERROR_SUCCESS;
576 }
577
578 /* Don't allow deleting the root */
579 if (hTargetKey == RootKey)
580 {
581 /* Fail */
582 rc = ERROR_ACCESS_DENIED; // STATUS_CANNOT_DELETE;
583 goto Quit;
584 }
585
586 /* Get the hive and node */
587 Key = HKEY_TO_MEMKEY(hTargetKey);
588 Hive = &Key->RegistryHive->Hive;
589
590 /* Get the key node */
591 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Key->KeyCellOffset);
592 if (!KeyNode)
593 {
594 rc = ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
595 goto Quit;
596 }
597
598 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
599
600 /* Check if we don't have any children */
601 if (!(KeyNode->SubKeyCounts[Stable] + KeyNode->SubKeyCounts[Volatile]) &&
602 !(KeyNode->Flags & KEY_NO_DELETE))
603 {
604 /* Get the parent and free the cell */
605 ParentCell = KeyNode->Parent;
606 Status = CmpFreeKeyByCell(Hive, Key->KeyCellOffset, TRUE);
607 if (NT_SUCCESS(Status))
608 {
609 /* Get the parent node */
610 Parent = (PCM_KEY_NODE)HvGetCell(Hive, ParentCell);
611 if (Parent)
612 {
613 /* Make sure we're dirty */
614 ASSERT(HvIsCellDirty(Hive, ParentCell));
615
616 /* Update the write time */
617 KeQuerySystemTime(&Parent->LastWriteTime);
618
619 /* Release the cell */
620 HvReleaseCell(Hive, ParentCell);
621 }
622
623 rc = ERROR_SUCCESS;
624 }
625 else
626 {
627 /* Fail */
628 rc = ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
629 }
630 }
631 else
632 {
633 /* Fail */
634 rc = ERROR_ACCESS_DENIED; // STATUS_CANNOT_DELETE;
635 }
636
637 /* Release the cell */
638 HvReleaseCell(Hive, Key->KeyCellOffset);
639
640 Quit:
641 if (lpSubKey)
642 RegCloseKey(hTargetKey);
643
644 return rc;
645 }
646
647 LONG WINAPI
648 RegOpenKeyW(
649 IN HKEY hKey,
650 IN LPCWSTR lpSubKey,
651 OUT PHKEY phkResult)
652 {
653 return RegpCreateOrOpenKey(hKey, lpSubKey, FALSE, FALSE, phkResult);
654 }
655
656 LONG WINAPI
657 RegSetValueExW(
658 IN HKEY hKey,
659 IN LPCWSTR lpValueName OPTIONAL,
660 IN ULONG Reserved,
661 IN ULONG dwType,
662 IN const UCHAR* lpData,
663 IN ULONG cbData)
664 {
665 PMEMKEY Key = HKEY_TO_MEMKEY(hKey); // ParentKey
666 PHHIVE Hive;
667 PCM_KEY_NODE KeyNode; // ParentNode
668 PCM_KEY_VALUE ValueCell;
669 ULONG ChildIndex;
670 HCELL_INDEX CellIndex;
671 UNICODE_STRING ValueNameString;
672
673 PVOID DataCell;
674 ULONG DataCellSize;
675 NTSTATUS Status;
676
677 if (dwType == REG_LINK)
678 {
679 PMEMKEY DestKey;
680
681 /* Special handling of registry links */
682 if (cbData != sizeof(PVOID))
683 return ERROR_INVALID_PARAMETER; // STATUS_INVALID_PARAMETER;
684
685 DestKey = HKEY_TO_MEMKEY(*(PHKEY)lpData);
686
687 // FIXME: Add additional checks for the validity of DestKey
688
689 /* Create the link in registry hive (if applicable) */
690 if (Key->RegistryHive != DestKey->RegistryHive)
691 return ERROR_SUCCESS;
692
693 DPRINT1("Save link to registry\n");
694 return ERROR_INVALID_FUNCTION; // STATUS_NOT_IMPLEMENTED;
695 }
696
697 if ((cbData & ~CM_KEY_VALUE_SPECIAL_SIZE) != cbData)
698 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
699
700 Hive = &Key->RegistryHive->Hive;
701
702 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Key->KeyCellOffset);
703 if (!KeyNode)
704 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
705
706 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
707
708 /* Mark the parent as dirty since we are going to create a new value in it */
709 HvMarkCellDirty(Hive, Key->KeyCellOffset, FALSE);
710
711 /* Initialize value name string */
712 RtlInitUnicodeString(&ValueNameString, lpValueName);
713 if (!CmpFindNameInList(Hive,
714 &KeyNode->ValueList,
715 &ValueNameString,
716 &ChildIndex,
717 &CellIndex))
718 {
719 /* Sanity check */
720 ASSERT(CellIndex == HCELL_NIL);
721 /* Fail */
722 Status = STATUS_INSUFFICIENT_RESOURCES;
723 }
724 if (CellIndex == HCELL_NIL)
725 {
726 /* The value doesn't exist, create a new one */
727 Status = CmiAddValueKey(Key->RegistryHive,
728 KeyNode,
729 ChildIndex,
730 &ValueNameString,
731 &ValueCell,
732 &CellIndex);
733 }
734 else
735 {
736 /* The value already exists, use it. Get the value cell. */
737 ValueCell = HvGetCell(&Key->RegistryHive->Hive, CellIndex);
738 ASSERT(ValueCell != NULL);
739 Status = STATUS_SUCCESS;
740 }
741
742 // /**/HvReleaseCell(Hive, CellIndex);/**/
743
744 if (!NT_SUCCESS(Status))
745 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
746
747 /* Get size of the allocated cell (if any) */
748 if (!(ValueCell->DataLength & CM_KEY_VALUE_SPECIAL_SIZE) &&
749 (ValueCell->DataLength & ~CM_KEY_VALUE_SPECIAL_SIZE) != 0)
750 {
751 DataCell = HvGetCell(Hive, ValueCell->Data);
752 if (!DataCell)
753 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
754
755 DataCellSize = (ULONG)(-HvGetCellSize(Hive, DataCell));
756 }
757 else
758 {
759 DataCell = NULL;
760 DataCellSize = 0;
761 }
762
763 if (cbData <= sizeof(HCELL_INDEX))
764 {
765 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
766 DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
767 if (DataCell)
768 HvFreeCell(Hive, ValueCell->Data);
769
770 RtlCopyMemory(&ValueCell->Data, lpData, cbData);
771 ValueCell->DataLength = (cbData | CM_KEY_VALUE_SPECIAL_SIZE);
772 ValueCell->Type = dwType;
773 }
774 else
775 {
776 if (cbData > DataCellSize)
777 {
778 /* New data size is larger than the current, destroy current
779 * data block and allocate a new one. */
780 HCELL_INDEX NewOffset;
781
782 DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
783
784 NewOffset = HvAllocateCell(Hive, cbData, Stable, HCELL_NIL);
785 if (NewOffset == HCELL_NIL)
786 {
787 DPRINT("HvAllocateCell() has failed!\n");
788 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
789 }
790
791 if (DataCell)
792 HvFreeCell(Hive, ValueCell->Data);
793
794 ValueCell->Data = NewOffset;
795 DataCell = (PVOID)HvGetCell(Hive, NewOffset);
796 }
797
798 /* Copy new contents to cell */
799 RtlCopyMemory(DataCell, lpData, cbData);
800 ValueCell->DataLength = (cbData & ~CM_KEY_VALUE_SPECIAL_SIZE);
801 ValueCell->Type = dwType;
802 HvMarkCellDirty(Hive, ValueCell->Data, FALSE);
803 }
804
805 HvMarkCellDirty(Hive, CellIndex, FALSE);
806
807 /* Check if the maximum value name length changed, update it if so */
808 if (KeyNode->MaxValueNameLen < ValueNameString.Length)
809 KeyNode->MaxValueNameLen = ValueNameString.Length;
810
811 /* Check if the maximum data length changed, update it if so */
812 if (KeyNode->MaxValueDataLen < cbData)
813 KeyNode->MaxValueDataLen = cbData;
814
815 /* Save the write time */
816 KeQuerySystemTime(&KeyNode->LastWriteTime);
817
818 return ERROR_SUCCESS;
819 }
820
821
822 // Synced with freeldr/ntldr/registry.c
823 static
824 VOID
825 RepGetValueData(
826 IN PHHIVE Hive,
827 IN PCM_KEY_VALUE ValueCell,
828 OUT PULONG Type OPTIONAL,
829 OUT PUCHAR Data OPTIONAL,
830 IN OUT PULONG DataSize OPTIONAL)
831 {
832 ULONG DataLength;
833 PVOID DataCell;
834
835 /* Does the caller want the type? */
836 if (Type != NULL)
837 *Type = ValueCell->Type;
838
839 /* Does the caller provide DataSize? */
840 if (DataSize != NULL)
841 {
842 // NOTE: CmpValueToData doesn't support big data (the function will
843 // bugcheck if so), FreeLdr is not supposed to read such data.
844 // If big data is needed, use instead CmpGetValueData.
845 // CmpGetValueData(Hive, ValueCell, DataSize, &DataCell, ...);
846 DataCell = CmpValueToData(Hive, ValueCell, &DataLength);
847
848 /* Does the caller want the data? */
849 if ((Data != NULL) && (*DataSize != 0))
850 {
851 RtlCopyMemory(Data,
852 DataCell,
853 min(*DataSize, DataLength));
854 }
855
856 /* Return the actual data length */
857 *DataSize = DataLength;
858 }
859 }
860
861 // Similar to RegQueryValue in freeldr/ntldr/registry.c
862 LONG WINAPI
863 RegQueryValueExW(
864 IN HKEY hKey,
865 IN LPCWSTR lpValueName,
866 IN PULONG lpReserved,
867 OUT PULONG lpType OPTIONAL,
868 OUT PUCHAR lpData OPTIONAL,
869 IN OUT PULONG lpcbData OPTIONAL)
870 {
871 PMEMKEY ParentKey = HKEY_TO_MEMKEY(hKey);
872 PHHIVE Hive = &ParentKey->RegistryHive->Hive;
873 PCM_KEY_NODE KeyNode;
874 PCM_KEY_VALUE ValueCell;
875 HCELL_INDEX CellIndex;
876 UNICODE_STRING ValueNameString;
877
878 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey->KeyCellOffset);
879 if (!KeyNode)
880 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
881
882 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
883
884 /* Initialize value name string */
885 RtlInitUnicodeString(&ValueNameString, lpValueName);
886 CellIndex = CmpFindValueByName(Hive, KeyNode, &ValueNameString);
887 if (CellIndex == HCELL_NIL)
888 return ERROR_FILE_NOT_FOUND; // STATUS_OBJECT_NAME_NOT_FOUND;
889
890 /* Get the value cell */
891 ValueCell = HvGetCell(Hive, CellIndex);
892 ASSERT(ValueCell != NULL);
893
894 RepGetValueData(Hive, ValueCell, lpType, lpData, lpcbData);
895
896 HvReleaseCell(Hive, CellIndex);
897
898 return ERROR_SUCCESS;
899 }
900
901 LONG WINAPI
902 RegDeleteValueW(
903 IN HKEY hKey,
904 IN LPCWSTR lpValueName OPTIONAL)
905 {
906 LONG rc;
907 NTSTATUS Status;
908 PMEMKEY Key = HKEY_TO_MEMKEY(hKey); // ParentKey
909 PHHIVE Hive = &Key->RegistryHive->Hive;
910 PCM_KEY_NODE KeyNode; // ParentNode
911 PCM_KEY_VALUE ValueCell;
912 HCELL_INDEX CellIndex;
913 ULONG ChildIndex;
914 UNICODE_STRING ValueNameString;
915
916 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Key->KeyCellOffset);
917 if (!KeyNode)
918 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
919
920 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
921
922 /* Initialize value name string */
923 RtlInitUnicodeString(&ValueNameString, lpValueName);
924 if (!CmpFindNameInList(Hive,
925 &KeyNode->ValueList,
926 &ValueNameString,
927 &ChildIndex,
928 &CellIndex))
929 {
930 /* Sanity check */
931 ASSERT(CellIndex == HCELL_NIL);
932 }
933 if (CellIndex == HCELL_NIL)
934 {
935 rc = ERROR_FILE_NOT_FOUND; // STATUS_OBJECT_NAME_NOT_FOUND;
936 goto Quit;
937 }
938
939 /* We found the value, mark all relevant cells dirty */
940 HvMarkCellDirty(Hive, Key->KeyCellOffset, FALSE);
941 HvMarkCellDirty(Hive, KeyNode->ValueList.List, FALSE);
942 HvMarkCellDirty(Hive, CellIndex, FALSE);
943
944 /* Get the key value */
945 ValueCell = (PCM_KEY_VALUE)HvGetCell(Hive, CellIndex);
946 ASSERT(ValueCell);
947
948 /* Mark it and all related data as dirty */
949 if (!CmpMarkValueDataDirty(Hive, ValueCell))
950 {
951 /* Not enough log space, fail */
952 rc = ERROR_NO_LOG_SPACE; // STATUS_NO_LOG_SPACE;
953 goto Quit;
954 }
955
956 /* Sanity checks */
957 ASSERT(HvIsCellDirty(Hive, KeyNode->ValueList.List));
958 ASSERT(HvIsCellDirty(Hive, CellIndex));
959
960 /* Remove the value from the child list */
961 Status = CmpRemoveValueFromList(Hive, ChildIndex, &KeyNode->ValueList);
962 if (!NT_SUCCESS(Status))
963 {
964 /* Set known error */
965 rc = ERROR_NO_SYSTEM_RESOURCES; // STATUS_INSUFFICIENT_RESOURCES;
966 goto Quit;
967 }
968
969 /* Remove the value and its data itself */
970 if (!CmpFreeValue(Hive, CellIndex))
971 {
972 /* Failed to free the value, fail */
973 rc = ERROR_NO_SYSTEM_RESOURCES; // STATUS_INSUFFICIENT_RESOURCES;
974 goto Quit;
975 }
976
977 /* Set the last write time */
978 KeQuerySystemTime(&KeyNode->LastWriteTime);
979
980 /* Sanity check */
981 ASSERT(HvIsCellDirty(Hive, Key->KeyCellOffset));
982
983 /* Check if the value list is empty now */
984 if (!KeyNode->ValueList.Count)
985 {
986 /* Then clear key node data */
987 KeyNode->MaxValueNameLen = 0;
988 KeyNode->MaxValueDataLen = 0;
989 }
990
991 /* Change default Status to success */
992 rc = ERROR_SUCCESS;
993
994 Quit:
995 /* Check if we had a value */
996 if (ValueCell)
997 {
998 /* Release the child cell */
999 ASSERT(CellIndex != HCELL_NIL);
1000 HvReleaseCell(Hive, CellIndex);
1001 }
1002
1003 /* Release the parent cell, if any */
1004 if (KeyNode)
1005 HvReleaseCell(Hive, Key->KeyCellOffset);
1006
1007 return rc;
1008 }
1009
1010
1011 static BOOL
1012 ConnectRegistry(
1013 IN HKEY RootKey,
1014 IN PCMHIVE HiveToConnect,
1015 IN PUCHAR SecurityDescriptor,
1016 IN ULONG SecurityDescriptorLength,
1017 IN PCWSTR Path)
1018 {
1019 NTSTATUS Status;
1020 LONG rc;
1021 PREPARSE_POINT ReparsePoint;
1022 PMEMKEY NewKey;
1023
1024 ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
1025 if (!ReparsePoint)
1026 return FALSE;
1027
1028 /*
1029 * Use a dummy root key name:
1030 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
1031 * - On Vista+, this is "CMI-CreateHive{guid}"
1032 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
1033 * for more information.
1034 */
1035 Status = CmiInitializeHive(HiveToConnect, L"$$$PROTO.HIV");
1036 if (!NT_SUCCESS(Status))
1037 {
1038 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status);
1039 free(ReparsePoint);
1040 return FALSE;
1041 }
1042
1043 /*
1044 * Add security to the root key.
1045 * NOTE: One can implement this using the lpSecurityAttributes
1046 * parameter of RegCreateKeyExW.
1047 */
1048 Status = CmiCreateSecurityKey(&HiveToConnect->Hive,
1049 HiveToConnect->Hive.BaseBlock->RootCell,
1050 SecurityDescriptor, SecurityDescriptorLength);
1051 if (!NT_SUCCESS(Status))
1052 DPRINT1("Failed to add security for root key '%S'\n", Path);
1053
1054 /* Create the key */
1055 rc = RegCreateKeyExW(RootKey,
1056 Path,
1057 0,
1058 NULL,
1059 REG_OPTION_VOLATILE,
1060 0,
1061 NULL,
1062 (PHKEY)&NewKey,
1063 NULL);
1064 if (rc != ERROR_SUCCESS)
1065 {
1066 free(ReparsePoint);
1067 return FALSE;
1068 }
1069
1070 ReparsePoint->SourceHive = NewKey->RegistryHive;
1071 ReparsePoint->SourceKeyCellOffset = NewKey->KeyCellOffset;
1072 NewKey->RegistryHive = HiveToConnect;
1073 NewKey->KeyCellOffset = HiveToConnect->Hive.BaseBlock->RootCell;
1074 ReparsePoint->DestinationHive = NewKey->RegistryHive;
1075 ReparsePoint->DestinationKeyCellOffset = NewKey->KeyCellOffset;
1076 InsertTailList(&CmiReparsePointsHead, &ReparsePoint->ListEntry);
1077
1078 return TRUE;
1079 }
1080
1081 static BOOL
1082 CreateSymLink(
1083 IN PCWSTR LinkKeyPath OPTIONAL,
1084 IN OUT PHKEY LinkKeyHandle OPTIONAL,
1085 // IN PCWSTR TargetKeyPath OPTIONAL,
1086 IN HKEY TargetKeyHandle)
1087 {
1088 LONG rc;
1089 PMEMKEY LinkKey, TargetKey;
1090 PREPARSE_POINT ReparsePoint;
1091
1092 ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
1093 if (!ReparsePoint)
1094 return FALSE;
1095
1096 if (LinkKeyPath && !(LinkKeyHandle && *LinkKeyHandle))
1097 {
1098 /* Create the link key */
1099 rc = RegCreateKeyExW(NULL,
1100 LinkKeyPath,
1101 0,
1102 NULL,
1103 REG_OPTION_VOLATILE,
1104 0,
1105 NULL,
1106 (PHKEY)&LinkKey,
1107 NULL);
1108 if (rc != ERROR_SUCCESS)
1109 {
1110 free(ReparsePoint);
1111 return FALSE;
1112 }
1113 }
1114 else if (LinkKeyHandle)
1115 {
1116 /* Use the user-provided link key handle */
1117 LinkKey = HKEY_TO_MEMKEY(*LinkKeyHandle);
1118 }
1119
1120 if (LinkKeyHandle)
1121 *LinkKeyHandle = MEMKEY_TO_HKEY(LinkKey);
1122
1123 TargetKey = HKEY_TO_MEMKEY(TargetKeyHandle);
1124
1125 ReparsePoint->SourceHive = LinkKey->RegistryHive;
1126 ReparsePoint->SourceKeyCellOffset = LinkKey->KeyCellOffset;
1127 ReparsePoint->DestinationHive = TargetKey->RegistryHive;
1128 ReparsePoint->DestinationKeyCellOffset = TargetKey->KeyCellOffset;
1129 InsertTailList(&CmiReparsePointsHead, &ReparsePoint->ListEntry);
1130
1131 return TRUE;
1132 }
1133
1134 VOID
1135 RegInitializeRegistry(
1136 IN PCSTR HiveList)
1137 {
1138 NTSTATUS Status;
1139 UINT i;
1140 HKEY ControlSetKey;
1141
1142 InitializeListHead(&CmiHiveListHead);
1143 InitializeListHead(&CmiReparsePointsHead);
1144
1145 Status = CmiInitializeHive(&RootHive, L"");
1146 if (!NT_SUCCESS(Status))
1147 {
1148 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status);
1149 return;
1150 }
1151
1152 RootKey = CreateInMemoryStructure(&RootHive,
1153 RootHive.Hive.BaseBlock->RootCell);
1154
1155 for (i = 0; i < _countof(RegistryHives); ++i)
1156 {
1157 /* Skip this registry hive if it's not in the list */
1158 if (!strstr(HiveList, RegistryHives[i].HiveName))
1159 continue;
1160
1161 /* Create the registry key */
1162 ConnectRegistry(NULL,
1163 RegistryHives[i].CmHive,
1164 RegistryHives[i].SecurityDescriptor,
1165 RegistryHives[i].SecurityDescriptorLength,
1166 RegistryHives[i].HiveRegistryPath);
1167
1168 /* If we happen to deal with the special setup registry hive, stop there */
1169 // if (strcmp(RegistryHives[i].HiveName, "SETUPREG") == 0)
1170 if (i == 0)
1171 break;
1172 }
1173
1174 /* Create the 'ControlSet001' key */
1175 RegCreateKeyW(NULL,
1176 L"Registry\\Machine\\SYSTEM\\ControlSet001",
1177 &ControlSetKey);
1178
1179 /* Create the 'CurrentControlSet' key as a symlink to 'ControlSet001' */
1180 CreateSymLink(L"Registry\\Machine\\SYSTEM\\CurrentControlSet",
1181 NULL, ControlSetKey);
1182
1183 RegCloseKey(ControlSetKey);
1184
1185 #if 0
1186 /* Link SECURITY to SAM */
1187 CmpLinkKeyToHive(L"\\Registry\\Machine\\Security\\SAM", L"\\Registry\\Machine\\SAM\\SAM");
1188 /* Link S-1-5-18 to .Default */
1189 CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18", L"\\Registry\\User\\.Default");
1190 #endif
1191 }
1192
1193 VOID
1194 RegShutdownRegistry(VOID)
1195 {
1196 PLIST_ENTRY Entry;
1197 PREPARSE_POINT ReparsePoint;
1198
1199 /* Clean up the reparse points list */
1200 while (!IsListEmpty(&CmiReparsePointsHead))
1201 {
1202 Entry = RemoveHeadList(&CmiReparsePointsHead);
1203 ReparsePoint = CONTAINING_RECORD(Entry, REPARSE_POINT, ListEntry);
1204 free(ReparsePoint);
1205 }
1206
1207 /* FIXME: clean up the complete hive */
1208
1209 free(RootKey);
1210 }
1211
1212 /* EOF */