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 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 /* Lock the hive list */ 217 ExAcquirePushLockExclusive(&CmpHiveListHeadLock); 218 219 /* Insert this hive */ 220 InsertHeadList(&CmpHiveListHead, &Hive->HiveList); 221 222 /* Release the lock */ 223 ExReleasePushLock(&CmpHiveListHeadLock); 224 225 /* Return the hive and success */ 226 *CmHive = Hive; 227 return STATUS_SUCCESS; 228 } 229 230 NTSTATUS 231 NTAPI 232 CmpDestroyHive(IN PCMHIVE CmHive) 233 { 234 /* Remove the hive from the list */ 235 ExAcquirePushLockExclusive(&CmpHiveListHeadLock); 236 RemoveEntryList(&CmHive->HiveList); 237 ExReleasePushLock(&CmpHiveListHeadLock); 238 239 /* Destroy the security descriptor cache */ 240 CmpDestroySecurityCache(CmHive); 241 242 /* Destroy the view list */ 243 CmpDestroyHiveViewList(CmHive); 244 245 /* Delete the flusher lock */ 246 ExDeleteResourceLite(CmHive->FlusherLock); 247 ExFreePoolWithTag(CmHive->FlusherLock, TAG_CMHIVE); 248 249 /* Delete the view lock */ 250 ExFreePoolWithTag(CmHive->ViewLock, TAG_CMHIVE); 251 252 /* Free the hive storage */ 253 HvFree(&CmHive->Hive); 254 255 /* Free the hive */ 256 CmpFree(CmHive, TAG_CM); 257 258 return STATUS_SUCCESS; 259 } 260 261 NTSTATUS 262 NTAPI 263 CmpOpenHiveFiles(IN PCUNICODE_STRING BaseName, 264 IN PCWSTR Extension OPTIONAL, 265 OUT PHANDLE Primary, 266 OUT PHANDLE Log, 267 OUT PULONG PrimaryDisposition, 268 OUT PULONG LogDisposition, 269 IN BOOLEAN CreateAllowed, 270 IN BOOLEAN MarkAsSystemHive, 271 IN BOOLEAN NoBuffering, 272 OUT PULONG ClusterSize OPTIONAL) 273 { 274 HANDLE EventHandle; 275 PKEVENT Event; 276 NTSTATUS Status; 277 UNICODE_STRING FullName, ExtensionName; 278 PWCHAR NameBuffer; 279 USHORT Length; 280 OBJECT_ATTRIBUTES ObjectAttributes; 281 IO_STATUS_BLOCK IoStatusBlock; 282 ULONG AttributeFlags, ShareMode, DesiredAccess, CreateDisposition, IoFlags; 283 USHORT CompressionState; 284 FILE_STANDARD_INFORMATION FileInformation; 285 FILE_FS_SIZE_INFORMATION FsSizeInformation; 286 287 /* Create event */ 288 Status = CmpCreateEvent(NotificationEvent, &EventHandle, &Event); 289 if (!NT_SUCCESS(Status)) return Status; 290 291 /* Initialize the full name */ 292 RtlInitEmptyUnicodeString(&FullName, NULL, 0); 293 Length = BaseName->Length; 294 295 /* Check if we have an extension */ 296 if (Extension) 297 { 298 /* Update the name length */ 299 Length += (USHORT)wcslen(Extension) * sizeof(WCHAR) + sizeof(UNICODE_NULL); 300 301 /* Allocate the buffer for the full name */ 302 NameBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); 303 if (!NameBuffer) 304 { 305 /* Fail */ 306 ObDereferenceObject(Event); 307 ZwClose(EventHandle); 308 return STATUS_NO_MEMORY; 309 } 310 311 /* Build the full name */ 312 FullName.Buffer = NameBuffer; 313 FullName.MaximumLength = Length; 314 RtlCopyUnicodeString(&FullName, BaseName); 315 } 316 else 317 { 318 /* The base name is the full name */ 319 FullName = *BaseName; 320 NameBuffer = NULL; 321 } 322 323 /* Initialize the attributes */ 324 InitializeObjectAttributes(&ObjectAttributes, 325 &FullName, 326 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 327 NULL, 328 NULL); 329 330 /* Check if we can create the hive */ 331 if ((CreateAllowed) && !(CmpShareSystemHives)) 332 { 333 /* Open only or create */ 334 CreateDisposition = FILE_OPEN_IF; 335 } 336 else 337 { 338 /* Open only */ 339 CreateDisposition = FILE_OPEN; 340 } 341 342 /* Setup the flags */ 343 // FIXME : FILE_OPEN_FOR_BACKUP_INTENT is unimplemented and breaks 3rd stage boot 344 IoFlags = //FILE_OPEN_FOR_BACKUP_INTENT | 345 FILE_NO_COMPRESSION | 346 FILE_RANDOM_ACCESS | 347 (NoBuffering ? FILE_NO_INTERMEDIATE_BUFFERING : 0); 348 349 /* Set share and access modes */ 350 if ((CmpMiniNTBoot) && (CmpShareSystemHives)) 351 { 352 /* We're on Live CD or otherwise sharing */ 353 DesiredAccess = FILE_READ_DATA; 354 ShareMode = FILE_SHARE_READ; 355 } 356 else 357 { 358 /* We want to write exclusively */ 359 ShareMode = 0; 360 DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA; 361 } 362 363 /* Default attributes */ 364 AttributeFlags = FILE_ATTRIBUTE_NORMAL; 365 366 /* Now create the file */ 367 Status = ZwCreateFile(Primary, 368 DesiredAccess | SYNCHRONIZE, 369 &ObjectAttributes, 370 &IoStatusBlock, 371 NULL, 372 AttributeFlags, 373 ShareMode, 374 CreateDisposition, 375 FILE_SYNCHRONOUS_IO_NONALERT | IoFlags, 376 NULL, 377 0); 378 /* Check if anything failed until now */ 379 if (!NT_SUCCESS(Status)) 380 { 381 DPRINT1("ZwCreateFile(%wZ) failed, Status 0x%08lx.\n", ObjectAttributes.ObjectName, Status); 382 383 /* Close handles and free buffers */ 384 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 385 ObDereferenceObject(Event); 386 ZwClose(EventHandle); 387 *Primary = NULL; 388 return Status; 389 } 390 391 if (MarkAsSystemHive) 392 { 393 /* We opened it, mark it as a system hive */ 394 Status = ZwFsControlFile(*Primary, 395 EventHandle, 396 NULL, 397 NULL, 398 &IoStatusBlock, 399 FSCTL_MARK_AS_SYSTEM_HIVE, 400 NULL, 401 0, 402 NULL, 403 0); 404 if (Status == STATUS_PENDING) 405 { 406 /* Wait for completion */ 407 KeWaitForSingleObject(Event, 408 Executive, 409 KernelMode, 410 FALSE, 411 NULL); 412 Status = IoStatusBlock.Status; 413 } 414 415 /* If we don't support it, ignore the failure */ 416 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS; 417 418 if (!NT_SUCCESS(Status)) 419 { 420 /* Close handles and free buffers */ 421 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 422 ObDereferenceObject(Event); 423 ZwClose(EventHandle); 424 ZwClose(*Primary); 425 *Primary = NULL; 426 return Status; 427 } 428 } 429 430 /* Disable compression */ 431 CompressionState = 0; 432 Status = ZwFsControlFile(*Primary, 433 EventHandle, 434 NULL, 435 NULL, 436 &IoStatusBlock, 437 FSCTL_SET_COMPRESSION, 438 &CompressionState, 439 sizeof(CompressionState), 440 NULL, 441 0); 442 if (Status == STATUS_PENDING) 443 { 444 /* Wait for completion */ 445 KeWaitForSingleObject(Event, 446 Executive, 447 KernelMode, 448 FALSE, 449 NULL); 450 } 451 452 /* Get the disposition */ 453 *PrimaryDisposition = (ULONG)IoStatusBlock.Information; 454 if (IoStatusBlock.Information != FILE_CREATED) 455 { 456 /* Check how large the file is */ 457 Status = ZwQueryInformationFile(*Primary, 458 &IoStatusBlock, 459 &FileInformation, 460 sizeof(FileInformation), 461 FileStandardInformation); 462 if (NT_SUCCESS(Status)) 463 { 464 /* Check if it's 0 bytes */ 465 if (!FileInformation.EndOfFile.QuadPart) 466 { 467 /* Assume it's a new file */ 468 *PrimaryDisposition = FILE_CREATED; 469 } 470 } 471 } 472 473 /* Check if the caller wants cluster size returned */ 474 if (ClusterSize) 475 { 476 /* Query it */ 477 Status = ZwQueryVolumeInformationFile(*Primary, 478 &IoStatusBlock, 479 &FsSizeInformation, 480 sizeof(FsSizeInformation), 481 FileFsSizeInformation); 482 if (!NT_SUCCESS(Status)) 483 { 484 /* Close handles and free buffers */ 485 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 486 ObDereferenceObject(Event); 487 ZwClose(EventHandle); 488 return Status; 489 } 490 491 /* Check if the sector size is invalid */ 492 if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE) 493 { 494 /* Close handles and free buffers */ 495 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 496 ObDereferenceObject(Event); 497 ZwClose(EventHandle); 498 return STATUS_CANNOT_LOAD_REGISTRY_FILE; 499 } 500 501 /* Return cluster size */ 502 *ClusterSize = max(1, FsSizeInformation.BytesPerSector / HSECTOR_SIZE); 503 } 504 505 /* Check if we don't need to create a log file */ 506 if (!Extension) 507 { 508 /* We're done, close handles */ 509 ObDereferenceObject(Event); 510 ZwClose(EventHandle); 511 return STATUS_SUCCESS; 512 } 513 514 /* Check if we can create the hive */ 515 CreateDisposition = CmpShareSystemHives ? FILE_OPEN : FILE_OPEN_IF; 516 if (*PrimaryDisposition == FILE_CREATED) 517 { 518 /* Over-write the existing log file, since this is a new hive */ 519 CreateDisposition = FILE_SUPERSEDE; 520 } 521 522 /* Setup the name */ 523 RtlInitUnicodeString(&ExtensionName, Extension); 524 RtlAppendUnicodeStringToString(&FullName, &ExtensionName); 525 526 /* Initialize the attributes */ 527 InitializeObjectAttributes(&ObjectAttributes, 528 &FullName, 529 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 530 NULL, 531 NULL); 532 533 /* Setup the flags */ 534 IoFlags = FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING; 535 536 /* Check if this is a log file */ 537 if (!_wcsnicmp(Extension, L".log", 4)) 538 { 539 /* Hide log files */ 540 AttributeFlags |= FILE_ATTRIBUTE_HIDDEN; 541 } 542 543 /* Now create the file */ 544 Status = ZwCreateFile(Log, 545 DesiredAccess, 546 &ObjectAttributes, 547 &IoStatusBlock, 548 NULL, 549 AttributeFlags, 550 ShareMode, 551 CreateDisposition, 552 IoFlags, 553 NULL, 554 0); 555 if ((NT_SUCCESS(Status)) && (MarkAsSystemHive)) 556 { 557 /* We opened it, mark it as a system hive */ 558 Status = ZwFsControlFile(*Log, 559 EventHandle, 560 NULL, 561 NULL, 562 &IoStatusBlock, 563 FSCTL_MARK_AS_SYSTEM_HIVE, 564 NULL, 565 0, 566 NULL, 567 0); 568 if (Status == STATUS_PENDING) 569 { 570 /* Wait for completion */ 571 KeWaitForSingleObject(Event, 572 Executive, 573 KernelMode, 574 FALSE, 575 NULL); 576 Status = IoStatusBlock.Status; 577 } 578 579 /* If we don't support it, ignore the failure */ 580 if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS; 581 582 /* If we failed, close the handle */ 583 if (!NT_SUCCESS(Status)) ZwClose(*Log); 584 } 585 586 /* Check if anything failed until now */ 587 if (!NT_SUCCESS(Status)) 588 { 589 /* Clear the handle */ 590 *Log = NULL; 591 } 592 else 593 { 594 /* Disable compression */ 595 Status = ZwFsControlFile(*Log, 596 EventHandle, 597 NULL, 598 NULL, 599 &IoStatusBlock, 600 FSCTL_SET_COMPRESSION, 601 &CompressionState, 602 sizeof(CompressionState), 603 NULL, 604 0); 605 if (Status == STATUS_PENDING) 606 { 607 /* Wait for completion */ 608 KeWaitForSingleObject(Event, 609 Executive, 610 KernelMode, 611 FALSE, 612 NULL); 613 } 614 615 /* Return the disposition */ 616 *LogDisposition = (ULONG)IoStatusBlock.Information; 617 } 618 619 /* We're done, close handles and free buffers */ 620 if (NameBuffer) ExFreePoolWithTag(NameBuffer, TAG_CM); 621 ObDereferenceObject(Event); 622 ZwClose(EventHandle); 623 return STATUS_SUCCESS; 624 } 625 626 VOID 627 NTAPI 628 CmpCloseHiveFiles(IN PCMHIVE Hive) 629 { 630 ULONG i; 631 632 for (i = 0; i < HFILE_TYPE_MAX; i++) 633 { 634 if (Hive->FileHandles[i] != NULL) 635 { 636 ZwClose(Hive->FileHandles[i]); 637 Hive->FileHandles[i] = NULL; 638 } 639 } 640 } 641