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