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