From d7450d740ef53c6cb099010c7eb4e5f7084ac874 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 27 Jun 2022 17:27:45 +0100 Subject: [PATCH] dll: Mount Manager directory support --- src/dll/library.h | 6 ++ src/dll/mount.c | 270 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 209 insertions(+), 67 deletions(-) diff --git a/src/dll/library.h b/src/dll/library.h index 0485e32e..f1a2e908 100644 --- a/src/dll/library.h +++ b/src/dll/library.h @@ -126,6 +126,12 @@ static inline BOOLEAN FspPathIsMountmgrMountPoint(PWSTR FileName) ) && L':' == FileName[5]; } +static inline BOOLEAN FspPathIsMountmgrDrive(PWSTR FileName) +{ + return + FspPathIsMountmgrMountPoint(FileName) && + L'\0' == FileName[6]; +} #define FSP_NEXT_EA(Ea, EaEnd) \ (0 != (Ea)->NextEntryOffset ? (PVOID)((PUINT8)(Ea) + (Ea)->NextEntryOffset) : (EaEnd)) diff --git a/src/dll/mount.c b/src/dll/mount.c index 2784182c..3f912ee7 100644 --- a/src/dll/mount.c +++ b/src/dll/mount.c @@ -122,12 +122,8 @@ exit: return Result; } -static NTSTATUS FspMountSet_Mountmgr(HANDLE VolumeHandle, PWSTR VolumeName, PWSTR MountPoint) +static NTSTATUS FspMountmgrMakeMountdev(HANDLE VolumeHandle, PWSTR VolumeName, GUID *UniqueId) { - /* only support drives for now! (format: \\.\X:) */ - if (L'\0' != MountPoint[6]) - return STATUS_INVALID_PARAMETER; - /* mountmgr.h */ typedef enum { @@ -147,38 +143,21 @@ static NTSTATUS FspMountSet_Mountmgr(HANDLE VolumeHandle, PWSTR VolumeName, PWST USHORT DeviceNameLength; WCHAR DeviceName[1]; } MOUNTMGR_TARGET_NAME; - typedef struct - { - USHORT SymbolicLinkNameOffset; - USHORT SymbolicLinkNameLength; - USHORT DeviceNameOffset; - USHORT DeviceNameLength; - } MOUNTMGR_CREATE_POINT_INPUT; - GUID UniqueId; MOUNTMGR_QUERY_AUTO_MOUNT QueryAutoMount; MOUNTMGR_SET_AUTO_MOUNT SetAutoMount; MOUNTMGR_TARGET_NAME *TargetName = 0; - MOUNTMGR_CREATE_POINT_INPUT *CreatePointInput = 0; - ULONG VolumeNameSize, QueryAutoMountSize, TargetNameSize, CreatePointInputSize; - HKEY RegKey; - LONG RegResult; - WCHAR RegValueName[MAX_PATH]; - UINT8 RegValueData[sizeof UniqueId]; - DWORD RegValueNameSize, RegValueDataSize; - DWORD RegType; + ULONG VolumeNameSize, QueryAutoMountSize, TargetNameSize; NTSTATUS Result; /* transform our volume into one that can be used by the MountManager */ - Result = FspFsctlMakeMountdev(VolumeHandle, FALSE, &UniqueId); + 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; - CreatePointInputSize = sizeof *CreatePointInput + - sizeof L"\\DosDevices\\X:" - sizeof(WCHAR) + VolumeNameSize; TargetName = MemAlloc(TargetNameSize); if (0 == TargetName) @@ -187,13 +166,6 @@ static NTSTATUS FspMountSet_Mountmgr(HANDLE VolumeHandle, PWSTR VolumeName, PWST goto exit; } - CreatePointInput = MemAlloc(CreatePointInputSize); - if (0 == CreatePointInput) - { - 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), @@ -229,10 +201,145 @@ static NTSTATUS FspMountSet_Mountmgr(HANDLE VolumeHandle, PWSTR VolumeName, PWST CTL_CODE('m', 16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), /* IOCTL_MOUNTMGR_SET_AUTO_MOUNT */ &SetAutoMount, sizeof SetAutoMount, 0, 0); -#if 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; -#endif + + 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); @@ -255,46 +362,54 @@ static NTSTATUS FspMountSet_Mountmgr(HANDLE VolumeHandle, PWSTR VolumeName, PWST if (!NT_SUCCESS(Result)) goto exit; - /* 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); - } + FspMountmgrDeleteRegistry(&UniqueId); Result = STATUS_SUCCESS; exit: MemFree(CreatePointInput); - MemFree(TargetName); return Result; } -static NTSTATUS FspMountRemove_Mountmgr(PWSTR MountPoint) +static NTSTATUS FspMountSet_Directory(PWSTR VolumeName, PWSTR MountPoint, + PSECURITY_DESCRIPTOR SecurityDescriptor, PHANDLE PMountHandle); +static NTSTATUS FspMountRemove_Directory(HANDLE MountHandle); +static NTSTATUS FspMountSet_MountmgrDirectory(HANDLE VolumeHandle, PWSTR VolumeName, PWSTR MountPoint, + PSECURITY_DESCRIPTOR SecurityDescriptor, PHANDLE PMountHandle) +{ + GUID UniqueId; + HANDLE MountHandle = INVALID_HANDLE_VALUE; + NTSTATUS Result; + + *PMountHandle = 0; + + Result = FspMountSet_Directory(VolumeName, MountPoint + 4, SecurityDescriptor, &MountHandle); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = FspMountmgrMakeMountdev(VolumeHandle, VolumeName, &UniqueId); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = FspMountmgrNotify(VolumeName, MountPoint + 4, TRUE); + if (!NT_SUCCESS(Result)) + goto exit; + + FspMountmgrDeleteRegistry(&UniqueId); + + *PMountHandle = MountHandle; + + Result = STATUS_SUCCESS; + +exit: + if (!NT_SUCCESS(Result) && INVALID_HANDLE_VALUE != MountHandle) + FspMountRemove_Directory(MountHandle); + + return Result; +} + +static NTSTATUS FspMountRemove_MountmgrDrive(PWSTR MountPoint) { /* mountmgr.h */ typedef struct @@ -361,6 +476,22 @@ exit: return Result; } +static NTSTATUS FspMountRemove_MountmgrDirectory(PWSTR VolumeName, PWSTR MountPoint, HANDLE MountHandle) +{ + NTSTATUS Result; + + FspMountmgrNotify(VolumeName, MountPoint + 4, FALSE); + + Result = FspMountRemove_Directory(MountHandle); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = STATUS_SUCCESS; + +exit: + return Result; +} + static NTSTATUS FspLauncherDefineDosDevice( WCHAR Sign, PWSTR MountPoint, PWSTR VolumeName) { @@ -740,8 +871,11 @@ FSP_API NTSTATUS FspMountSet(FSP_MOUNT_DESC *Desc) Desc->MountPoint[0] = L'*'; return STATUS_NO_SUCH_DEVICE; } + else if (FspPathIsMountmgrDrive(Desc->MountPoint)) + return FspMountSet_MountmgrDrive(Desc->VolumeHandle, Desc->VolumeName, Desc->MountPoint); else if (FspPathIsMountmgrMountPoint(Desc->MountPoint)) - return FspMountSet_Mountmgr(Desc->VolumeHandle, Desc->VolumeName, Desc->MountPoint); + return FspMountSet_MountmgrDirectory(Desc->VolumeHandle, Desc->VolumeName, Desc->MountPoint, + Desc->Security, &Desc->MountHandle); else if (FspPathIsDrive(Desc->MountPoint)) return FspMountSet_Drive(Desc->VolumeName, Desc->MountPoint, &Desc->MountHandle); @@ -754,8 +888,10 @@ FSP_API NTSTATUS FspMountRemove(FSP_MOUNT_DESC *Desc) { InitOnceExecuteOnce(&FspMountInitOnce, FspMountInitialize, 0, 0); - if (FspPathIsMountmgrMountPoint(Desc->MountPoint)) - return FspMountRemove_Mountmgr(Desc->MountPoint); + if (FspPathIsMountmgrDrive(Desc->MountPoint)) + return FspMountRemove_MountmgrDrive(Desc->MountPoint); + else if (FspPathIsMountmgrMountPoint(Desc->MountPoint)) + return FspMountRemove_MountmgrDirectory(Desc->VolumeName, Desc->MountPoint, Desc->MountHandle); else if (FspPathIsDrive(Desc->MountPoint)) return FspMountRemove_Drive(Desc->VolumeName, Desc->MountPoint, Desc->MountHandle); else