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