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