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