[MKHIVE] Implement and use RegCloseKey().
[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 /*
29 * TODO:
30 * - Implement RegDeleteKeyW() and RegDeleteValueW()
31 */
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdio.h>
36
37 #define NDEBUG
38 #include "mkhive.h"
39
40 static CMHIVE RootHive;
41 static PMEMKEY RootKey;
42
43 static CMHIVE SystemHive; /* \Registry\Machine\SYSTEM */
44 static CMHIVE SoftwareHive; /* \Registry\Machine\SOFTWARE */
45 static CMHIVE DefaultHive; /* \Registry\User\.DEFAULT */
46 static CMHIVE SamHive; /* \Registry\Machine\SAM */
47 static CMHIVE SecurityHive; /* \Registry\Machine\SECURITY */
48 static CMHIVE BcdHive; /* \Registry\Machine\BCD00000000 */
49
50 //
51 // TODO: Write these values in a more human-readable form.
52 // See http://amnesia.gtisc.gatech.edu/~moyix/suzibandit.ltd.uk/MSc/Registry%20Structure%20-%20Appendices%20V4.pdf
53 // Appendix 12 "The Registry NT Security Descriptor" for more information.
54 //
55 // Those SECURITY_DESCRIPTORs were obtained by dumping the security block "sk"
56 // of registry hives created by setting their permissions to be the same as
57 // the ones of the BCD, SOFTWARE, or SYSTEM, SAM and .DEFAULT system hives.
58 // A cross-check was subsequently done with the system hives to verify that
59 // the security descriptors were the same.
60 //
61 static UCHAR BcdSecurity[] =
62 {
63 // SECURITY_DESCRIPTOR_RELATIVE
64 0x01, // Revision
65 0x00, // Sbz1
66 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
67 // SE_DACL_PROTECTED (0x1000) |
68 // SE_DACL_AUTO_INHERITED (0x0400) |
69 // SE_DACL_PRESENT (0x0004)
70 0x48, 0x00, 0x00, 0x00, // Owner
71 0x58, 0x00, 0x00, 0x00, // Group
72 0x00, 0x00, 0x00, 0x00, // Sacl (None)
73 0x14, 0x00, 0x00, 0x00, // Dacl
74
75 // DACL
76 0x02, // AclRevision
77 0x00, // Sbz1
78 0x34, 0x00, // AclSize
79 0x02, 0x00, // AceCount
80 0x00, 0x00, // Sbz2
81
82 // (1st ACE)
83 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
84 0x02, // AceFlags: CONTAINER_INHERIT_ACE
85 0x18, 0x00, // AceSize
86 0x19, 0x00, 0x06, 0x00, // ACCESS_MASK: "Write DAC" (0x00040000) |
87 // "Read Control" (0x00020000) |
88 // "Notify" (0x00000010) |
89 // "Enumerate Subkeys" (0x00000008) |
90 // "Query Value" (0x00000001)
91 // (SidStart: S-1-5-32-544 "Administrators")
92 0x01, 0x02, 0x00, 0x00,
93 0x00, 0x00, 0x00, 0x05,
94 0x20, 0x00, 0x00, 0x00,
95 0x20, 0x02, 0x00, 0x00,
96
97 // (2nd ACE)
98 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
99 0x02, // AceFlags: CONTAINER_INHERIT_ACE
100 0x14, 0x00, // AceSize
101 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
102 // (SidStart: S-1-5-18 "Local System")
103 0x01, 0x01, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x05,
105 0x12, 0x00, 0x00, 0x00,
106
107 // Owner SID (S-1-5-32-544 "Administrators")
108 0x01, 0x02, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x05,
110 0x20, 0x00, 0x00, 0x00,
111 0x20, 0x02, 0x00, 0x00,
112
113 // Group SID (S-1-5-21-domain-513 "Domain Users")
114 0x01, 0x05, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x05,
116 0x15, 0x00, 0x00, 0x00,
117 0xAC, 0xD0, 0x49, 0xCB,
118 0xE6, 0x52, 0x47, 0x9C,
119 0xE4, 0x31, 0xDB, 0x5C,
120 0x01, 0x02, 0x00, 0x00
121 };
122
123 static UCHAR SoftwareSecurity[] =
124 {
125 // SECURITY_DESCRIPTOR_RELATIVE
126 0x01, // Revision
127 0x00, // Sbz1
128 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
129 // SE_DACL_PROTECTED (0x1000) |
130 // SE_DACL_AUTO_INHERITED (0x0400) |
131 // SE_DACL_PRESENT (0x0004)
132 0xA0, 0x00, 0x00, 0x00, // Owner
133 0xB0, 0x00, 0x00, 0x00, // Group
134 0x00, 0x00, 0x00, 0x00, // Sacl (None)
135 0x14, 0x00, 0x00, 0x00, // Dacl
136
137 // DACL
138 0x02, // AclRevision
139 0x00, // Sbz1
140 0x8C, 0x00, // AclSize
141 0x06, 0x00, // AceCount
142 0x00, 0x00, // Sbz2
143
144 // (1st ACE)
145 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
146 0x02, // AceFlags: CONTAINER_INHERIT_ACE
147 0x18, 0x00, // AceSize
148 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
149 // (SidStart: S-1-5-32-544 "Administrators")
150 0x01, 0x02, 0x00, 0x00,
151 0x00, 0x00, 0x00, 0x05,
152 0x20, 0x00, 0x00, 0x00,
153 0x20, 0x02, 0x00, 0x00,
154
155 // (2nd ACE)
156 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
157 0x0A, // AceFlags: INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE
158 0x14, 0x00, // AceSize
159 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
160 // (SidStart: S-1-3-0 "Creator Owner")
161 0x01, 0x01, 0x00, 0x00,
162 0x00, 0x00, 0x00, 0x03,
163 0x00, 0x00, 0x00, 0x00,
164
165 // (3rd ACE)
166 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
167 0x02, // AceFlags: CONTAINER_INHERIT_ACE
168 0x14, 0x00, // AceSize
169 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
170 // (SidStart: S-1-5-18 "Local System")
171 0x01, 0x01, 0x00, 0x00,
172 0x00, 0x00, 0x00, 0x05,
173 0x12, 0x00, 0x00, 0x00,
174
175 // (4th ACE)
176 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
177 0x02, // AceFlags: CONTAINER_INHERIT_ACE
178 0x14, 0x00, // AceSize
179 0x1F, 0x00, 0x03, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
180 // "Delete" (0x00010000) |
181 // "Notify" (0x00000010) |
182 // "Enumerate Subkeys" (0x00000008) |
183 // "Create Subkey" (0x00000004) |
184 // "Set Value" (0x00000002) |
185 // "Query Value" (0x00000001)
186 // (SidStart: S-1-5-13 "Terminal Server Users")
187 0x01, 0x01, 0x00, 0x00,
188 0x00, 0x00, 0x00, 0x05,
189 0x0D, 0x00, 0x00, 0x00,
190
191 // (5th ACE)
192 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
193 0x02, // AceFlags: CONTAINER_INHERIT_ACE
194 0x18, 0x00, // AceSize
195 0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
196 // "Notify" (0x00000010) |
197 // "Enumerate Subkeys" (0x00000008) |
198 // "Query Value" (0x00000001)
199 // (SidStart: S-1-5-32-545 "Users")
200 0x01, 0x02, 0x00, 0x00,
201 0x00, 0x00, 0x00, 0x05,
202 0x20, 0x00, 0x00, 0x00,
203 0x21, 0x02, 0x00, 0x00,
204
205 // (6th ACE)
206 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
207 0x02, // AceFlags: CONTAINER_INHERIT_ACE
208 0x18, 0x00, // AceSize
209 0x1F, 0x00, 0x03, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
210 // "Delete" (0x00010000) |
211 // "Notify" (0x00000010) |
212 // "Enumerate Subkeys" (0x00000008) |
213 // "Create Subkey" (0x00000004) |
214 // "Set Value" (0x00000002) |
215 // "Query Value" (0x00000001)
216 // (SidStart: S-1-5-32-547 "Power Users")
217 0x01, 0x02, 0x00, 0x00,
218 0x00, 0x00, 0x00, 0x05,
219 0x20, 0x00, 0x00, 0x00,
220 0x23, 0x02, 0x00, 0x00,
221
222 // Owner SID (S-1-5-32-544 "Administrators")
223 0x01, 0x02, 0x00, 0x00,
224 0x00, 0x00, 0x00, 0x05,
225 0x20, 0x00, 0x00, 0x00,
226 0x20, 0x02, 0x00, 0x00,
227
228 // Group SID (S-1-5-21-domain-513 "Domain Users")
229 0x01, 0x05, 0x00, 0x00,
230 0x00, 0x00, 0x00, 0x05,
231 0x15, 0x00, 0x00, 0x00,
232 0xAC, 0xD0, 0x49, 0xCB,
233 0xE6, 0x52, 0x47, 0x9C,
234 0xE4, 0x31, 0xDB, 0x5C,
235 0x01, 0x02, 0x00, 0x00
236 };
237
238 // Same security for SYSTEM, SAM and .DEFAULT
239 static UCHAR SystemSecurity[] =
240 {
241 // SECURITY_DESCRIPTOR_RELATIVE
242 0x01, // Revision
243 0x00, // Sbz1
244 0x04, 0x94, // Control: SE_SELF_RELATIVE (0x8000) |
245 // SE_DACL_PROTECTED (0x1000) |
246 // SE_DACL_AUTO_INHERITED (0x0400) |
247 // SE_DACL_PRESENT (0x0004)
248 0x8C, 0x00, 0x00, 0x00, // Owner
249 0x9C, 0x00, 0x00, 0x00, // Group
250 0x00, 0x00, 0x00, 0x00, // Sacl (None)
251 0x14, 0x00, 0x00, 0x00, // Dacl
252
253 // DACL
254 0x02, // AclRevision
255 0x00, // Sbz1
256 0x78, 0x00, // AclSize
257 0x05, 0x00, // AceCount
258 0x00, 0x00, // Sbz2
259
260 // (1st ACE)
261 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
262 0x02, // AceFlags: CONTAINER_INHERIT_ACE
263 0x18, 0x00, // AceSize
264 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
265 // (SidStart: S-1-5-32-544 "Administrators")
266 0x01, 0x02, 0x00, 0x00,
267 0x00, 0x00, 0x00, 0x05,
268 0x20, 0x00, 0x00, 0x00,
269 0x20, 0x02, 0x00, 0x00,
270
271 // (2nd ACE)
272 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
273 0x0A, // AceFlags: INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE
274 0x14, 0x00, // AceSize
275 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
276 // (SidStart: S-1-3-0 "Creator Owner")
277 0x01, 0x01, 0x00, 0x00,
278 0x00, 0x00, 0x00, 0x03,
279 0x00, 0x00, 0x00, 0x00,
280
281 // (3rd ACE)
282 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
283 0x02, // AceFlags: CONTAINER_INHERIT_ACE
284 0x14, 0x00, // AceSize
285 0x3F, 0x00, 0x0F, 0x00, // ACCESS_MASK: "Full Control" (0x000F003F)
286 // (SidStart: S-1-5-18 "Local System")
287 0x01, 0x01, 0x00, 0x00,
288 0x00, 0x00, 0x00, 0x05,
289 0x12, 0x00, 0x00, 0x00,
290
291 // (4th ACE)
292 0x00, // AceType : ACCESS_ALLOWED_ACE_TYPE
293 0x02, // AceFlags: CONTAINER_INHERIT_ACE
294 0x18, 0x00, // AceSize
295 0x19, 0x00, 0x02, 0x00, // ACCESS_MASK: "Read Control" (0x00020000) |
296 // "Notify" (0x00000010) |
297 // "Enumerate Subkeys" (0x00000008) |
298 // "Query Value" (0x00000001)
299 // (SidStart: S-1-5-32-545 "Users")
300 0x01, 0x02, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x05,
302 0x20, 0x00, 0x00, 0x00,
303 0x21, 0x02, 0x00, 0x00,
304
305 // (5th 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-547 "Power Users")
314 0x01, 0x02, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x05,
316 0x20, 0x00, 0x00, 0x00,
317 0x23, 0x02, 0x00, 0x00,
318
319 // Owner SID (S-1-5-32-544 "Administrators")
320 0x01, 0x02, 0x00, 0x00,
321 0x00, 0x00, 0x00, 0x05,
322 0x20, 0x00, 0x00, 0x00,
323 0x20, 0x02, 0x00, 0x00,
324
325 // Group SID (S-1-5-21-domain-513 "Domain Users")
326 0x01, 0x05, 0x00, 0x00,
327 0x00, 0x00, 0x00, 0x05,
328 0x15, 0x00, 0x00, 0x00,
329 0xAC, 0xD0, 0x49, 0xCB,
330 0xE6, 0x52, 0x47, 0x9C,
331 0xE4, 0x31, 0xDB, 0x5C,
332 0x01, 0x02, 0x00, 0x00
333 };
334
335
336 HIVE_LIST_ENTRY RegistryHives[/*MAX_NUMBER_OF_REGISTRY_HIVES*/] =
337 {
338 /* Special Setup system registry hive */
339 // WARNING: Please *keep* it in first position!
340 { "SETUPREG", L"Registry\\Machine\\SYSTEM" , &SystemHive , SystemSecurity , sizeof(SystemSecurity) },
341
342 /* Regular registry hives */
343 { "SYSTEM" , L"Registry\\Machine\\SYSTEM" , &SystemHive , SystemSecurity , sizeof(SystemSecurity) },
344 { "SOFTWARE", L"Registry\\Machine\\SOFTWARE" , &SoftwareHive, SoftwareSecurity, sizeof(SoftwareSecurity) },
345 { "DEFAULT" , L"Registry\\User\\.DEFAULT" , &DefaultHive , SystemSecurity , sizeof(SystemSecurity) },
346 { "SAM" , L"Registry\\Machine\\SAM" , &SamHive , SystemSecurity , sizeof(SystemSecurity) },
347 { "SECURITY", L"Registry\\Machine\\SECURITY" , &SecurityHive, NULL , 0 },
348 { "BCD" , L"Registry\\Machine\\BCD00000000", &BcdHive , BcdSecurity , sizeof(BcdSecurity) },
349 };
350 C_ASSERT(_countof(RegistryHives) == MAX_NUMBER_OF_REGISTRY_HIVES);
351
352
353 static PMEMKEY
354 CreateInMemoryStructure(
355 IN PCMHIVE RegistryHive,
356 IN HCELL_INDEX KeyCellOffset)
357 {
358 PMEMKEY Key;
359
360 Key = (PMEMKEY)malloc(sizeof(MEMKEY));
361 if (!Key)
362 return NULL;
363
364 Key->RegistryHive = RegistryHive;
365 Key->KeyCellOffset = KeyCellOffset;
366 return Key;
367 }
368
369 LIST_ENTRY CmiHiveListHead;
370 LIST_ENTRY CmiReparsePointsHead;
371
372 static LONG
373 RegpCreateOrOpenKey(
374 IN HKEY hParentKey,
375 IN PCWSTR KeyName,
376 IN BOOL AllowCreation,
377 IN BOOL Volatile,
378 OUT PHKEY Key)
379 {
380 PWSTR LocalKeyName;
381 PWSTR End;
382 UNICODE_STRING KeyString;
383 NTSTATUS Status;
384 PREPARSE_POINT CurrentReparsePoint;
385 PMEMKEY CurrentKey;
386 PCMHIVE ParentRegistryHive;
387 HCELL_INDEX ParentCellOffset;
388 PCM_KEY_NODE ParentKeyCell;
389 PLIST_ENTRY Ptr;
390 PCM_KEY_NODE SubKeyCell;
391 HCELL_INDEX BlockOffset;
392
393 DPRINT("RegpCreateOrOpenKey('%S')\n", KeyName);
394
395 if (*KeyName == OBJ_NAME_PATH_SEPARATOR)
396 {
397 KeyName++;
398 ParentRegistryHive = RootKey->RegistryHive;
399 ParentCellOffset = RootKey->KeyCellOffset;
400 }
401 else if (hParentKey == NULL)
402 {
403 ParentRegistryHive = RootKey->RegistryHive;
404 ParentCellOffset = RootKey->KeyCellOffset;
405 }
406 else
407 {
408 ParentRegistryHive = HKEY_TO_MEMKEY(hParentKey)->RegistryHive;
409 ParentCellOffset = HKEY_TO_MEMKEY(hParentKey)->KeyCellOffset;
410 }
411
412 LocalKeyName = (PWSTR)KeyName;
413 for (;;)
414 {
415 End = (PWSTR)strchrW(LocalKeyName, OBJ_NAME_PATH_SEPARATOR);
416 if (End)
417 {
418 KeyString.Buffer = LocalKeyName;
419 KeyString.Length = KeyString.MaximumLength =
420 (USHORT)((ULONG_PTR)End - (ULONG_PTR)LocalKeyName);
421 }
422 else
423 {
424 RtlInitUnicodeString(&KeyString, LocalKeyName);
425 if (KeyString.Length == 0)
426 {
427 /* Trailing path separator: we're done */
428 break;
429 }
430 }
431
432 ParentKeyCell = (PCM_KEY_NODE)HvGetCell(&ParentRegistryHive->Hive, ParentCellOffset);
433 if (!ParentKeyCell)
434 return STATUS_UNSUCCESSFUL;
435
436 VERIFY_KEY_CELL(ParentKeyCell);
437
438 BlockOffset = CmpFindSubKeyByName(&ParentRegistryHive->Hive, ParentKeyCell, &KeyString);
439 if (BlockOffset != HCELL_NIL)
440 {
441 Status = STATUS_SUCCESS;
442
443 /* Search for a possible reparse point */
444 Ptr = CmiReparsePointsHead.Flink;
445 while (Ptr != &CmiReparsePointsHead)
446 {
447 CurrentReparsePoint = CONTAINING_RECORD(Ptr, REPARSE_POINT, ListEntry);
448 if (CurrentReparsePoint->SourceHive == ParentRegistryHive &&
449 CurrentReparsePoint->SourceKeyCellOffset == BlockOffset)
450 {
451 ParentRegistryHive = CurrentReparsePoint->DestinationHive;
452 BlockOffset = CurrentReparsePoint->DestinationKeyCellOffset;
453 break;
454 }
455 Ptr = Ptr->Flink;
456 }
457 }
458 else if (AllowCreation) // && (BlockOffset == HCELL_NIL)
459 {
460 Status = CmiAddSubKey(ParentRegistryHive,
461 ParentCellOffset,
462 &KeyString,
463 Volatile,
464 &BlockOffset);
465 }
466
467 HvReleaseCell(&ParentRegistryHive->Hive, ParentCellOffset);
468
469 if (!NT_SUCCESS(Status))
470 return ERROR_UNSUCCESSFUL;
471
472 ParentCellOffset = BlockOffset;
473 if (End)
474 LocalKeyName = End + 1;
475 else
476 break;
477 }
478
479 CurrentKey = CreateInMemoryStructure(ParentRegistryHive, ParentCellOffset);
480 if (!CurrentKey)
481 return ERROR_OUTOFMEMORY;
482
483 *Key = MEMKEY_TO_HKEY(CurrentKey);
484
485 return ERROR_SUCCESS;
486 }
487
488 LONG WINAPI
489 RegCloseKey(
490 IN HKEY hKey)
491 {
492 PMEMKEY Key = HKEY_TO_MEMKEY(hKey); // ParentKey
493
494 /* Free the object */
495 free(Key);
496
497 return ERROR_SUCCESS;
498 }
499
500 LONG WINAPI
501 RegCreateKeyW(
502 IN HKEY hKey,
503 IN LPCWSTR lpSubKey,
504 OUT PHKEY phkResult)
505 {
506 return RegpCreateOrOpenKey(hKey, lpSubKey, TRUE, FALSE, phkResult);
507 }
508
509 LONG WINAPI
510 RegCreateKeyExW(
511 IN HKEY hKey,
512 IN LPCWSTR lpSubKey,
513 IN DWORD Reserved,
514 IN LPWSTR lpClass OPTIONAL,
515 IN DWORD dwOptions,
516 IN REGSAM samDesired,
517 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL,
518 OUT PHKEY phkResult,
519 OUT LPDWORD lpdwDisposition OPTIONAL)
520 {
521 return RegpCreateOrOpenKey(hKey,
522 lpSubKey,
523 TRUE,
524 (dwOptions & REG_OPTION_VOLATILE) != 0,
525 phkResult);
526 }
527
528 LONG WINAPI
529 RegDeleteKeyW(
530 IN HKEY hKey,
531 IN LPCWSTR lpSubKey)
532 {
533 DPRINT1("RegDeleteKeyW(0x%p, '%S') is UNIMPLEMENTED!\n",
534 hKey, (lpSubKey ? lpSubKey : L""));
535 return ERROR_SUCCESS;
536 }
537
538 LONG WINAPI
539 RegOpenKeyW(
540 IN HKEY hKey,
541 IN LPCWSTR lpSubKey,
542 OUT PHKEY phkResult)
543 {
544 return RegpCreateOrOpenKey(hKey, lpSubKey, FALSE, FALSE, phkResult);
545 }
546
547 LONG WINAPI
548 RegSetValueExW(
549 IN HKEY hKey,
550 IN LPCWSTR lpValueName OPTIONAL,
551 IN ULONG Reserved,
552 IN ULONG dwType,
553 IN const UCHAR* lpData,
554 IN ULONG cbData)
555 {
556 PMEMKEY Key = HKEY_TO_MEMKEY(hKey); // ParentKey
557 PHHIVE Hive;
558 PCM_KEY_NODE KeyNode; // ParentNode
559 PCM_KEY_VALUE ValueCell;
560 HCELL_INDEX CellIndex;
561 UNICODE_STRING ValueNameString;
562
563 PVOID DataCell;
564 ULONG DataCellSize;
565 NTSTATUS Status;
566
567 if (dwType == REG_LINK)
568 {
569 PMEMKEY DestKey;
570
571 /* Special handling of registry links */
572 if (cbData != sizeof(PVOID))
573 return STATUS_INVALID_PARAMETER;
574
575 DestKey = HKEY_TO_MEMKEY(*(PHKEY)lpData);
576
577 // FIXME: Add additional checks for the validity of DestKey
578
579 /* Create the link in registry hive (if applicable) */
580 if (Key->RegistryHive != DestKey->RegistryHive)
581 return STATUS_SUCCESS;
582
583 DPRINT1("Save link to registry\n");
584 return STATUS_NOT_IMPLEMENTED;
585 }
586
587 if ((cbData & ~CM_KEY_VALUE_SPECIAL_SIZE) != cbData)
588 return STATUS_UNSUCCESSFUL;
589
590 Hive = &Key->RegistryHive->Hive;
591
592 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Key->KeyCellOffset);
593 if (!KeyNode)
594 return ERROR_UNSUCCESSFUL;
595
596 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
597
598 /* Mark the parent as dirty since we are going to create a new value in it */
599 HvMarkCellDirty(Hive, Key->KeyCellOffset, FALSE);
600
601 /* Initialize value name string */
602 RtlInitUnicodeString(&ValueNameString, lpValueName);
603 CellIndex = CmpFindValueByName(Hive, KeyNode, &ValueNameString);
604 if (CellIndex == HCELL_NIL)
605 {
606 /* The value doesn't exist, create a new one */
607 Status = CmiAddValueKey(Key->RegistryHive,
608 KeyNode,
609 &ValueNameString,
610 &ValueCell,
611 &CellIndex);
612 }
613 else
614 {
615 /* The value already exists, use it. Get the value cell. */
616 ValueCell = HvGetCell(&Key->RegistryHive->Hive, CellIndex);
617 ASSERT(ValueCell != NULL);
618 Status = STATUS_SUCCESS;
619 }
620
621 // /**/HvReleaseCell(Hive, CellIndex);/**/
622
623 if (!NT_SUCCESS(Status))
624 return ERROR_UNSUCCESSFUL;
625
626 /* Get size of the allocated cell (if any) */
627 if (!(ValueCell->DataLength & CM_KEY_VALUE_SPECIAL_SIZE) &&
628 (ValueCell->DataLength & ~CM_KEY_VALUE_SPECIAL_SIZE) != 0)
629 {
630 DataCell = HvGetCell(Hive, ValueCell->Data);
631 if (!DataCell)
632 return ERROR_UNSUCCESSFUL;
633
634 DataCellSize = (ULONG)(-HvGetCellSize(Hive, DataCell));
635 }
636 else
637 {
638 DataCell = NULL;
639 DataCellSize = 0;
640 }
641
642 if (cbData <= sizeof(HCELL_INDEX))
643 {
644 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
645 DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
646 if (DataCell)
647 HvFreeCell(Hive, ValueCell->Data);
648
649 RtlCopyMemory(&ValueCell->Data, lpData, cbData);
650 ValueCell->DataLength = (cbData | CM_KEY_VALUE_SPECIAL_SIZE);
651 ValueCell->Type = dwType;
652 }
653 else
654 {
655 if (cbData > DataCellSize)
656 {
657 /* New data size is larger than the current, destroy current
658 * data block and allocate a new one. */
659 HCELL_INDEX NewOffset;
660
661 DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
662
663 NewOffset = HvAllocateCell(Hive, cbData, Stable, HCELL_NIL);
664 if (NewOffset == HCELL_NIL)
665 {
666 DPRINT("HvAllocateCell() has failed!\n");
667 return ERROR_UNSUCCESSFUL;
668 }
669
670 if (DataCell)
671 HvFreeCell(Hive, ValueCell->Data);
672
673 ValueCell->Data = NewOffset;
674 DataCell = (PVOID)HvGetCell(Hive, NewOffset);
675 }
676
677 /* Copy new contents to cell */
678 RtlCopyMemory(DataCell, lpData, cbData);
679 ValueCell->DataLength = (cbData & ~CM_KEY_VALUE_SPECIAL_SIZE);
680 ValueCell->Type = dwType;
681 HvMarkCellDirty(Hive, ValueCell->Data, FALSE);
682 }
683
684 HvMarkCellDirty(Hive, CellIndex, FALSE);
685
686 /* Check if the maximum value name length changed, update it if so */
687 if (KeyNode->MaxValueNameLen < ValueNameString.Length)
688 KeyNode->MaxValueNameLen = ValueNameString.Length;
689
690 /* Check if the maximum data length changed, update it if so */
691 if (KeyNode->MaxValueDataLen < cbData)
692 KeyNode->MaxValueDataLen = cbData;
693
694 /* Save the write time */
695 KeQuerySystemTime(&KeyNode->LastWriteTime);
696
697 return ERROR_SUCCESS;
698 }
699
700
701 // Synced with freeldr/windows/registry.c
702 static
703 VOID
704 RepGetValueData(
705 IN PHHIVE Hive,
706 IN PCM_KEY_VALUE ValueCell,
707 OUT PULONG Type OPTIONAL,
708 OUT PUCHAR Data OPTIONAL,
709 IN OUT PULONG DataSize OPTIONAL)
710 {
711 ULONG DataLength;
712 PVOID DataCell;
713
714 /* Does the caller want the type? */
715 if (Type != NULL)
716 *Type = ValueCell->Type;
717
718 /* Does the caller provide DataSize? */
719 if (DataSize != NULL)
720 {
721 // NOTE: CmpValueToData doesn't support big data (the function will
722 // bugcheck if so), FreeLdr is not supposed to read such data.
723 // If big data is needed, use instead CmpGetValueData.
724 // CmpGetValueData(Hive, ValueCell, DataSize, &DataCell, ...);
725 DataCell = CmpValueToData(Hive, ValueCell, &DataLength);
726
727 /* Does the caller want the data? */
728 if ((Data != NULL) && (*DataSize != 0))
729 {
730 RtlCopyMemory(Data,
731 DataCell,
732 min(*DataSize, DataLength));
733 }
734
735 /* Return the actual data length */
736 *DataSize = DataLength;
737 }
738 }
739
740 // Similar to RegQueryValue in freeldr/windows/registry.c
741 LONG WINAPI
742 RegQueryValueExW(
743 IN HKEY hKey,
744 IN LPCWSTR lpValueName,
745 IN PULONG lpReserved,
746 OUT PULONG lpType OPTIONAL,
747 OUT PUCHAR lpData OPTIONAL,
748 IN OUT PULONG lpcbData OPTIONAL)
749 {
750 PMEMKEY ParentKey = HKEY_TO_MEMKEY(hKey);
751 PHHIVE Hive = &ParentKey->RegistryHive->Hive;
752 PCM_KEY_NODE KeyNode;
753 PCM_KEY_VALUE ValueCell;
754 HCELL_INDEX CellIndex;
755 UNICODE_STRING ValueNameString;
756
757 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey->KeyCellOffset);
758 if (!KeyNode)
759 return ERROR_UNSUCCESSFUL;
760
761 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
762
763 /* Initialize value name string */
764 RtlInitUnicodeString(&ValueNameString, lpValueName);
765 CellIndex = CmpFindValueByName(Hive, KeyNode, &ValueNameString);
766 if (CellIndex == HCELL_NIL)
767 return ERROR_FILE_NOT_FOUND;
768
769 /* Get the value cell */
770 ValueCell = HvGetCell(Hive, CellIndex);
771 ASSERT(ValueCell != NULL);
772
773 RepGetValueData(Hive, ValueCell, lpType, lpData, lpcbData);
774
775 HvReleaseCell(Hive, CellIndex);
776
777 return ERROR_SUCCESS;
778 }
779
780 LONG WINAPI
781 RegDeleteValueW(
782 IN HKEY hKey,
783 IN LPCWSTR lpValueName OPTIONAL)
784 {
785 DPRINT1("RegDeleteValueW(0x%p, '%S') is UNIMPLEMENTED!\n",
786 hKey, (lpValueName ? lpValueName : L""));
787 return ERROR_UNSUCCESSFUL;
788 }
789
790
791 static BOOL
792 ConnectRegistry(
793 IN HKEY RootKey,
794 IN PCMHIVE HiveToConnect,
795 IN PUCHAR SecurityDescriptor,
796 IN ULONG SecurityDescriptorLength,
797 IN PCWSTR Path)
798 {
799 NTSTATUS Status;
800 LONG rc;
801 PREPARSE_POINT ReparsePoint;
802 PMEMKEY NewKey;
803
804 ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
805 if (!ReparsePoint)
806 return FALSE;
807
808 /*
809 * Use a dummy root key name:
810 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
811 * - On Vista+, this is "CMI-CreateHive{guid}"
812 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
813 * for more information.
814 */
815 Status = CmiInitializeHive(HiveToConnect, L"$$$PROTO.HIV");
816 if (!NT_SUCCESS(Status))
817 {
818 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status);
819 free(ReparsePoint);
820 return FALSE;
821 }
822
823 /*
824 * Add security to the root key.
825 * NOTE: One can implement this using the lpSecurityAttributes
826 * parameter of RegCreateKeyExW.
827 */
828 Status = CmiCreateSecurityKey(&HiveToConnect->Hive,
829 HiveToConnect->Hive.BaseBlock->RootCell,
830 SecurityDescriptor, SecurityDescriptorLength);
831 if (!NT_SUCCESS(Status))
832 DPRINT1("Failed to add security for root key '%S'\n", Path);
833
834 /* Create the key */
835 rc = RegCreateKeyExW(RootKey,
836 Path,
837 0,
838 NULL,
839 REG_OPTION_VOLATILE,
840 0,
841 NULL,
842 (PHKEY)&NewKey,
843 NULL);
844 if (rc != ERROR_SUCCESS)
845 {
846 free(ReparsePoint);
847 return FALSE;
848 }
849
850 ReparsePoint->SourceHive = NewKey->RegistryHive;
851 ReparsePoint->SourceKeyCellOffset = NewKey->KeyCellOffset;
852 NewKey->RegistryHive = HiveToConnect;
853 NewKey->KeyCellOffset = HiveToConnect->Hive.BaseBlock->RootCell;
854 ReparsePoint->DestinationHive = NewKey->RegistryHive;
855 ReparsePoint->DestinationKeyCellOffset = NewKey->KeyCellOffset;
856 InsertTailList(&CmiReparsePointsHead, &ReparsePoint->ListEntry);
857
858 return TRUE;
859 }
860
861 static BOOL
862 CreateSymLink(
863 IN PCWSTR LinkKeyPath OPTIONAL,
864 IN OUT PHKEY LinkKeyHandle OPTIONAL,
865 // IN PCWSTR TargetKeyPath OPTIONAL,
866 IN HKEY TargetKeyHandle)
867 {
868 PMEMKEY LinkKey, TargetKey;
869 PREPARSE_POINT ReparsePoint;
870
871 ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
872 if (!ReparsePoint)
873 return FALSE;
874
875 if (LinkKeyPath && !(LinkKeyHandle && *LinkKeyHandle))
876 {
877 /* Create the link key */
878 RegCreateKeyExW(NULL,
879 LinkKeyPath,
880 0,
881 NULL,
882 REG_OPTION_VOLATILE,
883 0,
884 NULL,
885 (HKEY*)&LinkKey,
886 NULL);
887 }
888 else if (LinkKeyHandle)
889 {
890 /* Use the user-provided link key handle */
891 LinkKey = HKEY_TO_MEMKEY(*LinkKeyHandle);
892 }
893
894 if (LinkKeyHandle)
895 *LinkKeyHandle = MEMKEY_TO_HKEY(LinkKey);
896
897 TargetKey = HKEY_TO_MEMKEY(TargetKeyHandle);
898
899 ReparsePoint->SourceHive = LinkKey->RegistryHive;
900 ReparsePoint->SourceKeyCellOffset = LinkKey->KeyCellOffset;
901 ReparsePoint->DestinationHive = TargetKey->RegistryHive;
902 ReparsePoint->DestinationKeyCellOffset = TargetKey->KeyCellOffset;
903 InsertTailList(&CmiReparsePointsHead, &ReparsePoint->ListEntry);
904
905 return TRUE;
906 }
907
908 VOID
909 RegInitializeRegistry(
910 IN PCSTR HiveList)
911 {
912 NTSTATUS Status;
913 UINT i;
914 HKEY ControlSetKey;
915
916 InitializeListHead(&CmiHiveListHead);
917 InitializeListHead(&CmiReparsePointsHead);
918
919 Status = CmiInitializeHive(&RootHive, L"");
920 if (!NT_SUCCESS(Status))
921 {
922 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status);
923 return;
924 }
925
926 RootKey = CreateInMemoryStructure(&RootHive,
927 RootHive.Hive.BaseBlock->RootCell);
928
929 for (i = 0; i < _countof(RegistryHives); ++i)
930 {
931 /* Skip this registry hive if it's not in the list */
932 if (!strstr(HiveList, RegistryHives[i].HiveName))
933 continue;
934
935 /* Create the registry key */
936 ConnectRegistry(NULL,
937 RegistryHives[i].CmHive,
938 RegistryHives[i].SecurityDescriptor,
939 RegistryHives[i].SecurityDescriptorLength,
940 RegistryHives[i].HiveRegistryPath);
941
942 /* If we happen to deal with the special setup registry hive, stop there */
943 // if (strcmp(RegistryHives[i].HiveName, "SETUPREG") == 0)
944 if (i == 0)
945 break;
946 }
947
948 /* Create the 'ControlSet001' key */
949 RegCreateKeyW(NULL,
950 L"Registry\\Machine\\SYSTEM\\ControlSet001",
951 &ControlSetKey);
952
953 /* Create the 'CurrentControlSet' key as a symlink to 'ControlSet001' */
954 CreateSymLink(L"Registry\\Machine\\SYSTEM\\CurrentControlSet",
955 NULL, ControlSetKey);
956
957 RegCloseKey(ControlSetKey);
958
959 #if 0
960 /* Link SECURITY to SAM */
961 CmpLinkKeyToHive(L"\\Registry\\Machine\\Security\\SAM", L"\\Registry\\Machine\\SAM\\SAM");
962 /* Link S-1-5-18 to .Default */
963 CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18", L"\\Registry\\User\\.Default");
964 #endif
965 }
966
967 VOID
968 RegShutdownRegistry(VOID)
969 {
970 PLIST_ENTRY Entry;
971 PREPARSE_POINT ReparsePoint;
972
973 /* Clean up the reparse points list */
974 while (!IsListEmpty(&CmiReparsePointsHead))
975 {
976 Entry = RemoveHeadList(&CmiReparsePointsHead);
977 ReparsePoint = CONTAINING_RECORD(Entry, REPARSE_POINT, ListEntry);
978 free(ReparsePoint);
979 }
980
981 /* FIXME: clean up the complete hive */
982
983 free(RootKey);
984 }
985
986 /* EOF */