Compare commits

..

22 Commits

Author SHA1 Message Date
b69ed7e2f0 Fix #213 and a typo in macro FSP_FUSE_CTLCODE_FROM_IOCTL 2019-02-18 12:25:34 -08:00
f214561832 update changelog 2019-02-18 12:23:56 -08:00
35c06fe0ba bump version to 2019.2 Gold 2019-02-18 12:20:40 -08:00
0eb84d68e2 update changelog 2018-12-10 10:06:17 -08:00
750e424ac3 bump version to 2019.1 Gold 2018-12-10 10:05:58 -08:00
58162a8d78 update changelog 2018-12-10 10:03:00 -08:00
b323925d94 update changelog 2018-12-10 09:34:17 -08:00
3206e3dd15 change version to 2018.2 B4 2018-12-03 13:31:34 -08:00
0f185587c9 dll: np: implement custom Credential Provider logic 2018-11-29 21:05:57 -08:00
3119922708 np, launcher: allow RunAs=. registry setting 2018-11-26 13:29:34 -08:00
5d90c35e20 sys: FspFsvrtDeviceControl: STATUS_UNRECOGNIZED_VOLUME
This fixes GitHub issue #177. All credit for the investigation and
suggested workaround goes to @thinkport.
2018-11-21 15:32:25 -08:00
a910385cb1 dll: ensure FspFileSystemFinalize is called 2018-11-21 13:46:50 -08:00
17d687fe7e tools: run-tests: disable create_readonlydir_test on compat FUSE tests (no FileAttributes) 2018-11-05 14:14:21 -08:00
4deb7b96a9 tools: run-tests: disable create_readonlydir_test on FUSE3 (no FileAttributes) 2018-11-05 12:39:55 -08:00
36ba4ff402 dll: FspAccessCheckEx: fix #190: add test 2018-11-05 11:08:47 -08:00
55955b8514 dll: FspAccessCheckEx: fix #190: add test 2018-11-05 10:45:11 -08:00
1bebbcf634 dll: FspAccessCheckEx: fix #190 2018-10-19 21:53:44 -07:00
a292cd4d73 dll: FspAccessCheckEx: fix #190 2018-10-19 21:41:52 -07:00
0de00e872f dotnet: ModifySecurityDescriptorEx
Deprecate ModifySecurityDecriptor and introduce
ModifySecurityDescriptorEx. Works around the problem
of clobbering an existing security descriptor when the
native API FspSetSecurityDescriptor fails.
2018-10-08 15:08:07 -07:00
084f0b5b36 update changelog 2018-10-02 11:10:20 -07:00
901ef5e92f update changelog 2018-10-01 17:05:14 -07:00
f09597a519 bump version to 2018.2 Gold 2018-10-01 16:57:49 -07:00
22 changed files with 524 additions and 76 deletions

View File

@ -1,6 +1,61 @@
= Changelog = Changelog
v1.4 (2019.2)::
Changes since v1.3:
* FUSE3 API (version 3.2) is now available. The FUSE2 API (version 2.8) also remains supported.
* New `Control` file system operation allows sending custom control codes to the file system using the Windows `DeviceIoControl` API. FUSE `ioctl` is also supported.
* New `SetDelete` file system operation can optionally be used instead of `CanDelete`. `SetDelete` or `CanDelete` are used to handle the file "disposition" flag, which determines if a file is marked for deletion. See the relevant documentation for more details.
* `FlushAndPurgeOnCleanup` has now been added to the .NET API. (GitHub PR #176; thanks @FrKaram.)
* The Launcher now supports running file systems under the user account that started them. Use `RunAs="."` in the file system registry entry.
* New sample file system "airfs" contributed by @JohnOberschelp. Airfs is an in-memory file system like Memfs on which it is based on; it has received substantial improvements in how the file name space is maintained and has been modified to use modern C++ techniques by John.
* New sample file system "passthrough-fuse3" passes all operations to an underlying file system. This file system is built using the FUSE3 API. It builds and runs on both Windows and Cygwin.
* The FUSE layer now supports multiple file systems within a single process. This is a long standing problem that has been fixed. (GitHub issue #135.)
* The FSD includes a fix for a Windows problem: that case-sensitive file systems do not work properly when mounted as directories. See FAQ entry #3.
* The FSD includes a fix for a rare but serious problem. (GitHub issue #177. Thanks @thinkport.)
* The FSD includes a fix for an incompatibility with DrWeb Antivirus. (GitHub issue #192)
* The DLL includes a fix for an errorenous `STATUS_ACCESS_DENIED` on read-only directories. (GitHub issue #190. Thanks @alfaunits.)
* The FUSE layer includes a fix for the `ioctl` operation. (GitHub PR #214. Thanks @felfert.)
v1.4 (2019.1)::
Changes since v1.3:
* FUSE3 API (version 3.2) is now available. The FUSE2 API (version 2.8) also remains supported.
* New `Control` file system operation allows sending custom control codes to the file system using the Windows `DeviceIoControl` API. FUSE `ioctl` is also supported.
* New `SetDelete` file system operation can optionally be used instead of `CanDelete`. `SetDelete` or `CanDelete` are used to handle the file "disposition" flag, which determines if a file is marked for deletion. See the relevant documentation for more details.
* `FlushAndPurgeOnCleanup` has now been added to the .NET API. (GitHub PR #176; thanks @FrKaram.)
* The Launcher now supports running file systems under the user account that started them. Use `RunAs="."` in the file system registry entry.
* New sample file system "airfs" contributed by @JohnOberschelp. Airfs is an in-memory file system like Memfs on which it is based on; it has received substantial improvements in how the file name space is maintained and has been modified to use modern C++ techniques by John.
* New sample file system "passthrough-fuse3" passes all operations to an underlying file system. This file system is built using the FUSE3 API. It builds and runs on both Windows and Cygwin.
* The FUSE layer now supports multiple file systems within a single process. This is a long standing problem that has been fixed. (GitHub issue #135.)
* The FSD includes a fix for a Windows problem: that case-sensitive file systems do not work properly when mounted as directories. See FAQ entry #3.
* The FSD includes a fix for a rare but serious problem. (GitHub issue #177. Thanks @thinkport.)
* The FSD includes a fix for an incompatibility with DrWeb Antivirus. (GitHub issue #192)
* The DLL includes a fix for an errorenous `STATUS_ACCESS_DENIED` on read-only directories. (GitHub issue #190. Thanks @alfaunits.)
v1.4B4 (2018.2 B4)::
Changes since v1.3:
* FUSE3 API (version 3.2) is now available. The FUSE2 API (version 2.8) also remains supported.
* New `Control` file system operation allows sending custom control codes to the file system using the Windows `DeviceIoControl` API. FUSE `ioctl` is also supported.
* New `SetDelete` file system operation can optionally be used instead of `CanDelete`. `SetDelete` or `CanDelete` are used to handle the file "disposition" flag, which determines if a file is marked for deletion. See the relevant documentation for more details.
* `FlushAndPurgeOnCleanup` has now been added to the .NET API. (GitHub PR #176; thanks @FrKaram.)
* The Launcher now supports running file systems under the user account that started them. Use `RunAs="."` in the file system registry entry.
* New sample file system "airfs" contributed by @JohnOberschelp. Airfs is an in-memory file system like Memfs on which it is based on; it has received substantial improvements in how the file name space is maintained and has been modified to use modern C++ techniques by John.
* New sample file system "passthrough-fuse3" passes all operations to an underlying file system. This file system is built using the FUSE3 API. It builds and runs on both Windows and Cygwin.
* The FUSE layer now supports multiple file systems within a single process. This is a long standing problem that has been fixed. (GitHub issue #135.)
* The FSD includes a fix for a Windows problem: that case-sensitive file systems do not work properly when mounted as directories. See FAQ entry #3.
* The FSD includes a fix for a rare but serious problem. (GitHub issue #177. Thanks @thinkport.)
* The FSD includes a fix for an incompatibility with DrWeb Antivirus. (GitHub issue #192)
* The DLL includes a fix for an errorenous `STATUS_ACCESS_DENIED` on read-only directories. (GitHub issue #190. Thanks @alfaunits.)
v1.4B3 (2018.2 B3):: v1.4B3 (2018.2 B3)::
Changes since v1.3: Changes since v1.3:

View File

@ -18,8 +18,8 @@
<MyCanonicalVersion>1.4</MyCanonicalVersion> <MyCanonicalVersion>1.4</MyCanonicalVersion>
<MyProductVersion>2018.2 B3</MyProductVersion> <MyProductVersion>2019.2</MyProductVersion>
<MyProductStage>Beta</MyProductStage> <MyProductStage>Gold</MyProductStage>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion> <MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas> <MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>

View File

@ -222,7 +222,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile> <ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -250,7 +250,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile> <ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -281,7 +281,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile> <ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -312,7 +312,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile> <ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib</AdditionalDependencies>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>

View File

@ -59,7 +59,7 @@ extern "C" {
#define FSP_FUSE_DEVICE_TYPE (0x8000 | 'W' | 'F' * 0x100) /* DeviceIoControl -> ioctl */ #define FSP_FUSE_DEVICE_TYPE (0x8000 | 'W' | 'F' * 0x100) /* DeviceIoControl -> ioctl */
#define FSP_FUSE_CTLCODE_FROM_IOCTL(cmd)\ #define FSP_FUSE_CTLCODE_FROM_IOCTL(cmd)\
(FSP_FUSE_DEVICE_TYPE << 16) | (((c) & 0x0fff) << 2) (FSP_FUSE_DEVICE_TYPE << 16) | (((cmd) & 0x0fff) << 2)
#define FSP_FUSE_IOCTL(cmd, isiz, osiz) \ #define FSP_FUSE_IOCTL(cmd, isiz, osiz) \
( \ ( \
(((osiz) != 0) << 31) | \ (((osiz) != 0) << 31) | \

View File

@ -111,7 +111,43 @@ enum
*/ */
FSP_API NTSTATUS FspLaunchCallLauncherPipe( FSP_API NTSTATUS FspLaunchCallLauncherPipe(
WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl, WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl,
PWSTR Buffer, PULONG PSize, PULONG PLauncherError); PWSTR Buffer, PULONG PSize,
PULONG PLauncherError);
/**
* Call launcher pipe.
*
* This function is used to send a command to the launcher and receive a response.
*
* @param Command
* Launcher command to send. For example, the 'L' launcher command instructs
* the launcher to list all running service instances.
* @param Argc
* Command argument count. May be 0.
* @param Argv
* Command argument array. May be NULL.
* @param Argl
* Command argument length array. May be NULL. If this is NULL all command arguments
* are assumed to be NULL-terminated strings. It is also possible for specific arguments
* to be NULL-terminated; in this case pass -1 in the corresponding Argl position.
* @param Buffer
* Buffer that receives the command response. May be NULL.
* @param PSize
* Pointer to a ULONG. On input it contains the size of the Buffer. On output it
* contains the number of bytes transferred. May be NULL.
* @param AllowImpersonation
* Allow caller to be impersonated by launcher.
* @param PLauncherError
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
* @return
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
* returns an error. Other status codes indicate a communication error. Launcher errors are
* reported through PLauncherError.
*/
FSP_API NTSTATUS FspLaunchCallLauncherPipeEx(
WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl,
PWSTR Buffer, PULONG PSize,
BOOLEAN AllowImpersonation,
PULONG PLauncherError);
/** /**
* Start a service instance. * Start a service instance.
* *
@ -138,6 +174,35 @@ FSP_API NTSTATUS FspLaunchStart(
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv, PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv,
BOOLEAN HasSecret, BOOLEAN HasSecret,
PULONG PLauncherError); PULONG PLauncherError);
/**
* Start a service instance.
*
* @param ClassName
* Class name of the service instance to start.
* @param InstanceName
* Instance name of the service instance to start.
* @param Argc
* Service instance argument count. May be 0.
* @param Argv
* Service instance argument array. May be NULL.
* @param HasSecret
* Whether the last argument in Argv is assumed to be a secret (e.g. password) or not.
* Secrets are passed to service instances through standard input rather than the command
* line.
* @param AllowImpersonation
* Allow caller to be impersonated by launcher.
* @param PLauncherError
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
* @return
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
* returns an error. Other status codes indicate a communication error. Launcher errors are
* reported through PLauncherError.
*/
FSP_API NTSTATUS FspLaunchStartEx(
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv,
BOOLEAN HasSecret,
BOOLEAN AllowImpersonation,
PULONG PLauncherError);
/** /**
* Stop a service instance. * Stop a service instance.
* *
@ -221,10 +286,12 @@ typedef struct _FSP_LAUNCH_REG_RECORD
PWSTR WorkDirectory; PWSTR WorkDirectory;
PWSTR RunAs; PWSTR RunAs;
PWSTR Security; PWSTR Security;
PVOID Reserved0[6]; PWSTR AuthPackage;
PVOID Reserved0[5];
ULONG JobControl; ULONG JobControl;
ULONG Credentials; ULONG Credentials;
ULONG Reserved1[6]; ULONG AuthPackageId;
ULONG Reserved1[5];
UINT8 Buffer[]; UINT8 Buffer[];
} FSP_LAUNCH_REG_RECORD; } FSP_LAUNCH_REG_RECORD;
#pragma warning(pop) #pragma warning(pop)

View File

@ -1795,6 +1795,10 @@ FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize, PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout, PULONG PBytesTransferred, ULONG Timeout,
PSID Sid); PSID Sid);
FSP_API NTSTATUS FspCallNamedPipeSecurelyEx(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout, BOOLEAN AllowImpersonation,
PSID Sid);
FSP_API NTSTATUS FspVersion(PUINT32 PVersion); FSP_API NTSTATUS FspVersion(PUINT32 PVersion);
/* /*

View File

@ -2168,6 +2168,7 @@ static NTSTATUS fsp_fuse_intf_Control(FSP_FILE_SYSTEM *FileSystem,
memcpy(OutputBuffer, InputBuffer, InputBufferLength); memcpy(OutputBuffer, InputBuffer, InputBufferLength);
err = f->ops.ioctl(filedesc->PosixPath, cmd, 0, &fi, 0, OutputBuffer); err = f->ops.ioctl(filedesc->PosixPath, cmd, 0, &fi, 0, OutputBuffer);
} }
*PBytesTransferred = OutputBufferLength;
return fsp_fuse_ntstatus_from_errno(f->env, err); return fsp_fuse_ntstatus_from_errno(f->env, err);
} }

View File

@ -23,7 +23,18 @@
FSP_API NTSTATUS FspLaunchCallLauncherPipe( FSP_API NTSTATUS FspLaunchCallLauncherPipe(
WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl, WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl,
PWSTR Buffer, PULONG PSize, PULONG PLauncherError) PWSTR Buffer, PULONG PSize,
PULONG PLauncherError)
{
return FspLaunchCallLauncherPipeEx(
Command, Argc, Argv, Argl, Buffer, PSize, FALSE, PLauncherError);
}
FSP_API NTSTATUS FspLaunchCallLauncherPipeEx(
WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl,
PWSTR Buffer, PULONG PSize,
BOOLEAN AllowImpersonation,
PULONG PLauncherError)
{ {
PWSTR PipeBuf = 0, P; PWSTR PipeBuf = 0, P;
ULONG Length, BytesTransferred; ULONG Length, BytesTransferred;
@ -53,9 +64,9 @@ FSP_API NTSTATUS FspLaunchCallLauncherPipe(
memcpy(P, Argv[I], Length * sizeof(WCHAR)); P += Length; *P++ = L'\0'; memcpy(P, Argv[I], Length * sizeof(WCHAR)); P += Length; *P++ = L'\0';
} }
Result = FspCallNamedPipeSecurely(L"" FSP_LAUNCH_PIPE_NAME, Result = FspCallNamedPipeSecurelyEx(L"" FSP_LAUNCH_PIPE_NAME,
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), PipeBuf, FSP_LAUNCH_PIPE_BUFFER_SIZE, PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), PipeBuf, FSP_LAUNCH_PIPE_BUFFER_SIZE,
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, FSP_LAUNCH_PIPE_OWNER); &BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, AllowImpersonation, FSP_LAUNCH_PIPE_OWNER);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
@ -102,8 +113,17 @@ exit:
} }
FSP_API NTSTATUS FspLaunchStart( FSP_API NTSTATUS FspLaunchStart(
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv,
BOOLEAN HasSecret,
PULONG PLauncherError)
{
return FspLaunchStartEx(ClassName, InstanceName, Argc, Argv, HasSecret, FALSE, PLauncherError);
}
FSP_API NTSTATUS FspLaunchStartEx(
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv0, PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv0,
BOOLEAN HasSecret, BOOLEAN HasSecret,
BOOLEAN AllowImpersonation,
PULONG PLauncherError) PULONG PLauncherError)
{ {
PWSTR Argv[9 + 2]; PWSTR Argv[9 + 2];
@ -115,9 +135,9 @@ FSP_API NTSTATUS FspLaunchStart(
Argv[1] = InstanceName; Argv[1] = InstanceName;
memcpy(Argv + 2, Argv0, Argc * sizeof(PWSTR)); memcpy(Argv + 2, Argv0, Argc * sizeof(PWSTR));
return FspLaunchCallLauncherPipe( return FspLaunchCallLauncherPipeEx(
HasSecret ? FspLaunchCmdStartWithSecret : FspLaunchCmdStart, HasSecret ? FspLaunchCmdStartWithSecret : FspLaunchCmdStart,
Argc + 2, Argv, 0, 0, 0, PLauncherError); Argc + 2, Argv, 0, 0, 0, AllowImpersonation, PLauncherError);
} }
FSP_API NTSTATUS FspLaunchStop( FSP_API NTSTATUS FspLaunchStop(
@ -250,8 +270,10 @@ FSP_API NTSTATUS FspLaunchRegSetRecord(
SETFIELD(WorkDirectory); SETFIELD(WorkDirectory);
SETFIELD(RunAs); SETFIELD(RunAs);
SETFIELD(Security); SETFIELD(Security);
SETFIELD(AuthPackage);
SETFIELDI(JobControl, ~0); /* JobControl default is 1; but we treat as without default */ SETFIELDI(JobControl, ~0); /* JobControl default is 1; but we treat as without default */
SETFIELDI(Credentials, 0); SETFIELDI(Credentials, 0);
SETFIELDI(AuthPackageId, 0);
} }
else else
{ {
@ -400,8 +422,10 @@ FSP_API NTSTATUS FspLaunchRegGetRecord(
GETFIELD(WorkDirectory); GETFIELD(WorkDirectory);
GETFIELD(RunAs); GETFIELD(RunAs);
GETFIELD(Security); GETFIELD(Security);
GETFIELD(AuthPackage);
GETFIELDI(JobControl); GETFIELDI(JobControl);
GETFIELDI(Credentials); GETFIELDI(Credentials);
GETFIELDI(AuthPackageId);
if (0 == Record->Executable) if (0 == Record->Executable)
{ {
@ -430,8 +454,11 @@ FSP_API NTSTATUS FspLaunchRegGetRecord(
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.RunAs - RegBuf)) : 0; (PVOID)(Record->Buffer + ((PUINT8)RecordBuf.RunAs - RegBuf)) : 0;
Record->Security = 0 != RecordBuf.Security ? Record->Security = 0 != RecordBuf.Security ?
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.Security - RegBuf)) : 0; (PVOID)(Record->Buffer + ((PUINT8)RecordBuf.Security - RegBuf)) : 0;
Record->AuthPackage = 0 != RecordBuf.AuthPackage ?
(PVOID)(Record->Buffer + ((PUINT8)RecordBuf.AuthPackage - RegBuf)) : 0;
Record->JobControl = RecordBuf.JobControl; Record->JobControl = RecordBuf.JobControl;
Record->Credentials = RecordBuf.Credentials; Record->Credentials = RecordBuf.Credentials;
Record->AuthPackageId = RecordBuf.AuthPackageId;
*PRecord = Record; *PRecord = Record;
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;

View File

@ -46,6 +46,7 @@ BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
Dynamic = 0 == Reserved; Dynamic = 0 == Reserved;
fsp_fuse_finalize(Dynamic); fsp_fuse_finalize(Dynamic);
FspServiceFinalize(Dynamic); FspServiceFinalize(Dynamic);
FspFileSystemFinalize(Dynamic);
FspEventLogFinalize(Dynamic); FspEventLogFinalize(Dynamic);
FspPosixFinalize(Dynamic); FspPosixFinalize(Dynamic);
FspWksidFinalize(Dynamic); FspWksidFinalize(Dynamic);

View File

@ -47,6 +47,7 @@
VOID FspWksidFinalize(BOOLEAN Dynamic); VOID FspWksidFinalize(BOOLEAN Dynamic);
VOID FspPosixFinalize(BOOLEAN Dynamic); VOID FspPosixFinalize(BOOLEAN Dynamic);
VOID FspEventLogFinalize(BOOLEAN Dynamic); VOID FspEventLogFinalize(BOOLEAN Dynamic);
VOID FspFileSystemFinalize(BOOLEAN Dynamic);
VOID FspServiceFinalize(BOOLEAN Dynamic); VOID FspServiceFinalize(BOOLEAN Dynamic);
VOID fsp_fuse_finalize(BOOLEAN Dynamic); VOID fsp_fuse_finalize(BOOLEAN Dynamic);
VOID fsp_fuse_finalize_thread(VOID); VOID fsp_fuse_finalize_thread(VOID);

View File

@ -23,6 +23,9 @@
#include <npapi.h> #include <npapi.h>
#include <wincred.h> #include <wincred.h>
#define _NTDEF_
#include <ntsecapi.h>
#define FSP_NP_NAME LIBRARY_NAME ".Np" #define FSP_NP_NAME LIBRARY_NAME ".Np"
#define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */ #define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */
#define FSP_NP_ADDCONNECTION_TIMEOUT 15000 #define FSP_NP_ADDCONNECTION_TIMEOUT 15000
@ -179,12 +182,14 @@ static inline BOOLEAN FspNpParseRemoteUserName(PWSTR RemoteName,
static inline DWORD FspNpCallLauncherPipe( static inline DWORD FspNpCallLauncherPipe(
WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl, WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl,
PWSTR Buffer, PULONG PSize) PWSTR Buffer, PULONG PSize,
BOOLEAN AllowImpersonation)
{ {
NTSTATUS Result; NTSTATUS Result;
ULONG ErrorCode; ULONG ErrorCode;
Result = FspLaunchCallLauncherPipe(Command, Argc, Argv, Argl, Buffer, PSize, &ErrorCode); Result = FspLaunchCallLauncherPipeEx(Command, Argc, Argv, Argl, Buffer, PSize, AllowImpersonation,
&ErrorCode);
return !NT_SUCCESS(Result) ? return !NT_SUCCESS(Result) ?
WN_NO_NETWORK : WN_NO_NETWORK :
(ERROR_BROKEN_PIPE == ErrorCode ? WN_NO_NETWORK : ErrorCode); (ERROR_BROKEN_PIPE == ErrorCode ? WN_NO_NETWORK : ErrorCode);
@ -251,7 +256,50 @@ static WCHAR FspNpGetDriveLetter(PDWORD PLogicalDrives, PWSTR VolumeName)
return 0; return 0;
} }
static DWORD FspNpGetRemoteInfo(PWSTR RemoteName, PDWORD PCredentialsKind) static NTSTATUS FspNpGetAuthPackage(PWSTR AuthPackageName, PULONG PAuthPackage)
{
HANDLE LsaHandle;
BOOLEAN LsaHandleValid = FALSE;
CHAR LsaAuthPackageNameBuf[127]; /* "The package name must not exceed 127 bytes in length." */
LSA_STRING LsaAuthPackageName;
ULONG AuthPackage;
NTSTATUS Result;
*PAuthPackage = 0;
Result = LsaConnectUntrusted(&LsaHandle);
if (!NT_SUCCESS(Result))
goto exit;
LsaHandleValid = TRUE;
LsaAuthPackageName.MaximumLength = sizeof LsaAuthPackageNameBuf;
LsaAuthPackageName.Buffer = LsaAuthPackageNameBuf;
LsaAuthPackageName.Length = WideCharToMultiByte(CP_UTF8, 0,
AuthPackageName, lstrlenW(AuthPackageName),
LsaAuthPackageNameBuf, sizeof LsaAuthPackageNameBuf,
0, 0);
if (0 == LsaAuthPackageName.Length)
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
Result = LsaLookupAuthenticationPackage(LsaHandle, &LsaAuthPackageName, &AuthPackage);
if (!NT_SUCCESS(Result))
goto exit;
*PAuthPackage = AuthPackage;
Result = STATUS_SUCCESS;
exit:
if (LsaHandleValid)
LsaDeregisterLogonProcess(LsaHandle);
return Result;
}
static DWORD FspNpGetRemoteInfo(PWSTR RemoteName,
PDWORD PAuthPackage, PDWORD PCredentialsKind, PBOOLEAN PAllowImpersonation)
{ {
PWSTR ClassName, InstanceName; PWSTR ClassName, InstanceName;
ULONG ClassNameLen, InstanceNameLen; ULONG ClassNameLen, InstanceNameLen;
@ -259,8 +307,15 @@ static DWORD FspNpGetRemoteInfo(PWSTR RemoteName, PDWORD PCredentialsKind)
FSP_LAUNCH_REG_RECORD *Record; FSP_LAUNCH_REG_RECORD *Record;
NTSTATUS Result; NTSTATUS Result;
if (0 != PAuthPackage)
*PAuthPackage = 0;
if (0 != PCredentialsKind)
*PCredentialsKind = FSP_NP_CREDENTIALS_NONE; *PCredentialsKind = FSP_NP_CREDENTIALS_NONE;
if (0 != PAllowImpersonation)
*PAllowImpersonation = FALSE;
if (!FspNpParseRemoteName(RemoteName, if (!FspNpParseRemoteName(RemoteName,
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen)) &ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
return WN_BAD_NETNAME; return WN_BAD_NETNAME;
@ -274,6 +329,23 @@ static DWORD FspNpGetRemoteInfo(PWSTR RemoteName, PDWORD PCredentialsKind)
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return WN_NO_NETWORK; return WN_NO_NETWORK;
if (0 != PAuthPackage)
{
if (0 != Record->AuthPackage)
{
ULONG AuthPackage = 0;
Result = FspNpGetAuthPackage(Record->AuthPackage, &AuthPackage);
if (!NT_SUCCESS(Result))
return WN_NO_NETWORK;
*PAuthPackage = AuthPackage + 1; /* ensure non-0 (Negotiate AuthPackage == 0) */
}
else if (0 != Record->AuthPackageId)
*PAuthPackage = Record->AuthPackageId + 1; /* ensure non-0 (Negotiate AuthPackage == 0) */
}
if (0 != PCredentialsKind)
switch (Record->Credentials) switch (Record->Credentials)
{ {
case FSP_NP_CREDENTIALS_NONE: case FSP_NP_CREDENTIALS_NONE:
@ -283,6 +355,10 @@ static DWORD FspNpGetRemoteInfo(PWSTR RemoteName, PDWORD PCredentialsKind)
break; break;
} }
if (0 != PAllowImpersonation)
*PAllowImpersonation = 0 != Record->RunAs &&
L'.' == Record->RunAs[0] && L'\0' == Record->RunAs[1];
FspLaunchRegFreeRecord(Record); FspLaunchRegFreeRecord(Record);
return WN_SUCCESS; return WN_SUCCESS;
@ -290,7 +366,7 @@ static DWORD FspNpGetRemoteInfo(PWSTR RemoteName, PDWORD PCredentialsKind)
static DWORD FspNpGetCredentials( static DWORD FspNpGetCredentials(
HWND hwndOwner, PWSTR Caption, DWORD PrevNpResult, HWND hwndOwner, PWSTR Caption, DWORD PrevNpResult,
DWORD CredentialsKind, DWORD AuthPackage0, DWORD CredentialsKind,
PBOOL PSave, PBOOL PSave,
PWSTR UserName, ULONG UserNameSize/* in chars */, PWSTR UserName, ULONG UserNameSize/* in chars */,
PWSTR Password, ULONG PasswordSize/* in chars */) PWSTR Password, ULONG PasswordSize/* in chars */)
@ -317,7 +393,7 @@ static DWORD FspNpGetCredentials(
(FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind ? 0/*CREDUI_FLAGS_KEEP_USERNAME*/ : 0)); (FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind ? 0/*CREDUI_FLAGS_KEEP_USERNAME*/ : 0));
#else #else
WCHAR Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1]; WCHAR Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1];
ULONG AuthPackage = 0; ULONG AuthPackage = 0 != AuthPackage0 ? AuthPackage0 - 1 : 0;
PVOID InAuthBuf = 0, OutAuthBuf = 0; PVOID InAuthBuf = 0, OutAuthBuf = 0;
ULONG InAuthSize, OutAuthSize, DomainSize; ULONG InAuthSize, OutAuthSize, DomainSize;
@ -346,7 +422,8 @@ static DWORD FspNpGetCredentials(
NpResult = CredUIPromptForWindowsCredentialsW(&UiInfo, PrevNpResult, NpResult = CredUIPromptForWindowsCredentialsW(&UiInfo, PrevNpResult,
&AuthPackage, InAuthBuf, InAuthSize, &OutAuthBuf, &OutAuthSize, PSave, &AuthPackage, InAuthBuf, InAuthSize, &OutAuthBuf, &OutAuthSize, PSave,
CREDUIWIN_GENERIC | (0 != PSave ? CREDUIWIN_CHECKBOX : 0)); (0 != AuthPackage0 ? CREDUIWIN_AUTHPACKAGE_ONLY : CREDUIWIN_GENERIC) |
(0 != PSave ? CREDUIWIN_CHECKBOX : 0));
if (ERROR_SUCCESS != NpResult) if (ERROR_SUCCESS != NpResult)
goto exit; goto exit;
@ -464,6 +541,7 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
PWSTR ClassName, InstanceName, RemoteName, P; PWSTR ClassName, InstanceName, RemoteName, P;
ULONG ClassNameLen, InstanceNameLen; ULONG ClassNameLen, InstanceNameLen;
DWORD CredentialsKind; DWORD CredentialsKind;
BOOLEAN AllowImpersonation;
ULONG Argc; ULONG Argc;
PWSTR Argv[6]; PWSTR Argv[6];
ULONG Argl[6]; ULONG Argl[6];
@ -493,7 +571,7 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
return WN_ALREADY_CONNECTED; return WN_ALREADY_CONNECTED;
} }
NpResult = FspNpGetRemoteInfo(lpRemoteName, &CredentialsKind); NpResult = FspNpGetRemoteInfo(lpRemoteName, 0, &CredentialsKind, &AllowImpersonation);
if (WN_SUCCESS != NpResult) if (WN_SUCCESS != NpResult)
return NpResult; return NpResult;
@ -550,7 +628,8 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
NpResult = FspNpCallLauncherPipe( NpResult = FspNpCallLauncherPipe(
FSP_NP_CREDENTIALS_NONE != CredentialsKind ? FspLaunchCmdStartWithSecret : FspLaunchCmdStart, FSP_NP_CREDENTIALS_NONE != CredentialsKind ? FspLaunchCmdStartWithSecret : FspLaunchCmdStart,
Argc, Argv, Argl, 0, 0); Argc, Argv, Argl, 0, 0,
AllowImpersonation);
switch (NpResult) switch (NpResult)
{ {
case WN_SUCCESS: case WN_SUCCESS:
@ -602,7 +681,8 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
if (WN_SUCCESS != FspNpCallLauncherPipe( if (WN_SUCCESS != FspNpCallLauncherPipe(
FspLaunchCmdGetInfo, FspLaunchCmdGetInfo,
Argc, Argv, Argl, 0, 0)) Argc, Argv, Argl, 0, 0,
FALSE))
{ {
/* looks like the file system is gone! */ /* looks like the file system is gone! */
NpResult = WN_NO_NETWORK; NpResult = WN_NO_NETWORK;
@ -659,7 +739,7 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
{ {
DWORD NpResult; DWORD NpResult;
PWSTR RemoteName = lpNetResource->lpRemoteName; PWSTR RemoteName = lpNetResource->lpRemoteName;
DWORD CredentialsKind; DWORD AuthPackage, CredentialsKind;
WCHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1], Password[CREDUI_MAX_PASSWORD_LENGTH + 1]; WCHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1], Password[CREDUI_MAX_PASSWORD_LENGTH + 1];
#if defined(FSP_NP_CREDENTIAL_MANAGER) #if defined(FSP_NP_CREDENTIAL_MANAGER)
BOOL Save = TRUE; BOOL Save = TRUE;
@ -679,7 +759,7 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
return NpResult; return NpResult;
} }
NpResult = FspNpGetRemoteInfo(RemoteName, &CredentialsKind); NpResult = FspNpGetRemoteInfo(RemoteName, &AuthPackage, &CredentialsKind, 0);
if (WN_SUCCESS != NpResult) if (WN_SUCCESS != NpResult)
return NpResult; return NpResult;
if (FSP_NP_CREDENTIALS_NONE == CredentialsKind) if (FSP_NP_CREDENTIALS_NONE == CredentialsKind)
@ -695,7 +775,7 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
{ {
NpResult = FspNpGetCredentials( NpResult = FspNpGetCredentials(
hwndOwner, RemoteName, NpResult, hwndOwner, RemoteName, NpResult,
CredentialsKind, AuthPackage, CredentialsKind,
#if defined(FSP_NP_CREDENTIAL_MANAGER) #if defined(FSP_NP_CREDENTIAL_MANAGER)
&Save, &Save,
#else #else
@ -766,7 +846,8 @@ DWORD APIENTRY NPCancelConnection(LPWSTR lpName, BOOL fForce)
NpResult = FspNpCallLauncherPipe( NpResult = FspNpCallLauncherPipe(
FspLaunchCmdStop, FspLaunchCmdStop,
Argc, Argv, Argl, 0, 0); Argc, Argv, Argl, 0, 0,
FALSE);
switch (NpResult) switch (NpResult)
{ {
case WN_SUCCESS: case WN_SUCCESS:

View File

@ -341,26 +341,25 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
if (Request->Req.Create.UserMode) if (Request->Req.Create.UserMode)
{ {
if (0 != (FileAttributes & FILE_ATTRIBUTE_READONLY)) if (FILE_ATTRIBUTE_READONLY == (FileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY)) &&
{ (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD)))
if (DesiredAccess &
(FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD))
{ {
Result = STATUS_ACCESS_DENIED; Result = STATUS_ACCESS_DENIED;
goto exit; goto exit;
} }
if (Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE)
if (FILE_ATTRIBUTE_READONLY == (FileAttributes & FILE_ATTRIBUTE_READONLY) &&
(Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE))
{ {
Result = STATUS_CANNOT_DELETE; Result = STATUS_CANNOT_DELETE;
goto exit; goto exit;
} }
}
if (0 == SecurityDescriptorSize) if (0 == SecurityDescriptorSize)
*PGrantedAccess = (MAXIMUM_ALLOWED & DesiredAccess) ? *PGrantedAccess = (MAXIMUM_ALLOWED & DesiredAccess) ?
FspFileGenericMapping.GenericAll : DesiredAccess; FspFileGenericMapping.GenericAll : DesiredAccess;
if (0 != (FileAttributes & FILE_ATTRIBUTE_READONLY) && if (FILE_ATTRIBUTE_READONLY == (FileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY)) &&
0 != (MAXIMUM_ALLOWED & DesiredAccess)) 0 != (MAXIMUM_ALLOWED & DesiredAccess))
*PGrantedAccess &= ~(FILE_WRITE_DATA | FILE_APPEND_DATA | *PGrantedAccess &= ~(FILE_WRITE_DATA | FILE_APPEND_DATA |
FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD); FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD);

View File

@ -67,6 +67,16 @@ FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize, PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout, PULONG PBytesTransferred, ULONG Timeout,
PSID Sid) PSID Sid)
{
return FspCallNamedPipeSecurelyEx(PipeName,
InBuffer, InBufferSize, OutBuffer, OutBufferSize, PBytesTransferred, Timeout,
FALSE, Sid);
}
FSP_API NTSTATUS FspCallNamedPipeSecurelyEx(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout, BOOLEAN AllowImpersonation,
PSID Sid)
{ {
NTSTATUS Result; NTSTATUS Result;
HANDLE Pipe = INVALID_HANDLE_VALUE; HANDLE Pipe = INVALID_HANDLE_VALUE;
@ -75,7 +85,8 @@ FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
Pipe = CreateFileW(PipeName, Pipe = CreateFileW(PipeName,
GENERIC_READ | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES, GENERIC_READ | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, 0); SECURITY_SQOS_PRESENT | (AllowImpersonation ? SECURITY_IMPERSONATION : SECURITY_IDENTIFICATION),
0);
if (INVALID_HANDLE_VALUE == Pipe) if (INVALID_HANDLE_VALUE == Pipe)
{ {
if (ERROR_PIPE_BUSY != GetLastError()) if (ERROR_PIPE_BUSY != GetLastError())
@ -89,7 +100,8 @@ FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
Pipe = CreateFileW(PipeName, Pipe = CreateFileW(PipeName,
GENERIC_READ | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES, GENERIC_READ | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, 0); SECURITY_SQOS_PRESENT | (AllowImpersonation ? SECURITY_IMPERSONATION : SECURITY_IDENTIFICATION),
0);
if (INVALID_HANDLE_VALUE == Pipe) if (INVALID_HANDLE_VALUE == Pipe)
{ {
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());

View File

@ -707,7 +707,7 @@ namespace Fsp
/// Describes the modifications to apply to the file or directory security descriptor. /// Describes the modifications to apply to the file or directory security descriptor.
/// </param> /// </param>
/// <returns>STATUS_SUCCESS or error code.</returns> /// <returns>STATUS_SUCCESS or error code.</returns>
/// <seealso cref="ModifySecurityDescriptor"/> /// <seealso cref="ModifySecurityDescriptorEx"/>
public virtual Int32 SetSecurity( public virtual Int32 SetSecurity(
Object FileNode, Object FileNode,
Object FileDesc, Object FileDesc,
@ -1105,7 +1105,7 @@ namespace Fsp
return (int)Api.FspFileSystemOperationProcessId(); return (int)Api.FspFileSystemOperationProcessId();
} }
/// <summary> /// <summary>
/// Modifies a security descriptor. /// Modifies a security descriptor. [OBSOLETE]
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This is a helper for implementing the SetSecurity operation. /// This is a helper for implementing the SetSecurity operation.
@ -1121,6 +1121,7 @@ namespace Fsp
/// </param> /// </param>
/// <returns>The modified security descriptor.</returns> /// <returns>The modified security descriptor.</returns>
/// <seealso cref="SetSecurity"/> /// <seealso cref="SetSecurity"/>
[Obsolete("use ModifySecurityDescriptorEx")]
public static byte[] ModifySecurityDescriptor( public static byte[] ModifySecurityDescriptor(
Byte[] SecurityDescriptor, Byte[] SecurityDescriptor,
AccessControlSections Sections, AccessControlSections Sections,
@ -1140,6 +1141,47 @@ namespace Fsp
SecurityInformation, SecurityInformation,
ModificationDescriptor); ModificationDescriptor);
} }
/// <summary>
/// Modifies a security descriptor.
/// </summary>
/// <remarks>
/// This is a helper for implementing the SetSecurity operation.
/// </remarks>
/// <param name="SecurityDescriptor">
/// The original security descriptor.
/// </param>
/// <param name="Sections">
/// Describes what parts of the file or directory security descriptor should be modified.
/// </param>
/// <param name="ModificationDescriptor">
/// Describes the modifications to apply to the file or directory security descriptor.
/// </param>
/// <param name="ModifiedDescriptor">
/// The modified security descriptor. This parameter is modified only on success.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
/// <seealso cref="SetSecurity"/>
public static Int32 ModifySecurityDescriptorEx(
Byte[] SecurityDescriptor,
AccessControlSections Sections,
Byte[] ModificationDescriptor,
ref Byte[] ModifiedDescriptor)
{
UInt32 SecurityInformation = 0;
if (0 != (Sections & AccessControlSections.Owner))
SecurityInformation |= 1/*OWNER_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Group))
SecurityInformation |= 2/*GROUP_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Access))
SecurityInformation |= 4/*DACL_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Audit))
SecurityInformation |= 8/*SACL_SECURITY_INFORMATION*/;
return Api.ModifySecurityDescriptorEx(
SecurityDescriptor,
SecurityInformation,
ModificationDescriptor,
ref ModifiedDescriptor);
}
public Int32 SeekableReadDirectory( public Int32 SeekableReadDirectory(
Object FileNode, Object FileNode,
Object FileDesc, Object FileDesc,

View File

@ -928,6 +928,26 @@ namespace Fsp.Interop
return SecurityDescriptorBytes; return SecurityDescriptorBytes;
} }
} }
internal unsafe static Int32 ModifySecurityDescriptorEx(
Byte[] SecurityDescriptorBytes,
UInt32 SecurityInformation,
Byte[] ModificationDescriptorBytes,
ref Byte[] ModifiedDescriptorBytes)
{
fixed (Byte *S = SecurityDescriptorBytes)
fixed (Byte *M = ModificationDescriptorBytes)
{
IntPtr SecurityDescriptor;
Int32 Result = FspSetSecurityDescriptor(
(IntPtr)S, SecurityInformation, (IntPtr)M, out SecurityDescriptor);
if (0 > Result)
return Result;
SecurityDescriptorBytes = MakeSecurityDescriptor(SecurityDescriptor);
FspDeleteSecurityDescriptor(SecurityDescriptor, _FspSetSecurityDescriptorPtr);
ModifiedDescriptorBytes = SecurityDescriptorBytes;
return 0/*STATUS_SUCCESS*/;
}
}
internal unsafe static Int32 CopyReparsePoint( internal unsafe static Int32 CopyReparsePoint(
Byte[] ReparseData, Byte[] ReparseData,

View File

@ -72,8 +72,8 @@ static int call_pipe_and_report(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
NTSTATUS Result; NTSTATUS Result;
DWORD LastError, BytesTransferred; DWORD LastError, BytesTransferred;
Result = FspCallNamedPipeSecurely(L"" FSP_LAUNCH_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize, Result = FspCallNamedPipeSecurelyEx(L"" FSP_LAUNCH_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize,
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, FSP_LAUNCH_PIPE_OWNER); &BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, TRUE, FSP_LAUNCH_PIPE_OWNER);
LastError = FspWin32FromNtStatus(Result); LastError = FspWin32FromNtStatus(Result);
if (0 != LastError) if (0 != LastError)

View File

@ -255,6 +255,7 @@ exit:
static BOOL LogonCreateProcess( static BOOL LogonCreateProcess(
PWSTR UserName, PWSTR UserName,
HANDLE Token,
LPCWSTR ApplicationName, LPCWSTR ApplicationName,
LPWSTR CommandLine, LPWSTR CommandLine,
LPSECURITY_ATTRIBUTES ProcessAttributes, LPSECURITY_ATTRIBUTES ProcessAttributes,
@ -271,11 +272,20 @@ static BOOL LogonCreateProcess(
if (0 != UserName) if (0 != UserName)
{ {
if (0 == invariant_wcsicmp(UserName, L"LocalSystem")) if (0 == invariant_wcsicmp(UserName, L"LocalSystem"))
{
UserName = 0; UserName = 0;
Token = 0;
}
else else
if (0 == invariant_wcsicmp(UserName, L"LocalService") || if (0 == invariant_wcsicmp(UserName, L"LocalService") ||
0 == invariant_wcsicmp(UserName, L"NetworkService")) 0 == invariant_wcsicmp(UserName, L"NetworkService"))
{
DomainName = L"NT AUTHORITY"; DomainName = L"NT AUTHORITY";
Token = 0;
}
else
if (0 == invariant_wcsicmp(UserName, L"."))
;
else else
{ {
SetLastError(ERROR_ACCESS_DENIED); SetLastError(ERROR_ACCESS_DENIED);
@ -299,9 +309,12 @@ static BOOL LogonCreateProcess(
HANDLE LogonToken = 0; HANDLE LogonToken = 0;
PVOID EnvironmentBlock = 0; PVOID EnvironmentBlock = 0;
DWORD SessionId;
DWORD LastError; DWORD LastError;
BOOL Success; BOOL Success;
if (0 == Token)
{
Success = LogonUserW( Success = LogonUserW(
UserName, UserName,
DomainName, DomainName,
@ -311,6 +324,25 @@ static BOOL LogonCreateProcess(
&LogonToken); &LogonToken);
if (!Success) if (!Success)
goto exit; goto exit;
}
else
{
/* convert the impersonation token to a primary token */
Success = DuplicateTokenEx(Token,
TOKEN_ALL_ACCESS,
0,
SecurityAnonymous,
TokenPrimary,
&LogonToken);
if (!Success)
goto exit;
if (!ProcessIdToSessionId(GetCurrentProcessId(), &SessionId))
SessionId = 0;
/* place the duplicated token in the service session (session 0) */
Success = SetTokenInformation(LogonToken, TokenSessionId, &SessionId, sizeof SessionId);
if (!Success)
goto exit;
}
if (0 == Environment) if (0 == Environment)
{ {
@ -663,7 +695,7 @@ static NTSTATUS SvcInstanceAccessCheck(HANDLE ClientToken, ULONG DesiredAccess,
return Result; return Result;
} }
static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
PWSTR Executable, PWSTR CommandLine, PWSTR WorkDirectory, PWSTR Executable, PWSTR CommandLine, PWSTR WorkDirectory,
HANDLE StdioHandles[2], HANDLE StdioHandles[2],
PPROCESS_INFORMATION ProcessInfo) PPROCESS_INFORMATION ProcessInfo)
@ -758,7 +790,7 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName,
StartupInfoEx.StartupInfo.hStdOutput = ChildHandles[1]; StartupInfoEx.StartupInfo.hStdOutput = ChildHandles[1];
StartupInfoEx.StartupInfo.hStdError = ChildHandles[2]; StartupInfoEx.StartupInfo.hStdError = ChildHandles[2];
if (!LogonCreateProcess(UserName, if (!LogonCreateProcess(UserName, ClientToken,
Executable, CommandLine, 0, 0, TRUE, Executable, CommandLine, 0, 0, TRUE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT, CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT,
0, WorkDirectory, 0, WorkDirectory,
@ -779,7 +811,7 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName,
* Not ideal, but... * Not ideal, but...
*/ */
StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx.StartupInfo; StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx.StartupInfo;
if (!LogonCreateProcess(UserName, if (!LogonCreateProcess(UserName, ClientToken,
Executable, CommandLine, 0, 0, TRUE, Executable, CommandLine, 0, 0, TRUE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP, CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP,
0, WorkDirectory, 0, WorkDirectory,
@ -792,7 +824,7 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName,
} }
else else
{ {
if (!LogonCreateProcess(UserName, if (!LogonCreateProcess(UserName, ClientToken,
Executable, CommandLine, 0, 0, FALSE, Executable, CommandLine, 0, 0, FALSE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP, CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP,
0, WorkDirectory, 0, WorkDirectory,
@ -1009,7 +1041,7 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
Result = SvcInstanceCreateProcess(L'\0' != RunAsBuf[0] ? RunAsBuf : 0, Result = SvcInstanceCreateProcess(L'\0' != RunAsBuf[0] ? RunAsBuf : 0, ClientToken,
Executable, SvcInstance->CommandLine, L'\0' != WorkDirectory[0] ? WorkDirectory : 0, Executable, SvcInstance->CommandLine, L'\0' != WorkDirectory[0] ? WorkDirectory : 0,
RedirectStdio ? SvcInstance->StdioHandles : 0, &ProcessInfo); RedirectStdio ? SvcInstance->StdioHandles : 0, &ProcessInfo);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
@ -1629,7 +1661,10 @@ static DWORD WINAPI SvcPipeServer(PVOID Context)
ClientToken = 0; ClientToken = 0;
if (!ImpersonateNamedPipeClient(SvcPipe) || if (!ImpersonateNamedPipeClient(SvcPipe) ||
!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &ClientToken) || (
!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_DUPLICATE, FALSE, &ClientToken) &&
!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &ClientToken)
) ||
!RevertToSelf()) !RevertToSelf())
{ {
LastError = GetLastError(); LastError = GetLastError();

View File

@ -21,6 +21,8 @@
#include <sys/driver.h> #include <sys/driver.h>
static NTSTATUS FspFsvrtDeviceControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolDeviceControl( static NTSTATUS FspFsvolDeviceControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolDeviceControlComplete; FSP_IOCMPL_DISPATCH FspFsvolDeviceControlComplete;
@ -28,6 +30,7 @@ static FSP_IOP_REQUEST_FINI FspFsvolDeviceControlRequestFini;
FSP_DRIVER_DISPATCH FspDeviceControl; FSP_DRIVER_DISPATCH FspDeviceControl;
#ifdef ALLOC_PRAGMA #ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFsvrtDeviceControl)
#pragma alloc_text(PAGE, FspFsvolDeviceControl) #pragma alloc_text(PAGE, FspFsvolDeviceControl)
#pragma alloc_text(PAGE, FspFsvolDeviceControlComplete) #pragma alloc_text(PAGE, FspFsvolDeviceControlComplete)
#pragma alloc_text(PAGE, FspFsvolDeviceControlRequestFini) #pragma alloc_text(PAGE, FspFsvolDeviceControlRequestFini)
@ -39,6 +42,28 @@ enum
RequestFileNode = 0, RequestFileNode = 0,
}; };
static NTSTATUS FspFsvrtDeviceControl(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
/*
* Fix GitHub issue #177. All credit for the investigation of this issue
* and the suggested steps to reproduce and work around the problem goes
* to GitHub user @thinkport.
*
* When Windows attempts to mount a new volume it iterates over all disk file
* systems registered with IoRegisterFileSystem. Foreign (i.e. non-WinFsp) file
* systems would in some cases attempt to mount our Fsvrt volume device by
* sending it unknown IOCTL codes, which would then be failed with
* STATUS_INVALID_DEVICE_REQUEST. Unfortunately the file systems would then
* report this error code to the I/O Manager, which would cause it to abort the
* mounting process completely and thus WinFsp would never get a chance to
* mount its own volume device!
*/
return STATUS_UNRECOGNIZED_VOLUME;
}
static NTSTATUS FspFsvolDeviceControl( static NTSTATUS FspFsvolDeviceControl(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{ {
@ -155,6 +180,8 @@ NTSTATUS FspDeviceControl(
{ {
case FspFsvolDeviceExtensionKind: case FspFsvolDeviceExtensionKind:
FSP_RETURN(Result = FspFsvolDeviceControl(DeviceObject, Irp, IrpSp)); FSP_RETURN(Result = FspFsvolDeviceControl(DeviceObject, Irp, IrpSp));
case FspFsvrtDeviceExtensionKind:
FSP_RETURN(Result = FspFsvrtDeviceControl(DeviceObject, Irp, IrpSp));
default: default:
FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST); FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST);
} }

View File

@ -169,6 +169,21 @@ NTSTATUS DriverEntry(
&FspFsmupDeviceObject); &FspFsmupDeviceObject);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
#if DBG
/*
* Fix GitHub issue #177. All credit for the investigation of this issue
* and the suggested steps to reproduce and work around the problem goes
* to GitHub user @thinkport.
*
* On debug builds set DO_LOW_PRIORITY_FILESYSTEM to place the file system
* at the end of the file system list during IoRegisterFileSystem below.
* This allows us to test the behavior of our Fsvrt devices when foreign
* file systems attempt to use them for mounting.
*/
SetFlag(FspFsctlDiskDeviceObject->Flags, DO_LOW_PRIORITY_FILESYSTEM);
#endif
Result = FspDeviceInitialize(FspFsctlDiskDeviceObject); Result = FspDeviceInitialize(FspFsctlDiskDeviceObject);
ASSERT(STATUS_SUCCESS == Result); ASSERT(STATUS_SUCCESS == Result);
Result = FspDeviceInitialize(FspFsctlNetDeviceObject); Result = FspDeviceInitialize(FspFsctlNetDeviceObject);

View File

@ -725,13 +725,13 @@ exit /b 0
:sample-passthrough-fuse3-x64 :sample-passthrough-fuse3-x64
call :__run_sample_fuse_test passthrough-fuse3 x64 passthrough-fuse3-x64 winfsp-tests-x64 ^ call :__run_sample_fuse_test passthrough-fuse3 x64 passthrough-fuse3-x64 winfsp-tests-x64 ^
"-create_fileattr_test -setfileinfo_test" "-create_fileattr_test -create_readonlydir_test -setfileinfo_test"
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
:sample-passthrough-fuse3-x86 :sample-passthrough-fuse3-x86
call :__run_sample_fuse_test passthrough-fuse3 x86 passthrough-fuse3-x86 winfsp-tests-x86 ^ call :__run_sample_fuse_test passthrough-fuse3 x86 passthrough-fuse3-x86 winfsp-tests-x86 ^
"-create_fileattr_test -setfileinfo_test" "-create_fileattr_test -create_readonlydir_test -setfileinfo_test"
if !ERRORLEVEL! neq 0 goto fail if !ERRORLEVEL! neq 0 goto fail
exit /b 0 exit /b 0
@ -923,7 +923,7 @@ cd L: >nul 2>nul || (echo Unable to find drive L: >&2 & goto fail)
L: L:
"%ProjRoot%\build\VStudio\build\%Configuration%\%3.exe" ^ "%ProjRoot%\build\VStudio\build\%Configuration%\%3.exe" ^
--external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^ --external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^
-create_fileattr_test -create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^ -create_fileattr_test -create_readonlydir_test -create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^
-getfileinfo_name_test -setfileinfo_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test -querydir_namelen_test -exec_rename_dir_test ^ -getfileinfo_name_test -setfileinfo_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test -querydir_namelen_test -exec_rename_dir_test ^
-reparse* -stream* -reparse* -stream*
if !ERRORLEVEL! neq 0 set RunSampleTestExit=1 if !ERRORLEVEL! neq 0 set RunSampleTestExit=1

View File

@ -783,10 +783,8 @@ namespace memfs
if (null != FileNode.MainFileNode) if (null != FileNode.MainFileNode)
FileNode = FileNode.MainFileNode; FileNode = FileNode.MainFileNode;
FileNode.FileSecurity = ModifySecurityDescriptor( return ModifySecurityDescriptorEx(FileNode.FileSecurity, Sections, SecurityDescriptor,
FileNode.FileSecurity, Sections, SecurityDescriptor); ref FileNode.FileSecurity);
return STATUS_SUCCESS;
} }
public override Boolean ReadDirectoryEntry( public override Boolean ReadDirectoryEntry(

View File

@ -352,6 +352,68 @@ static void create_fileattr_test(void)
create_fileattr_dotest(MemfsNet, L"\\\\memfs\\share"); create_fileattr_dotest(MemfsNet, L"\\\\memfs\\share");
} }
static void create_readonlydir_dotest(ULONG Flags, PWSTR Prefix)
{
void *memfs = memfs_start(Flags);
HANDLE Handle;
BOOLEAN Success;
DWORD FileAttributes;
WCHAR DirPath[MAX_PATH], FilePath[MAX_PATH];
StringCbPrintfW(DirPath, sizeof DirPath, L"%s%s\\dir0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0\\file0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = CreateDirectoryW(DirPath, 0);
ASSERT(Success);
Success = SetFileAttributesW(DirPath, FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY);
ASSERT(Success);
FileAttributes = GetFileAttributesW(DirPath);
ASSERT((FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY) == FileAttributes);
Handle = CreateFileW(FilePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
Success = DeleteFileW(FilePath);
ASSERT(Success);
Success = RemoveDirectoryW(DirPath);
ASSERT(!Success);
ASSERT(ERROR_ACCESS_DENIED == GetLastError());
Success = SetFileAttributesW(DirPath, FILE_ATTRIBUTE_DIRECTORY);
ASSERT(Success);
FileAttributes = GetFileAttributesW(DirPath);
ASSERT(FILE_ATTRIBUTE_DIRECTORY == FileAttributes);
Success = RemoveDirectoryW(DirPath);
ASSERT(Success);
memfs_stop(memfs);
}
static void create_readonlydir_test(void)
{
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf);
create_readonlydir_dotest(-1, DirBuf);
}
if (WinFspDiskTests)
create_readonlydir_dotest(MemfsDisk, 0);
if (WinFspNetTests)
create_readonlydir_dotest(MemfsNet, L"\\\\memfs\\share");
}
void create_related_dotest(ULONG Flags, PWSTR Prefix) void create_related_dotest(ULONG Flags, PWSTR Prefix)
{ {
void *memfs = memfs_start(Flags); void *memfs = memfs_start(Flags);
@ -1265,6 +1327,7 @@ void create_tests(void)
{ {
TEST(create_test); TEST(create_test);
TEST(create_fileattr_test); TEST(create_fileattr_test);
TEST(create_readonlydir_test);
TEST(create_related_test); TEST(create_related_test);
TEST(create_allocation_test); TEST(create_allocation_test);
TEST(create_sd_test); TEST(create_sd_test);