[MKHIVE] Fix compilation warnings.
[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 }
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 else
623 {
624 /* Fail */
625 rc = ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
626 }
627 }
628 else
629 {
630 /* Fail */
631 rc = ERROR_ACCESS_DENIED; // STATUS_CANNOT_DELETE;
632 }
633
634 /* Release the cell */
635 HvReleaseCell(Hive, Key->KeyCellOffset);
636
637 Quit:
638 if (lpSubKey)
639 RegCloseKey(hTargetKey);
640
641 return rc;
642 }
643
644 LONG WINAPI
645 RegOpenKeyW(
646 IN HKEY hKey,
647 IN LPCWSTR lpSubKey,
648 OUT PHKEY phkResult)
649 {
650 return RegpCreateOrOpenKey(hKey, lpSubKey, FALSE, FALSE, phkResult);
651 }
652
653 LONG WINAPI
654 RegSetValueExW(
655 IN HKEY hKey,
656 IN LPCWSTR lpValueName OPTIONAL,
657 IN ULONG Reserved,
658 IN ULONG dwType,
659 IN const UCHAR* lpData,
660 IN ULONG cbData)
661 {
662 PMEMKEY Key = HKEY_TO_MEMKEY(hKey); // ParentKey
663 PHHIVE Hive;
664 PCM_KEY_NODE KeyNode; // ParentNode
665 PCM_KEY_VALUE ValueCell;
666 ULONG ChildIndex;
667 HCELL_INDEX CellIndex;
668 UNICODE_STRING ValueNameString;
669
670 PVOID DataCell;
671 ULONG DataCellSize;
672 NTSTATUS Status;
673
674 if (dwType == REG_LINK)
675 {
676 PMEMKEY DestKey;
677
678 /* Special handling of registry links */
679 if (cbData != sizeof(PVOID))
680 return ERROR_INVALID_PARAMETER; // STATUS_INVALID_PARAMETER;
681
682 DestKey = HKEY_TO_MEMKEY(*(PHKEY)lpData);
683
684 // FIXME: Add additional checks for the validity of DestKey
685
686 /* Create the link in registry hive (if applicable) */
687 if (Key->RegistryHive != DestKey->RegistryHive)
688 return ERROR_SUCCESS;
689
690 DPRINT1("Save link to registry\n");
691 return ERROR_INVALID_FUNCTION; // STATUS_NOT_IMPLEMENTED;
692 }
693
694 if ((cbData & ~CM_KEY_VALUE_SPECIAL_SIZE) != cbData)
695 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
696
697 Hive = &Key->RegistryHive->Hive;
698
699 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Key->KeyCellOffset);
700 if (!KeyNode)
701 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
702
703 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
704
705 /* Mark the parent as dirty since we are going to create a new value in it */
706 HvMarkCellDirty(Hive, Key->KeyCellOffset, FALSE);
707
708 /* Initialize value name string */
709 RtlInitUnicodeString(&ValueNameString, lpValueName);
710 if (!CmpFindNameInList(Hive,
711 &KeyNode->ValueList,
712 &ValueNameString,
713 &ChildIndex,
714 &CellIndex))
715 {
716 /* Sanity check */
717 ASSERT(CellIndex == HCELL_NIL);
718 /* Fail */
719 Status = STATUS_INSUFFICIENT_RESOURCES;
720 }
721 if (CellIndex == HCELL_NIL)
722 {
723 /* The value doesn't exist, create a new one */
724 Status = CmiAddValueKey(Key->RegistryHive,
725 KeyNode,
726 ChildIndex,
727 &ValueNameString,
728 &ValueCell,
729 &CellIndex);
730 }
731 else
732 {
733 /* The value already exists, use it. Get the value cell. */
734 ValueCell = HvGetCell(&Key->RegistryHive->Hive, CellIndex);
735 ASSERT(ValueCell != NULL);
736 Status = STATUS_SUCCESS;
737 }
738
739 // /**/HvReleaseCell(Hive, CellIndex);/**/
740
741 if (!NT_SUCCESS(Status))
742 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
743
744 /* Get size of the allocated cell (if any) */
745 if (!(ValueCell->DataLength & CM_KEY_VALUE_SPECIAL_SIZE) &&
746 (ValueCell->DataLength & ~CM_KEY_VALUE_SPECIAL_SIZE) != 0)
747 {
748 DataCell = HvGetCell(Hive, ValueCell->Data);
749 if (!DataCell)
750 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
751
752 DataCellSize = (ULONG)(-HvGetCellSize(Hive, DataCell));
753 }
754 else
755 {
756 DataCell = NULL;
757 DataCellSize = 0;
758 }
759
760 if (cbData <= sizeof(HCELL_INDEX))
761 {
762 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
763 DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
764 if (DataCell)
765 HvFreeCell(Hive, ValueCell->Data);
766
767 RtlCopyMemory(&ValueCell->Data, lpData, cbData);
768 ValueCell->DataLength = (cbData | CM_KEY_VALUE_SPECIAL_SIZE);
769 ValueCell->Type = dwType;
770 }
771 else
772 {
773 if (cbData > DataCellSize)
774 {
775 /* New data size is larger than the current, destroy current
776 * data block and allocate a new one. */
777 HCELL_INDEX NewOffset;
778
779 DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
780
781 NewOffset = HvAllocateCell(Hive, cbData, Stable, HCELL_NIL);
782 if (NewOffset == HCELL_NIL)
783 {
784 DPRINT("HvAllocateCell() has failed!\n");
785 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
786 }
787
788 if (DataCell)
789 HvFreeCell(Hive, ValueCell->Data);
790
791 ValueCell->Data = NewOffset;
792 DataCell = (PVOID)HvGetCell(Hive, NewOffset);
793 }
794
795 /* Copy new contents to cell */
796 RtlCopyMemory(DataCell, lpData, cbData);
797 ValueCell->DataLength = (cbData & ~CM_KEY_VALUE_SPECIAL_SIZE);
798 ValueCell->Type = dwType;
799 HvMarkCellDirty(Hive, ValueCell->Data, FALSE);
800 }
801
802 HvMarkCellDirty(Hive, CellIndex, FALSE);
803
804 /* Check if the maximum value name length changed, update it if so */
805 if (KeyNode->MaxValueNameLen < ValueNameString.Length)
806 KeyNode->MaxValueNameLen = ValueNameString.Length;
807
808 /* Check if the maximum data length changed, update it if so */
809 if (KeyNode->MaxValueDataLen < cbData)
810 KeyNode->MaxValueDataLen = cbData;
811
812 /* Save the write time */
813 KeQuerySystemTime(&KeyNode->LastWriteTime);
814
815 return ERROR_SUCCESS;
816 }
817
818
819 // Synced with freeldr/ntldr/registry.c
820 static
821 VOID
822 RepGetValueData(
823 IN PHHIVE Hive,
824 IN PCM_KEY_VALUE ValueCell,
825 OUT PULONG Type OPTIONAL,
826 OUT PUCHAR Data OPTIONAL,
827 IN OUT PULONG DataSize OPTIONAL)
828 {
829 ULONG DataLength;
830 PVOID DataCell;
831
832 /* Does the caller want the type? */
833 if (Type != NULL)
834 *Type = ValueCell->Type;
835
836 /* Does the caller provide DataSize? */
837 if (DataSize != NULL)
838 {
839 // NOTE: CmpValueToData doesn't support big data (the function will
840 // bugcheck if so), FreeLdr is not supposed to read such data.
841 // If big data is needed, use instead CmpGetValueData.
842 // CmpGetValueData(Hive, ValueCell, DataSize, &DataCell, ...);
843 DataCell = CmpValueToData(Hive, ValueCell, &DataLength);
844
845 /* Does the caller want the data? */
846 if ((Data != NULL) && (*DataSize != 0))
847 {
848 RtlCopyMemory(Data,
849 DataCell,
850 min(*DataSize, DataLength));
851 }
852
853 /* Return the actual data length */
854 *DataSize = DataLength;
855 }
856 }
857
858 // Similar to RegQueryValue in freeldr/ntldr/registry.c
859 LONG WINAPI
860 RegQueryValueExW(
861 IN HKEY hKey,
862 IN LPCWSTR lpValueName,
863 IN PULONG lpReserved,
864 OUT PULONG lpType OPTIONAL,
865 OUT PUCHAR lpData OPTIONAL,
866 IN OUT PULONG lpcbData OPTIONAL)
867 {
868 PMEMKEY ParentKey = HKEY_TO_MEMKEY(hKey);
869 PHHIVE Hive = &ParentKey->RegistryHive->Hive;
870 PCM_KEY_NODE KeyNode;
871 PCM_KEY_VALUE ValueCell;
872 HCELL_INDEX CellIndex;
873 UNICODE_STRING ValueNameString;
874
875 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey->KeyCellOffset);
876 if (!KeyNode)
877 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
878
879 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
880
881 /* Initialize value name string */
882 RtlInitUnicodeString(&ValueNameString, lpValueName);
883 CellIndex = CmpFindValueByName(Hive, KeyNode, &ValueNameString);
884 if (CellIndex == HCELL_NIL)
885 return ERROR_FILE_NOT_FOUND; // STATUS_OBJECT_NAME_NOT_FOUND;
886
887 /* Get the value cell */
888 ValueCell = HvGetCell(Hive, CellIndex);
889 ASSERT(ValueCell != NULL);
890
891 RepGetValueData(Hive, ValueCell, lpType, lpData, lpcbData);
892
893 HvReleaseCell(Hive, CellIndex);
894
895 return ERROR_SUCCESS;
896 }
897
898 LONG WINAPI
899 RegDeleteValueW(
900 IN HKEY hKey,
901 IN LPCWSTR lpValueName OPTIONAL)
902 {
903 LONG rc;
904 NTSTATUS Status;
905 PMEMKEY Key = HKEY_TO_MEMKEY(hKey); // ParentKey
906 PHHIVE Hive = &Key->RegistryHive->Hive;
907 PCM_KEY_NODE KeyNode; // ParentNode
908 PCM_KEY_VALUE ValueCell;
909 HCELL_INDEX CellIndex;
910 ULONG ChildIndex;
911 UNICODE_STRING ValueNameString;
912
913 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Key->KeyCellOffset);
914 if (!KeyNode)
915 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
916
917 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
918
919 /* Initialize value name string */
920 RtlInitUnicodeString(&ValueNameString, lpValueName);
921 if (!CmpFindNameInList(Hive,
922 &KeyNode->ValueList,
923 &ValueNameString,
924 &ChildIndex,
925 &CellIndex))
926 {
927 /* Sanity check */
928 ASSERT(CellIndex == HCELL_NIL);
929 }
930 if (CellIndex == HCELL_NIL)
931 {
932 rc = ERROR_FILE_NOT_FOUND; // STATUS_OBJECT_NAME_NOT_FOUND;
933 goto Quit;
934 }
935
936 /* We found the value, mark all relevant cells dirty */
937 HvMarkCellDirty(Hive, Key->KeyCellOffset, FALSE);
938 HvMarkCellDirty(Hive, KeyNode->ValueList.List, FALSE);
939 HvMarkCellDirty(Hive, CellIndex, FALSE);
940
941 /* Get the key value */
942 ValueCell = (PCM_KEY_VALUE)HvGetCell(Hive, CellIndex);
943 ASSERT(ValueCell);
944
945 /* Mark it and all related data as dirty */
946 if (!CmpMarkValueDataDirty(Hive, ValueCell))
947 {
948 /* Not enough log space, fail */
949 rc = ERROR_NO_LOG_SPACE; // STATUS_NO_LOG_SPACE;
950 goto Quit;
951 }
952
953 /* Sanity checks */
954 ASSERT(HvIsCellDirty(Hive, KeyNode->ValueList.List));
955 ASSERT(HvIsCellDirty(Hive, CellIndex));
956
957 /* Remove the value from the child list */
958 Status = CmpRemoveValueFromList(Hive, ChildIndex, &KeyNode->ValueList);
959 if (!NT_SUCCESS(Status))
960 {
961 /* Set known error */
962 rc = ERROR_NO_SYSTEM_RESOURCES; // STATUS_INSUFFICIENT_RESOURCES;
963 goto Quit;
964 }
965
966 /* Remove the value and its data itself */
967 if (!CmpFreeValue(Hive, CellIndex))
968 {
969 /* Failed to free the value, fail */
970 rc = ERROR_NO_SYSTEM_RESOURCES; // STATUS_INSUFFICIENT_RESOURCES;
971 goto Quit;
972 }
973
974 /* Set the last write time */
975 KeQuerySystemTime(&KeyNode->LastWriteTime);
976
977 /* Sanity check */
978 ASSERT(HvIsCellDirty(Hive, Key->KeyCellOffset));
979
980 /* Check if the value list is empty now */
981 if (!KeyNode->ValueList.Count)
982 {
983 /* Then clear key node data */
984 KeyNode->MaxValueNameLen = 0;
985 KeyNode->MaxValueDataLen = 0;
986 }
987
988 /* Change default Status to success */
989 rc = ERROR_SUCCESS;
990
991 Quit:
992 /* Check if we had a value */
993 if (ValueCell)
994 {
995 /* Release the child cell */
996 ASSERT(CellIndex != HCELL_NIL);
997 HvReleaseCell(Hive, CellIndex);
998 }
999
1000 /* Release the parent cell, if any */
1001 if (KeyNode)
1002 HvReleaseCell(Hive, Key->KeyCellOffset);
1003
1004 return rc;
1005 }
1006
1007
1008 static BOOL
1009 ConnectRegistry(
1010 IN HKEY RootKey,
1011 IN PCMHIVE HiveToConnect,
1012 IN PUCHAR SecurityDescriptor,
1013 IN ULONG SecurityDescriptorLength,
1014 IN PCWSTR Path)
1015 {
1016 NTSTATUS Status;
1017 LONG rc;
1018 PREPARSE_POINT ReparsePoint;
1019 PMEMKEY NewKey;
1020
1021 ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
1022 if (!ReparsePoint)
1023 return FALSE;
1024
1025 /*
1026 * Use a dummy root key name:
1027 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
1028 * - On Vista+, this is "CMI-CreateHive{guid}"
1029 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
1030 * for more information.
1031 */
1032 Status = CmiInitializeHive(HiveToConnect, L"$$$PROTO.HIV");
1033 if (!NT_SUCCESS(Status))
1034 {
1035 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status);
1036 free(ReparsePoint);
1037 return FALSE;
1038 }
1039
1040 /*
1041 * Add security to the root key.
1042 * NOTE: One can implement this using the lpSecurityAttributes
1043 * parameter of RegCreateKeyExW.
1044 */
1045 Status = CmiCreateSecurityKey(&HiveToConnect->Hive,
1046 HiveToConnect->Hive.BaseBlock->RootCell,
1047 SecurityDescriptor, SecurityDescriptorLength);
1048 if (!NT_SUCCESS(Status))
1049 DPRINT1("Failed to add security for root key '%S'\n", Path);
1050
1051 /* Create the key */
1052 rc = RegCreateKeyExW(RootKey,
1053 Path,
1054 0,
1055 NULL,
1056 REG_OPTION_VOLATILE,
1057 0,
1058 NULL,
1059 (PHKEY)&NewKey,
1060 NULL);
1061 if (rc != ERROR_SUCCESS)
1062 {
1063 free(ReparsePoint);
1064 return FALSE;
1065 }
1066
1067 ReparsePoint->SourceHive = NewKey->RegistryHive;
1068 ReparsePoint->SourceKeyCellOffset = NewKey->KeyCellOffset;
1069 NewKey->RegistryHive = HiveToConnect;
1070 NewKey->KeyCellOffset = HiveToConnect->Hive.BaseBlock->RootCell;
1071 ReparsePoint->DestinationHive = NewKey->RegistryHive;
1072 ReparsePoint->DestinationKeyCellOffset = NewKey->KeyCellOffset;
1073 InsertTailList(&CmiReparsePointsHead, &ReparsePoint->ListEntry);
1074
1075 return TRUE;
1076 }
1077
1078 static BOOL
1079 CreateSymLink(
1080 IN PCWSTR LinkKeyPath OPTIONAL,
1081 IN OUT PHKEY LinkKeyHandle OPTIONAL,
1082 // IN PCWSTR TargetKeyPath OPTIONAL,
1083 IN HKEY TargetKeyHandle)
1084 {
1085 LONG rc;
1086 PMEMKEY LinkKey, TargetKey;
1087 PREPARSE_POINT ReparsePoint;
1088
1089 ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
1090 if (!ReparsePoint)
1091 return FALSE;
1092
1093 if (LinkKeyPath && !(LinkKeyHandle && *LinkKeyHandle))
1094 {
1095 /* Create the link key */
1096 rc = RegCreateKeyExW(NULL,
1097 LinkKeyPath,
1098 0,
1099 NULL,
1100 REG_OPTION_VOLATILE,
1101 0,
1102 NULL,
1103 (PHKEY)&LinkKey,
1104 NULL);
1105 if (rc != ERROR_SUCCESS)
1106 {
1107 free(ReparsePoint);
1108 return FALSE;
1109 }
1110 }
1111 else if (LinkKeyHandle)
1112 {
1113 /* Use the user-provided link key handle */
1114 LinkKey = HKEY_TO_MEMKEY(*LinkKeyHandle);
1115 }
1116
1117 if (LinkKeyHandle)
1118 *LinkKeyHandle = MEMKEY_TO_HKEY(LinkKey);
1119
1120 TargetKey = HKEY_TO_MEMKEY(TargetKeyHandle);
1121
1122 ReparsePoint->SourceHive = LinkKey->RegistryHive;
1123 ReparsePoint->SourceKeyCellOffset = LinkKey->KeyCellOffset;
1124 ReparsePoint->DestinationHive = TargetKey->RegistryHive;
1125 ReparsePoint->DestinationKeyCellOffset = TargetKey->KeyCellOffset;
1126 InsertTailList(&CmiReparsePointsHead, &ReparsePoint->ListEntry);
1127
1128 return TRUE;
1129 }
1130
1131 VOID
1132 RegInitializeRegistry(
1133 IN PCSTR HiveList)
1134 {
1135 NTSTATUS Status;
1136 UINT i;
1137 HKEY ControlSetKey;
1138
1139 InitializeListHead(&CmiHiveListHead);
1140 InitializeListHead(&CmiReparsePointsHead);
1141
1142 Status = CmiInitializeHive(&RootHive, L"");
1143 if (!NT_SUCCESS(Status))
1144 {
1145 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status);
1146 return;
1147 }
1148
1149 RootKey = CreateInMemoryStructure(&RootHive,
1150 RootHive.Hive.BaseBlock->RootCell);
1151
1152 for (i = 0; i < _countof(RegistryHives); ++i)
1153 {
1154 /* Skip this registry hive if it's not in the list */
1155 if (!strstr(HiveList, RegistryHives[i].HiveName))
1156 continue;
1157
1158 /* Create the registry key */
1159 ConnectRegistry(NULL,
1160 RegistryHives[i].CmHive,
1161 RegistryHives[i].SecurityDescriptor,
1162 RegistryHives[i].SecurityDescriptorLength,
1163 RegistryHives[i].HiveRegistryPath);
1164
1165 /* If we happen to deal with the special setup registry hive, stop there */
1166 // if (strcmp(RegistryHives[i].HiveName, "SETUPREG") == 0)
1167 if (i == 0)
1168 break;
1169 }
1170
1171 /* Create the 'ControlSet001' key */
1172 RegCreateKeyW(NULL,
1173 L"Registry\\Machine\\SYSTEM\\ControlSet001",
1174 &ControlSetKey);
1175
1176 /* Create the 'CurrentControlSet' key as a symlink to 'ControlSet001' */
1177 CreateSymLink(L"Registry\\Machine\\SYSTEM\\CurrentControlSet",
1178 NULL, ControlSetKey);
1179
1180 RegCloseKey(ControlSetKey);
1181
1182 #if 0
1183 /* Link SECURITY to SAM */
1184 CmpLinkKeyToHive(L"\\Registry\\Machine\\Security\\SAM", L"\\Registry\\Machine\\SAM\\SAM");
1185 /* Link S-1-5-18 to .Default */
1186 CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18", L"\\Registry\\User\\.Default");
1187 #endif
1188 }
1189
1190 VOID
1191 RegShutdownRegistry(VOID)
1192 {
1193 PLIST_ENTRY Entry;
1194 PREPARSE_POINT ReparsePoint;
1195
1196 /* Clean up the reparse points list */
1197 while (!IsListEmpty(&CmiReparsePointsHead))
1198 {
1199 Entry = RemoveHeadList(&CmiReparsePointsHead);
1200 ReparsePoint = CONTAINING_RECORD(Entry, REPARSE_POINT, ListEntry);
1201 free(ReparsePoint);
1202 }
1203
1204 /* FIXME: clean up the complete hive */
1205
1206 free(RootKey);
1207 }
1208
1209 /* EOF */