diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index b814da4c..c44ed040 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -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 { diff --git a/src/dll/fsctl.c b/src/dll/fsctl.c index 5da70a6e..2a4d3542 100644 --- a/src/dll/fsctl.c +++ b/src/dll/fsctl.c @@ -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) { /* diff --git a/src/dll/sxs.c b/src/dll/sxs.c index 874dad71..8227cb6f 100644 --- a/src/dll/sxs.c +++ b/src/dll/sxs.c @@ -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; diff --git a/src/fsptool/fsptool.c b/src/fsptool/fsptool.c index 2ce083b1..1b816f49 100644 --- a/src/fsptool/fsptool.c +++ b/src/fsptool/fsptool.c @@ -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 diff --git a/src/shared/ku/config.h b/src/shared/ku/config.h index f6f3cd70..e8f5f6b3 100644 --- a/src/shared/ku/config.h +++ b/src/shared/ku/config.h @@ -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 diff --git a/src/sys/sxs.c b/src/sys/sxs.c index 084e6d65..23788352 100644 --- a/src/sys/sxs.c +++ b/src/sys/sxs.c @@ -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;