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