dll: FspFsctlEnumServices

This commit is contained in:
Bill Zissimopoulos 2022-09-10 16:23:14 +01:00
parent b99fb9a5cb
commit 2fc2c237d3
6 changed files with 157 additions and 7 deletions

View File

@ -698,6 +698,9 @@ FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath,
FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath);
FSP_API NTSTATUS FspFsctlStartService(VOID);
FSP_API NTSTATUS FspFsctlStopService(VOID);
FSP_API NTSTATUS FspFsctlEnumServices(
VOID (*EnumFn)(PVOID Context, PWSTR ServiceName, BOOLEAN Running),
PVOID Context);
typedef struct
{

View File

@ -447,17 +447,14 @@ static BOOLEAN FspFsctlRunningInContainer(VOID)
0, 0);
}
FSP_API NTSTATUS FspFsctlStartService(VOID)
static NTSTATUS FspFsctlStartServiceByName(PWSTR DriverName)
{
WCHAR DriverName[256];
SC_HANDLE ScmHandle = 0;
SC_HANDLE SvcHandle = 0;
SERVICE_STATUS ServiceStatus;
DWORD LastError;
NTSTATUS Result;
FspSxsAppendSuffix(DriverName, sizeof DriverName, L"" FSP_FSCTL_DRIVER_NAME);
AcquireSRWLockExclusive(&FspFsctlStartStopServiceLock);
if (FspFsctlRunningInContainer())
@ -525,6 +522,58 @@ exit:
return Result;
}
static VOID FspFsctlStartService_EnumFn(PVOID Context, PWSTR ServiceName, BOOLEAN Running)
{
PWSTR *PDriverName = Context;
if (0 == *PDriverName ||
0 > invariant_wcscmp(*PDriverName, ServiceName))
*PDriverName = ServiceName;
}
FSP_API NTSTATUS FspFsctlStartService(VOID)
{
/*
* With the introduction of side-by-side (SxS) FSD installations,
* we revisit how the FSD is started:
*
* - If the DLL is started in non-SxS mode, we first try to start
* the non-SxS FSD. If that fails we then enumerate all SxS FSD's
* and make a best guess on which one to start.
*
* - If the DLL is started in SxS mode, we only attempt to start
* the associated SxS FSD.
*/
if (L'\0' == FspSxsIdent()[0])
{
/* non-SxS mode */
NTSTATUS Result;
PWSTR DriverName = 0;
Result = FspFsctlStartServiceByName(L"" FSP_FSCTL_DRIVER_NAME);
if (NT_SUCCESS(Result))
return Result;
/* DO NOT CLOBBER Result. We will return it if our best effort below fails. */
FspFsctlEnumServices(FspFsctlStartService_EnumFn, &DriverName);
if (0 == DriverName || !NT_SUCCESS(FspFsctlStartServiceByName(DriverName)))
return Result;
return STATUS_SUCCESS;
}
else
{
/* SxS mode */
WCHAR DriverName[256];
FspSxsAppendSuffix(DriverName, sizeof DriverName, L"" FSP_FSCTL_DRIVER_NAME);
return FspFsctlStartServiceByName(DriverName);
}
}
FSP_API NTSTATUS FspFsctlStopService(VOID)
{
WCHAR DriverName[256];
@ -615,6 +664,75 @@ exit:
return Result;
}
FSP_API NTSTATUS FspFsctlEnumServices(
VOID (*EnumFn)(PVOID Context, PWSTR ServiceName, BOOLEAN Running),
PVOID Context)
{
SC_HANDLE ScmHandle = 0;
LPENUM_SERVICE_STATUSW Services = 0;
DWORD Size, ServiceCount;
DWORD LastError;
NTSTATUS Result;
ScmHandle = OpenSCManagerW(0, 0, SC_MANAGER_ENUMERATE_SERVICE);
if (0 == ScmHandle)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (!EnumServicesStatusW(ScmHandle,
SERVICE_FILE_SYSTEM_DRIVER, SERVICE_STATE_ALL, 0, 0, &Size, &ServiceCount, 0))
{
LastError = GetLastError();
if (ERROR_MORE_DATA != LastError)
{
Result = FspNtStatusFromWin32(LastError);
goto exit;
}
}
if (0 == Size)
{
Result = STATUS_SUCCESS;
goto exit;
}
Services = MemAlloc(Size);
if (0 == Services)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!EnumServicesStatusW(ScmHandle,
SERVICE_FILE_SYSTEM_DRIVER, SERVICE_STATE_ALL, Services, Size, &Size, &ServiceCount, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
for (DWORD I = 0; ServiceCount > I; I++)
{
if (0 != invariant_wcsicmp(Services[I].lpServiceName, L"" FSP_FSCTL_DRIVER_NAME) &&
0 != invariant_wcsnicmp(Services[I].lpServiceName,
L"" FSP_FSCTL_DRIVER_NAME FSP_SXS_SEPARATOR_STRING,
sizeof(FSP_FSCTL_DRIVER_NAME FSP_SXS_SEPARATOR_STRING) - 1))
continue;
EnumFn(Context,
Services[I].lpServiceName,
SERVICE_STOPPED != Services[I].ServiceStatus.dwCurrentState);
}
Result = STATUS_SUCCESS;
exit:
MemFree(Services);
if (0 != ScmHandle)
CloseServiceHandle(ScmHandle);
return Result;
}
static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
{
/*

View File

@ -93,7 +93,7 @@ static BOOLEAN FspSxsIdentInitializeFromFile(VOID)
if (0 == Size)
goto exit;
FspSxsIdentBuf[0] = L'+';
FspSxsIdentBuf[0] = FSP_SXS_SEPARATOR_CHAR;
memcpy(FspSxsIdentBuf + 1, WBuffer, Size * sizeof(WCHAR));
FspSxsIdentBuf[1 + Size] = L'\0';
@ -155,7 +155,7 @@ static BOOLEAN FspSxsIdentInitializeFromDirectory(VOID)
if (0 == Ident)
goto exit;
FspSxsIdentBuf[0] = L'+';
FspSxsIdentBuf[0] = FSP_SXS_SEPARATOR_CHAR;
EndQ = FspSxsIdentBuf + (ARRAYSIZE(FspSxsIdentBuf) - 1);
for (P = Ident, Q = FspSxsIdentBuf + 1; EndP > P && EndQ > Q && L'\\' != *P; P++, Q++)
*Q = *P;

View File

@ -65,6 +65,7 @@ static void usage(void)
" lsvol list file system devices (volumes)\n"
" id [NAME|SID|UID] print user id\n"
" perm [PATH|SDDL|UID:GID:MODE] print permissions\n"
" lsdrv list drivers\n"
" unload unload driver (requires load driver priv)\n",
PROGNAME);
}
@ -564,6 +565,25 @@ static int perm(int argc, wchar_t **argv)
return FspWin32FromNtStatus(Result);
}
static VOID lsdrv_enumfn(PVOID Context, PWSTR ServiceName, BOOLEAN Running)
{
info("%-4s%S", Running ? "R" : "-", ServiceName);
}
static int lsdrv(int argc, wchar_t **argv)
{
if (1 != argc)
usage();
NTSTATUS Result;
Result = FspFsctlEnumServices(lsdrv_enumfn, 0);
if (!NT_SUCCESS(Result))
return FspWin32FromNtStatus(Result);
return 0;
}
static int unload(int argc, wchar_t **argv)
{
if (1 != argc)
@ -598,6 +618,9 @@ int wmain(int argc, wchar_t **argv)
if (0 == invariant_wcscmp(L"perm", argv[0]))
return perm(argc, argv);
else
if (0 == invariant_wcscmp(L"lsdrv", argv[0]))
return lsdrv(argc, argv);
else
if (0 == invariant_wcscmp(L"unload", argv[0]))
return unload(argc, argv);
else

View File

@ -30,4 +30,10 @@
*/
#define FSP_CFG_REJECT_EARLY_IRP
/*
* SxS separator. The '+' in "WinFsp+20220906T173701Z".
*/
#define FSP_SXS_SEPARATOR_CHAR '+'
#define FSP_SXS_SEPARATOR_STRING "+"
#endif

View File

@ -42,7 +42,7 @@ VOID FspSxsIdentInitialize(PUNICODE_STRING DriverName)
{
if (L'\\' == *P)
break;
if (L'+' == *P)
if (FSP_SXS_SEPARATOR_CHAR == *P)
{
Ident = P;
break;