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