[NTOS] Addendum to da81345: Fix checks when a hive is opened in shared mode.
[reactos.git] / ntoskrnl / config / cminit.c
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 }