432b3df0cc0323c3f59ef52b849c43464bc7a3c7
[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 ULONG ChildIndex;
561 HCELL_INDEX CellIndex;
562 UNICODE_STRING ValueNameString;
563
564 PVOID DataCell;
565 ULONG DataCellSize;
566 NTSTATUS Status;
567
568 if (dwType == REG_LINK)
569 {
570 PMEMKEY DestKey;
571
572 /* Special handling of registry links */
573 if (cbData != sizeof(PVOID))
574 return STATUS_INVALID_PARAMETER;
575
576 DestKey = HKEY_TO_MEMKEY(*(PHKEY)lpData);
577
578 // FIXME: Add additional checks for the validity of DestKey
579
580 /* Create the link in registry hive (if applicable) */
581 if (Key->RegistryHive != DestKey->RegistryHive)
582 return STATUS_SUCCESS;
583
584 DPRINT1("Save link to registry\n");
585 return STATUS_NOT_IMPLEMENTED;
586 }
587
588 if ((cbData & ~CM_KEY_VALUE_SPECIAL_SIZE) != cbData)
589 return STATUS_UNSUCCESSFUL;
590
591 Hive = &Key->RegistryHive->Hive;
592
593 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Key->KeyCellOffset);
594 if (!KeyNode)
595 return ERROR_UNSUCCESSFUL;
596
597 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
598
599 /* Mark the parent as dirty since we are going to create a new value in it */
600 HvMarkCellDirty(Hive, Key->KeyCellOffset, FALSE);
601
602 /* Initialize value name string */
603 RtlInitUnicodeString(&ValueNameString, lpValueName);
604 if (!CmpFindNameInList(Hive,
605 &KeyNode->ValueList,
606 &ValueNameString,
607 &ChildIndex,
608 &CellIndex))
609 {
610 /* Sanity check */
611 ASSERT(CellIndex == HCELL_NIL);
612 /* Fail */
613 // Status = STATUS_INSUFFICIENT_RESOURCES;
614 return ERROR_UNSUCCESSFUL;
615 }
616 if (CellIndex == HCELL_NIL)
617 {
618 /* The value doesn't exist, create a new one */
619 Status = CmiAddValueKey(Key->RegistryHive,
620 KeyNode,
621 ChildIndex,
622 &ValueNameString,
623 &ValueCell,
624 &CellIndex);
625 }
626 else
627 {
628 /* The value already exists, use it. Get the value cell. */
629 ValueCell = HvGetCell(&Key->RegistryHive->Hive, CellIndex);
630 ASSERT(ValueCell != NULL);
631 Status = STATUS_SUCCESS;
632 }
633
634 // /**/HvReleaseCell(Hive, CellIndex);/**/
635
636 if (!NT_SUCCESS(Status))
637 return ERROR_UNSUCCESSFUL;
638
639 /* Get size of the allocated cell (if any) */
640 if (!(ValueCell->DataLength & CM_KEY_VALUE_SPECIAL_SIZE) &&
641 (ValueCell->DataLength & ~CM_KEY_VALUE_SPECIAL_SIZE) != 0)
642 {
643 DataCell = HvGetCell(Hive, ValueCell->Data);
644 if (!DataCell)
645 return ERROR_UNSUCCESSFUL;
646
647 DataCellSize = (ULONG)(-HvGetCellSize(Hive, DataCell));
648 }
649 else
650 {
651 DataCell = NULL;
652 DataCellSize = 0;
653 }
654
655 if (cbData <= sizeof(HCELL_INDEX))
656 {
657 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
658 DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
659 if (DataCell)
660 HvFreeCell(Hive, ValueCell->Data);
661
662 RtlCopyMemory(&ValueCell->Data, lpData, cbData);
663 ValueCell->DataLength = (cbData | CM_KEY_VALUE_SPECIAL_SIZE);
664 ValueCell->Type = dwType;
665 }
666 else
667 {
668 if (cbData > DataCellSize)
669 {
670 /* New data size is larger than the current, destroy current
671 * data block and allocate a new one. */
672 HCELL_INDEX NewOffset;
673
674 DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
675
676 NewOffset = HvAllocateCell(Hive, cbData, Stable, HCELL_NIL);
677 if (NewOffset == HCELL_NIL)
678 {
679 DPRINT("HvAllocateCell() has failed!\n");
680 return ERROR_UNSUCCESSFUL;
681 }
682
683 if (DataCell)
684 HvFreeCell(Hive, ValueCell->Data);
685
686 ValueCell->Data = NewOffset;
687 DataCell = (PVOID)HvGetCell(Hive, NewOffset);
688 }
689
690 /* Copy new contents to cell */
691 RtlCopyMemory(DataCell, lpData, cbData);
692 ValueCell->DataLength = (cbData & ~CM_KEY_VALUE_SPECIAL_SIZE);
693 ValueCell->Type = dwType;
694 HvMarkCellDirty(Hive, ValueCell->Data, FALSE);
695 }
696
697 HvMarkCellDirty(Hive, CellIndex, FALSE);
698
699 /* Check if the maximum value name length changed, update it if so */
700 if (KeyNode->MaxValueNameLen < ValueNameString.Length)
701 KeyNode->MaxValueNameLen = ValueNameString.Length;
702
703 /* Check if the maximum data length changed, update it if so */
704 if (KeyNode->MaxValueDataLen < cbData)
705 KeyNode->MaxValueDataLen = cbData;
706
707 /* Save the write time */
708 KeQuerySystemTime(&KeyNode->LastWriteTime);
709
710 return ERROR_SUCCESS;
711 }
712
713
714 // Synced with freeldr/windows/registry.c
715 static
716 VOID
717 RepGetValueData(
718 IN PHHIVE Hive,
719 IN PCM_KEY_VALUE ValueCell,
720 OUT PULONG Type OPTIONAL,
721 OUT PUCHAR Data OPTIONAL,
722 IN OUT PULONG DataSize OPTIONAL)
723 {
724 ULONG DataLength;
725 PVOID DataCell;
726
727 /* Does the caller want the type? */
728 if (Type != NULL)
729 *Type = ValueCell->Type;
730
731 /* Does the caller provide DataSize? */
732 if (DataSize != NULL)
733 {
734 // NOTE: CmpValueToData doesn't support big data (the function will
735 // bugcheck if so), FreeLdr is not supposed to read such data.
736 // If big data is needed, use instead CmpGetValueData.
737 // CmpGetValueData(Hive, ValueCell, DataSize, &DataCell, ...);
738 DataCell = CmpValueToData(Hive, ValueCell, &DataLength);
739
740 /* Does the caller want the data? */
741 if ((Data != NULL) && (*DataSize != 0))
742 {
743 RtlCopyMemory(Data,
744 DataCell,
745 min(*DataSize, DataLength));
746 }
747
748 /* Return the actual data length */
749 *DataSize = DataLength;
750 }
751 }
752
753 // Similar to RegQueryValue in freeldr/windows/registry.c
754 LONG WINAPI
755 RegQueryValueExW(
756 IN HKEY hKey,
757 IN LPCWSTR lpValueName,
758 IN PULONG lpReserved,
759 OUT PULONG lpType OPTIONAL,
760 OUT PUCHAR lpData OPTIONAL,
761 IN OUT PULONG lpcbData OPTIONAL)
762 {
763 PMEMKEY ParentKey = HKEY_TO_MEMKEY(hKey);
764 PHHIVE Hive = &ParentKey->RegistryHive->Hive;
765 PCM_KEY_NODE KeyNode;
766 PCM_KEY_VALUE ValueCell;
767 HCELL_INDEX CellIndex;
768 UNICODE_STRING ValueNameString;
769
770 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey->KeyCellOffset);
771 if (!KeyNode)
772 return ERROR_UNSUCCESSFUL;
773
774 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
775
776 /* Initialize value name string */
777 RtlInitUnicodeString(&ValueNameString, lpValueName);
778 CellIndex = CmpFindValueByName(Hive, KeyNode, &ValueNameString);
779 if (CellIndex == HCELL_NIL)
780 return ERROR_FILE_NOT_FOUND;
781
782 /* Get the value cell */
783 ValueCell = HvGetCell(Hive, CellIndex);
784 ASSERT(ValueCell != NULL);
785
786 RepGetValueData(Hive, ValueCell, lpType, lpData, lpcbData);
787
788 HvReleaseCell(Hive, CellIndex);
789
790 return ERROR_SUCCESS;
791 }
792
793 LONG WINAPI
794 RegDeleteValueW(
795 IN HKEY hKey,
796 IN LPCWSTR lpValueName OPTIONAL)
797 {
798 DPRINT1("RegDeleteValueW(0x%p, '%S') is UNIMPLEMENTED!\n",
799 hKey, (lpValueName ? lpValueName : L""));
800 return ERROR_UNSUCCESSFUL;
801 }
802
803
804 static BOOL
805 ConnectRegistry(
806 IN HKEY RootKey,
807 IN PCMHIVE HiveToConnect,
808 IN PUCHAR SecurityDescriptor,
809 IN ULONG SecurityDescriptorLength,
810 IN PCWSTR Path)
811 {
812 NTSTATUS Status;
813 LONG rc;
814 PREPARSE_POINT ReparsePoint;
815 PMEMKEY NewKey;
816
817 ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
818 if (!ReparsePoint)
819 return FALSE;
820
821 /*
822 * Use a dummy root key name:
823 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
824 * - On Vista+, this is "CMI-CreateHive{guid}"
825 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
826 * for more information.
827 */
828 Status = CmiInitializeHive(HiveToConnect, L"$$$PROTO.HIV");
829 if (!NT_SUCCESS(Status))
830 {
831 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status);
832 free(ReparsePoint);
833 return FALSE;
834 }
835
836 /*
837 * Add security to the root key.
838 * NOTE: One can implement this using the lpSecurityAttributes
839 * parameter of RegCreateKeyExW.
840 */
841 Status = CmiCreateSecurityKey(&HiveToConnect->Hive,
842 HiveToConnect->Hive.BaseBlock->RootCell,
843 SecurityDescriptor, SecurityDescriptorLength);
844 if (!NT_SUCCESS(Status))
845 DPRINT1("Failed to add security for root key '%S'\n", Path);
846
847 /* Create the key */
848 rc = RegCreateKeyExW(RootKey,
849 Path,
850 0,
851 NULL,
852 REG_OPTION_VOLATILE,
853 0,
854 NULL,
855 (PHKEY)&NewKey,
856 NULL);
857 if (rc != ERROR_SUCCESS)
858 {
859 free(ReparsePoint);
860 return FALSE;
861 }
862
863 ReparsePoint->SourceHive = NewKey->RegistryHive;
864 ReparsePoint->SourceKeyCellOffset = NewKey->KeyCellOffset;
865 NewKey->RegistryHive = HiveToConnect;
866 NewKey->KeyCellOffset = HiveToConnect->Hive.BaseBlock->RootCell;
867 ReparsePoint->DestinationHive = NewKey->RegistryHive;
868 ReparsePoint->DestinationKeyCellOffset = NewKey->KeyCellOffset;
869 InsertTailList(&CmiReparsePointsHead, &ReparsePoint->ListEntry);
870
871 return TRUE;
872 }
873
874 static BOOL
875 CreateSymLink(
876 IN PCWSTR LinkKeyPath OPTIONAL,
877 IN OUT PHKEY LinkKeyHandle OPTIONAL,
878 // IN PCWSTR TargetKeyPath OPTIONAL,
879 IN HKEY TargetKeyHandle)
880 {
881 PMEMKEY LinkKey, TargetKey;
882 PREPARSE_POINT ReparsePoint;
883
884 ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
885 if (!ReparsePoint)
886 return FALSE;
887
888 if (LinkKeyPath && !(LinkKeyHandle && *LinkKeyHandle))
889 {
890 /* Create the link key */
891 RegCreateKeyExW(NULL,
892 LinkKeyPath,
893 0,
894 NULL,
895 REG_OPTION_VOLATILE,
896 0,
897 NULL,
898 (HKEY*)&LinkKey,
899 NULL);
900 }
901 else if (LinkKeyHandle)
902 {
903 /* Use the user-provided link key handle */
904 LinkKey = HKEY_TO_MEMKEY(*LinkKeyHandle);
905 }
906
907 if (LinkKeyHandle)
908 *LinkKeyHandle = MEMKEY_TO_HKEY(LinkKey);
909
910 TargetKey = HKEY_TO_MEMKEY(TargetKeyHandle);
911
912 ReparsePoint->SourceHive = LinkKey->RegistryHive;
913 ReparsePoint->SourceKeyCellOffset = LinkKey->KeyCellOffset;
914 ReparsePoint->DestinationHive = TargetKey->RegistryHive;
915 ReparsePoint->DestinationKeyCellOffset = TargetKey->KeyCellOffset;
916 InsertTailList(&CmiReparsePointsHead, &ReparsePoint->ListEntry);
917
918 return TRUE;
919 }
920
921 VOID
922 RegInitializeRegistry(
923 IN PCSTR HiveList)
924 {
925 NTSTATUS Status;
926 UINT i;
927 HKEY ControlSetKey;
928
929 InitializeListHead(&CmiHiveListHead);
930 InitializeListHead(&CmiReparsePointsHead);
931
932 Status = CmiInitializeHive(&RootHive, L"");
933 if (!NT_SUCCESS(Status))
934 {
935 DPRINT1("CmiInitializeHive() failed with status 0x%08x\n", Status);
936 return;
937 }
938
939 RootKey = CreateInMemoryStructure(&RootHive,
940 RootHive.Hive.BaseBlock->RootCell);
941
942 for (i = 0; i < _countof(RegistryHives); ++i)
943 {
944 /* Skip this registry hive if it's not in the list */
945 if (!strstr(HiveList, RegistryHives[i].HiveName))
946 continue;
947
948 /* Create the registry key */
949 ConnectRegistry(NULL,
950 RegistryHives[i].CmHive,
951 RegistryHives[i].SecurityDescriptor,
952 RegistryHives[i].SecurityDescriptorLength,
953 RegistryHives[i].HiveRegistryPath);
954
955 /* If we happen to deal with the special setup registry hive, stop there */
956 // if (strcmp(RegistryHives[i].HiveName, "SETUPREG") == 0)
957 if (i == 0)
958 break;
959 }
960
961 /* Create the 'ControlSet001' key */
962 RegCreateKeyW(NULL,
963 L"Registry\\Machine\\SYSTEM\\ControlSet001",
964 &ControlSetKey);
965
966 /* Create the 'CurrentControlSet' key as a symlink to 'ControlSet001' */
967 CreateSymLink(L"Registry\\Machine\\SYSTEM\\CurrentControlSet",
968 NULL, ControlSetKey);
969
970 RegCloseKey(ControlSetKey);
971
972 #if 0
973 /* Link SECURITY to SAM */
974 CmpLinkKeyToHive(L"\\Registry\\Machine\\Security\\SAM", L"\\Registry\\Machine\\SAM\\SAM");
975 /* Link S-1-5-18 to .Default */
976 CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18", L"\\Registry\\User\\.Default");
977 #endif
978 }
979
980 VOID
981 RegShutdownRegistry(VOID)
982 {
983 PLIST_ENTRY Entry;
984 PREPARSE_POINT ReparsePoint;
985
986 /* Clean up the reparse points list */
987 while (!IsListEmpty(&CmiReparsePointsHead))
988 {
989 Entry = RemoveHeadList(&CmiReparsePointsHead);
990 ReparsePoint = CONTAINING_RECORD(Entry, REPARSE_POINT, ListEntry);
991 free(ReparsePoint);
992 }
993
994 /* FIXME: clean up the complete hive */
995
996 free(RootKey);
997 }
998
999 /* EOF */