Skip to content

Instantly share code, notes, and snippets.

@billziss-gh
Last active April 17, 2020 04:58
Show Gist options
  • Save billziss-gh/9bc2b3eba7599680ccb7a3e21081c2dd to your computer and use it in GitHub Desktop.
Save billziss-gh/9bc2b3eba7599680ccb7a3e21081c2dd to your computer and use it in GitHub Desktop.
diff --git a/inc/winfsp/launch.h b/inc/winfsp/launch.h
index 112ee251..4a029316 100644
--- a/inc/winfsp/launch.h
+++ b/inc/winfsp/launch.h
@@ -292,7 +292,8 @@ typedef struct _FSP_LAUNCH_REG_RECORD
ULONG Credentials;
ULONG AuthPackageId;
ULONG Recovery;
- ULONG Reserved1[4];
+ ULONG VolumePrefixComponentCount;
+ ULONG Reserved1[3];
UINT8 Buffer[];
} FSP_LAUNCH_REG_RECORD;
#pragma warning(pop)
diff --git a/src/dll/launch.c b/src/dll/launch.c
index 8912cdd7..9d05edfd 100644
--- a/src/dll/launch.c
+++ b/src/dll/launch.c
@@ -275,6 +275,7 @@ FSP_API NTSTATUS FspLaunchRegSetRecord(
SETFIELDI(Credentials, 0);
SETFIELDI(AuthPackageId, 0);
SETFIELDI(Recovery, 0);
+ SETFIELDI(VolumePrefixComponentCount, 0);
}
else
{
@@ -428,6 +429,7 @@ FSP_API NTSTATUS FspLaunchRegGetRecord(
GETFIELDI(Credentials);
GETFIELDI(AuthPackageId);
GETFIELDI(Recovery);
+ GETFIELDI(VolumePrefixComponentCount);
if (0 == Record->Executable)
{
@@ -461,6 +463,8 @@ FSP_API NTSTATUS FspLaunchRegGetRecord(
Record->JobControl = RecordBuf.JobControl;
Record->Credentials = RecordBuf.Credentials;
Record->AuthPackageId = RecordBuf.AuthPackageId;
+ Record->Recovery = RecordBuf.Recovery;
+ Record->VolumePrefixComponentCount = RecordBuf.VolumePrefixComponentCount;
*PRecord = Record;
Result = STATUS_SUCCESS;
diff --git a/src/dll/library.def b/src/dll/library.def
index 8c61982f..0d812ad5 100644
--- a/src/dll/library.def
+++ b/src/dll/library.def
@@ -9,3 +9,4 @@ EXPORTS
NPOpenEnum PRIVATE
NPEnumResource PRIVATE
NPCloseEnum PRIVATE
+ NPGetResourceInformation PRIVATE
diff --git a/src/dll/np.c b/src/dll/np.c
index ce04708a..12cb7bfb 100644
--- a/src/dll/np.c
+++ b/src/dll/np.c
@@ -87,7 +87,8 @@ DWORD APIENTRY NPGetCaps(DWORD Index)
* WNNC_DLG_PROPERTYDIALOG
* WNNC_DLG_SEARCHDIALOG
*/
- return 0;
+ return
+ WNNC_DLG_GETRESOURCEINFORMATION;
case WNNC_ENUMERATION:
/*
* WNNC_ENUM_GLOBAL
@@ -869,6 +870,7 @@ typedef struct
DWORD dwScope;
PWCHAR VolumeListBuf, VolumeListBufEnd, VolumeName;
DWORD LogicalDrives;
+ PWSTR RemoteName, *PRemain;
} FSP_NP_ENUM;
static inline BOOLEAN FspNpValidateEnum(FSP_NP_ENUM *Enum)
@@ -885,6 +887,40 @@ static inline BOOLEAN FspNpValidateEnum(FSP_NP_ENUM *Enum)
#endif
}
+static DWORD APIENTRY NPOpenEnumWithVolumePrefix(
+ DWORD dwScope, PWSTR VolumePrefix, PWSTR VolumePrefixEnd, LPHANDLE lphEnum)
+{
+ static const WCHAR DevicePrefix[] = L"\\Device\\Volume{00000000-0000-0000-0000-000000000000}";
+ FSP_NP_ENUM *Enum = 0;
+ SIZE_T VolumeListSize;
+
+ Enum = MemAlloc(sizeof *Enum);
+ if (0 == Enum)
+ return WN_OUT_OF_MEMORY;
+
+ VolumeListSize = sizeof DevicePrefix + (VolumePrefixEnd - VolumePrefix) * sizeof(WCHAR);
+ Enum->VolumeListBuf = MemAlloc(VolumeListSize);
+ if (0 == Enum->VolumeListBuf)
+ {
+ MemFree(Enum);
+ return WN_OUT_OF_MEMORY;
+ }
+ memcpy(Enum->VolumeListBuf, DevicePrefix, sizeof DevicePrefix);
+ memcpy(Enum->VolumeListBuf + sizeof DevicePrefix / sizeof(WCHAR) - 1,
+ VolumePrefix, (VolumePrefixEnd - VolumePrefix) * sizeof(WCHAR));
+ Enum->VolumeListBuf[sizeof DevicePrefix / sizeof(WCHAR) - 1 + VolumePrefixEnd - VolumePrefix] = L'\0';
+
+ Enum->Signature = 'munE';
+ Enum->dwScope = dwScope;
+ Enum->VolumeListBufEnd = (PVOID)((PUINT8)Enum->VolumeListBuf + VolumeListSize);
+ Enum->VolumeName = Enum->VolumeListBuf;
+ Enum->LogicalDrives = GetLogicalDrives();
+
+ *lphEnum = Enum;
+
+ return WN_SUCCESS;
+}
+
DWORD APIENTRY NPOpenEnum(
DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCEW lpNetResource, LPHANDLE lphEnum)
{
@@ -937,7 +973,7 @@ DWORD APIENTRY NPEnumResource(
PWCHAR ProviderName = 0;
DWORD Count;
PWCHAR P, VolumePrefix;
- ULONG Backslashes;
+ ULONG Backslashes, VolumePrefixLen;
WCHAR Drive;
if (!FspNpValidateEnum(Enum))
@@ -968,12 +1004,15 @@ DWORD APIENTRY NPEnumResource(
if (3 == ++Backslashes)
break;
- if (3 == Backslashes)
+ VolumePrefixLen = lstrlenW(VolumePrefix);
+ if (3 == Backslashes && (0 == Enum->RemoteName ||
+ 0 == invariant_wcsnicmp(Enum->RemoteName, VolumePrefix, VolumePrefixLen)))
{
Drive = FspNpGetDriveLetter(&Enum->LogicalDrives, Enum->VolumeName);
- Strings -= (Drive ? 3 : 0) + 2/* backslash + term-0 */ + lstrlenW(VolumePrefix) +
- (0 == ProviderName ? lstrlenW(L"" FSP_NP_NAME) + 1 : 0);
+ Strings -= (Drive ? 3 : 0) + 2/* backslash + term-0 */ + VolumePrefixLen +
+ (0 == ProviderName ? lstrlenW(L"" FSP_NP_NAME) + 1 : 0) +
+ (0 != Enum->PRemain ? lstrlenW(Enum->RemoteName) - VolumePrefixLen + 1 : 0);
if ((PVOID)(Resource + 1) > (PVOID)Strings)
{
@@ -993,9 +1032,16 @@ DWORD APIENTRY NPEnumResource(
goto exit;
}
+ if (0 != Enum->PRemain)
+ {
+ *Enum->PRemain = Strings + (Drive ? 3 : 0) + 2/* backslash + term-0 */ + VolumePrefixLen +
+ (0 == ProviderName ? lstrlenW(L"" FSP_NP_NAME) + 1 : 0);
+ lstrcpyW(*Enum->PRemain, Enum->RemoteName + VolumePrefixLen);
+ }
+
if (0 == ProviderName)
{
- ProviderName = Strings + (Drive ? 3 : 0) + 2/* backslash + term-0 */ + lstrlenW(VolumePrefix);
+ ProviderName = Strings + (Drive ? 3 : 0) + 2/* backslash + term-0 */ + VolumePrefixLen;
lstrcpyW(ProviderName, L"" FSP_NP_NAME);
}
@@ -1056,6 +1102,88 @@ DWORD APIENTRY NPCloseEnum(HANDLE hEnum)
return WN_SUCCESS;
}
+DWORD APIENTRY NPGetResourceInformation(
+ LPNETRESOURCEW lpNetResource, LPVOID lpBuffer, LPDWORD lpBufferSize, LPWSTR *lplpSystem)
+{
+ DWORD NpResult;
+ NTSTATUS Result;
+ DWORD dwType = lpNetResource->dwType;
+ LPWSTR lpRemoteName = lpNetResource->lpRemoteName;
+ PWSTR ClassName, InstanceName, RemoteName;
+ ULONG ClassNameLen, InstanceNameLen;
+ WCHAR ClassNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
+ HANDLE Enum;
+ DWORD EnumCount;
+ FSP_LAUNCH_REG_RECORD *Record;
+ ULONG RegVolumePrefixComponentCount, VolumePrefixComponentCount;
+ PWSTR VolumePrefixEnd;
+
+ if (dwType & RESOURCETYPE_PRINT)
+ return WN_BAD_VALUE;
+
+ if (!FspNpParseRemoteName(lpRemoteName,
+ &ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
+ return WN_BAD_NETNAME;
+ RemoteName = lpRemoteName + 1;
+
+ if (ClassNameLen > sizeof ClassNameBuf / sizeof ClassNameBuf[0] - 1)
+ ClassNameLen = sizeof ClassNameBuf / sizeof ClassNameBuf[0] - 1;
+ memcpy(ClassNameBuf, ClassName, ClassNameLen * sizeof(WCHAR));
+ ClassNameBuf[ClassNameLen] = '\0';
+
+ NpResult = NPOpenEnum(
+ RESOURCE_CONNECTED, RESOURCETYPE_DISK, RESOURCEUSAGE_CONNECTABLE, 0, &Enum);
+ if (WN_SUCCESS == NpResult)
+ {
+ ((FSP_NP_ENUM *)Enum)->RemoteName = RemoteName;
+ ((FSP_NP_ENUM *)Enum)->PRemain = lplpSystem;
+
+ EnumCount = 1;
+ NpResult = NPEnumResource(Enum, &EnumCount, lpBuffer, lpBufferSize);
+ NPCloseEnum(Enum);
+ if (WN_SUCCESS == NpResult)
+ return NpResult;
+ }
+
+ Result = FspLaunchRegGetRecord(ClassNameBuf, L"" FSP_NP_NAME, &Record);
+ if (!NT_SUCCESS(Result))
+ return WN_BAD_NETNAME;
+ RegVolumePrefixComponentCount = Record->VolumePrefixComponentCount;
+ FspLaunchRegFreeRecord(Record);
+
+ if (RegVolumePrefixComponentCount < 2)
+ RegVolumePrefixComponentCount = 2;
+
+ VolumePrefixComponentCount = 0;
+ for (VolumePrefixEnd = RemoteName; L'\0' != *VolumePrefixEnd; VolumePrefixEnd++)
+ if (L'\\' == *VolumePrefixEnd)
+ {
+ if (RegVolumePrefixComponentCount == VolumePrefixComponentCount)
+ break;
+ }
+ else if (VolumePrefixEnd > RemoteName && L'\\' == VolumePrefixEnd[-1])
+ VolumePrefixComponentCount++;
+
+ if (RegVolumePrefixComponentCount != VolumePrefixComponentCount)
+ return WN_BAD_NETNAME;
+
+ NpResult = NPOpenEnumWithVolumePrefix(
+ RESOURCE_CONTEXT, RemoteName, VolumePrefixEnd, &Enum);
+ if (WN_SUCCESS == NpResult)
+ {
+ ((FSP_NP_ENUM *)Enum)->RemoteName = RemoteName;
+ ((FSP_NP_ENUM *)Enum)->PRemain = lplpSystem;
+
+ EnumCount = 1;
+ NpResult = NPEnumResource(Enum, &EnumCount, lpBuffer, lpBufferSize);
+ NPCloseEnum(Enum);
+ if (WN_SUCCESS == NpResult)
+ return NpResult;
+ }
+
+ return WN_BAD_NETNAME;
+}
+
NTSTATUS FspNpRegister(VOID)
{
extern HINSTANCE DllInstance;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment