diff --git a/build/VStudio/winfsp_dll.vcxproj b/build/VStudio/winfsp_dll.vcxproj index cf77883c..19bd2de1 100644 --- a/build/VStudio/winfsp_dll.vcxproj +++ b/build/VStudio/winfsp_dll.vcxproj @@ -75,6 +75,7 @@ + diff --git a/build/VStudio/winfsp_dll.vcxproj.filters b/build/VStudio/winfsp_dll.vcxproj.filters index 6299aaca..13c62356 100644 --- a/build/VStudio/winfsp_dll.vcxproj.filters +++ b/build/VStudio/winfsp_dll.vcxproj.filters @@ -175,6 +175,9 @@ Source + + Source\shared\ku + diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj index 3092efa0..62a6f886 100644 --- a/build/VStudio/winfsp_sys.vcxproj +++ b/build/VStudio/winfsp_sys.vcxproj @@ -228,6 +228,7 @@ + diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters index a23ea4f0..fabab43a 100644 --- a/build/VStudio/winfsp_sys.vcxproj.filters +++ b/build/VStudio/winfsp_sys.vcxproj.filters @@ -131,6 +131,9 @@ Source + + Source\shared\ku + diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index ef970587..f5d7293a 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -91,6 +91,8 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid = /* fsctl device codes */ #define FSP_FSCTL_MOUNTDEV \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'M', METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSP_FSCTL_MOUNTMGR \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'm', METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSP_FSCTL_VOLUME_NAME \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'N', METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSP_FSCTL_VOLUME_LIST \ @@ -679,6 +681,8 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath, PHANDLE PVolumeHandle); FSP_API NTSTATUS FspFsctlMakeMountdev(HANDLE VolumeHandle, BOOLEAN Persistent, GUID *UniqueId); +FSP_API NTSTATUS FspFsctlUseMountmgr(HANDLE VolumeHandle, + PWSTR MountPoint); FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle, PVOID ResponseBuf, SIZE_T ResponseBufSize, PVOID RequestBuf, SIZE_T *PRequestBufSize, diff --git a/src/dll/fsctl.c b/src/dll/fsctl.c index 956c3840..81dbf823 100644 --- a/src/dll/fsctl.c +++ b/src/dll/fsctl.c @@ -130,6 +130,22 @@ FSP_API NTSTATUS FspFsctlMakeMountdev(HANDLE VolumeHandle, return STATUS_SUCCESS; } +FSP_API NTSTATUS FspFsctlUseMountmgr(HANDLE VolumeHandle, + PWSTR MountPoint) +{ + DWORD Bytes; + + Bytes = 0 != MountPoint ? lstrlenW(MountPoint) * sizeof(WCHAR) : 0; + + if (!DeviceIoControl(VolumeHandle, + FSP_FSCTL_MOUNTMGR, + MountPoint, Bytes, 0, 0, + &Bytes, 0)) + return FspNtStatusFromWin32(GetLastError()); + + return STATUS_SUCCESS; +} + FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle, PVOID ResponseBuf, SIZE_T ResponseBufSize, PVOID RequestBuf, SIZE_T *PRequestBufSize, diff --git a/src/dll/library.h b/src/dll/library.h index f1a2e908..fa982ab2 100644 --- a/src/dll/library.h +++ b/src/dll/library.h @@ -73,6 +73,15 @@ NTSTATUS FspEventLogUnregister(VOID); PSID FspWksidNew(WELL_KNOWN_SID_TYPE WellKnownSidType, PNTSTATUS PResult); PSID FspWksidGet(WELL_KNOWN_SID_TYPE WellKnownSidType); +NTSTATUS FspMountmgrCreateDrive( + PUNICODE_STRING VolumeName, GUID *UniqueId, PUNICODE_STRING MountPoint); +NTSTATUS FspMountmgrDeleteDrive( + PUNICODE_STRING MountPoint); +NTSTATUS FspMountmgrNotifyCreateDirectory( + PUNICODE_STRING VolumeName, GUID *UniqueId, PUNICODE_STRING MountPoint); +NTSTATUS FspMountmgrNotifyDeleteDirectory( + PUNICODE_STRING VolumeName, PUNICODE_STRING MountPoint); + ULONG FspLdapConnect(PWSTR HostName, PVOID *PLdap); VOID FspLdapClose(PVOID Ldap); ULONG FspLdapGetValue(PVOID Ldap, PWSTR Base, ULONG Scope, PWSTR Filter, PWSTR Attribute, diff --git a/src/dll/mount.c b/src/dll/mount.c index 3f912ee7..ff745365 100644 --- a/src/dll/mount.c +++ b/src/dll/mount.c @@ -31,6 +31,7 @@ static NTSTATUS (NTAPI *FspNtClose)( HANDLE Handle); static BOOLEAN FspMountDoNotUseLauncherValue; static BOOLEAN FspMountBroadcastDriveChangeValue; +static BOOLEAN FspMountUseMountmgrFromFSDValue; static VOID FspMountInitializeFromRegistry(VOID) { @@ -53,6 +54,14 @@ static VOID FspMountInitializeFromRegistry(VOID) RRF_RT_REG_DWORD, 0, &Value, &Size); if (ERROR_SUCCESS == Result) FspMountBroadcastDriveChangeValue = !!Value; + + Value = 0; + Size = sizeof Value; + Result = RegGetValueW(HKEY_LOCAL_MACHINE, L"" FSP_FSCTL_PRODUCT_FULL_REGKEY, + L"MountUseMountmgrFromFSD", + RRF_RT_REG_DWORD, 0, &Value, &Size); + if (ERROR_SUCCESS == Result) + FspMountUseMountmgrFromFSDValue = !!Value; } static BOOL WINAPI FspMountInitialize( @@ -80,301 +89,40 @@ static BOOL WINAPI FspMountInitialize( return TRUE; } -static NTSTATUS FspMountmgrControl(ULONG IoControlCode, - PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, PULONG POutputBufferLength) -{ - HANDLE MgrHandle = INVALID_HANDLE_VALUE; - DWORD Bytes = 0; - NTSTATUS Result; - - if (0 == POutputBufferLength) - POutputBufferLength = &Bytes; - - MgrHandle = CreateFileW(L"\\\\.\\MountPointManager", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - 0, - 0); - if (INVALID_HANDLE_VALUE == MgrHandle) - { - Result = FspNtStatusFromWin32(GetLastError()); - goto exit; - } - - if (!DeviceIoControl(MgrHandle, - IoControlCode, - InputBuffer, InputBufferLength, OutputBuffer, *POutputBufferLength, - &Bytes, 0)) - { - Result = FspNtStatusFromWin32(GetLastError()); - goto exit; - } - - *POutputBufferLength = Bytes; - Result = STATUS_SUCCESS; - -exit: - if (INVALID_HANDLE_VALUE != MgrHandle) - CloseHandle(MgrHandle); - - return Result; -} - -static NTSTATUS FspMountmgrMakeMountdev(HANDLE VolumeHandle, PWSTR VolumeName, GUID *UniqueId) -{ - /* mountmgr.h */ - typedef enum - { - Disabled = 0, - Enabled, - } MOUNTMGR_AUTO_MOUNT_STATE; - typedef struct - { - MOUNTMGR_AUTO_MOUNT_STATE CurrentState; - } MOUNTMGR_QUERY_AUTO_MOUNT; - typedef struct - { - MOUNTMGR_AUTO_MOUNT_STATE NewState; - } MOUNTMGR_SET_AUTO_MOUNT; - typedef struct - { - USHORT DeviceNameLength; - WCHAR DeviceName[1]; - } MOUNTMGR_TARGET_NAME; - - MOUNTMGR_QUERY_AUTO_MOUNT QueryAutoMount; - MOUNTMGR_SET_AUTO_MOUNT SetAutoMount; - MOUNTMGR_TARGET_NAME *TargetName = 0; - ULONG VolumeNameSize, QueryAutoMountSize, TargetNameSize; - NTSTATUS Result; - - /* transform our volume into one that can be used by the MountManager */ - Result = FspFsctlMakeMountdev(VolumeHandle, FALSE, UniqueId); - if (!NT_SUCCESS(Result)) - goto exit; - - VolumeNameSize = lstrlenW(VolumeName) * sizeof(WCHAR); - QueryAutoMountSize = sizeof QueryAutoMount; - TargetNameSize = FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + VolumeNameSize; - - TargetName = MemAlloc(TargetNameSize); - if (0 == TargetName) - { - Result = STATUS_INSUFFICIENT_RESOURCES; - goto exit; - } - - /* query the current AutoMount value and save it */ - Result = FspMountmgrControl( - CTL_CODE('m', 15, METHOD_BUFFERED, FILE_ANY_ACCESS), - /* IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT */ - 0, 0, &QueryAutoMount, &QueryAutoMountSize); - if (!NT_SUCCESS(Result)) - goto exit; - - /* disable AutoMount */ - SetAutoMount.NewState = 0; - Result = FspMountmgrControl( - CTL_CODE('m', 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - /* IOCTL_MOUNTMGR_SET_AUTO_MOUNT */ - &SetAutoMount, sizeof SetAutoMount, 0, 0); - if (!NT_SUCCESS(Result)) - goto exit; - - /* announce volume arrival */ - memset(TargetName, 0, sizeof *TargetName); - TargetName->DeviceNameLength = (USHORT)VolumeNameSize; - memcpy(TargetName->DeviceName, - VolumeName, TargetName->DeviceNameLength); - Result = FspMountmgrControl( - CTL_CODE('m', 11, METHOD_BUFFERED, FILE_READ_ACCESS), - /* IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION */ - TargetName, TargetNameSize, 0, 0); - if (!NT_SUCCESS(Result)) - goto exit; - - /* reset the AutoMount value to the saved one */ - SetAutoMount.NewState = QueryAutoMount.CurrentState; - FspMountmgrControl( - CTL_CODE('m', 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - /* IOCTL_MOUNTMGR_SET_AUTO_MOUNT */ - &SetAutoMount, sizeof SetAutoMount, 0, 0); - - Result = STATUS_SUCCESS; - -exit: - MemFree(TargetName); - - return Result; -} - -static NTSTATUS FspMountmgrNotify(PWSTR VolumeName, PWSTR MountPoint, BOOLEAN Created) -{ - /* mountmgr.h */ - typedef struct - { - USHORT SourceVolumeNameOffset; - USHORT SourceVolumeNameLength; - USHORT TargetVolumeNameOffset; - USHORT TargetVolumeNameLength; - } MOUNTMGR_VOLUME_MOUNT_POINT; - - MOUNTMGR_VOLUME_MOUNT_POINT *VolumeMountPoint = 0; - ULONG VolumeNameSize, MountPointSize, VolumeMountPointSize; - NTSTATUS Result; - - VolumeNameSize = lstrlenW(VolumeName) * sizeof(WCHAR); - MountPointSize = lstrlenW(MountPoint) * sizeof(WCHAR); - VolumeMountPointSize = sizeof *VolumeMountPoint + - sizeof L"\\DosDevices\\" - sizeof(WCHAR) + MountPointSize + VolumeNameSize; - - VolumeMountPoint = MemAlloc(VolumeMountPointSize); - if (0 == VolumeMountPoint) - { - Result = STATUS_INSUFFICIENT_RESOURCES; - goto exit; - } - - /* notify volume mount point created/deleted */ - memset(VolumeMountPoint, 0, sizeof *VolumeMountPoint); - VolumeMountPoint->SourceVolumeNameOffset = sizeof *VolumeMountPoint; - VolumeMountPoint->SourceVolumeNameLength = (USHORT)( - sizeof L"\\DosDevices\\" - sizeof(WCHAR) + MountPointSize); - VolumeMountPoint->TargetVolumeNameOffset = - VolumeMountPoint->SourceVolumeNameOffset + VolumeMountPoint->SourceVolumeNameLength; - VolumeMountPoint->TargetVolumeNameLength = (USHORT)VolumeNameSize; - memcpy((PUINT8)VolumeMountPoint + VolumeMountPoint->SourceVolumeNameOffset, - L"\\DosDevices\\", sizeof L"\\DosDevices\\" - sizeof(WCHAR)); - memcpy((PUINT8)VolumeMountPoint + - VolumeMountPoint->SourceVolumeNameOffset + (sizeof L"\\DosDevices\\" - sizeof(WCHAR)), - MountPoint, MountPointSize); - memcpy((PUINT8)VolumeMountPoint + VolumeMountPoint->TargetVolumeNameOffset, - VolumeName, VolumeNameSize); - Result = FspMountmgrControl( - Created ? - CTL_CODE('m', 6, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) : - /* IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED */ - CTL_CODE('m', 7, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - /* IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED */ - VolumeMountPoint, VolumeMountPointSize, 0, 0); - if (!NT_SUCCESS(Result)) - goto exit; - - Result = STATUS_SUCCESS; - -exit: - MemFree(VolumeMountPoint); - - return Result; -} - -static VOID FspMountmgrDeleteRegistry(GUID *UniqueId) -{ - HKEY RegKey; - LONG RegResult; - WCHAR RegValueName[MAX_PATH]; - UINT8 RegValueData[sizeof *UniqueId]; - DWORD RegValueNameSize, RegValueDataSize; - DWORD RegType; - - /* HACK: delete the MountManager registry entries */ - RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\MountedDevices", - 0, KEY_READ | KEY_WRITE, &RegKey); - if (ERROR_SUCCESS == RegResult) - { - for (DWORD I = 0;; I++) - { - RegValueNameSize = MAX_PATH; - RegValueDataSize = sizeof RegValueData; - RegResult = RegEnumValueW(RegKey, - I, RegValueName, &RegValueNameSize, 0, &RegType, RegValueData, &RegValueDataSize); - if (ERROR_NO_MORE_ITEMS == RegResult) - break; - else if (ERROR_SUCCESS != RegResult) - continue; - - if (REG_BINARY == RegType && - sizeof RegValueData == RegValueDataSize && - InlineIsEqualGUID((GUID *)&RegValueData, UniqueId)) - { - RegResult = RegDeleteValueW(RegKey, RegValueName); - if (ERROR_SUCCESS == RegResult) - /* reset index after modifying key; only safe way to use RegEnumValueW with modifications */ - I = -1; - } - } - - RegCloseKey(RegKey); - } -} - -static NTSTATUS FspMountSet_MountmgrDrive(HANDLE VolumeHandle, PWSTR VolumeName, PWSTR MountPoint) -{ - /* mountmgr.h */ - typedef struct - { - USHORT SymbolicLinkNameOffset; - USHORT SymbolicLinkNameLength; - USHORT DeviceNameOffset; - USHORT DeviceNameLength; - } MOUNTMGR_CREATE_POINT_INPUT; - - GUID UniqueId; - MOUNTMGR_CREATE_POINT_INPUT *CreatePointInput = 0; - ULONG VolumeNameSize, CreatePointInputSize; - NTSTATUS Result; - - Result = FspMountmgrMakeMountdev(VolumeHandle, VolumeName, &UniqueId); - if (!NT_SUCCESS(Result)) - goto exit; - - VolumeNameSize = lstrlenW(VolumeName) * sizeof(WCHAR); - CreatePointInputSize = sizeof *CreatePointInput + - sizeof L"\\DosDevices\\X:" - sizeof(WCHAR) + VolumeNameSize; - - CreatePointInput = MemAlloc(CreatePointInputSize); - if (0 == CreatePointInput) - { - Result = STATUS_INSUFFICIENT_RESOURCES; - goto exit; - } - - /* create mount point */ - memset(CreatePointInput, 0, sizeof *CreatePointInput); - CreatePointInput->SymbolicLinkNameOffset = sizeof *CreatePointInput; - CreatePointInput->SymbolicLinkNameLength = sizeof L"\\DosDevices\\X:" - sizeof(WCHAR); - CreatePointInput->DeviceNameOffset = - CreatePointInput->SymbolicLinkNameOffset + CreatePointInput->SymbolicLinkNameLength; - CreatePointInput->DeviceNameLength = (USHORT)VolumeNameSize; - memcpy((PUINT8)CreatePointInput + CreatePointInput->SymbolicLinkNameOffset, - L"\\DosDevices\\X:", CreatePointInput->SymbolicLinkNameLength); - ((PWCHAR)((PUINT8)CreatePointInput + CreatePointInput->SymbolicLinkNameOffset))[12] = - MountPoint[4] & ~0x20; - /* convert to uppercase */ - memcpy((PUINT8)CreatePointInput + CreatePointInput->DeviceNameOffset, - VolumeName, CreatePointInput->DeviceNameLength); - Result = FspMountmgrControl( - CTL_CODE('m', 0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - /* IOCTL_MOUNTMGR_CREATE_POINT */ - CreatePointInput, CreatePointInputSize, 0, 0); - if (!NT_SUCCESS(Result)) - goto exit; - - FspMountmgrDeleteRegistry(&UniqueId); - - Result = STATUS_SUCCESS; - -exit: - MemFree(CreatePointInput); - - return Result; -} - static NTSTATUS FspMountSet_Directory(PWSTR VolumeName, PWSTR MountPoint, PSECURITY_DESCRIPTOR SecurityDescriptor, PHANDLE PMountHandle); static NTSTATUS FspMountRemove_Directory(HANDLE MountHandle); + +static NTSTATUS FspMountSet_MountmgrDrive(HANDLE VolumeHandle, PWSTR VolumeName, PWSTR MountPoint) +{ + if (FspMountUseMountmgrFromFSDValue) + /* use MountManager from FSD and exit */ + return FspFsctlUseMountmgr(VolumeHandle, MountPoint + 4); + + GUID UniqueId; + NTSTATUS Result; + + /* transform our volume into one that can be used by the MountManager */ + Result = FspFsctlMakeMountdev(VolumeHandle, FALSE, &UniqueId); + if (!NT_SUCCESS(Result)) + goto exit; + + /* use the MountManager to create the drive */ + UNICODE_STRING UVolumeName, UMountPoint; + UVolumeName.Length = UVolumeName.MaximumLength = (USHORT)(lstrlenW(VolumeName) * sizeof(WCHAR)); + UVolumeName.Buffer = VolumeName; + UMountPoint.Length = UMountPoint.MaximumLength = (USHORT)((lstrlenW(MountPoint) - 4) * sizeof(WCHAR)); + UMountPoint.Buffer = MountPoint + 4; + Result = FspMountmgrCreateDrive(&UVolumeName, &UniqueId, &UMountPoint); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = STATUS_SUCCESS; + +exit: + return Result; +} + static NTSTATUS FspMountSet_MountmgrDirectory(HANDLE VolumeHandle, PWSTR VolumeName, PWSTR MountPoint, PSECURITY_DESCRIPTOR SecurityDescriptor, PHANDLE PMountHandle) { @@ -384,20 +132,33 @@ static NTSTATUS FspMountSet_MountmgrDirectory(HANDLE VolumeHandle, PWSTR VolumeN *PMountHandle = 0; + /* create the directory mount point */ Result = FspMountSet_Directory(VolumeName, MountPoint + 4, SecurityDescriptor, &MountHandle); if (!NT_SUCCESS(Result)) goto exit; - Result = FspMountmgrMakeMountdev(VolumeHandle, VolumeName, &UniqueId); + if (FspMountUseMountmgrFromFSDValue) + { + /* use MountManager from FSD and exit */ + Result = FspFsctlUseMountmgr(VolumeHandle, MountPoint + 4); + goto exit; + } + + /* transform our volume into one that can be used by the MountManager */ + Result = FspFsctlMakeMountdev(VolumeHandle, FALSE, &UniqueId); if (!NT_SUCCESS(Result)) goto exit; - Result = FspMountmgrNotify(VolumeName, MountPoint + 4, TRUE); + /* notify the MountManager about the created directory mount point */ + UNICODE_STRING UVolumeName, UMountPoint; + UVolumeName.Length = UVolumeName.MaximumLength = (USHORT)(lstrlenW(VolumeName) * sizeof(WCHAR)); + UVolumeName.Buffer = VolumeName; + UMountPoint.Length = UMountPoint.MaximumLength = (USHORT)((lstrlenW(MountPoint) - 4) * sizeof(WCHAR)); + UMountPoint.Buffer = MountPoint + 4; + Result = FspMountmgrNotifyCreateDirectory(&UVolumeName, &UniqueId, &UMountPoint); if (!NT_SUCCESS(Result)) goto exit; - FspMountmgrDeleteRegistry(&UniqueId); - *PMountHandle = MountHandle; Result = STATUS_SUCCESS; @@ -409,79 +170,39 @@ exit: return Result; } -static NTSTATUS FspMountRemove_MountmgrDrive(PWSTR MountPoint) +static NTSTATUS FspMountRemove_MountmgrDrive(HANDLE VolumeHandle, PWSTR MountPoint) { - /* mountmgr.h */ - typedef struct - { - ULONG SymbolicLinkNameOffset; - USHORT SymbolicLinkNameLength; - USHORT Reserved1; - ULONG UniqueIdOffset; - USHORT UniqueIdLength; - USHORT Reserved2; - ULONG DeviceNameOffset; - USHORT DeviceNameLength; - USHORT Reserved3; - } MOUNTMGR_MOUNT_POINT; - typedef struct - { - ULONG Size; - ULONG NumberOfMountPoints; - MOUNTMGR_MOUNT_POINT MountPoints[1]; - } MOUNTMGR_MOUNT_POINTS; + if (FspMountUseMountmgrFromFSDValue) + /* use MountManager from FSD and exit */ + return FspFsctlUseMountmgr(VolumeHandle, 0); - MOUNTMGR_MOUNT_POINT *Input = 0; - MOUNTMGR_MOUNT_POINTS *Output = 0; - ULONG InputSize, OutputSize; - NTSTATUS Result; - - InputSize = sizeof *Input + sizeof L"\\DosDevices\\X:" - sizeof(WCHAR); - OutputSize = 4096; - - Input = MemAlloc(InputSize); - if (0 == Input) - { - Result = STATUS_INSUFFICIENT_RESOURCES; - goto exit; - } - - Output = MemAlloc(OutputSize); - if (0 == Output) - { - Result = STATUS_INSUFFICIENT_RESOURCES; - goto exit; - } - - memset(Input, 0, sizeof *Input); - Input->SymbolicLinkNameOffset = sizeof *Input; - Input->SymbolicLinkNameLength = sizeof L"\\DosDevices\\X:" - sizeof(WCHAR); - memcpy((PUINT8)Input + Input->SymbolicLinkNameOffset, - L"\\DosDevices\\X:", Input->SymbolicLinkNameLength); - ((PWCHAR)((PUINT8)Input + Input->SymbolicLinkNameOffset))[12] = MountPoint[4] & ~0x20; - /* convert to uppercase */ - Result = FspMountmgrControl( - CTL_CODE('m', 1, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), - /* IOCTL_MOUNTMGR_DELETE_POINTS */ - Input, InputSize, Output, &OutputSize); - if (!NT_SUCCESS(Result)) - goto exit; - - Result = STATUS_SUCCESS; - -exit: - MemFree(Output); - MemFree(Input); - - return Result; + /* use the MountManager to delete the drive */ + UNICODE_STRING UMountPoint; + UMountPoint.Length = UMountPoint.MaximumLength = (USHORT)((lstrlenW(MountPoint) - 4) * sizeof(WCHAR)); + UMountPoint.Buffer = MountPoint + 4; + return FspMountmgrDeleteDrive(&UMountPoint); } -static NTSTATUS FspMountRemove_MountmgrDirectory(PWSTR VolumeName, PWSTR MountPoint, HANDLE MountHandle) +static NTSTATUS FspMountRemove_MountmgrDirectory(HANDLE VolumeHandle, PWSTR VolumeName, PWSTR MountPoint, + HANDLE MountHandle) { NTSTATUS Result; - FspMountmgrNotify(VolumeName, MountPoint + 4, FALSE); + if (FspMountUseMountmgrFromFSDValue) + /* use MountManager from FSD, but do not exit; additional processing is required below */ + FspFsctlUseMountmgr(VolumeHandle, 0); + else + { + /* notify the MountManager about the deleted directory mount point */ + UNICODE_STRING UVolumeName, UMountPoint; + UVolumeName.Length = UVolumeName.MaximumLength = (USHORT)(lstrlenW(VolumeName) * sizeof(WCHAR)); + UVolumeName.Buffer = VolumeName; + UMountPoint.Length = UMountPoint.MaximumLength = (USHORT)((lstrlenW(MountPoint) - 4) * sizeof(WCHAR)); + UMountPoint.Buffer = MountPoint + 4; + FspMountmgrNotifyDeleteDirectory(&UVolumeName, &UMountPoint); + } + /* delete the directory mount point */ Result = FspMountRemove_Directory(MountHandle); if (!NT_SUCCESS(Result)) goto exit; @@ -889,9 +610,10 @@ FSP_API NTSTATUS FspMountRemove(FSP_MOUNT_DESC *Desc) InitOnceExecuteOnce(&FspMountInitOnce, FspMountInitialize, 0, 0); if (FspPathIsMountmgrDrive(Desc->MountPoint)) - return FspMountRemove_MountmgrDrive(Desc->MountPoint); + return FspMountRemove_MountmgrDrive(Desc->VolumeHandle, Desc->MountPoint); else if (FspPathIsMountmgrMountPoint(Desc->MountPoint)) - return FspMountRemove_MountmgrDirectory(Desc->VolumeName, Desc->MountPoint, Desc->MountHandle); + return FspMountRemove_MountmgrDirectory(Desc->VolumeHandle, Desc->VolumeName, Desc->MountPoint, + Desc->MountHandle); else if (FspPathIsDrive(Desc->MountPoint)) return FspMountRemove_Drive(Desc->VolumeName, Desc->MountPoint, Desc->MountHandle); else diff --git a/src/shared/ku/mountmgr.c b/src/shared/ku/mountmgr.c new file mode 100644 index 00000000..3437cc5f --- /dev/null +++ b/src/shared/ku/mountmgr.c @@ -0,0 +1,599 @@ +/** + * @file shared/ku/mountmgr.c + * + * @copyright 2015-2022 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this software + * in accordance with the commercial license agreement provided in + * conjunction with the software. The terms and conditions of any such + * commercial license agreement shall govern, supersede, and render + * ineffective any application of the GPLv3 license to this software, + * notwithstanding of any reference thereto in the software or + * associated repository. + */ + +#include + +#pragma warning(push) +#pragma warning(disable:4459) /* declaration of 'identifier' hides global declaration */ + +static NTSTATUS FspMountmgrControl(ULONG IoControlCode, + PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, PULONG POutputBufferLength); +static NTSTATUS FspMountmgrNotifyVolumeArrival( + PUNICODE_STRING VolumeName, GUID *UniqueId); +static NTSTATUS FspMountmgrNotifyMountPoint( + PUNICODE_STRING VolumeName, PUNICODE_STRING MountPoint, BOOLEAN Created); +static NTSTATUS FspMountmgrCreateMountPoint( + PUNICODE_STRING VolumeName, PUNICODE_STRING MountPoint); +static NTSTATUS FspMountmgrDeleteMountPoint( + PUNICODE_STRING MountPoint); +static VOID FspMountmgrDeleteRegistry( + GUID *UniqueId); +NTSTATUS FspMountmgrCreateDrive( + PUNICODE_STRING VolumeName, GUID *UniqueId, PUNICODE_STRING MountPoint); +NTSTATUS FspMountmgrDeleteDrive( + PUNICODE_STRING MountPoint); +NTSTATUS FspMountmgrNotifyCreateDirectory( + PUNICODE_STRING VolumeName, GUID *UniqueId, PUNICODE_STRING MountPoint); +NTSTATUS FspMountmgrNotifyDeleteDirectory( + PUNICODE_STRING VolumeName, PUNICODE_STRING MountPoint); + +#if defined(_KERNEL_MODE) +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FspMountmgrControl) +#pragma alloc_text(PAGE, FspMountmgrNotifyVolumeArrival) +#pragma alloc_text(PAGE, FspMountmgrNotifyMountPoint) +#pragma alloc_text(PAGE, FspMountmgrCreateMountPoint) +#pragma alloc_text(PAGE, FspMountmgrDeleteMountPoint) +#pragma alloc_text(PAGE, FspMountmgrCreateDrive) +#pragma alloc_text(PAGE, FspMountmgrDeleteDrive) +#pragma alloc_text(PAGE, FspMountmgrNotifyCreateDirectory) +#pragma alloc_text(PAGE, FspMountmgrNotifyDeleteDirectory) +#endif +#endif + +static NTSTATUS FspMountmgrControl(ULONG IoControlCode, + PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, PULONG POutputBufferLength) +{ +#if defined(_KERNEL_MODE) + FSP_KU_CODE; + + UNICODE_STRING DeviceName; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatus; + HANDLE MgrHandle = 0; + ULONG Bytes = 0; + + if (0 == POutputBufferLength) + POutputBufferLength = &Bytes; + + RtlInitUnicodeString(&DeviceName, L"\\Device\\MountPointManager"); + InitializeObjectAttributes( + &ObjectAttributes, + &DeviceName, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + 0/*RootDirectory*/, + 0); + + IoStatus.Status = ZwOpenFile( + &MgrHandle, + GENERIC_READ | GENERIC_WRITE, + &ObjectAttributes, + &IoStatus, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_ALERT); + if (!NT_SUCCESS(IoStatus.Status)) + goto exit; + + IoStatus.Status = ZwDeviceIoControlFile( + MgrHandle, + 0, 0, 0, + &IoStatus, + IoControlCode, + InputBuffer, InputBufferLength, OutputBuffer, *POutputBufferLength); + if (!NT_SUCCESS(IoStatus.Status)) + goto exit; + + *POutputBufferLength = (ULONG)IoStatus.Information; + IoStatus.Status = STATUS_SUCCESS; + +exit: + if (0 != MgrHandle) + ZwClose(MgrHandle); + + return IoStatus.Status; +#else + HANDLE MgrHandle = INVALID_HANDLE_VALUE; + DWORD Bytes = 0; + NTSTATUS Result; + + if (0 == POutputBufferLength) + POutputBufferLength = &Bytes; + + MgrHandle = CreateFileW(L"\\\\.\\MountPointManager", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + 0, + 0); + if (INVALID_HANDLE_VALUE == MgrHandle) + { + Result = FspNtStatusFromWin32(GetLastError()); + goto exit; + } + + if (!DeviceIoControl(MgrHandle, + IoControlCode, + InputBuffer, InputBufferLength, OutputBuffer, *POutputBufferLength, + &Bytes, 0)) + { + Result = FspNtStatusFromWin32(GetLastError()); + goto exit; + } + + *POutputBufferLength = Bytes; + Result = STATUS_SUCCESS; + +exit: + if (INVALID_HANDLE_VALUE != MgrHandle) + CloseHandle(MgrHandle); + + return Result; +#endif +} + +static NTSTATUS FspMountmgrNotifyVolumeArrival( + PUNICODE_STRING VolumeName, GUID *UniqueId) +{ + FSP_KU_CODE; + + /* mountmgr.h */ + typedef enum + { + Disabled = 0, + Enabled, + } MOUNTMGR_AUTO_MOUNT_STATE; + typedef struct + { + MOUNTMGR_AUTO_MOUNT_STATE CurrentState; + } MOUNTMGR_QUERY_AUTO_MOUNT; + typedef struct + { + MOUNTMGR_AUTO_MOUNT_STATE NewState; + } MOUNTMGR_SET_AUTO_MOUNT; + typedef struct + { + USHORT DeviceNameLength; + WCHAR DeviceName[1]; + } MOUNTMGR_TARGET_NAME; + + MOUNTMGR_QUERY_AUTO_MOUNT QueryAutoMount; + MOUNTMGR_SET_AUTO_MOUNT SetAutoMount; + MOUNTMGR_TARGET_NAME *TargetName = 0; + ULONG QueryAutoMountSize, TargetNameSize; + NTSTATUS Result; + + QueryAutoMountSize = sizeof QueryAutoMount; + TargetNameSize = FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + VolumeName->Length; + + TargetName = MemAlloc(TargetNameSize); + if (0 == TargetName) + { + Result = STATUS_INSUFFICIENT_RESOURCES; + goto exit; + } + + /* query the current AutoMount value and save it */ + Result = FspMountmgrControl( + CTL_CODE('m', 15, METHOD_BUFFERED, FILE_ANY_ACCESS), + /* IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT */ + 0, 0, &QueryAutoMount, &QueryAutoMountSize); + if (!NT_SUCCESS(Result)) + goto exit; + + /* disable AutoMount */ + SetAutoMount.NewState = 0; + Result = FspMountmgrControl( + CTL_CODE('m', 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + /* IOCTL_MOUNTMGR_SET_AUTO_MOUNT */ + &SetAutoMount, sizeof SetAutoMount, 0, 0); + if (!NT_SUCCESS(Result)) + goto exit; + + /* announce volume arrival */ + memset(TargetName, 0, sizeof *TargetName); + TargetName->DeviceNameLength = VolumeName->Length; + memcpy(TargetName->DeviceName, VolumeName->Buffer, VolumeName->Length); + Result = FspMountmgrControl( + CTL_CODE('m', 11, METHOD_BUFFERED, FILE_READ_ACCESS), + /* IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION */ + TargetName, TargetNameSize, 0, 0); + if (!NT_SUCCESS(Result)) + goto exit; + + /* reset the AutoMount value to the saved one */ + SetAutoMount.NewState = QueryAutoMount.CurrentState; + FspMountmgrControl( + CTL_CODE('m', 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + /* IOCTL_MOUNTMGR_SET_AUTO_MOUNT */ + &SetAutoMount, sizeof SetAutoMount, 0, 0); + + Result = STATUS_SUCCESS; + +exit: + MemFree(TargetName); + + return Result; +} + +static NTSTATUS FspMountmgrNotifyMountPoint( + PUNICODE_STRING VolumeName, PUNICODE_STRING MountPoint, BOOLEAN Created) +{ + FSP_KU_CODE; + + /* mountmgr.h */ + typedef struct + { + USHORT SourceVolumeNameOffset; + USHORT SourceVolumeNameLength; + USHORT TargetVolumeNameOffset; + USHORT TargetVolumeNameLength; + } MOUNTMGR_VOLUME_MOUNT_POINT; + + MOUNTMGR_VOLUME_MOUNT_POINT *VolumeMountPoint = 0; + ULONG VolumeMountPointSize; + NTSTATUS Result; + + VolumeMountPointSize = sizeof *VolumeMountPoint + + sizeof L"\\DosDevices\\" - sizeof(WCHAR) + MountPoint->Length + VolumeName->Length; + + VolumeMountPoint = MemAlloc(VolumeMountPointSize); + if (0 == VolumeMountPoint) + { + Result = STATUS_INSUFFICIENT_RESOURCES; + goto exit; + } + + /* notify volume mount point created/deleted */ + memset(VolumeMountPoint, 0, sizeof *VolumeMountPoint); + VolumeMountPoint->SourceVolumeNameOffset = sizeof *VolumeMountPoint; + VolumeMountPoint->SourceVolumeNameLength = (USHORT)( + sizeof L"\\DosDevices\\" - sizeof(WCHAR) + MountPoint->Length); + VolumeMountPoint->TargetVolumeNameOffset = + VolumeMountPoint->SourceVolumeNameOffset + VolumeMountPoint->SourceVolumeNameLength; + VolumeMountPoint->TargetVolumeNameLength = VolumeName->Length; + memcpy((PUINT8)VolumeMountPoint + VolumeMountPoint->SourceVolumeNameOffset, + L"\\DosDevices\\", sizeof L"\\DosDevices\\" - sizeof(WCHAR)); + memcpy((PUINT8)VolumeMountPoint + + VolumeMountPoint->SourceVolumeNameOffset + (sizeof L"\\DosDevices\\" - sizeof(WCHAR)), + MountPoint->Buffer, MountPoint->Length); + memcpy((PUINT8)VolumeMountPoint + VolumeMountPoint->TargetVolumeNameOffset, + VolumeName->Buffer, VolumeName->Length); + Result = FspMountmgrControl( + Created ? + CTL_CODE('m', 6, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) : + /* IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED */ + CTL_CODE('m', 7, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + /* IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED */ + VolumeMountPoint, VolumeMountPointSize, 0, 0); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = STATUS_SUCCESS; + +exit: + MemFree(VolumeMountPoint); + + return Result; +} + +static NTSTATUS FspMountmgrCreateMountPoint( + PUNICODE_STRING VolumeName, PUNICODE_STRING MountPoint) +{ + FSP_KU_CODE; + + /* mountmgr.h */ + typedef struct + { + USHORT SymbolicLinkNameOffset; + USHORT SymbolicLinkNameLength; + USHORT DeviceNameOffset; + USHORT DeviceNameLength; + } MOUNTMGR_CREATE_POINT_INPUT; + + MOUNTMGR_CREATE_POINT_INPUT *CreatePointInput = 0; + ULONG CreatePointInputSize; + NTSTATUS Result; + + CreatePointInputSize = sizeof *CreatePointInput + + sizeof L"\\DosDevices\\X:" - sizeof(WCHAR) + VolumeName->Length; + + CreatePointInput = MemAlloc(CreatePointInputSize); + if (0 == CreatePointInput) + { + Result = STATUS_INSUFFICIENT_RESOURCES; + goto exit; + } + + /* create mount point */ + memset(CreatePointInput, 0, sizeof *CreatePointInput); + CreatePointInput->SymbolicLinkNameOffset = sizeof *CreatePointInput; + CreatePointInput->SymbolicLinkNameLength = sizeof L"\\DosDevices\\X:" - sizeof(WCHAR); + CreatePointInput->DeviceNameOffset = + CreatePointInput->SymbolicLinkNameOffset + CreatePointInput->SymbolicLinkNameLength; + CreatePointInput->DeviceNameLength = VolumeName->Length; + memcpy((PUINT8)CreatePointInput + CreatePointInput->SymbolicLinkNameOffset, + L"\\DosDevices\\X:", CreatePointInput->SymbolicLinkNameLength); + ((PWCHAR)((PUINT8)CreatePointInput + CreatePointInput->SymbolicLinkNameOffset))[12] = + MountPoint->Buffer[0] & ~0x20; + /* convert to uppercase */ + memcpy((PUINT8)CreatePointInput + CreatePointInput->DeviceNameOffset, + VolumeName->Buffer, VolumeName->Length); + Result = FspMountmgrControl( + CTL_CODE('m', 0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + /* IOCTL_MOUNTMGR_CREATE_POINT */ + CreatePointInput, CreatePointInputSize, 0, 0); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = STATUS_SUCCESS; + +exit: + MemFree(CreatePointInput); + + return Result; +} + +static NTSTATUS FspMountmgrDeleteMountPoint( + PUNICODE_STRING MountPoint) +{ + FSP_KU_CODE; + + /* mountmgr.h */ + typedef struct + { + ULONG SymbolicLinkNameOffset; + USHORT SymbolicLinkNameLength; + USHORT Reserved1; + ULONG UniqueIdOffset; + USHORT UniqueIdLength; + USHORT Reserved2; + ULONG DeviceNameOffset; + USHORT DeviceNameLength; + USHORT Reserved3; + } MOUNTMGR_MOUNT_POINT; + typedef struct + { + ULONG Size; + ULONG NumberOfMountPoints; + MOUNTMGR_MOUNT_POINT MountPoints[1]; + } MOUNTMGR_MOUNT_POINTS; + + MOUNTMGR_MOUNT_POINT *Input = 0; + MOUNTMGR_MOUNT_POINTS *Output = 0; + ULONG InputSize, OutputSize; + NTSTATUS Result; + + InputSize = sizeof *Input + sizeof L"\\DosDevices\\X:" - sizeof(WCHAR); + OutputSize = 4096; + + Input = MemAlloc(InputSize); + if (0 == Input) + { + Result = STATUS_INSUFFICIENT_RESOURCES; + goto exit; + } + + Output = MemAlloc(OutputSize); + if (0 == Output) + { + Result = STATUS_INSUFFICIENT_RESOURCES; + goto exit; + } + + /* delete mount point */ + memset(Input, 0, sizeof *Input); + Input->SymbolicLinkNameOffset = sizeof *Input; + Input->SymbolicLinkNameLength = sizeof L"\\DosDevices\\X:" - sizeof(WCHAR); + memcpy((PUINT8)Input + Input->SymbolicLinkNameOffset, + L"\\DosDevices\\X:", Input->SymbolicLinkNameLength); + ((PWCHAR)((PUINT8)Input + Input->SymbolicLinkNameOffset))[12] = + MountPoint->Buffer[0] & ~0x20; + /* convert to uppercase */ + Result = FspMountmgrControl( + CTL_CODE('m', 1, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), + /* IOCTL_MOUNTMGR_DELETE_POINTS */ + Input, InputSize, Output, &OutputSize); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = STATUS_SUCCESS; + +exit: + MemFree(Output); + MemFree(Input); + + return Result; +} + +static VOID FspMountmgrDeleteRegistry(GUID *UniqueId) +{ +#if defined(_KERNEL_MODE) + FSP_KU_CODE; + + UNICODE_STRING Path; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE Handle = 0; + union + { + KEY_VALUE_FULL_INFORMATION V; + UINT8 B[FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) + 255 + sizeof *UniqueId]; + } FullInformation; + ULONG FullInformationLength; + UNICODE_STRING ValueName; + NTSTATUS Result; + + RtlInitUnicodeString(&Path, L"\\Registry\\Machine\\System\\MountedDevices"); + InitializeObjectAttributes( + &ObjectAttributes, + &Path, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + 0/*RootDirectory*/, + 0); + + Result = ZwOpenKey(&Handle, KEY_QUERY_VALUE, &ObjectAttributes); + if (NT_SUCCESS(Result)) + { + for (ULONG I = 0;; I++) + { + Result = ZwEnumerateValueKey(Handle, + I, KeyValueFullInformation, &FullInformation, + sizeof FullInformation, &FullInformationLength); + if (STATUS_NO_MORE_ENTRIES == Result) + break; + else if (!NT_SUCCESS(Result)) + continue; + + if (REG_BINARY == FullInformation.V.Type && + sizeof *UniqueId == FullInformation.V.DataLength && + InlineIsEqualGUID((GUID *)((PUINT8)&FullInformation.V + FullInformation.V.DataOffset), + UniqueId)) + { + ValueName.Length = ValueName.MaximumLength = (USHORT)FullInformation.V.NameLength; + ValueName.Buffer = FullInformation.V.Name; + Result = ZwDeleteValueKey(Handle, &ValueName); + if (NT_SUCCESS(Result)) + /* reset index after modifying key; only safe way to use RegEnumValueW with modifications */ + I = (ULONG)-1; + } + } + + ZwClose(Handle); + } +#else + HKEY RegKey; + LONG RegResult; + WCHAR RegValueName[MAX_PATH]; + UINT8 RegValueData[sizeof *UniqueId]; + DWORD RegValueNameSize, RegValueDataSize; + DWORD RegType; + + RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\MountedDevices", + 0, KEY_READ | KEY_WRITE, &RegKey); + if (ERROR_SUCCESS == RegResult) + { + for (DWORD I = 0;; I++) + { + RegValueNameSize = MAX_PATH; + RegValueDataSize = sizeof RegValueData; + RegResult = RegEnumValueW(RegKey, + I, RegValueName, &RegValueNameSize, 0, &RegType, RegValueData, &RegValueDataSize); + if (ERROR_NO_MORE_ITEMS == RegResult) + break; + else if (ERROR_SUCCESS != RegResult) + continue; + + if (REG_BINARY == RegType && + sizeof RegValueData == RegValueDataSize && + InlineIsEqualGUID((GUID *)&RegValueData, UniqueId)) + { + RegResult = RegDeleteValueW(RegKey, RegValueName); + if (ERROR_SUCCESS == RegResult) + /* reset index after modifying key; only safe way to use RegEnumValueW with modifications */ + I = -1; + } + } + + RegCloseKey(RegKey); + } +#endif +} + +NTSTATUS FspMountmgrCreateDrive( + PUNICODE_STRING VolumeName, GUID *UniqueId, PUNICODE_STRING MountPoint) +{ + FSP_KU_CODE; + + NTSTATUS Result; + + /* notify the MountManager about the new volume */ + Result = FspMountmgrNotifyVolumeArrival(VolumeName, UniqueId); + if (!NT_SUCCESS(Result)) + goto exit; + + /* use the MountManager to create the drive */ + Result = FspMountmgrCreateMountPoint(VolumeName, MountPoint); + if (!NT_SUCCESS(Result)) + goto exit; + + /* HACK: delete the MountManager registry entries */ + FspMountmgrDeleteRegistry(UniqueId); + + Result = STATUS_SUCCESS; + +exit: + return Result; +} + +NTSTATUS FspMountmgrDeleteDrive( + PUNICODE_STRING MountPoint) +{ + FSP_KU_CODE; + + NTSTATUS Result; + + /* use the MountManager to delete the drive */ + Result = FspMountmgrDeleteMountPoint(MountPoint); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = STATUS_SUCCESS; + +exit: + return Result; +} + +NTSTATUS FspMountmgrNotifyCreateDirectory( + PUNICODE_STRING VolumeName, GUID *UniqueId, PUNICODE_STRING MountPoint) +{ + FSP_KU_CODE; + + NTSTATUS Result; + + /* notify the MountManager about the new volume */ + Result = FspMountmgrNotifyVolumeArrival(VolumeName, UniqueId); + if (!NT_SUCCESS(Result)) + goto exit; + + /* notify the MountManager about the created directory mount point */ + Result = FspMountmgrNotifyMountPoint(VolumeName, MountPoint, TRUE); + if (!NT_SUCCESS(Result)) + goto exit; + + /* HACK: delete the MountManager registry entries */ + FspMountmgrDeleteRegistry(UniqueId); + + Result = STATUS_SUCCESS; + +exit: + return Result; +} + +NTSTATUS FspMountmgrNotifyDeleteDirectory( + PUNICODE_STRING VolumeName, PUNICODE_STRING MountPoint) +{ + FSP_KU_CODE; + + /* notify the MountManager about the deleted directory mount point */ + return FspMountmgrNotifyMountPoint(VolumeName, MountPoint, FALSE); +} + +#pragma warning(pop) diff --git a/src/sys/device.c b/src/sys/device.c index 15cb89a3..9f0c5138 100644 --- a/src/sys/device.c +++ b/src/sys/device.c @@ -59,6 +59,8 @@ VOID FspFsvolDeviceGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_I BOOLEAN FspFsvolDeviceTryGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo); VOID FspFsvolDeviceSetVolumeInfo(PDEVICE_OBJECT DeviceObject, const FSP_FSCTL_VOLUME_INFO *VolumeInfo); VOID FspFsvolDeviceInvalidateVolumeInfo(PDEVICE_OBJECT DeviceObject); +static NTSTATUS FspFsvrtDeviceInit(PDEVICE_OBJECT DeviceObject); +static VOID FspFsvrtDeviceFini(PDEVICE_OBJECT DeviceObject); static NTSTATUS FspFsmupDeviceInit(PDEVICE_OBJECT DeviceObject); static VOID FspFsmupDeviceFini(PDEVICE_OBJECT DeviceObject); NTSTATUS FspDeviceCopyList( @@ -84,6 +86,8 @@ VOID FspDeviceDeleteAll(VOID); #pragma alloc_text(PAGE, FspFsvolDeviceCompareContextByName) #pragma alloc_text(PAGE, FspFsvolDeviceAllocateContextByName) #pragma alloc_text(PAGE, FspFsvolDeviceFreeContextByName) +#pragma alloc_text(PAGE, FspFsvrtDeviceInit) +#pragma alloc_text(PAGE, FspFsvrtDeviceFini) #pragma alloc_text(PAGE, FspFsmupDeviceInit) #pragma alloc_text(PAGE, FspFsmupDeviceFini) #pragma alloc_text(PAGE, FspDeviceCopyList) @@ -171,7 +175,7 @@ NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject) Result = FspFsvolDeviceInit(DeviceObject); break; case FspFsvrtDeviceExtensionKind: - Result = STATUS_SUCCESS; + Result = FspFsvrtDeviceInit(DeviceObject); break; case FspFsmupDeviceExtensionKind: Result = FspFsmupDeviceInit(DeviceObject); @@ -202,6 +206,7 @@ VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject) FspFsvolDeviceFini(DeviceObject); break; case FspFsvrtDeviceExtensionKind: + FspFsvrtDeviceFini(DeviceObject); break; case FspFsmupDeviceExtensionKind: FspFsmupDeviceFini(DeviceObject); @@ -848,6 +853,27 @@ VOID FspFsvolDeviceInvalidateVolumeInfo(PDEVICE_OBJECT DeviceObject) KeReleaseSpinLock(&FsvolDeviceExtension->InfoSpinLock, Irql); } +static NTSTATUS FspFsvrtDeviceInit(PDEVICE_OBJECT DeviceObject) +{ + PAGED_CODE(); + + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject); + + ExInitializeFastMutex(&FsvrtDeviceExtension->MountMutex); + + return STATUS_SUCCESS; +} + +static VOID FspFsvrtDeviceFini(PDEVICE_OBJECT DeviceObject) +{ + PAGED_CODE(); + + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject); + + if (0 != FsvrtDeviceExtension->MountPoint.Buffer) + FspFree(FsvrtDeviceExtension->MountPoint.Buffer); +} + static NTSTATUS FspFsmupDeviceInit(PDEVICE_OBJECT DeviceObject) { PAGED_CODE(); diff --git a/src/sys/driver.h b/src/sys/driver.h index 19701468..c0e56e26 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -1232,13 +1232,18 @@ typedef struct } FSP_FSVOL_DEVICE_EXTENSION; typedef struct { + /* read-only after creation (and insertion in the ContextTable) */ FSP_DEVICE_EXTENSION Base; UINT16 SectorSize; - LONG IsMountdev; - BOOLEAN Persistent; - GUID UniqueId; UNICODE_STRING VolumeName; WCHAR VolumeNameBuf[FSP_FSCTL_VOLUME_NAME_SIZE / sizeof(WCHAR)]; + FAST_MUTEX MountMutex; + /* interlocked access */ + LONG IsMountdev; + /* protected under MountMutex */ + BOOLEAN Persistent; + GUID UniqueId; + UNICODE_STRING MountPoint; } FSP_FSVRT_DEVICE_EXTENSION; typedef struct { @@ -1435,6 +1440,18 @@ BOOLEAN FspFsvolDeviceVolumePrefixInString(PDEVICE_OBJECT DeviceObject, PUNICODE TRUE); } static inline +VOID FspFsvrtDeviceLockMount(PDEVICE_OBJECT DeviceObject) +{ + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject); + ExAcquireFastMutexUnsafe(&FsvrtDeviceExtension->MountMutex); +} +static inline +VOID FspFsvrtDeviceUnlockMount(PDEVICE_OBJECT DeviceObject) +{ + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject); + ExReleaseFastMutexUnsafe(&FsvrtDeviceExtension->MountMutex); +} +static inline VOID FspFsmupDeviceLockPrefixTable(PDEVICE_OBJECT DeviceObject) { FSP_FSMUP_DEVICE_EXTENSION *FsmupDeviceExtension = FspFsmupDeviceExtension(DeviceObject); @@ -1524,6 +1541,16 @@ NTSTATUS FspMountdevMake( VOID FspMountdevFini( PDEVICE_OBJECT FsvrtDeviceObject); +/* mountmgr */ +NTSTATUS FspMountmgrCreateDrive( + PUNICODE_STRING VolumeName, GUID *UniqueId, PUNICODE_STRING MountPoint); +NTSTATUS FspMountmgrDeleteDrive( + PUNICODE_STRING MountPoint); +NTSTATUS FspMountmgrNotifyCreateDirectory( + PUNICODE_STRING VolumeName, GUID *UniqueId, PUNICODE_STRING MountPoint); +NTSTATUS FspMountmgrNotifyDeleteDirectory( + PUNICODE_STRING VolumeName, PUNICODE_STRING MountPoint); + /* fsmup */ NTSTATUS FspMupRegister( PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject); @@ -1543,6 +1570,8 @@ NTSTATUS FspVolumeMount( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeMakeMountdev( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +NTSTATUS FspVolumeUseMountmgr( + PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeGetName( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeGetNameList( diff --git a/src/sys/fsctl.c b/src/sys/fsctl.c index fcef99fc..cc526512 100644 --- a/src/sys/fsctl.c +++ b/src/sys/fsctl.c @@ -81,6 +81,10 @@ static NTSTATUS FspFsctlFileSystemControl( if (0 != IrpSp->FileObject->FsContext2) Result = FspVolumeMakeMountdev(FsctlDeviceObject, Irp, IrpSp); break; + case FSP_FSCTL_MOUNTMGR: + if (0 != IrpSp->FileObject->FsContext2) + Result = FspVolumeUseMountmgr(FsctlDeviceObject, Irp, IrpSp); + break; case FSP_FSCTL_VOLUME_NAME: if (0 != IrpSp->FileObject->FsContext2) Result = FspVolumeGetName(FsctlDeviceObject, Irp, IrpSp); diff --git a/src/sys/mountdev.c b/src/sys/mountdev.c index 4db3feb2..50fb967c 100644 --- a/src/sys/mountdev.c +++ b/src/sys/mountdev.c @@ -138,7 +138,7 @@ NTSTATUS FspMountdevMake( * be mounted using the MountManager. * * This function requires protection against concurrency. In general this - * is achieved by acquiring the GlobalDeviceLock. + * is achieved by the caller acquiring the MountMutex. */ PAGED_CODE(); @@ -178,11 +178,6 @@ NTSTATUS FspMountdevMake( /* initialize the fsvrt device extension */ RtlCopyMemory(&FsvrtDeviceExtension->UniqueId, &Guid, sizeof Guid); - RtlInitEmptyUnicodeString(&FsvrtDeviceExtension->VolumeName, - FsvrtDeviceExtension->VolumeNameBuf, sizeof FsvrtDeviceExtension->VolumeNameBuf); - RtlCopyUnicodeString(&FsvrtDeviceExtension->VolumeName, &FsvolDeviceExtension->VolumeName); - - /* mark the fsvrt device as initialized */ InterlockedIncrement(&FspFsvrtDeviceExtension(FsvrtDeviceObject)->IsMountdev); Result = STATUS_SUCCESS; diff --git a/src/sys/volume.c b/src/sys/volume.c index de0f8668..f5a177fb 100644 --- a/src/sys/volume.c +++ b/src/sys/volume.c @@ -38,6 +38,8 @@ static NTSTATUS FspVolumeMountNoLock( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeMakeMountdev( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +NTSTATUS FspVolumeUseMountmgr( + PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeGetName( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeGetNameList( @@ -76,6 +78,7 @@ NTSTATUS FspVolumeWork( // ! #pragma alloc_text(PAGE, FspVolumeMount) // ! #pragma alloc_text(PAGE, FspVolumeMountNoLock) #pragma alloc_text(PAGE, FspVolumeMakeMountdev) +#pragma alloc_text(PAGE, FspVolumeUseMountmgr) #pragma alloc_text(PAGE, FspVolumeGetName) #pragma alloc_text(PAGE, FspVolumeGetNameList) #pragma alloc_text(PAGE, FspVolumeGetNameListNoLock) @@ -316,8 +319,12 @@ static NTSTATUS FspVolumeCreateNoLock( { if (0 != FsvrtDeviceObject) { - FspFsvrtDeviceExtension(FsvrtDeviceObject)->SectorSize = - FsvolDeviceExtension->VolumeParams.SectorSize; + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); + FsvrtDeviceExtension->SectorSize = FsvolDeviceExtension->VolumeParams.SectorSize; + RtlInitEmptyUnicodeString(&FsvrtDeviceExtension->VolumeName, + FsvrtDeviceExtension->VolumeNameBuf, sizeof FsvrtDeviceExtension->VolumeNameBuf); + RtlCopyUnicodeString(&FsvrtDeviceExtension->VolumeName, &FsvolDeviceExtension->VolumeName); + Result = FspDeviceInitialize(FsvrtDeviceObject); } } @@ -638,7 +645,7 @@ NTSTATUS FspVolumeMakeMountdev( if (sizeof(GUID) > OutputBufferLength) return STATUS_INVALID_PARAMETER; - FspDeviceGlobalLock(); + FspFsvrtDeviceLockMount(FsvrtDeviceObject); Result = FspMountdevMake(FsvrtDeviceObject, FsvolDeviceObject, Persistent); if (!NT_SUCCESS(Result)) @@ -654,7 +661,147 @@ NTSTATUS FspVolumeMakeMountdev( Result = STATUS_SUCCESS; exit: - FspDeviceGlobalUnlock(); + FspFsvrtDeviceUnlockMount(FsvrtDeviceObject); + + return Result; +} + +NTSTATUS FspVolumeUseMountmgr( + PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + ASSERT(IRP_MJ_FILE_SYSTEM_CONTROL == IrpSp->MajorFunction); + ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction); + ASSERT(FSP_FSCTL_MOUNTMGR == IrpSp->Parameters.FileSystemControl.FsControlCode); + ASSERT(0 != IrpSp->FileObject->FsContext2); + + PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; + ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; + NTSTATUS Result; + + if (0 == FsvrtDeviceObject) + return STATUS_INVALID_PARAMETER; /* cannot only use fsvrt with mount manager */ + if (1024 * sizeof(WCHAR) < InputBufferLength) + return STATUS_INVALID_PARAMETER; /* disallow very long paths */ + + FspFsvrtDeviceLockMount(FsvrtDeviceObject); + + if (0 < InputBufferLength) + { + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); + PWCHAR MountPointBuf = Irp->AssociatedIrp.SystemBuffer; + UNICODE_STRING RegPath; + UNICODE_STRING RegName; + union + { + KEY_VALUE_PARTIAL_INFORMATION V; + UINT8 B[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(ULONG)]; + } RegValue; + ULONG RegLength; + BOOLEAN Persistent = FALSE; + + if (!( + 2 * sizeof(WCHAR) <= InputBufferLength && + ( + (L'A' <= MountPointBuf[0] && MountPointBuf[0] <= L'Z') || + (L'a' <= MountPointBuf[0] && MountPointBuf[0] <= L'z') + ) && + L':' == MountPointBuf[1] + )) + { + Result = STATUS_INVALID_PARAMETER; + goto exit; + } + + if (0 != FsvrtDeviceExtension->MountPoint.Buffer) + { + Result = STATUS_INVALID_PARAMETER; + goto exit; + } + + RtlInitUnicodeString(&RegPath, L"" FSP_REGKEY); + RtlInitUnicodeString(&RegName, L"MountUseMountmgrFromFSD"); + RegLength = sizeof RegValue; + Result = FspRegistryGetValue(&RegPath, &RegName, &RegValue.V, &RegLength); + if (!NT_SUCCESS(Result) || REG_DWORD != RegValue.V.Type || 1 != *(PULONG)&RegValue.V.Data) + { + Result = STATUS_ACCESS_DENIED; + goto exit; + } + + Result = FspMountdevMake(FsvrtDeviceObject, FsvolDeviceObject, Persistent); + if (!NT_SUCCESS(Result)) + { + if (STATUS_TOO_LATE != Result) + goto exit; + } + + FsvrtDeviceExtension->MountPoint.Buffer = FspAllocNonPaged(InputBufferLength); + if (0 == FsvrtDeviceExtension->MountPoint.Buffer) + { + Result = STATUS_INSUFFICIENT_RESOURCES; + goto exit; + } + FsvrtDeviceExtension->MountPoint.Length = + FsvrtDeviceExtension->MountPoint.MaximumLength = (USHORT)InputBufferLength; + RtlCopyMemory(FsvrtDeviceExtension->MountPoint.Buffer, MountPointBuf, InputBufferLength); + + if (2 * sizeof(WCHAR) == FsvrtDeviceExtension->MountPoint.Length) + Result = FspMountmgrCreateDrive( + &FsvrtDeviceExtension->VolumeName, + &FsvrtDeviceExtension->UniqueId, + &FsvrtDeviceExtension->MountPoint); + else + Result = FspMountmgrNotifyCreateDirectory( + &FsvrtDeviceExtension->VolumeName, + &FsvrtDeviceExtension->UniqueId, + &FsvrtDeviceExtension->MountPoint); + if (!NT_SUCCESS(Result)) + { + FspFree(FsvrtDeviceExtension->MountPoint.Buffer); + FsvrtDeviceExtension->MountPoint.Buffer = 0; + FsvrtDeviceExtension->MountPoint.Length = + FsvrtDeviceExtension->MountPoint.MaximumLength = 0; + goto exit; + } + + Irp->IoStatus.Information = 0; + Result = STATUS_SUCCESS; + + } + else + { + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); + + if (0 == FsvrtDeviceExtension->MountPoint.Buffer) + { + Result = STATUS_INVALID_PARAMETER; + goto exit; + } + + if (2 * sizeof(WCHAR) == FsvrtDeviceExtension->MountPoint.Length) + Result = FspMountmgrDeleteDrive( + &FsvrtDeviceExtension->MountPoint); + else + Result = FspMountmgrNotifyDeleteDirectory( + &FsvrtDeviceExtension->VolumeName, + &FsvrtDeviceExtension->MountPoint); + /* ignore Result */ + + FspFree(FsvrtDeviceExtension->MountPoint.Buffer); + FsvrtDeviceExtension->MountPoint.Buffer = 0; + FsvrtDeviceExtension->MountPoint.Length = + FsvrtDeviceExtension->MountPoint.MaximumLength = 0; + + Irp->IoStatus.Information = 0; + Result = STATUS_SUCCESS; + } + +exit: + FspFsvrtDeviceUnlockMount(FsvrtDeviceObject); return Result; }