xref: /reactos/ntoskrnl/io/iomgr/file.c (revision 6363f782)
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