[NTOS:IO] Finally remove the dreadful IopParseDevice() hack! \o/
[reactos.git] / ntoskrnl / io / iomgr / file.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/file.c
5 * PURPOSE: Functions that deal with managing the FILE_OBJECT itself.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Gunnar Dalsnes
8 * Eric Kohl
9 * Filip Navara (navaraf@reactos.org)
10 * Pierre Schweitzer
11 */
12
13 /* INCLUDES *****************************************************************/
14
15 #include <ntoskrnl.h>
16 #define NDEBUG
17 #include <debug.h>
18
19 extern ERESOURCE IopSecurityResource;
20
21 /* PRIVATE FUNCTIONS *********************************************************/
22
23 VOID
24 NTAPI
25 IopCheckBackupRestorePrivilege(IN PACCESS_STATE AccessState,
26 IN OUT PULONG CreateOptions,
27 IN KPROCESSOR_MODE PreviousMode,
28 IN ULONG Disposition)
29 {
30 ACCESS_MASK DesiredAccess, ReadAccess, WriteAccess;
31 PRIVILEGE_SET Privileges;
32 BOOLEAN AccessGranted, HaveBackupPriv = FALSE, CheckRestore = FALSE;
33 PAGED_CODE();
34
35 /* Don't do anything if privileges were checked already */
36 if (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED) return;
37
38 /* Check if the file was actually opened for backup purposes */
39 if (*CreateOptions & FILE_OPEN_FOR_BACKUP_INTENT)
40 {
41 /* Set the check flag since were doing it now */
42 AccessState->Flags |= SE_BACKUP_PRIVILEGES_CHECKED;
43
44 /* Set the access masks required */
45 ReadAccess = READ_CONTROL |
46 ACCESS_SYSTEM_SECURITY |
47 FILE_GENERIC_READ |
48 FILE_TRAVERSE;
49 WriteAccess = WRITE_DAC |
50 WRITE_OWNER |
51 ACCESS_SYSTEM_SECURITY |
52 FILE_GENERIC_WRITE |
53 FILE_ADD_FILE |
54 FILE_ADD_SUBDIRECTORY |
55 DELETE;
56 DesiredAccess = AccessState->RemainingDesiredAccess;
57
58 /* Check if desired access was the maximum */
59 if (DesiredAccess & MAXIMUM_ALLOWED)
60 {
61 /* Then add all the access masks required */
62 DesiredAccess |= (ReadAccess | WriteAccess);
63 }
64
65 /* Check if the file already exists */
66 if (Disposition & FILE_OPEN)
67 {
68 /* Check if desired access has the read mask */
69 if (ReadAccess & DesiredAccess)
70 {
71 /* Setup the privilege check lookup */
72 Privileges.PrivilegeCount = 1;
73 Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
74 Privileges.Privilege[0].Luid = SeBackupPrivilege;
75 Privileges.Privilege[0].Attributes = 0;
76 AccessGranted = SePrivilegeCheck(&Privileges,
77 &AccessState->
78 SubjectSecurityContext,
79 PreviousMode);
80 if (AccessGranted)
81 {
82 /* Remember that backup was allowed */
83 HaveBackupPriv = TRUE;
84
85 /* Append the privileges and update the access state */
86 SeAppendPrivileges(AccessState, &Privileges);
87 AccessState->PreviouslyGrantedAccess |= (DesiredAccess & ReadAccess);
88 AccessState->RemainingDesiredAccess &= ~ReadAccess;
89 DesiredAccess &= ~ReadAccess;
90
91 /* Set backup privilege for the token */
92 AccessState->Flags |= TOKEN_HAS_BACKUP_PRIVILEGE;
93 }
94 }
95 }
96 else
97 {
98 /* Caller is creating the file, check restore privileges later */
99 CheckRestore = TRUE;
100 }
101
102 /* Check if caller wants write access or if it's creating a file */
103 if ((WriteAccess & DesiredAccess) || (CheckRestore))
104 {
105 /* Setup the privilege lookup and do it */
106 Privileges.PrivilegeCount = 1;
107 Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
108 Privileges.Privilege[0].Luid = SeRestorePrivilege;
109 Privileges.Privilege[0].Attributes = 0;
110 AccessGranted = SePrivilegeCheck(&Privileges,
111 &AccessState->SubjectSecurityContext,
112 PreviousMode);
113 if (AccessGranted)
114 {
115 /* Remember that privilege was given */
116 HaveBackupPriv = TRUE;
117
118 /* Append the privileges and update the access state */
119 SeAppendPrivileges(AccessState, &Privileges);
120 AccessState->PreviouslyGrantedAccess |= (DesiredAccess & WriteAccess);
121 AccessState->RemainingDesiredAccess &= ~WriteAccess;
122
123 /* Set restore privilege for the token */
124 AccessState->Flags |= TOKEN_HAS_RESTORE_PRIVILEGE;
125 }
126 }
127
128 /* If we don't have the privilege, remove the option */
129 if (!HaveBackupPriv) *CreateOptions &= ~FILE_OPEN_FOR_BACKUP_INTENT;
130 }
131 }
132
133 NTSTATUS
134 NTAPI
135 IopCheckDeviceAndDriver(IN POPEN_PACKET OpenPacket,
136 IN PDEVICE_OBJECT DeviceObject)
137 {
138 /* Make sure the object is valid */
139 if ((IoGetDevObjExtension(DeviceObject)->ExtensionFlags &
140 (DOE_UNLOAD_PENDING |
141 DOE_DELETE_PENDING |
142 DOE_REMOVE_PENDING |
143 DOE_REMOVE_PROCESSED)) ||
144 (DeviceObject->Flags & DO_DEVICE_INITIALIZING))
145 {
146 /* It's unloading or initializing, so fail */
147 DPRINT1("You are seeing this because the following ROS driver: %wZ\n"
148 " sucks. Please fix it's AddDevice Routine\n",
149 &DeviceObject->DriverObject->DriverName);
150 return STATUS_NO_SUCH_DEVICE;
151 }
152 else if ((DeviceObject->Flags & DO_EXCLUSIVE) &&
153 (DeviceObject->ReferenceCount) &&
154 !(OpenPacket->RelatedFileObject) &&
155 !(OpenPacket->Options & IO_ATTACH_DEVICE))
156 {
157 return STATUS_ACCESS_DENIED;
158 }
159
160 else
161 {
162 /* Increase reference count */
163 InterlockedIncrement(&DeviceObject->ReferenceCount);
164 return STATUS_SUCCESS;
165 }
166 }
167
168 VOID
169 NTAPI
170 IopDoNameTransmogrify(IN PIRP Irp,
171 IN PFILE_OBJECT FileObject,
172 IN PREPARSE_DATA_BUFFER DataBuffer)
173 {
174 PWSTR Buffer;
175 USHORT Length;
176 USHORT RequiredLength;
177 PWSTR NewBuffer;
178
179 PAGED_CODE();
180
181 ASSERT(Irp->IoStatus.Status == STATUS_REPARSE);
182 ASSERT(Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT);
183 ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
184 ASSERT(DataBuffer != NULL);
185 ASSERT(DataBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
186 ASSERT(DataBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
187 ASSERT(DataBuffer->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
188
189 /* First of all, validate data */
190 if (DataBuffer->ReparseDataLength < REPARSE_DATA_BUFFER_HEADER_SIZE ||
191 (DataBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
192 DataBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength +
193 FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0])) > MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
194 {
195 Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
196 }
197
198 /* Everything went right */
199 if (NT_SUCCESS(Irp->IoStatus.Status))
200 {
201 /* Compute buffer & length */
202 Buffer = (PWSTR)((ULONG_PTR)DataBuffer->MountPointReparseBuffer.PathBuffer +
203 DataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
204 Length = DataBuffer->MountPointReparseBuffer.SubstituteNameLength;
205
206 /* Check we don't overflow */
207 if (((ULONG)MAXUSHORT - DataBuffer->Reserved) <= (Length + sizeof(UNICODE_NULL)))
208 {
209 Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
210 }
211 else
212 {
213 /* Compute how much mem we'll need */
214 RequiredLength = DataBuffer->Reserved + Length + sizeof(UNICODE_NULL);
215
216 /* Check if FileObject can already hold what we need */
217 if (FileObject->FileName.MaximumLength >= RequiredLength)
218 {
219 NewBuffer = FileObject->FileName.Buffer;
220 }
221 else
222 {
223 /* Allocate otherwise */
224 NewBuffer = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_IO_NAME);
225 if (NewBuffer == NULL)
226 {
227 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
228 }
229 }
230 }
231 }
232
233 /* Everything went right */
234 if (NT_SUCCESS(Irp->IoStatus.Status))
235 {
236 /* Copy reserved */
237 if (DataBuffer->Reserved)
238 {
239 RtlMoveMemory((PWSTR)((ULONG_PTR)NewBuffer + Length),
240 (PWSTR)((ULONG_PTR)FileObject->FileName.Buffer + FileObject->FileName.Length - DataBuffer->Reserved),
241 DataBuffer->Reserved);
242 }
243
244 /* Then, buffer */
245 if (Length)
246 {
247 RtlCopyMemory(NewBuffer, Buffer, Length);
248 }
249
250 /* And finally replace buffer if new one was allocated */
251 FileObject->FileName.Length = RequiredLength - sizeof(UNICODE_NULL);
252 if (NewBuffer != FileObject->FileName.Buffer)
253 {
254 if (FileObject->FileName.Buffer)
255 {
256 ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
257 }
258
259 FileObject->FileName.Buffer = NewBuffer;
260 FileObject->FileName.MaximumLength = RequiredLength;
261 FileObject->FileName.Buffer[RequiredLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
262 }
263 }
264
265 /* We don't need them anymore - it was allocated by the driver */
266 ExFreePool(DataBuffer);
267 }
268
269 NTSTATUS
270 IopCheckTopDeviceHint(IN OUT PDEVICE_OBJECT * DeviceObject,
271 IN POPEN_PACKET OpenPacket,
272 BOOLEAN DirectOpen)
273 {
274 PDEVICE_OBJECT LocalDevice;
275 DEVICE_TYPE DeviceType;
276
277 LocalDevice = *DeviceObject;
278
279 /* Direct open is not allowed */
280 if (DirectOpen)
281 {
282 return STATUS_INVALID_PARAMETER;
283 }
284
285 /* Validate we have a file system device */
286 DeviceType = LocalDevice->DeviceType;
287 if (DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM &&
288 DeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM &&
289 DeviceType != FILE_DEVICE_TAPE_FILE_SYSTEM &&
290 DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM &&
291 DeviceType != FILE_DEVICE_DFS_FILE_SYSTEM)
292 {
293 return STATUS_INVALID_PARAMETER;
294 }
295
296 /* Verify the hint and if it's OK, return it */
297 if (IopVerifyDeviceObjectOnStack(LocalDevice, OpenPacket->TopDeviceObjectHint))
298 {
299 *DeviceObject = OpenPacket->TopDeviceObjectHint;
300 return STATUS_SUCCESS;
301 }
302
303 /* Failure case here */
304 /* If we thought was had come through a mount point,
305 * actually update we didn't and return the error
306 */
307 if (OpenPacket->TraversedMountPoint)
308 {
309 OpenPacket->TraversedMountPoint = FALSE;
310 return STATUS_MOUNT_POINT_NOT_RESOLVED;
311 }
312
313 /* Otherwise, just return the fact the hint is invalid */
314 return STATUS_INVALID_DEVICE_OBJECT_PARAMETER;
315 }
316
317 NTSTATUS
318 NTAPI
319 IopParseDevice(IN PVOID ParseObject,
320 IN PVOID ObjectType,
321 IN OUT PACCESS_STATE AccessState,
322 IN KPROCESSOR_MODE AccessMode,
323 IN ULONG Attributes,
324 IN OUT PUNICODE_STRING CompleteName,
325 IN OUT PUNICODE_STRING RemainingName,
326 IN OUT PVOID Context,
327 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
328 OUT PVOID *Object)
329 {
330 POPEN_PACKET OpenPacket = (POPEN_PACKET)Context;
331 PDEVICE_OBJECT OriginalDeviceObject = (PDEVICE_OBJECT)ParseObject;
332 PDEVICE_OBJECT DeviceObject, OwnerDevice;
333 NTSTATUS Status;
334 PFILE_OBJECT FileObject;
335 PVPB Vpb = NULL;
336 PIRP Irp;
337 PIO_STACK_LOCATION StackLoc;
338 IO_SECURITY_CONTEXT SecurityContext;
339 IO_STATUS_BLOCK IoStatusBlock;
340 BOOLEAN DirectOpen = FALSE, OpenCancelled, UseDummyFile;
341 OBJECT_ATTRIBUTES ObjectAttributes;
342 KIRQL OldIrql;
343 PDUMMY_FILE_OBJECT LocalFileObject;
344 PFILE_BASIC_INFORMATION FileBasicInfo;
345 ULONG ReturnLength;
346 KPROCESSOR_MODE CheckMode;
347 BOOLEAN VolumeOpen = FALSE;
348 ACCESS_MASK DesiredAccess, GrantedAccess;
349 BOOLEAN AccessGranted, LockHeld = FALSE;
350 PPRIVILEGE_SET Privileges = NULL;
351 UNICODE_STRING FileString;
352 USHORT Attempt;
353 IOTRACE(IO_FILE_DEBUG, "ParseObject: %p. RemainingName: %wZ\n",
354 ParseObject, RemainingName);
355
356 for (Attempt = 0; Attempt < IOP_MAX_REPARSE_TRAVERSAL; ++Attempt)
357 {
358 /* Assume failure */
359 *Object = NULL;
360
361 /* Validate the open packet */
362 if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
363
364 /* Valide reparse point in case we traversed a mountpoint */
365 if (OpenPacket->TraversedMountPoint)
366 {
367 /* This is a reparse point we understand */
368 ASSERT(OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT);
369
370 /* Make sure we're dealing with correct DO */
371 if (OriginalDeviceObject->DeviceType != FILE_DEVICE_DISK &&
372 OriginalDeviceObject->DeviceType != FILE_DEVICE_CD_ROM &&
373 OriginalDeviceObject->DeviceType != FILE_DEVICE_VIRTUAL_DISK &&
374 OriginalDeviceObject->DeviceType != FILE_DEVICE_TAPE)
375 {
376 OpenPacket->FinalStatus = STATUS_IO_REPARSE_DATA_INVALID;
377 return STATUS_IO_REPARSE_DATA_INVALID;
378 }
379 }
380
381 /* Check if we have a related file object */
382 if (OpenPacket->RelatedFileObject)
383 {
384 /* Use the related file object's device object */
385 OriginalDeviceObject = OpenPacket->RelatedFileObject->DeviceObject;
386 }
387
388 /* Validate device status */
389 Status = IopCheckDeviceAndDriver(OpenPacket, OriginalDeviceObject);
390 if (!NT_SUCCESS(Status))
391 {
392 /* We failed, return status */
393 OpenPacket->FinalStatus = Status;
394 return Status;
395 }
396
397 /* Map the generic mask and set the new mapping in the access state */
398 RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
399 &IoFileObjectType->TypeInfo.GenericMapping);
400 RtlMapGenericMask(&AccessState->OriginalDesiredAccess,
401 &IoFileObjectType->TypeInfo.GenericMapping);
402 SeSetAccessStateGenericMapping(AccessState,
403 &IoFileObjectType->TypeInfo.GenericMapping);
404 DesiredAccess = AccessState->RemainingDesiredAccess;
405
406 /* Check what kind of access checks to do */
407 if ((AccessMode != KernelMode) ||
408 (OpenPacket->Options & IO_FORCE_ACCESS_CHECK))
409 {
410 /* Call is from user-mode or kernel is forcing checks */
411 CheckMode = UserMode;
412 }
413 else
414 {
415 /* Call is from the kernel */
416 CheckMode = KernelMode;
417 }
418
419 /* Check privilege for backup or restore operation */
420 IopCheckBackupRestorePrivilege(AccessState,
421 &OpenPacket->CreateOptions,
422 CheckMode,
423 OpenPacket->Disposition);
424
425 /* Check if we are re-parsing */
426 if (((OpenPacket->Override) && !(RemainingName->Length)) ||
427 (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED))
428 {
429 /* Get granted access from the last call */
430 DesiredAccess |= AccessState->PreviouslyGrantedAccess;
431 }
432
433 /* Check if this is a volume open */
434 if ((OpenPacket->RelatedFileObject) &&
435 (OpenPacket->RelatedFileObject->Flags & FO_VOLUME_OPEN) &&
436 !(RemainingName->Length))
437 {
438 /* It is */
439 VolumeOpen = TRUE;
440 }
441
442 /* Now check if we need access checks */
443 if (((AccessMode != KernelMode) ||
444 (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) &&
445 (!(OpenPacket->RelatedFileObject) || (VolumeOpen)) &&
446 !(OpenPacket->Override))
447 {
448 KeEnterCriticalRegion();
449 ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
450
451 /* Check if a device object is being parsed */
452 if (!RemainingName->Length)
453 {
454 /* Lock the subject context */
455 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
456 LockHeld = TRUE;
457
458 /* Do access check */
459 AccessGranted = SeAccessCheck(OriginalDeviceObject->
460 SecurityDescriptor,
461 &AccessState->SubjectSecurityContext,
462 LockHeld,
463 DesiredAccess,
464 0,
465 &Privileges,
466 &IoFileObjectType->
467 TypeInfo.GenericMapping,
468 UserMode,
469 &GrantedAccess,
470 &Status);
471 if (Privileges)
472 {
473 /* Append and free the privileges */
474 SeAppendPrivileges(AccessState, Privileges);
475 SeFreePrivileges(Privileges);
476 }
477
478 /* Check if we got access */
479 if (AccessGranted)
480 {
481 /* Update access state */
482 AccessState->PreviouslyGrantedAccess |= GrantedAccess;
483 AccessState->RemainingDesiredAccess &= ~(GrantedAccess |
484 MAXIMUM_ALLOWED);
485 OpenPacket->Override= TRUE;
486 }
487
488 FileString.Length = 8;
489 FileString.MaximumLength = 8;
490 FileString.Buffer = L"File";
491
492 /* Do Audit/Alarm for open operation */
493 SeOpenObjectAuditAlarm(&FileString,
494 OriginalDeviceObject,
495 CompleteName,
496 OriginalDeviceObject->SecurityDescriptor,
497 AccessState,
498 FALSE,
499 AccessGranted,
500 UserMode,
501 &AccessState->GenerateOnClose);
502 }
503 else
504 {
505 /* Check if we need to do traverse validation */
506 if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ||
507 ((OriginalDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
508 (OriginalDeviceObject->DeviceType == FILE_DEVICE_CD_ROM)))
509 {
510 /* Check if this is a restricted token */
511 if (!(AccessState->Flags & TOKEN_IS_RESTRICTED))
512 {
513 /* Do the FAST traverse check */
514 AccessGranted = SeFastTraverseCheck(OriginalDeviceObject->SecurityDescriptor,
515 AccessState,
516 FILE_TRAVERSE,
517 UserMode);
518 }
519 else
520 {
521 /* Fail */
522 AccessGranted = FALSE;
523 }
524
525 /* Check if we failed to get access */
526 if (!AccessGranted)
527 {
528 /* Lock the subject context */
529 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
530 LockHeld = TRUE;
531
532 /* Do access check */
533 AccessGranted = SeAccessCheck(OriginalDeviceObject->
534 SecurityDescriptor,
535 &AccessState->SubjectSecurityContext,
536 LockHeld,
537 FILE_TRAVERSE,
538 0,
539 &Privileges,
540 &IoFileObjectType->
541 TypeInfo.GenericMapping,
542 UserMode,
543 &GrantedAccess,
544 &Status);
545 if (Privileges)
546 {
547 /* Append and free the privileges */
548 SeAppendPrivileges(AccessState, Privileges);
549 SeFreePrivileges(Privileges);
550 }
551 }
552
553 /* FIXME: Do Audit/Alarm for traverse check */
554 }
555 else
556 {
557 /* Access automatically granted */
558 AccessGranted = TRUE;
559 }
560 }
561
562 ExReleaseResourceLite(&IopSecurityResource);
563 KeLeaveCriticalRegion();
564
565 /* Check if we hold the lock */
566 if (LockHeld)
567 {
568 /* Release it */
569 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
570 }
571
572 /* Check if access failed */
573 if (!AccessGranted)
574 {
575 /* Dereference the device and fail */
576 DPRINT1("Traverse access failed!\n");
577 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
578 return STATUS_ACCESS_DENIED;
579 }
580 }
581
582 /* Check if we can simply use a dummy file */
583 UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
584
585 /* Check if this is a direct open */
586 if (!(RemainingName->Length) &&
587 !(OpenPacket->RelatedFileObject) &&
588 ((DesiredAccess & ~(SYNCHRONIZE |
589 FILE_READ_ATTRIBUTES |
590 READ_CONTROL |
591 ACCESS_SYSTEM_SECURITY |
592 WRITE_OWNER |
593 WRITE_DAC)) == 0) &&
594 !(UseDummyFile))
595 {
596 /* Remember this for later */
597 DirectOpen = TRUE;
598 }
599
600 /* Check if we have a related FO that wasn't a direct open */
601 if ((OpenPacket->RelatedFileObject) &&
602 !(OpenPacket->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN))
603 {
604 /* The device object is the one we were given */
605 DeviceObject = ParseObject;
606
607 /* Check if the related FO had a VPB */
608 if (OpenPacket->RelatedFileObject->Vpb)
609 {
610 /* Yes, remember it */
611 Vpb = OpenPacket->RelatedFileObject->Vpb;
612
613 /* Reference it */
614 InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
615
616 /* Check if we were given a specific top level device to use */
617 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
618 {
619 DeviceObject = Vpb->DeviceObject;
620 }
621 }
622 }
623 else
624 {
625 /* Check if it has a VPB */
626 if ((OriginalDeviceObject->Vpb) && !(DirectOpen))
627 {
628 /* Check if the VPB is mounted, and mount it */
629 Vpb = IopCheckVpbMounted(OpenPacket,
630 OriginalDeviceObject,
631 RemainingName,
632 &Status);
633 if (!Vpb) return Status;
634
635 /* Get the VPB's device object */
636 DeviceObject = Vpb->DeviceObject;
637 }
638 else
639 {
640 /* The device object is the one we were given */
641 DeviceObject = OriginalDeviceObject;
642 }
643
644 /* If we weren't given a specific top level device, look for an attached device */
645 if (!(OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT) &&
646 DeviceObject->AttachedDevice)
647 {
648 /* Get the attached device */
649 DeviceObject = IoGetAttachedDevice(DeviceObject);
650 }
651 }
652
653 /* If we have a top level device hint, verify it */
654 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
655 {
656 Status = IopCheckTopDeviceHint(&DeviceObject, OpenPacket, DirectOpen);
657 if (!NT_SUCCESS(Status))
658 {
659 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
660 if (Vpb) IopDereferenceVpbAndFree(Vpb);
661 return Status;
662 }
663 }
664
665 /* If we traversed a mount point, reset the information */
666 if (OpenPacket->TraversedMountPoint)
667 {
668 OpenPacket->TraversedMountPoint = FALSE;
669 }
670
671 /* Check if this is a secure FSD */
672 if ((DeviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) &&
673 ((OpenPacket->RelatedFileObject) || (RemainingName->Length)) &&
674 (!VolumeOpen))
675 {
676 Privileges = NULL;
677 GrantedAccess = 0;
678
679 KeEnterCriticalRegion();
680 ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
681
682 /* Lock the subject context */
683 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
684
685 /* Do access check */
686 AccessGranted = SeAccessCheck(OriginalDeviceObject->SecurityDescriptor,
687 &AccessState->SubjectSecurityContext,
688 TRUE,
689 DesiredAccess,
690 0,
691 &Privileges,
692 &IoFileObjectType->TypeInfo.GenericMapping,
693 UserMode,
694 &GrantedAccess,
695 &Status);
696 if (Privileges != NULL)
697 {
698 /* Append and free the privileges */
699 SeAppendPrivileges(AccessState, Privileges);
700 SeFreePrivileges(Privileges);
701 }
702
703 /* Check if we got access */
704 if (GrantedAccess)
705 {
706 AccessState->PreviouslyGrantedAccess |= GrantedAccess;
707 AccessState->RemainingDesiredAccess &= ~(GrantedAccess | MAXIMUM_ALLOWED);
708 }
709
710 FileString.Length = 8;
711 FileString.MaximumLength = 8;
712 FileString.Buffer = L"File";
713
714 /* Do Audit/Alarm for open operation
715 * NOTA: we audit target device object
716 */
717 SeOpenObjectAuditAlarm(&FileString,
718 DeviceObject,
719 CompleteName,
720 OriginalDeviceObject->SecurityDescriptor,
721 AccessState,
722 FALSE,
723 AccessGranted,
724 UserMode,
725 &AccessState->GenerateOnClose);
726
727 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
728
729 ExReleaseResourceLite(&IopSecurityResource);
730 KeLeaveCriticalRegion();
731
732 /* Check if access failed */
733 if (!AccessGranted)
734 {
735 /* Dereference the device and fail */
736 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
737 if (Vpb) IopDereferenceVpbAndFree(Vpb);
738 return STATUS_ACCESS_DENIED;
739 }
740 }
741
742 /* Allocate the IRP */
743 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
744 if (!Irp)
745 {
746 /* Dereference the device and VPB, then fail */
747 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
748 if (Vpb) IopDereferenceVpbAndFree(Vpb);
749 return STATUS_INSUFFICIENT_RESOURCES;
750 }
751
752 /* Now set the IRP data */
753 Irp->RequestorMode = AccessMode;
754 Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION;
755 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
756 Irp->UserIosb = &IoStatusBlock;
757 Irp->MdlAddress = NULL;
758 Irp->PendingReturned = FALSE;
759 Irp->UserEvent = NULL;
760 Irp->Cancel = FALSE;
761 Irp->CancelRoutine = NULL;
762 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
763
764 /* Setup the security context */
765 SecurityContext.SecurityQos = SecurityQos;
766 SecurityContext.AccessState = AccessState;
767 SecurityContext.DesiredAccess = AccessState->RemainingDesiredAccess;
768 SecurityContext.FullCreateOptions = OpenPacket->CreateOptions;
769
770 /* Get the I/O Stack location */
771 StackLoc = IoGetNextIrpStackLocation(Irp);
772 StackLoc->Control = 0;
773
774 /* Check what kind of file this is */
775 switch (OpenPacket->CreateFileType)
776 {
777 /* Normal file */
778 case CreateFileTypeNone:
779
780 /* Set the major function and EA Length */
781 StackLoc->MajorFunction = IRP_MJ_CREATE;
782 StackLoc->Parameters.Create.EaLength = OpenPacket->EaLength;
783
784 /* Set the flags */
785 StackLoc->Flags = (UCHAR)OpenPacket->Options;
786 StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ? SL_CASE_SENSITIVE: 0;
787 break;
788
789 /* Named pipe */
790 case CreateFileTypeNamedPipe:
791
792 /* Set the named pipe MJ and set the parameters */
793 StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
794 StackLoc->Parameters.CreatePipe.Parameters = OpenPacket->ExtraCreateParameters;
795 break;
796
797 /* Mailslot */
798 case CreateFileTypeMailslot:
799
800 /* Set the mailslot MJ and set the parameters */
801 StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
802 StackLoc->Parameters.CreateMailslot.Parameters = OpenPacket->ExtraCreateParameters;
803 break;
804 }
805
806 /* Set the common data */
807 Irp->Overlay.AllocationSize = OpenPacket->AllocationSize;
808 Irp->AssociatedIrp.SystemBuffer = OpenPacket->EaBuffer;
809 StackLoc->Parameters.Create.Options = (OpenPacket->Disposition << 24) |
810 (OpenPacket->CreateOptions &
811 0xFFFFFF);
812 StackLoc->Parameters.Create.FileAttributes = OpenPacket->FileAttributes;
813 StackLoc->Parameters.Create.ShareAccess = OpenPacket->ShareAccess;
814 StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
815
816 /* Check if we really need to create an object */
817 if (!UseDummyFile)
818 {
819 ULONG ObjectSize = sizeof(FILE_OBJECT);
820
821 /* Tag on space for a file object extension */
822 if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
823 ObjectSize += sizeof(FILE_OBJECT_EXTENSION);
824
825 /* Create the actual file object */
826 InitializeObjectAttributes(&ObjectAttributes,
827 NULL,
828 Attributes,
829 NULL,
830 NULL);
831 Status = ObCreateObject(KernelMode,
832 IoFileObjectType,
833 &ObjectAttributes,
834 AccessMode,
835 NULL,
836 ObjectSize,
837 0,
838 0,
839 (PVOID*)&FileObject);
840 if (!NT_SUCCESS(Status))
841 {
842 /* Create failed, free the IRP */
843 IoFreeIrp(Irp);
844
845 /* Dereference the device and VPB */
846 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
847 if (Vpb) IopDereferenceVpbAndFree(Vpb);
848
849 /* We failed, return status */
850 OpenPacket->FinalStatus = Status;
851 return Status;
852 }
853
854 /* Clear the file object */
855 RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
856
857 /* Check if this is Synch I/O */
858 if (OpenPacket->CreateOptions &
859 (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
860 {
861 /* Set the synch flag */
862 FileObject->Flags |= FO_SYNCHRONOUS_IO;
863
864 /* Check if it's also alertable */
865 if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
866 {
867 /* It is, set the alertable flag */
868 FileObject->Flags |= FO_ALERTABLE_IO;
869 }
870 }
871
872 /* Check if this is synch I/O */
873 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
874 {
875 /* Initialize the event */
876 KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE);
877 }
878
879 /* Check if the caller requested no intermediate buffering */
880 if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
881 {
882 /* Set the correct flag for the FSD to read */
883 FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
884 }
885
886 /* Check if the caller requested write through support */
887 if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
888 {
889 /* Set the correct flag for the FSD to read */
890 FileObject->Flags |= FO_WRITE_THROUGH;
891 }
892
893 /* Check if the caller says the file will be only read sequentially */
894 if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
895 {
896 /* Set the correct flag for the FSD to read */
897 FileObject->Flags |= FO_SEQUENTIAL_ONLY;
898 }
899
900 /* Check if the caller believes the file will be only read randomly */
901 if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
902 {
903 /* Set the correct flag for the FSD to read */
904 FileObject->Flags |= FO_RANDOM_ACCESS;
905 }
906
907 /* Check if we were asked to setup a file object extension */
908 if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
909 {
910 PFILE_OBJECT_EXTENSION FileObjectExtension;
911
912 /* Make sure the file object knows it has an extension */
913 FileObject->Flags |= FO_FILE_OBJECT_HAS_EXTENSION;
914
915 FileObjectExtension = (PFILE_OBJECT_EXTENSION)(FileObject + 1);
916 FileObject->FileObjectExtension = FileObjectExtension;
917
918 /* Add the top level device which we'll send the request to */
919 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
920 {
921 FileObjectExtension->TopDeviceObjectHint = DeviceObject;
922 }
923 }
924 }
925 else
926 {
927 /* Use the dummy object instead */
928 LocalFileObject = OpenPacket->LocalFileObject;
929 RtlZeroMemory(LocalFileObject, sizeof(DUMMY_FILE_OBJECT));
930
931 /* Set it up */
932 FileObject = (PFILE_OBJECT)&LocalFileObject->ObjectHeader.Body;
933 LocalFileObject->ObjectHeader.Type = IoFileObjectType;
934 LocalFileObject->ObjectHeader.PointerCount = 1;
935 }
936
937 /* Setup the file header */
938 FileObject->Type = IO_TYPE_FILE;
939 FileObject->Size = sizeof(FILE_OBJECT);
940 FileObject->RelatedFileObject = OpenPacket->RelatedFileObject;
941 FileObject->DeviceObject = OriginalDeviceObject;
942
943 /* Check if this is a direct device open */
944 if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
945
946 /* Check if the caller wants case sensitivity */
947 if (!(Attributes & OBJ_CASE_INSENSITIVE))
948 {
949 /* Tell the driver about it */
950 FileObject->Flags |= FO_OPENED_CASE_SENSITIVE;
951 }
952
953 /* Now set the file object */
954 Irp->Tail.Overlay.OriginalFileObject = FileObject;
955 StackLoc->FileObject = FileObject;
956
957 /* Check if the file object has a name */
958 if (RemainingName->Length)
959 {
960 /* Setup the unicode string */
961 FileObject->FileName.MaximumLength = RemainingName->Length +
962 sizeof(WCHAR);
963 FileObject->FileName.Buffer = ExAllocatePoolWithTag(PagedPool,
964 FileObject->
965 FileName.
966 MaximumLength,
967 TAG_IO_NAME);
968 if (!FileObject->FileName.Buffer)
969 {
970 /* Failed to allocate the name, free the IRP */
971 IoFreeIrp(Irp);
972
973 /* Dereference the device object and VPB */
974 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
975 if (Vpb) IopDereferenceVpbAndFree(Vpb);
976
977 /* Clear the FO and dereference it */
978 FileObject->DeviceObject = NULL;
979 if (!UseDummyFile) ObDereferenceObject(FileObject);
980
981 /* Fail */
982 return STATUS_INSUFFICIENT_RESOURCES;
983 }
984 }
985
986 /* Copy the name */
987 RtlCopyUnicodeString(&FileObject->FileName, RemainingName);
988
989 /* Initialize the File Object event and set the FO */
990 KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
991 OpenPacket->FileObject = FileObject;
992
993 /* Queue the IRP and call the driver */
994 IopQueueIrpToThread(Irp);
995 Status = IoCallDriver(DeviceObject, Irp);
996 if (Status == STATUS_PENDING)
997 {
998 /* Wait for the driver to complete the create */
999 KeWaitForSingleObject(&FileObject->Event,
1000 Executive,
1001 KernelMode,
1002 FALSE,
1003 NULL);
1004
1005 /* Get the new status */
1006 Status = IoStatusBlock.Status;
1007 }
1008 else
1009 {
1010 /* We'll have to complete it ourselves */
1011 ASSERT(!Irp->PendingReturned);
1012 ASSERT(!Irp->MdlAddress);
1013
1014 /* Handle name change if required */
1015 if (Status == STATUS_REPARSE)
1016 {
1017 /* Check this is a mount point */
1018 if (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)
1019 {
1020 PREPARSE_DATA_BUFFER ReparseData;
1021
1022 /* Reparse point attributes were passed by the driver in the auxiliary buffer */
1023 ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
1024 ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
1025
1026 ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
1027 ASSERT(ReparseData->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1028 ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1029
1030 IopDoNameTransmogrify(Irp, FileObject, ReparseData);
1031 }
1032 }
1033
1034 /* Completion happens at APC_LEVEL */
1035 KeRaiseIrql(APC_LEVEL, &OldIrql);
1036
1037 /* Get the new I/O Status block ourselves */
1038 IoStatusBlock = Irp->IoStatus;
1039 Status = IoStatusBlock.Status;
1040
1041 /* Manually signal the even, we can't have any waiters */
1042 FileObject->Event.Header.SignalState = 1;
1043
1044 /* Now that we've signaled the events, de-associate the IRP */
1045 IopUnQueueIrpFromThread(Irp);
1046
1047 /* Check if the IRP had an input buffer */
1048 if ((Irp->Flags & IRP_BUFFERED_IO) &&
1049 (Irp->Flags & IRP_DEALLOCATE_BUFFER))
1050 {
1051 /* Free it. A driver might've tacked one on */
1052 ExFreePool(Irp->AssociatedIrp.SystemBuffer);
1053 }
1054
1055 /* Free the IRP and bring the IRQL back down */
1056 IoFreeIrp(Irp);
1057 KeLowerIrql(OldIrql);
1058 }
1059
1060 /* Copy the I/O Status */
1061 OpenPacket->Information = IoStatusBlock.Information;
1062
1063 /* The driver failed to create the file */
1064 if (!NT_SUCCESS(Status))
1065 {
1066 /* Check if we have a name */
1067 if (FileObject->FileName.Length)
1068 {
1069 /* Free it */
1070 ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
1071 FileObject->FileName.Length = 0;
1072 }
1073
1074 /* Clear its device object */
1075 FileObject->DeviceObject = NULL;
1076
1077 /* Save this now because the FO might go away */
1078 OpenCancelled = FileObject->Flags & FO_FILE_OPEN_CANCELLED ?
1079 TRUE : FALSE;
1080
1081 /* Clear the file object in the open packet */
1082 OpenPacket->FileObject = NULL;
1083
1084 /* Dereference the file object */
1085 if (!UseDummyFile) ObDereferenceObject(FileObject);
1086
1087 /* Dereference the device object */
1088 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
1089
1090 /* Unless the driver cancelled the open, dereference the VPB */
1091 if (!(OpenCancelled) && (Vpb)) IopDereferenceVpbAndFree(Vpb);
1092
1093 /* Set the status and return */
1094 OpenPacket->FinalStatus = Status;
1095 return Status;
1096 }
1097 else if (Status == STATUS_REPARSE)
1098 {
1099 if (OpenPacket->Information == IO_REPARSE ||
1100 OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1101 {
1102 /* Update CompleteName with reparse info which got updated in IopDoNameTransmogrify() */
1103 if (CompleteName->MaximumLength < FileObject->FileName.Length)
1104 {
1105 PWSTR NewCompleteName;
1106
1107 /* Allocate a new buffer for the string */
1108 NewCompleteName = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.Length, TAG_IO_NAME);
1109 if (NewCompleteName == NULL)
1110 {
1111 OpenPacket->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
1112 return STATUS_INSUFFICIENT_RESOURCES;
1113 }
1114
1115 /* Release the old one */
1116 if (CompleteName->Buffer != NULL)
1117 {
1118 ExFreePoolWithTag(CompleteName->Buffer, 0);
1119 }
1120
1121 /* And setup the new one */
1122 CompleteName->Buffer = NewCompleteName;
1123 CompleteName->MaximumLength = FileObject->FileName.Length;
1124 }
1125
1126 /* Copy our new complete name */
1127 RtlCopyUnicodeString(CompleteName, &FileObject->FileName);
1128
1129 if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1130 {
1131 OpenPacket->RelatedFileObject = NULL;
1132 }
1133 }
1134
1135 /* Check if we have a name */
1136 if (FileObject->FileName.Length)
1137 {
1138 /* Free it */
1139 ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
1140 FileObject->FileName.Length = 0;
1141 }
1142
1143 /* Clear its device object */
1144 FileObject->DeviceObject = NULL;
1145
1146 /* Clear the file object in the open packet */
1147 OpenPacket->FileObject = NULL;
1148
1149 /* Dereference the file object */
1150 if (!UseDummyFile) ObDereferenceObject(FileObject);
1151
1152 /* Dereference the device object */
1153 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
1154
1155 /* Unless the driver cancelled the open, dereference the VPB */
1156 if (Vpb != NULL) IopDereferenceVpbAndFree(Vpb);
1157
1158 if (OpenPacket->Information != IO_REMOUNT)
1159 {
1160 OpenPacket->RelatedFileObject = NULL;
1161
1162 /* Inform we traversed a mount point for later attempt */
1163 if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1164 {
1165 OpenPacket->TraversedMountPoint = 1;
1166 }
1167
1168 /* In case we override checks, but got this on volume open, fail hard */
1169 if (OpenPacket->Override)
1170 {
1171 KeBugCheckEx(DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN,
1172 (ULONG_PTR)OriginalDeviceObject,
1173 (ULONG_PTR)DeviceObject,
1174 (ULONG_PTR)CompleteName,
1175 OpenPacket->Information);
1176 }
1177
1178 /* Return to IO/OB so that information can be upgraded */
1179 return STATUS_REPARSE;
1180 }
1181
1182 /* Loop again and reattempt an opening */
1183 continue;
1184 }
1185
1186 break;
1187 }
1188
1189 if (Attempt == IOP_MAX_REPARSE_TRAVERSAL)
1190 return STATUS_UNSUCCESSFUL;
1191
1192 /* Get the owner of the File Object */
1193 OwnerDevice = IoGetRelatedDeviceObject(FileObject);
1194
1195 /*
1196 * It's possible that the device to whom we sent the IRP to
1197 * isn't actually the device that ended opening the file object
1198 * internally.
1199 */
1200 if (OwnerDevice != DeviceObject)
1201 {
1202 /* We have to de-reference the VPB we had associated */
1203 if (Vpb) IopDereferenceVpbAndFree(Vpb);
1204
1205 /* And re-associate with the actual one */
1206 Vpb = FileObject->Vpb;
1207 if (Vpb) InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
1208 }
1209
1210 /* Make sure we are not using a dummy */
1211 if (!UseDummyFile)
1212 {
1213 /* Check if this was a volume open */
1214 if ((!(FileObject->RelatedFileObject) ||
1215 (FileObject->RelatedFileObject->Flags & FO_VOLUME_OPEN)) &&
1216 !(FileObject->FileName.Length))
1217 {
1218 /* All signs point to it, but make sure it was actually an FSD */
1219 if ((OwnerDevice->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
1220 (OwnerDevice->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
1221 (OwnerDevice->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM) ||
1222 (OwnerDevice->DeviceType == FILE_DEVICE_FILE_SYSTEM))
1223 {
1224 /* The owner device is an FSD, so this is a volume open for real */
1225 FileObject->Flags |= FO_VOLUME_OPEN;
1226 }
1227 }
1228
1229 /* Reference the object and set the parse check */
1230 ObReferenceObject(FileObject);
1231 *Object = FileObject;
1232 OpenPacket->FinalStatus = IoStatusBlock.Status;
1233 OpenPacket->ParseCheck = TRUE;
1234 return OpenPacket->FinalStatus;
1235 }
1236 else
1237 {
1238 /* Check if this was a query */
1239 if (OpenPacket->QueryOnly)
1240 {
1241 /* Check if the caller wants basic info only */
1242 if (!OpenPacket->FullAttributes)
1243 {
1244 /* Allocate the buffer */
1245 FileBasicInfo = ExAllocatePoolWithTag(NonPagedPool,
1246 sizeof(*FileBasicInfo),
1247 TAG_IO);
1248 if (FileBasicInfo)
1249 {
1250 /* Do the query */
1251 Status = IoQueryFileInformation(FileObject,
1252 FileBasicInformation,
1253 sizeof(*FileBasicInfo),
1254 FileBasicInfo,
1255 &ReturnLength);
1256 if (NT_SUCCESS(Status))
1257 {
1258 /* Copy the data */
1259 RtlCopyMemory(OpenPacket->BasicInformation,
1260 FileBasicInfo,
1261 ReturnLength);
1262 }
1263
1264 /* Free our buffer */
1265 ExFreePoolWithTag(FileBasicInfo, TAG_IO);
1266 }
1267 else
1268 {
1269 /* Fail */
1270 Status = STATUS_INSUFFICIENT_RESOURCES;
1271 }
1272 }
1273 else
1274 {
1275 /* This is a full query */
1276 Status = IoQueryFileInformation(
1277 FileObject,
1278 FileNetworkOpenInformation,
1279 sizeof(FILE_NETWORK_OPEN_INFORMATION),
1280 OpenPacket->NetworkInformation,
1281 &ReturnLength);
1282 if (!NT_SUCCESS(Status)) ASSERT(Status != STATUS_NOT_IMPLEMENTED);
1283 }
1284 }
1285
1286 /* Delete the file object */
1287 IopDeleteFile(FileObject);
1288
1289 /* Clear out the file */
1290 OpenPacket->FileObject = NULL;
1291
1292 /* Set and return status */
1293 OpenPacket->FinalStatus = Status;
1294 OpenPacket->ParseCheck = TRUE;
1295 return Status;
1296 }
1297 }
1298
1299 NTSTATUS
1300 NTAPI
1301 IopParseFile(IN PVOID ParseObject,
1302 IN PVOID ObjectType,
1303 IN OUT PACCESS_STATE AccessState,
1304 IN KPROCESSOR_MODE AccessMode,
1305 IN ULONG Attributes,
1306 IN OUT PUNICODE_STRING CompleteName,
1307 IN OUT PUNICODE_STRING RemainingName,
1308 IN OUT PVOID Context OPTIONAL,
1309 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
1310 OUT PVOID *Object)
1311 {
1312 PVOID DeviceObject;
1313 POPEN_PACKET OpenPacket = (POPEN_PACKET)Context;
1314
1315 /* Validate the open packet */
1316 if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
1317
1318 /* Get the device object */
1319 DeviceObject = IoGetRelatedDeviceObject(ParseObject);
1320 OpenPacket->RelatedFileObject = ParseObject;
1321
1322 /* Call the main routine */
1323 return IopParseDevice(DeviceObject,
1324 ObjectType,
1325 AccessState,
1326 AccessMode,
1327 Attributes,
1328 CompleteName,
1329 RemainingName,
1330 OpenPacket,
1331 SecurityQos,
1332 Object);
1333 }
1334
1335 VOID
1336 NTAPI
1337 IopDeleteFile(IN PVOID ObjectBody)
1338 {
1339 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
1340 PIRP Irp;
1341 PIO_STACK_LOCATION StackPtr;
1342 NTSTATUS Status;
1343 KEVENT Event;
1344 PDEVICE_OBJECT DeviceObject;
1345 BOOLEAN DereferenceDone = FALSE;
1346 PVPB Vpb;
1347 KIRQL OldIrql;
1348 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1349
1350 /* Check if the file has a device object */
1351 if (FileObject->DeviceObject)
1352 {
1353 /* Check if this is a direct open or not */
1354 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1355 {
1356 /* Get the attached device */
1357 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1358 }
1359 else
1360 {
1361 /* Use the file object's device object */
1362 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1363 }
1364
1365 /* Sanity check */
1366 ASSERT(!(FileObject->Flags & FO_SYNCHRONOUS_IO) ||
1367 (InterlockedExchange((PLONG)&FileObject->Busy, TRUE) == FALSE));
1368
1369 /* Check if the handle wasn't created yet */
1370 if (!(FileObject->Flags & FO_HANDLE_CREATED))
1371 {
1372 /* Send the cleanup IRP */
1373 IopCloseFile(NULL, ObjectBody, 0, 1, 1);
1374 }
1375
1376 /* Clear and set up Events */
1377 KeClearEvent(&FileObject->Event);
1378 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1379
1380 /* Allocate an IRP */
1381 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
1382
1383 /* Set it up */
1384 Irp->UserEvent = &Event;
1385 Irp->UserIosb = &Irp->IoStatus;
1386 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1387 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1388 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
1389
1390 /* Set up Stack Pointer Data */
1391 StackPtr = IoGetNextIrpStackLocation(Irp);
1392 StackPtr->MajorFunction = IRP_MJ_CLOSE;
1393 StackPtr->FileObject = FileObject;
1394
1395 /* Queue the IRP */
1396 IopQueueIrpToThread(Irp);
1397
1398 /* Get the VPB and check if this isn't a direct open */
1399 Vpb = FileObject->Vpb;
1400 if ((Vpb) && !(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
1401 {
1402 /* Dereference the VPB before the close */
1403 InterlockedDecrement((PLONG)&Vpb->ReferenceCount);
1404 }
1405
1406 /* Check if the FS will never disappear by itself */
1407 if (FileObject->DeviceObject->Flags & DO_NEVER_LAST_DEVICE)
1408 {
1409 /* Dereference it */
1410 InterlockedDecrement(&FileObject->DeviceObject->ReferenceCount);
1411 DereferenceDone = TRUE;
1412 }
1413
1414 /* Call the FS Driver */
1415 Status = IoCallDriver(DeviceObject, Irp);
1416 if (Status == STATUS_PENDING)
1417 {
1418 /* Wait for completion */
1419 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1420 }
1421
1422 /* De-queue the IRP */
1423 KeRaiseIrql(APC_LEVEL, &OldIrql);
1424 IopUnQueueIrpFromThread(Irp);
1425 KeLowerIrql(OldIrql);
1426
1427 /* Free the IRP */
1428 IoFreeIrp(Irp);
1429
1430 /* Clear the file name */
1431 if (FileObject->FileName.Buffer)
1432 {
1433 ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
1434 FileObject->FileName.Buffer = NULL;
1435 }
1436
1437 /* Check if the FO had a completion port */
1438 if (FileObject->CompletionContext)
1439 {
1440 /* Free it */
1441 ObDereferenceObject(FileObject->CompletionContext->Port);
1442 ExFreePool(FileObject->CompletionContext);
1443 }
1444
1445 /* Check if the FO had extension */
1446 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
1447 {
1448 /* Release filter context structure if any */
1449 FsRtlPTeardownPerFileObjectContexts(FileObject);
1450 }
1451
1452 /* Check if dereference has been done yet */
1453 if (!DereferenceDone)
1454 {
1455 /* Dereference device object */
1456 IopDereferenceDeviceObject(FileObject->DeviceObject, FALSE);
1457 }
1458 }
1459 }
1460
1461 PDEVICE_OBJECT
1462 NTAPI
1463 IopGetDeviceAttachmentBase(IN PDEVICE_OBJECT DeviceObject)
1464 {
1465 PDEVICE_OBJECT PDO = DeviceObject;
1466
1467 /* Go down the stack to attempt to get the PDO */
1468 for (; ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo != NULL;
1469 PDO = ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo);
1470
1471 return PDO;
1472 }
1473
1474 PDEVICE_OBJECT
1475 NTAPI
1476 IopGetDevicePDO(IN PDEVICE_OBJECT DeviceObject)
1477 {
1478 KIRQL OldIrql;
1479 PDEVICE_OBJECT PDO;
1480
1481 ASSERT(DeviceObject != NULL);
1482
1483 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
1484 /* Get the base DO */
1485 PDO = IopGetDeviceAttachmentBase(DeviceObject);
1486 /* Check whether that's really a PDO and if so, keep it */
1487 if ((PDO->Flags & DO_BUS_ENUMERATED_DEVICE) != DO_BUS_ENUMERATED_DEVICE)
1488 {
1489 PDO = NULL;
1490 }
1491 else
1492 {
1493 ObReferenceObject(PDO);
1494 }
1495 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
1496
1497 return PDO;
1498 }
1499
1500 NTSTATUS
1501 NTAPI
1502 IopSetDeviceSecurityDescriptor(IN PDEVICE_OBJECT DeviceObject,
1503 IN PSECURITY_INFORMATION SecurityInformation,
1504 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1505 IN POOL_TYPE PoolType,
1506 IN PGENERIC_MAPPING GenericMapping)
1507 {
1508 NTSTATUS Status;
1509 PSECURITY_DESCRIPTOR OldSecurityDescriptor, CachedSecurityDescriptor, NewSecurityDescriptor;
1510
1511 PAGED_CODE();
1512
1513 /* Keep attempting till we find our old SD or fail */
1514 while (TRUE)
1515 {
1516 KeEnterCriticalRegion();
1517 ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
1518
1519 /* Get our old SD and reference it */
1520 OldSecurityDescriptor = DeviceObject->SecurityDescriptor;
1521 if (OldSecurityDescriptor != NULL)
1522 {
1523 ObReferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1524 }
1525
1526 ExReleaseResourceLite(&IopSecurityResource);
1527 KeLeaveCriticalRegion();
1528
1529 /* Set the SD information */
1530 NewSecurityDescriptor = OldSecurityDescriptor;
1531 Status = SeSetSecurityDescriptorInfo(NULL, SecurityInformation,
1532 SecurityDescriptor, &NewSecurityDescriptor,
1533 PoolType, GenericMapping);
1534
1535 if (!NT_SUCCESS(Status))
1536 {
1537 if (OldSecurityDescriptor != NULL)
1538 {
1539 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1540 }
1541
1542 break;
1543 }
1544
1545 /* Add the new DS to the internal cache */
1546 Status = ObLogSecurityDescriptor(NewSecurityDescriptor,
1547 &CachedSecurityDescriptor, 1);
1548 ExFreePool(NewSecurityDescriptor);
1549 if (!NT_SUCCESS(Status))
1550 {
1551 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1552 break;
1553 }
1554
1555 KeEnterCriticalRegion();
1556 ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
1557 /* Check if someone changed it in our back */
1558 if (DeviceObject->SecurityDescriptor == OldSecurityDescriptor)
1559 {
1560 /* We're clear, do the swap */
1561 DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
1562 ExReleaseResourceLite(&IopSecurityResource);
1563 KeLeaveCriticalRegion();
1564
1565 /* And dereference old SD (twice - us + not in use) */
1566 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 2);
1567
1568 break;
1569 }
1570 ExReleaseResourceLite(&IopSecurityResource);
1571 KeLeaveCriticalRegion();
1572
1573 /* If so, try again */
1574 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1575 ObDereferenceSecurityDescriptor(CachedSecurityDescriptor, 1);
1576 }
1577
1578 return Status;
1579 }
1580
1581 NTSTATUS
1582 NTAPI
1583 IopSetDeviceSecurityDescriptors(IN PDEVICE_OBJECT UpperDeviceObject,
1584 IN PDEVICE_OBJECT PhysicalDeviceObject,
1585 IN PSECURITY_INFORMATION SecurityInformation,
1586 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1587 IN POOL_TYPE PoolType,
1588 IN PGENERIC_MAPPING GenericMapping)
1589 {
1590 PDEVICE_OBJECT CurrentDO = PhysicalDeviceObject, NextDevice;
1591 NTSTATUS Status = STATUS_SUCCESS, TmpStatus;
1592
1593 PAGED_CODE();
1594
1595 ASSERT(PhysicalDeviceObject != NULL);
1596
1597 /* We always reference the DO we're working on */
1598 ObReferenceObject(CurrentDO);
1599
1600 /* Go up from PDO to latest DO */
1601 do
1602 {
1603 /* Attempt to set the new SD on it */
1604 TmpStatus = IopSetDeviceSecurityDescriptor(CurrentDO, SecurityInformation,
1605 SecurityDescriptor, PoolType,
1606 GenericMapping);
1607 /* Was our last one? Remember that status then */
1608 if (CurrentDO == UpperDeviceObject)
1609 {
1610 Status = TmpStatus;
1611 }
1612
1613 /* Try to move to the next DO (and thus, reference it) */
1614 NextDevice = CurrentDO->AttachedDevice;
1615 if (NextDevice)
1616 {
1617 ObReferenceObject(NextDevice);
1618 }
1619
1620 /* Dereference current DO and move to the next one */
1621 ObDereferenceObject(CurrentDO);
1622 CurrentDO = NextDevice;
1623 }
1624 while (CurrentDO != NULL);
1625
1626 return Status;
1627 }
1628
1629 NTSTATUS
1630 NTAPI
1631 IopGetSetSecurityObject(IN PVOID ObjectBody,
1632 IN SECURITY_OPERATION_CODE OperationCode,
1633 IN PSECURITY_INFORMATION SecurityInformation,
1634 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1635 IN OUT PULONG BufferLength,
1636 IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
1637 IN POOL_TYPE PoolType,
1638 IN OUT PGENERIC_MAPPING GenericMapping)
1639 {
1640 IO_STATUS_BLOCK IoStatusBlock;
1641 PIO_STACK_LOCATION StackPtr;
1642 PFILE_OBJECT FileObject;
1643 PDEVICE_OBJECT DeviceObject;
1644 PIRP Irp;
1645 BOOLEAN LocalEvent = FALSE;
1646 KEVENT Event;
1647 NTSTATUS Status = STATUS_SUCCESS;
1648 PAGED_CODE();
1649 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1650
1651 /* Check if this is a device or file */
1652 if (((PFILE_OBJECT)ObjectBody)->Type == IO_TYPE_DEVICE)
1653 {
1654 /* It's a device */
1655 DeviceObject = (PDEVICE_OBJECT)ObjectBody;
1656 FileObject = NULL;
1657 }
1658 else
1659 {
1660 /* It's a file */
1661 FileObject = (PFILE_OBJECT)ObjectBody;
1662
1663 /* Check if this is a direct open */
1664 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1665 {
1666 /* Get the Device Object */
1667 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1668 }
1669 else
1670 {
1671 /* Otherwise, use the direct device*/
1672 DeviceObject = FileObject->DeviceObject;
1673 }
1674 }
1675
1676 /* Check if the request was for a device object */
1677 if (!(FileObject) ||
1678 (!(FileObject->FileName.Length) && !(FileObject->RelatedFileObject)) ||
1679 (FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
1680 {
1681 /* Check what kind of request this was */
1682 if (OperationCode == QuerySecurityDescriptor)
1683 {
1684 return SeQuerySecurityDescriptorInfo(SecurityInformation,
1685 SecurityDescriptor,
1686 BufferLength,
1687 &DeviceObject->SecurityDescriptor);
1688 }
1689 else if (OperationCode == DeleteSecurityDescriptor)
1690 {
1691 /* Simply return success */
1692 return STATUS_SUCCESS;
1693 }
1694 else if (OperationCode == AssignSecurityDescriptor)
1695 {
1696 Status = STATUS_SUCCESS;
1697
1698 /* Make absolutely sure this is a device object */
1699 if (!(FileObject) || !(FileObject->Flags & FO_STREAM_FILE))
1700 {
1701 PSECURITY_DESCRIPTOR CachedSecurityDescriptor;
1702
1703 /* Add the security descriptor in cache */
1704 Status = ObLogSecurityDescriptor(SecurityDescriptor, &CachedSecurityDescriptor, 1);
1705 if (NT_SUCCESS(Status))
1706 {
1707 KeEnterCriticalRegion();
1708 ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
1709
1710 /* Assign the Security Descriptor */
1711 DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
1712
1713 ExReleaseResourceLite(&IopSecurityResource);
1714 KeLeaveCriticalRegion();
1715 }
1716 }
1717
1718 /* Return status */
1719 return Status;
1720 }
1721 else if (OperationCode == SetSecurityDescriptor)
1722 {
1723 /* Get the Physical Device Object if any */
1724 PDEVICE_OBJECT PDO = IopGetDevicePDO(DeviceObject);
1725
1726 if (PDO != NULL)
1727 {
1728 /* Apply the new SD to any DO in the path from PDO to current DO */
1729 Status = IopSetDeviceSecurityDescriptors(DeviceObject, PDO,
1730 SecurityInformation,
1731 SecurityDescriptor,
1732 PoolType, GenericMapping);
1733 ObDereferenceObject(PDO);
1734 }
1735 else
1736 {
1737 /* Otherwise, just set for ourselves */
1738 Status = IopSetDeviceSecurityDescriptor(DeviceObject,
1739 SecurityInformation,
1740 SecurityDescriptor,
1741 PoolType, GenericMapping);
1742 }
1743
1744 return STATUS_SUCCESS;
1745 }
1746
1747 /* Shouldn't happen */
1748 return STATUS_SUCCESS;
1749 }
1750 else if (OperationCode == DeleteSecurityDescriptor)
1751 {
1752 /* Same as for devices, do nothing */
1753 return STATUS_SUCCESS;
1754 }
1755
1756 /* At this point, we know we're a file. Reference it */
1757 ObReferenceObject(FileObject);
1758
1759 /* Check if we should use Sync IO or not */
1760 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1761 {
1762 /* Lock the file object */
1763 Status = IopLockFileObject(FileObject, ExGetPreviousMode());
1764 if (Status != STATUS_SUCCESS)
1765 {
1766 ObDereferenceObject(FileObject);
1767 return Status;
1768 }
1769 }
1770 else
1771 {
1772 /* Use local event */
1773 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1774 LocalEvent = TRUE;
1775 }
1776
1777 /* Clear the File Object event */
1778 KeClearEvent(&FileObject->Event);
1779
1780 /* Get the device object */
1781 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1782
1783 /* Allocate the IRP */
1784 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1785 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
1786
1787 /* Set the IRP */
1788 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1789 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1790 Irp->RequestorMode = ExGetPreviousMode();
1791 Irp->UserIosb = &IoStatusBlock;
1792 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1793 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1794 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1795
1796 /* Set Stack Parameters */
1797 StackPtr = IoGetNextIrpStackLocation(Irp);
1798 StackPtr->FileObject = FileObject;
1799
1800 /* Check if this is a query or set */
1801 if (OperationCode == QuerySecurityDescriptor)
1802 {
1803 /* Set the major function and parameters */
1804 StackPtr->MajorFunction = IRP_MJ_QUERY_SECURITY;
1805 StackPtr->Parameters.QuerySecurity.SecurityInformation =
1806 *SecurityInformation;
1807 StackPtr->Parameters.QuerySecurity.Length = *BufferLength;
1808 Irp->UserBuffer = SecurityDescriptor;
1809 }
1810 else
1811 {
1812 /* Set the major function and parameters for a set */
1813 StackPtr->MajorFunction = IRP_MJ_SET_SECURITY;
1814 StackPtr->Parameters.SetSecurity.SecurityInformation =
1815 *SecurityInformation;
1816 StackPtr->Parameters.SetSecurity.SecurityDescriptor =
1817 SecurityDescriptor;
1818 }
1819
1820 /* Queue the IRP */
1821 IopQueueIrpToThread(Irp);
1822
1823 /* Update operation counts */
1824 IopUpdateOperationCount(IopOtherTransfer);
1825
1826 /* Call the Driver */
1827 Status = IoCallDriver(DeviceObject, Irp);
1828
1829 /* Check if this was async I/O */
1830 if (LocalEvent)
1831 {
1832 /* Check if the IRP is pending completion */
1833 if (Status == STATUS_PENDING)
1834 {
1835 /* Wait on the local event */
1836 KeWaitForSingleObject(&Event,
1837 Executive,
1838 KernelMode,
1839 FALSE,
1840 NULL);
1841 Status = IoStatusBlock.Status;
1842 }
1843 }
1844 else
1845 {
1846 /* Check if the IRP is pending completion */
1847 if (Status == STATUS_PENDING)
1848 {
1849 /* Wait on the file object */
1850 KeWaitForSingleObject(&FileObject->Event,
1851 Executive,
1852 KernelMode,
1853 FALSE,
1854 NULL);
1855 Status = FileObject->FinalStatus;
1856 }
1857
1858 /* Release the lock */
1859 IopUnlockFileObject(FileObject);
1860 }
1861
1862 /* This Driver doesn't implement Security, so try to give it a default */
1863 if (Status == STATUS_INVALID_DEVICE_REQUEST)
1864 {
1865 /* Was this a query? */
1866 if (OperationCode == QuerySecurityDescriptor)
1867 {
1868 /* Set a World Security Descriptor */
1869 Status = SeSetWorldSecurityDescriptor(*SecurityInformation,
1870 SecurityDescriptor,
1871 BufferLength);
1872 }
1873 else
1874 {
1875 /* It wasn't a query, so just fake success */
1876 Status = STATUS_SUCCESS;
1877 }
1878 }
1879 else if (OperationCode == QuerySecurityDescriptor)
1880 {
1881 /* Callers usually expect the normalized form */
1882 if (Status == STATUS_BUFFER_OVERFLOW) Status = STATUS_BUFFER_TOO_SMALL;
1883
1884 _SEH2_TRY
1885 {
1886 /* Return length */
1887 *BufferLength = (ULONG)IoStatusBlock.Information;
1888 }
1889 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1890 {
1891 /* Get the exception code */
1892 Status = _SEH2_GetExceptionCode();
1893 }
1894 _SEH2_END;
1895 }
1896
1897 /* Return Status */
1898 return Status;
1899 }
1900
1901 NTSTATUS
1902 NTAPI
1903 IopQueryName(IN PVOID ObjectBody,
1904 IN BOOLEAN HasName,
1905 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
1906 IN ULONG Length,
1907 OUT PULONG ReturnLength,
1908 IN KPROCESSOR_MODE PreviousMode)
1909 {
1910 return IopQueryNameInternal(ObjectBody,
1911 HasName,
1912 FALSE,
1913 ObjectNameInfo,
1914 Length,
1915 ReturnLength,
1916 PreviousMode);
1917 }
1918
1919 NTSTATUS
1920 NTAPI
1921 IopQueryNameInternal(IN PVOID ObjectBody,
1922 IN BOOLEAN HasName,
1923 IN BOOLEAN QueryDosName,
1924 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
1925 IN ULONG Length,
1926 OUT PULONG ReturnLength,
1927 IN KPROCESSOR_MODE PreviousMode)
1928 {
1929 POBJECT_NAME_INFORMATION LocalInfo;
1930 PFILE_NAME_INFORMATION LocalFileInfo;
1931 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
1932 ULONG LocalReturnLength, FileLength;
1933 BOOLEAN LengthMismatch = FALSE;
1934 NTSTATUS Status;
1935 PWCHAR p;
1936 PDEVICE_OBJECT DeviceObject;
1937 BOOLEAN NoObCall;
1938
1939 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1940
1941 /* Validate length */
1942 if (Length < sizeof(OBJECT_NAME_INFORMATION))
1943 {
1944 /* Wrong length, fail */
1945 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
1946 return STATUS_INFO_LENGTH_MISMATCH;
1947 }
1948
1949 /* Allocate Buffer */
1950 LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, TAG_IO);
1951 if (!LocalInfo) return STATUS_INSUFFICIENT_RESOURCES;
1952
1953 /* Query DOS name if the caller asked to */
1954 NoObCall = FALSE;
1955 if (QueryDosName)
1956 {
1957 DeviceObject = FileObject->DeviceObject;
1958
1959 /* In case of a network file system, don't call mountmgr */
1960 if (DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM)
1961 {
1962 /* We'll store separator and terminator */
1963 LocalReturnLength = sizeof(OBJECT_NAME_INFORMATION) + 2 * sizeof(WCHAR);
1964 if (Length < LocalReturnLength)
1965 {
1966 Status = STATUS_BUFFER_OVERFLOW;
1967 }
1968 else
1969 {
1970 LocalInfo->Name.Length = sizeof(WCHAR);
1971 LocalInfo->Name.MaximumLength = sizeof(WCHAR);
1972 LocalInfo->Name.Buffer = (PVOID)((ULONG_PTR)LocalInfo + sizeof(OBJECT_NAME_INFORMATION));
1973 LocalInfo->Name.Buffer[0] = OBJ_NAME_PATH_SEPARATOR;
1974 Status = STATUS_SUCCESS;
1975 }
1976 }
1977 /* Otherwise, call mountmgr to get DOS name */
1978 else
1979 {
1980 Status = IoVolumeDeviceToDosName(DeviceObject, &LocalInfo->Name);
1981 LocalReturnLength = LocalInfo->Name.Length + sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR);
1982 }
1983 }
1984
1985 /* Fall back if querying DOS name failed or if caller never wanted it ;-) */
1986 if (!QueryDosName || !NT_SUCCESS(Status))
1987 {
1988 /* Query the name */
1989 Status = ObQueryNameString(FileObject->DeviceObject,
1990 LocalInfo,
1991 Length,
1992 &LocalReturnLength);
1993 }
1994 else
1995 {
1996 NoObCall = TRUE;
1997 }
1998
1999 if (!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
2000 {
2001 /* Free the buffer and fail */
2002 ExFreePoolWithTag(LocalInfo, TAG_IO);
2003 return Status;
2004 }
2005
2006 /* Get buffer pointer */
2007 p = (PWCHAR)(ObjectNameInfo + 1);
2008
2009 _SEH2_TRY
2010 {
2011 /* Copy the information */
2012 if (QueryDosName && NoObCall)
2013 {
2014 ASSERT(PreviousMode == KernelMode);
2015
2016 /* Copy structure first */
2017 RtlCopyMemory(ObjectNameInfo,
2018 LocalInfo,
2019 (Length >= LocalReturnLength ? sizeof(OBJECT_NAME_INFORMATION) : Length));
2020 /* Name then */
2021 RtlCopyMemory(p, LocalInfo->Name.Buffer,
2022 (Length >= LocalReturnLength ? LocalInfo->Name.Length : Length - sizeof(OBJECT_NAME_INFORMATION)));
2023
2024 if (FileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM)
2025 {
2026 ExFreePool(LocalInfo->Name.Buffer);
2027 }
2028 }
2029 else
2030 {
2031 RtlCopyMemory(ObjectNameInfo,
2032 LocalInfo,
2033 (LocalReturnLength > Length) ?
2034 Length : LocalReturnLength);
2035 }
2036
2037 /* Set buffer pointer */
2038 ObjectNameInfo->Name.Buffer = p;
2039
2040 /* Advance in buffer */
2041 p += (LocalInfo->Name.Length / sizeof(WCHAR));
2042
2043 /* Check if this already filled our buffer */
2044 if (LocalReturnLength > Length)
2045 {
2046 /* Set the length mismatch to true, so that we can return
2047 * the proper buffer size to the caller later
2048 */
2049 LengthMismatch = TRUE;
2050
2051 /* Save the initial buffer length value */
2052 *ReturnLength = LocalReturnLength;
2053 }
2054
2055 /* Now get the file name buffer and check the length needed */
2056 LocalFileInfo = (PFILE_NAME_INFORMATION)LocalInfo;
2057 FileLength = Length -
2058 LocalReturnLength +
2059 FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2060
2061 /* Query the File name */
2062 if (PreviousMode == KernelMode &&
2063 BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2064 {
2065 Status = IopGetFileInformation(FileObject,
2066 LengthMismatch ? Length : FileLength,
2067 FileNameInformation,
2068 LocalFileInfo,
2069 &LocalReturnLength);
2070 }
2071 else
2072 {
2073 Status = IoQueryFileInformation(FileObject,
2074 FileNameInformation,
2075 LengthMismatch ? Length : FileLength,
2076 LocalFileInfo,
2077 &LocalReturnLength);
2078 }
2079 if (NT_ERROR(Status))
2080 {
2081 /* Allow status that would mean it's not implemented in the storage stack */
2082 if (Status != STATUS_INVALID_PARAMETER && Status != STATUS_INVALID_DEVICE_REQUEST &&
2083 Status != STATUS_NOT_IMPLEMENTED && Status != STATUS_INVALID_INFO_CLASS)
2084 {
2085 _SEH2_LEAVE;
2086 }
2087
2088 /* In such case, zero output */
2089 LocalReturnLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2090 LocalFileInfo->FileNameLength = 0;
2091 LocalFileInfo->FileName[0] = OBJ_NAME_PATH_SEPARATOR;
2092 }
2093 else
2094 {
2095 /* We'll at least return the name length */
2096 if (LocalReturnLength < FIELD_OFFSET(FILE_NAME_INFORMATION, FileName))
2097 {
2098 LocalReturnLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2099 }
2100 }
2101
2102 /* If the provided buffer is too small, return the required size */
2103 if (LengthMismatch)
2104 {
2105 /* Add the required length */
2106 *ReturnLength += LocalFileInfo->FileNameLength;
2107
2108 /* Free the allocated buffer and return failure */
2109 Status = STATUS_BUFFER_OVERFLOW;
2110 _SEH2_LEAVE;
2111 }
2112
2113 /* Now calculate the new lengths left */
2114 FileLength = LocalReturnLength -
2115 FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2116 LocalReturnLength = (ULONG)((ULONG_PTR)p -
2117 (ULONG_PTR)ObjectNameInfo +
2118 LocalFileInfo->FileNameLength);
2119
2120 /* Don't copy the name if it's not valid */
2121 if (LocalFileInfo->FileName[0] != OBJ_NAME_PATH_SEPARATOR)
2122 {
2123 /* Free the allocated buffer and return failure */
2124 Status = STATUS_OBJECT_PATH_INVALID;
2125 _SEH2_LEAVE;
2126 }
2127
2128 /* Write the Name and null-terminate it */
2129 RtlCopyMemory(p, LocalFileInfo->FileName, FileLength);
2130 p += (FileLength / sizeof(WCHAR));
2131 *p = UNICODE_NULL;
2132 LocalReturnLength += sizeof(UNICODE_NULL);
2133
2134 /* Return the length needed */
2135 *ReturnLength = LocalReturnLength;
2136
2137 /* Setup the length and maximum length */
2138 FileLength = (ULONG)((ULONG_PTR)p - (ULONG_PTR)ObjectNameInfo);
2139 ObjectNameInfo->Name.Length = (USHORT)FileLength -
2140 sizeof(OBJECT_NAME_INFORMATION);
2141 ObjectNameInfo->Name.MaximumLength = (USHORT)ObjectNameInfo->Name.Length +
2142 sizeof(UNICODE_NULL);
2143 }
2144 _SEH2_FINALLY
2145 {
2146 /* Free buffer and return */
2147 ExFreePoolWithTag(LocalInfo, TAG_IO);
2148 } _SEH2_END;
2149
2150 return Status;
2151 }
2152
2153 VOID
2154 NTAPI
2155 IopCloseFile(IN PEPROCESS Process OPTIONAL,
2156 IN PVOID ObjectBody,
2157 IN ACCESS_MASK GrantedAccess,
2158 IN ULONG HandleCount,
2159 IN ULONG SystemHandleCount)
2160 {
2161 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
2162 KEVENT Event;
2163 PIRP Irp;
2164 PIO_STACK_LOCATION StackPtr;
2165 NTSTATUS Status;
2166 PDEVICE_OBJECT DeviceObject;
2167 KIRQL OldIrql;
2168 IO_STATUS_BLOCK IoStatusBlock;
2169 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
2170
2171 /* If this isn't the last handle for the current process, quit */
2172 if (HandleCount != 1) return;
2173
2174 /* Check if the file is locked and has more then one handle opened */
2175 if ((FileObject->LockOperation) && (SystemHandleCount != 1))
2176 {
2177 /* Check if this is a direct open or not */
2178 if (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN))
2179 {
2180 /* Get the attached device */
2181 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2182 }
2183 else
2184 {
2185 /* Get the FO's device */
2186 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2187 }
2188
2189 /* Check if this is a sync FO and lock it */
2190 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2191 {
2192 (VOID)IopLockFileObject(FileObject, KernelMode);
2193 }
2194
2195 /* Go the FastIO path if possible, otherwise fall back to IRP */
2196 if (DeviceObject->DriverObject->FastIoDispatch == NULL ||
2197 DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll == NULL ||
2198 !DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll(FileObject, PsGetCurrentProcess(), &IoStatusBlock, DeviceObject))
2199 {
2200 /* Clear and set up Events */
2201 KeClearEvent(&FileObject->Event);
2202 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2203
2204 /* Allocate an IRP */
2205 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
2206
2207 /* Set it up */
2208 Irp->UserEvent = &Event;
2209 Irp->UserIosb = &Irp->IoStatus;
2210 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2211 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2212 Irp->RequestorMode = KernelMode;
2213 Irp->Flags = IRP_SYNCHRONOUS_API;
2214 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2215 ObReferenceObject(FileObject);
2216
2217 /* Set up Stack Pointer Data */
2218 StackPtr = IoGetNextIrpStackLocation(Irp);
2219 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
2220 StackPtr->MinorFunction = IRP_MN_UNLOCK_ALL;
2221 StackPtr->FileObject = FileObject;
2222
2223 /* Queue the IRP */
2224 IopQueueIrpToThread(Irp);
2225
2226 /* Call the FS Driver */
2227 Status = IoCallDriver(DeviceObject, Irp);
2228 if (Status == STATUS_PENDING)
2229 {
2230 /* Wait for completion */
2231 KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
2232 }
2233
2234 /* IO will unqueue & free for us */
2235 }
2236
2237 /* Release the lock if we were holding it */
2238 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2239 {
2240 IopUnlockFileObject(FileObject);
2241 }
2242 }
2243
2244 /* Make sure this is the last handle */
2245 if (SystemHandleCount != 1) return;
2246
2247 /* Check if this is a direct open or not */
2248 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2249 {
2250 /* Get the attached device */
2251 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2252 }
2253 else
2254 {
2255 /* Get the FO's device */
2256 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2257 }
2258
2259 /* Set the handle created flag */
2260 FileObject->Flags |= FO_HANDLE_CREATED;
2261
2262 /* Check if this is a sync FO and lock it */
2263 if (Process != NULL &&
2264 BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2265 {
2266 (VOID)IopLockFileObject(FileObject, KernelMode);
2267 }
2268
2269 /* Clear and set up Events */
2270 KeClearEvent(&FileObject->Event);
2271 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2272
2273 /* Allocate an IRP */
2274 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
2275
2276 /* Set it up */
2277 Irp->UserEvent = &Event;
2278 Irp->UserIosb = &Irp->IoStatus;
2279 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2280 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2281 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2282 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
2283
2284 /* Set up Stack Pointer Data */
2285 StackPtr = IoGetNextIrpStackLocation(Irp);
2286 StackPtr->MajorFunction = IRP_MJ_CLEANUP;
2287 StackPtr->FileObject = FileObject;
2288
2289 /* Queue the IRP */
2290 IopQueueIrpToThread(Irp);
2291
2292 /* Update operation counts */
2293 IopUpdateOperationCount(IopOtherTransfer);
2294
2295 /* Call the FS Driver */
2296 Status = IoCallDriver(DeviceObject, Irp);
2297 if (Status == STATUS_PENDING)
2298 {
2299 /* Wait for completion */
2300 KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
2301 }
2302
2303 /* Unqueue the IRP */
2304 KeRaiseIrql(APC_LEVEL, &OldIrql);
2305 IopUnQueueIrpFromThread(Irp);
2306 KeLowerIrql(OldIrql);
2307
2308 /* Free the IRP */
2309 IoFreeIrp(Irp);
2310
2311 /* Release the lock if we were holding it */
2312 if (Process != NULL &&
2313 BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2314 {
2315 IopUnlockFileObject(FileObject);
2316 }
2317 }
2318
2319 NTSTATUS
2320 NTAPI
2321 IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2322 IN FILE_INFORMATION_CLASS FileInformationClass,
2323 IN ULONG FileInformationSize,
2324 OUT PVOID FileInformation)
2325 {
2326 NTSTATUS Status;
2327 KPROCESSOR_MODE AccessMode = ExGetPreviousMode();
2328 DUMMY_FILE_OBJECT LocalFileObject;
2329 FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo;
2330 HANDLE Handle;
2331 OPEN_PACKET OpenPacket;
2332 BOOLEAN IsBasic;
2333 PAGED_CODE();
2334 IOTRACE(IO_FILE_DEBUG, "Class: %lx\n", FileInformationClass);
2335
2336 /* Check if the caller was user mode */
2337 if (AccessMode != KernelMode)
2338 {
2339 /* Protect probe in SEH */
2340 _SEH2_TRY
2341 {
2342 /* Probe the buffer */
2343 ProbeForWrite(FileInformation, FileInformationSize, sizeof(ULONG));
2344 }
2345 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2346 {
2347 /* Return the exception code */
2348 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2349 }
2350 _SEH2_END;
2351 }
2352
2353 /* Check if this is a basic or full request */
2354 IsBasic = (FileInformationSize == sizeof(FILE_BASIC_INFORMATION));
2355
2356 /* Setup the Open Packet */
2357 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
2358 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
2359 OpenPacket.Size = sizeof(OPEN_PACKET);
2360 OpenPacket.CreateOptions = FILE_OPEN_REPARSE_POINT;
2361 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2362 OpenPacket.Disposition = FILE_OPEN;
2363 OpenPacket.BasicInformation = IsBasic ? FileInformation : NULL;
2364 OpenPacket.NetworkInformation = IsBasic ? &NetworkOpenInfo :
2365 (AccessMode != KernelMode) ?
2366 &NetworkOpenInfo : FileInformation;
2367 OpenPacket.QueryOnly = TRUE;
2368 OpenPacket.FullAttributes = IsBasic ? FALSE : TRUE;
2369 OpenPacket.LocalFileObject = &LocalFileObject;
2370
2371 /* Update the operation count */
2372 IopUpdateOperationCount(IopOtherTransfer);
2373
2374 /*
2375 * Attempt opening the file. This will call the I/O Parse Routine for
2376 * the File Object (IopParseDevice) which will use the dummy file obejct
2377 * send the IRP to its device object. Note that we have two statuses
2378 * to worry about: the Object Manager's status (in Status) and the I/O
2379 * status, which is in the Open Packet's Final Status, and determined
2380 * by the Parse Check member.
2381 */
2382 Status = ObOpenObjectByName(ObjectAttributes,
2383 NULL,
2384 AccessMode,
2385 NULL,
2386 FILE_READ_ATTRIBUTES,
2387 &OpenPacket,
2388 &Handle);
2389 if (OpenPacket.ParseCheck == FALSE)
2390 {
2391 /* Parse failed */
2392 DPRINT("IopQueryAttributesFile failed for '%wZ' with 0x%lx\n",
2393 ObjectAttributes->ObjectName, Status);
2394 return Status;
2395 }
2396 else
2397 {
2398 /* Use the Io status */
2399 Status = OpenPacket.FinalStatus;
2400 }
2401
2402 /* Check if we were succesful and this was user mode and a full query */
2403 if ((NT_SUCCESS(Status)) && (AccessMode != KernelMode) && !(IsBasic))
2404 {
2405 /* Enter SEH for copy */
2406 _SEH2_TRY
2407 {
2408 /* Copy the buffer back */
2409 RtlCopyMemory(FileInformation,
2410 &NetworkOpenInfo,
2411 FileInformationSize);
2412 }
2413 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2414 {
2415 /* Get exception code */
2416 Status = _SEH2_GetExceptionCode();
2417 }
2418 _SEH2_END;
2419 }
2420
2421 /* Return status */
2422 return Status;
2423 }
2424
2425 NTSTATUS
2426 NTAPI
2427 IopAcquireFileObjectLock(
2428 _In_ PFILE_OBJECT FileObject,
2429 _In_ KPROCESSOR_MODE WaitMode,
2430 _In_ BOOLEAN Alertable,
2431 _Out_ PBOOLEAN LockFailed)
2432 {
2433 NTSTATUS Status;
2434
2435 PAGED_CODE();
2436
2437 InterlockedIncrement((PLONG)&FileObject->Waiters);
2438
2439 Status = STATUS_SUCCESS;
2440 do
2441 {
2442 if (!InterlockedExchange((PLONG)&FileObject->Busy, TRUE))
2443 {
2444 break;
2445 }
2446 Status = KeWaitForSingleObject(&FileObject->Lock,
2447 Executive,
2448 WaitMode,
2449 Alertable,
2450 NULL);
2451 } while (Status == STATUS_SUCCESS);
2452
2453 InterlockedDecrement((PLONG)&FileObject->Waiters);
2454 if (Status == STATUS_SUCCESS)
2455 {
2456 ObReferenceObject(FileObject);
2457 *LockFailed = FALSE;
2458 }
2459 else
2460 {
2461 if (!FileObject->Busy && FileObject->Waiters)
2462 {
2463 KeSetEvent(&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2464 }
2465 *LockFailed = TRUE;
2466 }
2467
2468 return Status;
2469 }
2470
2471 PVOID
2472 NTAPI
2473 IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject)
2474 {
2475 if (BooleanFlagOn(FileObject->Flags, FO_FILE_OBJECT_HAS_EXTENSION))
2476 {
2477 PFILE_OBJECT_EXTENSION FileObjectExtension;
2478
2479 FileObjectExtension = FileObject->FileObjectExtension;
2480 return FileObjectExtension->FilterContext;
2481 }
2482
2483 return NULL;
2484 }
2485
2486 NTSTATUS
2487 NTAPI
2488 IoChangeFileObjectFilterContext(IN PFILE_OBJECT FileObject,
2489 IN PVOID FilterContext,
2490 IN BOOLEAN Define)
2491 {
2492 ULONG_PTR Success;
2493 PFILE_OBJECT_EXTENSION FileObjectExtension;
2494
2495 if (!BooleanFlagOn(FileObject->Flags, FO_FILE_OBJECT_HAS_EXTENSION))
2496 {
2497 return STATUS_INVALID_PARAMETER;
2498 }
2499
2500 FileObjectExtension = FileObject->FileObjectExtension;
2501 if (Define)
2502 {
2503 /* If define, just set the new value if not value is set
2504 * Success will only contain old value. It is valid if it is NULL
2505 */
2506 Success = (ULONG_PTR)InterlockedCompareExchangePointer(&FileObjectExtension->FilterContext, FilterContext, NULL);
2507 }
2508 else
2509 {
2510 /* If not define, we want to reset filter context.
2511 * We will remove value (provided by the caller) and set NULL instead.
2512 * This will only success if caller provides correct previous value.
2513 * To catch whether it worked, we substract previous value to expect value:
2514 * If it matches (and thus, we reset), Success will contain 0
2515 * Otherwise, it will contain a non-zero value.
2516 */
2517 Success = (ULONG_PTR)InterlockedCompareExchangePointer(&FileObjectExtension->FilterContext, NULL, FilterContext) - (ULONG_PTR)FilterContext;
2518 }
2519
2520 /* If success isn't 0, it means we failed somewhere (set or unset) */
2521 if (Success != 0)
2522 {
2523 return STATUS_ALREADY_COMMITTED;
2524 }
2525
2526 return STATUS_SUCCESS;
2527 }
2528
2529 NTSTATUS
2530 NTAPI
2531 IopCreateFile(OUT PHANDLE FileHandle,
2532 IN ACCESS_MASK DesiredAccess,
2533 IN POBJECT_ATTRIBUTES ObjectAttributes,
2534 OUT PIO_STATUS_BLOCK IoStatusBlock,
2535 IN PLARGE_INTEGER AllocationSize OPTIONAL,
2536 IN ULONG FileAttributes,
2537 IN ULONG ShareAccess,
2538 IN ULONG Disposition,
2539 IN ULONG CreateOptions,
2540 IN PVOID EaBuffer OPTIONAL,
2541 IN ULONG EaLength,
2542 IN CREATE_FILE_TYPE CreateFileType,
2543 IN PVOID ExtraCreateParameters OPTIONAL,
2544 IN ULONG Options,
2545 IN ULONG Flags,
2546 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
2547 {
2548 KPROCESSOR_MODE AccessMode;
2549 HANDLE LocalHandle = 0;
2550 LARGE_INTEGER SafeAllocationSize;
2551 NTSTATUS Status = STATUS_SUCCESS;
2552 PNAMED_PIPE_CREATE_PARAMETERS NamedPipeCreateParameters;
2553 POPEN_PACKET OpenPacket;
2554 ULONG EaErrorOffset;
2555 PAGED_CODE();
2556
2557 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
2558
2559
2560 /* Check if we have no parameter checking to do */
2561 if (Options & IO_NO_PARAMETER_CHECKING)
2562 {
2563 /* Then force kernel-mode access to avoid checks */
2564 AccessMode = KernelMode;
2565 }
2566 else
2567 {
2568 /* Otherwise, use the actual mode */
2569 AccessMode = ExGetPreviousMode();
2570 }
2571
2572 /* Check if we need to do parameter checking */
2573 if ((AccessMode != KernelMode) || (Options & IO_CHECK_CREATE_PARAMETERS))
2574 {
2575 /* Validate parameters */
2576 if (FileAttributes & ~FILE_ATTRIBUTE_VALID_FLAGS)
2577 {
2578 DPRINT1("File Create 'FileAttributes' Parameter contains invalid flags!\n");
2579 return STATUS_INVALID_PARAMETER;
2580 }
2581
2582 if (ShareAccess & ~FILE_SHARE_VALID_FLAGS)
2583 {
2584 DPRINT1("File Create 'ShareAccess' Parameter contains invalid flags!\n");
2585 return STATUS_INVALID_PARAMETER;
2586 }
2587
2588 if (Disposition > FILE_MAXIMUM_DISPOSITION)
2589 {
2590 DPRINT1("File Create 'Disposition' Parameter is out of range!\n");
2591 return STATUS_INVALID_PARAMETER;
2592 }
2593
2594 if (CreateOptions & ~FILE_VALID_OPTION_FLAGS)
2595 {
2596 DPRINT1("File Create 'CreateOptions' parameter contains invalid flags!\n");
2597 return STATUS_INVALID_PARAMETER;
2598 }
2599
2600 if ((CreateOptions & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) &&
2601 (!(DesiredAccess & SYNCHRONIZE)))
2602 {
2603 DPRINT1("File Create 'CreateOptions' parameter FILE_SYNCHRONOUS_IO_* requested, but 'DesiredAccess' does not have SYNCHRONIZE!\n");
2604 return STATUS_INVALID_PARAMETER;
2605 }
2606
2607 if ((CreateOptions & FILE_DELETE_ON_CLOSE) && (!(DesiredAccess & DELETE)))
2608 {
2609 DPRINT1("File Create 'CreateOptions' parameter FILE_DELETE_ON_CLOSE requested, but 'DesiredAccess' does not have DELETE!\n");
2610 return STATUS_INVALID_PARAMETER;
2611 }
2612
2613 if ((CreateOptions & (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT)) ==
2614 (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT))
2615 {
2616 DPRINT1("File Create 'FileAttributes' parameter both FILE_SYNCHRONOUS_IO_NONALERT and FILE_SYNCHRONOUS_IO_ALERT specified!\n");
2617 return STATUS_INVALID_PARAMETER;
2618 }
2619
2620 if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
2621 (CreateOptions & ~(FILE_DIRECTORY_FILE |
2622 FILE_SYNCHRONOUS_IO_ALERT |
2623 FILE_SYNCHRONOUS_IO_NONALERT |
2624 FILE_WRITE_THROUGH |
2625 FILE_COMPLETE_IF_OPLOCKED |
2626 FILE_OPEN_FOR_BACKUP_INTENT |
2627 FILE_DELETE_ON_CLOSE |
2628 FILE_OPEN_FOR_FREE_SPACE_QUERY |
2629 FILE_OPEN_BY_FILE_ID |
2630 FILE_NO_COMPRESSION |
2631 FILE_OPEN_REPARSE_POINT)))
2632 {
2633 DPRINT1("File Create 'CreateOptions' Parameter has flags incompatible with FILE_DIRECTORY_FILE!\n");
2634 return STATUS_INVALID_PARAMETER;
2635 }
2636
2637 if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
2638 (Disposition != FILE_CREATE) && (Disposition != FILE_OPEN) && (Disposition != FILE_OPEN_IF))
2639 {
2640 DPRINT1("File Create 'CreateOptions' Parameter FILE_DIRECTORY_FILE requested, but 'Disposition' is not FILE_CREATE/FILE_OPEN/FILE_OPEN_IF!\n");
2641 return STATUS_INVALID_PARAMETER;
2642 }
2643
2644 if ((CreateOptions & FILE_COMPLETE_IF_OPLOCKED) && (CreateOptions & FILE_RESERVE_OPFILTER))
2645 {
2646 DPRINT1("File Create 'CreateOptions' Parameter both FILE_COMPLETE_IF_OPLOCKED and FILE_RESERVE_OPFILTER specified!\n");
2647 return STATUS_INVALID_PARAMETER;
2648 }
2649
2650 if ((CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) && (DesiredAccess & FILE_APPEND_DATA))
2651 {
2652 DPRINT1("File Create 'CreateOptions' parameter FILE_NO_INTERMEDIATE_BUFFERING requested, but 'DesiredAccess' FILE_APPEND_DATA requires it!\n");
2653 return STATUS_INVALID_PARAMETER;
2654 }
2655
2656 /* Now check if this is a named pipe */
2657 if (CreateFileType == CreateFileTypeNamedPipe)
2658 {
2659 /* Make sure we have extra parameters */
2660 if (!ExtraCreateParameters)
2661 {
2662 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2663 return STATUS_INVALID_PARAMETER;
2664 }
2665
2666 /* Get the parameters and validate them */
2667 NamedPipeCreateParameters = ExtraCreateParameters;
2668 if ((NamedPipeCreateParameters->NamedPipeType > FILE_PIPE_MESSAGE_TYPE) ||
2669 (NamedPipeCreateParameters->ReadMode > FILE_PIPE_MESSAGE_MODE) ||
2670 (NamedPipeCreateParameters->CompletionMode > FILE_PIPE_COMPLETE_OPERATION) ||
2671 (ShareAccess & FILE_SHARE_DELETE) ||
2672 ((Disposition < FILE_OPEN) || (Disposition > FILE_OPEN_IF)) ||
2673 (CreateOptions & ~FILE_VALID_PIPE_OPTION_FLAGS))
2674 {
2675 /* Invalid named pipe create */
2676 DPRINT1("Invalid named pipe create\n");
2677 return STATUS_INVALID_PARAMETER;
2678 }
2679 }
2680 else if (CreateFileType == CreateFileTypeMailslot)
2681 {
2682 /* Make sure we have extra parameters */
2683 if (!ExtraCreateParameters)
2684 {
2685 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2686 return STATUS_INVALID_PARAMETER;
2687 }
2688
2689 /* Get the parameters and validate them */
2690 if ((ShareAccess & FILE_SHARE_DELETE) ||
2691 !(ShareAccess & ~FILE_SHARE_WRITE) ||
2692 (Disposition != FILE_CREATE) ||
2693 (CreateOptions & ~FILE_VALID_MAILSLOT_OPTION_FLAGS))
2694 {
2695 /* Invalid mailslot create */
2696 DPRINT1("Invalid mailslot create\n");
2697 return STATUS_INVALID_PARAMETER;
2698 }
2699 }
2700 }
2701
2702 /* Allocate the open packet */
2703 OpenPacket = ExAllocatePoolWithTag(NonPagedPool, sizeof(*OpenPacket), 'pOoI');
2704 if (!OpenPacket) return STATUS_INSUFFICIENT_RESOURCES;
2705 RtlZeroMemory(OpenPacket, sizeof(*OpenPacket));
2706
2707 /* Check if the call came from user mode */
2708 if (AccessMode != KernelMode)
2709 {
2710 _SEH2_TRY
2711 {
2712 /* Probe the output parameters */
2713 ProbeForWriteHandle(FileHandle);
2714 ProbeForWriteIoStatusBlock(IoStatusBlock);
2715
2716 /* Probe the allocation size if one was passed in */
2717 if (AllocationSize)
2718 {
2719 SafeAllocationSize = ProbeForReadLargeInteger(AllocationSize);
2720 }
2721 else
2722 {
2723 SafeAllocationSize.QuadPart = 0;
2724 }
2725
2726 /* Make sure it's valid */
2727 if (SafeAllocationSize.QuadPart < 0)
2728 {
2729 RtlRaiseStatus(STATUS_INVALID_PARAMETER);
2730 }
2731
2732 /* Check if EA was passed in */
2733 if ((EaBuffer) && (EaLength))
2734 {
2735 /* Probe it */
2736 ProbeForRead(EaBuffer, EaLength, sizeof(ULONG));
2737
2738 /* And marshall it */
2739 OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
2740 EaLength,
2741 TAG_EA);
2742 OpenPacket->EaLength = EaLength;
2743 RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
2744
2745 /* Validate the buffer */
2746 Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
2747 EaLength,
2748 &EaErrorOffset);
2749 if (!NT_SUCCESS(Status))
2750 {
2751 /* Undo everything if it's invalid */
2752 DPRINT1("Invalid EA buffer\n");
2753 IoStatusBlock->Status = Status;
2754 IoStatusBlock->Information = EaErrorOffset;
2755 RtlRaiseStatus(Status);
2756 }
2757 }
2758 }
2759 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2760 {
2761 /* Return the exception code */
2762 if (OpenPacket->EaBuffer != NULL) ExFreePool(OpenPacket->EaBuffer);
2763 ExFreePool(OpenPacket);
2764 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2765 }
2766 _SEH2_END;
2767 }
2768 else
2769 {
2770 /* Check if this is a device attach */
2771 if (CreateOptions & IO_ATTACH_DEVICE_API)
2772 {
2773 /* Set the flag properly */
2774 Options |= IO_ATTACH_DEVICE;
2775 CreateOptions &= ~IO_ATTACH_DEVICE_API;
2776 }
2777
2778 /* Check if we have allocation size */
2779 if (AllocationSize)
2780 {
2781 /* Capture it */
2782 SafeAllocationSize = *AllocationSize;
2783 }
2784 else
2785 {
2786 /* Otherwise, no size */
2787 SafeAllocationSize.QuadPart = 0;
2788 }
2789
2790 /* Check if we have an EA packet */
2791 if ((EaBuffer) && (EaLength))
2792 {
2793 /* Allocate the kernel copy */
2794 OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
2795 EaLength,
2796 TAG_EA);
2797 if (!OpenPacket->EaBuffer)
2798 {
2799 ExFreePool(OpenPacket);
2800 DPRINT1("Failed to allocate open packet EA buffer\n");
2801 return STATUS_INSUFFICIENT_RESOURCES;
2802 }
2803
2804 /* Copy the data */
2805 OpenPacket->EaLength = EaLength;
2806 RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
2807
2808 /* Validate the buffer */
2809 Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
2810 EaLength,
2811 &EaErrorOffset);
2812 if (!NT_SUCCESS(Status))
2813 {
2814 /* Undo everything if it's invalid */
2815 DPRINT1("Invalid EA buffer\n");
2816 ExFreePool(OpenPacket->EaBuffer);
2817 IoStatusBlock->Status = Status;
2818 IoStatusBlock->Information = EaErrorOffset;
2819 ExFreePool(OpenPacket);
2820 return Status;
2821 }
2822 }
2823 }
2824
2825 /* Setup the Open Packet */
2826 OpenPacket->Type = IO_TYPE_OPEN_PACKET;
2827 OpenPacket->Size = sizeof(*OpenPacket);
2828 OpenPacket->AllocationSize = SafeAllocationSize;
2829 OpenPacket->CreateOptions = CreateOptions;
2830 OpenPacket->FileAttributes = (USHORT)FileAttributes;
2831 OpenPacket->ShareAccess = (USHORT)ShareAccess;
2832 OpenPacket->Options = Options;
2833 OpenPacket->Disposition = Disposition;
2834 OpenPacket->CreateFileType = CreateFileType;
2835 OpenPacket->ExtraCreateParameters = ExtraCreateParameters;
2836 OpenPacket->InternalFlags = Flags;
2837 OpenPacket->TopDeviceObjectHint = DeviceObject;
2838
2839 /* Update the operation count */
2840 IopUpdateOperationCount(IopOtherTransfer);
2841
2842 /*
2843 * Attempt opening the file. This will call the I/O Parse Routine for
2844 * the File Object (IopParseDevice) which will create the object and
2845 * send the IRP to its device object. Note that we have two statuses
2846 * to worry about: the Object Manager's status (in Status) and the I/O
2847 * status, which is in the Open Packet's Final Status, and determined
2848 * by the Parse Check member.
2849 */
2850 Status = ObOpenObjectByName(ObjectAttributes,
2851 NULL,
2852 AccessMode,
2853 NULL,
2854 DesiredAccess,
2855 OpenPacket,
2856 &LocalHandle);
2857
2858 /* Free the EA Buffer */
2859 if (OpenPacket->EaBuffer) ExFreePool(OpenPacket->EaBuffer);
2860
2861 /* Now check for Ob or Io failure */
2862 if (!(NT_SUCCESS(Status)) || (OpenPacket->ParseCheck == FALSE))
2863 {
2864 /* Check if Ob thinks well went well */
2865 if (NT_SUCCESS(Status))
2866 {
2867 /*
2868 * Tell it otherwise. Because we didn't use an ObjectType,
2869 * it incorrectly returned us a handle to God knows what.
2870 */
2871 ZwClose(LocalHandle);
2872 Status = STATUS_OBJECT_TYPE_MISMATCH;
2873 }
2874
2875 /* Now check the Io status */
2876 if (!NT_SUCCESS(OpenPacket->FinalStatus))
2877 {
2878 /* Use this status instead of Ob's */
2879 Status = OpenPacket->FinalStatus;
2880
2881 /* Check if it was only a warning */
2882 if (NT_WARNING(Status))
2883 {
2884 /* Protect write with SEH */
2885 _SEH2_TRY
2886 {
2887 /* In this case, we copy the I/O Status back */
2888 IoStatusBlock->Information = OpenPacket->Information;
2889 IoStatusBlock->Status = OpenPacket->FinalStatus;
2890 }
2891 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2892 {
2893 /* Get exception code */
2894 Status = _SEH2_GetExceptionCode();
2895 }
2896 _SEH2_END;
2897 }
2898 }
2899 else if ((OpenPacket->FileObject) && (OpenPacket->ParseCheck == FALSE))
2900 {
2901 /*
2902 * This can happen in the very bizarre case where the parse routine
2903 * actually executed more then once (due to a reparse) and ended
2904 * up failing after already having created the File Object.
2905 */
2906 if (OpenPacket->FileObject->FileName.Length)
2907 {
2908 /* It had a name, free it */
2909 ExFreePoolWithTag(OpenPacket->FileObject->FileName.Buffer, TAG_IO_NAME);
2910 }
2911
2912 /* Clear the device object to invalidate the FO, and dereference */
2913 OpenPacket->FileObject->DeviceObject = NULL;
2914 ObDereferenceObject(OpenPacket->FileObject);
2915 }
2916 }
2917 else
2918 {
2919 /* We reached success and have a valid file handle */
2920 OpenPacket->FileObject->Flags |= FO_HANDLE_CREATED;
2921 ASSERT(OpenPacket->FileObject->Type == IO_TYPE_FILE);
2922
2923 /* Enter SEH for write back */
2924 _SEH2_TRY
2925 {
2926 /* Write back the handle and I/O Status */
2927 *FileHandle = LocalHandle;
2928 IoStatusBlock->Information = OpenPacket->Information;
2929 IoStatusBlock->Status = OpenPacket->FinalStatus;
2930
2931 /* Get the Io status */
2932 Status = OpenPacket->FinalStatus;
2933 }
2934 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2935 {
2936 /* Get the exception status */
2937 Status = _SEH2_GetExceptionCode();
2938 }
2939 _SEH2_END;
2940 }
2941
2942 /* Check if we were 100% successful */
2943 if ((OpenPacket->ParseCheck != FALSE) && (OpenPacket->FileObject))
2944 {
2945 /* Dereference the File Object */
2946 ObDereferenceObject(OpenPacket->FileObject);
2947 }
2948
2949 /* Return status */
2950 ExFreePool(OpenPacket);
2951 return Status;
2952 }
2953
2954 /* FUNCTIONS *****************************************************************/
2955
2956 /*
2957 * @unimplemented
2958 */
2959 NTSTATUS
2960 NTAPI
2961 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
2962 IN ULONG Length,
2963 IN BOOLEAN SetOperation)
2964 {
2965 UNIMPLEMENTED;
2966 return STATUS_NOT_IMPLEMENTED;
2967 }
2968
2969 /*
2970 * @unimplemented
2971 */
2972 NTSTATUS
2973 NTAPI
2974 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
2975 IN ULONG QuotaLength,
2976 OUT PULONG ErrorOffset)
2977 {
2978 UNIMPLEMENTED;
2979 return STATUS_NOT_IMPLEMENTED;
2980 }
2981
2982 /*
2983 * @implemented
2984 */
2985 NTSTATUS
2986 NTAPI
2987 IoCreateFile(OUT PHANDLE FileHandle,
2988 IN ACCESS_MASK DesiredAccess,
2989 IN POBJECT_ATTRIBUTES ObjectAttributes,
2990 OUT PIO_STATUS_BLOCK IoStatusBlock,
2991 IN PLARGE_INTEGER AllocationSize OPTIONAL,
2992 IN ULONG FileAttributes,
2993 IN ULONG ShareAccess,
2994 IN ULONG Disposition,
2995 IN ULONG CreateOptions,
2996 IN PVOID EaBuffer OPTIONAL,
2997 IN ULONG EaLength,
2998 IN CREATE_FILE_TYPE CreateFileType,
2999 IN PVOID ExtraCreateParameters OPTIONAL,
3000 IN ULONG Options)
3001 {
3002 PAGED_CODE();
3003
3004 return IopCreateFile(FileHandle,
3005 DesiredAccess,
3006 ObjectAttributes,
3007 IoStatusBlock,
3008 AllocationSize,
3009 FileAttributes,
3010 ShareAccess,
3011 Disposition,
3012 CreateOptions,
3013 EaBuffer,
3014 EaLength,
3015 CreateFileType,
3016 ExtraCreateParameters,
3017 Options,
3018 0,
3019 NULL);
3020 }
3021
3022 /*
3023 * @unimplemented
3024 */
3025 NTSTATUS
3026 NTAPI
3027 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle,
3028 IN ACCESS_MASK DesiredAccess,
3029 IN POBJECT_ATTRIBUTES ObjectAttributes,
3030 OUT PIO_STATUS_BLOCK IoStatusBlock,
3031 IN PLARGE_INTEGER AllocationSize OPTIONAL,
3032 IN ULONG FileAttributes,
3033 IN ULONG ShareAccess,
3034 IN ULONG Disposition,
3035 IN ULONG CreateOptions,
3036 IN PVOID EaBuffer OPTIONAL,
3037 IN ULONG EaLength,
3038 IN CREATE_FILE_TYPE CreateFileType,
3039 IN PVOID ExtraCreateParameters OPTIONAL,
3040 IN ULONG Options,
3041 IN PVOID DeviceObject)
3042 {
3043 ULONG Flags = 0;
3044
3045 PAGED_CODE();
3046
3047 /* Check if we were passed a device to send the create request to*/
3048 if (DeviceObject)
3049 {
3050 /* We'll tag this request into a file object extension */
3051 Flags = (IOP_CREATE_FILE_OBJECT_EXTENSION | IOP_USE_TOP_LEVEL_DEVICE_HINT);
3052 }
3053
3054 return IopCreateFile(FileHandle,
3055 DesiredAccess,
3056 ObjectAttributes,
3057 IoStatusBlock,
3058 AllocationSize,
3059 FileAttributes,
3060 ShareAccess,
3061 Disposition,
3062 CreateOptions,
3063 EaBuffer,
3064 EaLength,
3065 CreateFileType,
3066 ExtraCreateParameters,
3067 Options | IO_NO_PARAMETER_CHECKING,
3068 Flags,
3069 DeviceObject);
3070 }
3071
3072 /*
3073 * @implemented
3074 */
3075 PFILE_OBJECT
3076 NTAPI
3077 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL,
3078 IN PDEVICE_OBJECT DeviceObject OPTIONAL,
3079 OUT PHANDLE FileObjectHandle OPTIONAL)
3080 {
3081 PFILE_OBJECT CreatedFileObject;
3082 NTSTATUS Status;
3083 HANDLE FileHandle;
3084 OBJECT_ATTRIBUTES ObjectAttributes;
3085 PAGED_CODE();
3086 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
3087
3088 /* Choose Device Object */
3089 if (FileObject) DeviceObject = FileObject->DeviceObject;
3090
3091 /* Reference the device object and initialize attributes */
3092 InterlockedIncrement(&DeviceObject->ReferenceCount);
3093 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
3094
3095 /* Create the File Object */
3096 Status = ObCreateObject(KernelMode,
3097 IoFileObjectType,
3098 &ObjectAttributes,
3099 KernelMode,
3100 NULL,
3101 sizeof(FILE_OBJECT),
3102 sizeof(FILE_OBJECT),
3103 0,
3104 (PVOID*)&CreatedFileObject);
3105 if (!NT_SUCCESS(Status))
3106 {
3107 /* Fail */
3108 IopDereferenceDeviceObject(DeviceObject, FALSE);
3109 ExRaiseStatus(Status);
3110 }
3111
3112 /* Set File Object Data */
3113 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
3114 CreatedFileObject->DeviceObject = DeviceObject;
3115 CreatedFileObject->Type = IO_TYPE_FILE;
3116 CreatedFileObject->Size = sizeof(FILE_OBJECT);
3117 CreatedFileObject->Flags = FO_STREAM_FILE;
3118
3119 /* Initialize the wait event */
3120 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
3121
3122 /* Insert it to create a handle for it */
3123 Status = ObInsertObject(CreatedFileObject,
3124 NULL,
3125 FILE_READ_DATA,
3126 1,
3127 (PVOID*)&CreatedFileObject,
3128 &FileHandle);
3129 if (!NT_SUCCESS(Status)) ExRaiseStatus(Status);
3130
3131 /* Set the handle created flag */
3132 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
3133 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
3134
3135 /* Check if we have a VPB */
3136 if (DeviceObject->Vpb)
3137 {
3138 /* Reference it */
3139 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
3140 }
3141
3142 /* Check if the caller wants the handle */
3143 if (FileObjectHandle)
3144 {
3145 /* Return it */
3146 *FileObjectHandle = FileHandle;
3147 ObDereferenceObject(CreatedFileObject);
3148 }
3149 else
3150 {
3151 /* Otherwise, close it */
3152 ObCloseHandle(FileHandle, KernelMode);
3153 }
3154
3155 /* Return the file object */
3156 return CreatedFileObject;
3157 }
3158
3159 /*
3160 * @implemented
3161 */
3162 PFILE_OBJECT
3163 NTAPI
3164 IoCreateStreamFileObject(IN PFILE_OBJECT FileObject,
3165 IN PDEVICE_OBJECT DeviceObject)
3166 {
3167 /* Call the newer function */
3168 return IoCreateStreamFileObjectEx(FileObject, DeviceObject, NULL);
3169 }
3170
3171 /*
3172 * @implemented
3173 */
3174 PFILE_OBJECT
3175 NTAPI
3176 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL,
3177 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
3178 {
3179 PFILE_OBJECT CreatedFileObject;
3180 NTSTATUS Status;
3181 OBJECT_ATTRIBUTES ObjectAttributes;
3182 PAGED_CODE();
3183 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
3184
3185 /* Choose Device Object */
3186 if (FileObject) DeviceObject = FileObject->DeviceObject;
3187
3188 /* Reference the device object and initialize attributes */
3189 InterlockedIncrement(&DeviceObject->ReferenceCount);
3190 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
3191
3192 /* Create the File Object */
3193 Status = ObCreateObject(KernelMode,
3194 IoFileObjectType,
3195 &ObjectAttributes,
3196 KernelMode,
3197 NULL,
3198 sizeof(FILE_OBJECT),
3199 sizeof(FILE_OBJECT),
3200 0,
3201 (PVOID*)&CreatedFileObject);
3202 if (!NT_SUCCESS(Status))
3203 {
3204 /* Fail */
3205 IopDereferenceDeviceObject(DeviceObject, FALSE);
3206 ExRaiseStatus(Status);
3207 }
3208
3209 /* Set File Object Data */
3210 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
3211 CreatedFileObject->DeviceObject = DeviceObject;
3212 CreatedFileObject->Type = IO_TYPE_FILE;
3213 CreatedFileObject->Size = sizeof(FILE_OBJECT);
3214 CreatedFileObject->Flags = FO_STREAM_FILE;
3215
3216 /* Initialize the wait event */
3217 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
3218
3219 /* Destroy create information */
3220 ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->
3221 ObjectCreateInfo);
3222 OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->ObjectCreateInfo = NULL;
3223
3224 /* Set the handle created flag */
3225 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
3226 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
3227
3228 /* Check if we have a VPB */
3229 if (DeviceObject->Vpb)
3230 {
3231 /* Reference it */
3232 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
3233 }
3234
3235 /* Return the file object */
3236 return CreatedFileObject;
3237 }
3238
3239 /*
3240 * @implemented
3241 */
3242 PGENERIC_MAPPING
3243 NTAPI
3244 IoGetFileObjectGenericMapping(VOID)
3245 {
3246 /* Return the mapping */
3247 return &IopFileMapping;
3248 }
3249
3250 /*
3251 * @implemented
3252 */
3253 BOOLEAN
3254 NTAPI
3255 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject)
3256 {
3257 /* Return the flag status */
3258 return FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
3259 }
3260
3261 /*
3262 * @implemented
3263 */
3264 BOOLEAN
3265 NTAPI
3266 IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
3267 IN ACCESS_MASK DesiredAccess,
3268 IN ULONG OpenOptions,
3269 OUT PIO_STATUS_BLOCK IoStatus,
3270 OUT PFILE_NETWORK_OPEN_INFORMATION Buffer)
3271 {
3272 NTSTATUS Status;
3273 DUMMY_FILE_OBJECT LocalFileObject;
3274 HANDLE Handle;
3275 OPEN_PACKET OpenPacket;
3276 PAGED_CODE();
3277 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
3278
3279 /* Setup the Open Packet */
3280 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
3281 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
3282 OpenPacket.Size = sizeof(OPEN_PACKET);
3283 OpenPacket.CreateOptions = OpenOptions | FILE_OPEN_REPARSE_POINT;
3284 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
3285 OpenPacket.Options = IO_FORCE_ACCESS_CHECK;
3286 OpenPacket.Disposition = FILE_OPEN;
3287 OpenPacket.NetworkInformation = Buffer;
3288 OpenPacket.QueryOnly = TRUE;
3289 OpenPacket.FullAttributes = TRUE;
3290 OpenPacket.LocalFileObject = &LocalFileObject;
3291
3292 /*
3293 * Attempt opening the file. This will call the I/O Parse Routine for
3294 * the File Object (IopParseDevice) which will use the dummy file obejct
3295 * send the IRP to its device object. Note that we have two statuses
3296 * to worry about: the Object Manager's status (in Status) and the I/O
3297 * status, which is in the Open Packet's Final Status, and determined
3298 * by the Parse Check member.
3299 */
3300 Status = ObOpenObjectByName(ObjectAttributes,
3301 NULL,
3302 KernelMode,
3303 NULL,
3304 DesiredAccess,
3305 &OpenPacket,
3306 &Handle);
3307 if (OpenPacket.ParseCheck == FALSE)
3308 {
3309 /* Parse failed */
3310 IoStatus->Status = Status;
3311 }
3312 else
3313 {
3314 /* Use the Io status */
3315 IoStatus->Status = OpenPacket.FinalStatus;
3316 IoStatus->Information = OpenPacket.Information;
3317 }
3318
3319 /* Return success */
3320 return TRUE;
3321 }
3322
3323 /*
3324 * @implemented
3325 */
3326 VOID
3327 NTAPI
3328 IoUpdateShareAccess(IN PFILE_OBJECT FileObject,
3329 OUT PSHARE_ACCESS ShareAccess)
3330 {
3331 PAGED_CODE();
3332
3333 /* Check if the file has an extension */
3334 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3335 {
3336 /* Check if caller specified to ignore access checks */
3337 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3338 {
3339 /* Don't update share access */
3340 return;
3341 }
3342 }
3343
3344 /* Otherwise, check if there's any access present */
3345 if ((FileObject->ReadAccess) ||
3346 (FileObject->WriteAccess) ||
3347 (FileObject->DeleteAccess))
3348 {
3349 /* Increase the open count */
3350 ShareAccess->OpenCount++;
3351
3352 /* Add new share access */
3353 ShareAccess->Readers += FileObject->ReadAccess;
3354 ShareAccess->Writers += FileObject->WriteAccess;
3355 ShareAccess->Deleters += FileObject->DeleteAccess;
3356 ShareAccess->SharedRead += FileObject->SharedRead;
3357 ShareAccess->SharedWrite += FileObject->SharedWrite;
3358 ShareAccess->SharedDelete += FileObject->SharedDelete;
3359 }
3360 }
3361
3362 /*
3363 * @implemented
3364 */
3365 NTSTATUS
3366 NTAPI
3367 IoCheckShareAccess(IN ACCESS_MASK DesiredAccess,
3368 IN ULONG DesiredShareAccess,
3369 IN PFILE_OBJECT FileObject,
3370 IN PSHARE_ACCESS ShareAccess,
3371 IN BOOLEAN Update)
3372 {
3373 BOOLEAN ReadAccess;
3374 BOOLEAN WriteAccess;
3375 BOOLEAN DeleteAccess;
3376 BOOLEAN SharedRead;
3377 BOOLEAN SharedWrite;
3378 BOOLEAN SharedDelete;
3379 PAGED_CODE();
3380
3381 /* Get access masks */
3382 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
3383 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
3384 DeleteAccess = (DesiredAccess & DELETE) != 0;
3385
3386 /* Set them in the file object */
3387 FileObject->ReadAccess = ReadAccess;
3388 FileObject->WriteAccess = WriteAccess;
3389 FileObject->DeleteAccess = DeleteAccess;
3390
3391 /* Check if the file has an extension */
3392 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3393 {
3394 /* Check if caller specified to ignore access checks */
3395 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3396 {
3397 /* Don't check share access */
3398 return STATUS_SUCCESS;
3399 }
3400 }
3401
3402 /* Check if we have any access */
3403 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
3404 {
3405 /* Get shared access masks */
3406 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
3407 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
3408 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
3409
3410 /* Set them */
3411 FileObject->SharedRead = SharedRead;
3412 FileObject->SharedWrite = SharedWrite;
3413 FileObject->SharedDelete = SharedDelete;
3414
3415 /* Check if the shared access is violated */
3416 if ((ReadAccess &&
3417 (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
3418 (WriteAccess &&
3419 (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
3420 (DeleteAccess &&
3421 (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
3422 ((ShareAccess->Readers != 0) && !SharedRead) ||
3423 ((ShareAccess->Writers != 0) && !SharedWrite) ||
3424 ((ShareAccess->Deleters != 0) && !SharedDelete))
3425 {
3426 /* Sharing violation, fail */
3427 return STATUS_SHARING_VIOLATION;
3428 }
3429
3430 /* It's not, check if caller wants us to update it */
3431 if (Update)
3432 {
3433 /* Increase open count */
3434 ShareAccess->OpenCount++;
3435
3436 /* Update shared access */
3437 ShareAccess->Readers += ReadAccess;
3438 ShareAccess->Writers += WriteAccess;
3439 ShareAccess->Deleters += DeleteAccess;
3440 ShareAccess->SharedRead += SharedRead;
3441 ShareAccess->SharedWrite += SharedWrite;
3442 ShareAccess->SharedDelete += SharedDelete;
3443 }
3444 }
3445
3446 /* Validation successful */
3447 return STATUS_SUCCESS;
3448 }
3449
3450 /*
3451 * @implemented
3452 */
3453 VOID
3454 NTAPI
3455 IoRemoveShareAccess(IN PFILE_OBJECT FileObject,
3456 IN PSHARE_ACCESS ShareAccess)
3457 {
3458 PAGED_CODE();
3459
3460 /* Check if the file has an extension */
3461 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3462 {
3463