xref: /reactos/sdk/tools/mkhive/registry.c (revision f4d29a74)
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 // These SECURITY_DESCRIPTORs were obtained by dumping the security block "sk"
70 // of registry hives created by setting their permissions to be the same as
71 // the ones of the BCD, SOFTWARE, or SYSTEM, SAM and .DEFAULT system hives.
72 // A cross-check was subsequently done with the system hives to verify that
73 // the security descriptors were the same.
74 //
75 static UCHAR BcdSecurity[] =
76 {
77     // SECURITY_DESCRIPTOR_RELATIVE
78     0x01,                   // Revision
79     0x00,                   // Sbz1
80     0x04, 0x94,             // Control: SE_SELF_RELATIVE        (0x8000) |
81                             //          SE_DACL_PROTECTED       (0x1000) |
82                             //          SE_DACL_AUTO_INHERITED  (0x0400) |
83                             //          SE_DACL_PRESENT         (0x0004)
84     0x48, 0x00, 0x00, 0x00, // Owner
85     0x58, 0x00, 0x00, 0x00, // Group
86     0x00, 0x00, 0x00, 0x00, // Sacl (None)
87     0x14, 0x00, 0x00, 0x00, // Dacl
88 
89     // DACL
90     0x02,       // AclRevision
91     0x00,       // Sbz1
92     0x34, 0x00, // AclSize
93     0x02, 0x00, // AceCount
94     0x00, 0x00, // Sbz2
95 
96     // (1st ACE)
97     0x00,                   // AceType : ACCESS_ALLOWED_ACE_TYPE
98     0x02,                   // AceFlags: CONTAINER_INHERIT_ACE
99     0x18, 0x00,             // AceSize
100     0x19, 0x00, 0x06, 0x00, // ACCESS_MASK: "Write DAC"         (0x00040000) |
101                             //              "Read Control"      (0x00020000) |
102                             //              "Notify"            (0x00000010) |
103                             //              "Enumerate Subkeys" (0x00000008) |
104                             //              "Query Value"       (0x00000001)
105     // (SidStart: S-1-5-32-544 "Administrators")
106     0x01, 0x02, 0x00, 0x00,
107     0x00, 0x00, 0x00, 0x05,
108     0x20, 0x00, 0x00, 0x00,
109     0x20, 0x02, 0x00, 0x00,
110 
111     // (2nd ACE)
112     0x00,                   // AceType : ACCESS_ALLOWED_ACE_TYPE
113     0x02,                   // AceFlags: CONTAINER_INHERIT_ACE
114     0x14, 0x00,             // AceSize
115     0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
116     // (SidStart: S-1-5-18 "Local System")
117     0x01, 0x01, 0x00, 0x00,
118     0x00, 0x00, 0x00, 0x05,
119     0x12, 0x00, 0x00, 0x00,
120 
121     // Owner SID (S-1-5-32-544 "Administrators")
122     0x01, 0x02, 0x00, 0x00,
123     0x00, 0x00, 0x00, 0x05,
124     0x20, 0x00, 0x00, 0x00,
125     0x20, 0x02, 0x00, 0x00,
126 
127     // Group SID (S-1-5-21-domain-513 "Domain Users")
128     0x01, 0x05, 0x00, 0x00,
129     0x00, 0x00, 0x00, 0x05,
130     0x15, 0x00, 0x00, 0x00,
131     0xAC, 0xD0, 0x49, 0xCB,
132     0xE6, 0x52, 0x47, 0x9C,
133     0xE4, 0x31, 0xDB, 0x5C,
134     0x01, 0x02, 0x00, 0x00
135 };
136 
137 static UCHAR SoftwareSecurity[] =
138 {
139     // SECURITY_DESCRIPTOR_RELATIVE
140     0x01,                   // Revision
141     0x00,                   // Sbz1
142     0x04, 0x94,             // Control: SE_SELF_RELATIVE        (0x8000) |
143                             //          SE_DACL_PROTECTED       (0x1000) |
144                             //          SE_DACL_AUTO_INHERITED  (0x0400) |
145                             //          SE_DACL_PRESENT         (0x0004)
146     0xA0, 0x00, 0x00, 0x00, // Owner
147     0xB0, 0x00, 0x00, 0x00, // Group
148     0x00, 0x00, 0x00, 0x00, // Sacl (None)
149     0x14, 0x00, 0x00, 0x00, // Dacl
150 
151     // DACL
152     0x02,       // AclRevision
153     0x00,       // Sbz1
154     0x8C, 0x00, // AclSize
155     0x06, 0x00, // AceCount
156     0x00, 0x00, // Sbz2
157 
158     // (1st ACE)
159     0x00,                   // AceType : ACCESS_ALLOWED_ACE_TYPE
160     0x02,                   // AceFlags: CONTAINER_INHERIT_ACE
161     0x18, 0x00,             // AceSize
162     0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
163     // (SidStart: S-1-5-32-544 "Administrators")
164     0x01, 0x02, 0x00, 0x00,
165     0x00, 0x00, 0x00, 0x05,
166     0x20, 0x00, 0x00, 0x00,
167     0x20, 0x02, 0x00, 0x00,
168 
169     // (2nd ACE)
170     0x00,                   // AceType : ACCESS_ALLOWED_ACE_TYPE
171     0x0A,                   // AceFlags: INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE
172     0x14, 0x00,             // AceSize
173     0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
174     // (SidStart: S-1-3-0 "Creator Owner")
175     0x01, 0x01, 0x00, 0x00,
176     0x00, 0x00, 0x00, 0x03,
177     0x00, 0x00, 0x00, 0x00,
178 
179     // (3rd ACE)
180     0x00,                   // AceType : ACCESS_ALLOWED_ACE_TYPE
181     0x02,                   // AceFlags: CONTAINER_INHERIT_ACE
182     0x14, 0x00,             // AceSize
183     0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
184     // (SidStart: S-1-5-18 "Local System")
185     0x01, 0x01, 0x00, 0x00,
186     0x00, 0x00, 0x00, 0x05,
187     0x12, 0x00, 0x00, 0x00,
188 
189     // (4th ACE)
190     0x00,                   // AceType : ACCESS_ALLOWED_ACE_TYPE
191     0x02,                   // AceFlags: CONTAINER_INHERIT_ACE
192     0x14, 0x00,             // AceSize
193     0x1F, 0x00, 0x03, 0x00, // ACCESS_MASK: "Read Control"      (0x00020000) |
194                             //              "Delete"            (0x00010000) |
195                             //              "Notify"            (0x00000010) |
196                             //              "Enumerate Subkeys" (0x00000008) |
197                             //              "Create Subkey"     (0x00000004) |
198                             //              "Set Value"         (0x00000002) |
199                             //              "Query Value"       (0x00000001)
200     // (SidStart: S-1-5-13 "Terminal Server Users")
201     0x01, 0x01, 0x00, 0x00,
202     0x00, 0x00, 0x00, 0x05,
203     0x0D, 0x00, 0x00, 0x00,
204 
205     // (5th ACE)
206     0x00,                   // AceType : ACCESS_ALLOWED_ACE_TYPE
207     0x02,                   // AceFlags: CONTAINER_INHERIT_ACE
208     0x18, 0x00,             // AceSize
209     0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control"      (0x00020000) |
210                             //              "Notify"            (0x00000010) |
211                             //              "Enumerate Subkeys" (0x00000008) |
212                             //              "Query Value"       (0x00000001)
213     // (SidStart: S-1-5-32-545 "Users")
214     0x01, 0x02, 0x00, 0x00,
215     0x00, 0x00, 0x00, 0x05,
216     0x20, 0x00, 0x00, 0x00,
217     0x21, 0x02, 0x00, 0x00,
218 
219     // (6th ACE)
220     0x00,                   // AceType : ACCESS_ALLOWED_ACE_TYPE
221     0x02,                   // AceFlags: CONTAINER_INHERIT_ACE
222     0x18, 0x00,             // AceSize
223     0x1F, 0x00, 0x03, 0x00, // ACCESS_MASK: "Read Control"      (0x00020000) |
224                             //              "Delete"            (0x00010000) |
225                             //              "Notify"            (0x00000010) |
226                             //              "Enumerate Subkeys" (0x00000008) |
227                             //              "Create Subkey"     (0x00000004) |
228                             //              "Set Value"         (0x00000002) |
229                             //              "Query Value"       (0x00000001)
230     // (SidStart: S-1-5-32-547 "Power Users")
231     0x01, 0x02, 0x00, 0x00,
232     0x00, 0x00, 0x00, 0x05,
233     0x20, 0x00, 0x00, 0x00,
234     0x23, 0x02, 0x00, 0x00,
235 
236     // Owner SID (S-1-5-32-544 "Administrators")
237     0x01, 0x02, 0x00, 0x00,
238     0x00, 0x00, 0x00, 0x05,
239     0x20, 0x00, 0x00, 0x00,
240     0x20, 0x02, 0x00, 0x00,
241 
242     // Group SID (S-1-5-21-domain-513 "Domain Users")
243     0x01, 0x05, 0x00, 0x00,
244     0x00, 0x00, 0x00, 0x05,
245     0x15, 0x00, 0x00, 0x00,
246     0xAC, 0xD0, 0x49, 0xCB,
247     0xE6, 0x52, 0x47, 0x9C,
248     0xE4, 0x31, 0xDB, 0x5C,
249     0x01, 0x02, 0x00, 0x00
250 };
251 
252 // Same security for SYSTEM, SAM and .DEFAULT
253 static UCHAR SystemSecurity[] =
254 {
255     // SECURITY_DESCRIPTOR_RELATIVE
256     0x01,                   // Revision
257     0x00,                   // Sbz1
258     0x04, 0x94,             // Control: SE_SELF_RELATIVE        (0x8000) |
259                             //          SE_DACL_PROTECTED       (0x1000) |
260                             //          SE_DACL_AUTO_INHERITED  (0x0400) |
261                             //          SE_DACL_PRESENT         (0x0004)
262     0x8C, 0x00, 0x00, 0x00, // Owner
263     0x9C, 0x00, 0x00, 0x00, // Group
264     0x00, 0x00, 0x00, 0x00, // Sacl (None)
265     0x14, 0x00, 0x00, 0x00, // Dacl
266 
267     // DACL
268     0x02,       // AclRevision
269     0x00,       // Sbz1
270     0x78, 0x00, // AclSize
271     0x05, 0x00, // AceCount
272     0x00, 0x00, // Sbz2
273 
274     // (1st ACE)
275     0x00,                   // AceType : ACCESS_ALLOWED_ACE_TYPE
276     0x02,                   // AceFlags: CONTAINER_INHERIT_ACE
277     0x18, 0x00,             // AceSize
278     0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
279     // (SidStart: S-1-5-32-544 "Administrators")
280     0x01, 0x02, 0x00, 0x00,
281     0x00, 0x00, 0x00, 0x05,
282     0x20, 0x00, 0x00, 0x00,
283     0x20, 0x02, 0x00, 0x00,
284 
285     // (2nd ACE)
286     0x00,                   // AceType : ACCESS_ALLOWED_ACE_TYPE
287     0x0A,                   // AceFlags: INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE
288     0x14, 0x00,             // AceSize
289     0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
290     // (SidStart: S-1-3-0 "Creator Owner")
291     0x01, 0x01, 0x00, 0x00,
292     0x00, 0x00, 0x00, 0x03,
293     0x00, 0x00, 0x00, 0x00,
294 
295     // (3rd ACE)
296     0x00,                   // AceType : ACCESS_ALLOWED_ACE_TYPE
297     0x02,                   // AceFlags: CONTAINER_INHERIT_ACE
298     0x14, 0x00,             // AceSize
299     0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
300     // (SidStart: S-1-5-18 "Local System")
301     0x01, 0x01, 0x00, 0x00,
302     0x00, 0x00, 0x00, 0x05,
303     0x12, 0x00, 0x00, 0x00,
304 
305     // (4th ACE)
306     0x00,                   // AceType : ACCESS_ALLOWED_ACE_TYPE
307     0x02,                   // AceFlags: CONTAINER_INHERIT_ACE
308     0x18, 0x00,             // AceSize
309     0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control"      (0x00020000) |
310                             //              "Notify"            (0x00000010) |
311                             //              "Enumerate Subkeys" (0x00000008) |
312                             //              "Query Value"       (0x00000001)
313     // (SidStart: S-1-5-32-545 "Users")
314     0x01, 0x02, 0x00, 0x00,
315     0x00, 0x00, 0x00, 0x05,
316     0x20, 0x00, 0x00, 0x00,
317     0x21, 0x02, 0x00, 0x00,
318 
319     // (5th ACE)
320     0x00,                   // AceType : ACCESS_ALLOWED_ACE_TYPE
321     0x02,                   // AceFlags: CONTAINER_INHERIT_ACE
322     0x18, 0x00,             // AceSize
323     0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control"      (0x00020000) |
324                             //              "Notify"            (0x00000010) |
325                             //              "Enumerate Subkeys" (0x00000008) |
326                             //              "Query Value"       (0x00000001)
327     // (SidStart: S-1-5-32-547 "Power Users")
328     0x01, 0x02, 0x00, 0x00,
329     0x00, 0x00, 0x00, 0x05,
330     0x20, 0x00, 0x00, 0x00,
331     0x23, 0x02, 0x00, 0x00,
332 
333     // Owner SID (S-1-5-32-544 "Administrators")
334     0x01, 0x02, 0x00, 0x00,
335     0x00, 0x00, 0x00, 0x05,
336     0x20, 0x00, 0x00, 0x00,
337     0x20, 0x02, 0x00, 0x00,
338 
339     // Group SID (S-1-5-21-domain-513 "Domain Users")
340     0x01, 0x05, 0x00, 0x00,
341     0x00, 0x00, 0x00, 0x05,
342     0x15, 0x00, 0x00, 0x00,
343     0xAC, 0xD0, 0x49, 0xCB,
344     0xE6, 0x52, 0x47, 0x9C,
345     0xE4, 0x31, 0xDB, 0x5C,
346     0x01, 0x02, 0x00, 0x00
347 };
348 
349 /* GLOBALS ******************************************************************/
350 
351 HIVE_LIST_ENTRY RegistryHives[/*MAX_NUMBER_OF_REGISTRY_HIVES*/] =
352 {
353     /* Special Setup system registry hive */
354     // WARNING: Please *keep* it in first position!
355     { "SETUPREG", L"Registry\\Machine\\SYSTEM"     , &SystemHive  , SystemSecurity  , sizeof(SystemSecurity)   },
356 
357     /* Regular registry hives */
358     { "SYSTEM"  , L"Registry\\Machine\\SYSTEM"     , &SystemHive  , SystemSecurity  , sizeof(SystemSecurity)   },
359     { "SOFTWARE", L"Registry\\Machine\\SOFTWARE"   , &SoftwareHive, SoftwareSecurity, sizeof(SoftwareSecurity) },
360     { "DEFAULT" , L"Registry\\User\\.DEFAULT"      , &DefaultHive , SystemSecurity  , sizeof(SystemSecurity)   },
361     { "SAM"     , L"Registry\\Machine\\SAM"        , &SamHive     , SystemSecurity  , sizeof(SystemSecurity)   },
362     { "SECURITY", L"Registry\\Machine\\SECURITY"   , &SecurityHive, NULL            , 0                        },
363     { "BCD"     , L"Registry\\Machine\\BCD00000000", &BcdHive     , BcdSecurity     , sizeof(BcdSecurity)      },
364 };
365 C_ASSERT(_countof(RegistryHives) == MAX_NUMBER_OF_REGISTRY_HIVES);
366 
367 /* FUNCTIONS ****************************************************************/
368 
369 static PMEMKEY
370 CreateInMemoryStructure(
371     IN PCMHIVE RegistryHive,
372     IN HCELL_INDEX KeyCellOffset)
373 {
374     PMEMKEY Key;
375 
376     Key = (PMEMKEY)malloc(sizeof(MEMKEY));
377     if (!Key)
378         return NULL;
379 
380     Key->RegistryHive = RegistryHive;
381     Key->KeyCellOffset = KeyCellOffset;
382     return Key;
383 }
384 
385 LIST_ENTRY CmiHiveListHead;
386 LIST_ENTRY CmiReparsePointsHead;
387 
388 static LONG
389 RegpCreateOrOpenKey(
390     IN HKEY hParentKey,
391     IN PCWSTR KeyName,
392     IN BOOL AllowCreation,
393     IN BOOL Volatile,
394     OUT PHKEY Key)
395 {
396     NTSTATUS Status;
397     PWSTR LocalKeyName;
398     PWSTR End;
399     UNICODE_STRING KeyString;
400     PREPARSE_POINT CurrentReparsePoint;
401     PMEMKEY CurrentKey;
402     PCMHIVE ParentRegistryHive;
403     HCELL_INDEX ParentCellOffset;
404     PCM_KEY_NODE ParentKeyCell;
405     PLIST_ENTRY Ptr;
406     HCELL_INDEX BlockOffset;
407 
408     DPRINT("RegpCreateOrOpenKey('%S')\n", KeyName);
409 
410     if (*KeyName == OBJ_NAME_PATH_SEPARATOR)
411     {
412         KeyName++;
413         ParentRegistryHive = RootKey->RegistryHive;
414         ParentCellOffset = RootKey->KeyCellOffset;
415     }
416     else if (hParentKey == NULL)
417     {
418         ParentRegistryHive = RootKey->RegistryHive;
419         ParentCellOffset = RootKey->KeyCellOffset;
420     }
421     else
422     {
423         ParentRegistryHive = HKEY_TO_MEMKEY(hParentKey)->RegistryHive;
424         ParentCellOffset = HKEY_TO_MEMKEY(hParentKey)->KeyCellOffset;
425     }
426 
427     LocalKeyName = (PWSTR)KeyName;
428     for (;;)
429     {
430         End = (PWSTR)strchrW(LocalKeyName, OBJ_NAME_PATH_SEPARATOR);
431         if (End)
432         {
433             KeyString.Buffer = LocalKeyName;
434             KeyString.Length = KeyString.MaximumLength =
435                 (USHORT)((ULONG_PTR)End - (ULONG_PTR)LocalKeyName);
436         }
437         else
438         {
439             RtlInitUnicodeString(&KeyString, LocalKeyName);
440             if (KeyString.Length == 0)
441             {
442                 /* Trailing path separator: we're done */
443                 break;
444             }
445         }
446 
447         ParentKeyCell = (PCM_KEY_NODE)HvGetCell(&ParentRegistryHive->Hive, ParentCellOffset);
448         if (!ParentKeyCell)
449             return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
450 
451         VERIFY_KEY_CELL(ParentKeyCell);
452 
453         BlockOffset = CmpFindSubKeyByName(&ParentRegistryHive->Hive, ParentKeyCell, &KeyString);
454         if (BlockOffset != HCELL_NIL)
455         {
456             Status = STATUS_SUCCESS;
457 
458             /* Search for a possible reparse point */
459             Ptr = CmiReparsePointsHead.Flink;
460             while (Ptr != &CmiReparsePointsHead)
461             {
462                 CurrentReparsePoint = CONTAINING_RECORD(Ptr, REPARSE_POINT, ListEntry);
463                 if (CurrentReparsePoint->SourceHive == ParentRegistryHive &&
464                     CurrentReparsePoint->SourceKeyCellOffset == BlockOffset)
465                 {
466                     ParentRegistryHive = CurrentReparsePoint->DestinationHive;
467                     BlockOffset = CurrentReparsePoint->DestinationKeyCellOffset;
468                     break;
469                 }
470                 Ptr = Ptr->Flink;
471             }
472         }
473         else if (AllowCreation) // && (BlockOffset == HCELL_NIL)
474         {
475             Status = CmiAddSubKey(ParentRegistryHive,
476                                   ParentCellOffset,
477                                   &KeyString,
478                                   Volatile,
479                                   &BlockOffset);
480         }
481         else // if (BlockOffset == HCELL_NIL)
482         {
483             Status = STATUS_OBJECT_NAME_NOT_FOUND;
484         }
485 
486         HvReleaseCell(&ParentRegistryHive->Hive, ParentCellOffset);
487 
488         if (!NT_SUCCESS(Status))
489         {
490             DPRINT("RegpCreateOrOpenKey('%S'): Could not create or open subkey '%.*S', Status 0x%08x\n",
491                    KeyName, (int)(KeyString.Length / sizeof(WCHAR)), KeyString.Buffer, Status);
492             return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
493         }
494 
495         ParentCellOffset = BlockOffset;
496         if (End)
497             LocalKeyName = End + 1;
498         else
499             break;
500     }
501 
502     CurrentKey = CreateInMemoryStructure(ParentRegistryHive, ParentCellOffset);
503     if (!CurrentKey)
504         return ERROR_NOT_ENOUGH_MEMORY; // STATUS_NO_MEMORY;
505 
506     *Key = MEMKEY_TO_HKEY(CurrentKey);
507 
508     return ERROR_SUCCESS;
509 }
510 
511 LONG WINAPI
512 RegCloseKey(
513     IN HKEY hKey)
514 {
515     PMEMKEY Key = HKEY_TO_MEMKEY(hKey); // ParentKey
516 
517     /* Free the object */
518     free(Key);
519 
520     return ERROR_SUCCESS;
521 }
522 
523 LONG WINAPI
524 RegCreateKeyW(
525     IN HKEY hKey,
526     IN LPCWSTR lpSubKey,
527     OUT PHKEY phkResult)
528 {
529     return RegpCreateOrOpenKey(hKey, lpSubKey, TRUE, FALSE, phkResult);
530 }
531 
532 LONG WINAPI
533 RegCreateKeyExW(
534     IN HKEY hKey,
535     IN LPCWSTR lpSubKey,
536     IN DWORD Reserved,
537     IN LPWSTR lpClass OPTIONAL,
538     IN DWORD dwOptions,
539     IN REGSAM samDesired,
540     IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL,
541     OUT PHKEY phkResult,
542     OUT LPDWORD lpdwDisposition OPTIONAL)
543 {
544     return RegpCreateOrOpenKey(hKey,
545                                lpSubKey,
546                                TRUE,
547                                (dwOptions & REG_OPTION_VOLATILE) != 0,
548                                phkResult);
549 }
550 
551 LONG WINAPI
552 RegDeleteKeyW(
553     IN HKEY hKey,
554     IN LPCWSTR lpSubKey)
555 {
556     LONG rc;
557     NTSTATUS Status;
558     HKEY hTargetKey;
559     PMEMKEY Key; // ParentKey
560     PHHIVE Hive;
561     PCM_KEY_NODE KeyNode; // ParentNode
562     PCM_KEY_NODE Parent;
563     HCELL_INDEX ParentCell;
564 
565     if (lpSubKey)
566     {
567         rc = RegOpenKeyW(hKey, lpSubKey, &hTargetKey);
568         if (rc != ERROR_SUCCESS)
569             return rc;
570     }
571     else
572     {
573         hTargetKey = hKey;
574         rc = ERROR_SUCCESS;
575     }
576 
577     /* Don't allow deleting the root */
578     if (hTargetKey == RootKey)
579     {
580         /* Fail */
581         rc = ERROR_ACCESS_DENIED; // STATUS_CANNOT_DELETE;
582         goto Quit;
583     }
584 
585     /* Get the hive and node */
586     Key = HKEY_TO_MEMKEY(hTargetKey);
587     Hive = &Key->RegistryHive->Hive;
588 
589     /* Get the key node */
590     KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Key->KeyCellOffset);
591     if (!KeyNode)
592     {
593         rc = ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
594         goto Quit;
595     }
596 
597     ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
598 
599     /* Check if we don't have any children */
600     if (!(KeyNode->SubKeyCounts[Stable] + KeyNode->SubKeyCounts[Volatile]) &&
601         !(KeyNode->Flags & KEY_NO_DELETE))
602     {
603         /* Get the parent and free the cell */
604         ParentCell = KeyNode->Parent;
605         Status = CmpFreeKeyByCell(Hive, Key->KeyCellOffset, TRUE);
606         if (NT_SUCCESS(Status))
607         {
608             /* Get the parent node */
609             Parent = (PCM_KEY_NODE)HvGetCell(Hive, ParentCell);
610             if (Parent)
611             {
612                 /* Make sure we're dirty */
613                 ASSERT(HvIsCellDirty(Hive, ParentCell));
614 
615                 /* Update the write time */
616                 KeQuerySystemTime(&Parent->LastWriteTime);
617 
618                 /* Release the cell */
619                 HvReleaseCell(Hive, ParentCell);
620             }
621 
622             rc = ERROR_SUCCESS;
623         }
624         else
625         {
626             /* Fail */
627             rc = ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
628         }
629     }
630     else
631     {
632         /* Fail */
633         rc = ERROR_ACCESS_DENIED; // STATUS_CANNOT_DELETE;
634     }
635 
636     /* Release the cell */
637     HvReleaseCell(Hive, Key->KeyCellOffset);
638 
639 Quit:
640     if (lpSubKey)
641         RegCloseKey(hTargetKey);
642 
643     return rc;
644 }
645 
646 LONG WINAPI
647 RegOpenKeyW(
648     IN HKEY hKey,
649     IN LPCWSTR lpSubKey,
650     OUT PHKEY phkResult)
651 {
652     return RegpCreateOrOpenKey(hKey, lpSubKey, FALSE, FALSE, phkResult);
653 }
654 
655 LONG WINAPI
656 RegSetValueExW(
657     IN HKEY hKey,
658     IN LPCWSTR lpValueName OPTIONAL,
659     IN ULONG Reserved,
660     IN ULONG dwType,
661     IN const UCHAR* lpData,
662     IN ULONG cbData)
663 {
664     PMEMKEY Key = HKEY_TO_MEMKEY(hKey); // ParentKey
665     PHHIVE Hive;
666     PCM_KEY_NODE KeyNode; // ParentNode
667     PCM_KEY_VALUE ValueCell;
668     ULONG ChildIndex;
669     HCELL_INDEX CellIndex;
670     UNICODE_STRING ValueNameString;
671 
672     PVOID DataCell;
673     ULONG DataCellSize;
674     NTSTATUS Status;
675 
676     if (dwType == REG_LINK)
677     {
678         PMEMKEY DestKey;
679 
680         /* Special handling of registry links */
681         if (cbData != sizeof(PVOID))
682             return ERROR_INVALID_PARAMETER; // STATUS_INVALID_PARAMETER;
683 
684         DestKey = HKEY_TO_MEMKEY(*(PHKEY)lpData);
685 
686         // FIXME: Add additional checks for the validity of DestKey
687 
688         /* Create the link in registry hive (if applicable) */
689         if (Key->RegistryHive != DestKey->RegistryHive)
690             return ERROR_SUCCESS;
691 
692         DPRINT1("Save link to registry\n");
693         return ERROR_INVALID_FUNCTION; // STATUS_NOT_IMPLEMENTED;
694     }
695 
696     if ((cbData & ~CM_KEY_VALUE_SPECIAL_SIZE) != cbData)
697         return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
698 
699     Hive = &Key->RegistryHive->Hive;
700 
701     KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Key->KeyCellOffset);
702     if (!KeyNode)
703         return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
704 
705     ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
706 
707     /* Mark the parent as dirty since we are going to create a new value in it */
708     HvMarkCellDirty(Hive, Key->KeyCellOffset, FALSE);
709 
710     /* Initialize value name string */
711     RtlInitUnicodeString(&ValueNameString, lpValueName);
712     if (!CmpFindNameInList(Hive,
713                            &KeyNode->ValueList,
714                            &ValueNameString,
715                            &ChildIndex,
716                            &CellIndex))
717     {
718         /* Sanity check */
719         ASSERT(CellIndex == HCELL_NIL);
720         /* Fail */
721         Status = STATUS_INSUFFICIENT_RESOURCES;
722     }
723     if (CellIndex == HCELL_NIL)
724     {
725         /* The value doesn't exist, create a new one */
726         Status = CmiAddValueKey(Key->RegistryHive,
727                                 KeyNode,
728                                 ChildIndex,
729                                 &ValueNameString,
730                                 &ValueCell,
731                                 &CellIndex);
732     }
733     else
734     {
735         /* The value already exists, use it. Get the value cell. */
736         ValueCell = HvGetCell(&Key->RegistryHive->Hive, CellIndex);
737         ASSERT(ValueCell != NULL);
738         Status = STATUS_SUCCESS;
739     }
740 
741     // /**/HvReleaseCell(Hive, CellIndex);/**/
742 
743     if (!NT_SUCCESS(Status))
744         return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
745 
746     /* Get size of the allocated cell (if any) */
747     if (!(ValueCell->DataLength & CM_KEY_VALUE_SPECIAL_SIZE) &&
748          (ValueCell->DataLength & ~CM_KEY_VALUE_SPECIAL_SIZE) != 0)
749     {
750         DataCell = HvGetCell(Hive, ValueCell->Data);
751         if (!DataCell)
752             return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
753 
754         DataCellSize = (ULONG)(-HvGetCellSize(Hive, DataCell));
755     }
756     else
757     {
758         DataCell = NULL;
759         DataCellSize = 0;
760     }
761 
762     if (cbData <= sizeof(HCELL_INDEX))
763     {
764         /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
765         DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
766         if (DataCell)
767             HvFreeCell(Hive, ValueCell->Data);
768 
769         RtlCopyMemory(&ValueCell->Data, lpData, cbData);
770         ValueCell->DataLength = (cbData | CM_KEY_VALUE_SPECIAL_SIZE);
771         ValueCell->Type = dwType;
772     }
773     else
774     {
775         if (cbData > DataCellSize)
776         {
777             /* New data size is larger than the current, destroy current
778              * data block and allocate a new one. */
779             HCELL_INDEX NewOffset;
780 
781             DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
782 
783             NewOffset = HvAllocateCell(Hive, cbData, Stable, HCELL_NIL);
784             if (NewOffset == HCELL_NIL)
785             {
786                 DPRINT("HvAllocateCell() has failed!\n");
787                 return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
788             }
789 
790             if (DataCell)
791                 HvFreeCell(Hive, ValueCell->Data);
792 
793             ValueCell->Data = NewOffset;
794             DataCell = (PVOID)HvGetCell(Hive, NewOffset);
795         }
796 
797         /* Copy new contents to cell */
798         RtlCopyMemory(DataCell, lpData, cbData);
799         ValueCell->DataLength = (cbData & ~CM_KEY_VALUE_SPECIAL_SIZE);
800         ValueCell->Type = dwType;
801         HvMarkCellDirty(Hive, ValueCell->Data, FALSE);
802     }
803 
804     HvMarkCellDirty(Hive, CellIndex, FALSE);
805 
806     /* Check if the maximum value name length changed, update it if so */
807     if (KeyNode->MaxValueNameLen < ValueNameString.Length)
808         KeyNode->MaxValueNameLen = ValueNameString.Length;
809 
810     /* Check if the maximum data length changed, update it if so */
811     if (KeyNode->MaxValueDataLen < cbData)
812         KeyNode->MaxValueDataLen = cbData;
813 
814     /* Save the write time */
815     KeQuerySystemTime(&KeyNode->LastWriteTime);
816 
817     return ERROR_SUCCESS;
818 }
819 
820 
821 // Synced with freeldr/ntldr/registry.c
822 static
823 VOID
824 RepGetValueData(
825     IN PHHIVE Hive,
826     IN PCM_KEY_VALUE ValueCell,
827     OUT PULONG Type OPTIONAL,
828     OUT PUCHAR Data OPTIONAL,
829     IN OUT PULONG DataSize OPTIONAL)
830 {
831     ULONG DataLength;
832     PVOID DataCell;
833 
834     /* Does the caller want the type? */
835     if (Type != NULL)
836         *Type = ValueCell->Type;
837 
838     /* Does the caller provide DataSize? */
839     if (DataSize != NULL)
840     {
841         // NOTE: CmpValueToData doesn't support big data (the function will
842         // bugcheck if so), FreeLdr is not supposed to read such data.
843         // If big data is needed, use instead CmpGetValueData.
844         // CmpGetValueData(Hive, ValueCell, DataSize, &DataCell, ...);
845         DataCell = CmpValueToData(Hive, ValueCell, &DataLength);
846 
847         /* Does the caller want the data? */
848         if ((Data != NULL) && (*DataSize != 0))
849         {
850             RtlCopyMemory(Data,
851                           DataCell,
852                           min(*DataSize, DataLength));
853         }
854 
855         /* Return the actual data length */
856         *DataSize = DataLength;
857     }
858 }
859 
860 // Similar to RegQueryValue in freeldr/ntldr/registry.c
861 LONG WINAPI
862 RegQueryValueExW(
863     IN HKEY hKey,
864     IN LPCWSTR lpValueName,
865     IN PULONG lpReserved,
866     OUT PULONG lpType OPTIONAL,
867     OUT PUCHAR lpData OPTIONAL,
868     IN OUT PULONG lpcbData OPTIONAL)
869 {
870     PMEMKEY ParentKey = HKEY_TO_MEMKEY(hKey);
871     PHHIVE Hive = &ParentKey->RegistryHive->Hive;
872     PCM_KEY_NODE KeyNode;
873     PCM_KEY_VALUE ValueCell;
874     HCELL_INDEX CellIndex;
875     UNICODE_STRING ValueNameString;
876 
877     KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey->KeyCellOffset);
878     if (!KeyNode)
879         return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
880 
881     ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
882 
883     /* Initialize value name string */
884     RtlInitUnicodeString(&ValueNameString, lpValueName);
885     CellIndex = CmpFindValueByName(Hive, KeyNode, &ValueNameString);
886     if (CellIndex == HCELL_NIL)
887         return ERROR_FILE_NOT_FOUND; // STATUS_OBJECT_NAME_NOT_FOUND;
888 
889     /* Get the value cell */
890     ValueCell = HvGetCell(Hive, CellIndex);
891     ASSERT(ValueCell != NULL);
892 
893     RepGetValueData(Hive, ValueCell, lpType, lpData, lpcbData);
894 
895     HvReleaseCell(Hive, CellIndex);
896 
897     return ERROR_SUCCESS;
898 }
899 
900 LONG WINAPI
901 RegDeleteValueW(
902     IN HKEY hKey,
903     IN LPCWSTR lpValueName OPTIONAL)
904 {
905     LONG rc;
906     NTSTATUS Status;
907     PMEMKEY Key = HKEY_TO_MEMKEY(hKey); // ParentKey
908     PHHIVE Hive = &Key->RegistryHive->Hive;
909     PCM_KEY_NODE KeyNode; // ParentNode
910     PCM_KEY_VALUE ValueCell;
911     HCELL_INDEX CellIndex;
912     ULONG ChildIndex;
913     UNICODE_STRING ValueNameString;
914 
915     KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Key->KeyCellOffset);
916     if (!KeyNode)
917         return ERROR_GEN_FAILURE; // STATUS_UNSUCCESSFUL;
918 
919     ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
920 
921     /* Initialize value name string */
922     RtlInitUnicodeString(&ValueNameString, lpValueName);
923     if (!CmpFindNameInList(Hive,
924                            &KeyNode->ValueList,
925                            &ValueNameString,
926                            &ChildIndex,
927                            &CellIndex))
928     {
929         /* Sanity check */
930         ASSERT(CellIndex == HCELL_NIL);
931     }
932     if (CellIndex == HCELL_NIL)
933     {
934         rc = ERROR_FILE_NOT_FOUND; // STATUS_OBJECT_NAME_NOT_FOUND;
935         goto Quit;
936     }
937 
938     /* We found the value, mark all relevant cells dirty */
939     HvMarkCellDirty(Hive, Key->KeyCellOffset, FALSE);
940     HvMarkCellDirty(Hive, KeyNode->ValueList.List, FALSE);
941     HvMarkCellDirty(Hive, CellIndex, FALSE);
942 
943     /* Get the key value */
944     ValueCell = (PCM_KEY_VALUE)HvGetCell(Hive, CellIndex);
945     ASSERT(ValueCell);
946 
947     /* Mark it and all related data as dirty */
948     if (!CmpMarkValueDataDirty(Hive, ValueCell))
949     {
950         /* Not enough log space, fail */
951         rc = ERROR_NO_LOG_SPACE; // STATUS_NO_LOG_SPACE;
952         goto Quit;
953     }
954 
955     /* Sanity checks */
956     ASSERT(HvIsCellDirty(Hive, KeyNode->ValueList.List));
957     ASSERT(HvIsCellDirty(Hive, CellIndex));
958 
959     /* Remove the value from the child list */
960     Status = CmpRemoveValueFromList(Hive, ChildIndex, &KeyNode->ValueList);
961     if (!NT_SUCCESS(Status))
962     {
963         /* Set known error */
964         rc = ERROR_NO_SYSTEM_RESOURCES; // STATUS_INSUFFICIENT_RESOURCES;
965         goto Quit;
966     }
967 
968     /* Remove the value and its data itself */
969     if (!CmpFreeValue(Hive, CellIndex))
970     {
971         /* Failed to free the value, fail */
972         rc = ERROR_NO_SYSTEM_RESOURCES; // STATUS_INSUFFICIENT_RESOURCES;
973         goto Quit;
974     }
975 
976     /* Set the last write time */
977     KeQuerySystemTime(&KeyNode->LastWriteTime);
978 
979     /* Sanity check */
980     ASSERT(HvIsCellDirty(Hive, Key->KeyCellOffset));
981 
982     /* Check if the value list is empty now */
983     if (!KeyNode->ValueList.Count)
984     {
985         /* Then clear key node data */
986         KeyNode->MaxValueNameLen = 0;
987         KeyNode->MaxValueDataLen = 0;
988     }
989 
990     /* Change default Status to success */
991     rc = ERROR_SUCCESS;
992 
993 Quit:
994     /* Check if we had a value */
995     if (ValueCell)
996     {
997         /* Release the child cell */
998         ASSERT(CellIndex != HCELL_NIL);
999         HvReleaseCell(Hive, CellIndex);
1000     }
1001 
1002     /* Release the parent cell, if any */
1003     if (KeyNode)
1004         HvReleaseCell(Hive, Key->KeyCellOffset);
1005 
1006     return rc;
1007 }
1008 
1009 
1010 static BOOL
1011 ConnectRegistry(
1012     IN HKEY RootKey,
1013     IN PCWSTR Path,
1014     IN PCMHIVE HiveToConnect,
1015     IN PUCHAR SecurityDescriptor,
1016     IN ULONG SecurityDescriptorLength)
1017 {
1018     NTSTATUS Status;
1019     LONG rc;
1020     PREPARSE_POINT ReparsePoint;
1021     PMEMKEY NewKey;
1022 
1023     ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
1024     if (!ReparsePoint)
1025         return FALSE;
1026 
1027     /*
1028      * Use a dummy root key name:
1029      * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
1030      * - On Vista+, this is "CMI-CreateHive{guid}"
1031      * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
1032      * for more information.
1033      */
1034     Status = CmiInitializeHive(HiveToConnect, L"$$$PROTO.HIV");
1035     if (!NT_SUCCESS(Status))
1036     {
1037         DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status);
1038         free(ReparsePoint);
1039         return FALSE;
1040     }
1041 
1042     /*
1043      * Add security to the root key.
1044      * NOTE: One can implement this using the lpSecurityAttributes
1045      * parameter of RegCreateKeyExW.
1046      */
1047     Status = CmiCreateSecurityKey(&HiveToConnect->Hive,
1048                                   HiveToConnect->Hive.BaseBlock->RootCell,
1049                                   SecurityDescriptor, SecurityDescriptorLength);
1050     if (!NT_SUCCESS(Status))
1051         DPRINT1("Failed to add security for root key '%S'\n", Path);
1052 
1053     /* Create the key */
1054     rc = RegCreateKeyExW(RootKey,
1055                          Path,
1056                          0,
1057                          NULL,
1058                          REG_OPTION_VOLATILE,
1059                          0,
1060                          NULL,
1061                          (PHKEY)&NewKey,
1062                          NULL);
1063     if (rc != ERROR_SUCCESS)
1064     {
1065         free(ReparsePoint);
1066         return FALSE;
1067     }
1068 
1069     ReparsePoint->SourceHive = NewKey->RegistryHive;
1070     ReparsePoint->SourceKeyCellOffset = NewKey->KeyCellOffset;
1071     NewKey->RegistryHive = HiveToConnect;
1072     NewKey->KeyCellOffset = HiveToConnect->Hive.BaseBlock->RootCell;
1073     ReparsePoint->DestinationHive = NewKey->RegistryHive;
1074     ReparsePoint->DestinationKeyCellOffset = NewKey->KeyCellOffset;
1075     InsertTailList(&CmiReparsePointsHead, &ReparsePoint->ListEntry);
1076 
1077     return TRUE;
1078 }
1079 
1080 static BOOL
1081 CreateSymLink(
1082     IN PCWSTR LinkKeyPath OPTIONAL,
1083     IN OUT PHKEY LinkKeyHandle OPTIONAL,
1084     // IN PCWSTR TargetKeyPath OPTIONAL,
1085     IN HKEY TargetKeyHandle)
1086 {
1087     LONG rc;
1088     PMEMKEY LinkKey, TargetKey;
1089     PREPARSE_POINT ReparsePoint;
1090 
1091     ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
1092     if (!ReparsePoint)
1093         return FALSE;
1094 
1095     if (LinkKeyPath && !(LinkKeyHandle && *LinkKeyHandle))
1096     {
1097         /* Create the link key */
1098         rc = RegCreateKeyExW(NULL,
1099                              LinkKeyPath,
1100                              0,
1101                              NULL,
1102                              REG_OPTION_VOLATILE,
1103                              0,
1104                              NULL,
1105                              (PHKEY)&LinkKey,
1106                              NULL);
1107         if (rc != ERROR_SUCCESS)
1108         {
1109             free(ReparsePoint);
1110             return FALSE;
1111         }
1112     }
1113     else if (LinkKeyHandle)
1114     {
1115         /* Use the user-provided link key handle */
1116         LinkKey = HKEY_TO_MEMKEY(*LinkKeyHandle);
1117     }
1118 
1119     if (LinkKeyHandle)
1120         *LinkKeyHandle = MEMKEY_TO_HKEY(LinkKey);
1121 
1122     TargetKey = HKEY_TO_MEMKEY(TargetKeyHandle);
1123 
1124     ReparsePoint->SourceHive = LinkKey->RegistryHive;
1125     ReparsePoint->SourceKeyCellOffset = LinkKey->KeyCellOffset;
1126     ReparsePoint->DestinationHive = TargetKey->RegistryHive;
1127     ReparsePoint->DestinationKeyCellOffset = TargetKey->KeyCellOffset;
1128     InsertTailList(&CmiReparsePointsHead, &ReparsePoint->ListEntry);
1129 
1130     return TRUE;
1131 }
1132 
1133 VOID
1134 RegInitializeRegistry(
1135     IN PCSTR HiveList)
1136 {
1137     NTSTATUS Status;
1138     UINT i;
1139     HKEY ControlSetKey;
1140 
1141     InitializeListHead(&CmiHiveListHead);
1142     InitializeListHead(&CmiReparsePointsHead);
1143 
1144     Status = CmiInitializeHive(&RootHive, L"");
1145     if (!NT_SUCCESS(Status))
1146     {
1147         DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status);
1148         return;
1149     }
1150 
1151     RootKey = CreateInMemoryStructure(&RootHive,
1152                                       RootHive.Hive.BaseBlock->RootCell);
1153 
1154     for (i = 0; i < _countof(RegistryHives); ++i)
1155     {
1156         /* Skip this registry hive if it's not in the list */
1157         if (!strstr(HiveList, RegistryHives[i].HiveName))
1158             continue;
1159 
1160         /* Create the registry key */
1161         ConnectRegistry(NULL,
1162                         RegistryHives[i].HiveRegistryPath,
1163                         RegistryHives[i].CmHive,
1164                         RegistryHives[i].SecurityDescriptor,
1165                         RegistryHives[i].SecurityDescriptorLength);
1166 
1167         /* If we happen to deal with the special setup registry hive, stop there */
1168         // if (strcmp(RegistryHives[i].HiveName, "SETUPREG") == 0)
1169         if (i == 0)
1170             break;
1171     }
1172 
1173     /* Create the 'ControlSet001' key */
1174     RegCreateKeyW(NULL,
1175                   L"Registry\\Machine\\SYSTEM\\ControlSet001",
1176                   &ControlSetKey);
1177 
1178     /* Create the 'CurrentControlSet' key as a symlink to 'ControlSet001' */
1179     CreateSymLink(L"Registry\\Machine\\SYSTEM\\CurrentControlSet",
1180                   NULL, ControlSetKey);
1181 
1182     RegCloseKey(ControlSetKey);
1183 
1184 #if 0
1185     /* Link SECURITY to SAM */
1186     CmpLinkKeyToHive(L"\\Registry\\Machine\\Security\\SAM", L"\\Registry\\Machine\\SAM\\SAM");
1187     /* Link S-1-5-18 to .Default */
1188     CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18", L"\\Registry\\User\\.Default");
1189 #endif
1190 }
1191 
1192 VOID
1193 RegShutdownRegistry(VOID)
1194 {
1195     PLIST_ENTRY Entry;
1196     PREPARSE_POINT ReparsePoint;
1197 
1198     /* Clean up the reparse points list */
1199     while (!IsListEmpty(&CmiReparsePointsHead))
1200     {
1201         Entry = RemoveHeadList(&CmiReparsePointsHead);
1202         ReparsePoint = CONTAINING_RECORD(Entry, REPARSE_POINT, ListEntry);
1203         free(ReparsePoint);
1204     }
1205 
1206     /* FIXME: clean up the complete hive */
1207 
1208     free(RootKey);
1209 }
1210 
1211 /* EOF */
1212