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 Status = ZwCreateFile(Primary, 371 DesiredAccess | SYNCHRONIZE, 372 &ObjectAttributes, 373 &IoStatusBlock, 374 NULL, 375 AttributeFlags, 376 ShareMode, 377 CreateDisposition, 378 FILE_SYNCHRONOUS_IO_NONALERT | IoFlags, 379 NULL, 380 0); 381 /* Check if anything failed until now */ 382 if (!NT_SUCCESS(Status)) 383 { 384 DPRINT1("ZwCreateFile(%wZ) failed, Status 0x%08lx.\n", ObjectAttributes.ObjectName, Status); 385 386 /* Close handles and free buffers */ 387 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 388 ObDereferenceObject(Event); 389 ZwClose(EventHandle); 390 *Primary = NULL; 391 return Status; 392 } 393 394 if (MarkAsSystemHive) 395 { 396 /* We opened it, mark it as a system hive */ 397 Status = ZwFsControlFile(*Primary, 398 EventHandle, 399 NULL, 400 NULL, 401 &IoStatusBlock, 402 FSCTL_MARK_AS_SYSTEM_HIVE, 403 NULL, 404 0, 405 NULL, 406 0); 407 if (Status == STATUS_PENDING) 408 { 409 /* Wait for completion */ 410 KeWaitForSingleObject(Event, 411 Executive, 412 KernelMode, 413 FALSE, 414 NULL); 415 Status = IoStatusBlock.Status; 416 } 417 418 /* If we don't support it, ignore the failure */ 419 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS; 420 421 if (!NT_SUCCESS(Status)) 422 { 423 /* Close handles and free buffers */ 424 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 425 ObDereferenceObject(Event); 426 ZwClose(EventHandle); 427 ZwClose(*Primary); 428 *Primary = NULL; 429 return Status; 430 } 431 } 432 433 /* Disable compression */ 434 CompressionState = 0; 435 Status = ZwFsControlFile(*Primary, 436 EventHandle, 437 NULL, 438 NULL, 439 &IoStatusBlock, 440 FSCTL_SET_COMPRESSION, 441 &CompressionState, 442 sizeof(CompressionState), 443 NULL, 444 0); 445 if (Status == STATUS_PENDING) 446 { 447 /* Wait for completion */ 448 KeWaitForSingleObject(Event, 449 Executive, 450 KernelMode, 451 FALSE, 452 NULL); 453 } 454 455 /* Get the disposition */ 456 *PrimaryDisposition = (ULONG)IoStatusBlock.Information; 457 if (IoStatusBlock.Information != FILE_CREATED) 458 { 459 /* Check how large the file is */ 460 Status = ZwQueryInformationFile(*Primary, 461 &IoStatusBlock, 462 &FileInformation, 463 sizeof(FileInformation), 464 FileStandardInformation); 465 if (NT_SUCCESS(Status)) 466 { 467 /* Check if it's 0 bytes */ 468 if (!FileInformation.EndOfFile.QuadPart) 469 { 470 /* Assume it's a new file */ 471 *PrimaryDisposition = FILE_CREATED; 472 } 473 } 474 } 475 476 /* Check if the caller wants cluster size returned */ 477 if (ClusterSize) 478 { 479 /* Query it */ 480 Status = ZwQueryVolumeInformationFile(*Primary, 481 &IoStatusBlock, 482 &FsSizeInformation, 483 sizeof(FsSizeInformation), 484 FileFsSizeInformation); 485 if (!NT_SUCCESS(Status)) 486 { 487 /* Close handles and free buffers */ 488 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 489 ObDereferenceObject(Event); 490 ZwClose(EventHandle); 491 return Status; 492 } 493 494 /* Check if the sector size is invalid */ 495 if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE) 496 { 497 /* Close handles and free buffers */ 498 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 499 ObDereferenceObject(Event); 500 ZwClose(EventHandle); 501 return STATUS_CANNOT_LOAD_REGISTRY_FILE; 502 } 503 504 /* Return cluster size */ 505 *ClusterSize = max(1, FsSizeInformation.BytesPerSector / HSECTOR_SIZE); 506 } 507 508 /* Check if we don't need to create a log file */ 509 if (!Extension) 510 { 511 /* We're done, close handles */ 512 ObDereferenceObject(Event); 513 ZwClose(EventHandle); 514 return STATUS_SUCCESS; 515 } 516 517 /* Check if we can create the hive */ 518 CreateDisposition = CmpShareSystemHives ? FILE_OPEN : FILE_OPEN_IF; 519 if (*PrimaryDisposition == FILE_CREATED) 520 { 521 /* Over-write the existing log file, since this is a new hive */ 522 CreateDisposition = FILE_SUPERSEDE; 523 } 524 525 /* Setup the name */ 526 RtlInitUnicodeString(&ExtensionName, Extension); 527 RtlAppendUnicodeStringToString(&FullName, &ExtensionName); 528 529 /* Initialize the attributes */ 530 InitializeObjectAttributes(&ObjectAttributes, 531 &FullName, 532 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 533 NULL, 534 NULL); 535 536 /* Setup the flags */ 537 IoFlags = FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING; 538 539 /* Check if this is a log file */ 540 if (!_wcsnicmp(Extension, L".log", 4)) 541 { 542 /* Hide log files */ 543 AttributeFlags |= FILE_ATTRIBUTE_HIDDEN; 544 } 545 546 /* Now create the file */ 547 Status = ZwCreateFile(Log, 548 DesiredAccess, 549 &ObjectAttributes, 550 &IoStatusBlock, 551 NULL, 552 AttributeFlags, 553 ShareMode, 554 CreateDisposition, 555 IoFlags, 556 NULL, 557 0); 558 if ((NT_SUCCESS(Status)) && (MarkAsSystemHive)) 559 { 560 /* We opened it, mark it as a system hive */ 561 Status = ZwFsControlFile(*Log, 562 EventHandle, 563 NULL, 564 NULL, 565 &IoStatusBlock, 566 FSCTL_MARK_AS_SYSTEM_HIVE, 567 NULL, 568 0, 569 NULL, 570 0); 571 if (Status == STATUS_PENDING) 572 { 573 /* Wait for completion */ 574 KeWaitForSingleObject(Event, 575 Executive, 576 KernelMode, 577 FALSE, 578 NULL); 579 Status = IoStatusBlock.Status; 580 } 581 582 /* If we don't support it, ignore the failure */ 583 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS; 584 585 /* If we failed, close the handle */ 586 if (!NT_SUCCESS(Status)) ZwClose(*Log); 587 } 588 589 /* Check if anything failed until now */ 590 if (!NT_SUCCESS(Status)) 591 { 592 /* Clear the handle */ 593 *Log = NULL; 594 } 595 else 596 { 597 /* Disable compression */ 598 Status = ZwFsControlFile(*Log, 599 EventHandle, 600 NULL, 601 NULL, 602 &IoStatusBlock, 603 FSCTL_SET_COMPRESSION, 604 &CompressionState, 605 sizeof(CompressionState), 606 NULL, 607 0); 608 if (Status == STATUS_PENDING) 609 { 610 /* Wait for completion */ 611 KeWaitForSingleObject(Event, 612 Executive, 613 KernelMode, 614 FALSE, 615 NULL); 616 } 617 618 /* Return the disposition */ 619 *LogDisposition = (ULONG)IoStatusBlock.Information; 620 } 621 622 /* We're done, close handles and free buffers */ 623 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 624 ObDereferenceObject(Event); 625 ZwClose(EventHandle); 626 return STATUS_SUCCESS; 627 } 628 629 VOID 630 NTAPI 631 CmpCloseHiveFiles(IN PCMHIVE Hive) 632 { 633 ULONG i; 634 635 for (i = 0; i < HFILE_TYPE_MAX; i++) 636 { 637 if (Hive->FileHandles[i] != NULL) 638 { 639 ZwClose(Hive->FileHandles[i]); 640 Hive->FileHandles[i] = NULL; 641 } 642 } 643 } 644