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