1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/config/cminit.c 5 * PURPOSE: Configuration Manager - Hive Initialization 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include "ntoskrnl.h" 12 #define NDEBUG 13 #include "debug.h" 14 15 /* FUNCTIONS *****************************************************************/ 16 17 NTSTATUS 18 NTAPI 19 CmpInitializeHive(OUT PCMHIVE *CmHive, 20 IN ULONG OperationType, 21 IN ULONG HiveFlags, 22 IN ULONG FileType, 23 IN PVOID HiveData OPTIONAL, 24 IN HANDLE Primary, 25 IN HANDLE Log, 26 IN HANDLE External, 27 IN PCUNICODE_STRING FileName OPTIONAL, 28 IN ULONG CheckFlags) 29 { 30 PCMHIVE Hive; 31 IO_STATUS_BLOCK IoStatusBlock; 32 FILE_FS_SIZE_INFORMATION FileSizeInformation; 33 NTSTATUS Status; 34 ULONG Cluster; 35 36 /* Assume failure */ 37 *CmHive = NULL; 38 39 /* 40 * The following are invalid: 41 * - An external hive that is also internal. 42 * - A log hive that is not a primary hive too. 43 * - A volatile hive that is linked to permanent storage, 44 * unless this hive is a shared system hive. 45 * - An in-memory initialization without hive data. 46 * - A log hive that is not linked to a correct file type. 47 */ 48 if (((External) && ((Primary) || (Log))) || 49 ((Log) && !(Primary)) || 50 (!(CmpShareSystemHives) && (HiveFlags & HIVE_VOLATILE) && 51 ((Primary) || (External) || (Log))) || 52 ((OperationType == HINIT_MEMORY) && (!HiveData)) || 53 ((Log) && (FileType != HFILE_TYPE_LOG))) 54 { 55 /* Fail the request */ 56 return STATUS_INVALID_PARAMETER; 57 } 58 59 /* Check if this is a primary hive */ 60 if (Primary) 61 { 62 /* Get the cluster size */ 63 Status = ZwQueryVolumeInformationFile(Primary, 64 &IoStatusBlock, 65 &FileSizeInformation, 66 sizeof(FILE_FS_SIZE_INFORMATION), 67 FileFsSizeInformation); 68 if (!NT_SUCCESS(Status)) return Status; 69 70 /* Make sure it's not larger then the block size */ 71 if (FileSizeInformation.BytesPerSector > HBLOCK_SIZE) 72 { 73 /* Fail */ 74 return STATUS_REGISTRY_IO_FAILED; 75 } 76 77 /* Otherwise, calculate the cluster */ 78 Cluster = FileSizeInformation.BytesPerSector / HSECTOR_SIZE; 79 Cluster = max(1, Cluster); 80 } 81 else 82 { 83 /* Otherwise use cluster 1 */ 84 Cluster = 1; 85 } 86 87 /* Allocate the hive */ 88 Hive = ExAllocatePoolWithTag(NonPagedPool, sizeof(CMHIVE), TAG_CMHIVE); 89 if (!Hive) return STATUS_INSUFFICIENT_RESOURCES; 90 91 /* Setup null fields */ 92 Hive->UnloadEvent = NULL; 93 Hive->RootKcb = NULL; 94 Hive->Frozen = FALSE; 95 Hive->UnloadWorkItem = NULL; 96 Hive->GrowOnlyMode = FALSE; 97 Hive->GrowOffset = 0; 98 Hive->CellRemapArray = NULL; 99 Hive->UseCountLog.Next = 0; 100 Hive->LockHiveLog.Next = 0; 101 Hive->FileObject = NULL; 102 Hive->NotifyList.Flink = NULL; 103 Hive->NotifyList.Blink = NULL; 104 105 /* Set the loading flag */ 106 Hive->HiveIsLoading = TRUE; 107 108 /* Set the current thread as creator */ 109 Hive->CreatorOwner = KeGetCurrentThread(); 110 111 /* Initialize lists */ 112 InitializeListHead(&Hive->KcbConvertListHead); 113 InitializeListHead(&Hive->KnodeConvertListHead); 114 InitializeListHead(&Hive->TrustClassEntry); 115 116 /* Allocate the view log */ 117 Hive->ViewLock = ExAllocatePoolWithTag(NonPagedPool, 118 sizeof(KGUARDED_MUTEX), 119 TAG_CMHIVE); 120 if (!Hive->ViewLock) 121 { 122 /* Cleanup allocation and fail */ 123 ExFreePoolWithTag(Hive, TAG_CMHIVE); 124 return STATUS_INSUFFICIENT_RESOURCES; 125 } 126 127 /* Allocate the flush lock */ 128 Hive->FlusherLock = ExAllocatePoolWithTag(NonPagedPool, 129 sizeof(ERESOURCE), 130 TAG_CMHIVE); 131 if (!Hive->FlusherLock) 132 { 133 /* Cleanup allocations and fail */ 134 ExFreePoolWithTag(Hive->ViewLock, TAG_CMHIVE); 135 ExFreePoolWithTag(Hive, TAG_CMHIVE); 136 return STATUS_INSUFFICIENT_RESOURCES; 137 } 138 139 /* Setup the handles */ 140 Hive->FileHandles[HFILE_TYPE_PRIMARY] = Primary; 141 Hive->FileHandles[HFILE_TYPE_LOG] = Log; 142 Hive->FileHandles[HFILE_TYPE_EXTERNAL] = External; 143 144 /* Initailize the guarded mutex */ 145 KeInitializeGuardedMutex(Hive->ViewLock); 146 Hive->ViewLockOwner = NULL; 147 148 /* Initialize the flush lock */ 149 ExInitializeResourceLite(Hive->FlusherLock); 150 151 /* Setup hive locks */ 152 ExInitializePushLock(&Hive->HiveLock); 153 Hive->HiveLockOwner = NULL; 154 ExInitializePushLock(&Hive->WriterLock); 155 Hive->WriterLockOwner = NULL; 156 ExInitializePushLock(&Hive->SecurityLock); 157 Hive->HiveSecurityLockOwner = NULL; 158 159 /* Clear file names */ 160 RtlInitEmptyUnicodeString(&Hive->FileUserName, NULL, 0); 161 RtlInitEmptyUnicodeString(&Hive->FileFullPath, NULL, 0); 162 163 /* Initialize the view list */ 164 CmpInitHiveViewList(Hive); 165 166 /* Initailize the security cache */ 167 CmpInitSecurityCache(Hive); 168 169 /* Setup flags */ 170 Hive->Flags = 0; 171 Hive->FlushCount = 0; 172 173 /* Initialize it */ 174 Status = HvInitialize(&Hive->Hive, 175 OperationType, 176 HiveFlags, 177 FileType, 178 HiveData, 179 CmpAllocate, 180 CmpFree, 181 CmpFileSetSize, 182 CmpFileWrite, 183 CmpFileRead, 184 CmpFileFlush, 185 Cluster, 186 FileName); 187 if (!NT_SUCCESS(Status)) 188 { 189 /* Cleanup allocations and fail */ 190 ExDeleteResourceLite(Hive->FlusherLock); 191 ExFreePoolWithTag(Hive->FlusherLock, TAG_CMHIVE); 192 ExFreePoolWithTag(Hive->ViewLock, TAG_CMHIVE); 193 ExFreePoolWithTag(Hive, TAG_CMHIVE); 194 return Status; 195 } 196 197 /* Check if we should verify the registry */ 198 if ((OperationType == HINIT_FILE) || 199 (OperationType == HINIT_MEMORY) || 200 (OperationType == HINIT_MEMORY_INPLACE) || 201 (OperationType == HINIT_MAPFILE)) 202 { 203 /* Verify integrity */ 204 ULONG CheckStatus = CmCheckRegistry(Hive, CheckFlags); 205 if (CheckStatus != 0) 206 { 207 /* Cleanup allocations and fail */ 208 ExDeleteResourceLite(Hive->FlusherLock); 209 ExFreePoolWithTag(Hive->FlusherLock, TAG_CMHIVE); 210 ExFreePoolWithTag(Hive->ViewLock, TAG_CMHIVE); 211 ExFreePoolWithTag(Hive, TAG_CMHIVE); 212 return STATUS_REGISTRY_CORRUPT; 213 } 214 } 215 216 /* Reset the loading flag */ 217 Hive->HiveIsLoading = FALSE; 218 219 /* Lock the hive list */ 220 ExAcquirePushLockExclusive(&CmpHiveListHeadLock); 221 222 /* Insert this hive */ 223 InsertHeadList(&CmpHiveListHead, &Hive->HiveList); 224 225 /* Release the lock */ 226 ExReleasePushLock(&CmpHiveListHeadLock); 227 228 /* Return the hive and success */ 229 *CmHive = Hive; 230 return STATUS_SUCCESS; 231 } 232 233 NTSTATUS 234 NTAPI 235 CmpDestroyHive(IN PCMHIVE CmHive) 236 { 237 /* Remove the hive from the list */ 238 ExAcquirePushLockExclusive(&CmpHiveListHeadLock); 239 RemoveEntryList(&CmHive->HiveList); 240 ExReleasePushLock(&CmpHiveListHeadLock); 241 242 /* Destroy the security descriptor cache */ 243 CmpDestroySecurityCache(CmHive); 244 245 /* Destroy the view list */ 246 CmpDestroyHiveViewList(CmHive); 247 248 /* Delete the flusher lock */ 249 ExDeleteResourceLite(CmHive->FlusherLock); 250 ExFreePoolWithTag(CmHive->FlusherLock, TAG_CMHIVE); 251 252 /* Delete the view lock */ 253 ExFreePoolWithTag(CmHive->ViewLock, TAG_CMHIVE); 254 255 /* Free the hive storage */ 256 HvFree(&CmHive->Hive); 257 258 /* Free the hive */ 259 CmpFree(CmHive, TAG_CM); 260 261 return STATUS_SUCCESS; 262 } 263 264 NTSTATUS 265 NTAPI 266 CmpOpenHiveFiles(IN PCUNICODE_STRING BaseName, 267 IN PCWSTR Extension OPTIONAL, 268 OUT PHANDLE Primary, 269 OUT PHANDLE Log, 270 OUT PULONG PrimaryDisposition, 271 OUT PULONG LogDisposition, 272 IN BOOLEAN CreateAllowed, 273 IN BOOLEAN MarkAsSystemHive, 274 IN BOOLEAN NoBuffering, 275 OUT PULONG ClusterSize OPTIONAL) 276 { 277 HANDLE EventHandle; 278 PKEVENT Event; 279 NTSTATUS Status; 280 UNICODE_STRING FullName, ExtensionName; 281 PWCHAR NameBuffer; 282 USHORT Length; 283 OBJECT_ATTRIBUTES ObjectAttributes; 284 IO_STATUS_BLOCK IoStatusBlock; 285 ULONG AttributeFlags, ShareMode, DesiredAccess, CreateDisposition, IoFlags; 286 USHORT CompressionState; 287 FILE_STANDARD_INFORMATION FileInformation; 288 FILE_FS_SIZE_INFORMATION FsSizeInformation; 289 290 /* Create event */ 291 Status = CmpCreateEvent(NotificationEvent, &EventHandle, &Event); 292 if (!NT_SUCCESS(Status)) return Status; 293 294 /* Initialize the full name */ 295 RtlInitEmptyUnicodeString(&FullName, NULL, 0); 296 Length = BaseName->Length; 297 298 /* Check if we have an extension */ 299 if (Extension) 300 { 301 /* Update the name length */ 302 Length += (USHORT)wcslen(Extension) * sizeof(WCHAR) + sizeof(UNICODE_NULL); 303 304 /* Allocate the buffer for the full name */ 305 NameBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); 306 if (!NameBuffer) 307 { 308 /* Fail */ 309 ObDereferenceObject(Event); 310 ZwClose(EventHandle); 311 return STATUS_NO_MEMORY; 312 } 313 314 /* Build the full name */ 315 FullName.Buffer = NameBuffer; 316 FullName.MaximumLength = Length; 317 RtlCopyUnicodeString(&FullName, BaseName); 318 } 319 else 320 { 321 /* The base name is the full name */ 322 FullName = *BaseName; 323 NameBuffer = NULL; 324 } 325 326 /* Initialize the attributes */ 327 InitializeObjectAttributes(&ObjectAttributes, 328 &FullName, 329 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 330 NULL, 331 NULL); 332 333 /* Check if we can create the hive */ 334 if ((CreateAllowed) && !(CmpShareSystemHives)) 335 { 336 /* Open only or create */ 337 CreateDisposition = FILE_OPEN_IF; 338 } 339 else 340 { 341 /* Open only */ 342 CreateDisposition = FILE_OPEN; 343 } 344 345 /* Setup the flags */ 346 // FIXME : FILE_OPEN_FOR_BACKUP_INTENT is unimplemented and breaks 3rd stage boot 347 IoFlags = //FILE_OPEN_FOR_BACKUP_INTENT | 348 FILE_NO_COMPRESSION | 349 FILE_RANDOM_ACCESS | 350 (NoBuffering ? FILE_NO_INTERMEDIATE_BUFFERING : 0); 351 352 /* Set share and access modes */ 353 if ((CmpMiniNTBoot) && (CmpShareSystemHives)) 354 { 355 /* We're on Live CD or otherwise sharing */ 356 DesiredAccess = FILE_READ_DATA; 357 ShareMode = FILE_SHARE_READ; 358 } 359 else 360 { 361 /* We want to write exclusively */ 362 ShareMode = 0; 363 DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA; 364 } 365 366 /* Default attributes */ 367 AttributeFlags = FILE_ATTRIBUTE_NORMAL; 368 369 /* Now create the file. 370 * Note: We use FILE_SYNCHRONOUS_IO_NONALERT here to simplify CmpFileRead/CmpFileWrite. 371 * Windows does async I/O and therefore does not use this flag (or SYNCHRONIZE). 372 */ 373 Status = ZwCreateFile(Primary, 374 DesiredAccess | SYNCHRONIZE, 375 &ObjectAttributes, 376 &IoStatusBlock, 377 NULL, 378 AttributeFlags, 379 ShareMode, 380 CreateDisposition, 381 FILE_SYNCHRONOUS_IO_NONALERT | IoFlags, 382 NULL, 383 0); 384 /* Check if anything failed until now */ 385 if (!NT_SUCCESS(Status)) 386 { 387 DPRINT1("ZwCreateFile(%wZ) failed, Status 0x%08lx.\n", ObjectAttributes.ObjectName, Status); 388 389 /* Close handles and free buffers */ 390 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 391 ObDereferenceObject(Event); 392 ZwClose(EventHandle); 393 *Primary = NULL; 394 return Status; 395 } 396 397 if (MarkAsSystemHive) 398 { 399 /* We opened it, mark it as a system hive */ 400 Status = ZwFsControlFile(*Primary, 401 EventHandle, 402 NULL, 403 NULL, 404 &IoStatusBlock, 405 FSCTL_MARK_AS_SYSTEM_HIVE, 406 NULL, 407 0, 408 NULL, 409 0); 410 if (Status == STATUS_PENDING) 411 { 412 /* Wait for completion */ 413 KeWaitForSingleObject(Event, 414 Executive, 415 KernelMode, 416 FALSE, 417 NULL); 418 Status = IoStatusBlock.Status; 419 } 420 421 /* If we don't support it, ignore the failure */ 422 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS; 423 424 if (!NT_SUCCESS(Status)) 425 { 426 /* Close handles and free buffers */ 427 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 428 ObDereferenceObject(Event); 429 ZwClose(EventHandle); 430 ZwClose(*Primary); 431 *Primary = NULL; 432 return Status; 433 } 434 } 435 436 /* Disable compression */ 437 CompressionState = 0; 438 Status = ZwFsControlFile(*Primary, 439 EventHandle, 440 NULL, 441 NULL, 442 &IoStatusBlock, 443 FSCTL_SET_COMPRESSION, 444 &CompressionState, 445 sizeof(CompressionState), 446 NULL, 447 0); 448 if (Status == STATUS_PENDING) 449 { 450 /* Wait for completion */ 451 KeWaitForSingleObject(Event, 452 Executive, 453 KernelMode, 454 FALSE, 455 NULL); 456 } 457 458 /* Get the disposition */ 459 *PrimaryDisposition = (ULONG)IoStatusBlock.Information; 460 if (IoStatusBlock.Information != FILE_CREATED) 461 { 462 /* Check how large the file is */ 463 Status = ZwQueryInformationFile(*Primary, 464 &IoStatusBlock, 465 &FileInformation, 466 sizeof(FileInformation), 467 FileStandardInformation); 468 if (NT_SUCCESS(Status)) 469 { 470 /* Check if it's 0 bytes */ 471 if (!FileInformation.EndOfFile.QuadPart) 472 { 473 /* Assume it's a new file */ 474 *PrimaryDisposition = FILE_CREATED; 475 } 476 } 477 } 478 479 /* Check if the caller wants cluster size returned */ 480 if (ClusterSize) 481 { 482 /* Query it */ 483 Status = ZwQueryVolumeInformationFile(*Primary, 484 &IoStatusBlock, 485 &FsSizeInformation, 486 sizeof(FsSizeInformation), 487 FileFsSizeInformation); 488 if (!NT_SUCCESS(Status)) 489 { 490 /* Close handles and free buffers */ 491 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 492 ObDereferenceObject(Event); 493 ZwClose(EventHandle); 494 return Status; 495 } 496 497 /* Check if the sector size is invalid */ 498 if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE) 499 { 500 /* Close handles and free buffers */ 501 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 502 ObDereferenceObject(Event); 503 ZwClose(EventHandle); 504 return STATUS_CANNOT_LOAD_REGISTRY_FILE; 505 } 506 507 /* Return cluster size */ 508 *ClusterSize = max(1, FsSizeInformation.BytesPerSector / HSECTOR_SIZE); 509 } 510 511 /* Check if we don't need to create a log file */ 512 if (!Extension) 513 { 514 /* We're done, close handles */ 515 ObDereferenceObject(Event); 516 ZwClose(EventHandle); 517 return STATUS_SUCCESS; 518 } 519 520 /* Check if we can create the hive */ 521 CreateDisposition = CmpShareSystemHives ? FILE_OPEN : FILE_OPEN_IF; 522 if (*PrimaryDisposition == FILE_CREATED) 523 { 524 /* Over-write the existing log file, since this is a new hive */ 525 CreateDisposition = FILE_SUPERSEDE; 526 } 527 528 /* Setup the name */ 529 RtlInitUnicodeString(&ExtensionName, Extension); 530 RtlAppendUnicodeStringToString(&FullName, &ExtensionName); 531 532 /* Initialize the attributes */ 533 InitializeObjectAttributes(&ObjectAttributes, 534 &FullName, 535 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 536 NULL, 537 NULL); 538 539 /* Setup the flags */ 540 IoFlags = FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING; 541 542 /* Check if this is a log file */ 543 if (!_wcsnicmp(Extension, L".log", 4)) 544 { 545 /* Hide log files */ 546 AttributeFlags |= FILE_ATTRIBUTE_HIDDEN; 547 } 548 549 /* Now create the file. 550 * Note: We use FILE_SYNCHRONOUS_IO_NONALERT here to simplify CmpFileRead/CmpFileWrite. 551 * Windows does async I/O and therefore does not use this flag (or SYNCHRONIZE). 552 */ 553 Status = ZwCreateFile(Log, 554 DesiredAccess | SYNCHRONIZE, 555 &ObjectAttributes, 556 &IoStatusBlock, 557 NULL, 558 AttributeFlags, 559 ShareMode, 560 CreateDisposition, 561 FILE_SYNCHRONOUS_IO_NONALERT | IoFlags, 562 NULL, 563 0); 564 if ((NT_SUCCESS(Status)) && (MarkAsSystemHive)) 565 { 566 /* We opened it, mark it as a system hive */ 567 Status = ZwFsControlFile(*Log, 568 EventHandle, 569 NULL, 570 NULL, 571 &IoStatusBlock, 572 FSCTL_MARK_AS_SYSTEM_HIVE, 573 NULL, 574 0, 575 NULL, 576 0); 577 if (Status == STATUS_PENDING) 578 { 579 /* Wait for completion */ 580 KeWaitForSingleObject(Event, 581 Executive, 582 KernelMode, 583 FALSE, 584 NULL); 585 Status = IoStatusBlock.Status; 586 } 587 588 /* If we don't support it, ignore the failure */ 589 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS; 590 591 /* If we failed, close the handle */ 592 if (!NT_SUCCESS(Status)) ZwClose(*Log); 593 } 594 595 /* Check if anything failed until now */ 596 if (!NT_SUCCESS(Status)) 597 { 598 /* Clear the handle */ 599 *Log = NULL; 600 } 601 else 602 { 603 /* Disable compression */ 604 Status = ZwFsControlFile(*Log, 605 EventHandle, 606 NULL, 607 NULL, 608 &IoStatusBlock, 609 FSCTL_SET_COMPRESSION, 610 &CompressionState, 611 sizeof(CompressionState), 612 NULL, 613 0); 614 if (Status == STATUS_PENDING) 615 { 616 /* Wait for completion */ 617 KeWaitForSingleObject(Event, 618 Executive, 619 KernelMode, 620 FALSE, 621 NULL); 622 } 623 624 /* Return the disposition */ 625 *LogDisposition = (ULONG)IoStatusBlock.Information; 626 } 627 628 /* We're done, close handles and free buffers */ 629 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 630 ObDereferenceObject(Event); 631 ZwClose(EventHandle); 632 return STATUS_SUCCESS; 633 } 634 635 VOID 636 NTAPI 637 CmpCloseHiveFiles(IN PCMHIVE Hive) 638 { 639 ULONG i; 640 641 for (i = 0; i < HFILE_TYPE_MAX; i++) 642 { 643 if (Hive->FileHandles[i] != NULL) 644 { 645 ZwClose(Hive->FileHandles[i]); 646 Hive->FileHandles[i] = NULL; 647 } 648 } 649 } 650