Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

parse.c File Reference

#include "iop.h"

Go to the source code of this file.

Defines

#define RoundNameSize(Length)
#define IO_MAX_REMOUNT_REPARSE_ATTEMPTS   32
#define COPY_ATTRIBUTES(n, b, s)

Functions

NTSTATUS IopCheckDeviceAndDriver (POPEN_PACKET op, PDEVICE_OBJECT parseDeviceObject)
PVPB IopCheckVpbMounted (IN POPEN_PACKET op, IN PDEVICE_OBJECT parseDeviceObject, IN OUT PUNICODE_STRING RemainingName, OUT PNTSTATUS status)
VOID IopDereferenceVpbAndFree (IN PVPB Vpb)
NTSTATUS IopParseDevice (IN PVOID ParseObject, IN PVOID ObjectType, IN PACCESS_STATE AccessState, IN KPROCESSOR_MODE AccessMode, IN ULONG Attributes, IN OUT PUNICODE_STRING CompleteName, IN OUT PUNICODE_STRING RemainingName, IN OUT PVOID Context OPTIONAL, IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, OUT PVOID *Object)
NTSTATUS IopParseFile (IN PVOID ParseObject, IN PVOID ObjectType, IN PACCESS_STATE AccessState, IN KPROCESSOR_MODE AccessMode, IN ULONG Attributes, IN OUT PUNICODE_STRING CompleteName, IN OUT PUNICODE_STRING RemainingName, IN OUT PVOID Context OPTIONAL, IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, OUT PVOID *Object)
NTSTATUS IopQueryName (IN PVOID Object, IN BOOLEAN HasObjectName, OUT POBJECT_NAME_INFORMATION ObjectNameInfo, IN ULONG Length, OUT PULONG ReturnLength)
VOID IopCheckBackupRestorePrivilege (IN PACCESS_STATE AccessState, IN OUT PULONG CreateOptions, IN KPROCESSOR_MODE PreviousMode, IN ULONG Disposition)


Define Documentation

#define COPY_ATTRIBUTES n,
b,
 ) 
 

Value:

{ \ (n)->CreationTime.QuadPart = (b)->CreationTime.QuadPart; \ (n)->LastAccessTime.QuadPart = (b)->LastAccessTime.QuadPart; \ (n)->LastWriteTime.QuadPart = (b)->LastWriteTime.QuadPart; \ (n)->ChangeTime.QuadPart = (b)->ChangeTime.QuadPart; \ (n)->AllocationSize.QuadPart = (s)->AllocationSize.QuadPart; \ (n)->EndOfFile.QuadPart = (s)->EndOfFile.QuadPart; \ (n)->FileAttributes = (b)->FileAttributes; }

Referenced by IopParseDevice().

#define IO_MAX_REMOUNT_REPARSE_ATTEMPTS   32
 

Definition at line 37 of file parse.c.

Referenced by IopParseDevice().

#define RoundNameSize Length   ) 
 

Value:

( \ (Length < 64 - 8) ? 64 - 8 : \ (Length < 128 - 8) ? 128 - 8 :\ (Length < 256 - 8) ? 256 - 8 : Length )

Definition at line 32 of file parse.c.

Referenced by IopParseDevice().


Function Documentation

VOID IopCheckBackupRestorePrivilege IN PACCESS_STATE  AccessState,
IN OUT PULONG  CreateOptions,
IN KPROCESSOR_MODE  PreviousMode,
IN ULONG  Disposition
 

Definition at line 2048 of file parse.c.

References FALSE, PAGED_CODE, SE_BACKUP_PRIVILEGES_CHECKED, SeAppendPrivileges(), SeBackupPrivilege, SePrivilegeCheck(), SeRestorePrivilege, TOKEN_HAS_BACKUP_PRIVILEGE, TOKEN_HAS_RESTORE_PRIVILEGE, TRUE, and VOID().

Referenced by IopParseDevice().

02057 : 02058 02059 This funcion will determine if the caller is asking for any accesses 02060 that may be satisfied by Backup or Restore privileges, and if so, 02061 perform the privilge checks. If the privilege checks succeed, then 02062 the appropriate bits will be moved out of the RemainingDesiredAccess 02063 field in the AccessState structure and placed into the PreviouslyGrantedAccess 02064 field. 02065 02066 Note that access is not denied if the caller does not have either or 02067 both of the privileges, since he may be granted the desired access 02068 via the security descriptor on the object. 02069 02070 This routine will also set a flag in the AccessState structure so that 02071 it will not perform these privilege checks again in case we come through 02072 this way again due to a reparse. 02073 02074 Arguments: 02075 02076 AccessState - The AccessState containing the current state of this access 02077 attempt. 02078 02079 CreateOptions - The CreateOptions field from the OPEN_PACKET structure for 02080 this open attempt. 02081 02082 PreviousMode - The processor mode to be used in checking parameters. 02083 02084 Disposition - The create disposition for this request. 02085 02086 Return Value: 02087 02088 None. 02089 02090 --*/ 02091 02092 { 02093 ACCESS_MASK desiredAccess; 02094 ACCESS_MASK readAccess; 02095 ACCESS_MASK writeAccess; 02096 PRIVILEGE_SET requiredPrivileges; 02097 BOOLEAN accessGranted; 02098 BOOLEAN keepBackupIntent = FALSE; 02099 BOOLEAN ForceRestoreCheck = FALSE; 02100 02101 PAGED_CODE(); 02102 02103 // 02104 // Check to determine whether or not this check has already been made. 02105 // If so, simply return back to the caller. 02106 // 02107 02108 if (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED) { 02109 return; 02110 } 02111 02112 if (*CreateOptions & FILE_OPEN_FOR_BACKUP_INTENT) { 02113 AccessState->Flags |= SE_BACKUP_PRIVILEGES_CHECKED; 02114 02115 readAccess = READ_CONTROL | ACCESS_SYSTEM_SECURITY | FILE_GENERIC_READ | FILE_TRAVERSE; 02116 writeAccess = WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY | FILE_GENERIC_WRITE | FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | DELETE; 02117 02118 desiredAccess = AccessState->RemainingDesiredAccess; 02119 02120 // 02121 // If the caller has requested MAXIMUM_ALLOWED, then make it appear as 02122 // if the request was for everything permitted by Backup and Restore, 02123 // and then grant everything that can actually be granted. 02124 // 02125 02126 if (desiredAccess & MAXIMUM_ALLOWED) { 02127 desiredAccess |= ( readAccess | writeAccess ); 02128 } 02129 02130 // 02131 // If the disposition says that we're opening the file, check for both backup 02132 // and restore privilege, depending on what's in the desired access. 02133 // 02134 // If the disposition says that we're creating or trying to overwrite the file, 02135 // then all we need to do is to check for restore privilege, and if it's there, 02136 // grant every possible access. 02137 // 02138 02139 if ( Disposition & FILE_OPEN ) { 02140 02141 // 02142 // If the request was for any of the bits in the read access mask, then 02143 // assume that this is a backup operation, and check for the Backup 02144 // privielege. If the caller has it, then grant the intersection of 02145 // the desired access and read access masks. 02146 // 02147 02148 if (readAccess & desiredAccess) { 02149 02150 requiredPrivileges.PrivilegeCount = 1; 02151 requiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY; 02152 requiredPrivileges.Privilege[0].Luid = SeBackupPrivilege; 02153 requiredPrivileges.Privilege[0].Attributes = 0; 02154 02155 accessGranted = SePrivilegeCheck( &requiredPrivileges, 02156 &AccessState->SubjectSecurityContext, 02157 PreviousMode ); 02158 02159 if (accessGranted) { 02160 02161 // 02162 // The caller has Backup privilege, so grant the appropriate 02163 // accesses. 02164 // 02165 02166 keepBackupIntent = TRUE; 02167 (VOID) SeAppendPrivileges( AccessState, &requiredPrivileges ); 02168 AccessState->PreviouslyGrantedAccess |= ( desiredAccess & readAccess ); 02169 AccessState->RemainingDesiredAccess &= ~readAccess; 02170 desiredAccess &= ~readAccess; 02171 AccessState->Flags |= TOKEN_HAS_BACKUP_PRIVILEGE; 02172 } 02173 } 02174 02175 } else { 02176 02177 ForceRestoreCheck = TRUE; 02178 } 02179 02180 // 02181 // If the request was for any of the bits in the write access mask, then 02182 // assume that this is a restore operation, so check for the Restore 02183 // privilege. If the caller has it, then grant the intersection of 02184 // the desired access and write access masks. 02185 // 02186 02187 if ((writeAccess & desiredAccess) || ForceRestoreCheck) { 02188 02189 requiredPrivileges.PrivilegeCount = 1; 02190 requiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY; 02191 requiredPrivileges.Privilege[0].Luid = SeRestorePrivilege; 02192 requiredPrivileges.Privilege[0].Attributes = 0; 02193 02194 accessGranted = SePrivilegeCheck( &requiredPrivileges, 02195 &AccessState->SubjectSecurityContext, 02196 PreviousMode ); 02197 02198 if (accessGranted) { 02199 02200 // 02201 // The caller has Restore privilege, so grant the appropriate 02202 // accesses. 02203 // 02204 02205 keepBackupIntent = TRUE; 02206 (VOID) SeAppendPrivileges( AccessState, &requiredPrivileges ); 02207 AccessState->PreviouslyGrantedAccess |= (desiredAccess & writeAccess); 02208 AccessState->RemainingDesiredAccess &= ~writeAccess; 02209 AccessState->Flags |= TOKEN_HAS_RESTORE_PRIVILEGE; 02210 } 02211 } 02212 02213 // 02214 // If either of the access types was granted because the caller had 02215 // backup or restore privilege, then the backup intent flag is kept. 02216 // Otherwise, it is cleared so that it is not passed onto the driver 02217 // so that it is not incorrectly propogated anywhere else, since this 02218 // caller does not actually have the privilege enabled. 02219 // 02220 02221 if (!keepBackupIntent) { 02222 *CreateOptions &= ~FILE_OPEN_FOR_BACKUP_INTENT; 02223 } 02224 } 02225 } }

NTSTATUS IopCheckDeviceAndDriver POPEN_PACKET  op,
PDEVICE_OBJECT  parseDeviceObject
 

Definition at line 47 of file parse.c.

References _DEVICE_OBJECT::DeviceObjectExtension, DO_DEVICE_INITIALIZING, DO_EXCLUSIVE, DOE_DELETE_PENDING, DOE_REMOVE_PENDING, DOE_REMOVE_PROCESSED, DOE_START_PENDING, DOE_UNLOAD_PENDING, _DEVOBJ_EXTENSION::ExtensionFlags, _DEVICE_OBJECT::Flags, IO_ATTACH_DEVICE, IopDatabaseLock, NTSTATUS(), NULL, _OPEN_PACKET::Options, _DEVICE_OBJECT::ReferenceCount, and _OPEN_PACKET::RelatedFileObject.

Referenced by IopParseDevice().

00051 { 00052 NTSTATUS status; 00053 KIRQL irql; 00054 00055 // 00056 // Make sure that the device and its driver are really there and they are 00057 // going to stay there. The object itself cannot go away just yet because 00058 // the object management system has performed a reference which bumps the 00059 // count of the number of reasons why the object must stick around. 00060 // However, the driver could be attempting to unload itself, so perform 00061 // this check. If the driver is being unloaded, then set the final status 00062 // of the operation to "No such device" and return with a NULL file object 00063 // pointer. 00064 // 00065 // Note that it is possible to "open" an exclusive device more than once 00066 // provided that the caller is performing a relative open. This feature 00067 // is how users "allocate" a device, and then use it to perform operations. 00068 // 00069 00070 ExAcquireFastLock( &IopDatabaseLock, &irql ); 00071 00072 if (parseDeviceObject->DeviceObjectExtension->ExtensionFlags & 00073 (DOE_UNLOAD_PENDING | DOE_DELETE_PENDING | DOE_REMOVE_PENDING | DOE_REMOVE_PROCESSED | DOE_START_PENDING) || 00074 parseDeviceObject->Flags & DO_DEVICE_INITIALIZING) { 00075 00076 status = STATUS_NO_SUCH_DEVICE; 00077 00078 } else if (parseDeviceObject->Flags & DO_EXCLUSIVE && 00079 parseDeviceObject->ReferenceCount != 0 && 00080 op->RelatedFileObject == NULL && 00081 !(op->Options & IO_ATTACH_DEVICE)) { 00082 00083 status = STATUS_ACCESS_DENIED; 00084 00085 } else { 00086 00087 parseDeviceObject->ReferenceCount++; 00088 status = STATUS_SUCCESS; 00089 00090 } 00091 00092 ExReleaseFastLock( &IopDatabaseLock, irql ); 00093 00094 return status; 00095 }

PVPB IopCheckVpbMounted IN POPEN_PACKET  op,
IN PDEVICE_OBJECT  parseDeviceObject,
IN OUT PUNICODE_STRING  RemainingName,
OUT PNTSTATUS  status
 

Definition at line 98 of file parse.c.

References FALSE, _VPB::Flags, IopDecrementDeviceObjectRef(), IopMountVolume(), IopVpbSpinLock, NT_SUCCESS, NULL, _VPB::ReferenceCount, TRUE, VPB_LOCKED, and VPB_MOUNTED.

Referenced by IopParseDevice().

00104 { 00105 PVPB vpb; 00106 KIRQL irql; 00107 BOOLEAN alertable; 00108 00109 // 00110 // Loop here until the VPB_MOUNTED test can be passed while holding the 00111 // VPB spinlock. After the mount succeeds, it is still necessary to acquire 00112 // the spinlock to check that the VPB (which may be different from the one 00113 // before the mount) is still mounted. If it is, then its reference count 00114 // is incremented before releasing the spinlock. 00115 // 00116 00117 ExAcquireFastLock( &IopVpbSpinLock, &irql ); 00118 00119 alertable = (op->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) ? TRUE : FALSE; 00120 while (!(parseDeviceObject->Vpb->Flags & VPB_MOUNTED)) { 00121 00122 ExReleaseFastLock( &IopVpbSpinLock, irql ); 00123 00124 // 00125 // Try to mount the volume, allowing only RAW to perform the mount if 00126 // this is a DASD open. 00127 // 00128 00129 *status = IopMountVolume( parseDeviceObject, 00130 (BOOLEAN) (!RemainingName->Length && !op->RelatedFileObject), 00131 FALSE, 00132 alertable ); 00133 // 00134 // If the mount operation was unsuccessful, adjust the reference 00135 // count for the device and return now. 00136 // 00137 00138 if (!NT_SUCCESS( *status ) || *status == STATUS_USER_APC || *status == STATUS_ALERTED) { 00139 00140 IopDecrementDeviceObjectRef( parseDeviceObject, FALSE ); 00141 00142 if (!NT_SUCCESS( *status )) { 00143 return NULL; 00144 } else { 00145 *status = STATUS_WRONG_VOLUME; 00146 return NULL; 00147 } 00148 } 00149 00150 ExAcquireFastLock( &IopVpbSpinLock, &irql ); 00151 } 00152 00153 // 00154 // Synchronize here with the file system to make sure that volumes do not 00155 // go away while en route to the FS. 00156 // 00157 00158 vpb = parseDeviceObject->Vpb; 00159 00160 // 00161 // Check here that the VPB is not locked. 00162 // 00163 00164 if (vpb->Flags & VPB_LOCKED) { 00165 00166 *status = STATUS_ACCESS_DENIED; 00167 vpb = NULL; 00168 00169 } else { 00170 00171 vpb->ReferenceCount += 1; 00172 } 00173 00174 ExReleaseFastLock( &IopVpbSpinLock, irql ); 00175 00176 return vpb; 00177 }

VOID IopDereferenceVpbAndFree IN PVPB  Vpb  ) 
 

Definition at line 180 of file parse.c.

References ExFreePool(), IopVpbSpinLock, NULL, and VPB_PERSISTENT.

Referenced by IopParseDevice().

00183 { 00184 KIRQL irql; 00185 PVPB vpb = (PVPB) NULL; 00186 00187 ExAcquireFastLock( &IopVpbSpinLock, &irql ); 00188 Vpb->ReferenceCount--; 00189 if ((Vpb->ReferenceCount == 0) && 00190 (Vpb->RealDevice->Vpb != Vpb) && 00191 !(Vpb->Flags & VPB_PERSISTENT)) { 00192 vpb = Vpb; 00193 } 00194 ExReleaseFastLock( &IopVpbSpinLock, irql ); 00195 if (vpb) { 00196 ExFreePool( vpb ); 00197 } 00198 }

NTSTATUS IopParseDevice IN PVOID  ParseObject,
IN PVOID  ObjectType,
IN PACCESS_STATE  AccessState,
IN KPROCESSOR_MODE  AccessMode,
IN ULONG  Attributes,
IN OUT PUNICODE_STRING  CompleteName,
IN OUT PUNICODE_STRING  RemainingName,
IN OUT PVOID Context  OPTIONAL,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos  OPTIONAL,
OUT PVOID *  Object
 

Definition at line 202 of file parse.c.

References _IO_SECURITY_CONTEXT::AccessState, _OPEN_PACKET::AllocationSize, APC_LEVEL, ASSERT, _IRP::AssociatedIrp, _DEVICE_OBJECT::AttachedDevice, _OPEN_PACKET::BasicInformation, _OBJECT_HEADER::Body, _IRP::Cancel, _IRP::CancelRoutine, _DEVICE_OBJECT::Characteristics, _IO_STACK_LOCATION::Control, COPY_ATTRIBUTES, _OPEN_PACKET::CreateFileType, CreateFileTypeNamedPipe, CreateFileTypeNone, _OPEN_PACKET::CreateOptions, _IRP::CurrentLocation, _OPEN_PACKET::DeleteOnly, _IO_SECURITY_CONTEXT::DesiredAccess, _IO_STACK_LOCATION::DeviceObject, _VPB::DeviceObject, _FILE_OBJECT::DeviceObject, _DEVICE_OBJECT::DeviceType, _OPEN_PACKET::Disposition, _DEVICE_OBJECT::DriverObject, _OPEN_PACKET::EaBuffer, _OPEN_PACKET::EaLength, _FILE_OBJECT::Event, ExAcquireResourceShared, ExAllocatePool, ExAllocatePoolWithTag, EXCEPTION_EXECUTE_HANDLER, Executive, ExFreePool(), ExInterlockedAddUlong(), ExReleaseResource, _OPEN_PACKET::ExtraCreateParameters, FALSE, _DRIVER_OBJECT::FastIoDispatch, _FAST_IO_DISPATCH::FastIoQueryBasicInfo, _FAST_IO_DISPATCH::FastIoQueryNetworkOpenInfo, _FAST_IO_DISPATCH::FastIoQueryOpen, FILE_OBJECT, _OPEN_PACKET::FileAttributes, _FILE_OBJECT::FileName, _OPEN_PACKET::FileObject, _IO_STACK_LOCATION::FileObject, _OPEN_PACKET::FinalStatus, _IO_STACK_LOCATION::Flags, _IRP::Flags, _FILE_OBJECT::Flags, FO_ALERTABLE_IO, FO_DIRECT_DEVICE_OPEN, FO_FILE_OPEN_CANCELLED, FO_NO_INTERMEDIATE_BUFFERING, FO_OPENED_CASE_SENSITIVE, FO_RANDOM_ACCESS, FO_SEQUENTIAL_ONLY, FO_SYNCHRONOUS_IO, FO_VOLUME_OPEN, FO_WRITE_THROUGH, _OPEN_PACKET::FullAttributes, _IO_SECURITY_CONTEXT::FullCreateOptions, _OBJECT_TYPE_INITIALIZER::GenericMapping, _KEVENT::Header, _OPEN_PACKET::Information, IO_FORCE_ACCESS_CHECK, IO_MAX_REMOUNT_REPARSE_ATTEMPTS, IO_REMOUNT, IO_REPARSE, IO_TYPE_FILE, IO_TYPE_OPEN_PACKET, IoCallDriver, IoFileObjectType, IoFreeIrp(), IoGetAttachedDevice(), IoGetNextIrpStackLocation, IoGetRelatedDeviceObject(), IopAllocateIrp, IopCheckBackupRestorePrivilege(), IopCheckDeviceAndDriver(), IopCheckVpbMounted(), IopDecrementDeviceObjectRef(), IopDeleteFile(), IopDequeueThreadIrp, IopDereferenceVpbAndFree(), IopDoNameTransmogrify(), IopQueueThreadIrp, IopSecurityResource, IopVpbSpinLock, IoQueryFileInformation(), IoSetNextIrpStackLocation, _IRP::IoStatus, IRP_BUFFERED_IO, IRP_CREATE_OPERATION, IRP_DEALLOCATE_BUFFER, IRP_DEFER_IO_COMPLETION, IRP_MJ_CREATE, IRP_MJ_CREATE_MAILSLOT, IRP_MJ_CREATE_NAMED_PIPE, IRP_SYNCHRONOUS_API, KeEnterCriticalRegion, KeInitializeEvent, KeLeaveCriticalRegion, KeLowerIrql(), KeRaiseIrql(), KernelMode, KeWaitForSingleObject(), KPROCESSOR_MODE, L, _OPEN_PACKET::LocalFileObject, _IO_STACK_LOCATION::MajorFunction, _IRP::MdlAddress, _OPEN_PACKET::NetworkInformation, NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, ObCreateObject(), ObDereferenceObject, _DUMMY_FILE_OBJECT::ObjectHeader, ObReferenceObject, OPEN_PACKET_PATTERN, _OPEN_PACKET::Options, _IRP::Overlay, _OPEN_PACKET::Override, PAGED_CODE, PagedPool, _IO_STACK_LOCATION::Parameters, _OPEN_PACKET::ParseCheck, PDRIVER_CANCEL, _IRP::PendingReturned, PKNORMAL_ROUTINE, _OBJECT_HEADER::PointerCount, PsGetCurrentThread, _OPEN_PACKET::QueryOnly, _VPB::ReferenceCount, _FILE_OBJECT::RelatedFileObject, _OPEN_PACKET::RelatedFileObject, _IRP::RequestorMode, RoundNameSize, RtlCopyUnicodeString(), RtlMapGenericMask(), SE_BACKUP_PRIVILEGES_CHECKED, SeAccessCheck(), SeAppendPrivileges(), _DEVICE_OBJECT::SecurityDescriptor, SecurityQos, _IO_SECURITY_CONTEXT::SecurityQos, SeFastTraverseCheck(), SeFreePrivileges(), SeLockSubjectContext(), SeOpenObjectAuditAlarm(), SeSetAccessStateGenericMapping(), SeTraverseAuditAlarm(), SeUnlockSubjectContext(), _OPEN_PACKET::ShareAccess, _DISPATCHER_HEADER::SignalState, _FILE_OBJECT::Size, _OPEN_PACKET::Size, _FAST_IO_DISPATCH::SizeOfFastIoDispatch, SL_CASE_SENSITIVE, _IRP::StackCount, _DEVICE_OBJECT::StackSize, _IRP::Tail, TOKEN_HAS_TRAVERSE_PRIVILEGE, TOKEN_IS_RESTRICTED, TRUE, _FILE_OBJECT::Type, _OBJECT_HEADER::Type, _OPEN_PACKET::Type, _OBJECT_TYPE::TypeInfo, _IRP::UserEvent, _IRP::UserIosb, UserMode, VOID(), and _FILE_OBJECT::Vpb.

Referenced by IopCreateObjectTypes(), and IopParseFile().

00217 : 00218 00219 This routine interfaces to the NT Object Manager. It is invoked when 00220 the object system is given the name of an entity to create or open and the 00221 name translates to a device object. This routine is specified as the parse 00222 routine for all device objects. 00223 00224 In the normal case of an NtCreateFile, the user specifies either the name 00225 of a device or of a file. In the former situation, this routine is invoked 00226 with a pointer to the device and a null ("") string. For this case, the 00227 routine simply allocates an IRP, fills it in, and passes it to the driver 00228 for the device. The driver will then perform whatever rudimentary functions 00229 are necessary and will return a status code indicating whether an error was 00230 incurred. This status code is remembered in the Open Packet (OP). 00231 00232 In the latter situation, the name string to be opened/created is non-null. 00233 That is, it contains the remainder of the pathname to the file that is to 00234 be opened or created. For this case, the routine allocates an IRP, fills 00235 it in, and passes it to the driver for the device. The driver may then 00236 need to take further action or it may complete the request immediately. If 00237 it needs to perform some work asynchronously, then it can queue the request 00238 and return a status of STATUS_PENDING. This allows this routine and its 00239 caller to return to the user so that he can continue. Otherwise, the open/ 00240 create is basically finished. 00241 00242 If the driver supports symbolic links, then it is also possible for the 00243 driver to return a new name. This name will be returned to the Object 00244 Manager as a new name to look up. The parsing will then begin again from 00245 the start. 00246 00247 It is also the responsibility of this routine to create a file object for 00248 the file, if the name specifies a file. The file object's address is 00249 returned to the NtCreateFile service through the OP. 00250 00251 Arguments: 00252 00253 ParseObject - Pointer to the device object the name translated into. 00254 00255 ObjectType - Type of the object being opened. 00256 00257 AccessState - Running security access state information for operation. 00258 00259 AccessMode - Access mode of the original caller. 00260 00261 Attributes - Attributes to be applied to the object. 00262 00263 CompleteName - Complete name of the object. 00264 00265 RemainingName - Remaining name of the object. 00266 00267 Context - Pointer to an Open Packet (OP) from NtCreateFile service. 00268 00269 SecurityQos - Optional security quality of service indicator. 00270 00271 Object - The address of a variable to receive the created file object, if 00272 any. 00273 00274 Return Value: 00275 00276 The function return value is one of the following: 00277 00278 a) Success - This indicates that the function succeeded and the object 00279 parameter contains the address of the created file object. 00280 00281 b) Error - This indicates that the file was not found or created and 00282 no file object was created. 00283 00284 c) Reparse - This indicates that the remaining name string has been 00285 replaced by a new name that is to be parsed. 00286 00287 --*/ 00288 00289 { 00290 00291 #define COPY_ATTRIBUTES( n, b, s ) { \ 00292 (n)->CreationTime.QuadPart = (b)->CreationTime.QuadPart; \ 00293 (n)->LastAccessTime.QuadPart = (b)->LastAccessTime.QuadPart; \ 00294 (n)->LastWriteTime.QuadPart = (b)->LastWriteTime.QuadPart; \ 00295 (n)->ChangeTime.QuadPart = (b)->ChangeTime.QuadPart; \ 00296 (n)->AllocationSize.QuadPart = (s)->AllocationSize.QuadPart; \ 00297 (n)->EndOfFile.QuadPart = (s)->EndOfFile.QuadPart; \ 00298 (n)->FileAttributes = (b)->FileAttributes; } 00299 00300 PIRP irp; 00301 PIO_STACK_LOCATION irpSp; 00302 POPEN_PACKET op; 00303 PFILE_OBJECT fileObject; 00304 NTSTATUS status; 00305 IO_STATUS_BLOCK ioStatus; 00306 IO_SECURITY_CONTEXT securityContext; 00307 PDEVICE_OBJECT deviceObject; 00308 PDEVICE_OBJECT parseDeviceObject; 00309 BOOLEAN directDeviceOpen; 00310 PVPB vpb; 00311 ACCESS_MASK desiredAccess; 00312 PDUMMY_FILE_OBJECT localFileObject; 00313 BOOLEAN realFileObjectRequired; 00314 KPROCESSOR_MODE modeForPrivilegeCheck; 00315 ULONG retryCount = 0; 00316 BOOLEAN relativeVolumeOpen = FALSE; // True if opening a filesystem volume 00317 00318 PAGED_CODE(); 00319 00320 reparse_loop: 00321 00322 // 00323 // Assume failure by setting the returned object pointer to NULL. 00324 // 00325 00326 *Object = (PVOID) NULL; 00327 00328 // 00329 // Get the address of the Open Packet (OP). 00330 // 00331 00332 op = Context; 00333 00334 // 00335 // Ensure that this routine is actually being invoked because someone is 00336 // attempting to open a device or a file through NtCreateFile. This code 00337 // must be invoked from there (as opposed to some other random object 00338 // create or open routine). 00339 // 00340 00341 if (op == NULL || 00342 op->Type != IO_TYPE_OPEN_PACKET || 00343 op->Size != sizeof( OPEN_PACKET )) { 00344 00345 return STATUS_OBJECT_TYPE_MISMATCH; 00346 } 00347 00348 // 00349 // Obtain a pointer to the parse object as a device object, which is the 00350 // actual type of the object anyway. 00351 // 00352 00353 parseDeviceObject = (PDEVICE_OBJECT) ParseObject; 00354 00355 // 00356 // If this is a relative open, then get the device on which the file 00357 // is really being opened from the related file object and use that for 00358 // the remainder of this function and for all operations performed on 00359 // the file object that is about to be created. 00360 // 00361 00362 if (op->RelatedFileObject) { 00363 parseDeviceObject = op->RelatedFileObject->DeviceObject; 00364 } 00365 00366 // 00367 // Make sure that the device and its driver are really there and they are 00368 // going to stay there. The object itself cannot go away just yet because 00369 // the object management system has performed a reference which bumps the 00370 // count of the number of reasons why the object must stick around. 00371 // However, the driver could be attempting to unload itself, so perform 00372 // this check. If the driver is being unloaded, then set the final status 00373 // of the operation to "No such device" and return with a NULL file object 00374 // pointer. 00375 // 00376 // Note that it is possible to "open" an exclusive device more than once 00377 // provided that the caller is performing a relative open. This feature 00378 // is how users "allocate" a device, and then use it to perform operations. 00379 // 00380 00381 status = IopCheckDeviceAndDriver( op, parseDeviceObject ); 00382 00383 if (!NT_SUCCESS(status)) { 00384 return op->FinalStatus = status; 00385 } 00386 00387 // 00388 // Since ObOpenObjectByName is called without being passed 00389 // any object type information, we need to map the generic 00390 // bits in the DesiredAccess mask here. We also need to save 00391 // the object's generic mapping in the access state structure 00392 // here, because this is the earliest opportunity we have 00393 // to do so. 00394 // 00395 00396 RtlMapGenericMask( &AccessState->RemainingDesiredAccess, 00397 &IoFileObjectType->TypeInfo.GenericMapping ); 00398 00399 RtlMapGenericMask( &AccessState->OriginalDesiredAccess, 00400 &IoFileObjectType->TypeInfo.GenericMapping ); 00401 00402 SeSetAccessStateGenericMapping( AccessState, &IoFileObjectType->TypeInfo.GenericMapping ); 00403 00404 desiredAccess = AccessState->RemainingDesiredAccess; 00405 00406 // 00407 // Compute the previous mode to be passed in to the privilege check 00408 // 00409 00410 if (AccessMode != KernelMode || op->Options & IO_FORCE_ACCESS_CHECK) { 00411 modeForPrivilegeCheck = UserMode; 00412 } else { 00413 modeForPrivilegeCheck = KernelMode; 00414 } 00415 00416 IopCheckBackupRestorePrivilege( AccessState, 00417 &op->CreateOptions, 00418 modeForPrivilegeCheck, 00419 op->Disposition 00420 ); 00421 00422 // 00423 // If this is not the first time through here for this object, and the 00424 // object itself is being opened, then the desired access must also 00425 // include the previously granted access from the last pass. Likewise, 00426 // if the privileges have been checked already, then this is another 00427 // pass through for a file, so add in the previously granted access. 00428 // 00429 00430 if ((op->Override && !RemainingName->Length) || 00431 AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED) { 00432 desiredAccess |= AccessState->PreviouslyGrantedAccess; 00433 } 00434 00435 // 00436 // If its a filesystem volume open and we are doing a relative open to it 00437 // then do the access check. Note that relative opens can be nested and we propagate 00438 // the fact that the relative open is for a volume using the FO_VOLUME_OPEN flag. 00439 // 00440 00441 if (op->RelatedFileObject) { 00442 if ((op->RelatedFileObject->Flags & FO_VOLUME_OPEN) && RemainingName->Length == 0) { 00443 relativeVolumeOpen = TRUE; 00444 } 00445 } 00446 00447 // 00448 // Now determine what type of security check should be made. This is 00449 // based on whether the remaining name string is null. If it is null, 00450 // then the device itself is being opened, so a full security check is 00451 // performed. Otherwise, only a check to ensure that the caller can 00452 // traverse the device object is made. Note that these checks are only 00453 // made if the caller's mode is user, or if access checking is being 00454 // forced. Note also that if an access check was already made on the 00455 // device itself, and this code is being executed again because of a 00456 // reparse, then the access check need not be made the second time 00457 // around. 00458 // 00459 00460 00461 if ((AccessMode != KernelMode || op->Options & IO_FORCE_ACCESS_CHECK) && 00462 (!op->RelatedFileObject || relativeVolumeOpen) && 00463 !op->Override) { 00464 00465 BOOLEAN subjectContextLocked = FALSE; 00466 BOOLEAN accessGranted; 00467 ACCESS_MASK grantedAccess; 00468 00469 // 00470 // The caller's mode is either user or access checking is being 00471 // forced. Perform the appropriate access check on the device 00472 // object. 00473 // 00474 00475 if (!RemainingName->Length) { 00476 00477 UNICODE_STRING nameString; 00478 PPRIVILEGE_SET privileges = NULL; 00479 00480 // 00481 // The device itself is being opened. Make a full security check 00482 // to ensure that the caller has the appropriate access. 00483 // 00484 00485 KeEnterCriticalRegion( ); 00486 ExAcquireResourceShared( &IopSecurityResource, TRUE ); 00487 00488 SeLockSubjectContext( &AccessState->SubjectSecurityContext ); 00489 subjectContextLocked = TRUE; 00490 00491 accessGranted = SeAccessCheck( parseDeviceObject->SecurityDescriptor, 00492 &AccessState->SubjectSecurityContext, 00493 subjectContextLocked, 00494 desiredAccess, 00495 0, 00496 &privileges, 00497 &IoFileObjectType->TypeInfo.GenericMapping, 00498 UserMode, 00499 &grantedAccess, 00500 &status ); 00501 00502 if (privileges) { 00503 (VOID) SeAppendPrivileges( AccessState, 00504 privileges ); 00505 SeFreePrivileges( privileges ); 00506 } 00507 00508 if (accessGranted) { 00509 AccessState->PreviouslyGrantedAccess |= grantedAccess; 00510 AccessState->RemainingDesiredAccess &= ~( grantedAccess | MAXIMUM_ALLOWED ); 00511 op->Override = TRUE; 00512 } 00513 00514 nameString.Length = 8; 00515 nameString.MaximumLength = 8; 00516 nameString.Buffer = L"File"; 00517 00518 SeOpenObjectAuditAlarm( &nameString, 00519 parseDeviceObject, 00520 CompleteName, 00521 parseDeviceObject->SecurityDescriptor, 00522 AccessState, 00523 FALSE, 00524 accessGranted, 00525 UserMode, 00526 &AccessState->GenerateOnClose ); 00527 00528 ExReleaseResource( &IopSecurityResource ); 00529 KeLeaveCriticalRegion(); 00530 00531 } else { 00532 00533 // 00534 // The device is not being opened, rather, a file on the device 00535 // is being opened or created. Therefore, only perform a check 00536 // here for traverse access to the device. 00537 // 00538 00539 // 00540 // First determine if we have to perform traverse checking at all. 00541 // Traverse checking only needs to be done if the device being 00542 // traversed is a disk, or if the caller does not already have 00543 // traverse checking privilege. Note that the former case is so 00544 // that an administrator can turn off access to the "system 00545 // partition", or someone would be able to install a trojan horse 00546 // into the system by simply replacing one of the files there with 00547 // something of their own. 00548 // 00549 00550 if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) || 00551 parseDeviceObject->DeviceType == FILE_DEVICE_DISK || 00552 parseDeviceObject->DeviceType == FILE_DEVICE_CD_ROM ) { 00553 00554 KeEnterCriticalRegion( ); 00555 ExAcquireResourceShared( &IopSecurityResource, TRUE ); 00556 00557 // 00558 // If the token is restricted we need to do the full 00559 // access check. 00560 // 00561 00562 if ((AccessState->Flags & TOKEN_IS_RESTRICTED) == 0) { 00563 accessGranted = SeFastTraverseCheck( parseDeviceObject->SecurityDescriptor, 00564 FILE_TRAVERSE, 00565 UserMode ); 00566 } else { 00567 accessGranted = FALSE; 00568 } 00569 00570 if (!accessGranted) { 00571 00572 PPRIVILEGE_SET privileges = NULL; 00573 00574 // 00575 // The caller was not granted traverse access through the 00576 // normal fast path lookup. Perform a full-blown access 00577 // check to determine whether some other ACE allows traverse 00578 // access. 00579 // 00580 00581 SeLockSubjectContext( &AccessState->SubjectSecurityContext ); 00582 00583 subjectContextLocked = TRUE; 00584 00585 accessGranted = SeAccessCheck( parseDeviceObject->SecurityDescriptor, 00586 &AccessState->SubjectSecurityContext, 00587 subjectContextLocked, 00588 FILE_TRAVERSE, 00589 0, 00590 &privileges, 00591 &IoFileObjectType->TypeInfo.GenericMapping, 00592 UserMode, 00593 &grantedAccess, 00594 &status ); 00595 00596 if (privileges) { 00597 00598 (VOID) SeAppendPrivileges( AccessState, 00599 privileges ); 00600 SeFreePrivileges( privileges ); 00601 } 00602 00603 } 00604 00605 // 00606 // Perform the traverse audit alarm if necessary. 00607 // 00608 00609 SeTraverseAuditAlarm( &AccessState->OperationID, 00610 parseDeviceObject, 00611 parseDeviceObject->SecurityDescriptor, 00612 &AccessState->SubjectSecurityContext, 00613 subjectContextLocked, 00614 FILE_TRAVERSE, 00615 (PPRIVILEGE_SET) NULL, 00616 accessGranted, 00617 UserMode ); 00618 ExReleaseResource( &IopSecurityResource ); 00619 KeLeaveCriticalRegion(); 00620 00621 } else { 00622 00623 accessGranted = TRUE; 00624 } 00625 } 00626 00627 // 00628 // Unlock the subject's security context so that it can be changed, 00629 // if it was locked. 00630 // 00631 00632 if (subjectContextLocked) { 00633 SeUnlockSubjectContext( &AccessState->SubjectSecurityContext ); 00634 } 00635 00636 // 00637 // Finally, determine whether or not access was granted to the device. 00638 // If not, clean everything up and get out now without even invoking 00639 // the device driver. 00640 // 00641 00642 if (!accessGranted) { 00643 00644 IopDecrementDeviceObjectRef( parseDeviceObject, FALSE ); 00645 return STATUS_ACCESS_DENIED; 00646 } 00647 00648 } 00649 00650 realFileObjectRequired = !(op->QueryOnly || op->DeleteOnly); 00651 00652 if (RemainingName->Length == 0 && 00653 op->RelatedFileObject == NULL && 00654 ((desiredAccess & ~(SYNCHRONIZE | 00655 FILE_READ_ATTRIBUTES | 00656 READ_CONTROL | 00657 ACCESS_SYSTEM_SECURITY | 00658 WRITE_OWNER | 00659 WRITE_DAC)) == 0) && 00660 realFileObjectRequired) { 00661 00662 // 00663 // If the name of the object being opened is just the name of the 00664 // device itself, and there is no related file object, and the caller 00665 // is opening the device for only read attributes access, then this 00666 // device will not be mounted. This allows applications to obtain 00667 // attributes about the device without actually mounting it. 00668 // 00669 // Note that if this *is* a direct device open, then the normal path 00670 // through the I/O system and drivers may never be used, even if 00671 // the device appears to be mounted. This is because the user may 00672 // remove the media from the drive (even though it is mounted), and 00673 // now attempting to determine what type of drive it is will still 00674 // fail, this time very hard, because a whole mount process is now 00675 // required, thus defeating this feature. 00676 // 00677 00678 directDeviceOpen = TRUE; 00679 00680 } else { 00681 00682 // 00683 // Otherwise, this is a normal open of a file, directory, device, or 00684 // volume. 00685 // 00686 00687 directDeviceOpen = FALSE; 00688 } 00689 00690 // 00691 // There are now five different cases. These are as follows: 00692 // 00693 // 1) This is a relative open, in which case we want to send the 00694 // request to then same device that opened the relative file object. 00695 // 00696 // 2) The VPB pointer in the device object is NULL. This means that 00697 // this device does not support a file system. This includes 00698 // devices such as terminals, etc. 00699 // 00700 // 3) The VPB pointer in the device object is not NULL and: 00701 // 00702 // a) The VPB is "blank". That is, the VPB has never been filled 00703 // in, which means that the device has never been mounted. 00704 // 00705 // b) The VPB is non-blank, but the verify flag on the device is 00706 // set, indicating that the door to the drive may have been 00707 // opened and the media may therefore have been changed. 00708 // 00709 // c) The VPB is non-blank and the verify flag is not set. 00710 // 00711 // Both of the latter are not explicitly checked for, as #c is 00712 // the normal case, and #b is the responsibility of the file 00713 // system to check. 00714 // 00715 00716 // 00717 // If this is a file system that supports volumes, vpbRefCount will 00718 // be filled in to point to the reference count in the Vpb. Error 00719 // exits paths later on key off this value to see if they should 00720 // decrement the ref count. Note that a direct device open does not 00721 // make it to the file system, so no increment is needed, and no 00722 // decrement will be performed in objsup.c IopDeleteFile(). 00723 // 00724 00725 vpb = NULL; 00726 00727 // 00728 // If the related open was a direct device open then we should go through the full mount 00729 // path for this open as this may not be a direct device open. 00730 // 00731 if (op->RelatedFileObject && (!(op->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN))) { 00732 00733 deviceObject = (PDEVICE_OBJECT)ParseObject; 00734 00735 if (op->RelatedFileObject->Vpb) { 00736 00737 vpb = op->RelatedFileObject->Vpb; 00738 00739 // 00740 // Synchronize here with the file system to make sure that 00741 // volumes don't go away while en route to the FS. 00742 // 00743 00744 ExInterlockedAddUlong( &vpb->ReferenceCount, 1, &IopVpbSpinLock ); 00745 } 00746 00747 } else { 00748 00749 deviceObject = parseDeviceObject; 00750 00751 if (parseDeviceObject->Vpb && !directDeviceOpen) { 00752 vpb = IopCheckVpbMounted( op, 00753 parseDeviceObject, 00754 RemainingName, 00755 &status ); 00756 if ( !vpb ) { 00757 return status; 00758 } 00759 00760 // 00761 // Set the address of the device object associated with the VPB. 00762 // 00763 00764 deviceObject = vpb->DeviceObject; 00765 } 00766 00767 // 00768 // Walk the attached device list. 00769 // 00770 00771 if (deviceObject->AttachedDevice) { 00772 deviceObject = IoGetAttachedDevice( deviceObject ); 00773 } 00774 } 00775 00776 // 00777 // If the driver says that the IO manager should do the access checks, lets do it here. 00778 // We do the check against the parse device object as that device object has a name 00779 // and we can set an ACL against it. 00780 // We only worry about related opens of devices as the other case is taken care of in the 00781 // filesystem. 00782 // 00783 if ((deviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) && 00784 (op->RelatedFileObject || RemainingName->Length) && (!relativeVolumeOpen)) { 00785 00786 BOOLEAN subjectContextLocked = FALSE; 00787 BOOLEAN accessGranted; 00788 ACCESS_MASK grantedAccess; 00789 UNICODE_STRING nameString; 00790 PPRIVILEGE_SET privileges = NULL; 00791 00792 // 00793 // If the device wants to ensure secure opens then lets check the two 00794 // cases which were skipped earlier. These cases are if its a relative 00795 // open or if there are trailing names. 00796 // 00797 00798 KeEnterCriticalRegion( ); 00799 ExAcquireResourceShared( &IopSecurityResource, TRUE ); 00800 00801 SeLockSubjectContext( &AccessState->SubjectSecurityContext ); 00802 subjectContextLocked = TRUE; 00803 00804 accessGranted = SeAccessCheck( parseDeviceObject->SecurityDescriptor, 00805 &AccessState->SubjectSecurityContext, 00806 subjectContextLocked, 00807 desiredAccess, 00808 0, 00809 &privileges, 00810 &IoFileObjectType->TypeInfo.GenericMapping, 00811 UserMode, 00812 &grantedAccess, 00813 &status ); 00814 00815 if (privileges) { 00816 (VOID) SeAppendPrivileges( AccessState, 00817 privileges ); 00818 SeFreePrivileges( privileges ); 00819 } 00820 00821 if (accessGranted) { 00822 AccessState->PreviouslyGrantedAccess |= grantedAccess; 00823 AccessState->RemainingDesiredAccess &= ~( grantedAccess | MAXIMUM_ALLOWED ); 00824 } 00825 00826 nameString.Length = 8; 00827 nameString.MaximumLength = 8; 00828 nameString.Buffer = L"File"; 00829 00830 SeOpenObjectAuditAlarm( &nameString, 00831 deviceObject, 00832 CompleteName, 00833 parseDeviceObject->SecurityDescriptor, 00834 AccessState, 00835 FALSE, 00836 accessGranted, 00837 UserMode, 00838 &AccessState->GenerateOnClose ); 00839 00840 SeUnlockSubjectContext( &AccessState->SubjectSecurityContext ); 00841 ExReleaseResource( &IopSecurityResource ); 00842 KeLeaveCriticalRegion(); 00843 00844 if (!accessGranted) { 00845 IopDecrementDeviceObjectRef( parseDeviceObject, FALSE ); 00846 00847 if (vpb) { 00848 IopDereferenceVpbAndFree(vpb); 00849 } 00850 return STATUS_ACCESS_DENIED; 00851 } 00852 } 00853 00854 // 00855 // Allocate and fill in the I/O Request Packet (IRP) to use in interfacing 00856 // to the driver. The allocation is done using an exception handler in 00857 // case the caller does not have enough quota to allocate the packet. 00858 // 00859 00860 irp = IopAllocateIrp( deviceObject->StackSize, TRUE ); 00861 if (!irp) { 00862 00863 // 00864 // An IRP could not be allocated. Cleanup and return an appropriate 00865 // error status code. 00866 // 00867 00868 IopDecrementDeviceObjectRef( parseDeviceObject, FALSE ); 00869 00870 if (vpb) { 00871 IopDereferenceVpbAndFree(vpb); 00872 } 00873 return STATUS_INSUFFICIENT_RESOURCES; 00874 } 00875 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 00876 irp->RequestorMode = AccessMode; 00877 irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION; 00878 00879 securityContext.SecurityQos = SecurityQos; 00880 securityContext.AccessState = AccessState; 00881 securityContext.DesiredAccess = desiredAccess; 00882 securityContext.FullCreateOptions = op->CreateOptions; 00883 00884 // 00885 // Get a pointer to the stack location for the first driver. This is where 00886 // the original function codes and parameters are passed. 00887 // 00888 00889 irpSp = IoGetNextIrpStackLocation( irp ); 00890 irpSp->Control = 0; 00891 00892 if (op->CreateFileType == CreateFileTypeNone) { 00893 00894 // 00895 // This is a normal file open or create function. 00896 // 00897 00898 irpSp->MajorFunction = IRP_MJ_CREATE; 00899 irpSp->Parameters.Create.EaLength = op->EaLength; 00900 irpSp->Flags = (UCHAR) op->Options; 00901 if (!(Attributes & OBJ_CASE_INSENSITIVE)) { 00902 irpSp->Flags |= SL_CASE_SENSITIVE; 00903 } 00904 00905 } else if (op->CreateFileType == CreateFileTypeNamedPipe) { 00906 00907 // 00908 // A named pipe is being created. 00909 // 00910 00911 irpSp->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE; 00912 irpSp->Parameters.CreatePipe.Parameters = op->ExtraCreateParameters; 00913 00914 } else { 00915 00916 // 00917 // A mailslot is being created. 00918 // 00919 00920 irpSp->MajorFunction = IRP_MJ_CREATE_MAILSLOT; 00921 irpSp->Parameters.CreateMailslot.Parameters = op->ExtraCreateParameters; 00922 } 00923 00924 // 00925 // Also fill in the NtCreateFile service's caller's parameters. 00926 // 00927 00928 irp->Overlay.AllocationSize = op->AllocationSize; 00929 irp->AssociatedIrp.SystemBuffer = op->EaBuffer; 00930 irpSp->Parameters.Create.Options = (op->Disposition << 24) | (op->CreateOptions & 0x00ffffff); 00931 irpSp->Parameters.Create.FileAttributes = op->FileAttributes; 00932 irpSp->Parameters.Create.ShareAccess = op->ShareAccess; 00933 irpSp->Parameters.Create.SecurityContext = &securityContext; 00934 00935 // 00936 // Fill in local parameters so this routine can determine when the I/O is 00937 // finished, and the normal I/O completion code will not get any errors. 00938 // 00939 00940 irp->UserIosb = &ioStatus; 00941 irp->MdlAddress = (PMDL) NULL; 00942 irp->PendingReturned = FALSE; 00943 irp->Cancel = FALSE; 00944 irp->UserEvent = (PKEVENT) NULL; 00945 irp->CancelRoutine = (PDRIVER_CANCEL) NULL; 00946 irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL; 00947 00948 // 00949 // Allocate and initialize the file object that will be used in dealing 00950 // with the device for the remainder of this session with the user. How 00951 // the file object is allocated is based on whether or not a real file 00952 // object is actually required. It is not required for the query and 00953 // delete only operations. 00954 // 00955 00956 if (realFileObjectRequired) { 00957 00958 OBJECT_ATTRIBUTES objectAttributes; 00959 00960 // 00961 // A real, full-blown file object is actually required. 00962 // 00963 00964 InitializeObjectAttributes( &objectAttributes, 00965 (PUNICODE_STRING) NULL, 00966 Attributes, 00967 (HANDLE) NULL, 00968 (PSECURITY_DESCRIPTOR) NULL 00969 ); 00970 00971 status = ObCreateObject( KernelMode, 00972 IoFileObjectType, 00973 &objectAttributes, 00974 AccessMode, 00975 (PVOID) NULL, 00976 (ULONG) sizeof( FILE_OBJECT ), 00977 0, 00978 0, 00979 (PVOID *) &fileObject ); 00980 00981 if (!NT_SUCCESS( status )) { 00982 IoFreeIrp( irp ); 00983 00984 IopDecrementDeviceObjectRef( parseDeviceObject, FALSE ); 00985 00986 if (vpb) { 00987 IopDereferenceVpbAndFree(vpb); 00988 } 00989 return op->FinalStatus = status; 00990 } 00991 00992 RtlZeroMemory( fileObject, sizeof( FILE_OBJECT ) ); 00993 fileObject->Type = IO_TYPE_FILE; 00994 fileObject->Size = sizeof( FILE_OBJECT ); 00995 fileObject->RelatedFileObject = op->RelatedFileObject; 00996 if (op->CreateOptions & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) { 00997 fileObject->Flags = FO_SYNCHRONOUS_IO; 00998 if (op->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) { 00999 fileObject->Flags |= FO_ALERTABLE_IO; 01000 } 01001 } 01002 01003 // 01004 // Now fill in the file object as best is possible at this point and set 01005 // a pointer to it in the IRP so everyone else can find it. 01006 // 01007 01008 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 01009 KeInitializeEvent( &fileObject->Lock, SynchronizationEvent, FALSE ); 01010 fileObject->Waiters = 0; 01011 fileObject->CurrentByteOffset.QuadPart = 0; 01012 } 01013 if (op->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) { 01014 fileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING; 01015 } 01016 if (op->CreateOptions & FILE_WRITE_THROUGH) { 01017 fileObject->Flags |= FO_WRITE_THROUGH; 01018 } 01019 if (op->CreateOptions & FILE_SEQUENTIAL_ONLY) { 01020 fileObject->Flags |= FO_SEQUENTIAL_ONLY; 01021 } 01022 if (op->CreateOptions & FILE_RANDOM_ACCESS) { 01023 fileObject->Flags |= FO_RANDOM_ACCESS; 01024 } 01025 01026 } else { 01027 01028 // 01029 // This is either a quick delete or query operation. For these cases, 01030 // it is possible to optimize the Object Manager out of the picture by 01031 // simply putting together something that "looks" like a file object, 01032 // and then operating on it. 01033 // 01034 01035 localFileObject = op->LocalFileObject; 01036 RtlZeroMemory( localFileObject, sizeof( DUMMY_FILE_OBJECT ) ); 01037 fileObject = (PFILE_OBJECT) &localFileObject->ObjectHeader.Body; 01038 localFileObject->ObjectHeader.Type = IoFileObjectType; 01039 localFileObject->ObjectHeader.PointerCount = 1; 01040 } 01041 01042 if (directDeviceOpen) { 01043 fileObject->Flags |= FO_DIRECT_DEVICE_OPEN; 01044 } 01045 if (!(Attributes & OBJ_CASE_INSENSITIVE)) { 01046 fileObject->Flags |= FO_OPENED_CASE_SENSITIVE; 01047 } 01048 01049 fileObject->Type = IO_TYPE_FILE; 01050 fileObject->Size = sizeof( FILE_OBJECT ); 01051 fileObject->RelatedFileObject = op->RelatedFileObject; 01052 fileObject->DeviceObject = parseDeviceObject; 01053 01054 irp->Tail.Overlay.OriginalFileObject = fileObject; 01055 irpSp->FileObject = fileObject; 01056 01057 // 01058 // Allocate a file name string buffer which is large enough to contain 01059 // the entire remaining name string and initialize the maximum length. 01060 // 01061 01062 if (RemainingName->Length) { 01063 fileObject->FileName.MaximumLength = RoundNameSize( RemainingName->Length ); 01064 fileObject->FileName.Buffer = ExAllocatePoolWithTag( PagedPool, 01065 fileObject->FileName.MaximumLength, 01066 'mNoI' ); 01067 if (!fileObject->FileName.Buffer) { 01068 IoFreeIrp( irp ); 01069 01070 IopDecrementDeviceObjectRef( parseDeviceObject, FALSE ); 01071 01072 if (vpb) { 01073 IopDereferenceVpbAndFree(vpb); 01074 } 01075 fileObject->DeviceObject = (PDEVICE_OBJECT) NULL; 01076 if (realFileObjectRequired) { 01077 ObDereferenceObject( fileObject ); 01078 } 01079 return STATUS_INSUFFICIENT_RESOURCES; 01080 } 01081 } 01082 01083 // 01084 // Now copy the name string into the file object from the remaining name 01085 // that is being reparsed. If the driver decides to reparse, then it must 01086 // replace this name. 01087 // 01088 01089 RtlCopyUnicodeString( &fileObject->FileName, RemainingName ); 01090 01091 // 01092 // Before invoking the driver's open routine, check to see whether or not 01093 // this is a fast network attributes query and, if so, and the driver 01094 // implements the function, attempt to call it here. 01095 // 01096 01097 if (op->QueryOnly) { 01098 PFAST_IO_DISPATCH fastIoDispatch = deviceObject->DriverObject->FastIoDispatch; 01099 BOOLEAN result; 01100 01101 if (fastIoDispatch && 01102 fastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET( FAST_IO_DISPATCH, FastIoQueryOpen ) && 01103 fastIoDispatch->FastIoQueryOpen) { 01104 01105 IoSetNextIrpStackLocation( irp ); 01106 irpSp->DeviceObject = deviceObject; 01107 result = (fastIoDispatch->FastIoQueryOpen)( irp, 01108 op->NetworkInformation, 01109 deviceObject ); 01110 if (result) { 01111 op->FinalStatus = irp->IoStatus.Status; 01112 op->Information = irp->IoStatus.Information; 01113 01114 // 01115 // The operation worked, so simply dereference and free the 01116 // resources acquired up to this point. 01117 // 01118 01119 if ((op->FinalStatus == STATUS_REPARSE) && 01120 irp->Tail.Overlay.AuxiliaryBuffer) { 01121 ASSERT( op->Information > IO_REPARSE_TAG_RESERVED_ONE ); 01122 ExFreePool( irp->Tail.Overlay.AuxiliaryBuffer ); 01123 irp->Tail.Overlay.AuxiliaryBuffer = NULL; 01124 op->RelatedFileObject = (PFILE_OBJECT) NULL; 01125 } 01126 01127 if (fileObject->FileName.Length) { 01128 ExFreePool( fileObject->FileName.Buffer ); 01129 } 01130 01131 IopDecrementDeviceObjectRef( parseDeviceObject, FALSE ); 01132 01133 if (vpb) { 01134 IopDereferenceVpbAndFree(vpb); 01135 } 01136 01137 #if DBG 01138 irp->CurrentLocation = irp->StackCount + 2; 01139 #endif // DBG 01140 01141 IoFreeIrp( irp ); 01142 01143 // 01144 // Finally, indicate that the parse routine was actually 01145 // invoked and that the information returned herein can be 01146 // used. 01147 // 01148 01149 op->ParseCheck = OPEN_PACKET_PATTERN; 01150 status = STATUS_SUCCESS; 01151 01152 if (!op->FullAttributes) { 01153 try { 01154 op->BasicInformation->FileAttributes = op->NetworkInformation->FileAttributes; 01155 } except(EXCEPTION_EXECUTE_HANDLER) { 01156 status = GetExceptionCode(); 01157 } 01158 } 01159 01160 return status; 01161 01162 } else { 01163 01164 // 01165 // The fast I/O operation did not work, so take the longer 01166 // route. 01167 // 01168 01169 irp->Tail.Overlay.CurrentStackLocation++; 01170 irp->CurrentLocation++; 01171 } 01172 } 01173 } 01174 01175 // 01176 // Finally, initialize the file object's event to the Not Signaled state 01177 // and remember that a file object was created. 01178 // 01179 01180 KeInitializeEvent( &fileObject->Event, NotificationEvent, FALSE ); 01181 op->FileObject = fileObject; 01182 01183 // 01184 // Insert the packet at the head of the IRP list for the thread. 01185 // 01186 01187 IopQueueThreadIrp( irp ); 01188 01189 // 01190 // Now invoke the driver itself to open the file. 01191 // 01192 01193 status = IoCallDriver( deviceObject, irp ); 01194 01195 // 01196 // One of four things may have happened when the driver was invoked: 01197 // 01198 // 1. The I/O operation is pending (Status == STATUS_PENDING). This can 01199 // occur on devices which need to perform some sort of device 01200 // manipulation (such as opening a file for a file system). 01201 // 01202 // 2. The driver returned an error (Status < 0). This occurs when either 01203 // a supplied parameter was in error, or the device or file system 01204 // incurred or discovered an error. 01205 // 01206 // 3. The operation ended in a reparse (Status == STATUS_REPARSE). This 01207 // occurs when a file system opens the file, only to discover that it 01208 // represents a symbolic link. 01209 // 01210 // 4. The operation is complete and was successful (Status == 01211 // STATUS_SUCCESS). Note that for this case the only action is to 01212 // return a pointer to the file object. 01213 // 01214 01215 if (status == STATUS_PENDING) { 01216 01217 (VOID) KeWaitForSingleObject( &fileObject->Event, 01218 Executive, 01219 KernelMode, 01220 FALSE, 01221 (PLARGE_INTEGER) NULL ); 01222 status = ioStatus.Status; 01223 01224 } else { 01225 01226 // 01227 // The I/O operation was completed without returning a status of 01228 // pending. This means that at this point, the IRP has not been 01229 // fully completed. Complete it now. 01230 // 01231 01232 PKNORMAL_ROUTINE normalRoutine; 01233 PVOID normalContext; 01234 KIRQL irql; 01235 01236 ASSERT( !irp->PendingReturned ); 01237 ASSERT( !irp->MdlAddress ); 01238 01239 // 01240 // In the case of name junctions do the transmogrify work. 01241 // 01242 01243 if (irp->IoStatus.Status == STATUS_REPARSE && 01244 irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT ) { 01245 01246 PREPARSE_DATA_BUFFER reparseBuffer = NULL; 01247 01248 ASSERT ( irp->Tail.Overlay.AuxiliaryBuffer != NULL ); 01249 01250 reparseBuffer = (PREPARSE_DATA_BUFFER) irp->Tail.Overlay.AuxiliaryBuffer; 01251 01252 ASSERT( reparseBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT ); 01253 ASSERT( reparseBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE ); 01254 ASSERT( reparseBuffer->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE ); 01255 01256 IopDoNameTransmogrify( irp, 01257 fileObject, 01258 reparseBuffer ); 01259 } 01260 01261 // 01262 // Now finish up the request. 01263 // 01264 01265 KeRaiseIrql( APC_LEVEL, &irql ); 01266 01267 // 01268 // Note that normally the system would simply call IopCompleteRequest 01269 // here to complete the packet. However, because this is a create 01270 // operation, several assumptions can be made that make it much faster 01271 // to perform the couple of operations that completing the request 01272 // would perform. These include: copying the I/O status block, 01273 // dequeueing the IRP and freeing it, and setting the file object's 01274 // event to the signalled state. The latter is done here by hand, 01275 // since it is known that it is not possible for any thread to be 01276 // waiting on the event. 01277 // 01278 01279 ioStatus = irp->IoStatus; 01280 status = ioStatus.Status; 01281 01282 fileObject->Event.Header.SignalState = 1; 01283 01284 IopDequeueThreadIrp( irp ); 01285 01286 // 01287 // The SystemBuffer is in some cases used by the driver, and 01288 // needs to be freed if present. 01289 // 01290 01291 if ((irp->Flags & IRP_BUFFERED_IO) && (irp->Flags & IRP_DEALLOCATE_BUFFER)) { 01292 ExFreePool(irp->AssociatedIrp.SystemBuffer); 01293 } 01294 01295 IoFreeIrp( irp ); 01296 01297 KeLowerIrql( irql ); 01298 } 01299 01300 // 01301 // Copy the information field of the I/O status block back to the 01302 // original caller in case it is required. 01303 // 01304 01305 op->Information = ioStatus.Information; 01306 01307 if (!NT_SUCCESS( status )) { 01308 int openCancelled; 01309 01310 // 01311 // The operation ended in an error. Kill the file object, dereference 01312 // the device object, and return a null pointer. 01313 // 01314 01315 if (fileObject->FileName.Length) { 01316 ExFreePool( fileObject->FileName.Buffer ); 01317 fileObject->FileName.Length = 0; 01318 } 01319 01320 fileObject->DeviceObject = (PDEVICE_OBJECT) NULL; 01321 01322 openCancelled = (fileObject->Flags & FO_FILE_OPEN_CANCELLED); 01323 01324 if (realFileObjectRequired) { 01325 ObDereferenceObject( fileObject ); 01326 } 01327 op->FileObject = (PFILE_OBJECT) NULL; 01328 01329 IopDecrementDeviceObjectRef( parseDeviceObject, FALSE ); 01330 01331 if ((!openCancelled) && (vpb )) { 01332 IopDereferenceVpbAndFree(vpb); 01333 } 01334 01335 return op->FinalStatus = status; 01336 01337 } else if (status == STATUS_REPARSE) { 01338 01339 // 01340 // The operation resulted in a reparse. This means that the file 01341 // name in the file object is the new name to be looked up. Replace 01342 // the complete name string with the new name and return STATUS_REPARSE 01343 // so the object manager knows to start over again. Note, however, 01344 // that the file name buffer in the file object itself is kept intact 01345 // so that it can be reused when coming back here again. 01346 // 01347 // A reparse status may also have been returned from the file system if 01348 // the volume that was in a drive needed to have been verified, but 01349 // the verification failed, and a new volume was mounted. In this 01350 // case, everything starts over again using the new volume. 01351 // 01352 01353 ASSERT( IO_REPARSE == IO_REPARSE_TAG_RESERVED_ZERO ); 01354 01355 if ((ioStatus.Information == IO_REPARSE) || 01356 (ioStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)) { 01357 01358 // 01359 // If the complete name buffer isn't large enough, reallocate it. 01360 // 01361 01362 if (CompleteName->MaximumLength < fileObject->FileName.Length) { 01363 01364 PVOID buffer; 01365 01366 buffer = ExAllocatePoolWithTag( PagedPool, 01367 fileObject->FileName.Length, 01368 'cFoI' ); 01369 if (!buffer) { 01370 return op->FinalStatus = STATUS_INSUFFICIENT_RESOURCES; 01371 } else { 01372 if (CompleteName->Buffer) { 01373 ExFreePool( CompleteName->Buffer ); 01374 } 01375 CompleteName->Buffer = buffer; 01376 CompleteName->MaximumLength = fileObject->FileName.Length; 01377 } 01378 } 01379 01380 RtlCopyUnicodeString( CompleteName, &fileObject->FileName ); 01381 01382 // 01383 // For NTFS directory junction points we NULL the RelatedFileObject. 01384 // If the prior call was a relative open, the subsequent one will 01385 // not be. 01386 // 01387 01388 if (ioStatus.Information == IO_REPARSE_TAG_MOUNT_POINT) { 01389 01390 op->RelatedFileObject = (PFILE_OBJECT) NULL; 01391 } 01392 } 01393 01394 // 01395 // Kill the file object, dereference the device object, and return a 01396 // null pointer. 01397 // 01398 01399 if (fileObject->FileName.Length) { 01400 ExFreePool( fileObject->FileName.Buffer ); 01401 fileObject->FileName.Length = 0; 01402 } 01403 01404 fileObject->DeviceObject = (PDEVICE_OBJECT) NULL; 01405 01406 if (realFileObjectRequired) { 01407 ObDereferenceObject( fileObject ); 01408 } 01409 op->FileObject = (PFILE_OBJECT) NULL; 01410 01411 IopDecrementDeviceObjectRef( parseDeviceObject, FALSE ); 01412 01413 if (vpb) { 01414 IopDereferenceVpbAndFree(vpb); 01415 } 01416 01417 ASSERT( IO_REMOUNT == IO_REPARSE_TAG_RESERVED_ONE ); 01418 01419 if (ioStatus.Information == IO_REPARSE_TAG_RESERVED_ONE) { 01420 01421 // 01422 // If we are reparsing to verify a volume, restart the reparse 01423 // by attempting to parse the device once again. Note that it 01424 // would be best to simply recurse, but it's not possible since 01425 // there is a limited amount of stack available to kernel mode 01426 // and a limit needs to be enforced for the number of times that 01427 // verify reparse can occur. 01428 // 01429 01430 if (++retryCount > IO_MAX_REMOUNT_REPARSE_ATTEMPTS) { 01431 01432 return STATUS_UNSUCCESSFUL; 01433 } 01434 goto reparse_loop; 01435 01436 } else { 01437 01438 // 01439 // Really reparsing a symbolic link, so go back to the object 01440 // manager so it can begin the parse from the top. 01441 // 01442 01443 op->RelatedFileObject = (PFILE_OBJECT) NULL; 01444 return STATUS_REPARSE; 01445 } 01446 01447 } else { 01448 01449 // 01450 // The operation was successful. The first thing to do is to see if 01451 // the device that processed the open also opened the file. If 01452 // not, we need to adjust the vpb reference counts. Then, if this is 01453 // not a query or a delete, but rather a normal open/create, return 01454 // the address of the FileObject to the caller and set the 01455 // information returned in the original requestor's I/O status block. 01456 // Also set the value of the parse check field in the open packet to 01457 // a value which will let the caller know that this routine was 01458 // successful in creating the file object. Finally, return the status 01459 // of the operation to the caller. 01460 // 01461 01462 PDEVICE_OBJECT deviceObjectThatOpenedFile; 01463 01464 deviceObjectThatOpenedFile = IoGetRelatedDeviceObject(fileObject); 01465 if (deviceObject != deviceObjectThatOpenedFile) { 01466 // 01467 // The device that opened the related file is not the one 01468 // that opened this file. So, readjust the vpb reference 01469 // counts. 01470 if (vpb) { 01471 IopDereferenceVpbAndFree(vpb); 01472 } 01473 vpb = fileObject->Vpb; 01474 if (vpb) { 01475 ExInterlockedAddUlong( 01476 &vpb->ReferenceCount, 1, &IopVpbSpinLock ); 01477 } 01478 } 01479 01480 if (realFileObjectRequired) { 01481 01482 *Object = fileObject; 01483 op->ParseCheck = OPEN_PACKET_PATTERN; 01484 01485 // 01486 // Add a reference so the file object cannot go away before 01487 // the create routine gets chance to flag the object for handle 01488 // create. 01489 // 01490 01491 ObReferenceObject( fileObject ); 01492 01493 // 01494 // If the filename length is zero and its not a relative open or 01495 // its a relative open to a volume open then set the volume open flag. 01496 // Also set it only for filesystem device object volume. 01497 // 01498 if ((!fileObject->RelatedFileObject || fileObject->RelatedFileObject->Flags & FO_VOLUME_OPEN) && 01499 (!fileObject->FileName.Length)) { 01500 switch (deviceObjectThatOpenedFile->DeviceType) { 01501 case FILE_DEVICE_DISK_FILE_SYSTEM: 01502 case FILE_DEVICE_CD_ROM_FILE_SYSTEM: 01503 case FILE_DEVICE_TAPE_FILE_SYSTEM: 01504 case FILE_DEVICE_FILE_SYSTEM: 01505 01506 fileObject->Flags |= FO_VOLUME_OPEN; 01507 break; 01508 01509 default: 01510 break; 01511 } 01512 } 01513 01514 return op->FinalStatus = ioStatus.Status; 01515 01516 } else { 01517 01518 // 01519 // This is either a quick query or delete operation. Determine 01520 // which it is and quickly perform the operation. 01521 // 01522 01523 if (op->QueryOnly) { 01524 PFAST_IO_DISPATCH fastIoDispatch; 01525 BOOLEAN queryResult = FALSE; 01526 01527 fastIoDispatch = deviceObjectThatOpenedFile->DriverObject->FastIoDispatch; 01528 01529 if (!op->FullAttributes) { 01530 PFILE_BASIC_INFORMATION basicInfo = NULL; 01531 01532 // 01533 // This is a simple FAT file attribute query. Attempt to 01534 // obtain the basic information about the file. 01535 // 01536 01537 try { 01538 01539 if (fastIoDispatch && fastIoDispatch->FastIoQueryBasicInfo) { 01540 queryResult = fastIoDispatch->FastIoQueryBasicInfo( 01541 fileObject, 01542 TRUE, 01543 op->BasicInformation, 01544 &ioStatus, 01545 deviceObjectThatOpenedFile 01546 ); 01547 } 01548 if (!queryResult) { 01549 ULONG returnedLength; 01550 01551 basicInfo = ExAllocatePool( NonPagedPool, 01552 sizeof( FILE_BASIC_INFORMATION ) ); 01553 if (basicInfo) { 01554 status = IoQueryFileInformation( 01555 fileObject, 01556 FileBasicInformation, 01557 sizeof( FILE_BASIC_INFORMATION ), 01558 basicInfo, 01559 &returnedLength 01560 ); 01561 if (NT_SUCCESS( status )) { 01562 RtlCopyMemory( op->BasicInformation, 01563 basicInfo, 01564 returnedLength ); 01565 } 01566 ExFreePool( basicInfo ); 01567 } else { 01568 status = STATUS_INSUFFICIENT_RESOURCES; 01569 } 01570 } else { 01571 status = ioStatus.Status; 01572 } 01573 } except(EXCEPTION_EXECUTE_HANDLER) { 01574 if (basicInfo) { 01575 ExFreePool( basicInfo ); 01576 } 01577 status = GetExceptionCode(); 01578 } 01579 01580 } else { 01581 01582 // 01583 // This is a full attribute query. Attempt to obtain the 01584 // full network attributes for the file. This includes 01585 // both the basic and standard information about the 01586 // file. Try the fast path first, if it exists. 01587 // 01588 01589 if (fastIoDispatch && 01590 fastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET( FAST_IO_DISPATCH, FastIoQueryNetworkOpenInfo ) && 01591 fastIoDispatch->FastIoQueryNetworkOpenInfo) { 01592 queryResult = fastIoDispatch->FastIoQueryNetworkOpenInfo( 01593 fileObject, 01594 TRUE, 01595 op->NetworkInformation, 01596 &ioStatus, 01597 deviceObjectThatOpenedFile 01598 ); 01599 } 01600 if (!queryResult) { 01601 ULONG returnedLength; 01602 01603 // 01604 // Either the fast dispatch routine did not exist, or 01605 // it simply wasn't callable at this time. Attempt to 01606 // obtain all of the information at once via an IRP- 01607 // based call. 01608 // 01609 01610 status = IoQueryFileInformation( 01611 fileObject, 01612 FileNetworkOpenInformation, 01613 sizeof( FILE_NETWORK_OPEN_INFORMATION ), 01614 op->NetworkInformation, 01615 &returnedLength 01616 ); 01617 01618 if (!NT_SUCCESS( status )) { 01619 if (status == STATUS_INVALID_PARAMETER || 01620 status == STATUS_NOT_IMPLEMENTED) { 01621 FILE_BASIC_INFORMATION basicInfo; 01622 FILE_STANDARD_INFORMATION stdInfo; 01623 01624 // 01625 // The IRP-based call did not work either, so 01626 // simply try to obtain the information by 01627 // doing IRP-based queries for the basic and 01628 // standard information and piecing together 01629 // the results into the caller's buffer. Note 01630 // that it might be possible to perform fast 01631 // I/O operations to get the data, but it 01632 // might also fail because of the above. So 01633 // simply query the information the long way. 01634 // 01635 01636 status = IoQueryFileInformation( 01637 fileObject, 01638 FileBasicInformation, 01639 sizeof( FILE_BASIC_INFORMATION ), 01640 &basicInfo, 01641 &returnedLength 01642 ); 01643 if (NT_SUCCESS( status )) { 01644 status = IoQueryFileInformation( 01645 fileObject, 01646 FileStandardInformation, 01647 sizeof( FILE_STANDARD_INFORMATION ), 01648 &stdInfo, 01649 &returnedLength 01650 ); 01651 if (NT_SUCCESS( status )) { 01652 COPY_ATTRIBUTES( op->NetworkInformation, 01653 &basicInfo, 01654 &stdInfo ); 01655 } 01656 } 01657 } 01658 } 01659 } 01660 } 01661 01662 } else { 01663 01664 // 01665 // There is nothing to do for a quick delete since the caller 01666 // set the FILE_DELETE_ON_CLOSE CreateOption so it is already 01667 // set in the file system. 01668 // 01669 01670 NOTHING; 01671 01672 } 01673 01674 op->ParseCheck = OPEN_PACKET_PATTERN; 01675 if (realFileObjectRequired) { 01676 ObDereferenceObject( fileObject ); 01677 } else { 01678 IopDeleteFile( fileObject ); 01679 } 01680 op->FileObject = (PFILE_OBJECT) NULL; 01681 01682 op->FinalStatus = status; 01683 01684 return status; 01685 } 01686 } 01687 }

NTSTATUS IopParseFile IN PVOID  ParseObject,
IN PVOID  ObjectType,
IN PACCESS_STATE  AccessState,
IN KPROCESSOR_MODE  AccessMode,
IN ULONG  Attributes,
IN OUT PUNICODE_STRING  CompleteName,
IN OUT PUNICODE_STRING  RemainingName,
IN OUT PVOID Context  OPTIONAL,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos  OPTIONAL,
OUT PVOID *  Object
 

Definition at line 1690 of file parse.c.

References IO_TYPE_OPEN_PACKET, IoGetRelatedDeviceObject(), IopParseDevice(), NULL, PAGED_CODE, _OPEN_PACKET::RelatedFileObject, SecurityQos, _OPEN_PACKET::Size, and _OPEN_PACKET::Type.

Referenced by IopCreateObjectTypes().

01705 : 01706 01707 This routine interfaces to the NT Object Manager. It is invoked when 01708 the object system is given the name of an entity to create or open and is 01709 also given a handle to a directory file object that the operation is to be 01710 performed relative to. This routine is specified as the parse routine for 01711 all file objects. 01712 01713 This routine simply invokes the parse routine for the appropriate device 01714 that is associated with the file object. It is the responsibility of that 01715 routine to perform the operation. 01716 01717 Arguments: 01718 01719 ParseObject - Pointer to the file object that the name is to be opened or 01720 created relative to. 01721 01722 ObjectType - Type of the object being opened. 01723 01724 AccessState - Running security access state information for operation. 01725 01726 AccessMode - Access mode of the original caller. 01727 01728 Attributes - Attributes to be applied to the object. 01729 01730 CompleteName - Complete name of the object. 01731 01732 RemainingName - Remaining name of the object. 01733 01734 Context - Pointer to an Open Packet (OP) from NtCreateFile service. 01735 01736 SecurityQos - Supplies a pointer to the captured QOS information 01737 if available. 01738 01739 Object - The address of a variable to receive the created file object, if 01740 any. 01741 01742 Return Value: 01743 01744 The function return value is one of the following: 01745 01746 a) Success - This indicates that the function succeeded and the object 01747 parameter contains the address of the created file object. 01748 01749 b) Error - This indicates that the file was not found or created and 01750 no file object was created. 01751 01752 c) Reparse - This indicates that the remaining name string has been 01753 replaced by a new name that is to be parsed. 01754 01755 --*/ 01756 01757 { 01758 PDEVICE_OBJECT deviceObject; 01759 POPEN_PACKET op; 01760 01761 PAGED_CODE(); 01762 01763 // 01764 // Get the address of the Open Packet (OP). 01765 // 01766 01767 op = (POPEN_PACKET) Context; 01768 01769 // 01770 // Ensure that this routine is actually being invoked because someone is 01771 // attempting to open a device or a file through NtCreateFile. This code 01772 // must be invoked from there (as opposed to some other random object 01773 // create or open routine). 01774 // 01775 01776 if (op == NULL || 01777 op->Type != IO_TYPE_OPEN_PACKET || 01778 op->Size != sizeof( OPEN_PACKET )) { 01779 return STATUS_OBJECT_TYPE_MISMATCH; 01780 } 01781 01782 // 01783 // Get a pointer to the device object for this file. 01784 // 01785 01786 deviceObject = IoGetRelatedDeviceObject( (PFILE_OBJECT) ParseObject ); 01787 01788 // 01789 // Pass the related file object to the device object parse routine. 01790 // 01791 01792 op->RelatedFileObject = (PFILE_OBJECT) ParseObject; 01793 01794 // 01795 // Open or create the specified file. 01796 // 01797 01798 return IopParseDevice( deviceObject, 01799 ObjectType, 01800 AccessState, 01801 AccessMode, 01802 Attributes, 01803 CompleteName, 01804 RemainingName, 01805 Context, 01806 SecurityQos, 01807 Object ); 01808 }

NTSTATUS IopQueryName IN PVOID  Object,
IN BOOLEAN  HasObjectName,
OUT POBJECT_NAME_INFORMATION  ObjectNameInfo,
IN ULONG  Length,
OUT PULONG  ReturnLength
 

Definition at line 1811 of file parse.c.

References ASSERT, _FILE_OBJECT::DeviceObject, ExAllocatePoolWithTag, ExFreePool(), FileName, _FILE_OBJECT::Flags, FO_SYNCHRONOUS_IO, IopGetFileName(), IoQueryFileInformation(), NT_ERROR, NT_SUCCESS, NTSTATUS(), ObQueryNameString(), PAGED_CODE, PagedPool, UserMode, and USHORT.

Referenced by IopCreateObjectTypes().

01821 : 01822 01823 This function implements the query name procedure for the Object Manager 01824 for querying the names of file objects. 01825 01826 Arguments: 01827 01828 Object - Pointer to the file object whose name is to be retrieved. 01829 01830 HasObjectName - Indicates whether or not the object has a name. 01831 01832 ObjectNameInfo - Buffer in which to return the name. 01833 01834 Length - Specifies the length of the output buffer, in bytes. 01835 01836 ReturnLength - Specifies the number of bytes actually returned in the 01837 output buffer. 01838 01839 Return Value: 01840 01841 The function return value is the final status of the query operation. 01842 01843 --*/ 01844 01845 { 01846 NTSTATUS status; 01847 ULONG lengthNeeded; 01848 PFILE_OBJECT fileObject; 01849 PUCHAR buffer; 01850 PWSTR p; 01851 POBJECT_NAME_INFORMATION deviceNameInfo; 01852 PFILE_NAME_INFORMATION fileNameInfo; 01853 ULONG length; 01854 01855 UNREFERENCED_PARAMETER( HasObjectName ); 01856 01857 PAGED_CODE(); 01858 01859 ASSERT( FIELD_OFFSET( FILE_NAME_INFORMATION, FileName ) < sizeof( OBJECT_NAME_INFORMATION ) ); 01860 01861 // 01862 // Ensure that the size of the output buffer is at least the minimum 01863 // size required to include the basic object name information structure. 01864 // 01865 01866 if (Length < sizeof( OBJECT_NAME_INFORMATION )) { 01867 return STATUS_INFO_LENGTH_MISMATCH; 01868 } 01869 01870 // 01871 // Begin by allocating a buffer in which to build the name of the file. 01872 // 01873 01874 buffer = ExAllocatePoolWithTag( PagedPool, Length, ' oI' ); 01875 if (!buffer) { 01876 return STATUS_INSUFFICIENT_RESOURCES; 01877 } 01878 01879 try { 01880 01881 // 01882 // Query the name of the device on which the file is open. 01883 // 01884 01885 fileObject = (PFILE_OBJECT) Object; 01886 deviceNameInfo = (POBJECT_NAME_INFORMATION) buffer; 01887 01888 status = ObQueryNameString( (PVOID) fileObject->DeviceObject, 01889 deviceNameInfo, 01890 Length, 01891 &lengthNeeded ); 01892 if (!NT_SUCCESS( status )) { 01893 return status; 01894 } 01895 01896 // 01897 // Ensure that there is enough room in the output buffer to return the 01898 // name and copy it. 01899 // 01900 01901 RtlCopyMemory( ObjectNameInfo, 01902 deviceNameInfo, 01903 lengthNeeded > Length ? Length : lengthNeeded ); 01904 p = (PWSTR) (ObjectNameInfo + 1); 01905 ObjectNameInfo->Name.Buffer = p; 01906 p = (PWSTR) ((PCHAR) p + deviceNameInfo->Name.Length); 01907 01908 // 01909 // If the buffer is already full, then return. 01910 // 01911 01912 if (lengthNeeded > Length) { 01913 return STATUS_BUFFER_OVERFLOW; 01914 } 01915 01916 // 01917 // Reset the state for the buffer to obtain the filename portion of the 01918 // name and calculate the remaining length of the caller's buffer. Note 01919 // that in the following calculations, there are two assumptions and 01920 // and dependencies: 01921 // 01922 // 1) The above query of the device name's returned length needed 01923 // include a NULL character which will be included at the end 01924 // of the entire name. This is included in the calculations 01925 // although it does not appear to be included. 01926 // 01927 // 2) The sizeof the object name information buffer is assumed 01928 // (and guaranteed because it can never change) to be larger 01929 // than the filename offset in a file name information buffer. 01930 // Therefore it is known that the new length of the "buffer" 01931 // variable can be set to the remaining length plus at least 4. 01932 // 01933 01934 fileNameInfo = (PFILE_NAME_INFORMATION) buffer; 01935 length = Length - lengthNeeded; 01936 01937 length += FIELD_OFFSET( FILE_NAME_INFORMATION, FileName ); 01938 01939 if (KeGetPreviousMode() == UserMode || 01940 !(fileObject->Flags & FO_SYNCHRONOUS_IO)) { 01941 01942 // 01943 // Query the name of the file based using an intermediary buffer. 01944 // 01945 01946 status = IoQueryFileInformation( fileObject, 01947 FileNameInformation, 01948 length, 01949 (PVOID) fileNameInfo, 01950 &lengthNeeded ); 01951 } 01952 else { 01953 01954 // 01955 // This is a kernel mode request for a file that was opened for 01956 // synchronous I/O. A special function that does not obtain the 01957 // file object lock is required, otherwise the request may deadlock 01958 // since the lock is probably already owned. 01959 // 01960 01961 status = IopGetFileName( fileObject, 01962 length, 01963 fileNameInfo, 01964 &lengthNeeded ); 01965 } 01966 01967 // 01968 // If an error occurred attempting to obtain the filename return now. Note 01969 // that buffer overflow is a warning, not an error. 01970 // 01971 01972 if (NT_ERROR( status )) { 01973 if (status == STATUS_INVALID_PARAMETER || 01974 status == STATUS_INVALID_DEVICE_REQUEST || 01975 status == STATUS_NOT_IMPLEMENTED || 01976 status == STATUS_INVALID_INFO_CLASS) { 01977 lengthNeeded = FIELD_OFFSET( FILE_NAME_INFORMATION, FileName ); 01978 fileNameInfo->FileNameLength = 0; 01979 fileNameInfo->FileName[0] = OBJ_NAME_PATH_SEPARATOR; 01980 status = STATUS_SUCCESS; 01981 } 01982 else { 01983 return status; 01984 } 01985 } 01986 01987 // 01988 // Set the remaining length of the caller's buffer as well as the total 01989 // length needed to contain the entire name of the file. 01990 // 01991 01992 length = lengthNeeded - FIELD_OFFSET( FILE_NAME_INFORMATION, FileName ); 01993 lengthNeeded = (ULONG)((PUCHAR) p - (PUCHAR) ObjectNameInfo) + fileNameInfo->FileNameLength; 01994 01995 // 01996 // Attempt to copy the name of the file into the output buffer. Note 01997 // that if the file name does not begin w/a '\', then it is not volume 01998 // relative, so the name of the file cannot be expressed as the 01999 // concatenation of the name of the device and the file. Therefore an 02000 // error is returned. 02001 // 02002 // The only example of this situation known at this time is when one 02003 // opens a directory by file ID, and then opens a file relative to that 02004 // directory. When attempting to query the path, if the caller did not 02005 // have traverse access to open the directory, then the only name that 02006 // can be returned is the path name to the file from the directory, but 02007 // the volume-relative name cannot be returned. Therefore, the file 02008 // system returns only the name of the directory and the path to the 02009 // file, but this is not volume-relative so the only recourse is to 02010 // return an error. 02011 // 02012 // Note that if the caller were to call NtQueryInformationFile and 02013 // request FileNameInformation, then the name above named will be 02014 // successfully returned from the file system. 02015 // 02016 02017 if (fileNameInfo->FileName[0] != OBJ_NAME_PATH_SEPARATOR) { 02018 return STATUS_OBJECT_PATH_INVALID; 02019 } 02020 02021 RtlMoveMemory( p, 02022 fileNameInfo->FileName, 02023 length ); 02024 p = (PWSTR) ((PCH) p + length); 02025 *p = '\0'; 02026 lengthNeeded += sizeof( WCHAR ); 02027 02028 *ReturnLength = lengthNeeded; 02029 02030 length = (ULONG)((PUCHAR) p - (PUCHAR) ObjectNameInfo); 02031 ObjectNameInfo->Name.Length = (USHORT) (length - sizeof( *ObjectNameInfo )); 02032 ObjectNameInfo->Name.MaximumLength = (USHORT) ((length - sizeof( *ObjectNameInfo )) + sizeof( WCHAR )); 02033 } 02034 02035 finally { 02036 02037 // 02038 // Finally, free the temporary buffer. 02039 // 02040 02041 ExFreePool( buffer ); 02042 } 02043 02044 return status; 02045 }


Generated on Sat May 15 19:45:01 2004 for test by doxygen 1.3.7