diff --git a/src/sys/create.c b/src/sys/create.c index 6b8250e5..39b77124 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -30,6 +30,12 @@ FSP_DRIVER_DISPATCH FspCreate; #define PREFIXW L"" FSP_FSCTL_VOLUME_PARAMS_PREFIX #define PREFIXW_SIZE (sizeof PREFIXW - sizeof(WCHAR)) +enum +{ + RequestFsContext = 0, + RequestAccessToken, +}; + static NTSTATUS FspFsctlCreate( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { @@ -61,12 +67,222 @@ static NTSTATUS FspFsvrtCreate( } static NTSTATUS FspFsvolCreate( - PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) + PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { PAGED_CODE(); - Irp->IoStatus.Information = FILE_OPENED; - return STATUS_SUCCESS; + NTSTATUS Result; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + PFILE_OBJECT FileObject = IrpSp->FileObject; + PFILE_OBJECT RelatedFileObject = FileObject->RelatedFileObject; + UNICODE_STRING FileName = FileObject->FileName; + + /* open the volume object? */ + if ((0 == RelatedFileObject || RelatedFileObject->FsContext) && 0 == FileName.Length) + { + if (0 != FsvolDeviceExtension->FsvrtDeviceObject) + IrpSp->FileObject->Vpb = FsvolDeviceExtension->FsvrtDeviceObject->Vpb; + + Irp->IoStatus.Information = FILE_OPENED; + return STATUS_SUCCESS; + } + + PACCESS_STATE AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState; + ULONG CreateOptions = IrpSp->Parameters.Create.Options; + USHORT FileAttributes = IrpSp->Parameters.Create.FileAttributes; + PSECURITY_DESCRIPTOR SecurityDescriptor = AccessState->SecurityDescriptor; + ULONG SecurityDescriptorSize = 0; + LARGE_INTEGER AllocationSize = Irp->Overlay.AllocationSize; + ACCESS_MASK DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; + USHORT ShareAccess = IrpSp->Parameters.Create.ShareAccess; + PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer; + //ULONG EaLength = IrpSp->Parameters.Create.EaLength; + ULONG Flags = IrpSp->Flags; + KPROCESSOR_MODE RequestorMode = + FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode; + BOOLEAN HasTraversePrivilege = + BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE); + BOOLEAN IsAbsoluteSecurityDescriptor = FALSE; + BOOLEAN IsSelfRelativeSecurityDescriptor = FALSE; + BOOLEAN HasTrailingBackslash = FALSE; + FSP_FILE_CONTEXT *FsContext = 0, *RelatedFsContext; + FSP_FSCTL_TRANSACT_REQ *Request; + + /* cannot open files by fileid */ + if (FlagOn(CreateOptions, FILE_OPEN_BY_FILE_ID)) + return STATUS_NOT_IMPLEMENTED; + + /* do we not support EA */ + if (0 != EaBuffer) + return STATUS_EAS_NOT_SUPPORTED; + + /* cannot open a paging file */ + if (FlagOn(Flags, SL_OPEN_PAGING_FILE)) + return STATUS_ACCESS_DENIED; + + /* check create options */ + if (FlagOn(CreateOptions, FILE_NON_DIRECTORY_FILE) && FlagOn(CreateOptions, FILE_DIRECTORY_FILE)) + return STATUS_INVALID_PARAMETER; + + /* check security descriptor validity */ + if (0 != SecurityDescriptor) + { + IsAbsoluteSecurityDescriptor = RtlValidSecurityDescriptor(SecurityDescriptor); + if (IsAbsoluteSecurityDescriptor) + { + Result = RtlAbsoluteToSelfRelativeSD(SecurityDescriptor, 0, &SecurityDescriptorSize); + if (STATUS_BUFFER_TOO_SMALL != Result) + return STATUS_INVALID_PARAMETER; + } + else + { + SecurityDescriptorSize = RtlLengthSecurityDescriptor(SecurityDescriptor); + IsSelfRelativeSecurityDescriptor = RtlValidRelativeSecurityDescriptor( + SecurityDescriptor, SecurityDescriptorSize, 0); + if (!IsSelfRelativeSecurityDescriptor) + return STATUS_INVALID_PARAMETER; + } + } + + /* according to fastfat, filenames that begin with two backslashes are ok */ + if (sizeof(WCHAR) * 2 <= FileName.Length && + L'\\' == FileName.Buffer[1] && L'\\' == FileName.Buffer[0]) + { + FileName.Length -= sizeof(WCHAR); + FileName.MaximumLength -= sizeof(WCHAR); + FileName.Buffer++; + + if (sizeof(WCHAR) * 2 <= FileName.Length && + L'\\' == FileName.Buffer[1] && L'\\' == FileName.Buffer[0]) + return STATUS_OBJECT_NAME_INVALID; + } + + /* check for trailing backslash */ + if (sizeof(WCHAR) * 2/* not empty or root */ <= FileName.Length && + L'\\' == FileName.Buffer[FileName.Length / 2 - 1]) + { + FileName.Length -= sizeof(WCHAR); + HasTrailingBackslash = TRUE; + + if (sizeof(WCHAR) * 2 <= FileName.Length && L'\\' == FileName.Buffer[FileName.Length / 2 - 1]) + return STATUS_OBJECT_NAME_INVALID; + } + if (HasTrailingBackslash && !FlagOn(CreateOptions, FILE_DIRECTORY_FILE)) + return STATUS_OBJECT_NAME_INVALID; + + /* is this a relative or absolute open? */ + if (0 != RelatedFileObject) + { + RelatedFsContext = RelatedFileObject->FsContext; + + /* is this a valid RelatedFileObject? */ + if (!FspFileContextIsValid(RelatedFsContext)) + return STATUS_OBJECT_PATH_NOT_FOUND; + + /* must be a relative path */ + if (sizeof(WCHAR) <= FileName.Length && L'\\' == FileName.Buffer[0]) + return STATUS_OBJECT_NAME_INVALID; + + /* cannot FILE_DELETE_ON_CLOSE on the root directory */ + if (FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE) && + sizeof(WCHAR) == RelatedFsContext->FileName.Length && 0 == FileName.Length) + return STATUS_CANNOT_DELETE; + + /* + * There is no need to lock our accesses of RelatedFileObject->FsContext->FileName, + * because RelatedFileObject->FsContext->Filename is read-only (after creation) and + * because RelatedFileObject->FsContext is guaranteed to exist while RelatedFileObject + * exists. + */ + BOOLEAN AppendBackslash = + sizeof(WCHAR) * 2/* not empty or root */ <= RelatedFsContext->FileName.Length && + sizeof(WCHAR) <= FileName.Length && L':' != FileName.Buffer[0]; + Result = FspFileContextCreate(FsvolDeviceObject, + RelatedFsContext->FileName.Length + AppendBackslash * sizeof(WCHAR) + FileName.Length, + &FsContext); + if (!NT_SUCCESS(Result)) + return Result; + + Result = RtlAppendUnicodeStringToString(&FsContext->FileName, &RelatedFsContext->FileName); + ASSERT(NT_SUCCESS(Result)); + if (AppendBackslash) + { + Result = RtlAppendUnicodeToString(&FsContext->FileName, L"\\"); + ASSERT(NT_SUCCESS(Result)); + } + } + else + { + /* must be an absolute path */ + if (sizeof(WCHAR) <= FileName.Length && L'\\' != FileName.Buffer[0]) + return STATUS_OBJECT_NAME_INVALID; + + /* cannot FILE_DELETE_ON_CLOSE on the root directory */ + if (FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE) && + sizeof(WCHAR) == FileName.Length) + return STATUS_CANNOT_DELETE; + + Result = FspFileContextCreate(FsvolDeviceObject, + FileName.Length, + &FsContext); + if (!NT_SUCCESS(Result)) + return Result; + } + + Result = RtlAppendUnicodeStringToString(&FsContext->FileName, &FileName); + ASSERT(NT_SUCCESS(Result)); + + /* create the user-mode file system request */ + Result = FspIopCreateRequestEx(Irp, &FsContext->FileName, SecurityDescriptorSize, + FspFsvolCreateRequestFini, &Request); + if (!NT_SUCCESS(Result)) + { + FspFileContextDelete(FsContext); + return Result; + } + + /* + * The new request is associated with our IRP. Go ahead and associate our FsContext + * with the Request as well. After this is done completing our IRP will automatically + * delete the Request and any associated resources. + */ + FspIopRequestContext(Request, RequestFsContext) = FsContext; + + /* populate the Create request */ + Request->Kind = FspFsctlTransactCreateKind; + Request->Req.Create.CreateOptions = CreateOptions; + Request->Req.Create.FileAttributes = FileAttributes; + Request->Req.Create.SecurityDescriptor.Offset = 0 == SecurityDescriptorSize ? 0 : + FSP_FSCTL_DEFAULT_ALIGN_UP(Request->FileName.Size); + Request->Req.Create.SecurityDescriptor.Size = (UINT16)SecurityDescriptorSize; + Request->Req.Create.AllocationSize = AllocationSize.QuadPart; + Request->Req.Create.AccessToken = 0; + Request->Req.Create.DesiredAccess = DesiredAccess; + Request->Req.Create.ShareAccess = ShareAccess; + Request->Req.Create.Ea.Offset = 0; + Request->Req.Create.Ea.Size = 0; + Request->Req.Create.UserMode = UserMode == RequestorMode; + Request->Req.Create.HasTraversePrivilege = HasTraversePrivilege; + Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY); + Request->Req.Create.CaseSensitive = BooleanFlagOn(Flags, SL_CASE_SENSITIVE); + + /* copy the security descriptor into the request */ + if (IsAbsoluteSecurityDescriptor) + { + Result = RtlAbsoluteToSelfRelativeSD(SecurityDescriptor, + Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset, &SecurityDescriptorSize); + if (!NT_SUCCESS(Result)) + { + if (STATUS_BAD_DESCRIPTOR_FORMAT == Result || STATUS_BUFFER_TOO_SMALL == Result) + Result = STATUS_INVALID_PARAMETER; /* should not happen */ + return Result; + } + } + else if (IsSelfRelativeSecurityDescriptor) + RtlCopyMemory(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset, + SecurityDescriptor, SecurityDescriptorSize); + + return STATUS_PENDING; } NTSTATUS FspFsvolCreatePrepare( @@ -90,6 +306,21 @@ VOID FspFsvolCreateComplete( static VOID FspFsvolCreateRequestFini(PVOID Context[3]) { PAGED_CODE(); + + if (0 != Context[RequestFsContext]) + FspFileContextRelease(Context[RequestFsContext]); + + if (0 != Context[RequestAccessToken]) + { +#if DBG + NTSTATUS Result0; + Result0 = ObCloseHandle(Context[RequestAccessToken], KernelMode); + if (!NT_SUCCESS(Result0)) + DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result0)); +#else + ObCloseHandle(Context[RequestAccessToken], KernelMode); +#endif + } } NTSTATUS FspCreate( diff --git a/src/sys/driver.h b/src/sys/driver.h index 8a856967..94353413 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -448,6 +448,57 @@ NTSTATUS FspVolumeTransact( NTSTATUS FspVolumeWork( PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +/* file objects */ +#define FspFileContextKind(FsContext) \ + (((FSP_FILE_CONTEXT *)FsContext)->Header.NodeTypeCode) +#define FspFileContextIsValid(FsContext)\ + (0 != (FsContext) && FspFileContextFileKind == ((FSP_FILE_CONTEXT *)FsContext)->Header.NodeTypeCode) +enum +{ + FspFileContextFileKind = 'BZ', +}; +typedef struct +{ + ERESOURCE Resource; + ERESOURCE PagingIoResource; + FAST_MUTEX HeaderFastMutex; +} FSP_FILE_CONTEXT_NONPAGED; +typedef struct +{ + FSRTL_ADVANCED_FCB_HEADER Header; + FSP_FILE_CONTEXT_NONPAGED *NonPaged; + /* interlocked access */ + LONG RefCount; +#if 0 + /* protected by Header.Resource */ + LONG OpenCount; + SHARE_ACCESS ShareAccess; + BOOLEAN DeletePending; /* FileDispositionInformation */ + BOOLEAN DeleteOnClose; /* FILE_DELETE_ON_CLOSE */ + FSP_DEVICE_GENERIC_TABLE_ELEMENT ElementStorage; + PDEVICE_OBJECT FsvolDeviceObject; + UINT64 UserContext; +#endif + /* read-only after creation */ + UNICODE_STRING FileName; + WCHAR FileNameBuf[]; +} FSP_FILE_CONTEXT; +NTSTATUS FspFileContextCreate(PDEVICE_OBJECT DeviceObject, + ULONG ExtraSize, FSP_FILE_CONTEXT **PFsContext); +VOID FspFileContextDelete(FSP_FILE_CONTEXT *Context); +static inline +VOID FspFileContextRetain(FSP_FILE_CONTEXT *Context) +{ + InterlockedIncrement(&Context->RefCount); +} +static inline +VOID FspFileContextRelease(FSP_FILE_CONTEXT *Context) +{ + LONG RefCount = InterlockedDecrement(&Context->RefCount); + if (0 == RefCount) + FspFileContextDelete(Context); +} + /* debug */ #if DBG const char *NtStatusSym(NTSTATUS Status); @@ -464,21 +515,6 @@ extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[]; extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[]; #if 0 -/* file objects */ -#define FspFileContextKind(FsContext) \ - (((FSP_FILE_CONTEXT *)FsContext)->Header.NodeTypeCode) -#define FspFileContextIsValid(FsContext)\ - (0 != (FsContext) && FspFileContextFileKind == ((FSP_FILE_CONTEXT *)FsContext)->Header.NodeTypeCode) -enum -{ - FspFileContextFileKind = 'BZ', -}; -typedef struct -{ - ERESOURCE Resource; - ERESOURCE PagingIoResource; - FAST_MUTEX HeaderFastMutex; -} FSP_FILE_CONTEXT_NONPAGED; typedef struct { FSRTL_ADVANCED_FCB_HEADER Header; @@ -513,18 +549,6 @@ LONG FspFileContextClose(FSP_FILE_CONTEXT *Context) ASSERT(0 < Context->OpenCount); return --Context->OpenCount; } -static inline -VOID FspFileContextRetain(FSP_FILE_CONTEXT *Context) -{ - InterlockedIncrement(&Context->RefCount); -} -static inline -VOID FspFileContextRelease(FSP_FILE_CONTEXT *Context) -{ - LONG RefCount = InterlockedDecrement(&Context->RefCount); - if (0 == RefCount) - FspFileContextDelete(Context); -} #endif