Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2563 lines
87 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. parse.c
  5. Abstract:
  6. This module contains the code to implement the device object parse routine.
  7. Author:
  8. Darryl E. Havens (darrylh) 15-May-1988
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "iomgr.h"
  14. //
  15. // Define macro to round up the size of a name for buffer optimization.
  16. //
  17. #define RoundNameSize( Length ) ( \
  18. (Length < 64 - 8) ? 64 - 8 : \
  19. (Length < 128 - 8) ? 128 - 8 :\
  20. (Length < 256 - 8) ? 256 - 8 : Length )
  21. #define IO_MAX_REMOUNT_REPARSE_ATTEMPTS 32
  22. NTSTATUS
  23. IopGetNetworkOpenInformation(
  24. IN PFILE_OBJECT FileObject,
  25. IN POPEN_PACKET Op
  26. );
  27. #ifdef ALLOC_PRAGMA
  28. #pragma alloc_text(PAGE, IopParseFile)
  29. #pragma alloc_text(PAGE, IopParseDevice)
  30. #pragma alloc_text(PAGE, IopQueryName)
  31. #pragma alloc_text(PAGE, IopQueryNameInternal)
  32. #pragma alloc_text(PAGE, IopCheckBackupRestorePrivilege)
  33. #pragma alloc_text(PAGE, IopGetNetworkOpenInformation)
  34. #endif
  35. NTSTATUS
  36. IopCheckDeviceAndDriver(
  37. POPEN_PACKET op,
  38. PDEVICE_OBJECT parseDeviceObject
  39. )
  40. {
  41. NTSTATUS status;
  42. KIRQL irql;
  43. //
  44. // Make sure that the device and its driver are really there and they are
  45. // going to stay there. The object itself cannot go away just yet because
  46. // the object management system has performed a reference which bumps the
  47. // count of the number of reasons why the object must stick around.
  48. // However, the driver could be attempting to unload itself, so perform
  49. // this check. If the driver is being unloaded, then set the final status
  50. // of the operation to "No such device" and return with a NULL file object
  51. // pointer.
  52. //
  53. // Note that it is possible to "open" an exclusive device more than once
  54. // provided that the caller is performing a relative open. This feature
  55. // is how users "allocate" a device, and then use it to perform operations.
  56. //
  57. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  58. if (parseDeviceObject->DeviceObjectExtension->ExtensionFlags &
  59. (DOE_UNLOAD_PENDING | DOE_DELETE_PENDING | DOE_REMOVE_PENDING | DOE_REMOVE_PROCESSED | DOE_START_PENDING) ||
  60. parseDeviceObject->Flags & DO_DEVICE_INITIALIZING) {
  61. status = STATUS_NO_SUCH_DEVICE;
  62. } else if (parseDeviceObject->Flags & DO_EXCLUSIVE &&
  63. parseDeviceObject->ReferenceCount != 0 &&
  64. op->RelatedFileObject == NULL &&
  65. !(op->Options & IO_ATTACH_DEVICE)) {
  66. status = STATUS_ACCESS_DENIED;
  67. } else {
  68. parseDeviceObject->ReferenceCount++;
  69. status = STATUS_SUCCESS;
  70. }
  71. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  72. return status;
  73. }
  74. PVPB
  75. IopCheckVpbMounted(
  76. IN POPEN_PACKET op,
  77. IN PDEVICE_OBJECT parseDeviceObject,
  78. IN OUT PUNICODE_STRING RemainingName,
  79. OUT PNTSTATUS status
  80. )
  81. {
  82. PVPB vpb;
  83. PVPB mountVpb;
  84. KIRQL irql;
  85. BOOLEAN alertable;
  86. //
  87. // Loop here until the VPB_MOUNTED test can be passed while holding the
  88. // VPB spinlock. After the mount succeeds, it is still necessary to acquire
  89. // the spinlock to check that the VPB (which may be different from the one
  90. // before the mount) is still mounted. If it is, then its reference count
  91. // is incremented before releasing the spinlock.
  92. //
  93. irql = KeAcquireQueuedSpinLock( LockQueueIoVpbLock );
  94. alertable = (op->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) ? TRUE : FALSE;
  95. while (!(parseDeviceObject->Vpb->Flags & VPB_MOUNTED)) {
  96. KeReleaseQueuedSpinLock( LockQueueIoVpbLock, irql );
  97. //
  98. // Try to mount the volume, allowing only RAW to perform the mount if
  99. // this is a DASD open.
  100. //
  101. mountVpb = NULL;
  102. *status = IopMountVolume( parseDeviceObject,
  103. (BOOLEAN) (!RemainingName->Length && !op->RelatedFileObject),
  104. FALSE,
  105. alertable,
  106. &mountVpb );
  107. //
  108. // If the mount operation was unsuccessful, adjust the reference
  109. // count for the device and return now.
  110. //
  111. if (!NT_SUCCESS( *status ) || *status == STATUS_USER_APC || *status == STATUS_ALERTED) {
  112. IopDecrementDeviceObjectRef( parseDeviceObject, FALSE, FALSE );
  113. if (!NT_SUCCESS( *status )) {
  114. return NULL;
  115. } else {
  116. *status = STATUS_WRONG_VOLUME;
  117. return NULL;
  118. }
  119. } else {
  120. //
  121. // In this case IopMountVolume did the synchronization already.
  122. //
  123. if (mountVpb) {
  124. return mountVpb;
  125. }
  126. }
  127. irql = KeAcquireQueuedSpinLock( LockQueueIoVpbLock );
  128. }
  129. //
  130. // Synchronize here with the file system to make sure that volumes do not
  131. // go away while en route to the FS.
  132. //
  133. vpb = parseDeviceObject->Vpb;
  134. //
  135. // Check here that the VPB is not locked.
  136. //
  137. if (vpb->Flags & VPB_LOCKED) {
  138. *status = STATUS_ACCESS_DENIED;
  139. vpb = NULL;
  140. } else {
  141. vpb->ReferenceCount += 1;
  142. }
  143. KeReleaseQueuedSpinLock( LockQueueIoVpbLock, irql );
  144. //
  145. // This is because VPB is locked.
  146. // Do the decrement outside the VPB lock because of possible deadlocks.
  147. //
  148. if (!vpb) {
  149. IopDecrementDeviceObjectRef( parseDeviceObject, FALSE, FALSE );
  150. }
  151. return vpb;
  152. }
  153. VOID
  154. IopDereferenceVpbAndFree(
  155. IN PVPB Vpb
  156. )
  157. {
  158. KIRQL irql;
  159. PVPB vpb = (PVPB) NULL;
  160. irql = KeAcquireQueuedSpinLock( LockQueueIoVpbLock );
  161. Vpb->ReferenceCount--;
  162. if ((Vpb->ReferenceCount == 0) &&
  163. (Vpb->RealDevice->Vpb != Vpb) &&
  164. !(Vpb->Flags & VPB_PERSISTENT)) {
  165. vpb = Vpb;
  166. }
  167. KeReleaseQueuedSpinLock( LockQueueIoVpbLock, irql );
  168. if (vpb) {
  169. ExFreePool( vpb );
  170. }
  171. }
  172. NTSTATUS
  173. IopParseDevice(
  174. IN PVOID ParseObject,
  175. IN PVOID ObjectType,
  176. IN PACCESS_STATE AccessState,
  177. IN KPROCESSOR_MODE AccessMode,
  178. IN ULONG Attributes,
  179. IN OUT PUNICODE_STRING CompleteName,
  180. IN OUT PUNICODE_STRING RemainingName,
  181. IN OUT PVOID Context OPTIONAL,
  182. IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
  183. OUT PVOID *Object
  184. )
  185. /*++
  186. Routine Description:
  187. This routine interfaces to the NT Object Manager. It is invoked when
  188. the object system is given the name of an entity to create or open and the
  189. name translates to a device object. This routine is specified as the parse
  190. routine for all device objects.
  191. In the normal case of an NtCreateFile, the user specifies either the name
  192. of a device or of a file. In the former situation, this routine is invoked
  193. with a pointer to the device and a null ("") string. For this case, the
  194. routine simply allocates an IRP, fills it in, and passes it to the driver
  195. for the device. The driver will then perform whatever rudimentary functions
  196. are necessary and will return a status code indicating whether an error was
  197. incurred. This status code is remembered in the Open Packet (OP).
  198. In the latter situation, the name string to be opened/created is non-null.
  199. That is, it contains the remainder of the pathname to the file that is to
  200. be opened or created. For this case, the routine allocates an IRP, fills
  201. it in, and passes it to the driver for the device. The driver may then
  202. need to take further action or it may complete the request immediately. If
  203. it needs to perform some work asynchronously, then it can queue the request
  204. and return a status of STATUS_PENDING. This allows this routine and its
  205. caller to return to the user so that he can continue. Otherwise, the open/
  206. create is basically finished.
  207. If the driver supports symbolic links, then it is also possible for the
  208. driver to return a new name. This name will be returned to the Object
  209. Manager as a new name to look up. The parsing will then begin again from
  210. the start.
  211. It is also the responsibility of this routine to create a file object for
  212. the file, if the name specifies a file. The file object's address is
  213. returned to the NtCreateFile service through the OP.
  214. Arguments:
  215. ParseObject - Pointer to the device object the name translated into.
  216. ObjectType - Type of the object being opened.
  217. AccessState - Running security access state information for operation.
  218. AccessMode - Access mode of the original caller.
  219. Attributes - Attributes to be applied to the object.
  220. CompleteName - Complete name of the object.
  221. RemainingName - Remaining name of the object.
  222. Context - Pointer to an Open Packet (OP) from NtCreateFile service.
  223. SecurityQos - Optional security quality of service indicator.
  224. Object - The address of a variable to receive the created file object, if
  225. any.
  226. Return Value:
  227. The function return value is one of the following:
  228. a) Success - This indicates that the function succeeded and the object
  229. parameter contains the address of the created file object.
  230. b) Error - This indicates that the file was not found or created and
  231. no file object was created.
  232. c) Reparse - This indicates that the remaining name string has been
  233. replaced by a new name that is to be parsed.
  234. --*/
  235. {
  236. PIRP irp;
  237. PIO_STACK_LOCATION irpSp;
  238. POPEN_PACKET op;
  239. PFILE_OBJECT fileObject;
  240. NTSTATUS status;
  241. IO_STATUS_BLOCK ioStatus;
  242. IO_SECURITY_CONTEXT securityContext;
  243. PDEVICE_OBJECT deviceObject;
  244. PDEVICE_OBJECT parseDeviceObject;
  245. BOOLEAN directDeviceOpen;
  246. PVPB vpb;
  247. ACCESS_MASK desiredAccess;
  248. PDUMMY_FILE_OBJECT localFileObject;
  249. BOOLEAN realFileObjectRequired;
  250. KPROCESSOR_MODE modeForPrivilegeCheck;
  251. ULONG retryCount = 0;
  252. BOOLEAN relativeVolumeOpen = FALSE; // True if opening a filesystem volume
  253. PETHREAD CurrentThread;
  254. ULONG returnedLength;
  255. PAGED_CODE();
  256. CurrentThread = PsGetCurrentThread ();
  257. reparse_loop:
  258. //
  259. // Assume failure by setting the returned object pointer to NULL.
  260. //
  261. *Object = (PVOID) NULL;
  262. //
  263. // Get the address of the Open Packet (OP).
  264. //
  265. op = Context;
  266. //
  267. // Ensure that this routine is actually being invoked because someone is
  268. // attempting to open a device or a file through NtCreateFile. This code
  269. // must be invoked from there (as opposed to some other random object
  270. // create or open routine).
  271. //
  272. if (op == NULL ||
  273. op->Type != IO_TYPE_OPEN_PACKET ||
  274. op->Size != sizeof( OPEN_PACKET )) {
  275. return STATUS_OBJECT_TYPE_MISMATCH;
  276. }
  277. //
  278. // Obtain a pointer to the parse object as a device object, which is the
  279. // actual type of the object anyway.
  280. //
  281. parseDeviceObject = (PDEVICE_OBJECT) ParseObject;
  282. //
  283. // If we passed through a mountpoint do an extra set of validation checks
  284. // that we don't go to a remote device. We really have to let the object manager
  285. // open the new path. If we fail it in the path that obtains the reparse point and
  286. // validates the name (using IoIsValidNameGraftingBuffer) its not sufficient. This is because
  287. // the path may be valid at that time and change before OB does the reparse.
  288. //
  289. if (op->TraversedMountPoint) {
  290. ASSERT (op->Information == IO_REPARSE_TAG_MOUNT_POINT);
  291. if ((parseDeviceObject->DeviceType != FILE_DEVICE_DISK) &&
  292. (parseDeviceObject->DeviceType != FILE_DEVICE_CD_ROM) &&
  293. (parseDeviceObject->DeviceType != FILE_DEVICE_TAPE)) {
  294. status = STATUS_IO_REPARSE_DATA_INVALID;
  295. return op->FinalStatus = status;
  296. }
  297. }
  298. //
  299. // If this is a relative open, then get the device on which the file
  300. // is really being opened from the related file object and use that for
  301. // the remainder of this function and for all operations performed on
  302. // the file object that is about to be created.
  303. //
  304. if (op->RelatedFileObject) {
  305. parseDeviceObject = op->RelatedFileObject->DeviceObject;
  306. }
  307. //
  308. // Make sure that the device and its driver are really there and they are
  309. // going to stay there. The object itself cannot go away just yet because
  310. // the object management system has performed a reference which bumps the
  311. // count of the number of reasons why the object must stick around.
  312. // However, the driver could be attempting to unload itself, so perform
  313. // this check. If the driver is being unloaded, then set the final status
  314. // of the operation to "No such device" and return with a NULL file object
  315. // pointer.
  316. //
  317. // Note that it is possible to "open" an exclusive device more than once
  318. // provided that the caller is performing a relative open. This feature
  319. // is how users "allocate" a device, and then use it to perform operations.
  320. //
  321. status = IopCheckDeviceAndDriver( op, parseDeviceObject );
  322. if (!NT_SUCCESS(status)) {
  323. return op->FinalStatus = status;
  324. }
  325. //
  326. // Since ObOpenObjectByName is called without being passed
  327. // any object type information, we need to map the generic
  328. // bits in the DesiredAccess mask here. We also need to save
  329. // the object's generic mapping in the access state structure
  330. // here, because this is the earliest opportunity we have
  331. // to do so.
  332. //
  333. RtlMapGenericMask( &AccessState->RemainingDesiredAccess,
  334. &IoFileObjectType->TypeInfo.GenericMapping );
  335. RtlMapGenericMask( &AccessState->OriginalDesiredAccess,
  336. &IoFileObjectType->TypeInfo.GenericMapping );
  337. SeSetAccessStateGenericMapping( AccessState, &IoFileObjectType->TypeInfo.GenericMapping );
  338. desiredAccess = AccessState->RemainingDesiredAccess;
  339. //
  340. // Compute the previous mode to be passed in to the privilege check
  341. //
  342. if (AccessMode != KernelMode || op->Options & IO_FORCE_ACCESS_CHECK) {
  343. modeForPrivilegeCheck = UserMode;
  344. } else {
  345. modeForPrivilegeCheck = KernelMode;
  346. }
  347. IopCheckBackupRestorePrivilege( AccessState,
  348. &op->CreateOptions,
  349. modeForPrivilegeCheck,
  350. op->Disposition
  351. );
  352. //
  353. // If this is not the first time through here for this object, and the
  354. // object itself is being opened, then the desired access must also
  355. // include the previously granted access from the last pass. Likewise,
  356. // if the privileges have been checked already, then this is another
  357. // pass through for a file, so add in the previously granted access.
  358. //
  359. if ((op->Override && !RemainingName->Length) ||
  360. AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED) {
  361. desiredAccess |= AccessState->PreviouslyGrantedAccess;
  362. }
  363. //
  364. // If its a filesystem volume open and we are doing a relative open to it
  365. // then do the access check. Note that relative opens can be nested and we propagate
  366. // the fact that the relative open is for a volume using the FO_VOLUME_OPEN flag.
  367. //
  368. if (op->RelatedFileObject) {
  369. if ((op->RelatedFileObject->Flags & FO_VOLUME_OPEN) && RemainingName->Length == 0) {
  370. relativeVolumeOpen = TRUE;
  371. }
  372. }
  373. //
  374. // Now determine what type of security check should be made. This is
  375. // based on whether the remaining name string is null. If it is null,
  376. // then the device itself is being opened, so a full security check is
  377. // performed. Otherwise, only a check to ensure that the caller can
  378. // traverse the device object is made. Note that these checks are only
  379. // made if the caller's mode is user, or if access checking is being
  380. // forced. Note also that if an access check was already made on the
  381. // device itself, and this code is being executed again because of a
  382. // reparse, then the access check need not be made the second time
  383. // around.
  384. //
  385. if ((AccessMode != KernelMode || op->Options & IO_FORCE_ACCESS_CHECK) &&
  386. (!op->RelatedFileObject || relativeVolumeOpen) &&
  387. !op->Override) {
  388. BOOLEAN subjectContextLocked = FALSE;
  389. BOOLEAN accessGranted;
  390. ACCESS_MASK grantedAccess;
  391. //
  392. // The caller's mode is either user or access checking is being
  393. // forced. Perform the appropriate access check on the device
  394. // object.
  395. //
  396. if (!RemainingName->Length) {
  397. UNICODE_STRING nameString;
  398. PPRIVILEGE_SET privileges = NULL;
  399. //
  400. // The device itself is being opened. Make a full security check
  401. // to ensure that the caller has the appropriate access.
  402. //
  403. KeEnterCriticalRegionThread( &CurrentThread->Tcb );
  404. ExAcquireResourceSharedLite( &IopSecurityResource, TRUE );
  405. SeLockSubjectContext( &AccessState->SubjectSecurityContext );
  406. subjectContextLocked = TRUE;
  407. accessGranted = SeAccessCheck( parseDeviceObject->SecurityDescriptor,
  408. &AccessState->SubjectSecurityContext,
  409. subjectContextLocked,
  410. desiredAccess,
  411. 0,
  412. &privileges,
  413. &IoFileObjectType->TypeInfo.GenericMapping,
  414. UserMode,
  415. &grantedAccess,
  416. &status );
  417. if (privileges) {
  418. (VOID) SeAppendPrivileges( AccessState,
  419. privileges );
  420. SeFreePrivileges( privileges );
  421. }
  422. if (accessGranted) {
  423. AccessState->PreviouslyGrantedAccess |= grantedAccess;
  424. AccessState->RemainingDesiredAccess &= ~( grantedAccess | MAXIMUM_ALLOWED );
  425. op->Override = TRUE;
  426. }
  427. nameString.Length = 8;
  428. nameString.MaximumLength = 8;
  429. nameString.Buffer = L"File";
  430. SeOpenObjectAuditAlarm( &nameString,
  431. parseDeviceObject,
  432. CompleteName,
  433. parseDeviceObject->SecurityDescriptor,
  434. AccessState,
  435. FALSE,
  436. accessGranted,
  437. UserMode,
  438. &AccessState->GenerateOnClose );
  439. ExReleaseResourceLite( &IopSecurityResource );
  440. KeLeaveCriticalRegionThread( &CurrentThread->Tcb );
  441. } else {
  442. //
  443. // The device is not being opened, rather, a file on the device
  444. // is being opened or created. Therefore, only perform a check
  445. // here for traverse access to the device.
  446. //
  447. //
  448. // First determine if we have to perform traverse checking at all.
  449. // Traverse checking only needs to be done if the device being
  450. // traversed is a disk, or if the caller does not already have
  451. // traverse checking privilege. Note that the former case is so
  452. // that an administrator can turn off access to the "system
  453. // partition", or someone would be able to install a trojan horse
  454. // into the system by simply replacing one of the files there with
  455. // something of their own.
  456. //
  457. if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ||
  458. parseDeviceObject->DeviceType == FILE_DEVICE_DISK ||
  459. parseDeviceObject->DeviceType == FILE_DEVICE_CD_ROM ) {
  460. KeEnterCriticalRegionThread( &CurrentThread->Tcb );
  461. ExAcquireResourceSharedLite( &IopSecurityResource, TRUE );
  462. //
  463. // If the token is restricted we need to do the full
  464. // access check.
  465. //
  466. if ((AccessState->Flags & TOKEN_IS_RESTRICTED) == 0) {
  467. accessGranted = SeFastTraverseCheck( parseDeviceObject->SecurityDescriptor,
  468. FILE_TRAVERSE,
  469. UserMode );
  470. } else {
  471. accessGranted = FALSE;
  472. }
  473. if (!accessGranted) {
  474. PPRIVILEGE_SET privileges = NULL;
  475. //
  476. // The caller was not granted traverse access through the
  477. // normal fast path lookup. Perform a full-blown access
  478. // check to determine whether some other ACE allows traverse
  479. // access.
  480. //
  481. SeLockSubjectContext( &AccessState->SubjectSecurityContext );
  482. subjectContextLocked = TRUE;
  483. accessGranted = SeAccessCheck( parseDeviceObject->SecurityDescriptor,
  484. &AccessState->SubjectSecurityContext,
  485. subjectContextLocked,
  486. FILE_TRAVERSE,
  487. 0,
  488. &privileges,
  489. &IoFileObjectType->TypeInfo.GenericMapping,
  490. UserMode,
  491. &grantedAccess,
  492. &status );
  493. if (privileges) {
  494. (VOID) SeAppendPrivileges( AccessState,
  495. privileges );
  496. SeFreePrivileges( privileges );
  497. }
  498. }
  499. ExReleaseResourceLite( &IopSecurityResource );
  500. KeLeaveCriticalRegionThread( &CurrentThread->Tcb );
  501. } else {
  502. accessGranted = TRUE;
  503. }
  504. }
  505. //
  506. // Unlock the subject's security context so that it can be changed,
  507. // if it was locked.
  508. //
  509. if (subjectContextLocked) {
  510. SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
  511. }
  512. //
  513. // Finally, determine whether or not access was granted to the device.
  514. // If not, clean everything up and get out now without even invoking
  515. // the device driver.
  516. //
  517. if (!accessGranted) {
  518. IopDecrementDeviceObjectRef( parseDeviceObject, FALSE, FALSE );
  519. return STATUS_ACCESS_DENIED;
  520. }
  521. }
  522. realFileObjectRequired = !(op->QueryOnly || op->DeleteOnly);
  523. if (RemainingName->Length == 0 &&
  524. op->RelatedFileObject == NULL &&
  525. ((desiredAccess & ~(SYNCHRONIZE |
  526. FILE_READ_ATTRIBUTES |
  527. READ_CONTROL |
  528. ACCESS_SYSTEM_SECURITY |
  529. WRITE_OWNER |
  530. WRITE_DAC)) == 0) &&
  531. realFileObjectRequired) {
  532. //
  533. // If the name of the object being opened is just the name of the
  534. // device itself, and there is no related file object, and the caller
  535. // is opening the device for only read attributes access, then this
  536. // device will not be mounted. This allows applications to obtain
  537. // attributes about the device without actually mounting it.
  538. //
  539. // Note that if this *is* a direct device open, then the normal path
  540. // through the I/O system and drivers may never be used, even if
  541. // the device appears to be mounted. This is because the user may
  542. // remove the media from the drive (even though it is mounted), and
  543. // now attempting to determine what type of drive it is will still
  544. // fail, this time very hard, because a whole mount process is now
  545. // required, thus defeating this feature.
  546. //
  547. directDeviceOpen = TRUE;
  548. } else {
  549. //
  550. // Otherwise, this is a normal open of a file, directory, device, or
  551. // volume.
  552. //
  553. directDeviceOpen = FALSE;
  554. }
  555. //
  556. // There are now five different cases. These are as follows:
  557. //
  558. // 1) This is a relative open, in which case we want to send the
  559. // request to then same device that opened the relative file object.
  560. //
  561. // 2) The VPB pointer in the device object is NULL. This means that
  562. // this device does not support a file system. This includes
  563. // devices such as terminals, etc.
  564. //
  565. // 3) The VPB pointer in the device object is not NULL and:
  566. //
  567. // a) The VPB is "blank". That is, the VPB has never been filled
  568. // in, which means that the device has never been mounted.
  569. //
  570. // b) The VPB is non-blank, but the verify flag on the device is
  571. // set, indicating that the door to the drive may have been
  572. // opened and the media may therefore have been changed.
  573. //
  574. // c) The VPB is non-blank and the verify flag is not set.
  575. //
  576. // Both of the latter are not explicitly checked for, as #c is
  577. // the normal case, and #b is the responsibility of the file
  578. // system to check.
  579. //
  580. //
  581. // If this is a file system that supports volumes, vpbRefCount will
  582. // be filled in to point to the reference count in the Vpb. Error
  583. // exits paths later on key off this value to see if they should
  584. // decrement the ref count. Note that a direct device open does not
  585. // make it to the file system, so no increment is needed, and no
  586. // decrement will be performed in objsup.c IopDeleteFile().
  587. //
  588. vpb = NULL;
  589. //
  590. // If the related open was a direct device open then we should go through the full mount
  591. // path for this open as this may not be a direct device open.
  592. //
  593. if (op->RelatedFileObject && (!(op->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN))) {
  594. deviceObject = (PDEVICE_OBJECT)ParseObject;
  595. if (op->RelatedFileObject->Vpb) {
  596. vpb = op->RelatedFileObject->Vpb;
  597. //
  598. // Synchronize here with the file system to make sure that
  599. // volumes don't go away while en route to the FS.
  600. //
  601. IopInterlockedIncrementUlong( LockQueueIoVpbLock,
  602. &vpb->ReferenceCount);
  603. }
  604. } else {
  605. deviceObject = parseDeviceObject;
  606. if (parseDeviceObject->Vpb && !directDeviceOpen) {
  607. vpb = IopCheckVpbMounted( op,
  608. parseDeviceObject,
  609. RemainingName,
  610. &status );
  611. //
  612. // Device object reference is decremented in IopCheckVpbMounted.
  613. //
  614. if ( !vpb ) {
  615. return status;
  616. }
  617. //
  618. // Set the address of the device object associated with the VPB.
  619. //
  620. deviceObject = vpb->DeviceObject;
  621. }
  622. //
  623. // If the top deviceobject hint is set use the hint if possible.
  624. //
  625. if (op->InternalFlags & IOP_CREATE_USE_TOP_DEVICE_OBJECT_HINT) {
  626. //
  627. // You cannot use the device object hint if you are trying to
  628. // open the device directly or if you are dealing with a device
  629. // that is not a file system. In these cases, return an error.
  630. //
  631. if (directDeviceOpen ||
  632. (deviceObject->DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM &&
  633. deviceObject->DeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM &&
  634. deviceObject->DeviceType != FILE_DEVICE_TAPE_FILE_SYSTEM &&
  635. deviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM &&
  636. deviceObject->DeviceType != FILE_DEVICE_DFS_FILE_SYSTEM)) {
  637. if (vpb) {
  638. IopDereferenceVpbAndFree( vpb );
  639. }
  640. IopDecrementDeviceObjectRef( parseDeviceObject, FALSE, FALSE );
  641. return STATUS_INVALID_PARAMETER;
  642. }
  643. if (IopVerifyDeviceObjectOnStack(deviceObject, op->TopDeviceObjectHint)) {
  644. deviceObject = op->TopDeviceObjectHint;
  645. } else {
  646. if (vpb) {
  647. IopDereferenceVpbAndFree(vpb);
  648. }
  649. IopDecrementDeviceObjectRef( parseDeviceObject, FALSE, FALSE );
  650. if (op->TraversedMountPoint) {
  651. op->TraversedMountPoint = FALSE;
  652. return STATUS_MOUNT_POINT_NOT_RESOLVED;
  653. } else {
  654. return STATUS_INVALID_DEVICE_OBJECT_PARAMETER;
  655. }
  656. }
  657. } else {
  658. //
  659. // Walk the attached device list.
  660. //
  661. if (deviceObject->AttachedDevice) {
  662. deviceObject = IoGetAttachedDevice( deviceObject );
  663. }
  664. }
  665. }
  666. //
  667. // If the TraversedMountPoint flag is still set, clear it now. We needed
  668. // to keep it to return the correct status if IopVerifyDeviceObjectOnStack
  669. // failed above.
  670. //
  671. if (op->TraversedMountPoint) {
  672. op->TraversedMountPoint = FALSE;
  673. }
  674. //
  675. // If the driver says that the IO manager should do the access checks, lets do it here.
  676. // We do the check against the parse device object as that device object has a name
  677. // and we can set an ACL against it.
  678. // We only worry about related opens of devices as the other case is taken care of in the
  679. // filesystem.
  680. //
  681. if ((deviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) &&
  682. (op->RelatedFileObject || RemainingName->Length) && (!relativeVolumeOpen)) {
  683. BOOLEAN subjectContextLocked = FALSE;
  684. BOOLEAN accessGranted;
  685. ACCESS_MASK grantedAccess;
  686. UNICODE_STRING nameString;
  687. PPRIVILEGE_SET privileges = NULL;
  688. //
  689. // If the device wants to ensure secure opens then lets check the two
  690. // cases which were skipped earlier. These cases are if its a relative
  691. // open or if there are trailing names.
  692. //
  693. KeEnterCriticalRegionThread( &CurrentThread->Tcb );
  694. ExAcquireResourceSharedLite( &IopSecurityResource, TRUE );
  695. SeLockSubjectContext( &AccessState->SubjectSecurityContext );
  696. subjectContextLocked = TRUE;
  697. accessGranted = SeAccessCheck( parseDeviceObject->SecurityDescriptor,
  698. &AccessState->SubjectSecurityContext,
  699. subjectContextLocked,
  700. desiredAccess,
  701. 0,
  702. &privileges,
  703. &IoFileObjectType->TypeInfo.GenericMapping,
  704. UserMode,
  705. &grantedAccess,
  706. &status );
  707. if (privileges) {
  708. (VOID) SeAppendPrivileges( AccessState,
  709. privileges );
  710. SeFreePrivileges( privileges );
  711. }
  712. if (accessGranted) {
  713. AccessState->PreviouslyGrantedAccess |= grantedAccess;
  714. AccessState->RemainingDesiredAccess &= ~( grantedAccess | MAXIMUM_ALLOWED );
  715. }
  716. nameString.Length = 8;
  717. nameString.MaximumLength = 8;
  718. nameString.Buffer = L"File";
  719. SeOpenObjectAuditAlarm( &nameString,
  720. deviceObject,
  721. CompleteName,
  722. parseDeviceObject->SecurityDescriptor,
  723. AccessState,
  724. FALSE,
  725. accessGranted,
  726. UserMode,
  727. &AccessState->GenerateOnClose );
  728. SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
  729. ExReleaseResourceLite( &IopSecurityResource );
  730. KeLeaveCriticalRegionThread( &CurrentThread->Tcb );
  731. if (!accessGranted) {
  732. IopDecrementDeviceObjectRef( parseDeviceObject, FALSE, FALSE );
  733. if (vpb) {
  734. IopDereferenceVpbAndFree(vpb);
  735. }
  736. return STATUS_ACCESS_DENIED;
  737. }
  738. }
  739. //
  740. // Allocate and fill in the I/O Request Packet (IRP) to use in interfacing
  741. // to the driver. The allocation is done using an exception handler in
  742. // case the caller does not have enough quota to allocate the packet.
  743. //
  744. irp = IopAllocateIrp( deviceObject->StackSize, TRUE );
  745. if (!irp) {
  746. //
  747. // An IRP could not be allocated. Cleanup and return an appropriate
  748. // error status code.
  749. //
  750. IopDecrementDeviceObjectRef( parseDeviceObject, FALSE, FALSE );
  751. if (vpb) {
  752. IopDereferenceVpbAndFree(vpb);
  753. }
  754. return STATUS_INSUFFICIENT_RESOURCES;
  755. }
  756. irp->Tail.Overlay.Thread = CurrentThread;
  757. irp->RequestorMode = AccessMode;
  758. irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION;
  759. securityContext.SecurityQos = SecurityQos;
  760. securityContext.AccessState = AccessState;
  761. securityContext.DesiredAccess = desiredAccess;
  762. securityContext.FullCreateOptions = op->CreateOptions;
  763. //
  764. // Get a pointer to the stack location for the first driver. This is where
  765. // the original function codes and parameters are passed.
  766. //
  767. irpSp = IoGetNextIrpStackLocation( irp );
  768. irpSp->Control = 0;
  769. if (op->CreateFileType == CreateFileTypeNone) {
  770. //
  771. // This is a normal file open or create function.
  772. //
  773. irpSp->MajorFunction = IRP_MJ_CREATE;
  774. irpSp->Parameters.Create.EaLength = op->EaLength;
  775. irpSp->Flags = (UCHAR) op->Options;
  776. if (!(Attributes & OBJ_CASE_INSENSITIVE)) {
  777. irpSp->Flags |= SL_CASE_SENSITIVE;
  778. }
  779. } else if (op->CreateFileType == CreateFileTypeNamedPipe) {
  780. //
  781. // A named pipe is being created.
  782. //
  783. irpSp->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
  784. irpSp->Parameters.CreatePipe.Parameters = op->ExtraCreateParameters;
  785. } else {
  786. //
  787. // A mailslot is being created.
  788. //
  789. irpSp->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
  790. irpSp->Parameters.CreateMailslot.Parameters = op->ExtraCreateParameters;
  791. }
  792. //
  793. // Also fill in the NtCreateFile service's caller's parameters.
  794. //
  795. irp->Overlay.AllocationSize = op->AllocationSize;
  796. irp->AssociatedIrp.SystemBuffer = op->EaBuffer;
  797. irpSp->Parameters.Create.Options = (op->Disposition << 24) | (op->CreateOptions & 0x00ffffff);
  798. irpSp->Parameters.Create.FileAttributes = op->FileAttributes;
  799. irpSp->Parameters.Create.ShareAccess = op->ShareAccess;
  800. irpSp->Parameters.Create.SecurityContext = &securityContext;
  801. //
  802. // Fill in local parameters so this routine can determine when the I/O is
  803. // finished, and the normal I/O completion code will not get any errors.
  804. //
  805. irp->UserIosb = &ioStatus;
  806. irp->MdlAddress = (PMDL) NULL;
  807. irp->PendingReturned = FALSE;
  808. irp->Cancel = FALSE;
  809. irp->UserEvent = (PKEVENT) NULL;
  810. irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
  811. irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;
  812. //
  813. // Allocate and initialize the file object that will be used in dealing
  814. // with the device for the remainder of this session with the user. How
  815. // the file object is allocated is based on whether or not a real file
  816. // object is actually required. It is not required for the query and
  817. // delete only operations.
  818. //
  819. if (realFileObjectRequired) {
  820. OBJECT_ATTRIBUTES objectAttributes;
  821. ULONG fileObjectSize;
  822. //
  823. // A real, full-blown file object is actually required.
  824. //
  825. InitializeObjectAttributes( &objectAttributes,
  826. (PUNICODE_STRING) NULL,
  827. Attributes,
  828. (HANDLE) NULL,
  829. (PSECURITY_DESCRIPTOR) NULL
  830. );
  831. if (op->InternalFlags &
  832. (IOP_CREATE_USE_TOP_DEVICE_OBJECT_HINT|IOP_CREATE_IGNORE_SHARE_ACCESS_CHECK)) {
  833. fileObjectSize = sizeof(FILE_OBJECT) + sizeof(IOP_FILE_OBJECT_EXTENSION);
  834. } else {
  835. fileObjectSize = sizeof(FILE_OBJECT);
  836. }
  837. status = ObCreateObject( KernelMode,
  838. IoFileObjectType,
  839. &objectAttributes,
  840. AccessMode,
  841. (PVOID) NULL,
  842. fileObjectSize,
  843. 0,
  844. 0,
  845. (PVOID *) &fileObject );
  846. if (!NT_SUCCESS( status )) {
  847. IoFreeIrp( irp );
  848. IopDecrementDeviceObjectRef( parseDeviceObject, FALSE, FALSE );
  849. if (vpb) {
  850. IopDereferenceVpbAndFree(vpb);
  851. }
  852. return op->FinalStatus = status;
  853. }
  854. IopPerfLogFileCreate(fileObject, CompleteName);
  855. RtlZeroMemory( fileObject, sizeof( FILE_OBJECT ) );
  856. if (op->CreateOptions & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) {
  857. fileObject->Flags = FO_SYNCHRONOUS_IO;
  858. if (op->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) {
  859. fileObject->Flags |= FO_ALERTABLE_IO;
  860. }
  861. }
  862. if (op->InternalFlags &
  863. (IOP_CREATE_USE_TOP_DEVICE_OBJECT_HINT|IOP_CREATE_IGNORE_SHARE_ACCESS_CHECK)) {
  864. PIOP_FILE_OBJECT_EXTENSION fileObjectExtension;
  865. fileObject->Flags |= FO_FILE_OBJECT_HAS_EXTENSION;
  866. fileObjectExtension = (PIOP_FILE_OBJECT_EXTENSION)(fileObject + 1);
  867. fileObjectExtension->FileObjectExtensionFlags = 0;
  868. fileObjectExtension->TopDeviceObjectHint = NULL;
  869. fileObjectExtension->FilterContext = NULL;
  870. if (op->InternalFlags & IOP_CREATE_USE_TOP_DEVICE_OBJECT_HINT) {
  871. fileObjectExtension->TopDeviceObjectHint = deviceObject;
  872. }
  873. if (op->InternalFlags & IOP_CREATE_IGNORE_SHARE_ACCESS_CHECK) {
  874. fileObjectExtension->FileObjectExtensionFlags |=FO_EXTENSION_IGNORE_SHARE_ACCESS_CHECK;
  875. }
  876. }
  877. //
  878. // Now fill in the file object as best is possible at this point and set
  879. // a pointer to it in the IRP so everyone else can find it.
  880. //
  881. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  882. KeInitializeEvent( &fileObject->Lock, SynchronizationEvent, FALSE );
  883. fileObject->Waiters = 0;
  884. fileObject->CurrentByteOffset.QuadPart = 0;
  885. }
  886. if (op->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) {
  887. fileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
  888. }
  889. if (op->CreateOptions & FILE_WRITE_THROUGH) {
  890. fileObject->Flags |= FO_WRITE_THROUGH;
  891. }
  892. if (op->CreateOptions & FILE_SEQUENTIAL_ONLY) {
  893. fileObject->Flags |= FO_SEQUENTIAL_ONLY;
  894. }
  895. if (op->CreateOptions & FILE_RANDOM_ACCESS) {
  896. fileObject->Flags |= FO_RANDOM_ACCESS;
  897. }
  898. } else {
  899. //
  900. // This is either a quick delete or query operation. For these cases,
  901. // it is possible to optimize the Object Manager out of the picture by
  902. // simply putting together something that "looks" like a file object,
  903. // and then operating on it.
  904. //
  905. localFileObject = op->LocalFileObject;
  906. RtlZeroMemory( localFileObject, sizeof( DUMMY_FILE_OBJECT ) );
  907. fileObject = (PFILE_OBJECT) &localFileObject->ObjectHeader.Body;
  908. localFileObject->ObjectHeader.Type = IoFileObjectType;
  909. localFileObject->ObjectHeader.PointerCount = 1;
  910. }
  911. if (directDeviceOpen) {
  912. fileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
  913. }
  914. if (!(Attributes & OBJ_CASE_INSENSITIVE)) {
  915. fileObject->Flags |= FO_OPENED_CASE_SENSITIVE;
  916. }
  917. fileObject->Type = IO_TYPE_FILE;
  918. fileObject->Size = sizeof( FILE_OBJECT );
  919. fileObject->RelatedFileObject = op->RelatedFileObject;
  920. fileObject->DeviceObject = parseDeviceObject;
  921. irp->Tail.Overlay.OriginalFileObject = fileObject;
  922. irpSp->FileObject = fileObject;
  923. //
  924. // Allocate a file name string buffer which is large enough to contain
  925. // the entire remaining name string and initialize the maximum length.
  926. //
  927. if (RemainingName->Length) {
  928. fileObject->FileName.MaximumLength = RoundNameSize( RemainingName->Length );
  929. fileObject->FileName.Buffer = ExAllocatePoolWithTag( PagedPool,
  930. fileObject->FileName.MaximumLength,
  931. 'mNoI' );
  932. if (!fileObject->FileName.Buffer) {
  933. IoFreeIrp( irp );
  934. IopDecrementDeviceObjectRef( parseDeviceObject, FALSE, FALSE );
  935. if (vpb) {
  936. IopDereferenceVpbAndFree(vpb);
  937. }
  938. fileObject->DeviceObject = (PDEVICE_OBJECT) NULL;
  939. if (realFileObjectRequired) {
  940. ObDereferenceObject( fileObject );
  941. }
  942. return STATUS_INSUFFICIENT_RESOURCES;
  943. }
  944. }
  945. //
  946. // Now copy the name string into the file object from the remaining name
  947. // that is being reparsed. If the driver decides to reparse, then it must
  948. // replace this name.
  949. //
  950. RtlCopyUnicodeString( &fileObject->FileName, RemainingName );
  951. //
  952. // Before invoking the driver's open routine, check to see whether or not
  953. // this is a fast network attributes query and, if so, and the driver
  954. // implements the function, attempt to call it here.
  955. //
  956. if (op->QueryOnly) {
  957. PFAST_IO_DISPATCH fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;
  958. BOOLEAN result;
  959. if (fastIoDispatch &&
  960. fastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET( FAST_IO_DISPATCH, FastIoQueryOpen ) &&
  961. fastIoDispatch->FastIoQueryOpen) {
  962. IoSetNextIrpStackLocation( irp );
  963. irpSp->DeviceObject = deviceObject;
  964. result = (fastIoDispatch->FastIoQueryOpen)( irp,
  965. op->NetworkInformation,
  966. deviceObject );
  967. if (result) {
  968. op->FinalStatus = irp->IoStatus.Status;
  969. op->Information = irp->IoStatus.Information;
  970. //
  971. // The operation worked, so simply dereference and free the
  972. // resources acquired up to this point.
  973. //
  974. if ((op->FinalStatus == STATUS_REPARSE) &&
  975. irp->Tail.Overlay.AuxiliaryBuffer) {
  976. ASSERT( op->Information > IO_REPARSE_TAG_RESERVED_ONE );
  977. ExFreePool( irp->Tail.Overlay.AuxiliaryBuffer );
  978. irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  979. op->RelatedFileObject = (PFILE_OBJECT) NULL;
  980. }
  981. if (fileObject->FileName.Length) {
  982. ExFreePool( fileObject->FileName.Buffer );
  983. }
  984. IopDecrementDeviceObjectRef( parseDeviceObject, FALSE, FALSE );
  985. if (vpb) {
  986. IopDereferenceVpbAndFree(vpb);
  987. }
  988. #if DBG
  989. irp->CurrentLocation = irp->StackCount + 2;
  990. #endif // DBG
  991. IoFreeIrp( irp );
  992. //
  993. // Finally, indicate that the parse routine was actually
  994. // invoked and that the information returned herein can be
  995. // used.
  996. //
  997. op->ParseCheck = OPEN_PACKET_PATTERN;
  998. status = STATUS_SUCCESS;
  999. if (!op->FullAttributes) {
  1000. try {
  1001. op->BasicInformation->FileAttributes = op->NetworkInformation->FileAttributes;
  1002. } except(EXCEPTION_EXECUTE_HANDLER) {
  1003. status = GetExceptionCode();
  1004. }
  1005. }
  1006. return status;
  1007. } else {
  1008. //
  1009. // The fast I/O operation did not work, so take the longer
  1010. // route.
  1011. //
  1012. irp->Tail.Overlay.CurrentStackLocation++;
  1013. irp->CurrentLocation++;
  1014. }
  1015. }
  1016. }
  1017. //
  1018. // Finally, initialize the file object's event to the Not Signaled state
  1019. // and remember that a file object was created.
  1020. //
  1021. KeInitializeEvent( &fileObject->Event, NotificationEvent, FALSE );
  1022. op->FileObject = fileObject;
  1023. //
  1024. // Insert the packet at the head of the IRP list for the thread.
  1025. //
  1026. IopQueueThreadIrp( irp );
  1027. //
  1028. // Now invoke the driver itself to open the file.
  1029. //
  1030. status = IoCallDriver( deviceObject, irp );
  1031. //
  1032. // One of four things may have happened when the driver was invoked:
  1033. //
  1034. // 1. The I/O operation is pending (Status == STATUS_PENDING). This can
  1035. // occur on devices which need to perform some sort of device
  1036. // manipulation (such as opening a file for a file system).
  1037. //
  1038. // 2. The driver returned an error (Status < 0). This occurs when either
  1039. // a supplied parameter was in error, or the device or file system
  1040. // incurred or discovered an error.
  1041. //
  1042. // 3. The operation ended in a reparse (Status == STATUS_REPARSE). This
  1043. // occurs when a file system opens the file, only to discover that it
  1044. // represents a symbolic link.
  1045. //
  1046. // 4. The operation is complete and was successful (Status ==
  1047. // STATUS_SUCCESS). Note that for this case the only action is to
  1048. // return a pointer to the file object.
  1049. //
  1050. if (status == STATUS_PENDING) {
  1051. (VOID) KeWaitForSingleObject( &fileObject->Event,
  1052. Executive,
  1053. KernelMode,
  1054. FALSE,
  1055. (PLARGE_INTEGER) NULL );
  1056. status = ioStatus.Status;
  1057. } else {
  1058. //
  1059. // The I/O operation was completed without returning a status of
  1060. // pending. This means that at this point, the IRP has not been
  1061. // fully completed. Complete it now.
  1062. //
  1063. KIRQL irql;
  1064. ASSERT( !irp->PendingReturned );
  1065. ASSERT( !irp->MdlAddress );
  1066. //
  1067. // In the case of name junctions do the transmogrify work.
  1068. //
  1069. if (irp->IoStatus.Status == STATUS_REPARSE &&
  1070. irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT ) {
  1071. PREPARSE_DATA_BUFFER reparseBuffer = NULL;
  1072. ASSERT ( irp->Tail.Overlay.AuxiliaryBuffer != NULL );
  1073. reparseBuffer = (PREPARSE_DATA_BUFFER) irp->Tail.Overlay.AuxiliaryBuffer;
  1074. ASSERT( reparseBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT );
  1075. ASSERT( reparseBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
  1076. ASSERT( reparseBuffer->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
  1077. IopDoNameTransmogrify( irp,
  1078. fileObject,
  1079. reparseBuffer );
  1080. }
  1081. //
  1082. // Now finish up the request.
  1083. //
  1084. KeRaiseIrql( APC_LEVEL, &irql );
  1085. //
  1086. // Note that normally the system would simply call IopCompleteRequest
  1087. // here to complete the packet. However, because this is a create
  1088. // operation, several assumptions can be made that make it much faster
  1089. // to perform the couple of operations that completing the request
  1090. // would perform. These include: copying the I/O status block,
  1091. // dequeueing the IRP and freeing it, and setting the file object's
  1092. // event to the signalled state. The latter is done here by hand,
  1093. // since it is known that it is not possible for any thread to be
  1094. // waiting on the event.
  1095. //
  1096. ioStatus = irp->IoStatus;
  1097. status = ioStatus.Status;
  1098. fileObject->Event.Header.SignalState = 1;
  1099. IopDequeueThreadIrp( irp );
  1100. //
  1101. // The SystemBuffer is in some cases used by the driver, and
  1102. // needs to be freed if present.
  1103. //
  1104. if ((irp->Flags & IRP_BUFFERED_IO) && (irp->Flags & IRP_DEALLOCATE_BUFFER)) {
  1105. ExFreePool(irp->AssociatedIrp.SystemBuffer);
  1106. }
  1107. IoFreeIrp( irp );
  1108. KeLowerIrql( irql );
  1109. }
  1110. //
  1111. // Copy the information field of the I/O status block back to the
  1112. // original caller in case it is required.
  1113. //
  1114. op->Information = ioStatus.Information;
  1115. if (!NT_SUCCESS( status )) {
  1116. int openCancelled;
  1117. //
  1118. // The operation ended in an error. Kill the file object, dereference
  1119. // the device object, and return a null pointer.
  1120. //
  1121. if (fileObject->FileName.Length) {
  1122. ExFreePool( fileObject->FileName.Buffer );
  1123. fileObject->FileName.Length = 0;
  1124. }
  1125. fileObject->DeviceObject = (PDEVICE_OBJECT) NULL;
  1126. openCancelled = (fileObject->Flags & FO_FILE_OPEN_CANCELLED);
  1127. if (realFileObjectRequired) {
  1128. ObDereferenceObject( fileObject );
  1129. }
  1130. op->FileObject = (PFILE_OBJECT) NULL;
  1131. IopDecrementDeviceObjectRef( parseDeviceObject, FALSE, FALSE );
  1132. if ((!openCancelled) && (vpb )) {
  1133. IopDereferenceVpbAndFree(vpb);
  1134. }
  1135. return op->FinalStatus = status;
  1136. } else if (status == STATUS_REPARSE) {
  1137. //
  1138. // The operation resulted in a reparse. This means that the file
  1139. // name in the file object is the new name to be looked up. Replace
  1140. // the complete name string with the new name and return STATUS_REPARSE
  1141. // so the object manager knows to start over again. Note, however,
  1142. // that the file name buffer in the file object itself is kept intact
  1143. // so that it can be reused when coming back here again.
  1144. //
  1145. // A reparse status may also have been returned from the file system if
  1146. // the volume that was in a drive needed to have been verified, but
  1147. // the verification failed, and a new volume was mounted. In this
  1148. // case, everything starts over again using the new volume.
  1149. //
  1150. ASSERT( IO_REPARSE == IO_REPARSE_TAG_RESERVED_ZERO );
  1151. if ((ioStatus.Information == IO_REPARSE) ||
  1152. (ioStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)) {
  1153. //
  1154. // If the complete name buffer isn't large enough, reallocate it.
  1155. //
  1156. if (CompleteName->MaximumLength < fileObject->FileName.Length) {
  1157. PVOID buffer;
  1158. buffer = ExAllocatePoolWithTag( PagedPool,
  1159. fileObject->FileName.Length,
  1160. 'cFoI' );
  1161. if (!buffer) {
  1162. return op->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
  1163. } else {
  1164. if (CompleteName->Buffer) {
  1165. ExFreePool( CompleteName->Buffer );
  1166. }
  1167. CompleteName->Buffer = buffer;
  1168. CompleteName->MaximumLength = fileObject->FileName.Length;
  1169. }
  1170. }
  1171. RtlCopyUnicodeString( CompleteName, &fileObject->FileName );
  1172. //
  1173. // For NTFS directory junction points we NULL the RelatedFileObject.
  1174. // If the prior call was a relative open, the subsequent one will
  1175. // not be.
  1176. //
  1177. if (ioStatus.Information == IO_REPARSE_TAG_MOUNT_POINT) {
  1178. op->RelatedFileObject = (PFILE_OBJECT) NULL;
  1179. }
  1180. }
  1181. //
  1182. // Kill the file object, dereference the device object, and return a
  1183. // null pointer.
  1184. //
  1185. if (fileObject->FileName.Length) {
  1186. ExFreePool( fileObject->FileName.Buffer );
  1187. fileObject->FileName.Length = 0;
  1188. }
  1189. fileObject->DeviceObject = (PDEVICE_OBJECT) NULL;
  1190. if (realFileObjectRequired) {
  1191. ObDereferenceObject( fileObject );
  1192. }
  1193. op->FileObject = (PFILE_OBJECT) NULL;
  1194. IopDecrementDeviceObjectRef( parseDeviceObject, FALSE, FALSE );
  1195. if (vpb) {
  1196. IopDereferenceVpbAndFree(vpb);
  1197. }
  1198. ASSERT( IO_REMOUNT == IO_REPARSE_TAG_RESERVED_ONE );
  1199. if (ioStatus.Information == IO_REPARSE_TAG_RESERVED_ONE) {
  1200. //
  1201. // If we are reparsing to verify a volume, restart the reparse
  1202. // by attempting to parse the device once again. Note that it
  1203. // would be best to simply recurse, but it's not possible since
  1204. // there is a limited amount of stack available to kernel mode
  1205. // and a limit needs to be enforced for the number of times that
  1206. // verify reparse can occur.
  1207. //
  1208. if (++retryCount > IO_MAX_REMOUNT_REPARSE_ATTEMPTS) {
  1209. return STATUS_UNSUCCESSFUL;
  1210. }
  1211. goto reparse_loop;
  1212. } else {
  1213. //
  1214. // Really reparsing a symbolic link, so go back to the object
  1215. // manager so it can begin the parse from the top.
  1216. //
  1217. op->RelatedFileObject = (PFILE_OBJECT) NULL;
  1218. //
  1219. // Note that the mountpoint should be set only for the correct
  1220. // tag. IO_REMOUNT is sent by FAT,CDFS and UDFS to remount a volume.
  1221. // IO_REPARSE is set by the network filesystems to just use a different path.
  1222. //
  1223. if (ioStatus.Information == IO_REPARSE_TAG_MOUNT_POINT) {
  1224. op->TraversedMountPoint = TRUE;
  1225. }
  1226. return STATUS_REPARSE;
  1227. }
  1228. } else {
  1229. //
  1230. // The operation was successful. The first thing to do is to see if
  1231. // the device that processed the open also opened the file. If
  1232. // not, we need to adjust the vpb reference counts. Then, if this is
  1233. // not a query or a delete, but rather a normal open/create, return
  1234. // the address of the FileObject to the caller and set the
  1235. // information returned in the original requestor's I/O status block.
  1236. // Also set the value of the parse check field in the open packet to
  1237. // a value which will let the caller know that this routine was
  1238. // successful in creating the file object. Finally, return the status
  1239. // of the operation to the caller.
  1240. //
  1241. PDEVICE_OBJECT deviceObjectThatOpenedFile;
  1242. deviceObjectThatOpenedFile = IoGetRelatedDeviceObject(fileObject);
  1243. if (deviceObject != deviceObjectThatOpenedFile) {
  1244. //
  1245. // The device that opened the related file is not the one
  1246. // that opened this file. So, readjust the vpb reference
  1247. // counts.
  1248. if (vpb) {
  1249. IopDereferenceVpbAndFree(vpb);
  1250. }
  1251. vpb = fileObject->Vpb;
  1252. if (vpb) {
  1253. IopInterlockedIncrementUlong( LockQueueIoVpbLock,
  1254. &vpb->ReferenceCount);
  1255. }
  1256. }
  1257. if (realFileObjectRequired) {
  1258. *Object = fileObject;
  1259. op->ParseCheck = OPEN_PACKET_PATTERN;
  1260. //
  1261. // Add a reference so the file object cannot go away before
  1262. // the create routine gets chance to flag the object for handle
  1263. // create.
  1264. //
  1265. ObReferenceObject( fileObject );
  1266. //
  1267. // If the filename length is zero and its not a relative open or
  1268. // its a relative open to a volume open then set the volume open flag.
  1269. // Also set it only for filesystem device object volume.
  1270. //
  1271. if ((!fileObject->RelatedFileObject || fileObject->RelatedFileObject->Flags & FO_VOLUME_OPEN) &&
  1272. (!fileObject->FileName.Length)) {
  1273. switch (deviceObjectThatOpenedFile->DeviceType) {
  1274. case FILE_DEVICE_DISK_FILE_SYSTEM:
  1275. case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
  1276. case FILE_DEVICE_TAPE_FILE_SYSTEM:
  1277. case FILE_DEVICE_FILE_SYSTEM:
  1278. fileObject->Flags |= FO_VOLUME_OPEN;
  1279. break;
  1280. default:
  1281. break;
  1282. }
  1283. }
  1284. return op->FinalStatus = ioStatus.Status;
  1285. } else {
  1286. //
  1287. // This is either a quick query or delete operation. Determine
  1288. // which it is and quickly perform the operation.
  1289. //
  1290. if (op->QueryOnly) {
  1291. PFAST_IO_DISPATCH fastIoDispatch;
  1292. BOOLEAN queryResult = FALSE;
  1293. fastIoDispatch = deviceObjectThatOpenedFile->DriverObject->FastIoDispatch;
  1294. if (!op->FullAttributes) {
  1295. PFILE_BASIC_INFORMATION basicInfo = NULL;
  1296. //
  1297. // This is a simple FAT file attribute query. Attempt to
  1298. // obtain the basic information about the file.
  1299. //
  1300. try {
  1301. if (fastIoDispatch && fastIoDispatch->FastIoQueryBasicInfo) {
  1302. queryResult = fastIoDispatch->FastIoQueryBasicInfo(
  1303. fileObject,
  1304. TRUE,
  1305. op->BasicInformation,
  1306. &ioStatus,
  1307. deviceObjectThatOpenedFile
  1308. );
  1309. }
  1310. if (!queryResult) {
  1311. basicInfo = ExAllocatePool( NonPagedPool,
  1312. sizeof( FILE_BASIC_INFORMATION ) );
  1313. if (basicInfo) {
  1314. status = IoQueryFileInformation(
  1315. fileObject,
  1316. FileBasicInformation,
  1317. sizeof( FILE_BASIC_INFORMATION ),
  1318. basicInfo,
  1319. &returnedLength
  1320. );
  1321. if (NT_SUCCESS( status )) {
  1322. RtlCopyMemory( op->BasicInformation,
  1323. basicInfo,
  1324. returnedLength );
  1325. }
  1326. ExFreePool( basicInfo );
  1327. } else {
  1328. status = STATUS_INSUFFICIENT_RESOURCES;
  1329. }
  1330. } else {
  1331. status = ioStatus.Status;
  1332. }
  1333. } except(EXCEPTION_EXECUTE_HANDLER) {
  1334. if (basicInfo) {
  1335. ExFreePool( basicInfo );
  1336. }
  1337. status = GetExceptionCode();
  1338. }
  1339. } else {
  1340. //
  1341. // This is a full attribute query. Attempt to obtain the
  1342. // full network attributes for the file. This includes
  1343. // both the basic and standard information about the
  1344. // file. Try the fast path first, if it exists.
  1345. //
  1346. if (fastIoDispatch &&
  1347. fastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET( FAST_IO_DISPATCH, FastIoQueryNetworkOpenInfo ) &&
  1348. fastIoDispatch->FastIoQueryNetworkOpenInfo) {
  1349. queryResult = fastIoDispatch->FastIoQueryNetworkOpenInfo(
  1350. fileObject,
  1351. TRUE,
  1352. op->NetworkInformation,
  1353. &ioStatus,
  1354. deviceObjectThatOpenedFile
  1355. );
  1356. }
  1357. if (!queryResult) {
  1358. //
  1359. // Either the fast dispatch routine did not exist, or
  1360. // it simply wasn't callable at this time. Attempt to
  1361. // obtain all of the information at once via an IRP-
  1362. // based call.
  1363. //
  1364. status = IoQueryFileInformation(
  1365. fileObject,
  1366. FileNetworkOpenInformation,
  1367. sizeof( FILE_NETWORK_OPEN_INFORMATION ),
  1368. op->NetworkInformation,
  1369. &returnedLength
  1370. );
  1371. if (!NT_SUCCESS( status )) {
  1372. if (status == STATUS_INVALID_PARAMETER ||
  1373. status == STATUS_NOT_IMPLEMENTED) {
  1374. status = IopGetNetworkOpenInformation(fileObject, op);
  1375. }
  1376. }
  1377. }
  1378. }
  1379. } else {
  1380. //
  1381. // There is nothing to do for a quick delete since the caller
  1382. // set the FILE_DELETE_ON_CLOSE CreateOption so it is already
  1383. // set in the file system.
  1384. //
  1385. NOTHING;
  1386. }
  1387. op->ParseCheck = OPEN_PACKET_PATTERN;
  1388. if (realFileObjectRequired) {
  1389. ObDereferenceObject( fileObject );
  1390. } else {
  1391. IopDeleteFile( fileObject );
  1392. }
  1393. op->FileObject = (PFILE_OBJECT) NULL;
  1394. op->FinalStatus = status;
  1395. return status;
  1396. }
  1397. }
  1398. }
  1399. NTSTATUS
  1400. IopGetNetworkOpenInformation(
  1401. IN PFILE_OBJECT FileObject,
  1402. IN POPEN_PACKET Op
  1403. )
  1404. /*++
  1405. Routine Description:
  1406. This routines gets the network information in two steps.
  1407. Its called out as a separate routine from IopParseDevice to save stack for
  1408. common create paths.
  1409. Arguments:
  1410. FileObject - Pointer to the fileobject for the opened file.
  1411. Op - Pointer to the open packet.
  1412. Return Value:
  1413. NTSTATUS
  1414. --*/
  1415. {
  1416. #define COPY_ATTRIBUTES( n, b, s ) { \
  1417. (n)->CreationTime.QuadPart = (b)->CreationTime.QuadPart; \
  1418. (n)->LastAccessTime.QuadPart = (b)->LastAccessTime.QuadPart; \
  1419. (n)->LastWriteTime.QuadPart = (b)->LastWriteTime.QuadPart; \
  1420. (n)->ChangeTime.QuadPart = (b)->ChangeTime.QuadPart; \
  1421. (n)->AllocationSize.QuadPart = (s)->AllocationSize.QuadPart; \
  1422. (n)->EndOfFile.QuadPart = (s)->EndOfFile.QuadPart; \
  1423. (n)->FileAttributes = (b)->FileAttributes; }
  1424. FILE_BASIC_INFORMATION basicInfo;
  1425. FILE_STANDARD_INFORMATION stdInfo;
  1426. ULONG returnedLength;
  1427. NTSTATUS status;
  1428. PAGED_CODE();
  1429. //
  1430. // The IRP-based call did not work either, so
  1431. // simply try to obtain the information by
  1432. // doing IRP-based queries for the basic and
  1433. // standard information and piecing together
  1434. // the results into the caller's buffer. Note
  1435. // that it might be possible to perform fast
  1436. // I/O operations to get the data, but it
  1437. // might also fail because of the above. So
  1438. // simply query the information the long way.
  1439. //
  1440. status = IoQueryFileInformation(
  1441. FileObject,
  1442. FileBasicInformation,
  1443. sizeof( FILE_BASIC_INFORMATION ),
  1444. &basicInfo,
  1445. &returnedLength
  1446. );
  1447. if (NT_SUCCESS( status )) {
  1448. status = IoQueryFileInformation(
  1449. FileObject,
  1450. FileStandardInformation,
  1451. sizeof( FILE_STANDARD_INFORMATION ),
  1452. &stdInfo,
  1453. &returnedLength
  1454. );
  1455. if (NT_SUCCESS( status )) {
  1456. COPY_ATTRIBUTES( Op->NetworkInformation,
  1457. &basicInfo,
  1458. &stdInfo );
  1459. }
  1460. }
  1461. return status;
  1462. }
  1463. NTSTATUS
  1464. IopParseFile(
  1465. IN PVOID ParseObject,
  1466. IN PVOID ObjectType,
  1467. IN PACCESS_STATE AccessState,
  1468. IN KPROCESSOR_MODE AccessMode,
  1469. IN ULONG Attributes,
  1470. IN OUT PUNICODE_STRING CompleteName,
  1471. IN OUT PUNICODE_STRING RemainingName,
  1472. IN OUT PVOID Context OPTIONAL,
  1473. IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
  1474. OUT PVOID *Object
  1475. )
  1476. /*++
  1477. Routine Description:
  1478. This routine interfaces to the NT Object Manager. It is invoked when
  1479. the object system is given the name of an entity to create or open and is
  1480. also given a handle to a directory file object that the operation is to be
  1481. performed relative to. This routine is specified as the parse routine for
  1482. all file objects.
  1483. This routine simply invokes the parse routine for the appropriate device
  1484. that is associated with the file object. It is the responsibility of that
  1485. routine to perform the operation.
  1486. Arguments:
  1487. ParseObject - Pointer to the file object that the name is to be opened or
  1488. created relative to.
  1489. ObjectType - Type of the object being opened.
  1490. AccessState - Running security access state information for operation.
  1491. AccessMode - Access mode of the original caller.
  1492. Attributes - Attributes to be applied to the object.
  1493. CompleteName - Complete name of the object.
  1494. RemainingName - Remaining name of the object.
  1495. Context - Pointer to an Open Packet (OP) from NtCreateFile service.
  1496. SecurityQos - Supplies a pointer to the captured QOS information
  1497. if available.
  1498. Object - The address of a variable to receive the created file object, if
  1499. any.
  1500. Return Value:
  1501. The function return value is one of the following:
  1502. a) Success - This indicates that the function succeeded and the object
  1503. parameter contains the address of the created file object.
  1504. b) Error - This indicates that the file was not found or created and
  1505. no file object was created.
  1506. c) Reparse - This indicates that the remaining name string has been
  1507. replaced by a new name that is to be parsed.
  1508. --*/
  1509. {
  1510. PDEVICE_OBJECT deviceObject;
  1511. POPEN_PACKET op;
  1512. PAGED_CODE();
  1513. //
  1514. // Get the address of the Open Packet (OP).
  1515. //
  1516. op = (POPEN_PACKET) Context;
  1517. //
  1518. // Ensure that this routine is actually being invoked because someone is
  1519. // attempting to open a device or a file through NtCreateFile. This code
  1520. // must be invoked from there (as opposed to some other random object
  1521. // create or open routine).
  1522. //
  1523. if (op == NULL ||
  1524. op->Type != IO_TYPE_OPEN_PACKET ||
  1525. op->Size != sizeof( OPEN_PACKET )) {
  1526. return STATUS_OBJECT_TYPE_MISMATCH;
  1527. }
  1528. //
  1529. // Get a pointer to the device object for this file.
  1530. //
  1531. deviceObject = IoGetRelatedDeviceObject( (PFILE_OBJECT) ParseObject );
  1532. //
  1533. // Pass the related file object to the device object parse routine.
  1534. //
  1535. op->RelatedFileObject = (PFILE_OBJECT) ParseObject;
  1536. //
  1537. // Open or create the specified file.
  1538. //
  1539. return IopParseDevice( deviceObject,
  1540. ObjectType,
  1541. AccessState,
  1542. AccessMode,
  1543. Attributes,
  1544. CompleteName,
  1545. RemainingName,
  1546. Context,
  1547. SecurityQos,
  1548. Object );
  1549. }
  1550. NTSTATUS
  1551. IopQueryNameInternal(
  1552. IN PVOID Object,
  1553. IN BOOLEAN HasObjectName,
  1554. IN BOOLEAN UseDosDeviceName,
  1555. OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
  1556. IN ULONG Length,
  1557. OUT PULONG ReturnLength
  1558. )
  1559. /*++
  1560. Routine Description:
  1561. This function implements the query name procedure for the Object Manager
  1562. for querying the names of file objects.
  1563. Arguments:
  1564. Object - Pointer to the file object whose name is to be retrieved.
  1565. HasObjectName - Indicates whether or not the object has a name.
  1566. UseDosDeviceName - Indicates whether to translate the device object part
  1567. of the fileobject into the dosdevice name space or the
  1568. regular \device namespace via ob
  1569. ObjectNameInfo - Buffer in which to return the name.
  1570. Length - Specifies the length of the output buffer, in bytes.
  1571. ReturnLength - Specifies the number of bytes actually returned in the
  1572. output buffer.
  1573. Return Value:
  1574. The function return value is the final status of the query operation.
  1575. --*/
  1576. {
  1577. NTSTATUS status;
  1578. ULONG lengthNeeded;
  1579. PFILE_OBJECT fileObject;
  1580. PUCHAR buffer;
  1581. PWSTR p;
  1582. POBJECT_NAME_INFORMATION deviceNameInfo;
  1583. PFILE_NAME_INFORMATION fileNameInfo;
  1584. ULONG length;
  1585. BOOLEAN deviceNameOverflow;
  1586. BOOLEAN dosLookupSuccess = 0;
  1587. UNREFERENCED_PARAMETER( HasObjectName );
  1588. PAGED_CODE();
  1589. ASSERT( FIELD_OFFSET( FILE_NAME_INFORMATION, FileName ) < sizeof( OBJECT_NAME_INFORMATION ) );
  1590. //
  1591. // Ensure that the size of the output buffer is at least the minimum
  1592. // size required to include the basic object name information structure.
  1593. //
  1594. if (Length < sizeof( OBJECT_NAME_INFORMATION )) {
  1595. return STATUS_INFO_LENGTH_MISMATCH;
  1596. }
  1597. //
  1598. // Begin by allocating a buffer in which to build the name of the file.
  1599. //
  1600. buffer = ExAllocatePoolWithTag( PagedPool, Length, ' oI' );
  1601. if (!buffer) {
  1602. return STATUS_INSUFFICIENT_RESOURCES;
  1603. }
  1604. try {
  1605. //
  1606. // Query the name of the device on which the file is open.
  1607. //
  1608. fileObject = (PFILE_OBJECT) Object;
  1609. deviceNameInfo = (POBJECT_NAME_INFORMATION) buffer;
  1610. if (UseDosDeviceName) {
  1611. if (fileObject->DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) {
  1612. lengthNeeded = sizeof(OBJECT_NAME_INFORMATION) + 2*sizeof(WCHAR); // For the extra '\' and '\0'
  1613. if (lengthNeeded > Length) {
  1614. status = STATUS_BUFFER_OVERFLOW;
  1615. } else {
  1616. status = STATUS_SUCCESS;
  1617. }
  1618. deviceNameInfo->Name.Length = sizeof(WCHAR);
  1619. deviceNameInfo->Name.MaximumLength = sizeof(WCHAR);
  1620. p = (PWSTR) (deviceNameInfo + 1);
  1621. *p = '\\'; // Start with a '\' as RDR does not return the extra
  1622. deviceNameInfo->Name.Buffer = p;
  1623. } else {
  1624. status = IoVolumeDeviceToDosName( fileObject->DeviceObject, &deviceNameInfo->Name );
  1625. lengthNeeded = sizeof(OBJECT_NAME_INFORMATION) + deviceNameInfo->Name.Length + sizeof(WCHAR);
  1626. }
  1627. //
  1628. // If querying the dos name fails try to atleast get the real device name
  1629. //
  1630. if (!NT_SUCCESS(status)) {
  1631. status = ObQueryNameString( (PVOID) fileObject->DeviceObject,
  1632. deviceNameInfo,
  1633. Length,
  1634. &lengthNeeded );
  1635. } else {
  1636. dosLookupSuccess++;
  1637. }
  1638. } else {
  1639. status = ObQueryNameString( (PVOID) fileObject->DeviceObject,
  1640. deviceNameInfo,
  1641. Length,
  1642. &lengthNeeded );
  1643. }
  1644. if (!NT_SUCCESS( status )) {
  1645. if (status != STATUS_INFO_LENGTH_MISMATCH) {
  1646. return status;
  1647. }
  1648. }
  1649. //
  1650. // Ensure that there is enough room in the output buffer to return the
  1651. // name and copy it.
  1652. //
  1653. p = (PWSTR) (ObjectNameInfo + 1);
  1654. //
  1655. // If we got a DOS name, note the name isn't contiguous to the device name info,
  1656. // and that we should free it (the Rtl call did not know we allocated this big
  1657. // buffer, and made a new one).
  1658. //
  1659. if (UseDosDeviceName && dosLookupSuccess) {
  1660. ULONG BaseCopyLength;
  1661. ULONG NameCopyLength;
  1662. //
  1663. // Figure out how much of each part we can copy.
  1664. //
  1665. BaseCopyLength = sizeof(UNICODE_STRING);
  1666. if ( Length < lengthNeeded ) {
  1667. if ( Length < sizeof(UNICODE_STRING)) {
  1668. BaseCopyLength = Length;
  1669. NameCopyLength = 0;
  1670. } else {
  1671. NameCopyLength = Length - BaseCopyLength;
  1672. }
  1673. } else {
  1674. NameCopyLength = deviceNameInfo->Name.Length;
  1675. }
  1676. //
  1677. // Copy in two parts - the base chunk of the UNICODE_STRING and then
  1678. // as much of the name as will fit.
  1679. //
  1680. RtlCopyMemory( ObjectNameInfo,
  1681. deviceNameInfo,
  1682. BaseCopyLength );
  1683. RtlCopyMemory( p,
  1684. deviceNameInfo->Name.Buffer,
  1685. NameCopyLength );
  1686. if (fileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM) {
  1687. ExFreePool( deviceNameInfo->Name.Buffer );
  1688. }
  1689. } else {
  1690. RtlCopyMemory( ObjectNameInfo,
  1691. deviceNameInfo,
  1692. lengthNeeded > Length ? Length : lengthNeeded );
  1693. }
  1694. ObjectNameInfo->Name.Buffer = p;
  1695. p = (PWSTR) ((PCHAR) p + deviceNameInfo->Name.Length);
  1696. //
  1697. // If the buffer is already full, note and continue to pick up the filename length.
  1698. // We want to return the required length for the entire result.
  1699. //
  1700. deviceNameOverflow = FALSE;
  1701. if (lengthNeeded > Length) {
  1702. *ReturnLength = lengthNeeded;
  1703. deviceNameOverflow = TRUE;
  1704. }
  1705. //
  1706. // Reset the state for the buffer to obtain the filename portion of the
  1707. // name and calculate the remaining length of the caller's buffer. Note
  1708. // that in the following calculations, there are two assumptions and
  1709. // and dependencies:
  1710. //
  1711. // 1) The above query of the device name's returned length needed
  1712. // include a NULL character which will be included at the end
  1713. // of the entire name. This is included in the calculations
  1714. // although it does not appear to be included.
  1715. //
  1716. // 2) The sizeof the object name information buffer is assumed
  1717. // (and guaranteed because it can never change) to be larger
  1718. // than the filename offset in a file name information buffer.
  1719. // Therefore it is known that the new length of the "buffer"
  1720. // variable can be set to the remaining length plus at least 4.
  1721. //
  1722. fileNameInfo = (PFILE_NAME_INFORMATION) buffer;
  1723. if (deviceNameOverflow) {
  1724. length = Length;
  1725. } else {
  1726. length = Length - lengthNeeded;
  1727. length += FIELD_OFFSET( FILE_NAME_INFORMATION, FileName );
  1728. }
  1729. if (((KeGetPreviousMode() == UserMode) && (!UseDosDeviceName)) ||
  1730. !(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  1731. //
  1732. // Query the name of the file based using an intermediary buffer.
  1733. //
  1734. status = IoQueryFileInformation( fileObject,
  1735. FileNameInformation,
  1736. length,
  1737. (PVOID) fileNameInfo,
  1738. &lengthNeeded );
  1739. } else {
  1740. //
  1741. // This is a kernel mode request for a file that was opened for
  1742. // synchronous I/O. A special function that does not obtain the
  1743. // file object lock is required, otherwise the request may deadlock
  1744. // since the lock is probably already owned.
  1745. //
  1746. status = IopGetFileInformation( fileObject,
  1747. length,
  1748. FileNameInformation,
  1749. fileNameInfo,
  1750. &lengthNeeded );
  1751. }
  1752. //
  1753. // If an error occurred attempting to obtain the filename return now. Note
  1754. // that buffer overflow is a warning, not an error.
  1755. //
  1756. if (NT_ERROR( status )) {
  1757. if (status == STATUS_INVALID_PARAMETER ||
  1758. status == STATUS_INVALID_DEVICE_REQUEST ||
  1759. status == STATUS_NOT_IMPLEMENTED ||
  1760. status == STATUS_INVALID_INFO_CLASS) {
  1761. lengthNeeded = FIELD_OFFSET( FILE_NAME_INFORMATION, FileName );
  1762. fileNameInfo->FileNameLength = 0;
  1763. fileNameInfo->FileName[0] = OBJ_NAME_PATH_SEPARATOR;
  1764. status = STATUS_SUCCESS;
  1765. } else {
  1766. return status;
  1767. }
  1768. }
  1769. //
  1770. // Compute the correct length
  1771. // Note that ReturnLength already contains a space for NULL added by the previous ObQueryNameString.
  1772. //
  1773. if (deviceNameOverflow) {
  1774. *ReturnLength += fileNameInfo->FileNameLength;
  1775. return STATUS_BUFFER_OVERFLOW;
  1776. }
  1777. //
  1778. // Set the remaining length of the caller's buffer as well as the total
  1779. // length needed to contain the entire name of the file.
  1780. //
  1781. length = lengthNeeded - FIELD_OFFSET( FILE_NAME_INFORMATION, FileName );
  1782. lengthNeeded = (ULONG)((PUCHAR) p - (PUCHAR) ObjectNameInfo) + fileNameInfo->FileNameLength;
  1783. //
  1784. // Attempt to copy the name of the file into the output buffer. Note
  1785. // that if the file name does not begin w/a '\', then it is not volume
  1786. // relative, so the name of the file cannot be expressed as the
  1787. // concatenation of the name of the device and the file. Therefore an
  1788. // error is returned.
  1789. //
  1790. // The only example of this situation known at this time is when one
  1791. // opens a directory by file ID, and then opens a file relative to that
  1792. // directory. When attempting to query the path, if the caller did not
  1793. // have traverse access to open the directory, then the only name that
  1794. // can be returned is the path name to the file from the directory, but
  1795. // the volume-relative name cannot be returned. Therefore, the file
  1796. // system returns only the name of the directory and the path to the
  1797. // file, but this is not volume-relative so the only recourse is to
  1798. // return an error.
  1799. //
  1800. // Note that if the caller were to call NtQueryInformationFile and
  1801. // request FileNameInformation, then the name above named will be
  1802. // successfully returned from the file system.
  1803. //
  1804. if (fileNameInfo->FileName[0] != OBJ_NAME_PATH_SEPARATOR) {
  1805. return STATUS_OBJECT_PATH_INVALID;
  1806. }
  1807. RtlCopyMemory( p,
  1808. fileNameInfo->FileName,
  1809. length );
  1810. p = (PWSTR) ((PCH) p + length);
  1811. *p = '\0';
  1812. lengthNeeded += sizeof( WCHAR );
  1813. *ReturnLength = lengthNeeded;
  1814. length = (ULONG)((PUCHAR) p - (PUCHAR) ObjectNameInfo);
  1815. ObjectNameInfo->Name.Length = (USHORT) (length - sizeof( *ObjectNameInfo ));
  1816. ObjectNameInfo->Name.MaximumLength = (USHORT) ((length - sizeof( *ObjectNameInfo )) + sizeof( WCHAR ));
  1817. }
  1818. finally {
  1819. //
  1820. // Finally, free the temporary buffer.
  1821. //
  1822. ExFreePool( buffer );
  1823. }
  1824. return status;
  1825. }
  1826. NTSTATUS
  1827. IopQueryName(
  1828. IN PVOID Object,
  1829. IN BOOLEAN HasObjectName,
  1830. OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
  1831. IN ULONG Length,
  1832. OUT PULONG ReturnLength
  1833. )
  1834. /*++
  1835. Routine Description:
  1836. This function implements the query name procedure for the Object Manager
  1837. for querying the names of file objects.
  1838. Arguments:
  1839. Object - Pointer to the file object whose name is to be retrieved.
  1840. HasObjectName - Indicates whether or not the object has a name.
  1841. ObjectNameInfo - Buffer in which to return the name.
  1842. Length - Specifies the length of the output buffer, in bytes.
  1843. ReturnLength - Specifies the number of bytes actually returned in the
  1844. output buffer.
  1845. Return Value:
  1846. The function return value is the final status of the query operation.
  1847. --*/
  1848. {
  1849. return IopQueryNameInternal( Object,
  1850. HasObjectName,
  1851. FALSE,
  1852. ObjectNameInfo,
  1853. Length,
  1854. ReturnLength );
  1855. }
  1856. VOID
  1857. IopCheckBackupRestorePrivilege(
  1858. IN PACCESS_STATE AccessState,
  1859. IN OUT PULONG CreateOptions,
  1860. IN KPROCESSOR_MODE PreviousMode,
  1861. IN ULONG Disposition
  1862. )
  1863. /*++
  1864. Routine Description:
  1865. This funcion will determine if the caller is asking for any accesses
  1866. that may be satisfied by Backup or Restore privileges, and if so,
  1867. perform the privilge checks. If the privilege checks succeed, then
  1868. the appropriate bits will be moved out of the RemainingDesiredAccess
  1869. field in the AccessState structure and placed into the PreviouslyGrantedAccess
  1870. field.
  1871. Note that access is not denied if the caller does not have either or
  1872. both of the privileges, since he may be granted the desired access
  1873. via the security descriptor on the object.
  1874. This routine will also set a flag in the AccessState structure so that
  1875. it will not perform these privilege checks again in case we come through
  1876. this way again due to a reparse.
  1877. Arguments:
  1878. AccessState - The AccessState containing the current state of this access
  1879. attempt.
  1880. CreateOptions - The CreateOptions field from the OPEN_PACKET structure for
  1881. this open attempt.
  1882. PreviousMode - The processor mode to be used in checking parameters.
  1883. Disposition - The create disposition for this request.
  1884. Return Value:
  1885. None.
  1886. --*/
  1887. {
  1888. ACCESS_MASK desiredAccess;
  1889. ACCESS_MASK readAccess;
  1890. ACCESS_MASK writeAccess;
  1891. PRIVILEGE_SET requiredPrivileges;
  1892. BOOLEAN accessGranted;
  1893. BOOLEAN keepBackupIntent = FALSE;
  1894. BOOLEAN ForceRestoreCheck = FALSE;
  1895. PAGED_CODE();
  1896. //
  1897. // Check to determine whether or not this check has already been made.
  1898. // If so, simply return back to the caller.
  1899. //
  1900. if (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED) {
  1901. return;
  1902. }
  1903. if (*CreateOptions & FILE_OPEN_FOR_BACKUP_INTENT) {
  1904. AccessState->Flags |= SE_BACKUP_PRIVILEGES_CHECKED;
  1905. readAccess = READ_CONTROL | ACCESS_SYSTEM_SECURITY | FILE_GENERIC_READ | FILE_TRAVERSE;
  1906. writeAccess = WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY | FILE_GENERIC_WRITE | FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | DELETE;
  1907. desiredAccess = AccessState->RemainingDesiredAccess;
  1908. //
  1909. // If the caller has requested MAXIMUM_ALLOWED, then make it appear as
  1910. // if the request was for everything permitted by Backup and Restore,
  1911. // and then grant everything that can actually be granted.
  1912. //
  1913. if (desiredAccess & MAXIMUM_ALLOWED) {
  1914. desiredAccess |= ( readAccess | writeAccess );
  1915. }
  1916. //
  1917. // If the disposition says that we're opening the file, check for both backup
  1918. // and restore privilege, depending on what's in the desired access.
  1919. //
  1920. // If the disposition says that we're creating or trying to overwrite the file,
  1921. // then all we need to do is to check for restore privilege, and if it's there,
  1922. // grant every possible access.
  1923. //
  1924. if ((Disposition == FILE_OPEN ) || (Disposition == FILE_OPEN_IF) || (Disposition == FILE_OVERWRITE_IF)) {
  1925. //
  1926. // If the request was for any of the bits in the read access mask, then
  1927. // assume that this is a backup operation, and check for the Backup
  1928. // privielege. If the caller has it, then grant the intersection of
  1929. // the desired access and read access masks.
  1930. //
  1931. if (readAccess & desiredAccess) {
  1932. requiredPrivileges.PrivilegeCount = 1;
  1933. requiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
  1934. requiredPrivileges.Privilege[0].Luid = SeBackupPrivilege;
  1935. requiredPrivileges.Privilege[0].Attributes = 0;
  1936. accessGranted = SePrivilegeCheck( &requiredPrivileges,
  1937. &AccessState->SubjectSecurityContext,
  1938. PreviousMode );
  1939. if (accessGranted) {
  1940. //
  1941. // The caller has Backup privilege, so grant the appropriate
  1942. // accesses.
  1943. //
  1944. keepBackupIntent = TRUE;
  1945. (VOID) SeAppendPrivileges( AccessState, &requiredPrivileges );
  1946. AccessState->PreviouslyGrantedAccess |= ( desiredAccess & readAccess );
  1947. AccessState->RemainingDesiredAccess &= ~readAccess;
  1948. desiredAccess &= ~readAccess;
  1949. AccessState->Flags |= TOKEN_HAS_BACKUP_PRIVILEGE;
  1950. }
  1951. }
  1952. } else {
  1953. ForceRestoreCheck = TRUE;
  1954. }
  1955. //
  1956. // If the request was for any of the bits in the write access mask, then
  1957. // assume that this is a restore operation, so check for the Restore
  1958. // privilege. If the caller has it, then grant the intersection of
  1959. // the desired access and write access masks.
  1960. //
  1961. if ((writeAccess & desiredAccess) || ForceRestoreCheck) {
  1962. requiredPrivileges.PrivilegeCount = 1;
  1963. requiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
  1964. requiredPrivileges.Privilege[0].Luid = SeRestorePrivilege;
  1965. requiredPrivileges.Privilege[0].Attributes = 0;
  1966. accessGranted = SePrivilegeCheck( &requiredPrivileges,
  1967. &AccessState->SubjectSecurityContext,
  1968. PreviousMode );
  1969. if (accessGranted) {
  1970. //
  1971. // The caller has Restore privilege, so grant the appropriate
  1972. // accesses.
  1973. //
  1974. keepBackupIntent = TRUE;
  1975. (VOID) SeAppendPrivileges( AccessState, &requiredPrivileges );
  1976. AccessState->PreviouslyGrantedAccess |= (desiredAccess & writeAccess);
  1977. AccessState->RemainingDesiredAccess &= ~writeAccess;
  1978. AccessState->Flags |= TOKEN_HAS_RESTORE_PRIVILEGE;
  1979. }
  1980. }
  1981. //
  1982. // If either of the access types was granted because the caller had
  1983. // backup or restore privilege, then the backup intent flag is kept.
  1984. // Otherwise, it is cleared so that it is not passed onto the driver
  1985. // so that it is not incorrectly propogated anywhere else, since this
  1986. // caller does not actually have the privilege enabled.
  1987. //
  1988. if (!keepBackupIntent) {
  1989. *CreateOptions &= ~FILE_OPEN_FOR_BACKUP_INTENT;
  1990. }
  1991. }
  1992. }