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