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