Compare commits

...

19 Commits
v1.4B3 ... v1.4

Author SHA1 Message Date
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
20 changed files with 503 additions and 75 deletions

View File

@ -1,6 +1,42 @@
= Changelog
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)::
Changes since v1.3:

View File

@ -18,8 +18,8 @@
<MyCanonicalVersion>1.4</MyCanonicalVersion>
<MyProductVersion>2018.2 B3</MyProductVersion>
<MyProductStage>Beta</MyProductStage>
<MyProductVersion>2019.1</MyProductVersion>
<MyProductStage>Gold</MyProductStage>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
<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>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<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>
</Link>
</ItemDefinitionGroup>
@ -250,7 +250,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<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>
</Link>
</ItemDefinitionGroup>
@ -281,7 +281,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<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>
</Link>
</ItemDefinitionGroup>
@ -312,7 +312,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<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>
</Link>
</ItemDefinitionGroup>

View File

@ -111,7 +111,43 @@ enum
*/
FSP_API NTSTATUS FspLaunchCallLauncherPipe(
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.
*
@ -138,6 +174,35 @@ FSP_API NTSTATUS FspLaunchStart(
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv,
BOOLEAN HasSecret,
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.
*
@ -221,10 +286,12 @@ typedef struct _FSP_LAUNCH_REG_RECORD
PWSTR WorkDirectory;
PWSTR RunAs;
PWSTR Security;
PVOID Reserved0[6];
PWSTR AuthPackage;
PVOID Reserved0[5];
ULONG JobControl;
ULONG Credentials;
ULONG Reserved1[6];
ULONG AuthPackageId;
ULONG Reserved1[5];
UINT8 Buffer[];
} FSP_LAUNCH_REG_RECORD;
#pragma warning(pop)

View File

@ -1795,6 +1795,10 @@ FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize,
PULONG PBytesTransferred, ULONG Timeout,
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);
/*

View File

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

View File

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

View File

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

View File

@ -23,6 +23,9 @@
#include <npapi.h>
#include <wincred.h>
#define _NTDEF_
#include <ntsecapi.h>
#define FSP_NP_NAME LIBRARY_NAME ".Np"
#define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */
#define FSP_NP_ADDCONNECTION_TIMEOUT 15000
@ -179,12 +182,14 @@ static inline BOOLEAN FspNpParseRemoteUserName(PWSTR RemoteName,
static inline DWORD FspNpCallLauncherPipe(
WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl,
PWSTR Buffer, PULONG PSize)
PWSTR Buffer, PULONG PSize,
BOOLEAN AllowImpersonation)
{
NTSTATUS Result;
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) ?
WN_NO_NETWORK :
(ERROR_BROKEN_PIPE == ErrorCode ? WN_NO_NETWORK : ErrorCode);
@ -251,7 +256,50 @@ static WCHAR FspNpGetDriveLetter(PDWORD PLogicalDrives, PWSTR VolumeName)
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;
ULONG ClassNameLen, InstanceNameLen;
@ -259,7 +307,14 @@ static DWORD FspNpGetRemoteInfo(PWSTR RemoteName, PDWORD PCredentialsKind)
FSP_LAUNCH_REG_RECORD *Record;
NTSTATUS Result;
*PCredentialsKind = FSP_NP_CREDENTIALS_NONE;
if (0 != PAuthPackage)
*PAuthPackage = 0;
if (0 != PCredentialsKind)
*PCredentialsKind = FSP_NP_CREDENTIALS_NONE;
if (0 != PAllowImpersonation)
*PAllowImpersonation = FALSE;
if (!FspNpParseRemoteName(RemoteName,
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
@ -274,15 +329,36 @@ static DWORD FspNpGetRemoteInfo(PWSTR RemoteName, PDWORD PCredentialsKind)
if (!NT_SUCCESS(Result))
return WN_NO_NETWORK;
switch (Record->Credentials)
if (0 != PAuthPackage)
{
case FSP_NP_CREDENTIALS_NONE:
case FSP_NP_CREDENTIALS_PASSWORD:
case FSP_NP_CREDENTIALS_USERPASS:
*PCredentialsKind = Record->Credentials;
break;
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)
{
case FSP_NP_CREDENTIALS_NONE:
case FSP_NP_CREDENTIALS_PASSWORD:
case FSP_NP_CREDENTIALS_USERPASS:
*PCredentialsKind = Record->Credentials;
break;
}
if (0 != PAllowImpersonation)
*PAllowImpersonation = 0 != Record->RunAs &&
L'.' == Record->RunAs[0] && L'\0' == Record->RunAs[1];
FspLaunchRegFreeRecord(Record);
return WN_SUCCESS;
@ -290,7 +366,7 @@ static DWORD FspNpGetRemoteInfo(PWSTR RemoteName, PDWORD PCredentialsKind)
static DWORD FspNpGetCredentials(
HWND hwndOwner, PWSTR Caption, DWORD PrevNpResult,
DWORD CredentialsKind,
DWORD AuthPackage0, DWORD CredentialsKind,
PBOOL PSave,
PWSTR UserName, ULONG UserNameSize/* 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));
#else
WCHAR Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1];
ULONG AuthPackage = 0;
ULONG AuthPackage = 0 != AuthPackage0 ? AuthPackage0 - 1 : 0;
PVOID InAuthBuf = 0, OutAuthBuf = 0;
ULONG InAuthSize, OutAuthSize, DomainSize;
@ -346,7 +422,8 @@ static DWORD FspNpGetCredentials(
NpResult = CredUIPromptForWindowsCredentialsW(&UiInfo, PrevNpResult,
&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)
goto exit;
@ -464,6 +541,7 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
PWSTR ClassName, InstanceName, RemoteName, P;
ULONG ClassNameLen, InstanceNameLen;
DWORD CredentialsKind;
BOOLEAN AllowImpersonation;
ULONG Argc;
PWSTR Argv[6];
ULONG Argl[6];
@ -493,7 +571,7 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
return WN_ALREADY_CONNECTED;
}
NpResult = FspNpGetRemoteInfo(lpRemoteName, &CredentialsKind);
NpResult = FspNpGetRemoteInfo(lpRemoteName, 0, &CredentialsKind, &AllowImpersonation);
if (WN_SUCCESS != NpResult)
return NpResult;
@ -550,7 +628,8 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
NpResult = FspNpCallLauncherPipe(
FSP_NP_CREDENTIALS_NONE != CredentialsKind ? FspLaunchCmdStartWithSecret : FspLaunchCmdStart,
Argc, Argv, Argl, 0, 0);
Argc, Argv, Argl, 0, 0,
AllowImpersonation);
switch (NpResult)
{
case WN_SUCCESS:
@ -602,7 +681,8 @@ DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword,
if (WN_SUCCESS != FspNpCallLauncherPipe(
FspLaunchCmdGetInfo,
Argc, Argv, Argl, 0, 0))
Argc, Argv, Argl, 0, 0,
FALSE))
{
/* looks like the file system is gone! */
NpResult = WN_NO_NETWORK;
@ -659,7 +739,7 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
{
DWORD NpResult;
PWSTR RemoteName = lpNetResource->lpRemoteName;
DWORD CredentialsKind;
DWORD AuthPackage, CredentialsKind;
WCHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1], Password[CREDUI_MAX_PASSWORD_LENGTH + 1];
#if defined(FSP_NP_CREDENTIAL_MANAGER)
BOOL Save = TRUE;
@ -679,7 +759,7 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
return NpResult;
}
NpResult = FspNpGetRemoteInfo(RemoteName, &CredentialsKind);
NpResult = FspNpGetRemoteInfo(RemoteName, &AuthPackage, &CredentialsKind, 0);
if (WN_SUCCESS != NpResult)
return NpResult;
if (FSP_NP_CREDENTIALS_NONE == CredentialsKind)
@ -695,7 +775,7 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
{
NpResult = FspNpGetCredentials(
hwndOwner, RemoteName, NpResult,
CredentialsKind,
AuthPackage, CredentialsKind,
#if defined(FSP_NP_CREDENTIAL_MANAGER)
&Save,
#else
@ -766,7 +846,8 @@ DWORD APIENTRY NPCancelConnection(LPWSTR lpName, BOOL fForce)
NpResult = FspNpCallLauncherPipe(
FspLaunchCmdStop,
Argc, Argv, Argl, 0, 0);
Argc, Argv, Argl, 0, 0,
FALSE);
switch (NpResult)
{
case WN_SUCCESS:

View File

@ -341,26 +341,25 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
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;
goto exit;
}
if (Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE)
{
Result = STATUS_CANNOT_DELETE;
goto exit;
}
Result = STATUS_ACCESS_DENIED;
goto exit;
}
if (FILE_ATTRIBUTE_READONLY == (FileAttributes & FILE_ATTRIBUTE_READONLY) &&
(Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE))
{
Result = STATUS_CANNOT_DELETE;
goto exit;
}
if (0 == SecurityDescriptorSize)
*PGrantedAccess = (MAXIMUM_ALLOWED & 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))
*PGrantedAccess &= ~(FILE_WRITE_DATA | FILE_APPEND_DATA |
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,
PULONG PBytesTransferred, ULONG Timeout,
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;
HANDLE Pipe = INVALID_HANDLE_VALUE;
@ -75,7 +85,8 @@ FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
Pipe = CreateFileW(PipeName,
GENERIC_READ | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES,
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 (ERROR_PIPE_BUSY != GetLastError())
@ -89,7 +100,8 @@ FSP_API NTSTATUS FspCallNamedPipeSecurely(PWSTR PipeName,
Pipe = CreateFileW(PipeName,
GENERIC_READ | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES,
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)
{
Result = FspNtStatusFromWin32(GetLastError());

View File

@ -707,7 +707,7 @@ namespace Fsp
/// Describes the modifications to apply to the file or directory security descriptor.
/// </param>
/// <returns>STATUS_SUCCESS or error code.</returns>
/// <seealso cref="ModifySecurityDescriptor"/>
/// <seealso cref="ModifySecurityDescriptorEx"/>
public virtual Int32 SetSecurity(
Object FileNode,
Object FileDesc,
@ -1105,7 +1105,7 @@ namespace Fsp
return (int)Api.FspFileSystemOperationProcessId();
}
/// <summary>
/// Modifies a security descriptor.
/// Modifies a security descriptor. [OBSOLETE]
/// </summary>
/// <remarks>
/// This is a helper for implementing the SetSecurity operation.
@ -1121,6 +1121,7 @@ namespace Fsp
/// </param>
/// <returns>The modified security descriptor.</returns>
/// <seealso cref="SetSecurity"/>
[Obsolete("use ModifySecurityDescriptorEx")]
public static byte[] ModifySecurityDescriptor(
Byte[] SecurityDescriptor,
AccessControlSections Sections,
@ -1140,6 +1141,47 @@ namespace Fsp
SecurityInformation,
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(
Object FileNode,
Object FileDesc,

View File

@ -928,6 +928,26 @@ namespace Fsp.Interop
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(
Byte[] ReparseData,

View File

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

View File

@ -255,6 +255,7 @@ exit:
static BOOL LogonCreateProcess(
PWSTR UserName,
HANDLE Token,
LPCWSTR ApplicationName,
LPWSTR CommandLine,
LPSECURITY_ATTRIBUTES ProcessAttributes,
@ -271,11 +272,20 @@ static BOOL LogonCreateProcess(
if (0 != UserName)
{
if (0 == invariant_wcsicmp(UserName, L"LocalSystem"))
{
UserName = 0;
Token = 0;
}
else
if (0 == invariant_wcsicmp(UserName, L"LocalService") ||
0 == invariant_wcsicmp(UserName, L"NetworkService"))
{
DomainName = L"NT AUTHORITY";
Token = 0;
}
else
if (0 == invariant_wcsicmp(UserName, L"."))
;
else
{
SetLastError(ERROR_ACCESS_DENIED);
@ -299,18 +309,40 @@ static BOOL LogonCreateProcess(
HANDLE LogonToken = 0;
PVOID EnvironmentBlock = 0;
DWORD SessionId;
DWORD LastError;
BOOL Success;
Success = LogonUserW(
UserName,
DomainName,
0,
LOGON32_LOGON_SERVICE,
LOGON32_PROVIDER_DEFAULT,
&LogonToken);
if (!Success)
goto exit;
if (0 == Token)
{
Success = LogonUserW(
UserName,
DomainName,
0,
LOGON32_LOGON_SERVICE,
LOGON32_PROVIDER_DEFAULT,
&LogonToken);
if (!Success)
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)
{
@ -663,7 +695,7 @@ static NTSTATUS SvcInstanceAccessCheck(HANDLE ClientToken, ULONG DesiredAccess,
return Result;
}
static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName,
static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName, HANDLE ClientToken,
PWSTR Executable, PWSTR CommandLine, PWSTR WorkDirectory,
HANDLE StdioHandles[2],
PPROCESS_INFORMATION ProcessInfo)
@ -758,7 +790,7 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName,
StartupInfoEx.StartupInfo.hStdOutput = ChildHandles[1];
StartupInfoEx.StartupInfo.hStdError = ChildHandles[2];
if (!LogonCreateProcess(UserName,
if (!LogonCreateProcess(UserName, ClientToken,
Executable, CommandLine, 0, 0, TRUE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT,
0, WorkDirectory,
@ -779,7 +811,7 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName,
* Not ideal, but...
*/
StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx.StartupInfo;
if (!LogonCreateProcess(UserName,
if (!LogonCreateProcess(UserName, ClientToken,
Executable, CommandLine, 0, 0, TRUE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP,
0, WorkDirectory,
@ -792,7 +824,7 @@ static NTSTATUS SvcInstanceCreateProcess(PWSTR UserName,
}
else
{
if (!LogonCreateProcess(UserName,
if (!LogonCreateProcess(UserName, ClientToken,
Executable, CommandLine, 0, 0, FALSE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP,
0, WorkDirectory,
@ -1009,7 +1041,7 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
if (!NT_SUCCESS(Result))
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,
RedirectStdio ? SvcInstance->StdioHandles : 0, &ProcessInfo);
if (!NT_SUCCESS(Result))
@ -1629,7 +1661,10 @@ static DWORD WINAPI SvcPipeServer(PVOID Context)
ClientToken = 0;
if (!ImpersonateNamedPipeClient(SvcPipe) ||
!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &ClientToken) ||
(
!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_DUPLICATE, FALSE, &ClientToken) &&
!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &ClientToken)
) ||
!RevertToSelf())
{
LastError = GetLastError();

View File

@ -21,6 +21,8 @@
#include <sys/driver.h>
static NTSTATUS FspFsvrtDeviceControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolDeviceControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolDeviceControlComplete;
@ -28,6 +30,7 @@ static FSP_IOP_REQUEST_FINI FspFsvolDeviceControlRequestFini;
FSP_DRIVER_DISPATCH FspDeviceControl;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFsvrtDeviceControl)
#pragma alloc_text(PAGE, FspFsvolDeviceControl)
#pragma alloc_text(PAGE, FspFsvolDeviceControlComplete)
#pragma alloc_text(PAGE, FspFsvolDeviceControlRequestFini)
@ -39,6 +42,28 @@ enum
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(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
@ -155,6 +180,8 @@ NTSTATUS FspDeviceControl(
{
case FspFsvolDeviceExtensionKind:
FSP_RETURN(Result = FspFsvolDeviceControl(DeviceObject, Irp, IrpSp));
case FspFsvrtDeviceExtensionKind:
FSP_RETURN(Result = FspFsvrtDeviceControl(DeviceObject, Irp, IrpSp));
default:
FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST);
}

View File

@ -169,6 +169,21 @@ NTSTATUS DriverEntry(
&FspFsmupDeviceObject);
if (!NT_SUCCESS(Result))
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);
ASSERT(STATUS_SUCCESS == Result);
Result = FspDeviceInitialize(FspFsctlNetDeviceObject);

View File

@ -725,13 +725,13 @@ exit /b 0
:sample-passthrough-fuse3-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
exit /b 0
:sample-passthrough-fuse3-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
exit /b 0
@ -923,7 +923,7 @@ cd L: >nul 2>nul || (echo Unable to find drive L: >&2 & goto fail)
L:
"%ProjRoot%\build\VStudio\build\%Configuration%\%3.exe" ^
--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 ^
-reparse* -stream*
if !ERRORLEVEL! neq 0 set RunSampleTestExit=1

View File

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

View File

@ -352,6 +352,68 @@ static void create_fileattr_test(void)
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 *memfs = memfs_start(Flags);
@ -1265,6 +1327,7 @@ void create_tests(void)
{
TEST(create_test);
TEST(create_fileattr_test);
TEST(create_readonlydir_test);
TEST(create_related_test);
TEST(create_allocation_test);
TEST(create_sd_test);