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
IopCheckBackupRestorePrivilege(IN PACCESS_STATE AccessState,IN OUT PULONG CreateOptions,IN KPROCESSOR_MODE PreviousMode,IN ULONG Disposition)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
IopCheckDeviceAndDriver(IN POPEN_PACKET OpenPacket,IN PDEVICE_OBJECT DeviceObject)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
IopDoNameTransmogrify(IN PIRP Irp,IN PFILE_OBJECT FileObject,IN PREPARSE_DATA_BUFFER DataBuffer)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 memory 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 the reserved data */
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 the 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 /*
257 * Don't use TAG_IO_NAME since the FileObject's FileName
258 * may have been re-allocated using a different tag
259 * by a filesystem.
260 */
261 ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
262 }
263
264 FileObject->FileName.Buffer = NewBuffer;
265 FileObject->FileName.MaximumLength = RequiredLength;
266 FileObject->FileName.Buffer[RequiredLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
267 }
268 }
269
270 /* We don't need them anymore - it was allocated by the driver */
271 ExFreePool(DataBuffer);
272 }
273
274 NTSTATUS
IopCheckTopDeviceHint(IN OUT PDEVICE_OBJECT * DeviceObject,IN POPEN_PACKET OpenPacket,BOOLEAN DirectOpen)275 IopCheckTopDeviceHint(IN OUT PDEVICE_OBJECT * DeviceObject,
276 IN POPEN_PACKET OpenPacket,
277 BOOLEAN DirectOpen)
278 {
279 PDEVICE_OBJECT LocalDevice;
280 DEVICE_TYPE DeviceType;
281
282 LocalDevice = *DeviceObject;
283
284 /* Direct open is not allowed */
285 if (DirectOpen)
286 {
287 return STATUS_INVALID_PARAMETER;
288 }
289
290 /* Validate we have a file system device */
291 DeviceType = LocalDevice->DeviceType;
292 if (DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM &&
293 DeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM &&
294 DeviceType != FILE_DEVICE_TAPE_FILE_SYSTEM &&
295 DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM &&
296 DeviceType != FILE_DEVICE_DFS_FILE_SYSTEM)
297 {
298 return STATUS_INVALID_PARAMETER;
299 }
300
301 /* Verify the hint and if it's OK, return it */
302 if (IopVerifyDeviceObjectOnStack(LocalDevice, OpenPacket->TopDeviceObjectHint))
303 {
304 *DeviceObject = OpenPacket->TopDeviceObjectHint;
305 return STATUS_SUCCESS;
306 }
307
308 /* Failure case here */
309 /* If we thought was had come through a mount point,
310 * actually update we didn't and return the error
311 */
312 if (OpenPacket->TraversedMountPoint)
313 {
314 OpenPacket->TraversedMountPoint = FALSE;
315 return STATUS_MOUNT_POINT_NOT_RESOLVED;
316 }
317
318 /* Otherwise, just return the fact the hint is invalid */
319 return STATUS_INVALID_DEVICE_OBJECT_PARAMETER;
320 }
321
322 NTSTATUS
323 NTAPI
IopParseDevice(IN PVOID ParseObject,IN PVOID ObjectType,IN OUT PACCESS_STATE AccessState,IN KPROCESSOR_MODE AccessMode,IN ULONG Attributes,IN OUT PUNICODE_STRING CompleteName,IN OUT PUNICODE_STRING RemainingName,IN OUT PVOID Context,IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,OUT PVOID * Object)324 IopParseDevice(IN PVOID ParseObject,
325 IN PVOID ObjectType,
326 IN OUT PACCESS_STATE AccessState,
327 IN KPROCESSOR_MODE AccessMode,
328 IN ULONG Attributes,
329 IN OUT PUNICODE_STRING CompleteName,
330 IN OUT PUNICODE_STRING RemainingName,
331 IN OUT PVOID Context,
332 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
333 OUT PVOID *Object)
334 {
335 POPEN_PACKET OpenPacket = (POPEN_PACKET)Context;
336 PDEVICE_OBJECT OriginalDeviceObject = (PDEVICE_OBJECT)ParseObject;
337 PDEVICE_OBJECT DeviceObject, OwnerDevice;
338 NTSTATUS Status;
339 PFILE_OBJECT FileObject;
340 PVPB Vpb = NULL;
341 PIRP Irp;
342 PIO_STACK_LOCATION StackLoc;
343 IO_SECURITY_CONTEXT SecurityContext;
344 IO_STATUS_BLOCK IoStatusBlock;
345 BOOLEAN DirectOpen = FALSE, OpenCancelled, UseDummyFile;
346 OBJECT_ATTRIBUTES ObjectAttributes;
347 KIRQL OldIrql;
348 PDUMMY_FILE_OBJECT LocalFileObject;
349 PFILE_BASIC_INFORMATION FileBasicInfo;
350 ULONG ReturnLength;
351 KPROCESSOR_MODE CheckMode;
352 BOOLEAN VolumeOpen = FALSE;
353 ACCESS_MASK DesiredAccess, GrantedAccess;
354 BOOLEAN AccessGranted, LockHeld = FALSE;
355 PPRIVILEGE_SET Privileges = NULL;
356 UNICODE_STRING FileString;
357 USHORT Attempt;
358 IOTRACE(IO_FILE_DEBUG, "ParseObject: %p. RemainingName: %wZ\n",
359 ParseObject, RemainingName);
360
361 for (Attempt = 0; Attempt < IOP_MAX_REPARSE_TRAVERSAL; ++Attempt)
362 {
363 /* Assume failure */
364 *Object = NULL;
365
366 /* Validate the open packet */
367 if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
368
369 /* Valide reparse point in case we traversed a mountpoint */
370 if (OpenPacket->TraversedMountPoint)
371 {
372 /* This is a reparse point we understand */
373 ASSERT(OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT);
374
375 /* Make sure we're dealing with correct DO */
376 if (OriginalDeviceObject->DeviceType != FILE_DEVICE_DISK &&
377 OriginalDeviceObject->DeviceType != FILE_DEVICE_CD_ROM &&
378 OriginalDeviceObject->DeviceType != FILE_DEVICE_VIRTUAL_DISK &&
379 OriginalDeviceObject->DeviceType != FILE_DEVICE_TAPE)
380 {
381 OpenPacket->FinalStatus = STATUS_IO_REPARSE_DATA_INVALID;
382 return STATUS_IO_REPARSE_DATA_INVALID;
383 }
384 }
385
386 /* Check if we have a related file object */
387 if (OpenPacket->RelatedFileObject)
388 {
389 /* Use the related file object's device object */
390 OriginalDeviceObject = OpenPacket->RelatedFileObject->DeviceObject;
391 }
392
393 /* Validate device status */
394 Status = IopCheckDeviceAndDriver(OpenPacket, OriginalDeviceObject);
395 if (!NT_SUCCESS(Status))
396 {
397 /* We failed, return status */
398 OpenPacket->FinalStatus = Status;
399 return Status;
400 }
401
402 /* Map the generic mask and set the new mapping in the access state */
403 RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
404 &IoFileObjectType->TypeInfo.GenericMapping);
405 RtlMapGenericMask(&AccessState->OriginalDesiredAccess,
406 &IoFileObjectType->TypeInfo.GenericMapping);
407 SeSetAccessStateGenericMapping(AccessState,
408 &IoFileObjectType->TypeInfo.GenericMapping);
409 DesiredAccess = AccessState->RemainingDesiredAccess;
410
411 /* Check what kind of access checks to do */
412 if ((AccessMode != KernelMode) ||
413 (OpenPacket->Options & IO_FORCE_ACCESS_CHECK))
414 {
415 /* Call is from user-mode or kernel is forcing checks */
416 CheckMode = UserMode;
417 }
418 else
419 {
420 /* Call is from the kernel */
421 CheckMode = KernelMode;
422 }
423
424 /* Check privilege for backup or restore operation */
425 IopCheckBackupRestorePrivilege(AccessState,
426 &OpenPacket->CreateOptions,
427 CheckMode,
428 OpenPacket->Disposition);
429
430 /* Check if we are re-parsing */
431 if (((OpenPacket->Override) && !(RemainingName->Length)) ||
432 (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED))
433 {
434 /* Get granted access from the last call */
435 DesiredAccess |= AccessState->PreviouslyGrantedAccess;
436 }
437
438 /* Check if this is a volume open */
439 if ((OpenPacket->RelatedFileObject) &&
440 (OpenPacket->RelatedFileObject->Flags & FO_VOLUME_OPEN) &&
441 !(RemainingName->Length))
442 {
443 /* It is */
444 VolumeOpen = TRUE;
445 }
446
447 /* Now check if we need access checks */
448 if (((AccessMode != KernelMode) ||
449 (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) &&
450 (!(OpenPacket->RelatedFileObject) || (VolumeOpen)) &&
451 !(OpenPacket->Override))
452 {
453 KeEnterCriticalRegion();
454 ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
455
456 /* Check if a device object is being parsed */
457 if (!RemainingName->Length)
458 {
459 /* Lock the subject context */
460 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
461 LockHeld = TRUE;
462
463 /* Do access check */
464 AccessGranted = SeAccessCheck(OriginalDeviceObject->
465 SecurityDescriptor,
466 &AccessState->SubjectSecurityContext,
467 LockHeld,
468 DesiredAccess,
469 0,
470 &Privileges,
471 &IoFileObjectType->
472 TypeInfo.GenericMapping,
473 UserMode,
474 &GrantedAccess,
475 &Status);
476 if (Privileges)
477 {
478 /* Append and free the privileges */
479 SeAppendPrivileges(AccessState, Privileges);
480 SeFreePrivileges(Privileges);
481 }
482
483 /* Check if we got access */
484 if (AccessGranted)
485 {
486 /* Update access state */
487 AccessState->PreviouslyGrantedAccess |= GrantedAccess;
488 AccessState->RemainingDesiredAccess &= ~(GrantedAccess |
489 MAXIMUM_ALLOWED);
490 OpenPacket->Override= TRUE;
491 }
492
493 FileString.Length = 8;
494 FileString.MaximumLength = 8;
495 FileString.Buffer = L"File";
496
497 /* Do Audit/Alarm for open operation */
498 SeOpenObjectAuditAlarm(&FileString,
499 OriginalDeviceObject,
500 CompleteName,
501 OriginalDeviceObject->SecurityDescriptor,
502 AccessState,
503 FALSE,
504 AccessGranted,
505 UserMode,
506 &AccessState->GenerateOnClose);
507 }
508 else
509 {
510 /* Check if we need to do traverse validation */
511 if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ||
512 ((OriginalDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
513 (OriginalDeviceObject->DeviceType == FILE_DEVICE_CD_ROM)))
514 {
515 /* Check if this is a restricted token */
516 if (!(AccessState->Flags & TOKEN_IS_RESTRICTED))
517 {
518 /* Do the FAST traverse check */
519 AccessGranted = SeFastTraverseCheck(OriginalDeviceObject->SecurityDescriptor,
520 AccessState,
521 FILE_TRAVERSE,
522 UserMode);
523 }
524 else
525 {
526 /* Fail */
527 AccessGranted = FALSE;
528 }
529
530 /* Check if we failed to get access */
531 if (!AccessGranted)
532 {
533 /* Lock the subject context */
534 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
535 LockHeld = TRUE;
536
537 /* Do access check */
538 AccessGranted = SeAccessCheck(OriginalDeviceObject->
539 SecurityDescriptor,
540 &AccessState->SubjectSecurityContext,
541 LockHeld,
542 FILE_TRAVERSE,
543 0,
544 &Privileges,
545 &IoFileObjectType->
546 TypeInfo.GenericMapping,
547 UserMode,
548 &GrantedAccess,
549 &Status);
550 if (Privileges)
551 {
552 /* Append and free the privileges */
553 SeAppendPrivileges(AccessState, Privileges);
554 SeFreePrivileges(Privileges);
555 }
556 }
557
558 /* FIXME: Do Audit/Alarm for traverse check */
559 }
560 else
561 {
562 /* Access automatically granted */
563 AccessGranted = TRUE;
564 }
565 }
566
567 ExReleaseResourceLite(&IopSecurityResource);
568 KeLeaveCriticalRegion();
569
570 /* Check if we hold the lock */
571 if (LockHeld)
572 {
573 /* Release it */
574 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
575 }
576
577 /* Check if access failed */
578 if (!AccessGranted)
579 {
580 /* Dereference the device and fail */
581 DPRINT1("Traverse access failed!\n");
582 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
583 return STATUS_ACCESS_DENIED;
584 }
585 }
586
587 /* Check if we can simply use a dummy file */
588 UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
589
590 /* Check if this is a direct open */
591 if (!(RemainingName->Length) &&
592 !(OpenPacket->RelatedFileObject) &&
593 ((DesiredAccess & ~(SYNCHRONIZE |
594 FILE_READ_ATTRIBUTES |
595 READ_CONTROL |
596 ACCESS_SYSTEM_SECURITY |
597 WRITE_OWNER |
598 WRITE_DAC)) == 0) &&
599 !(UseDummyFile))
600 {
601 /* Remember this for later */
602 DirectOpen = TRUE;
603 }
604
605 /* Check if we have a related FO that wasn't a direct open */
606 if ((OpenPacket->RelatedFileObject) &&
607 !(OpenPacket->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN))
608 {
609 /* The device object is the one we were given */
610 DeviceObject = ParseObject;
611
612 /* Check if the related FO had a VPB */
613 if (OpenPacket->RelatedFileObject->Vpb)
614 {
615 /* Yes, remember it */
616 Vpb = OpenPacket->RelatedFileObject->Vpb;
617
618 /* Reference it */
619 InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
620
621 /* Check if we were given a specific top level device to use */
622 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
623 {
624 DeviceObject = Vpb->DeviceObject;
625 }
626 }
627 }
628 else
629 {
630 /* Check if it has a VPB */
631 if ((OriginalDeviceObject->Vpb) && !(DirectOpen))
632 {
633 /* Check if the VPB is mounted, and mount it */
634 Vpb = IopCheckVpbMounted(OpenPacket,
635 OriginalDeviceObject,
636 RemainingName,
637 &Status);
638 if (!Vpb) return Status;
639
640 /* Get the VPB's device object */
641 DeviceObject = Vpb->DeviceObject;
642 }
643 else
644 {
645 /* The device object is the one we were given */
646 DeviceObject = OriginalDeviceObject;
647 }
648
649 /* If we weren't given a specific top level device, look for an attached device */
650 if (!(OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT) &&
651 DeviceObject->AttachedDevice)
652 {
653 /* Get the attached device */
654 DeviceObject = IoGetAttachedDevice(DeviceObject);
655 }
656 }
657
658 /* If we have a top level device hint, verify it */
659 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
660 {
661 Status = IopCheckTopDeviceHint(&DeviceObject, OpenPacket, DirectOpen);
662 if (!NT_SUCCESS(Status))
663 {
664 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
665 if (Vpb) IopDereferenceVpbAndFree(Vpb);
666 return Status;
667 }
668 }
669
670 /* If we traversed a mount point, reset the information */
671 if (OpenPacket->TraversedMountPoint)
672 {
673 OpenPacket->TraversedMountPoint = FALSE;
674 }
675
676 /* Check if this is a secure FSD */
677 if ((DeviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) &&
678 ((OpenPacket->RelatedFileObject) || (RemainingName->Length)) &&
679 (!VolumeOpen))
680 {
681 Privileges = NULL;
682 GrantedAccess = 0;
683
684 KeEnterCriticalRegion();
685 ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
686
687 /* Lock the subject context */
688 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
689
690 /* Do access check */
691 AccessGranted = SeAccessCheck(OriginalDeviceObject->SecurityDescriptor,
692 &AccessState->SubjectSecurityContext,
693 TRUE,
694 DesiredAccess,
695 0,
696 &Privileges,
697 &IoFileObjectType->TypeInfo.GenericMapping,
698 UserMode,
699 &GrantedAccess,
700 &Status);
701 if (Privileges != NULL)
702 {
703 /* Append and free the privileges */
704 SeAppendPrivileges(AccessState, Privileges);
705 SeFreePrivileges(Privileges);
706 }
707
708 /* Check if we got access */
709 if (GrantedAccess)
710 {
711 AccessState->PreviouslyGrantedAccess |= GrantedAccess;
712 AccessState->RemainingDesiredAccess &= ~(GrantedAccess | MAXIMUM_ALLOWED);
713 }
714
715 FileString.Length = 8;
716 FileString.MaximumLength = 8;
717 FileString.Buffer = L"File";
718
719 /* Do Audit/Alarm for open operation
720 * NOTA: we audit target device object
721 */
722 SeOpenObjectAuditAlarm(&FileString,
723 DeviceObject,
724 CompleteName,
725 OriginalDeviceObject->SecurityDescriptor,
726 AccessState,
727 FALSE,
728 AccessGranted,
729 UserMode,
730 &AccessState->GenerateOnClose);
731
732 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
733
734 ExReleaseResourceLite(&IopSecurityResource);
735 KeLeaveCriticalRegion();
736
737 /* Check if access failed */
738 if (!AccessGranted)
739 {
740 /* Dereference the device and fail */
741 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
742 if (Vpb) IopDereferenceVpbAndFree(Vpb);
743 return STATUS_ACCESS_DENIED;
744 }
745 }
746
747 /* Allocate the IRP */
748 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
749 if (!Irp)
750 {
751 /* Dereference the device and VPB, then fail */
752 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
753 if (Vpb) IopDereferenceVpbAndFree(Vpb);
754 return STATUS_INSUFFICIENT_RESOURCES;
755 }
756
757 /* Now set the IRP data */
758 Irp->RequestorMode = AccessMode;
759 Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION;
760 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
761 Irp->UserIosb = &IoStatusBlock;
762 Irp->MdlAddress = NULL;
763 Irp->PendingReturned = FALSE;
764 Irp->UserEvent = NULL;
765 Irp->Cancel = FALSE;
766 Irp->CancelRoutine = NULL;
767 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
768
769 /* Setup the security context */
770 SecurityContext.SecurityQos = SecurityQos;
771 SecurityContext.AccessState = AccessState;
772 SecurityContext.DesiredAccess = AccessState->RemainingDesiredAccess;
773 SecurityContext.FullCreateOptions = OpenPacket->CreateOptions;
774
775 /* Get the I/O Stack location */
776 StackLoc = IoGetNextIrpStackLocation(Irp);
777 StackLoc->Control = 0;
778
779 /* Check what kind of file this is */
780 switch (OpenPacket->CreateFileType)
781 {
782 /* Normal file */
783 case CreateFileTypeNone:
784
785 /* Set the major function and EA Length */
786 StackLoc->MajorFunction = IRP_MJ_CREATE;
787 StackLoc->Parameters.Create.EaLength = OpenPacket->EaLength;
788
789 /* Set the flags */
790 StackLoc->Flags = (UCHAR)OpenPacket->Options;
791 StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ? SL_CASE_SENSITIVE: 0;
792 break;
793
794 /* Named pipe */
795 case CreateFileTypeNamedPipe:
796
797 /* Set the named pipe MJ and set the parameters */
798 StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
799 StackLoc->Parameters.CreatePipe.Parameters = OpenPacket->ExtraCreateParameters;
800 break;
801
802 /* Mailslot */
803 case CreateFileTypeMailslot:
804
805 /* Set the mailslot MJ and set the parameters */
806 StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
807 StackLoc->Parameters.CreateMailslot.Parameters = OpenPacket->ExtraCreateParameters;
808 break;
809 }
810
811 /* Set the common data */
812 Irp->Overlay.AllocationSize = OpenPacket->AllocationSize;
813 Irp->AssociatedIrp.SystemBuffer = OpenPacket->EaBuffer;
814 StackLoc->Parameters.Create.Options = (OpenPacket->Disposition << 24) |
815 (OpenPacket->CreateOptions &
816 0xFFFFFF);
817 StackLoc->Parameters.Create.FileAttributes = OpenPacket->FileAttributes;
818 StackLoc->Parameters.Create.ShareAccess = OpenPacket->ShareAccess;
819 StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
820
821 /* Check if we really need to create an object */
822 if (!UseDummyFile)
823 {
824 ULONG ObjectSize = sizeof(FILE_OBJECT);
825
826 /* Tag on space for a file object extension */
827 if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
828 ObjectSize += sizeof(FILE_OBJECT_EXTENSION);
829
830 /* Create the actual file object */
831 InitializeObjectAttributes(&ObjectAttributes,
832 NULL,
833 Attributes,
834 NULL,
835 NULL);
836 Status = ObCreateObject(KernelMode,
837 IoFileObjectType,
838 &ObjectAttributes,
839 AccessMode,
840 NULL,
841 ObjectSize,
842 0,
843 0,
844 (PVOID*)&FileObject);
845 if (!NT_SUCCESS(Status))
846 {
847 /* Create failed, free the IRP */
848 IoFreeIrp(Irp);
849
850 /* Dereference the device and VPB */
851 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
852 if (Vpb) IopDereferenceVpbAndFree(Vpb);
853
854 /* We failed, return status */
855 OpenPacket->FinalStatus = Status;
856 return Status;
857 }
858
859 /* Clear the file object */
860 RtlZeroMemory(FileObject, ObjectSize);
861
862 /* Check if this is Synch I/O */
863 if (OpenPacket->CreateOptions &
864 (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
865 {
866 /* Set the synch flag */
867 FileObject->Flags |= FO_SYNCHRONOUS_IO;
868
869 /* Check if it's also alertable */
870 if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
871 {
872 /* It is, set the alertable flag */
873 FileObject->Flags |= FO_ALERTABLE_IO;
874 }
875 }
876
877 /* Check if this is synch I/O */
878 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
879 {
880 /* Initialize the event */
881 KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE);
882 }
883
884 /* Check if the caller requested no intermediate buffering */
885 if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
886 {
887 /* Set the correct flag for the FSD to read */
888 FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
889 }
890
891 /* Check if the caller requested write through support */
892 if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
893 {
894 /* Set the correct flag for the FSD to read */
895 FileObject->Flags |= FO_WRITE_THROUGH;
896 }
897
898 /* Check if the caller says the file will be only read sequentially */
899 if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
900 {
901 /* Set the correct flag for the FSD to read */
902 FileObject->Flags |= FO_SEQUENTIAL_ONLY;
903 }
904
905 /* Check if the caller believes the file will be only read randomly */
906 if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
907 {
908 /* Set the correct flag for the FSD to read */
909 FileObject->Flags |= FO_RANDOM_ACCESS;
910 }
911
912 /* Check if we were asked to setup a file object extension */
913 if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
914 {
915 PFILE_OBJECT_EXTENSION FileObjectExtension;
916
917 /* Make sure the file object knows it has an extension */
918 FileObject->Flags |= FO_FILE_OBJECT_HAS_EXTENSION;
919
920 /* Initialize file object extension */
921 FileObjectExtension = (PFILE_OBJECT_EXTENSION)(FileObject + 1);
922 FileObject->FileObjectExtension = FileObjectExtension;
923
924 /* Add the top level device which we'll send the request to */
925 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
926 {
927 FileObjectExtension->TopDeviceObjectHint = DeviceObject;
928 }
929 }
930 }
931 else
932 {
933 /* Use the dummy object instead */
934 LocalFileObject = OpenPacket->LocalFileObject;
935 RtlZeroMemory(LocalFileObject, sizeof(DUMMY_FILE_OBJECT));
936
937 /* Set it up */
938 FileObject = (PFILE_OBJECT)&LocalFileObject->ObjectHeader.Body;
939 LocalFileObject->ObjectHeader.Type = IoFileObjectType;
940 LocalFileObject->ObjectHeader.PointerCount = 1;
941 }
942
943 /* Setup the file header */
944 FileObject->Type = IO_TYPE_FILE;
945 FileObject->Size = sizeof(FILE_OBJECT);
946 FileObject->RelatedFileObject = OpenPacket->RelatedFileObject;
947 FileObject->DeviceObject = OriginalDeviceObject;
948
949 /* Check if this is a direct device open */
950 if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
951
952 /* Check if the caller wants case sensitivity */
953 if (!(Attributes & OBJ_CASE_INSENSITIVE))
954 {
955 /* Tell the driver about it */
956 FileObject->Flags |= FO_OPENED_CASE_SENSITIVE;
957 }
958
959 /* Now set the file object */
960 Irp->Tail.Overlay.OriginalFileObject = FileObject;
961 StackLoc->FileObject = FileObject;
962
963 /* Check if the file object has a name */
964 if (RemainingName->Length)
965 {
966 /* Setup the unicode string */
967 FileObject->FileName.MaximumLength = RemainingName->Length + sizeof(WCHAR);
968 FileObject->FileName.Buffer = ExAllocatePoolWithTag(PagedPool,
969 FileObject->FileName.MaximumLength,
970 TAG_IO_NAME);
971 if (!FileObject->FileName.Buffer)
972 {
973 /* Failed to allocate the name, free the IRP */
974 IoFreeIrp(Irp);
975
976 /* Dereference the device object and VPB */
977 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
978 if (Vpb) IopDereferenceVpbAndFree(Vpb);
979
980 /* Clear the FO and dereference it */
981 FileObject->DeviceObject = NULL;
982 if (!UseDummyFile) ObDereferenceObject(FileObject);
983
984 /* Fail */
985 return STATUS_INSUFFICIENT_RESOURCES;
986 }
987 }
988
989 /* Copy the name */
990 RtlCopyUnicodeString(&FileObject->FileName, RemainingName);
991
992 /* Initialize the File Object event and set the FO */
993 KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
994 OpenPacket->FileObject = FileObject;
995
996 /* Queue the IRP and call the driver */
997 IopQueueIrpToThread(Irp);
998 Status = IoCallDriver(DeviceObject, Irp);
999 if (Status == STATUS_PENDING)
1000 {
1001 /* Wait for the driver to complete the create */
1002 KeWaitForSingleObject(&FileObject->Event,
1003 Executive,
1004 KernelMode,
1005 FALSE,
1006 NULL);
1007
1008 /* Get the new status */
1009 Status = IoStatusBlock.Status;
1010 }
1011 else
1012 {
1013 /* We'll have to complete it ourselves */
1014 ASSERT(!Irp->PendingReturned);
1015 ASSERT(!Irp->MdlAddress);
1016
1017 /* Handle name change if required */
1018 if (Status == STATUS_REPARSE)
1019 {
1020 /* Check this is a mount point */
1021 if (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)
1022 {
1023 PREPARSE_DATA_BUFFER ReparseData;
1024
1025 /* Reparse point attributes were passed by the driver in the auxiliary buffer */
1026 ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
1027 ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
1028
1029 ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
1030 ASSERT(ReparseData->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1031 ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1032
1033 IopDoNameTransmogrify(Irp, FileObject, ReparseData);
1034 }
1035 }
1036
1037 /* Completion happens at APC_LEVEL */
1038 KeRaiseIrql(APC_LEVEL, &OldIrql);
1039
1040 /* Get the new I/O Status block ourselves */
1041 IoStatusBlock = Irp->IoStatus;
1042 Status = IoStatusBlock.Status;
1043
1044 /* Manually signal the even, we can't have any waiters */
1045 FileObject->Event.Header.SignalState = 1;
1046
1047 /* Now that we've signaled the events, de-associate the IRP */
1048 IopUnQueueIrpFromThread(Irp);
1049
1050 /* Check if the IRP had an input buffer */
1051 if ((Irp->Flags & IRP_BUFFERED_IO) &&
1052 (Irp->Flags & IRP_DEALLOCATE_BUFFER))
1053 {
1054 /* Free it. A driver might've tacked one on */
1055 ExFreePool(Irp->AssociatedIrp.SystemBuffer);
1056 }
1057
1058 /* Free the IRP and bring the IRQL back down */
1059 IoFreeIrp(Irp);
1060 KeLowerIrql(OldIrql);
1061 }
1062
1063 /* Copy the I/O Status */
1064 OpenPacket->Information = IoStatusBlock.Information;
1065
1066 /* The driver failed to create the file */
1067 if (!NT_SUCCESS(Status))
1068 {
1069 /* Check if we have a name and if so, free it */
1070 if (FileObject->FileName.Length)
1071 {
1072 /*
1073 * Don't use TAG_IO_NAME since the FileObject's FileName
1074 * may have been re-allocated using a different tag
1075 * by a filesystem.
1076 */
1077 ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
1078 FileObject->FileName.Buffer = NULL;
1079 FileObject->FileName.Length = 0;
1080 }
1081
1082 /* Clear its device object */
1083 FileObject->DeviceObject = NULL;
1084
1085 /* Save this now because the FO might go away */
1086 OpenCancelled = FileObject->Flags & FO_FILE_OPEN_CANCELLED ?
1087 TRUE : FALSE;
1088
1089 /* Clear the file object in the open packet */
1090 OpenPacket->FileObject = NULL;
1091
1092 /* Dereference the file object */
1093 if (!UseDummyFile) ObDereferenceObject(FileObject);
1094
1095 /* Dereference the device object */
1096 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
1097
1098 /* Unless the driver cancelled the open, dereference the VPB */
1099 if (!(OpenCancelled) && (Vpb)) IopDereferenceVpbAndFree(Vpb);
1100
1101 /* Set the status and return */
1102 OpenPacket->FinalStatus = Status;
1103 return Status;
1104 }
1105 else if (Status == STATUS_REPARSE)
1106 {
1107 if (OpenPacket->Information == IO_REPARSE ||
1108 OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1109 {
1110 /* Update CompleteName with reparse info which got updated in IopDoNameTransmogrify() */
1111 if (CompleteName->MaximumLength < FileObject->FileName.Length)
1112 {
1113 PWSTR NewCompleteName;
1114
1115 /* Allocate a new buffer for the string */
1116 NewCompleteName = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.Length, TAG_IO_NAME);
1117 if (NewCompleteName == NULL)
1118 {
1119 OpenPacket->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
1120 return STATUS_INSUFFICIENT_RESOURCES;
1121 }
1122
1123 /* Release the old one */
1124 if (CompleteName->Buffer != NULL)
1125 {
1126 /*
1127 * Don't use TAG_IO_NAME since the FileObject's FileName
1128 * may have been re-allocated using a different tag
1129 * by a filesystem.
1130 */
1131 ExFreePoolWithTag(CompleteName->Buffer, 0);
1132 }
1133
1134 /* And setup the new one */
1135 CompleteName->Buffer = NewCompleteName;
1136 CompleteName->MaximumLength = FileObject->FileName.Length;
1137 }
1138
1139 /* Copy our new complete name */
1140 RtlCopyUnicodeString(CompleteName, &FileObject->FileName);
1141
1142 if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1143 {
1144 OpenPacket->RelatedFileObject = NULL;
1145 }
1146 }
1147
1148 /* Check if we have a name and if so, free it */
1149 if (FileObject->FileName.Length)
1150 {
1151 /*
1152 * Don't use TAG_IO_NAME since the FileObject's FileName
1153 * may have been re-allocated using a different tag
1154 * by a filesystem.
1155 */
1156 ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
1157 FileObject->FileName.Buffer = NULL;
1158 FileObject->FileName.Length = 0;
1159 }
1160
1161 /* Clear its device object */
1162 FileObject->DeviceObject = NULL;
1163
1164 /* Clear the file object in the open packet */
1165 OpenPacket->FileObject = NULL;
1166
1167 /* Dereference the file object */
1168 if (!UseDummyFile) ObDereferenceObject(FileObject);
1169
1170 /* Dereference the device object */
1171 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
1172
1173 /* Unless the driver cancelled the open, dereference the VPB */
1174 if (Vpb != NULL) IopDereferenceVpbAndFree(Vpb);
1175
1176 if (OpenPacket->Information != IO_REMOUNT)
1177 {
1178 OpenPacket->RelatedFileObject = NULL;
1179
1180 /* Inform we traversed a mount point for later attempt */
1181 if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1182 {
1183 OpenPacket->TraversedMountPoint = 1;
1184 }
1185
1186 /* In case we override checks, but got this on volume open, fail hard */
1187 if (OpenPacket->Override)
1188 {
1189 KeBugCheckEx(DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN,
1190 (ULONG_PTR)OriginalDeviceObject,
1191 (ULONG_PTR)DeviceObject,
1192 (ULONG_PTR)CompleteName,
1193 OpenPacket->Information);
1194 }
1195
1196 /* Return to IO/OB so that information can be upgraded */
1197 return STATUS_REPARSE;
1198 }
1199
1200 /* Loop again and reattempt an opening */
1201 continue;
1202 }
1203
1204 break;
1205 }
1206
1207 if (Attempt == IOP_MAX_REPARSE_TRAVERSAL)
1208 return STATUS_UNSUCCESSFUL;
1209
1210 /* Get the owner of the File Object */
1211 OwnerDevice = IoGetRelatedDeviceObject(FileObject);
1212
1213 /*
1214 * It's possible that the device to whom we sent the IRP to
1215 * isn't actually the device that ended opening the file object
1216 * internally.
1217 */
1218 if (OwnerDevice != DeviceObject)
1219 {
1220 /* We have to de-reference the VPB we had associated */
1221 if (Vpb) IopDereferenceVpbAndFree(Vpb);
1222
1223 /* And re-associate with the actual one */
1224 Vpb = FileObject->Vpb;
1225 if (Vpb) InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
1226 }
1227
1228 /* Make sure we are not using a dummy */
1229 if (!UseDummyFile)
1230 {
1231 /* Check if this was a volume open */
1232 if ((!(FileObject->RelatedFileObject) ||
1233 (FileObject->RelatedFileObject->Flags & FO_VOLUME_OPEN)) &&
1234 !(FileObject->FileName.Length))
1235 {
1236 /* All signs point to it, but make sure it was actually an FSD */
1237 if ((OwnerDevice->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
1238 (OwnerDevice->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
1239 (OwnerDevice->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM) ||
1240 (OwnerDevice->DeviceType == FILE_DEVICE_FILE_SYSTEM))
1241 {
1242 /* The owner device is an FSD, so this is a volume open for real */
1243 FileObject->Flags |= FO_VOLUME_OPEN;
1244 }
1245 }
1246
1247 /* Reference the object and set the parse check */
1248 ObReferenceObject(FileObject);
1249 *Object = FileObject;
1250 OpenPacket->FinalStatus = IoStatusBlock.Status;
1251 OpenPacket->ParseCheck = TRUE;
1252 return OpenPacket->FinalStatus;
1253 }
1254 else
1255 {
1256 /* Check if this was a query */
1257 if (OpenPacket->QueryOnly)
1258 {
1259 /* Check if the caller wants basic info only */
1260 if (!OpenPacket->FullAttributes)
1261 {
1262 /* Allocate the buffer */
1263 FileBasicInfo = ExAllocatePoolWithTag(NonPagedPool,
1264 sizeof(*FileBasicInfo),
1265 TAG_IO);
1266 if (FileBasicInfo)
1267 {
1268 /* Do the query */
1269 Status = IoQueryFileInformation(FileObject,
1270 FileBasicInformation,
1271 sizeof(*FileBasicInfo),
1272 FileBasicInfo,
1273 &ReturnLength);
1274 if (NT_SUCCESS(Status))
1275 {
1276 /* Copy the data */
1277 RtlCopyMemory(OpenPacket->BasicInformation,
1278 FileBasicInfo,
1279 ReturnLength);
1280 }
1281
1282 /* Free our buffer */
1283 ExFreePoolWithTag(FileBasicInfo, TAG_IO);
1284 }
1285 else
1286 {
1287 /* Fail */
1288 Status = STATUS_INSUFFICIENT_RESOURCES;
1289 }
1290 }
1291 else
1292 {
1293 /* This is a full query */
1294 Status = IoQueryFileInformation(
1295 FileObject,
1296 FileNetworkOpenInformation,
1297 sizeof(FILE_NETWORK_OPEN_INFORMATION),
1298 OpenPacket->NetworkInformation,
1299 &ReturnLength);
1300 if (!NT_SUCCESS(Status)) ASSERT(Status != STATUS_NOT_IMPLEMENTED);
1301 }
1302 }
1303
1304 /* Delete the file object */
1305 IopDeleteFile(FileObject);
1306
1307 /* Clear out the file */
1308 OpenPacket->FileObject = NULL;
1309
1310 /* Set and return status */
1311 OpenPacket->FinalStatus = Status;
1312 OpenPacket->ParseCheck = TRUE;
1313 return Status;
1314 }
1315 }
1316
1317 NTSTATUS
1318 NTAPI
IopParseFile(IN PVOID ParseObject,IN PVOID ObjectType,IN OUT PACCESS_STATE AccessState,IN KPROCESSOR_MODE AccessMode,IN ULONG Attributes,IN OUT PUNICODE_STRING CompleteName,IN OUT PUNICODE_STRING RemainingName,IN OUT PVOID Context OPTIONAL,IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,OUT PVOID * Object)1319 IopParseFile(IN PVOID ParseObject,
1320 IN PVOID ObjectType,
1321 IN OUT PACCESS_STATE AccessState,
1322 IN KPROCESSOR_MODE AccessMode,
1323 IN ULONG Attributes,
1324 IN OUT PUNICODE_STRING CompleteName,
1325 IN OUT PUNICODE_STRING RemainingName,
1326 IN OUT PVOID Context OPTIONAL,
1327 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
1328 OUT PVOID *Object)
1329 {
1330 PVOID DeviceObject;
1331 POPEN_PACKET OpenPacket = (POPEN_PACKET)Context;
1332
1333 /* Validate the open packet */
1334 if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
1335
1336 /* Get the device object */
1337 DeviceObject = IoGetRelatedDeviceObject(ParseObject);
1338 OpenPacket->RelatedFileObject = ParseObject;
1339
1340 /* Call the main routine */
1341 return IopParseDevice(DeviceObject,
1342 ObjectType,
1343 AccessState,
1344 AccessMode,
1345 Attributes,
1346 CompleteName,
1347 RemainingName,
1348 OpenPacket,
1349 SecurityQos,
1350 Object);
1351 }
1352
1353 VOID
1354 NTAPI
IopDeleteFile(IN PVOID ObjectBody)1355 IopDeleteFile(IN PVOID ObjectBody)
1356 {
1357 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
1358 PIRP Irp;
1359 PIO_STACK_LOCATION StackPtr;
1360 NTSTATUS Status;
1361 KEVENT Event;
1362 PDEVICE_OBJECT DeviceObject;
1363 BOOLEAN DereferenceDone = FALSE;
1364 PVPB Vpb;
1365 KIRQL OldIrql;
1366 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1367
1368 /* Check if the file has a device object */
1369 if (FileObject->DeviceObject)
1370 {
1371 /* Check if this is a direct open or not */
1372 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1373 {
1374 /* Get the attached device */
1375 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1376 }
1377 else
1378 {
1379 /* Use the file object's device object */
1380 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1381 }
1382
1383 /* Sanity check */
1384 ASSERT(!(FileObject->Flags & FO_SYNCHRONOUS_IO) ||
1385 (InterlockedExchange((PLONG)&FileObject->Busy, TRUE) == FALSE));
1386
1387 /* Check if the handle wasn't created yet */
1388 if (!(FileObject->Flags & FO_HANDLE_CREATED))
1389 {
1390 /* Send the cleanup IRP */
1391 IopCloseFile(NULL, ObjectBody, 0, 1, 1);
1392 }
1393
1394 /* Clear and set up Events */
1395 KeClearEvent(&FileObject->Event);
1396 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1397
1398 /* Allocate an IRP */
1399 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
1400
1401 /* Set it up */
1402 Irp->UserEvent = &Event;
1403 Irp->UserIosb = &Irp->IoStatus;
1404 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1405 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1406 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
1407
1408 /* Set up Stack Pointer Data */
1409 StackPtr = IoGetNextIrpStackLocation(Irp);
1410 StackPtr->MajorFunction = IRP_MJ_CLOSE;
1411 StackPtr->FileObject = FileObject;
1412
1413 /* Queue the IRP */
1414 IopQueueIrpToThread(Irp);
1415
1416 /* Get the VPB and check if this isn't a direct open */
1417 Vpb = FileObject->Vpb;
1418 if ((Vpb) && !(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
1419 {
1420 /* Dereference the VPB before the close */
1421 InterlockedDecrement((PLONG)&Vpb->ReferenceCount);
1422 }
1423
1424 /* Check if the FS will never disappear by itself */
1425 if (FileObject->DeviceObject->Flags & DO_NEVER_LAST_DEVICE)
1426 {
1427 /* Dereference it */
1428 InterlockedDecrement(&FileObject->DeviceObject->ReferenceCount);
1429 DereferenceDone = TRUE;
1430 }
1431
1432 /* Call the FS Driver */
1433 Status = IoCallDriver(DeviceObject, Irp);
1434 if (Status == STATUS_PENDING)
1435 {
1436 /* Wait for completion */
1437 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1438 }
1439
1440 /* De-queue the IRP */
1441 KeRaiseIrql(APC_LEVEL, &OldIrql);
1442 IopUnQueueIrpFromThread(Irp);
1443 KeLowerIrql(OldIrql);
1444
1445 /* Free the IRP */
1446 IoFreeIrp(Irp);
1447
1448 /* Clear the file name */
1449 if (FileObject->FileName.Buffer)
1450 {
1451 /*
1452 * Don't use TAG_IO_NAME since the FileObject's FileName
1453 * may have been re-allocated using a different tag
1454 * by a filesystem.
1455 */
1456 ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
1457 FileObject->FileName.Buffer = NULL;
1458 }
1459
1460 /* Check if the FO had a completion port */
1461 if (FileObject->CompletionContext)
1462 {
1463 /* Free it */
1464 ObDereferenceObject(FileObject->CompletionContext->Port);
1465 ExFreePool(FileObject->CompletionContext);
1466 }
1467
1468 /* Check if the FO had extension */
1469 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
1470 {
1471 /* Release filter context structure if any */
1472 FsRtlPTeardownPerFileObjectContexts(FileObject);
1473 }
1474
1475 /* Check if dereference has been done yet */
1476 if (!DereferenceDone)
1477 {
1478 /* Dereference device object */
1479 IopDereferenceDeviceObject(FileObject->DeviceObject, FALSE);
1480 }
1481 }
1482 }
1483
1484 PDEVICE_OBJECT
1485 NTAPI
IopGetDeviceAttachmentBase(IN PDEVICE_OBJECT DeviceObject)1486 IopGetDeviceAttachmentBase(IN PDEVICE_OBJECT DeviceObject)
1487 {
1488 PDEVICE_OBJECT PDO = DeviceObject;
1489
1490 /* Go down the stack to attempt to get the PDO */
1491 for (; ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo != NULL;
1492 PDO = ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo);
1493
1494 return PDO;
1495 }
1496
1497 PDEVICE_OBJECT
1498 NTAPI
IopGetDevicePDO(IN PDEVICE_OBJECT DeviceObject)1499 IopGetDevicePDO(IN PDEVICE_OBJECT DeviceObject)
1500 {
1501 KIRQL OldIrql;
1502 PDEVICE_OBJECT PDO;
1503
1504 ASSERT(DeviceObject != NULL);
1505
1506 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
1507 /* Get the base DO */
1508 PDO = IopGetDeviceAttachmentBase(DeviceObject);
1509 /* Check whether that's really a PDO and if so, keep it */
1510 if ((PDO->Flags & DO_BUS_ENUMERATED_DEVICE) != DO_BUS_ENUMERATED_DEVICE)
1511 {
1512 PDO = NULL;
1513 }
1514 else
1515 {
1516 ObReferenceObject(PDO);
1517 }
1518 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
1519
1520 return PDO;
1521 }
1522
1523 NTSTATUS
1524 NTAPI
IopSetDeviceSecurityDescriptor(IN PDEVICE_OBJECT DeviceObject,IN PSECURITY_INFORMATION SecurityInformation,IN PSECURITY_DESCRIPTOR SecurityDescriptor,IN POOL_TYPE PoolType,IN PGENERIC_MAPPING GenericMapping)1525 IopSetDeviceSecurityDescriptor(IN PDEVICE_OBJECT DeviceObject,
1526 IN PSECURITY_INFORMATION SecurityInformation,
1527 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1528 IN POOL_TYPE PoolType,
1529 IN PGENERIC_MAPPING GenericMapping)
1530 {
1531 NTSTATUS Status;
1532 PSECURITY_DESCRIPTOR OldSecurityDescriptor, CachedSecurityDescriptor, NewSecurityDescriptor;
1533
1534 PAGED_CODE();
1535
1536 /* Keep attempting till we find our old SD or fail */
1537 while (TRUE)
1538 {
1539 KeEnterCriticalRegion();
1540 ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
1541
1542 /* Get our old SD and reference it */
1543 OldSecurityDescriptor = DeviceObject->SecurityDescriptor;
1544 if (OldSecurityDescriptor != NULL)
1545 {
1546 ObReferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1547 }
1548
1549 ExReleaseResourceLite(&IopSecurityResource);
1550 KeLeaveCriticalRegion();
1551
1552 /* Set the SD information */
1553 NewSecurityDescriptor = OldSecurityDescriptor;
1554 Status = SeSetSecurityDescriptorInfo(NULL, SecurityInformation,
1555 SecurityDescriptor, &NewSecurityDescriptor,
1556 PoolType, GenericMapping);
1557
1558 if (!NT_SUCCESS(Status))
1559 {
1560 if (OldSecurityDescriptor != NULL)
1561 {
1562 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1563 }
1564
1565 break;
1566 }
1567
1568 /* Add the new DS to the internal cache */
1569 Status = ObLogSecurityDescriptor(NewSecurityDescriptor,
1570 &CachedSecurityDescriptor, 1);
1571 ExFreePool(NewSecurityDescriptor);
1572 if (!NT_SUCCESS(Status))
1573 {
1574 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1575 break;
1576 }
1577
1578 KeEnterCriticalRegion();
1579 ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
1580 /* Check if someone changed it in our back */
1581 if (DeviceObject->SecurityDescriptor == OldSecurityDescriptor)
1582 {
1583 /* We're clear, do the swap */
1584 DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
1585 ExReleaseResourceLite(&IopSecurityResource);
1586 KeLeaveCriticalRegion();
1587
1588 /* And dereference old SD (twice - us + not in use) */
1589 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 2);
1590
1591 break;
1592 }
1593 ExReleaseResourceLite(&IopSecurityResource);
1594 KeLeaveCriticalRegion();
1595
1596 /* If so, try again */
1597 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1598 ObDereferenceSecurityDescriptor(CachedSecurityDescriptor, 1);
1599 }
1600
1601 return Status;
1602 }
1603
1604 NTSTATUS
1605 NTAPI
IopSetDeviceSecurityDescriptors(IN PDEVICE_OBJECT UpperDeviceObject,IN PDEVICE_OBJECT PhysicalDeviceObject,IN PSECURITY_INFORMATION SecurityInformation,IN PSECURITY_DESCRIPTOR SecurityDescriptor,IN POOL_TYPE PoolType,IN PGENERIC_MAPPING GenericMapping)1606 IopSetDeviceSecurityDescriptors(IN PDEVICE_OBJECT UpperDeviceObject,
1607 IN PDEVICE_OBJECT PhysicalDeviceObject,
1608 IN PSECURITY_INFORMATION SecurityInformation,
1609 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1610 IN POOL_TYPE PoolType,
1611 IN PGENERIC_MAPPING GenericMapping)
1612 {
1613 PDEVICE_OBJECT CurrentDO = PhysicalDeviceObject, NextDevice;
1614 NTSTATUS Status = STATUS_SUCCESS, TmpStatus;
1615
1616 PAGED_CODE();
1617
1618 ASSERT(PhysicalDeviceObject != NULL);
1619
1620 /* We always reference the DO we're working on */
1621 ObReferenceObject(CurrentDO);
1622
1623 /* Go up from PDO to latest DO */
1624 do
1625 {
1626 /* Attempt to set the new SD on it */
1627 TmpStatus = IopSetDeviceSecurityDescriptor(CurrentDO, SecurityInformation,
1628 SecurityDescriptor, PoolType,
1629 GenericMapping);
1630 /* Was our last one? Remember that status then */
1631 if (CurrentDO == UpperDeviceObject)
1632 {
1633 Status = TmpStatus;
1634 }
1635
1636 /* Try to move to the next DO (and thus, reference it) */
1637 NextDevice = CurrentDO->AttachedDevice;
1638 if (NextDevice)
1639 {
1640 ObReferenceObject(NextDevice);
1641 }
1642
1643 /* Dereference current DO and move to the next one */
1644 ObDereferenceObject(CurrentDO);
1645 CurrentDO = NextDevice;
1646 }
1647 while (CurrentDO != NULL);
1648
1649 return Status;
1650 }
1651
1652 NTSTATUS
1653 NTAPI
IopGetSetSecurityObject(IN PVOID ObjectBody,IN SECURITY_OPERATION_CODE OperationCode,IN PSECURITY_INFORMATION SecurityInformation,IN PSECURITY_DESCRIPTOR SecurityDescriptor,IN OUT PULONG BufferLength,IN OUT PSECURITY_DESCRIPTOR * OldSecurityDescriptor,IN POOL_TYPE PoolType,IN OUT PGENERIC_MAPPING GenericMapping)1654 IopGetSetSecurityObject(IN PVOID ObjectBody,
1655 IN SECURITY_OPERATION_CODE OperationCode,
1656 IN PSECURITY_INFORMATION SecurityInformation,
1657 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1658 IN OUT PULONG BufferLength,
1659 IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
1660 IN POOL_TYPE PoolType,
1661 IN OUT PGENERIC_MAPPING GenericMapping)
1662 {
1663 IO_STATUS_BLOCK IoStatusBlock;
1664 PIO_STACK_LOCATION StackPtr;
1665 PFILE_OBJECT FileObject;
1666 PDEVICE_OBJECT DeviceObject;
1667 PIRP Irp;
1668 BOOLEAN LocalEvent = FALSE;
1669 KEVENT Event;
1670 NTSTATUS Status = STATUS_SUCCESS;
1671 PAGED_CODE();
1672 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1673
1674 /* Check if this is a device or file */
1675 if (((PFILE_OBJECT)ObjectBody)->Type == IO_TYPE_DEVICE)
1676 {
1677 /* It's a device */
1678 DeviceObject = (PDEVICE_OBJECT)ObjectBody;
1679 FileObject = NULL;
1680 }
1681 else
1682 {
1683 /* It's a file */
1684 FileObject = (PFILE_OBJECT)ObjectBody;
1685
1686 /* Check if this is a direct open */
1687 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1688 {
1689 /* Get the Device Object */
1690 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1691 }
1692 else
1693 {
1694 /* Otherwise, use the direct device*/
1695 DeviceObject = FileObject->DeviceObject;
1696 }
1697 }
1698
1699 /* Check if the request was for a device object */
1700 if (!(FileObject) ||
1701 (!(FileObject->FileName.Length) && !(FileObject->RelatedFileObject)) ||
1702 (FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
1703 {
1704 /* Check what kind of request this was */
1705 if (OperationCode == QuerySecurityDescriptor)
1706 {
1707 return SeQuerySecurityDescriptorInfo(SecurityInformation,
1708 SecurityDescriptor,
1709 BufferLength,
1710 &DeviceObject->SecurityDescriptor);
1711 }
1712 else if (OperationCode == DeleteSecurityDescriptor)
1713 {
1714 /* Simply return success */
1715 return STATUS_SUCCESS;
1716 }
1717 else if (OperationCode == AssignSecurityDescriptor)
1718 {
1719 Status = STATUS_SUCCESS;
1720
1721 /* Make absolutely sure this is a device object */
1722 if (!(FileObject) || !(FileObject->Flags & FO_STREAM_FILE))
1723 {
1724 PSECURITY_DESCRIPTOR CachedSecurityDescriptor;
1725
1726 /* Add the security descriptor in cache */
1727 Status = ObLogSecurityDescriptor(SecurityDescriptor, &CachedSecurityDescriptor, 1);
1728 if (NT_SUCCESS(Status))
1729 {
1730 KeEnterCriticalRegion();
1731 ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
1732
1733 /* Assign the Security Descriptor */
1734 DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
1735
1736 ExReleaseResourceLite(&IopSecurityResource);
1737 KeLeaveCriticalRegion();
1738 }
1739 }
1740
1741 /* Return status */
1742 return Status;
1743 }
1744 else if (OperationCode == SetSecurityDescriptor)
1745 {
1746 /* Get the Physical Device Object if any */
1747 PDEVICE_OBJECT PDO = IopGetDevicePDO(DeviceObject);
1748
1749 if (PDO != NULL)
1750 {
1751 /* Apply the new SD to any DO in the path from PDO to current DO */
1752 Status = IopSetDeviceSecurityDescriptors(DeviceObject, PDO,
1753 SecurityInformation,
1754 SecurityDescriptor,
1755 PoolType, GenericMapping);
1756 ObDereferenceObject(PDO);
1757 }
1758 else
1759 {
1760 /* Otherwise, just set for ourselves */
1761 Status = IopSetDeviceSecurityDescriptor(DeviceObject,
1762 SecurityInformation,
1763 SecurityDescriptor,
1764 PoolType, GenericMapping);
1765 }
1766
1767 return STATUS_SUCCESS;
1768 }
1769
1770 /* Shouldn't happen */
1771 return STATUS_SUCCESS;
1772 }
1773 else if (OperationCode == DeleteSecurityDescriptor)
1774 {
1775 /* Same as for devices, do nothing */
1776 return STATUS_SUCCESS;
1777 }
1778
1779 /* At this point, we know we're a file. Reference it */
1780 ObReferenceObject(FileObject);
1781
1782 /* Check if we should use Sync IO or not */
1783 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1784 {
1785 /* Lock the file object */
1786 Status = IopLockFileObject(FileObject, ExGetPreviousMode());
1787 if (Status != STATUS_SUCCESS)
1788 {
1789 ObDereferenceObject(FileObject);
1790 return Status;
1791 }
1792 }
1793 else
1794 {
1795 /* Use local event */
1796 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1797 LocalEvent = TRUE;
1798 }
1799
1800 /* Clear the File Object event */
1801 KeClearEvent(&FileObject->Event);
1802
1803 /* Get the device object */
1804 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1805
1806 /* Allocate the IRP */
1807 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1808 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
1809
1810 /* Set the IRP */
1811 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1812 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1813 Irp->RequestorMode = ExGetPreviousMode();
1814 Irp->UserIosb = &IoStatusBlock;
1815 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1816 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1817 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1818
1819 /* Set Stack Parameters */
1820 StackPtr = IoGetNextIrpStackLocation(Irp);
1821 StackPtr->FileObject = FileObject;
1822
1823 /* Check if this is a query or set */
1824 if (OperationCode == QuerySecurityDescriptor)
1825 {
1826 /* Set the major function and parameters */
1827 StackPtr->MajorFunction = IRP_MJ_QUERY_SECURITY;
1828 StackPtr->Parameters.QuerySecurity.SecurityInformation =
1829 *SecurityInformation;
1830 StackPtr->Parameters.QuerySecurity.Length = *BufferLength;
1831 Irp->UserBuffer = SecurityDescriptor;
1832 }
1833 else
1834 {
1835 /* Set the major function and parameters for a set */
1836 StackPtr->MajorFunction = IRP_MJ_SET_SECURITY;
1837 StackPtr->Parameters.SetSecurity.SecurityInformation =
1838 *SecurityInformation;
1839 StackPtr->Parameters.SetSecurity.SecurityDescriptor =
1840 SecurityDescriptor;
1841 }
1842
1843 /* Queue the IRP */
1844 IopQueueIrpToThread(Irp);
1845
1846 /* Update operation counts */
1847 IopUpdateOperationCount(IopOtherTransfer);
1848
1849 /* Call the Driver */
1850 Status = IoCallDriver(DeviceObject, Irp);
1851
1852 /* Check if this was async I/O */
1853 if (LocalEvent)
1854 {
1855 /* Check if the IRP is pending completion */
1856 if (Status == STATUS_PENDING)
1857 {
1858 /* Wait on the local event */
1859 KeWaitForSingleObject(&Event,
1860 Executive,
1861 KernelMode,
1862 FALSE,
1863 NULL);
1864 Status = IoStatusBlock.Status;
1865 }
1866 }
1867 else
1868 {
1869 /* Check if the IRP is pending completion */
1870 if (Status == STATUS_PENDING)
1871 {
1872 /* Wait on the file object */
1873 KeWaitForSingleObject(&FileObject->Event,
1874 Executive,
1875 KernelMode,
1876 FALSE,
1877 NULL);
1878 Status = FileObject->FinalStatus;
1879 }
1880
1881 /* Release the lock */
1882 IopUnlockFileObject(FileObject);
1883 }
1884
1885 /* This Driver doesn't implement Security, so try to give it a default */
1886 if (Status == STATUS_INVALID_DEVICE_REQUEST)
1887 {
1888 /* Was this a query? */
1889 if (OperationCode == QuerySecurityDescriptor)
1890 {
1891 /* Set a World Security Descriptor */
1892 Status = SeSetWorldSecurityDescriptor(*SecurityInformation,
1893 SecurityDescriptor,
1894 BufferLength);
1895 }
1896 else
1897 {
1898 /* It wasn't a query, so just fake success */
1899 Status = STATUS_SUCCESS;
1900 }
1901 }
1902 else if (OperationCode == QuerySecurityDescriptor)
1903 {
1904 /* Callers usually expect the normalized form */
1905 if (Status == STATUS_BUFFER_OVERFLOW) Status = STATUS_BUFFER_TOO_SMALL;
1906
1907 _SEH2_TRY
1908 {
1909 /* Return length */
1910 *BufferLength = (ULONG)IoStatusBlock.Information;
1911 }
1912 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1913 {
1914 /* Get the exception code */
1915 Status = _SEH2_GetExceptionCode();
1916 }
1917 _SEH2_END;
1918 }
1919
1920 /* Return Status */
1921 return Status;
1922 }
1923
1924 NTSTATUS
1925 NTAPI
IopQueryName(IN PVOID ObjectBody,IN BOOLEAN HasName,OUT POBJECT_NAME_INFORMATION ObjectNameInfo,IN ULONG Length,OUT PULONG ReturnLength,IN KPROCESSOR_MODE PreviousMode)1926 IopQueryName(IN PVOID ObjectBody,
1927 IN BOOLEAN HasName,
1928 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
1929 IN ULONG Length,
1930 OUT PULONG ReturnLength,
1931 IN KPROCESSOR_MODE PreviousMode)
1932 {
1933 return IopQueryNameInternal(ObjectBody,
1934 HasName,
1935 FALSE,
1936 ObjectNameInfo,
1937 Length,
1938 ReturnLength,
1939 PreviousMode);
1940 }
1941
1942 NTSTATUS
1943 NTAPI
IopQueryNameInternal(IN PVOID ObjectBody,IN BOOLEAN HasName,IN BOOLEAN QueryDosName,OUT POBJECT_NAME_INFORMATION ObjectNameInfo,IN ULONG Length,OUT PULONG ReturnLength,IN KPROCESSOR_MODE PreviousMode)1944 IopQueryNameInternal(IN PVOID ObjectBody,
1945 IN BOOLEAN HasName,
1946 IN BOOLEAN QueryDosName,
1947 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
1948 IN ULONG Length,
1949 OUT PULONG ReturnLength,
1950 IN KPROCESSOR_MODE PreviousMode)
1951 {
1952 POBJECT_NAME_INFORMATION LocalInfo;
1953 PFILE_NAME_INFORMATION LocalFileInfo;
1954 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
1955 ULONG LocalReturnLength, FileLength;
1956 BOOLEAN LengthMismatch = FALSE;
1957 NTSTATUS Status;
1958 PWCHAR p;
1959 PDEVICE_OBJECT DeviceObject;
1960 BOOLEAN NoObCall;
1961
1962 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1963
1964 /* Validate length */
1965 if (Length < sizeof(OBJECT_NAME_INFORMATION))
1966 {
1967 /* Wrong length, fail */
1968 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
1969 return STATUS_INFO_LENGTH_MISMATCH;
1970 }
1971
1972 /* Allocate Buffer */
1973 LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, TAG_IO);
1974 if (!LocalInfo) return STATUS_INSUFFICIENT_RESOURCES;
1975
1976 /* Query DOS name if the caller asked to */
1977 NoObCall = FALSE;
1978 if (QueryDosName)
1979 {
1980 DeviceObject = FileObject->DeviceObject;
1981
1982 /* In case of a network file system, don't call mountmgr */
1983 if (DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM)
1984 {
1985 /* We'll store separator and terminator */
1986 LocalReturnLength = sizeof(OBJECT_NAME_INFORMATION) + 2 * sizeof(WCHAR);
1987 if (Length < LocalReturnLength)
1988 {
1989 Status = STATUS_BUFFER_OVERFLOW;
1990 }
1991 else
1992 {
1993 LocalInfo->Name.Length = sizeof(WCHAR);
1994 LocalInfo->Name.MaximumLength = sizeof(WCHAR);
1995 LocalInfo->Name.Buffer = (PVOID)((ULONG_PTR)LocalInfo + sizeof(OBJECT_NAME_INFORMATION));
1996 LocalInfo->Name.Buffer[0] = OBJ_NAME_PATH_SEPARATOR;
1997 Status = STATUS_SUCCESS;
1998 }
1999 }
2000 /* Otherwise, call mountmgr to get DOS name */
2001 else
2002 {
2003 Status = IoVolumeDeviceToDosName(DeviceObject, &LocalInfo->Name);
2004 LocalReturnLength = LocalInfo->Name.Length + sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR);
2005 }
2006 }
2007
2008 /* Fall back if querying DOS name failed or if caller never wanted it ;-) */
2009 if (!QueryDosName || !NT_SUCCESS(Status))
2010 {
2011 /* Query the name */
2012 Status = ObQueryNameString(FileObject->DeviceObject,
2013 LocalInfo,
2014 Length,
2015 &LocalReturnLength);
2016 }
2017 else
2018 {
2019 NoObCall = TRUE;
2020 }
2021
2022 if (!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
2023 {
2024 /* Free the buffer and fail */
2025 ExFreePoolWithTag(LocalInfo, TAG_IO);
2026 return Status;
2027 }
2028
2029 /* Get buffer pointer */
2030 p = (PWCHAR)(ObjectNameInfo + 1);
2031
2032 _SEH2_TRY
2033 {
2034 /* Copy the information */
2035 if (QueryDosName && NoObCall)
2036 {
2037 ASSERT(PreviousMode == KernelMode);
2038
2039 /* Copy structure first */
2040 RtlCopyMemory(ObjectNameInfo,
2041 LocalInfo,
2042 (Length >= LocalReturnLength ? sizeof(OBJECT_NAME_INFORMATION) : Length));
2043 /* Name then */
2044 RtlCopyMemory(p, LocalInfo->Name.Buffer,
2045 (Length >= LocalReturnLength ? LocalInfo->Name.Length : Length - sizeof(OBJECT_NAME_INFORMATION)));
2046
2047 if (FileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM)
2048 {
2049 ExFreePool(LocalInfo->Name.Buffer);
2050 }
2051 }
2052 else
2053 {
2054 RtlCopyMemory(ObjectNameInfo,
2055 LocalInfo,
2056 (LocalReturnLength > Length) ?
2057 Length : LocalReturnLength);
2058 }
2059
2060 /* Set buffer pointer */
2061 ObjectNameInfo->Name.Buffer = p;
2062
2063 /* Advance in buffer */
2064 p += (LocalInfo->Name.Length / sizeof(WCHAR));
2065
2066 /* Check if this already filled our buffer */
2067 if (LocalReturnLength > Length)
2068 {
2069 /* Set the length mismatch to true, so that we can return
2070 * the proper buffer size to the caller later
2071 */
2072 LengthMismatch = TRUE;
2073
2074 /* Save the initial buffer length value */
2075 *ReturnLength = LocalReturnLength;
2076 }
2077
2078 /* Now get the file name buffer and check the length needed */
2079 LocalFileInfo = (PFILE_NAME_INFORMATION)LocalInfo;
2080 FileLength = Length -
2081 LocalReturnLength +
2082 FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2083
2084 /* Query the File name */
2085 if (PreviousMode == KernelMode &&
2086 BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2087 {
2088 Status = IopGetFileInformation(FileObject,
2089 LengthMismatch ? Length : FileLength,
2090 FileNameInformation,
2091 LocalFileInfo,
2092 &LocalReturnLength);
2093 }
2094 else
2095 {
2096 Status = IoQueryFileInformation(FileObject,
2097 FileNameInformation,
2098 LengthMismatch ? Length : FileLength,
2099 LocalFileInfo,
2100 &LocalReturnLength);
2101 }
2102 if (NT_ERROR(Status))
2103 {
2104 /* Allow status that would mean it's not implemented in the storage stack */
2105 if (Status != STATUS_INVALID_PARAMETER && Status != STATUS_INVALID_DEVICE_REQUEST &&
2106 Status != STATUS_NOT_IMPLEMENTED && Status != STATUS_INVALID_INFO_CLASS)
2107 {
2108 _SEH2_LEAVE;
2109 }
2110
2111 /* In such case, zero the output and reset the status */
2112 LocalReturnLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2113 LocalFileInfo->FileNameLength = 0;
2114 LocalFileInfo->FileName[0] = OBJ_NAME_PATH_SEPARATOR;
2115 Status = STATUS_SUCCESS;
2116 }
2117 else
2118 {
2119 /* We'll at least return the name length */
2120 if (LocalReturnLength < FIELD_OFFSET(FILE_NAME_INFORMATION, FileName))
2121 {
2122 LocalReturnLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2123 }
2124 }
2125
2126 /* If the provided buffer is too small, return the required size */
2127 if (LengthMismatch)
2128 {
2129 /* Add the required length */
2130 *ReturnLength += LocalFileInfo->FileNameLength;
2131
2132 /* Free the allocated buffer and return failure */
2133 Status = STATUS_BUFFER_OVERFLOW;
2134 _SEH2_LEAVE;
2135 }
2136
2137 /* Now calculate the new lengths left */
2138 FileLength = LocalReturnLength -
2139 FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2140 LocalReturnLength = (ULONG)((ULONG_PTR)p -
2141 (ULONG_PTR)ObjectNameInfo +
2142 LocalFileInfo->FileNameLength);
2143
2144 /* Don't copy the name if it's not valid */
2145 if (LocalFileInfo->FileName[0] != OBJ_NAME_PATH_SEPARATOR)
2146 {
2147 /* Free the allocated buffer and return failure */
2148 Status = STATUS_OBJECT_PATH_INVALID;
2149 _SEH2_LEAVE;
2150 }
2151
2152 /* Write the Name and null-terminate it */
2153 RtlCopyMemory(p, LocalFileInfo->FileName, FileLength);
2154 p += (FileLength / sizeof(WCHAR));
2155 *p = UNICODE_NULL;
2156 LocalReturnLength += sizeof(UNICODE_NULL);
2157
2158 /* Return the length needed */
2159 *ReturnLength = LocalReturnLength;
2160
2161 /* Setup the length and maximum length */
2162 FileLength = (ULONG)((ULONG_PTR)p - (ULONG_PTR)ObjectNameInfo);
2163 ObjectNameInfo->Name.Length = (USHORT)FileLength -
2164 sizeof(OBJECT_NAME_INFORMATION);
2165 ObjectNameInfo->Name.MaximumLength = (USHORT)ObjectNameInfo->Name.Length +
2166 sizeof(UNICODE_NULL);
2167 }
2168 _SEH2_FINALLY
2169 {
2170 /* Free buffer and return */
2171 ExFreePoolWithTag(LocalInfo, TAG_IO);
2172 } _SEH2_END;
2173
2174 return Status;
2175 }
2176
2177 VOID
2178 NTAPI
IopCloseFile(IN PEPROCESS Process OPTIONAL,IN PVOID ObjectBody,IN ACCESS_MASK GrantedAccess,IN ULONG HandleCount,IN ULONG SystemHandleCount)2179 IopCloseFile(IN PEPROCESS Process OPTIONAL,
2180 IN PVOID ObjectBody,
2181 IN ACCESS_MASK GrantedAccess,
2182 IN ULONG HandleCount,
2183 IN ULONG SystemHandleCount)
2184 {
2185 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
2186 KEVENT Event;
2187 PIRP Irp;
2188 PIO_STACK_LOCATION StackPtr;
2189 NTSTATUS Status;
2190 PDEVICE_OBJECT DeviceObject;
2191 KIRQL OldIrql;
2192 IO_STATUS_BLOCK IoStatusBlock;
2193 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
2194
2195 /* If this isn't the last handle for the current process, quit */
2196 if (HandleCount != 1) return;
2197
2198 /* Check if the file is locked and has more then one handle opened */
2199 if ((FileObject->LockOperation) && (SystemHandleCount != 1))
2200 {
2201 /* Check if this is a direct open or not */
2202 if (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN))
2203 {
2204 /* Get the attached device */
2205 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2206 }
2207 else
2208 {
2209 /* Get the FO's device */
2210 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2211 }
2212
2213 /* Check if this is a sync FO and lock it */
2214 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2215 {
2216 (VOID)IopLockFileObject(FileObject, KernelMode);
2217 }
2218
2219 /* Go the FastIO path if possible, otherwise fall back to IRP */
2220 if (DeviceObject->DriverObject->FastIoDispatch == NULL ||
2221 DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll == NULL ||
2222 !DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll(FileObject, PsGetCurrentProcess(), &IoStatusBlock, DeviceObject))
2223 {
2224 /* Clear and set up Events */
2225 KeClearEvent(&FileObject->Event);
2226 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2227
2228 /* Allocate an IRP */
2229 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
2230
2231 /* Set it up */
2232 Irp->UserEvent = &Event;
2233 Irp->UserIosb = &Irp->IoStatus;
2234 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2235 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2236 Irp->RequestorMode = KernelMode;
2237 Irp->Flags = IRP_SYNCHRONOUS_API;
2238 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2239 ObReferenceObject(FileObject);
2240
2241 /* Set up Stack Pointer Data */
2242 StackPtr = IoGetNextIrpStackLocation(Irp);
2243 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
2244 StackPtr->MinorFunction = IRP_MN_UNLOCK_ALL;
2245 StackPtr->FileObject = FileObject;
2246
2247 /* Queue the IRP */
2248 IopQueueIrpToThread(Irp);
2249
2250 /* Call the FS Driver */
2251 Status = IoCallDriver(DeviceObject, Irp);
2252 if (Status == STATUS_PENDING)
2253 {
2254 /* Wait for completion */
2255 KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
2256 }
2257
2258 /* IO will unqueue & free for us */
2259 }
2260
2261 /* Release the lock if we were holding it */
2262 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2263 {
2264 IopUnlockFileObject(FileObject);
2265 }
2266 }
2267
2268 /* Make sure this is the last handle */
2269 if (SystemHandleCount != 1) return;
2270
2271 /* Check if this is a direct open or not */
2272 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2273 {
2274 /* Get the attached device */
2275 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2276 }
2277 else
2278 {
2279 /* Get the FO's device */
2280 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2281 }
2282
2283 /* Set the handle created flag */
2284 FileObject->Flags |= FO_HANDLE_CREATED;
2285
2286 /* Check if this is a sync FO and lock it */
2287 if (Process != NULL &&
2288 BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2289 {
2290 (VOID)IopLockFileObject(FileObject, KernelMode);
2291 }
2292
2293 /* Clear and set up Events */
2294 KeClearEvent(&FileObject->Event);
2295 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2296
2297 /* Allocate an IRP */
2298 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
2299
2300 /* Set it up */
2301 Irp->UserEvent = &Event;
2302 Irp->UserIosb = &Irp->IoStatus;
2303 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2304 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2305 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2306 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
2307
2308 /* Set up Stack Pointer Data */
2309 StackPtr = IoGetNextIrpStackLocation(Irp);
2310 StackPtr->MajorFunction = IRP_MJ_CLEANUP;
2311 StackPtr->FileObject = FileObject;
2312
2313 /* Queue the IRP */
2314 IopQueueIrpToThread(Irp);
2315
2316 /* Update operation counts */
2317 IopUpdateOperationCount(IopOtherTransfer);
2318
2319 /* Call the FS Driver */
2320 Status = IoCallDriver(DeviceObject, Irp);
2321 if (Status == STATUS_PENDING)
2322 {
2323 /* Wait for completion */
2324 KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
2325 }
2326
2327 /* Unqueue the IRP */
2328 KeRaiseIrql(APC_LEVEL, &OldIrql);
2329 IopUnQueueIrpFromThread(Irp);
2330 KeLowerIrql(OldIrql);
2331
2332 /* Free the IRP */
2333 IoFreeIrp(Irp);
2334
2335 /* Release the lock if we were holding it */
2336 if (Process != NULL &&
2337 BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2338 {
2339 IopUnlockFileObject(FileObject);
2340 }
2341 }
2342
2343 NTSTATUS
2344 NTAPI
IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,IN FILE_INFORMATION_CLASS FileInformationClass,IN ULONG FileInformationSize,OUT PVOID FileInformation)2345 IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2346 IN FILE_INFORMATION_CLASS FileInformationClass,
2347 IN ULONG FileInformationSize,
2348 OUT PVOID FileInformation)
2349 {
2350 NTSTATUS Status;
2351 KPROCESSOR_MODE AccessMode = ExGetPreviousMode();
2352 DUMMY_FILE_OBJECT LocalFileObject;
2353 FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo;
2354 HANDLE Handle;
2355 OPEN_PACKET OpenPacket;
2356 BOOLEAN IsBasic;
2357 PAGED_CODE();
2358 IOTRACE(IO_FILE_DEBUG, "Class: %lx\n", FileInformationClass);
2359
2360 /* Check if the caller was user mode */
2361 if (AccessMode != KernelMode)
2362 {
2363 /* Protect probe in SEH */
2364 _SEH2_TRY
2365 {
2366 /* Probe the buffer */
2367 ProbeForWrite(FileInformation, FileInformationSize, sizeof(ULONG));
2368 }
2369 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2370 {
2371 /* Return the exception code */
2372 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2373 }
2374 _SEH2_END;
2375 }
2376
2377 /* Check if this is a basic or full request */
2378 IsBasic = (FileInformationSize == sizeof(FILE_BASIC_INFORMATION));
2379
2380 /* Setup the Open Packet */
2381 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
2382 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
2383 OpenPacket.Size = sizeof(OPEN_PACKET);
2384 OpenPacket.CreateOptions = FILE_OPEN_REPARSE_POINT;
2385 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2386 OpenPacket.Disposition = FILE_OPEN;
2387 OpenPacket.BasicInformation = IsBasic ? FileInformation : NULL;
2388 OpenPacket.NetworkInformation = IsBasic ? &NetworkOpenInfo :
2389 (AccessMode != KernelMode) ?
2390 &NetworkOpenInfo : FileInformation;
2391 OpenPacket.QueryOnly = TRUE;
2392 OpenPacket.FullAttributes = IsBasic ? FALSE : TRUE;
2393 OpenPacket.LocalFileObject = &LocalFileObject;
2394
2395 /* Update the operation count */
2396 IopUpdateOperationCount(IopOtherTransfer);
2397
2398 /*
2399 * Attempt opening the file. This will call the I/O Parse Routine for
2400 * the File Object (IopParseDevice) which will use the dummy file obejct
2401 * send the IRP to its device object. Note that we have two statuses
2402 * to worry about: the Object Manager's status (in Status) and the I/O
2403 * status, which is in the Open Packet's Final Status, and determined
2404 * by the Parse Check member.
2405 */
2406 Status = ObOpenObjectByName(ObjectAttributes,
2407 NULL,
2408 AccessMode,
2409 NULL,
2410 FILE_READ_ATTRIBUTES,
2411 &OpenPacket,
2412 &Handle);
2413 if (OpenPacket.ParseCheck == FALSE)
2414 {
2415 /* Parse failed */
2416 DPRINT("IopQueryAttributesFile failed for '%wZ' with 0x%lx\n",
2417 ObjectAttributes->ObjectName, Status);
2418 return Status;
2419 }
2420 else
2421 {
2422 /* Use the Io status */
2423 Status = OpenPacket.FinalStatus;
2424 }
2425
2426 /* Check if we were succesful and this was user mode and a full query */
2427 if ((NT_SUCCESS(Status)) && (AccessMode != KernelMode) && !(IsBasic))
2428 {
2429 /* Enter SEH for copy */
2430 _SEH2_TRY
2431 {
2432 /* Copy the buffer back */
2433 RtlCopyMemory(FileInformation,
2434 &NetworkOpenInfo,
2435 FileInformationSize);
2436 }
2437 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2438 {
2439 /* Get exception code */
2440 Status = _SEH2_GetExceptionCode();
2441 }
2442 _SEH2_END;
2443 }
2444
2445 /* Return status */
2446 return Status;
2447 }
2448
2449 NTSTATUS
2450 NTAPI
IopAcquireFileObjectLock(_In_ PFILE_OBJECT FileObject,_In_ KPROCESSOR_MODE WaitMode,_In_ BOOLEAN Alertable,_Out_ PBOOLEAN LockFailed)2451 IopAcquireFileObjectLock(
2452 _In_ PFILE_OBJECT FileObject,
2453 _In_ KPROCESSOR_MODE WaitMode,
2454 _In_ BOOLEAN Alertable,
2455 _Out_ PBOOLEAN LockFailed)
2456 {
2457 NTSTATUS Status;
2458
2459 PAGED_CODE();
2460
2461 InterlockedIncrement((PLONG)&FileObject->Waiters);
2462
2463 Status = STATUS_SUCCESS;
2464 do
2465 {
2466 if (!InterlockedExchange((PLONG)&FileObject->Busy, TRUE))
2467 {
2468 break;
2469 }
2470 Status = KeWaitForSingleObject(&FileObject->Lock,
2471 Executive,
2472 WaitMode,
2473 Alertable,
2474 NULL);
2475 } while (Status == STATUS_SUCCESS);
2476
2477 InterlockedDecrement((PLONG)&FileObject->Waiters);
2478 if (Status == STATUS_SUCCESS)
2479 {
2480 ObReferenceObject(FileObject);
2481 *LockFailed = FALSE;
2482 }
2483 else
2484 {
2485 if (!FileObject->Busy && FileObject->Waiters)
2486 {
2487 KeSetEvent(&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2488 }
2489 *LockFailed = TRUE;
2490 }
2491
2492 return Status;
2493 }
2494
2495 PVOID
2496 NTAPI
IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject)2497 IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject)
2498 {
2499 if (BooleanFlagOn(FileObject->Flags, FO_FILE_OBJECT_HAS_EXTENSION))
2500 {
2501 PFILE_OBJECT_EXTENSION FileObjectExtension;
2502
2503 FileObjectExtension = FileObject->FileObjectExtension;
2504 return FileObjectExtension->FilterContext;
2505 }
2506
2507 return NULL;
2508 }
2509
2510 NTSTATUS
2511 NTAPI
IoChangeFileObjectFilterContext(IN PFILE_OBJECT FileObject,IN PVOID FilterContext,IN BOOLEAN Define)2512 IoChangeFileObjectFilterContext(IN PFILE_OBJECT FileObject,
2513 IN PVOID FilterContext,
2514 IN BOOLEAN Define)
2515 {
2516 ULONG_PTR Success;
2517 PFILE_OBJECT_EXTENSION FileObjectExtension;
2518
2519 if (!BooleanFlagOn(FileObject->Flags, FO_FILE_OBJECT_HAS_EXTENSION))
2520 {
2521 return STATUS_INVALID_PARAMETER;
2522 }
2523
2524 FileObjectExtension = FileObject->FileObjectExtension;
2525 if (Define)
2526 {
2527 /* If define, just set the new value if not value is set
2528 * Success will only contain old value. It is valid if it is NULL
2529 */
2530 Success = (ULONG_PTR)InterlockedCompareExchangePointer(&FileObjectExtension->FilterContext, FilterContext, NULL);
2531 }
2532 else
2533 {
2534 /* If not define, we want to reset filter context.
2535 * We will remove value (provided by the caller) and set NULL instead.
2536 * This will only success if caller provides correct previous value.
2537 * To catch whether it worked, we substract previous value to expect value:
2538 * If it matches (and thus, we reset), Success will contain 0
2539 * Otherwise, it will contain a non-zero value.
2540 */
2541 Success = (ULONG_PTR)InterlockedCompareExchangePointer(&FileObjectExtension->FilterContext, NULL, FilterContext) - (ULONG_PTR)FilterContext;
2542 }
2543
2544 /* If success isn't 0, it means we failed somewhere (set or unset) */
2545 if (Success != 0)
2546 {
2547 return STATUS_ALREADY_COMMITTED;
2548 }
2549
2550 return STATUS_SUCCESS;
2551 }
2552
2553 NTSTATUS
2554 NTAPI
IopCreateFile(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,IN PLARGE_INTEGER AllocationSize OPTIONAL,IN ULONG FileAttributes,IN ULONG ShareAccess,IN ULONG Disposition,IN ULONG CreateOptions,IN PVOID EaBuffer OPTIONAL,IN ULONG EaLength,IN CREATE_FILE_TYPE CreateFileType,IN PVOID ExtraCreateParameters OPTIONAL,IN ULONG Options,IN ULONG Flags,IN PDEVICE_OBJECT DeviceObject OPTIONAL)2555 IopCreateFile(OUT PHANDLE FileHandle,
2556 IN ACCESS_MASK DesiredAccess,
2557 IN POBJECT_ATTRIBUTES ObjectAttributes,
2558 OUT PIO_STATUS_BLOCK IoStatusBlock,
2559 IN PLARGE_INTEGER AllocationSize OPTIONAL,
2560 IN ULONG FileAttributes,
2561 IN ULONG ShareAccess,
2562 IN ULONG Disposition,
2563 IN ULONG CreateOptions,
2564 IN PVOID EaBuffer OPTIONAL,
2565 IN ULONG EaLength,
2566 IN CREATE_FILE_TYPE CreateFileType,
2567 IN PVOID ExtraCreateParameters OPTIONAL,
2568 IN ULONG Options,
2569 IN ULONG Flags,
2570 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
2571 {
2572 KPROCESSOR_MODE AccessMode;
2573 HANDLE LocalHandle = 0;
2574 LARGE_INTEGER SafeAllocationSize;
2575 NTSTATUS Status = STATUS_SUCCESS;
2576 PNAMED_PIPE_CREATE_PARAMETERS NamedPipeCreateParameters;
2577 POPEN_PACKET OpenPacket;
2578 ULONG EaErrorOffset;
2579 PAGED_CODE();
2580
2581 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
2582
2583
2584 /* Check if we have no parameter checking to do */
2585 if (Options & IO_NO_PARAMETER_CHECKING)
2586 {
2587 /* Then force kernel-mode access to avoid checks */
2588 AccessMode = KernelMode;
2589 }
2590 else
2591 {
2592 /* Otherwise, use the actual mode */
2593 AccessMode = ExGetPreviousMode();
2594 }
2595
2596 /* Check if we need to do parameter checking */
2597 if ((AccessMode != KernelMode) || (Options & IO_CHECK_CREATE_PARAMETERS))
2598 {
2599 /* Validate parameters */
2600 if (FileAttributes & ~FILE_ATTRIBUTE_VALID_FLAGS)
2601 {
2602 DPRINT1("File Create 'FileAttributes' Parameter contains invalid flags!\n");
2603 return STATUS_INVALID_PARAMETER;
2604 }
2605
2606 if (ShareAccess & ~FILE_SHARE_VALID_FLAGS)
2607 {
2608 DPRINT1("File Create 'ShareAccess' Parameter contains invalid flags!\n");
2609 return STATUS_INVALID_PARAMETER;
2610 }
2611
2612 if (Disposition > FILE_MAXIMUM_DISPOSITION)
2613 {
2614 DPRINT1("File Create 'Disposition' Parameter is out of range!\n");
2615 return STATUS_INVALID_PARAMETER;
2616 }
2617
2618 if (CreateOptions & ~FILE_VALID_OPTION_FLAGS)
2619 {
2620 DPRINT1("File Create 'CreateOptions' parameter contains invalid flags!\n");
2621 return STATUS_INVALID_PARAMETER;
2622 }
2623
2624 if ((CreateOptions & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) &&
2625 (!(DesiredAccess & SYNCHRONIZE)))
2626 {
2627 DPRINT1("File Create 'CreateOptions' parameter FILE_SYNCHRONOUS_IO_* requested, but 'DesiredAccess' does not have SYNCHRONIZE!\n");
2628 return STATUS_INVALID_PARAMETER;
2629 }
2630
2631 if ((CreateOptions & FILE_DELETE_ON_CLOSE) && (!(DesiredAccess & DELETE)))
2632 {
2633 DPRINT1("File Create 'CreateOptions' parameter FILE_DELETE_ON_CLOSE requested, but 'DesiredAccess' does not have DELETE!\n");
2634 return STATUS_INVALID_PARAMETER;
2635 }
2636
2637 if ((CreateOptions & (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT)) ==
2638 (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT))
2639 {
2640 DPRINT1("File Create 'FileAttributes' parameter both FILE_SYNCHRONOUS_IO_NONALERT and FILE_SYNCHRONOUS_IO_ALERT specified!\n");
2641 return STATUS_INVALID_PARAMETER;
2642 }
2643
2644 if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
2645 (CreateOptions & ~(FILE_DIRECTORY_FILE |
2646 FILE_SYNCHRONOUS_IO_ALERT |
2647 FILE_SYNCHRONOUS_IO_NONALERT |
2648 FILE_WRITE_THROUGH |
2649 FILE_COMPLETE_IF_OPLOCKED |
2650 FILE_OPEN_FOR_BACKUP_INTENT |
2651 FILE_DELETE_ON_CLOSE |
2652 FILE_OPEN_FOR_FREE_SPACE_QUERY |
2653 FILE_OPEN_BY_FILE_ID |
2654 FILE_NO_COMPRESSION |
2655 FILE_OPEN_REPARSE_POINT)))
2656 {
2657 DPRINT1("File Create 'CreateOptions' Parameter has flags incompatible with FILE_DIRECTORY_FILE!\n");
2658 return STATUS_INVALID_PARAMETER;
2659 }
2660
2661 if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
2662 (Disposition != FILE_CREATE) && (Disposition != FILE_OPEN) && (Disposition != FILE_OPEN_IF))
2663 {
2664 DPRINT1("File Create 'CreateOptions' Parameter FILE_DIRECTORY_FILE requested, but 'Disposition' is not FILE_CREATE/FILE_OPEN/FILE_OPEN_IF!\n");
2665 return STATUS_INVALID_PARAMETER;
2666 }
2667
2668 if ((CreateOptions & FILE_COMPLETE_IF_OPLOCKED) && (CreateOptions & FILE_RESERVE_OPFILTER))
2669 {
2670 DPRINT1("File Create 'CreateOptions' Parameter both FILE_COMPLETE_IF_OPLOCKED and FILE_RESERVE_OPFILTER specified!\n");
2671 return STATUS_INVALID_PARAMETER;
2672 }
2673
2674 if ((CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) && (DesiredAccess & FILE_APPEND_DATA))
2675 {
2676 DPRINT1("File Create 'CreateOptions' parameter FILE_NO_INTERMEDIATE_BUFFERING requested, but 'DesiredAccess' FILE_APPEND_DATA requires it!\n");
2677 return STATUS_INVALID_PARAMETER;
2678 }
2679
2680 /* Now check if this is a named pipe */
2681 if (CreateFileType == CreateFileTypeNamedPipe)
2682 {
2683 /* Make sure we have extra parameters */
2684 if (!ExtraCreateParameters)
2685 {
2686 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2687 return STATUS_INVALID_PARAMETER;
2688 }
2689
2690 /* Get the parameters and validate them */
2691 NamedPipeCreateParameters = ExtraCreateParameters;
2692 if ((NamedPipeCreateParameters->NamedPipeType > FILE_PIPE_MESSAGE_TYPE) ||
2693 (NamedPipeCreateParameters->ReadMode > FILE_PIPE_MESSAGE_MODE) ||
2694 (NamedPipeCreateParameters->CompletionMode > FILE_PIPE_COMPLETE_OPERATION) ||
2695 (ShareAccess & FILE_SHARE_DELETE) ||
2696 ((Disposition < FILE_OPEN) || (Disposition > FILE_OPEN_IF)) ||
2697 (CreateOptions & ~FILE_VALID_PIPE_OPTION_FLAGS))
2698 {
2699 /* Invalid named pipe create */
2700 DPRINT1("Invalid named pipe create\n");
2701 return STATUS_INVALID_PARAMETER;
2702 }
2703 }
2704 else if (CreateFileType == CreateFileTypeMailslot)
2705 {
2706 /* Make sure we have extra parameters */
2707 if (!ExtraCreateParameters)
2708 {
2709 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2710 return STATUS_INVALID_PARAMETER;
2711 }
2712
2713 /* Get the parameters and validate them */
2714 if ((ShareAccess & FILE_SHARE_DELETE) ||
2715 !(ShareAccess & ~FILE_SHARE_WRITE) ||
2716 (Disposition != FILE_CREATE) ||
2717 (CreateOptions & ~FILE_VALID_MAILSLOT_OPTION_FLAGS))
2718 {
2719 /* Invalid mailslot create */
2720 DPRINT1("Invalid mailslot create\n");
2721 return STATUS_INVALID_PARAMETER;
2722 }
2723 }
2724 }
2725
2726 /* Allocate the open packet */
2727 OpenPacket = ExAllocatePoolWithTag(NonPagedPool, sizeof(*OpenPacket), 'pOoI');
2728 if (!OpenPacket) return STATUS_INSUFFICIENT_RESOURCES;
2729 RtlZeroMemory(OpenPacket, sizeof(*OpenPacket));
2730
2731 /* Check if the call came from user mode */
2732 if (AccessMode != KernelMode)
2733 {
2734 _SEH2_TRY
2735 {
2736 /* Probe the output parameters */
2737 ProbeForWriteHandle(FileHandle);
2738 ProbeForWriteIoStatusBlock(IoStatusBlock);
2739
2740 /* Probe the allocation size if one was passed in */
2741 if (AllocationSize)
2742 {
2743 SafeAllocationSize = ProbeForReadLargeInteger(AllocationSize);
2744 }
2745 else
2746 {
2747 SafeAllocationSize.QuadPart = 0;
2748 }
2749
2750 /* Make sure it's valid */
2751 if (SafeAllocationSize.QuadPart < 0)
2752 {
2753 RtlRaiseStatus(STATUS_INVALID_PARAMETER);
2754 }
2755
2756 /* Check if EA was passed in */
2757 if ((EaBuffer) && (EaLength))
2758 {
2759 /* Probe it */
2760 ProbeForRead(EaBuffer, EaLength, sizeof(ULONG));
2761
2762 /* And marshall it */
2763 OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
2764 EaLength,
2765 TAG_EA);
2766 OpenPacket->EaLength = EaLength;
2767 RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
2768
2769 /* Validate the buffer */
2770 Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
2771 EaLength,
2772 &EaErrorOffset);
2773 if (!NT_SUCCESS(Status))
2774 {
2775 /* Undo everything if it's invalid */
2776 DPRINT1("Invalid EA buffer\n");
2777 IoStatusBlock->Status = Status;
2778 IoStatusBlock->Information = EaErrorOffset;
2779 RtlRaiseStatus(Status);
2780 }
2781 }
2782 }
2783 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2784 {
2785 /* Return the exception code */
2786 if (OpenPacket->EaBuffer != NULL) ExFreePool(OpenPacket->EaBuffer);
2787 ExFreePool(OpenPacket);
2788 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2789 }
2790 _SEH2_END;
2791 }
2792 else
2793 {
2794 /* Check if this is a device attach */
2795 if (CreateOptions & IO_ATTACH_DEVICE_API)
2796 {
2797 /* Set the flag properly */
2798 Options |= IO_ATTACH_DEVICE;
2799 CreateOptions &= ~IO_ATTACH_DEVICE_API;
2800 }
2801
2802 /* Check if we have allocation size */
2803 if (AllocationSize)
2804 {
2805 /* Capture it */
2806 SafeAllocationSize = *AllocationSize;
2807 }
2808 else
2809 {
2810 /* Otherwise, no size */
2811 SafeAllocationSize.QuadPart = 0;
2812 }
2813
2814 /* Check if we have an EA packet */
2815 if ((EaBuffer) && (EaLength))
2816 {
2817 /* Allocate the kernel copy */
2818 OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
2819 EaLength,
2820 TAG_EA);
2821 if (!OpenPacket->EaBuffer)
2822 {
2823 ExFreePool(OpenPacket);
2824 DPRINT1("Failed to allocate open packet EA buffer\n");
2825 return STATUS_INSUFFICIENT_RESOURCES;
2826 }
2827
2828 /* Copy the data */
2829 OpenPacket->EaLength = EaLength;
2830 RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
2831
2832 /* Validate the buffer */
2833 Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
2834 EaLength,
2835 &EaErrorOffset);
2836 if (!NT_SUCCESS(Status))
2837 {
2838 /* Undo everything if it's invalid */
2839 DPRINT1("Invalid EA buffer\n");
2840 ExFreePool(OpenPacket->EaBuffer);
2841 IoStatusBlock->Status = Status;
2842 IoStatusBlock->Information = EaErrorOffset;
2843 ExFreePool(OpenPacket);
2844 return Status;
2845 }
2846 }
2847 }
2848
2849 /* Setup the Open Packet */
2850 OpenPacket->Type = IO_TYPE_OPEN_PACKET;
2851 OpenPacket->Size = sizeof(*OpenPacket);
2852 OpenPacket->AllocationSize = SafeAllocationSize;
2853 OpenPacket->CreateOptions = CreateOptions;
2854 OpenPacket->FileAttributes = (USHORT)FileAttributes;
2855 OpenPacket->ShareAccess = (USHORT)ShareAccess;
2856 OpenPacket->Options = Options;
2857 OpenPacket->Disposition = Disposition;
2858 OpenPacket->CreateFileType = CreateFileType;
2859 OpenPacket->ExtraCreateParameters = ExtraCreateParameters;
2860 OpenPacket->InternalFlags = Flags;
2861 OpenPacket->TopDeviceObjectHint = DeviceObject;
2862
2863 /* Update the operation count */
2864 IopUpdateOperationCount(IopOtherTransfer);
2865
2866 /*
2867 * Attempt opening the file. This will call the I/O Parse Routine for
2868 * the File Object (IopParseDevice) which will create the object and
2869 * send the IRP to its device object. Note that we have two statuses
2870 * to worry about: the Object Manager's status (in Status) and the I/O
2871 * status, which is in the Open Packet's Final Status, and determined
2872 * by the Parse Check member.
2873 */
2874 Status = ObOpenObjectByName(ObjectAttributes,
2875 NULL,
2876 AccessMode,
2877 NULL,
2878 DesiredAccess,
2879 OpenPacket,
2880 &LocalHandle);
2881
2882 /* Free the EA Buffer */
2883 if (OpenPacket->EaBuffer) ExFreePool(OpenPacket->EaBuffer);
2884
2885 /* Now check for Ob or Io failure */
2886 if (!(NT_SUCCESS(Status)) || (OpenPacket->ParseCheck == FALSE))
2887 {
2888 /* Check if Ob thinks well went well */
2889 if (NT_SUCCESS(Status))
2890 {
2891 /*
2892 * Tell it otherwise. Because we didn't use an ObjectType,
2893 * it incorrectly returned us a handle to God knows what.
2894 */
2895 ZwClose(LocalHandle);
2896 Status = STATUS_OBJECT_TYPE_MISMATCH;
2897 }
2898
2899 /* Now check the Io status */
2900 if (!NT_SUCCESS(OpenPacket->FinalStatus))
2901 {
2902 /* Use this status instead of Ob's */
2903 Status = OpenPacket->FinalStatus;
2904
2905 /* Check if it was only a warning */
2906 if (NT_WARNING(Status))
2907 {
2908 /* Protect write with SEH */
2909 _SEH2_TRY
2910 {
2911 /* In this case, we copy the I/O Status back */
2912 IoStatusBlock->Information = OpenPacket->Information;
2913 IoStatusBlock->Status = OpenPacket->FinalStatus;
2914 }
2915 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2916 {
2917 /* Get exception code */
2918 Status = _SEH2_GetExceptionCode();
2919 }
2920 _SEH2_END;
2921 }
2922 }
2923 else if ((OpenPacket->FileObject) && (OpenPacket->ParseCheck == FALSE))
2924 {
2925 /*
2926 * This can happen in the very bizarre case where the parse routine
2927 * actually executed more then once (due to a reparse) and ended
2928 * up failing after already having created the File Object.
2929 */
2930 if (OpenPacket->FileObject->FileName.Length)
2931 {
2932 /* It had a name, free it */
2933 ExFreePoolWithTag(OpenPacket->FileObject->FileName.Buffer, TAG_IO_NAME);
2934 }
2935
2936 /* Clear the device object to invalidate the FO, and dereference */
2937 OpenPacket->FileObject->DeviceObject = NULL;
2938 ObDereferenceObject(OpenPacket->FileObject);
2939 }
2940 }
2941 else
2942 {
2943 /* We reached success and have a valid file handle */
2944 OpenPacket->FileObject->Flags |= FO_HANDLE_CREATED;
2945 ASSERT(OpenPacket->FileObject->Type == IO_TYPE_FILE);
2946
2947 /* Enter SEH for write back */
2948 _SEH2_TRY
2949 {
2950 /* Write back the handle and I/O Status */
2951 *FileHandle = LocalHandle;
2952 IoStatusBlock->Information = OpenPacket->Information;
2953 IoStatusBlock->Status = OpenPacket->FinalStatus;
2954
2955 /* Get the Io status */
2956 Status = OpenPacket->FinalStatus;
2957 }
2958 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2959 {
2960 /* Get the exception status */
2961 Status = _SEH2_GetExceptionCode();
2962 }
2963 _SEH2_END;
2964 }
2965
2966 /* Check if we were 100% successful */
2967 if ((OpenPacket->ParseCheck != FALSE) && (OpenPacket->FileObject))
2968 {
2969 /* Dereference the File Object */
2970 ObDereferenceObject(OpenPacket->FileObject);
2971 }
2972
2973 /* Return status */
2974 ExFreePool(OpenPacket);
2975 return Status;
2976 }
2977
2978 /* FUNCTIONS *****************************************************************/
2979
2980 /*
2981 * @unimplemented
2982 */
2983 NTSTATUS
2984 NTAPI
IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,IN ULONG Length,IN BOOLEAN SetOperation)2985 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
2986 IN ULONG Length,
2987 IN BOOLEAN SetOperation)
2988 {
2989 UNIMPLEMENTED;
2990 return STATUS_NOT_IMPLEMENTED;
2991 }
2992
2993 /*
2994 * @unimplemented
2995 */
2996 NTSTATUS
2997 NTAPI
IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,IN ULONG QuotaLength,OUT PULONG ErrorOffset)2998 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
2999 IN ULONG QuotaLength,
3000 OUT PULONG ErrorOffset)
3001 {
3002 UNIMPLEMENTED;
3003 return STATUS_NOT_IMPLEMENTED;
3004 }
3005
3006 /*
3007 * @implemented
3008 */
3009 NTSTATUS
3010 NTAPI
IoCreateFile(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,IN PLARGE_INTEGER AllocationSize OPTIONAL,IN ULONG FileAttributes,IN ULONG ShareAccess,IN ULONG Disposition,IN ULONG CreateOptions,IN PVOID EaBuffer OPTIONAL,IN ULONG EaLength,IN CREATE_FILE_TYPE CreateFileType,IN PVOID ExtraCreateParameters OPTIONAL,IN ULONG Options)3011 IoCreateFile(OUT PHANDLE FileHandle,
3012 IN ACCESS_MASK DesiredAccess,
3013 IN POBJECT_ATTRIBUTES ObjectAttributes,
3014 OUT PIO_STATUS_BLOCK IoStatusBlock,
3015 IN PLARGE_INTEGER AllocationSize OPTIONAL,
3016 IN ULONG FileAttributes,
3017 IN ULONG ShareAccess,
3018 IN ULONG Disposition,
3019 IN ULONG CreateOptions,
3020 IN PVOID EaBuffer OPTIONAL,
3021 IN ULONG EaLength,
3022 IN CREATE_FILE_TYPE CreateFileType,
3023 IN PVOID ExtraCreateParameters OPTIONAL,
3024 IN ULONG Options)
3025 {
3026 PAGED_CODE();
3027
3028 return IopCreateFile(FileHandle,
3029 DesiredAccess,
3030 ObjectAttributes,
3031 IoStatusBlock,
3032 AllocationSize,
3033 FileAttributes,
3034 ShareAccess,
3035 Disposition,
3036 CreateOptions,
3037 EaBuffer,
3038 EaLength,
3039 CreateFileType,
3040 ExtraCreateParameters,
3041 Options,
3042 0,
3043 NULL);
3044 }
3045
3046 /*
3047 * @unimplemented
3048 */
3049 NTSTATUS
3050 NTAPI
IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,IN PLARGE_INTEGER AllocationSize OPTIONAL,IN ULONG FileAttributes,IN ULONG ShareAccess,IN ULONG Disposition,IN ULONG CreateOptions,IN PVOID EaBuffer OPTIONAL,IN ULONG EaLength,IN CREATE_FILE_TYPE CreateFileType,IN PVOID ExtraCreateParameters OPTIONAL,IN ULONG Options,IN PVOID DeviceObject)3051 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle,
3052 IN ACCESS_MASK DesiredAccess,
3053 IN POBJECT_ATTRIBUTES ObjectAttributes,
3054 OUT PIO_STATUS_BLOCK IoStatusBlock,
3055 IN PLARGE_INTEGER AllocationSize OPTIONAL,
3056 IN ULONG FileAttributes,
3057 IN ULONG ShareAccess,
3058 IN ULONG Disposition,
3059 IN ULONG CreateOptions,
3060 IN PVOID EaBuffer OPTIONAL,
3061 IN ULONG EaLength,
3062 IN CREATE_FILE_TYPE CreateFileType,
3063 IN PVOID ExtraCreateParameters OPTIONAL,
3064 IN ULONG Options,
3065 IN PVOID DeviceObject)
3066 {
3067 ULONG Flags = 0;
3068
3069 PAGED_CODE();
3070
3071 /* Check if we were passed a device to send the create request to*/
3072 if (DeviceObject)
3073 {
3074 /* We'll tag this request into a file object extension */
3075 Flags = (IOP_CREATE_FILE_OBJECT_EXTENSION | IOP_USE_TOP_LEVEL_DEVICE_HINT);
3076 }
3077
3078 return IopCreateFile(FileHandle,
3079 DesiredAccess,
3080 ObjectAttributes,
3081 IoStatusBlock,
3082 AllocationSize,
3083 FileAttributes,
3084 ShareAccess,
3085 Disposition,
3086 CreateOptions,
3087 EaBuffer,
3088 EaLength,
3089 CreateFileType,
3090 ExtraCreateParameters,
3091 Options | IO_NO_PARAMETER_CHECKING,
3092 Flags,
3093 DeviceObject);
3094 }
3095
3096 /*
3097 * @implemented
3098 */
3099 PFILE_OBJECT
3100 NTAPI
IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL,IN PDEVICE_OBJECT DeviceObject OPTIONAL,OUT PHANDLE FileObjectHandle OPTIONAL)3101 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL,
3102 IN PDEVICE_OBJECT DeviceObject OPTIONAL,
3103 OUT PHANDLE FileObjectHandle OPTIONAL)
3104 {
3105 PFILE_OBJECT CreatedFileObject;
3106 NTSTATUS Status;
3107 HANDLE FileHandle;
3108 OBJECT_ATTRIBUTES ObjectAttributes;
3109 PAGED_CODE();
3110 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
3111
3112 /* Choose Device Object */
3113 if (FileObject) DeviceObject = FileObject->DeviceObject;
3114
3115 /* Reference the device object and initialize attributes */
3116 InterlockedIncrement(&DeviceObject->ReferenceCount);
3117 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
3118
3119 /* Create the File Object */
3120 Status = ObCreateObject(KernelMode,
3121 IoFileObjectType,
3122 &ObjectAttributes,
3123 KernelMode,
3124 NULL,
3125 sizeof(FILE_OBJECT),
3126 sizeof(FILE_OBJECT),
3127 0,
3128 (PVOID*)&CreatedFileObject);
3129 if (!NT_SUCCESS(Status))
3130 {
3131 /* Fail */
3132 IopDereferenceDeviceObject(DeviceObject, FALSE);
3133 ExRaiseStatus(Status);
3134 }
3135
3136 /* Set File Object Data */
3137 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
3138 CreatedFileObject->DeviceObject = DeviceObject;
3139 CreatedFileObject->Type = IO_TYPE_FILE;
3140 CreatedFileObject->Size = sizeof(FILE_OBJECT);
3141 CreatedFileObject->Flags = FO_STREAM_FILE;
3142
3143 /* Initialize the wait event */
3144 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
3145
3146 /* Insert it to create a handle for it */
3147 Status = ObInsertObject(CreatedFileObject,
3148 NULL,
3149 FILE_READ_DATA,
3150 1,
3151 (PVOID*)&CreatedFileObject,
3152 &FileHandle);
3153 if (!NT_SUCCESS(Status)) ExRaiseStatus(Status);
3154
3155 /* Set the handle created flag */
3156 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
3157 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
3158
3159 /* Check if we have a VPB */
3160 if (DeviceObject->Vpb)
3161 {
3162 /* Reference it */
3163 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
3164 }
3165
3166 /* Check if the caller wants the handle */
3167 if (FileObjectHandle)
3168 {
3169 /* Return it */
3170 *FileObjectHandle = FileHandle;
3171 ObDereferenceObject(CreatedFileObject);
3172 }
3173 else
3174 {
3175 /* Otherwise, close it */
3176 ObCloseHandle(FileHandle, KernelMode);
3177 }
3178
3179 /* Return the file object */
3180 return CreatedFileObject;
3181 }
3182
3183 /*
3184 * @implemented
3185 */
3186 PFILE_OBJECT
3187 NTAPI
IoCreateStreamFileObject(IN PFILE_OBJECT FileObject,IN PDEVICE_OBJECT DeviceObject)3188 IoCreateStreamFileObject(IN PFILE_OBJECT FileObject,
3189 IN PDEVICE_OBJECT DeviceObject)
3190 {
3191 /* Call the newer function */
3192 return IoCreateStreamFileObjectEx(FileObject, DeviceObject, NULL);
3193 }
3194
3195 /*
3196 * @implemented
3197 */
3198 PFILE_OBJECT
3199 NTAPI
IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL,IN PDEVICE_OBJECT DeviceObject OPTIONAL)3200 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL,
3201 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
3202 {
3203 PFILE_OBJECT CreatedFileObject;
3204 NTSTATUS Status;
3205 OBJECT_ATTRIBUTES ObjectAttributes;
3206 PAGED_CODE();
3207 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
3208
3209 /* Choose Device Object */
3210 if (FileObject) DeviceObject = FileObject->DeviceObject;
3211
3212 /* Reference the device object and initialize attributes */
3213 InterlockedIncrement(&DeviceObject->ReferenceCount);
3214 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
3215
3216 /* Create the File Object */
3217 Status = ObCreateObject(KernelMode,
3218 IoFileObjectType,
3219 &ObjectAttributes,
3220 KernelMode,
3221 NULL,
3222 sizeof(FILE_OBJECT),
3223 sizeof(FILE_OBJECT),
3224 0,
3225 (PVOID*)&CreatedFileObject);
3226 if (!NT_SUCCESS(Status))
3227 {
3228 /* Fail */
3229 IopDereferenceDeviceObject(DeviceObject, FALSE);
3230 ExRaiseStatus(Status);
3231 }
3232
3233 /* Set File Object Data */
3234 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
3235 CreatedFileObject->DeviceObject = DeviceObject;
3236 CreatedFileObject->Type = IO_TYPE_FILE;
3237 CreatedFileObject->Size = sizeof(FILE_OBJECT);
3238 CreatedFileObject->Flags = FO_STREAM_FILE;
3239
3240 /* Initialize the wait event */
3241 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
3242
3243 /* Destroy create information */
3244 ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->
3245 ObjectCreateInfo);
3246 OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->ObjectCreateInfo = NULL;
3247
3248 /* Set the handle created flag */
3249 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
3250 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
3251
3252 /* Check if we have a VPB */
3253 if (DeviceObject->Vpb)
3254 {
3255 /* Reference it */
3256 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
3257 }
3258
3259 /* Return the file object */
3260 return CreatedFileObject;
3261 }
3262
3263 /*
3264 * @implemented
3265 */
3266 PGENERIC_MAPPING
3267 NTAPI
IoGetFileObjectGenericMapping(VOID)3268 IoGetFileObjectGenericMapping(VOID)
3269 {
3270 /* Return the mapping */
3271 return &IopFileMapping;
3272 }
3273
3274 /*
3275 * @implemented
3276 */
3277 BOOLEAN
3278 NTAPI
IoIsFileOriginRemote(IN PFILE_OBJECT FileObject)3279 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject)
3280 {
3281 /* Return the flag status */
3282 return FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
3283 }
3284
3285 /*
3286 * @implemented
3287 */
3288 BOOLEAN
3289 NTAPI
IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,IN ACCESS_MASK DesiredAccess,IN ULONG OpenOptions,OUT PIO_STATUS_BLOCK IoStatus,OUT PFILE_NETWORK_OPEN_INFORMATION Buffer)3290 IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
3291 IN ACCESS_MASK DesiredAccess,
3292 IN ULONG OpenOptions,
3293 OUT PIO_STATUS_BLOCK IoStatus,
3294 OUT PFILE_NETWORK_OPEN_INFORMATION Buffer)
3295 {
3296 NTSTATUS Status;
3297 DUMMY_FILE_OBJECT LocalFileObject;
3298 HANDLE Handle;
3299 OPEN_PACKET OpenPacket;
3300 PAGED_CODE();
3301 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
3302
3303 /* Setup the Open Packet */
3304 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
3305 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
3306 OpenPacket.Size = sizeof(OPEN_PACKET);
3307 OpenPacket.CreateOptions = OpenOptions | FILE_OPEN_REPARSE_POINT;
3308 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
3309 OpenPacket.Options = IO_FORCE_ACCESS_CHECK;
3310 OpenPacket.Disposition = FILE_OPEN;
3311 OpenPacket.NetworkInformation = Buffer;
3312 OpenPacket.QueryOnly = TRUE;
3313 OpenPacket.FullAttributes = TRUE;
3314 OpenPacket.LocalFileObject = &LocalFileObject;
3315
3316 /*
3317 * Attempt opening the file. This will call the I/O Parse Routine for
3318 * the File Object (IopParseDevice) which will use the dummy file obejct
3319 * send the IRP to its device object. Note that we have two statuses
3320 * to worry about: the Object Manager's status (in Status) and the I/O
3321 * status, which is in the Open Packet's Final Status, and determined
3322 * by the Parse Check member.
3323 */
3324 Status = ObOpenObjectByName(ObjectAttributes,
3325 NULL,
3326 KernelMode,
3327 NULL,
3328 DesiredAccess,
3329 &OpenPacket,
3330 &Handle);
3331 if (OpenPacket.ParseCheck == FALSE)
3332 {
3333 /* Parse failed */
3334 IoStatus->Status = Status;
3335 }
3336 else
3337 {
3338 /* Use the Io status */
3339 IoStatus->Status = OpenPacket.FinalStatus;
3340 IoStatus->Information = OpenPacket.Information;
3341 }
3342
3343 /* Return success */
3344 return TRUE;
3345 }
3346
3347 /*
3348 * @implemented
3349 */
3350 VOID
3351 NTAPI
IoUpdateShareAccess(IN PFILE_OBJECT FileObject,OUT PSHARE_ACCESS ShareAccess)3352 IoUpdateShareAccess(IN PFILE_OBJECT FileObject,
3353 OUT PSHARE_ACCESS ShareAccess)
3354 {
3355 PAGED_CODE();
3356
3357 /* Check if the file has an extension */
3358 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3359 {
3360 /* Check if caller specified to ignore access checks */
3361 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3362 {
3363 /* Don't update share access */
3364 return;
3365 }
3366 }
3367
3368 /* Otherwise, check if there's any access present */
3369 if ((FileObject->ReadAccess) ||
3370 (FileObject->WriteAccess) ||
3371 (FileObject->DeleteAccess))
3372 {
3373 /* Increase the open count */
3374 ShareAccess->OpenCount++;
3375
3376 /* Add new share access */
3377 ShareAccess->Readers += FileObject->ReadAccess;
3378 ShareAccess->Writers += FileObject->WriteAccess;
3379 ShareAccess->Deleters += FileObject->DeleteAccess;
3380 ShareAccess->SharedRead += FileObject->SharedRead;
3381 ShareAccess->SharedWrite += FileObject->SharedWrite;
3382 ShareAccess->SharedDelete += FileObject->SharedDelete;
3383 }
3384 }
3385
3386 /*
3387 * @implemented
3388 */
3389 NTSTATUS
3390 NTAPI
IoCheckShareAccess(IN ACCESS_MASK DesiredAccess,IN ULONG DesiredShareAccess,IN PFILE_OBJECT FileObject,IN PSHARE_ACCESS ShareAccess,IN BOOLEAN Update)3391 IoCheckShareAccess(IN ACCESS_MASK DesiredAccess,
3392 IN ULONG DesiredShareAccess,
3393 IN PFILE_OBJECT FileObject,
3394 IN PSHARE_ACCESS ShareAccess,
3395 IN BOOLEAN Update)
3396 {
3397 BOOLEAN ReadAccess;
3398 BOOLEAN WriteAccess;
3399 BOOLEAN DeleteAccess;
3400 BOOLEAN SharedRead;
3401 BOOLEAN SharedWrite;
3402 BOOLEAN SharedDelete;
3403 PAGED_CODE();
3404
3405 /* Get access masks */
3406 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
3407 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
3408 DeleteAccess = (DesiredAccess & DELETE) != 0;
3409
3410 /* Set them in the file object */
3411 FileObject->ReadAccess = ReadAccess;
3412 FileObject->WriteAccess = WriteAccess;
3413 FileObject->DeleteAccess = DeleteAccess;
3414
3415 /* Check if the file has an extension */
3416 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3417 {
3418 /* Check if caller specified to ignore access checks */
3419 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3420 {
3421 /* Don't check share access */
3422 return STATUS_SUCCESS;
3423 }
3424 }
3425
3426 /* Check if we have any access */
3427 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
3428 {
3429 /* Get shared access masks */
3430 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
3431 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
3432 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
3433
3434 /* Check if the shared access is violated */
3435 if ((ReadAccess &&
3436 (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
3437 (WriteAccess &&
3438 (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
3439 (DeleteAccess &&
3440 (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
3441 ((ShareAccess->Readers != 0) && !SharedRead) ||
3442 ((ShareAccess->Writers != 0) && !SharedWrite) ||
3443 ((ShareAccess->Deleters != 0) && !SharedDelete))
3444 {
3445 /* Sharing violation, fail */
3446 return STATUS_SHARING_VIOLATION;
3447 }
3448
3449 /* Set them */
3450 FileObject->SharedRead = SharedRead;
3451 FileObject->SharedWrite = SharedWrite;
3452 FileObject->SharedDelete = SharedDelete;
3453
3454 /* It's not, check if caller wants us to update it */
3455 if (Update)
3456 {
3457 /* Increase open count */
3458 ShareAccess->OpenCount++;
3459
3460 /* Update shared access */
3461 ShareAccess->Readers += ReadAccess;
3462 ShareAccess->Writers += WriteAccess;
3463 ShareAccess->Deleters += DeleteAccess;
3464 ShareAccess->SharedRead += SharedRead;
3465 ShareAccess->SharedWrite += SharedWrite;
3466 ShareAccess->SharedDelete += SharedDelete;
3467 }
3468 }
3469
3470 /* Validation successful */
3471 return STATUS_SUCCESS;
3472 }
3473
3474 /*
3475 * @implemented
3476 */
3477 VOID
3478 NTAPI
IoRemoveShareAccess(IN PFILE_OBJECT FileObject,IN PSHARE_ACCESS ShareAccess)3479 IoRemoveShareAccess(IN PFILE_OBJECT FileObject,
3480 IN PSHARE_ACCESS ShareAccess)
3481 {
3482 PAGED_CODE();
3483
3484 /* Check if the file has an extension */
3485 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3486 {
3487 /* Check if caller specified to ignore access checks */
3488 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3489 {
3490 /* Don't update share access */
3491 return;
3492 }
3493 }
3494
3495 /* Otherwise, check if there's any access present */
3496 if ((FileObject->ReadAccess) ||
3497 (FileObject->WriteAccess) ||
3498 (FileObject->DeleteAccess))
3499 {
3500 /* Decrement the open count */
3501 ShareAccess->OpenCount--;
3502
3503 /* Remove share access */
3504 ShareAccess->Readers -= FileObject->ReadAccess;
3505 ShareAccess->Writers -= FileObject->WriteAccess;
3506 ShareAccess->Deleters -= FileObject->DeleteAccess;
3507 ShareAccess->SharedRead -= FileObject->SharedRead;
3508 ShareAccess->SharedWrite -= FileObject->SharedWrite;
3509 ShareAccess->SharedDelete -= FileObject->SharedDelete;
3510 }
3511 }
3512
3513 /*
3514 * @implemented
3515 */
3516 VOID
3517 NTAPI
IoSetShareAccess(IN ACCESS_MASK DesiredAccess,IN ULONG DesiredShareAccess,IN PFILE_OBJECT FileObject,OUT PSHARE_ACCESS ShareAccess)3518 IoSetShareAccess(IN ACCESS_MASK DesiredAccess,
3519 IN ULONG DesiredShareAccess,
3520 IN PFILE_OBJECT FileObject,
3521 OUT PSHARE_ACCESS ShareAccess)
3522 {
3523 BOOLEAN ReadAccess;
3524 BOOLEAN WriteAccess;
3525 BOOLEAN DeleteAccess;
3526 BOOLEAN SharedRead;
3527 BOOLEAN SharedWrite;
3528 BOOLEAN SharedDelete;
3529 BOOLEAN Update = TRUE;
3530 PAGED_CODE();
3531
3532 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
3533 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
3534 DeleteAccess = (DesiredAccess & DELETE) != 0;
3535
3536 /* Check if the file has an extension */
3537 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3538 {
3539 /* Check if caller specified to ignore access checks */
3540 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3541 {
3542 /* Don't update share access */
3543 Update = FALSE;
3544 }
3545 }
3546
3547 /* Update basic access */
3548 FileObject->ReadAccess = ReadAccess;
3549 FileObject->WriteAccess = WriteAccess;
3550 FileObject->DeleteAccess = DeleteAccess;
3551
3552 /* Check if we have no access as all */
3553 if (!(ReadAccess) && !(WriteAccess) && !(DeleteAccess))
3554 {
3555 /* Check if we need to update the structure */
3556 if (!Update) return;
3557
3558 /* Otherwise, clear data */
3559 ShareAccess->OpenCount = 0;
3560 ShareAccess->Readers = 0;
3561 ShareAccess->Writers = 0;
3562 ShareAccess->Deleters = 0;
3563 ShareAccess->SharedRead = 0;
3564 ShareAccess->SharedWrite = 0;
3565 ShareAccess->SharedDelete = 0;
3566 }
3567 else
3568 {
3569 /* Calculate shared access */
3570 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
3571 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
3572 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
3573
3574 /* Set it in the FO */
3575 FileObject->SharedRead = SharedRead;
3576 FileObject->SharedWrite = SharedWrite;
3577 FileObject->SharedDelete = SharedDelete;
3578
3579 /* Check if we need to update the structure */
3580 if (!Update) return;
3581
3582 /* Otherwise, set data */
3583 ShareAccess->OpenCount = 1;
3584 ShareAccess->Readers = ReadAccess;
3585 ShareAccess->Writers = WriteAccess;
3586 ShareAccess->Deleters = DeleteAccess;
3587 ShareAccess->SharedRead = SharedRead;
3588 ShareAccess->SharedWrite = SharedWrite;
3589 ShareAccess->SharedDelete = SharedDelete;
3590 }
3591 }
3592
3593 /*
3594 * @implemented
3595 */
3596 VOID
3597 NTAPI
IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject,IN PFILE_OBJECT FileObject)3598 IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject,
3599 IN PFILE_OBJECT FileObject)
3600 {
3601 PIRP Irp;
3602 KEVENT Event;
3603 KIRQL OldIrql;
3604 NTSTATUS Status;
3605 PIO_STACK_LOCATION Stack;
3606
3607 /* Check if handles were already created for the
3608 * open file. If so, that's over.
3609 */
3610 if (FileObject->Flags & FO_HANDLE_CREATED)
3611 KeBugCheckEx(INVALID_CANCEL_OF_FILE_OPEN,
3612 (ULONG_PTR)FileObject,
3613 (ULONG_PTR)DeviceObject, 0, 0);
3614
3615 /* Reset the events */
3616 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
3617 KeClearEvent(&FileObject->Event);
3618
3619 /* Allocate the IRP we'll use */
3620 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
3621 /* Properly set it */
3622 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3623 Irp->UserEvent = &Event;
3624 Irp->UserIosb = &Irp->IoStatus;
3625 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3626 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3627 Irp->RequestorMode = KernelMode;
3628 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
3629
3630 Stack = IoGetNextIrpStackLocation(Irp);
3631 Stack->MajorFunction = IRP_MJ_CLEANUP;
3632 Stack->FileObject = FileObject;
3633
3634 /* Put on top of IRPs list of the thread */
3635 IopQueueIrpToThread(Irp);
3636
3637 /* Call the driver */
3638 Status = IoCallDriver(DeviceObject, Irp);
3639 if (Status == STATUS_PENDING)
3640 {
3641 KeWaitForSingleObject(&Event, UserRequest,
3642 KernelMode, FALSE, NULL);
3643 }
3644
3645 /* Remove from IRPs list */
3646 KeRaiseIrql(APC_LEVEL, &OldIrql);
3647 IopUnQueueIrpFromThread(Irp);
3648 KeLowerIrql(OldIrql);
3649
3650 /* Free the IRP */
3651 IoFreeIrp(Irp);
3652
3653 /* Clear the event */
3654 KeClearEvent(&FileObject->Event);
3655 /* And finally, mark the open operation as canceled */
3656 FileObject->Flags |= FO_FILE_OPEN_CANCELLED;
3657 }
3658
3659 /*
3660 * @implemented
3661 */
3662 NTSTATUS
3663 NTAPI
IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject,OUT POBJECT_NAME_INFORMATION * ObjectNameInformation)3664 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject,
3665 OUT POBJECT_NAME_INFORMATION *ObjectNameInformation)
3666 {
3667 NTSTATUS Status;
3668 ULONG Length, ReturnLength;
3669 POBJECT_NAME_INFORMATION LocalInfo;
3670
3671 /* Start with a buffer length of 200 */
3672 ReturnLength = 200;
3673 /*
3674 * We'll loop until query works.
3675 * We will use returned length for next loop
3676 * iteration, trying to have a big enough buffer.
3677 */
3678 for (Length = 200; ; Length = ReturnLength)
3679 {
3680 /* Allocate our work buffer */
3681 LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, 'nDoI');
3682 if (LocalInfo == NULL)
3683 {
3684 return STATUS_INSUFFICIENT_RESOURCES;
3685 }
3686
3687 /* Query the DOS name */
3688 Status = IopQueryNameInternal(FileObject,
3689 TRUE,
3690 TRUE,
3691 LocalInfo,
3692 Length,
3693 &ReturnLength,
3694 KernelMode);
3695 /* If it succeed, nothing more to do */
3696 if (Status == STATUS_SUCCESS)
3697 {
3698 break;
3699 }
3700
3701 /* Otherwise, prepare for re-allocation */
3702 ExFreePoolWithTag(LocalInfo, 'nDoI');
3703
3704 /*
3705 * If we failed because of something else
3706 * than memory, simply stop and fail here
3707 */
3708 if (Status != STATUS_BUFFER_OVERFLOW)
3709 {
3710 return Status;
3711 }
3712 }
3713
3714 /* Success case here: return our buffer */
3715 *ObjectNameInformation = LocalInfo;
3716 return STATUS_SUCCESS;
3717 }
3718
3719 /*
3720 * @implemented
3721 */
3722 NTSTATUS
3723 NTAPI
IoSetFileOrigin(IN PFILE_OBJECT FileObject,IN BOOLEAN Remote)3724 IoSetFileOrigin(IN PFILE_OBJECT FileObject,
3725 IN BOOLEAN Remote)
3726 {
3727 NTSTATUS Status = STATUS_SUCCESS;
3728 BOOLEAN FlagSet;
3729
3730 /* Get the flag status */
3731 FlagSet = FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
3732
3733 /* Don't set the flag if it was set already, and don't remove it if it wasn't set */
3734 if (Remote && !FlagSet)
3735 {
3736 /* Set the flag */
3737 FileObject->Flags |= FO_REMOTE_ORIGIN;
3738 }
3739 else if (!Remote && FlagSet)
3740 {
3741 /* Remove the flag */
3742 FileObject->Flags &= ~FO_REMOTE_ORIGIN;
3743 }
3744 else
3745 {
3746 /* Fail */
3747 Status = STATUS_INVALID_PARAMETER_MIX;
3748 }
3749
3750 /* Return status */
3751 return Status;
3752 }
3753
3754 /*
3755 * @implemented
3756 */
3757 NTSTATUS
3758 NTAPI
NtCreateFile(PHANDLE FileHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,PIO_STATUS_BLOCK IoStatusBlock,PLARGE_INTEGER AllocateSize,ULONG FileAttributes,ULONG ShareAccess,ULONG CreateDisposition,ULONG CreateOptions,PVOID EaBuffer,ULONG EaLength)3759 NtCreateFile(PHANDLE FileHandle,
3760 ACCESS_MASK DesiredAccess,
3761 POBJECT_ATTRIBUTES ObjectAttributes,
3762 PIO_STATUS_BLOCK IoStatusBlock,
3763 PLARGE_INTEGER AllocateSize,
3764 ULONG FileAttributes,
3765 ULONG ShareAccess,
3766 ULONG CreateDisposition,
3767 ULONG CreateOptions,
3768 PVOID EaBuffer,
3769 ULONG EaLength)
3770 {
3771 /* Call the I/O Function */
3772 return IoCreateFile(FileHandle,
3773 DesiredAccess,
3774 ObjectAttributes,
3775 IoStatusBlock,
3776 AllocateSize,
3777 FileAttributes,
3778 ShareAccess,
3779 CreateDisposition,
3780 CreateOptions,
3781 EaBuffer,
3782 EaLength,
3783 CreateFileTypeNone,
3784 NULL,
3785 0);
3786 }
3787
3788 NTSTATUS
3789 NTAPI
NtCreateMailslotFile(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,IN ULONG CreateOptions,IN ULONG MailslotQuota,IN ULONG MaxMessageSize,IN PLARGE_INTEGER TimeOut)3790 NtCreateMailslotFile(OUT PHANDLE FileHandle,
3791 IN ACCESS_MASK DesiredAccess,
3792 IN POBJECT_ATTRIBUTES ObjectAttributes,
3793 OUT PIO_STATUS_BLOCK IoStatusBlock,
3794 IN ULONG CreateOptions,
3795 IN ULONG MailslotQuota,
3796 IN ULONG MaxMessageSize,
3797 IN PLARGE_INTEGER TimeOut)
3798 {
3799 MAILSLOT_CREATE_PARAMETERS Buffer;
3800 PAGED_CODE();
3801
3802 /* Check for Timeout */
3803 if (TimeOut)
3804 {
3805 /* check if the call came from user mode */
3806 if (KeGetPreviousMode() != KernelMode)
3807 {
3808 /* Enter SEH for Probe */
3809 _SEH2_TRY
3810 {
3811 /* Probe the timeout */
3812 Buffer.ReadTimeout = ProbeForReadLargeInteger(TimeOut);
3813 }
3814 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3815 {
3816 /* Return the exception code */
3817 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3818 }
3819 _SEH2_END;
3820 }
3821 else
3822 {
3823 /* Otherwise, capture directly */
3824 Buffer.ReadTimeout = *TimeOut;
3825 }
3826
3827 /* Set the correct setting */
3828 Buffer.TimeoutSpecified = TRUE;
3829 }
3830 else
3831 {
3832 /* Tell the FSD we don't have a timeout */
3833 Buffer.TimeoutSpecified = FALSE;
3834 }
3835
3836 /* Set Settings */
3837 Buffer.MailslotQuota = MailslotQuota;
3838 Buffer.MaximumMessageSize = MaxMessageSize;
3839
3840 /* Call I/O */
3841 return IoCreateFile(FileHandle,
3842 DesiredAccess,
3843 ObjectAttributes,
3844 IoStatusBlock,
3845 NULL,
3846 0,
3847 FILE_SHARE_READ | FILE_SHARE_WRITE,
3848 FILE_CREATE,
3849 CreateOptions,
3850 NULL,
3851 0,
3852 CreateFileTypeMailslot,
3853 (PVOID)&Buffer,
3854 0);
3855 }
3856
3857 NTSTATUS
3858 NTAPI
NtCreateNamedPipeFile(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,IN ULONG ShareAccess,IN ULONG CreateDisposition,IN ULONG CreateOptions,IN ULONG NamedPipeType,IN ULONG ReadMode,IN ULONG CompletionMode,IN ULONG MaximumInstances,IN ULONG InboundQuota,IN ULONG OutboundQuota,IN PLARGE_INTEGER DefaultTimeout)3859 NtCreateNamedPipeFile(OUT PHANDLE FileHandle,
3860 IN ACCESS_MASK DesiredAccess,
3861 IN POBJECT_ATTRIBUTES ObjectAttributes,
3862 OUT PIO_STATUS_BLOCK IoStatusBlock,
3863 IN ULONG ShareAccess,
3864 IN ULONG CreateDisposition,
3865 IN ULONG CreateOptions,
3866 IN ULONG NamedPipeType,
3867 IN ULONG ReadMode,
3868 IN ULONG CompletionMode,
3869 IN ULONG MaximumInstances,
3870 IN ULONG InboundQuota,
3871 IN ULONG OutboundQuota,
3872 IN PLARGE_INTEGER DefaultTimeout)
3873 {
3874 NAMED_PIPE_CREATE_PARAMETERS Buffer;
3875 PAGED_CODE();
3876
3877 /* Check for Timeout */
3878 if (DefaultTimeout)
3879 {
3880 /* check if the call came from user mode */
3881 if (KeGetPreviousMode() != KernelMode)
3882 {
3883 /* Enter SEH for Probe */
3884 _SEH2_TRY
3885 {
3886 /* Probe the timeout */
3887 Buffer.DefaultTimeout =
3888 ProbeForReadLargeInteger(DefaultTimeout);
3889 }
3890 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3891 {
3892 /* Return the exception code */
3893 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3894 }
3895 _SEH2_END;
3896 }
3897 else
3898 {
3899 /* Otherwise, capture directly */
3900 Buffer.DefaultTimeout = *DefaultTimeout;
3901 }
3902
3903 /* Set the correct setting */
3904 Buffer.TimeoutSpecified = TRUE;
3905 }
3906 else
3907 {
3908 /* Tell the FSD we don't have a timeout */
3909 Buffer.TimeoutSpecified = FALSE;
3910 }
3911
3912 /* Set Settings */
3913 Buffer.NamedPipeType = NamedPipeType;
3914 Buffer.ReadMode = ReadMode;
3915 Buffer.CompletionMode = CompletionMode;
3916 Buffer.MaximumInstances = MaximumInstances;
3917 Buffer.InboundQuota = InboundQuota;
3918 Buffer.OutboundQuota = OutboundQuota;
3919
3920 /* Call I/O */
3921 return IoCreateFile(FileHandle,
3922 DesiredAccess,
3923 ObjectAttributes,
3924 IoStatusBlock,
3925 NULL,
3926 0,
3927 ShareAccess,
3928 CreateDisposition,
3929 CreateOptions,
3930 NULL,
3931 0,
3932 CreateFileTypeNamedPipe,
3933 (PVOID)&Buffer,
3934 0);
3935 }
3936
3937 NTSTATUS
3938 NTAPI
NtFlushWriteBuffer(VOID)3939 NtFlushWriteBuffer(VOID)
3940 {
3941 PAGED_CODE();
3942
3943 /* Call the kernel */
3944 KeFlushWriteBuffer();
3945 return STATUS_SUCCESS;
3946 }
3947
3948 /*
3949 * @implemented
3950 */
3951 NTSTATUS
3952 NTAPI
NtOpenFile(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,IN ULONG ShareAccess,IN ULONG OpenOptions)3953 NtOpenFile(OUT PHANDLE FileHandle,
3954 IN ACCESS_MASK DesiredAccess,
3955 IN POBJECT_ATTRIBUTES ObjectAttributes,
3956 OUT PIO_STATUS_BLOCK IoStatusBlock,
3957 IN ULONG ShareAccess,
3958 IN ULONG OpenOptions)
3959 {
3960 /* Call the I/O Function */
3961 return IoCreateFile(FileHandle,
3962 DesiredAccess,
3963 ObjectAttributes,
3964 IoStatusBlock,
3965 NULL,
3966 0,
3967 ShareAccess,
3968 FILE_OPEN,
3969 OpenOptions,
3970 NULL,
3971 0,
3972 CreateFileTypeNone,
3973 NULL,
3974 0);
3975 }
3976
3977 NTSTATUS
3978 NTAPI
NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PFILE_BASIC_INFORMATION FileInformation)3979 NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
3980 OUT PFILE_BASIC_INFORMATION FileInformation)
3981 {
3982 /* Call the internal helper API */
3983 return IopQueryAttributesFile(ObjectAttributes,
3984 FileBasicInformation,
3985 sizeof(FILE_BASIC_INFORMATION),
3986 FileInformation);
3987 }
3988
3989 NTSTATUS
3990 NTAPI
NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation)3991 NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
3992 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation)
3993 {
3994 /* Call the internal helper API */
3995 return IopQueryAttributesFile(ObjectAttributes,
3996 FileNetworkOpenInformation,
3997 sizeof(FILE_NETWORK_OPEN_INFORMATION),
3998 FileInformation);
3999 }
4000
4001 /**
4002 * @name NtCancelIoFile
4003 *
4004 * Cancel all pending I/O operations in the current thread for specified
4005 * file object.
4006 *
4007 * @param FileHandle
4008 * Handle to file object to cancel requests for. No specific
4009 * access rights are needed.
4010 * @param IoStatusBlock
4011 * Pointer to status block which is filled with final completition
4012 * status on successful return.
4013 *
4014 * @return Status.
4015 *
4016 * @implemented
4017 */
4018 NTSTATUS
4019 NTAPI
NtCancelIoFile(IN HANDLE FileHandle,OUT PIO_STATUS_BLOCK IoStatusBlock)4020 NtCancelIoFile(IN HANDLE FileHandle,
4021 OUT PIO_STATUS_BLOCK IoStatusBlock)
4022 {
4023 PFILE_OBJECT FileObject;
4024 PETHREAD Thread;
4025 PIRP Irp;
4026 KIRQL OldIrql;
4027 BOOLEAN OurIrpsInList = FALSE;
4028 LARGE_INTEGER Interval;
4029 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
4030 NTSTATUS Status;
4031 PLIST_ENTRY ListHead, NextEntry;
4032 PAGED_CODE();
4033 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
4034
4035 /* Check the previous mode */
4036 if (PreviousMode != KernelMode)
4037 {
4038 /* Enter SEH for probing */
4039 _SEH2_TRY
4040 {
4041 /* Probe the I/O Status Block */
4042 ProbeForWriteIoStatusBlock(IoStatusBlock);
4043 }
4044 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4045 {
4046 /* Return the exception code */
4047 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4048 }
4049 _SEH2_END;
4050 }
4051
4052 /* Reference the file object */
4053 Status = ObReferenceObjectByHandle(FileHandle,
4054 0,
4055 IoFileObjectType,
4056 PreviousMode,
4057 (PVOID*)&FileObject,
4058 NULL);
4059 if (!NT_SUCCESS(Status)) return Status;
4060
4061 /* IRP cancellations are synchronized at APC_LEVEL. */
4062 KeRaiseIrql(APC_LEVEL, &OldIrql);
4063
4064 /* Get the current thread */
4065 Thread = PsGetCurrentThread();
4066
4067 /* Update the operation counts */
4068 IopUpdateOperationCount(IopOtherTransfer);
4069
4070 /* Loop the list */
4071 ListHead = &Thread->IrpList;
4072 NextEntry = ListHead->Flink;
4073 while (ListHead != NextEntry)
4074 {
4075 /* Get the IRP and check if the File Object matches */
4076 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
4077 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
4078 {
4079 /* Cancel this IRP and keep looping */
4080 IoCancelIrp(Irp);
4081 OurIrpsInList = TRUE;
4082 }
4083
4084 /* Go to the next entry */
4085 NextEntry = NextEntry->Flink;
4086 }
4087
4088 /* Lower the IRQL */
4089 KeLowerIrql(OldIrql);
4090
4091 /* Check if we had found an IRP */
4092 if (OurIrpsInList)
4093 {
4094 /* Setup a 10ms wait */
4095 Interval.QuadPart = -100000;
4096
4097 /* Start looping */
4098 while (OurIrpsInList)
4099 {
4100 /* Do the wait */
4101 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
4102 OurIrpsInList = FALSE;
4103
4104 /* Raise IRQL */
4105 KeRaiseIrql(APC_LEVEL, &OldIrql);
4106
4107 /* Now loop the list again */
4108 NextEntry = ListHead->Flink;
4109 while (NextEntry != ListHead)
4110 {
4111 /* Get the IRP and check if the File Object matches */
4112 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
4113 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
4114 {
4115 /* Keep looping */
4116 OurIrpsInList = TRUE;
4117 break;
4118 }
4119
4120 /* Go to the next entry */
4121 NextEntry = NextEntry->Flink;
4122 }
4123
4124 /* Lower the IRQL */
4125 KeLowerIrql(OldIrql);
4126 }
4127 }
4128
4129 /* Enter SEH for writing back the I/O Status */
4130 _SEH2_TRY
4131 {
4132 /* Write success */
4133 IoStatusBlock->Status = STATUS_SUCCESS;
4134 IoStatusBlock->Information = 0;
4135 }
4136 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4137 {
4138 /* Ignore exception */
4139 }
4140 _SEH2_END;
4141
4142 /* Dereference the file object and return success */
4143 ObDereferenceObject(FileObject);
4144 return STATUS_SUCCESS;
4145 }
4146
4147 /*
4148 * @implemented
4149 */
4150 NTSTATUS
4151 NTAPI
NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)4152 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
4153 {
4154 NTSTATUS Status;
4155 DUMMY_FILE_OBJECT LocalFileObject;
4156 HANDLE Handle;
4157 KPROCESSOR_MODE AccessMode = KeGetPreviousMode();
4158 OPEN_PACKET OpenPacket;
4159 PAGED_CODE();
4160 IOTRACE(IO_API_DEBUG, "FileMame: %wZ\n", ObjectAttributes->ObjectName);
4161
4162 /* Setup the Open Packet */
4163 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
4164 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
4165 OpenPacket.Size = sizeof(OPEN_PACKET);
4166 OpenPacket.CreateOptions = FILE_DELETE_ON_CLOSE;
4167 OpenPacket.ShareAccess = FILE_SHARE_READ |
4168 FILE_SHARE_WRITE |
4169 FILE_SHARE_DELETE;
4170 OpenPacket.Disposition = FILE_OPEN;
4171 OpenPacket.DeleteOnly = TRUE;
4172 OpenPacket.LocalFileObject = &LocalFileObject;
4173
4174 /* Update the operation counts */
4175 IopUpdateOperationCount(IopOtherTransfer);
4176
4177 /*
4178 * Attempt opening the file. This will call the I/O Parse Routine for
4179 * the File Object (IopParseDevice) which will use the dummy file obejct
4180 * send the IRP to its device object. Note that we have two statuses
4181 * to worry about: the Object Manager's status (in Status) and the I/O
4182 * status, which is in the Open Packet's Final Status, and determined
4183 * by the Parse Check member.
4184 */
4185 Status = ObOpenObjectByName(ObjectAttributes,
4186 NULL,
4187 AccessMode,
4188 NULL,
4189 DELETE,
4190 &OpenPacket,
4191 &Handle);
4192 if (OpenPacket.ParseCheck == FALSE) return Status;
4193
4194 /* Retrn the Io status */
4195 return OpenPacket.FinalStatus;
4196 }
4197
4198 /* EOF */
4199