[FREELDR]
[reactos.git] / reactos / boot / freeldr / freeldr / reactos / registry.c
1 /*
2 * FreeLoader
3 *
4 * Copyright (C) 2014 Timo Kreuzer <timo.kreuzer@reactos.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <freeldr.h>
22 #include <cmlib.h>
23 #include <debug.h>
24
25 DBG_DEFAULT_CHANNEL(REGISTRY);
26
27 static PCMHIVE CmHive;
28 static PCM_KEY_NODE RootKeyNode;
29 static FRLDRHKEY CurrentControlSetKey;
30
31 BOOLEAN
32 RegImportBinaryHive(
33 _In_ PCHAR ChunkBase,
34 _In_ ULONG ChunkSize)
35 {
36 NTSTATUS Status;
37 TRACE("RegImportBinaryHive(%p, 0x%lx)\n", ChunkBase, ChunkSize);
38
39 /* Allocate and initialize the hive */
40 CmHive = FrLdrTempAlloc(sizeof(CMHIVE), 'eviH');
41 Status = HvInitialize(&CmHive->Hive,
42 HINIT_FLAT,
43 0,
44 0,
45 ChunkBase,
46 NULL,
47 NULL,
48 NULL,
49 NULL,
50 NULL,
51 NULL,
52 1,
53 NULL);
54 if (!NT_SUCCESS(Status))
55 {
56 FrLdrTempFree(CmHive, 'eviH');
57 ERR("Invalid hive Signature!\n");
58 return FALSE;
59 }
60
61 /* Save the root key node */
62 RootKeyNode = HvGetCell(&CmHive->Hive, CmHive->Hive.BaseBlock->RootCell);
63
64 TRACE("RegImportBinaryHive done\n");
65 return TRUE;
66 }
67
68 VOID
69 RegInitializeRegistry(VOID)
70 {
71 /* Nothing to do */
72 }
73
74
75 LONG
76 RegInitCurrentControlSet(
77 _In_ BOOLEAN LastKnownGood)
78 {
79 WCHAR ControlSetKeyName[80];
80 FRLDRHKEY SelectKey;
81 FRLDRHKEY SystemKey;
82 ULONG CurrentSet = 0;
83 ULONG DefaultSet = 0;
84 ULONG LastKnownGoodSet = 0;
85 ULONG DataSize;
86 LONG Error;
87 TRACE("RegInitCurrentControlSet\n");
88
89 Error = RegOpenKey(NULL,
90 L"\\Registry\\Machine\\SYSTEM\\Select",
91 &SelectKey);
92 if (Error != ERROR_SUCCESS)
93 {
94 ERR("RegOpenKey() failed (Error %u)\n", (int)Error);
95 return Error;
96 }
97
98 DataSize = sizeof(ULONG);
99 Error = RegQueryValue(SelectKey,
100 L"Default",
101 NULL,
102 (PUCHAR)&DefaultSet,
103 &DataSize);
104 if (Error != ERROR_SUCCESS)
105 {
106 ERR("RegQueryValue('Default') failed (Error %u)\n", (int)Error);
107 return Error;
108 }
109
110 DataSize = sizeof(ULONG);
111 Error = RegQueryValue(SelectKey,
112 L"LastKnownGood",
113 NULL,
114 (PUCHAR)&LastKnownGoodSet,
115 &DataSize);
116 if (Error != ERROR_SUCCESS)
117 {
118 ERR("RegQueryValue('Default') failed (Error %u)\n", (int)Error);
119 return Error;
120 }
121
122 CurrentSet = (LastKnownGood == TRUE) ? LastKnownGoodSet : DefaultSet;
123 wcscpy(ControlSetKeyName, L"ControlSet");
124 switch(CurrentSet)
125 {
126 case 1:
127 wcscat(ControlSetKeyName, L"001");
128 break;
129 case 2:
130 wcscat(ControlSetKeyName, L"002");
131 break;
132 case 3:
133 wcscat(ControlSetKeyName, L"003");
134 break;
135 case 4:
136 wcscat(ControlSetKeyName, L"004");
137 break;
138 case 5:
139 wcscat(ControlSetKeyName, L"005");
140 break;
141 }
142
143 Error = RegOpenKey(NULL,
144 L"\\Registry\\Machine\\SYSTEM",
145 &SystemKey);
146 if (Error != ERROR_SUCCESS)
147 {
148 ERR("RegOpenKey(SystemKey) failed (Error %lu)\n", Error);
149 return Error;
150 }
151
152 Error = RegOpenKey(SystemKey,
153 ControlSetKeyName,
154 &CurrentControlSetKey);
155 if (Error != ERROR_SUCCESS)
156 {
157 ERR("RegOpenKey(CurrentControlSetKey) failed (Error %lu)\n", Error);
158 return Error;
159 }
160
161 TRACE("RegInitCurrentControlSet done\n");
162 return ERROR_SUCCESS;
163 }
164
165 static
166 BOOLEAN
167 GetNextPathElement(
168 _Out_ PUNICODE_STRING NextElement,
169 _Inout_ PUNICODE_STRING RemainingPath)
170 {
171 /* Check if there are any characters left */
172 if (RemainingPath->Length < sizeof(WCHAR))
173 {
174 /* Nothing left, bail out early */
175 return FALSE;
176 }
177
178 /* The next path elements starts with the remaining path */
179 NextElement->Buffer = RemainingPath->Buffer;
180
181 /* Loop until the path element ends */
182 while ((RemainingPath->Length >= sizeof(WCHAR)) &&
183 (RemainingPath->Buffer[0] != '\\'))
184 {
185 /* Skip this character */
186 RemainingPath->Buffer++;
187 RemainingPath->Length -= sizeof(WCHAR);
188 }
189
190 NextElement->Length = (RemainingPath->Buffer - NextElement->Buffer) * sizeof(WCHAR);
191 NextElement->MaximumLength = NextElement->Length;
192
193 /* Check if the path element ended with a path separator */
194 if (RemainingPath->Length >= sizeof(WCHAR))
195 {
196 /* Skip the path separator */
197 ASSERT(RemainingPath->Buffer[0] == '\\');
198 RemainingPath->Buffer++;
199 RemainingPath->Length -= sizeof(WCHAR);
200 }
201
202 /* Return whether we got any characters */
203 return TRUE;
204 }
205
206 static
207 PCM_KEY_NODE
208 RegpFindSubkeyInIndex(
209 _In_ PHHIVE Hive,
210 _In_ PCM_KEY_INDEX IndexCell,
211 _In_ PUNICODE_STRING SubKeyName)
212 {
213 PCM_KEY_NODE SubKeyNode;
214 ULONG i;
215 TRACE("RegpFindSubkeyInIndex('%wZ')\n", SubKeyName);
216
217 /* Check the cell type */
218 if ((IndexCell->Signature == CM_KEY_INDEX_ROOT) ||
219 (IndexCell->Signature == CM_KEY_INDEX_LEAF))
220 {
221 ASSERT(FALSE);
222
223 /* Enumerate subindex cells */
224 for (i = 0; i < IndexCell->Count; i++)
225 {
226 /* Get the subindex cell and call the function recursively */
227 PCM_KEY_INDEX SubIndexCell = HvGetCell(Hive, IndexCell->List[i]);
228
229 SubKeyNode = RegpFindSubkeyInIndex(Hive, SubIndexCell, SubKeyName);
230 if (SubKeyNode != NULL)
231 {
232 return SubKeyNode;
233 }
234 }
235 }
236 else if ((IndexCell->Signature == CM_KEY_FAST_LEAF) ||
237 (IndexCell->Signature == CM_KEY_HASH_LEAF))
238 {
239 /* Directly enumerate subkey nodes */
240 PCM_KEY_FAST_INDEX HashCell = (PCM_KEY_FAST_INDEX)IndexCell;
241 for (i = 0; i < HashCell->Count; i++)
242 {
243 SubKeyNode = HvGetCell(Hive, HashCell->List[i].Cell);
244 ASSERT(SubKeyNode->Signature == CM_KEY_NODE_SIGNATURE);
245
246 TRACE(" RegpFindSubkeyInIndex: checking '%.*s'\n",
247 SubKeyNode->NameLength, SubKeyNode->Name);
248 if (CmCompareKeyName(SubKeyNode, SubKeyName, TRUE))
249 {
250 return SubKeyNode;
251 }
252 }
253 }
254 else
255 {
256 ASSERT(FALSE);
257 }
258
259 return NULL;
260 }
261
262 LONG
263 RegEnumKey(
264 _In_ FRLDRHKEY Key,
265 _In_ ULONG Index,
266 _Out_ PWCHAR Name,
267 _Inout_ ULONG* NameSize,
268 _Out_opt_ FRLDRHKEY *SubKey)
269 {
270 PHHIVE Hive = &CmHive->Hive;
271 PCM_KEY_NODE KeyNode, SubKeyNode;
272 PCM_KEY_INDEX IndexCell;
273 PCM_KEY_FAST_INDEX HashCell;
274 TRACE("RegEnumKey(%p, %lu, %p, %p->%u)\n",
275 Key, Index, Name, NameSize, NameSize ? *NameSize : 0);
276
277 /* Get the key node */
278 KeyNode = (PCM_KEY_NODE)Key;
279 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
280
281 /* Check if the index is valid */
282 if ((KeyNode->SubKeyCounts[Stable] == 0) ||
283 (Index >= KeyNode->SubKeyCounts[Stable]))
284 {
285 TRACE("RegEnumKey index out of bounds\n");
286 return ERROR_NO_MORE_ITEMS;
287 }
288
289 /* Get the index cell */
290 IndexCell = HvGetCell(Hive, KeyNode->SubKeyLists[Stable]);
291 TRACE("IndexCell: %x, SubKeyCounts: %x\n", IndexCell, KeyNode->SubKeyCounts[Stable]);
292
293 /* Check the cell type */
294 if ((IndexCell->Signature == CM_KEY_FAST_LEAF) ||
295 (IndexCell->Signature == CM_KEY_HASH_LEAF))
296 {
297 /* Get the value cell */
298 HashCell = (PCM_KEY_FAST_INDEX)IndexCell;
299 SubKeyNode = HvGetCell(Hive, HashCell->List[Index].Cell);
300 }
301 else
302 {
303 ASSERT(FALSE);
304 }
305
306 *NameSize = CmCopyKeyName(SubKeyNode, Name, *NameSize);
307
308 if (SubKey != NULL)
309 {
310 *SubKey = (FRLDRHKEY)SubKeyNode;
311 }
312
313 TRACE("RegEnumKey done -> %u, '%.*s'\n", *NameSize, *NameSize, Name);
314 return STATUS_SUCCESS;
315 }
316
317 LONG
318 RegOpenKey(
319 _In_ FRLDRHKEY ParentKey,
320 _In_z_ PCWSTR KeyName,
321 _Out_ PFRLDRHKEY Key)
322 {
323 UNICODE_STRING RemainingPath, SubKeyName;
324 UNICODE_STRING CurrentControlSet = RTL_CONSTANT_STRING(L"CurrentControlSet");
325 PHHIVE Hive = &CmHive->Hive;
326 PCM_KEY_NODE KeyNode;
327 PCM_KEY_INDEX IndexCell;
328 TRACE("RegOpenKey(%p, '%S', %p)\n", ParentKey, KeyName, Key);
329
330 /* Initialize the remaining path name */
331 RtlInitUnicodeString(&RemainingPath, KeyName);
332
333 /* Get the parent key node */
334 KeyNode = (PCM_KEY_NODE)ParentKey;
335
336 /* Check if we have a parent key */
337 if (KeyNode == NULL)
338 {
339 UNICODE_STRING SubKeyName1, SubKeyName2, SubKeyName3;
340 UNICODE_STRING RegistryPath = RTL_CONSTANT_STRING(L"Registry");
341 UNICODE_STRING MachinePath = RTL_CONSTANT_STRING(L"MACHINE");
342 UNICODE_STRING SystemPath = RTL_CONSTANT_STRING(L"SYSTEM");
343 TRACE("RegOpenKey: absolute path\n");
344
345 if ((RemainingPath.Length < sizeof(WCHAR)) ||
346 RemainingPath.Buffer[0] != '\\')
347 {
348 /* The key path is not absolute */
349 ERR("RegOpenKey: invalid path '%S' (%wZ)\n", KeyName, &RemainingPath);
350 return ERROR_PATH_NOT_FOUND;
351 }
352
353 /* Skip initial path separator */
354 RemainingPath.Buffer++;
355 RemainingPath.Length -= sizeof(WCHAR);
356
357 /* Get the first 3 path elements */
358 GetNextPathElement(&SubKeyName1, &RemainingPath);
359 GetNextPathElement(&SubKeyName2, &RemainingPath);
360 GetNextPathElement(&SubKeyName3, &RemainingPath);
361 TRACE("RegOpenKey: %wZ / %wZ / %wZ\n", &SubKeyName1, &SubKeyName2, &SubKeyName3);
362
363 /* Check if we have the correct path */
364 if (!RtlEqualUnicodeString(&SubKeyName1, &RegistryPath, TRUE) ||
365 !RtlEqualUnicodeString(&SubKeyName2, &MachinePath, TRUE) ||
366 !RtlEqualUnicodeString(&SubKeyName3, &SystemPath, TRUE))
367 {
368 /* The key path is not inside HKLM\Machine\System */
369 ERR("RegOpenKey: invalid path '%S' (%wZ)\n", KeyName, &RemainingPath);
370 return ERROR_PATH_NOT_FOUND;
371 }
372
373 /* Use the root key */
374 KeyNode = RootKeyNode;
375 }
376
377 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
378
379 /* Check if this is the root key */
380 if (KeyNode == RootKeyNode)
381 {
382 UNICODE_STRING TempPath = RemainingPath;
383
384 /* Get the first path element */
385 GetNextPathElement(&SubKeyName, &TempPath);
386
387 /* Check if this is CurrentControlSet */
388 if (RtlEqualUnicodeString(&SubKeyName, &CurrentControlSet, TRUE))
389 {
390 /* Use the CurrentControlSetKey and update the remaining path */
391 KeyNode = (PCM_KEY_NODE)CurrentControlSetKey;
392 RemainingPath = TempPath;
393 }
394 }
395
396 TRACE("RegOpenKey: RemainingPath '%wZ'\n", &RemainingPath);
397
398 /* Loop while there are path elements */
399 while (GetNextPathElement(&SubKeyName, &RemainingPath))
400 {
401 TRACE("RegOpenKey: next element '%wZ'\n", &SubKeyName);
402
403 /* Check if there is any subkey */
404 if (KeyNode->SubKeyCounts[Stable] == 0)
405 {
406 return ERROR_PATH_NOT_FOUND;
407 }
408
409 /* Get the top level index cell */
410 IndexCell = HvGetCell(Hive, KeyNode->SubKeyLists[Stable]);
411
412 /* Get the next sub key */
413 KeyNode = RegpFindSubkeyInIndex(Hive, IndexCell, &SubKeyName);
414 if (KeyNode == NULL)
415 {
416
417 ERR("Did not find sub key '%wZ' (full %S)\n", &RemainingPath, KeyName);
418 return ERROR_PATH_NOT_FOUND;
419 }
420 }
421
422 TRACE("RegOpenKey done\n");
423 *Key = (FRLDRHKEY)KeyNode;
424 return ERROR_SUCCESS;
425 }
426
427 static
428 VOID
429 RepGetValueData(
430 _In_ PHHIVE Hive,
431 _In_ PCM_KEY_VALUE ValueCell,
432 _Out_opt_ ULONG* Type,
433 _Out_opt_ PUCHAR Data,
434 _Inout_opt_ ULONG* DataSize)
435 {
436 ULONG DataLength;
437
438 /* Does the caller want the type? */
439 if (Type != NULL)
440 {
441 *Type = ValueCell->Type;
442 }
443
444 /* Does the caller provide DataSize? */
445 if (DataSize != NULL)
446 {
447 /* Get the data length */
448 DataLength = ValueCell->DataLength & REG_DATA_SIZE_MASK;
449
450 /* Does the caller want the data? */
451 if ((Data != NULL) && (*DataSize != 0))
452 {
453 /* Check where the data is stored */
454 if ((DataLength <= sizeof(HCELL_INDEX)) &&
455 (ValueCell->DataLength & REG_DATA_IN_OFFSET))
456 {
457 /* The data member contains the data */
458 RtlCopyMemory(Data,
459 &ValueCell->Data,
460 min(*DataSize, DataLength));
461 }
462 else
463 {
464 /* The data member contains the data cell index */
465 PVOID DataCell = HvGetCell(Hive, ValueCell->Data);
466 RtlCopyMemory(Data,
467 DataCell,
468 min(*DataSize, ValueCell->DataLength));
469 }
470
471 }
472
473 /* Return the actual data length */
474 *DataSize = DataLength;
475 }
476 }
477
478 LONG
479 RegQueryValue(
480 _In_ FRLDRHKEY Key,
481 _In_z_ PCWSTR ValueName,
482 _Out_opt_ ULONG* Type,
483 _Out_opt_ PUCHAR Data,
484 _Inout_opt_ ULONG* DataSize)
485 {
486 PHHIVE Hive = &CmHive->Hive;
487 PCM_KEY_NODE KeyNode;
488 PCM_KEY_VALUE ValueCell;
489 PVALUE_LIST_CELL ValueListCell;
490 UNICODE_STRING ValueNameString;
491 ULONG i;
492 TRACE("RegQueryValue(%p, '%S', %p, %p, %p)\n",
493 Key, ValueName, Type, Data, DataSize);
494
495 /* Get the key node */
496 KeyNode = (PCM_KEY_NODE)Key;
497 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
498
499 /* Check if there are any values */
500 if (KeyNode->ValueList.Count == 0)
501 {
502 TRACE("RegQueryValue no values in key (%.*s)\n",
503 KeyNode->NameLength, KeyNode->Name);
504 return ERROR_INVALID_PARAMETER;
505 }
506
507 /* Initialize value name string */
508 RtlInitUnicodeString(&ValueNameString, ValueName);
509
510 ValueListCell = (PVALUE_LIST_CELL)HvGetCell(Hive, KeyNode->ValueList.List);
511 TRACE("ValueListCell: %x\n", ValueListCell);
512
513 /* Loop all values */
514 for (i = 0; i < KeyNode->ValueList.Count; i++)
515 {
516 /* Get the subkey node and check the name */
517 ValueCell = HvGetCell(Hive, ValueListCell->ValueOffset[i]);
518
519 /* Compare the value name */
520 TRACE("checking %.*s\n", ValueCell->NameLength, ValueCell->Name);
521 if (CmCompareKeyValueName(ValueCell, &ValueNameString, TRUE))
522 {
523 RepGetValueData(Hive, ValueCell, Type, Data, DataSize);
524 TRACE("RegQueryValue success\n");
525 return STATUS_SUCCESS;
526 }
527 }
528
529 TRACE("RegQueryValue value not found\n");
530 return ERROR_INVALID_PARAMETER;
531 }
532
533
534 LONG
535 RegEnumValue(
536 _In_ FRLDRHKEY Key,
537 _In_ ULONG Index,
538 _Out_ PWCHAR ValueName,
539 _Inout_ ULONG* NameSize,
540 _Out_ ULONG* Type,
541 _Out_ PUCHAR Data,
542 _Inout_ ULONG* DataSize)
543 {
544 PHHIVE Hive = &CmHive->Hive;
545 PCM_KEY_NODE KeyNode;
546 PCM_KEY_VALUE ValueCell;
547 PVALUE_LIST_CELL ValueListCell;
548 TRACE("RegEnumValue(%p, %lu, %S, %p, %p, %p, %p (%lu))\n",
549 Key, Index, ValueName, NameSize, Type, Data, DataSize, *DataSize);
550
551 /* Get the key node */
552 KeyNode = (PCM_KEY_NODE)Key;
553 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
554
555 /* Check if the index is valid */
556 if ((KeyNode->ValueList.Count == 0) ||
557 (Index >= KeyNode->ValueList.Count))
558 {
559 ERR("RegEnumValue: index invalid\n");
560 return ERROR_NO_MORE_ITEMS;
561 }
562
563 ValueListCell = (PVALUE_LIST_CELL)HvGetCell(Hive, KeyNode->ValueList.List);
564 TRACE("ValueListCell: %x\n", ValueListCell);
565
566 /* Get the value cell */
567 ValueCell = HvGetCell(Hive, ValueListCell->ValueOffset[Index]);
568 ASSERT(ValueCell != NULL);
569
570 if (NameSize != NULL)
571 {
572 *NameSize = CmCopyKeyValueName(ValueCell, ValueName, *NameSize);
573 }
574
575 RepGetValueData(Hive, ValueCell, Type, Data, DataSize);
576
577 if (DataSize != NULL)
578 {
579 if ((Data != NULL) && (*DataSize != 0))
580 {
581 RtlCopyMemory(Data,
582 &ValueCell->Data,
583 min(*DataSize, ValueCell->DataLength));
584 }
585
586 *DataSize = ValueCell->DataLength;
587 }
588
589 TRACE("RegEnumValue done\n");
590 return STATUS_SUCCESS;
591 }
592
593 /* EOF */