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 "registry.h" 24 #include <internal/cmboot.h> 25 26 #include <debug.h> 27 DBG_DEFAULT_CHANNEL(REGISTRY); 28 29 static PCMHIVE CmSystemHive; 30 static HCELL_INDEX SystemRootCell; 31 32 PHHIVE SystemHive = NULL; 33 HKEY CurrentControlSetKey = NULL; 34 35 #define HCI_TO_HKEY(CellIndex) ((HKEY)(ULONG_PTR)(CellIndex)) 36 #ifndef HKEY_TO_HCI // See also registry.h 37 #define HKEY_TO_HCI(hKey) ((HCELL_INDEX)(ULONG_PTR)(hKey)) 38 #endif 39 40 #define GET_HHIVE(CmHive) (&((CmHive)->Hive)) 41 #define GET_HHIVE_FROM_HKEY(hKey) GET_HHIVE(CmSystemHive) 42 #define GET_CM_KEY_NODE(hHive, hKey) ((PCM_KEY_NODE)HvGetCell(hHive, HKEY_TO_HCI(hKey))) 43 44 PVOID 45 NTAPI 46 CmpAllocate( 47 IN SIZE_T Size, 48 IN BOOLEAN Paged, 49 IN ULONG Tag) 50 { 51 UNREFERENCED_PARAMETER(Paged); 52 return FrLdrHeapAlloc(Size, Tag); 53 } 54 55 VOID 56 NTAPI 57 CmpFree( 58 IN PVOID Ptr, 59 IN ULONG Quota) 60 { 61 UNREFERENCED_PARAMETER(Quota); 62 FrLdrHeapFree(Ptr, 0); 63 } 64 65 BOOLEAN 66 RegImportBinaryHive( 67 _In_ PVOID ChunkBase, 68 _In_ ULONG ChunkSize) 69 { 70 NTSTATUS Status; 71 PCM_KEY_NODE KeyNode; 72 73 TRACE("RegImportBinaryHive(%p, 0x%lx)\n", ChunkBase, ChunkSize); 74 75 /* Allocate and initialize the hive */ 76 CmSystemHive = FrLdrTempAlloc(sizeof(CMHIVE), 'eviH'); 77 Status = HvInitialize(GET_HHIVE(CmSystemHive), 78 HINIT_FLAT, // HINIT_MEMORY_INPLACE 79 0, 80 0, 81 ChunkBase, 82 CmpAllocate, 83 CmpFree, 84 NULL, 85 NULL, 86 NULL, 87 NULL, 88 1, 89 NULL); 90 if (!NT_SUCCESS(Status)) 91 { 92 ERR("Corrupted hive %p!\n", ChunkBase); 93 FrLdrTempFree(CmSystemHive, 'eviH'); 94 return FALSE; 95 } 96 97 /* Save the root key node */ 98 SystemHive = GET_HHIVE(CmSystemHive); 99 SystemRootCell = SystemHive->BaseBlock->RootCell; 100 ASSERT(SystemRootCell != HCELL_NIL); 101 102 /* Verify it is accessible */ 103 KeyNode = (PCM_KEY_NODE)HvGetCell(SystemHive, SystemRootCell); 104 ASSERT(KeyNode); 105 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE); 106 HvReleaseCell(SystemHive, SystemRootCell); 107 108 return TRUE; 109 } 110 111 BOOLEAN 112 RegInitCurrentControlSet( 113 _In_ BOOLEAN LastKnownGood) 114 { 115 UNICODE_STRING ControlSetName; 116 HCELL_INDEX ControlCell; 117 PCM_KEY_NODE KeyNode; 118 BOOLEAN AutoSelect; 119 120 TRACE("RegInitCurrentControlSet\n"); 121 122 /* Choose which control set to open and set it as the new "Current" */ 123 RtlInitUnicodeString(&ControlSetName, 124 LastKnownGood ? L"LastKnownGood" 125 : L"Default"); 126 127 ControlCell = CmpFindControlSet(SystemHive, 128 SystemRootCell, 129 &ControlSetName, 130 &AutoSelect); 131 if (ControlCell == HCELL_NIL) 132 { 133 ERR("CmpFindControlSet('%wZ') failed\n", &ControlSetName); 134 return FALSE; 135 } 136 137 CurrentControlSetKey = HCI_TO_HKEY(ControlCell); 138 139 /* Verify it is accessible */ 140 KeyNode = (PCM_KEY_NODE)HvGetCell(SystemHive, ControlCell); 141 ASSERT(KeyNode); 142 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE); 143 HvReleaseCell(SystemHive, ControlCell); 144 145 return TRUE; 146 } 147 148 static 149 BOOLEAN 150 GetNextPathElement( 151 _Out_ PUNICODE_STRING NextElement, 152 _Inout_ PUNICODE_STRING RemainingPath) 153 { 154 /* Check if there are any characters left */ 155 if (RemainingPath->Length < sizeof(WCHAR)) 156 { 157 /* Nothing left, bail out early */ 158 return FALSE; 159 } 160 161 /* The next path elements starts with the remaining path */ 162 NextElement->Buffer = RemainingPath->Buffer; 163 164 /* Loop until the path element ends */ 165 while ((RemainingPath->Length >= sizeof(WCHAR)) && 166 (RemainingPath->Buffer[0] != '\\')) 167 { 168 /* Skip this character */ 169 RemainingPath->Buffer++; 170 RemainingPath->Length -= sizeof(WCHAR); 171 } 172 173 NextElement->Length = (USHORT)(RemainingPath->Buffer - NextElement->Buffer) * sizeof(WCHAR); 174 NextElement->MaximumLength = NextElement->Length; 175 176 /* Check if the path element ended with a path separator */ 177 if (RemainingPath->Length >= sizeof(WCHAR)) 178 { 179 /* Skip the path separator */ 180 ASSERT(RemainingPath->Buffer[0] == '\\'); 181 RemainingPath->Buffer++; 182 RemainingPath->Length -= sizeof(WCHAR); 183 } 184 185 /* Return whether we got any characters */ 186 return TRUE; 187 } 188 189 #if 0 190 LONG 191 RegEnumKey( 192 _In_ HKEY Key, 193 _In_ ULONG Index, 194 _Out_ PWCHAR Name, 195 _Inout_ PULONG NameSize, 196 _Out_opt_ PHKEY SubKey) 197 { 198 PHHIVE Hive = GET_HHIVE_FROM_HKEY(Key); 199 PCM_KEY_NODE KeyNode, SubKeyNode; 200 HCELL_INDEX CellIndex; 201 USHORT NameLength; 202 203 TRACE("RegEnumKey(%p, %lu, %p, %p->%u)\n", 204 Key, Index, Name, NameSize, NameSize ? *NameSize : 0); 205 206 /* Get the key node */ 207 KeyNode = GET_CM_KEY_NODE(Hive, Key); 208 ASSERT(KeyNode); 209 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE); 210 211 CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, Index); 212 if (CellIndex == HCELL_NIL) 213 { 214 TRACE("RegEnumKey index out of bounds (%d) in key (%.*s)\n", 215 Index, KeyNode->NameLength, KeyNode->Name); 216 HvReleaseCell(Hive, HKEY_TO_HCI(Key)); 217 return ERROR_NO_MORE_ITEMS; 218 } 219 HvReleaseCell(Hive, HKEY_TO_HCI(Key)); 220 221 /* Get the value cell */ 222 SubKeyNode = (PCM_KEY_NODE)HvGetCell(Hive, CellIndex); 223 ASSERT(SubKeyNode != NULL); 224 ASSERT(SubKeyNode->Signature == CM_KEY_NODE_SIGNATURE); 225 226 if (SubKeyNode->Flags & KEY_COMP_NAME) 227 { 228 NameLength = CmpCompressedNameSize(SubKeyNode->Name, SubKeyNode->NameLength); 229 230 /* Compressed name */ 231 CmpCopyCompressedName(Name, 232 *NameSize, 233 SubKeyNode->Name, 234 SubKeyNode->NameLength); 235 } 236 else 237 { 238 NameLength = SubKeyNode->NameLength; 239 240 /* Normal name */ 241 RtlCopyMemory(Name, SubKeyNode->Name, 242 min(*NameSize, SubKeyNode->NameLength)); 243 } 244 245 if (*NameSize >= NameLength + sizeof(WCHAR)) 246 { 247 Name[NameLength / sizeof(WCHAR)] = UNICODE_NULL; 248 } 249 250 *NameSize = NameLength + sizeof(WCHAR); 251 252 HvReleaseCell(Hive, CellIndex); 253 254 if (SubKey != NULL) 255 *SubKey = HCI_TO_HKEY(CellIndex); 256 257 TRACE("RegEnumKey done -> %u, '%.*S'\n", *NameSize, *NameSize, Name); 258 return ERROR_SUCCESS; 259 } 260 #endif 261 262 LONG 263 RegOpenKey( 264 _In_ HKEY ParentKey, 265 _In_z_ PCWSTR KeyName, 266 _Out_ PHKEY Key) 267 { 268 UNICODE_STRING RemainingPath, SubKeyName; 269 UNICODE_STRING CurrentControlSet = RTL_CONSTANT_STRING(L"CurrentControlSet"); 270 PHHIVE Hive = (ParentKey ? GET_HHIVE_FROM_HKEY(ParentKey) : GET_HHIVE(CmSystemHive)); 271 PCM_KEY_NODE KeyNode; 272 HCELL_INDEX CellIndex; 273 274 TRACE("RegOpenKey(%p, '%S', %p)\n", ParentKey, KeyName, Key); 275 276 /* Initialize the remaining path name */ 277 RtlInitUnicodeString(&RemainingPath, KeyName); 278 279 /* Check if we have a parent key */ 280 if (ParentKey == NULL) 281 { 282 UNICODE_STRING SubKeyName1, SubKeyName2, SubKeyName3; 283 UNICODE_STRING RegistryPath = RTL_CONSTANT_STRING(L"Registry"); 284 UNICODE_STRING MachinePath = RTL_CONSTANT_STRING(L"MACHINE"); 285 UNICODE_STRING SystemPath = RTL_CONSTANT_STRING(L"SYSTEM"); 286 287 TRACE("RegOpenKey: absolute path\n"); 288 289 if ((RemainingPath.Length < sizeof(WCHAR)) || 290 RemainingPath.Buffer[0] != '\\') 291 { 292 /* The key path is not absolute */ 293 ERR("RegOpenKey: invalid path '%S' (%wZ)\n", KeyName, &RemainingPath); 294 return ERROR_PATH_NOT_FOUND; 295 } 296 297 /* Skip initial path separator */ 298 RemainingPath.Buffer++; 299 RemainingPath.Length -= sizeof(WCHAR); 300 301 /* Get the first 3 path elements */ 302 GetNextPathElement(&SubKeyName1, &RemainingPath); 303 GetNextPathElement(&SubKeyName2, &RemainingPath); 304 GetNextPathElement(&SubKeyName3, &RemainingPath); 305 TRACE("RegOpenKey: %wZ / %wZ / %wZ\n", &SubKeyName1, &SubKeyName2, &SubKeyName3); 306 307 /* Check if we have the correct path */ 308 if (!RtlEqualUnicodeString(&SubKeyName1, &RegistryPath, TRUE) || 309 !RtlEqualUnicodeString(&SubKeyName2, &MachinePath, TRUE) || 310 !RtlEqualUnicodeString(&SubKeyName3, &SystemPath, TRUE)) 311 { 312 /* The key path is not inside HKLM\Machine\System */ 313 ERR("RegOpenKey: invalid path '%S' (%wZ)\n", KeyName, &RemainingPath); 314 return ERROR_PATH_NOT_FOUND; 315 } 316 317 /* Use the root key */ 318 CellIndex = SystemRootCell; 319 } 320 else 321 { 322 /* Use the parent key */ 323 CellIndex = HKEY_TO_HCI(ParentKey); 324 } 325 326 /* Check if this is the root key */ 327 if (CellIndex == SystemRootCell) 328 { 329 UNICODE_STRING TempPath = RemainingPath; 330 331 /* Get the first path element */ 332 GetNextPathElement(&SubKeyName, &TempPath); 333 334 /* Check if this is CurrentControlSet */ 335 if (RtlEqualUnicodeString(&SubKeyName, &CurrentControlSet, TRUE)) 336 { 337 /* Use the CurrentControlSetKey and update the remaining path */ 338 CellIndex = HKEY_TO_HCI(CurrentControlSetKey); 339 RemainingPath = TempPath; 340 } 341 } 342 343 /* Get the key node */ 344 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, CellIndex); 345 ASSERT(KeyNode); 346 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE); 347 348 TRACE("RegOpenKey: RemainingPath '%wZ'\n", &RemainingPath); 349 350 /* Loop while there are path elements */ 351 while (GetNextPathElement(&SubKeyName, &RemainingPath)) 352 { 353 HCELL_INDEX NextCellIndex; 354 355 TRACE("RegOpenKey: next element '%wZ'\n", &SubKeyName); 356 357 /* Get the next sub key */ 358 NextCellIndex = CmpFindSubKeyByName(Hive, KeyNode, &SubKeyName); 359 HvReleaseCell(Hive, CellIndex); 360 CellIndex = NextCellIndex; 361 if (CellIndex == HCELL_NIL) 362 { 363 WARN("Did not find sub key '%wZ' (full: %S)\n", &SubKeyName, KeyName); 364 return ERROR_PATH_NOT_FOUND; 365 } 366 367 /* Get the found key */ 368 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, CellIndex); 369 ASSERT(KeyNode); 370 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE); 371 } 372 373 HvReleaseCell(Hive, CellIndex); 374 *Key = HCI_TO_HKEY(CellIndex); 375 376 return ERROR_SUCCESS; 377 } 378 379 static 380 VOID 381 RepGetValueData( 382 _In_ PHHIVE Hive, 383 _In_ PCM_KEY_VALUE ValueCell, 384 _Out_opt_ PULONG Type, 385 _Out_opt_ PUCHAR Data, 386 _Inout_opt_ PULONG DataSize) 387 { 388 ULONG DataLength; 389 PVOID DataCell; 390 391 /* Does the caller want the type? */ 392 if (Type != NULL) 393 *Type = ValueCell->Type; 394 395 /* Does the caller provide DataSize? */ 396 if (DataSize != NULL) 397 { 398 // NOTE: CmpValueToData doesn't support big data (the function will 399 // bugcheck if so), FreeLdr is not supposed to read such data. 400 // If big data is needed, use instead CmpGetValueData. 401 // CmpGetValueData(Hive, ValueCell, DataSize, &DataCell, ...); 402 DataCell = CmpValueToData(Hive, ValueCell, &DataLength); 403 404 /* Does the caller want the data? */ 405 if ((Data != NULL) && (*DataSize != 0)) 406 { 407 RtlCopyMemory(Data, 408 DataCell, 409 min(*DataSize, DataLength)); 410 } 411 412 /* Return the actual data length */ 413 *DataSize = DataLength; 414 } 415 } 416 417 LONG 418 RegQueryValue( 419 _In_ HKEY Key, 420 _In_z_ PCWSTR ValueName, 421 _Out_opt_ PULONG Type, 422 _Out_opt_ PUCHAR Data, 423 _Inout_opt_ PULONG DataSize) 424 { 425 PHHIVE Hive = GET_HHIVE_FROM_HKEY(Key); 426 PCM_KEY_NODE KeyNode; 427 PCM_KEY_VALUE ValueCell; 428 HCELL_INDEX CellIndex; 429 UNICODE_STRING ValueNameString; 430 431 TRACE("RegQueryValue(%p, '%S', %p, %p, %p)\n", 432 Key, ValueName, Type, Data, DataSize); 433 434 /* Get the key node */ 435 KeyNode = GET_CM_KEY_NODE(Hive, Key); 436 ASSERT(KeyNode); 437 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE); 438 439 /* Initialize value name string */ 440 RtlInitUnicodeString(&ValueNameString, ValueName); 441 CellIndex = CmpFindValueByName(Hive, KeyNode, &ValueNameString); 442 if (CellIndex == HCELL_NIL) 443 { 444 TRACE("RegQueryValue value not found in key (%.*s)\n", 445 KeyNode->NameLength, KeyNode->Name); 446 HvReleaseCell(Hive, HKEY_TO_HCI(Key)); 447 return ERROR_FILE_NOT_FOUND; 448 } 449 HvReleaseCell(Hive, HKEY_TO_HCI(Key)); 450 451 /* Get the value cell */ 452 ValueCell = (PCM_KEY_VALUE)HvGetCell(Hive, CellIndex); 453 ASSERT(ValueCell != NULL); 454 455 RepGetValueData(Hive, ValueCell, Type, Data, DataSize); 456 457 HvReleaseCell(Hive, CellIndex); 458 459 return ERROR_SUCCESS; 460 } 461 462 /* 463 * NOTE: This function is currently unused in FreeLdr; however it is kept here 464 * as an implementation reference of RegEnumValue using CMLIB that may be used 465 * elsewhere in ReactOS. 466 */ 467 #if 0 468 LONG 469 RegEnumValue( 470 _In_ HKEY Key, 471 _In_ ULONG Index, 472 _Out_ PWCHAR ValueName, 473 _Inout_ PULONG NameSize, 474 _Out_opt_ PULONG Type, 475 _Out_opt_ PUCHAR Data, 476 _Inout_opt_ PULONG DataSize) 477 { 478 PHHIVE Hive = GET_HHIVE_FROM_HKEY(Key); 479 PCM_KEY_NODE KeyNode; 480 PCELL_DATA ValueListCell; 481 PCM_KEY_VALUE ValueCell; 482 USHORT NameLength; 483 484 TRACE("RegEnumValue(%p, %lu, %S, %p, %p, %p, %p (%lu))\n", 485 Key, Index, ValueName, NameSize, Type, Data, DataSize, *DataSize); 486 487 /* Get the key node */ 488 KeyNode = GET_CM_KEY_NODE(Hive, Key); 489 ASSERT(KeyNode); 490 ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE); 491 492 /* Check if the index is valid */ 493 if ((KeyNode->ValueList.Count == 0) || 494 (KeyNode->ValueList.List == HCELL_NIL) || 495 (Index >= KeyNode->ValueList.Count)) 496 { 497 ERR("RegEnumValue: index invalid\n"); 498 HvReleaseCell(Hive, HKEY_TO_HCI(Key)); 499 return ERROR_NO_MORE_ITEMS; 500 } 501 502 ValueListCell = (PCELL_DATA)HvGetCell(Hive, KeyNode->ValueList.List); 503 ASSERT(ValueListCell != NULL); 504 505 /* Get the value cell */ 506 ValueCell = (PCM_KEY_VALUE)HvGetCell(Hive, ValueListCell->KeyList[Index]); 507 ASSERT(ValueCell != NULL); 508 ASSERT(ValueCell->Signature == CM_KEY_VALUE_SIGNATURE); 509 510 if (ValueCell->Flags & VALUE_COMP_NAME) 511 { 512 NameLength = CmpCompressedNameSize(ValueCell->Name, ValueCell->NameLength); 513 514 /* Compressed name */ 515 CmpCopyCompressedName(ValueName, 516 *NameSize, 517 ValueCell->Name, 518 ValueCell->NameLength); 519 } 520 else 521 { 522 NameLength = ValueCell->NameLength; 523 524 /* Normal name */ 525 RtlCopyMemory(ValueName, ValueCell->Name, 526 min(*NameSize, ValueCell->NameLength)); 527 } 528 529 if (*NameSize >= NameLength + sizeof(WCHAR)) 530 { 531 ValueName[NameLength / sizeof(WCHAR)] = UNICODE_NULL; 532 } 533 534 *NameSize = NameLength + sizeof(WCHAR); 535 536 RepGetValueData(Hive, ValueCell, Type, Data, DataSize); 537 538 HvReleaseCell(Hive, ValueListCell->KeyList[Index]); 539 HvReleaseCell(Hive, KeyNode->ValueList.List); 540 HvReleaseCell(Hive, HKEY_TO_HCI(Key)); 541 542 TRACE("RegEnumValue done -> %u, '%.*S'\n", *NameSize, *NameSize, ValueName); 543 return ERROR_SUCCESS; 544 } 545 #endif 546 547 /* EOF */ 548