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