Compare commits

..

69 Commits
v0.12 ... v0.15

Author SHA1 Message Date
858df29ba2 Merge branch 'master' of https://github.com/billziss-gh/winfsp 2016-07-28 23:51:34 -07:00
4366866653 launcher: SvcInstanceStart: STATUS_TIMEOUT is not error; handle it correctly 2016-07-28 23:50:49 -07:00
e4b808806c Update README.md 2016-07-28 17:03:47 -07:00
13cee6e019 Update Changelog 2016-07-28 16:54:07 -07:00
35b9cb15a3 tst: do not test for read-only buffer during Write when not on Win8+ 2016-07-28 16:37:49 -07:00
0d8f0f9ac8 Merge branch 'master' of https://bitbucket.org/billziss/winfsp 2016-07-28 14:56:40 -07:00
a4e2ad9dd6 dll: FspFsctlStop: fix problem in call to DeviceIoControl
- The DeviceIoControl was invoked in an incorrect fashion that nevertheless worked in Win64, but not Win32.
2016-07-28 14:56:06 -07:00
9b4318c655 sys: fix request header alignment on 32-bit builds 2016-07-28 09:57:31 -07:00
5827b1fa9c sys: fixes for Win7 x86 2016-07-28 00:03:53 -07:00
913f7ac9cd dll: suppress compiler warning on x86 builds 2016-07-27 16:25:41 -07:00
0e2f46dc90 Define NTDDI_VERSION,_WIN32_WINNT; remove GetOverlappedResultEx
- Ensures that only Vista+ DDI/API's are used
- Project should now run on Win 7
2016-07-27 16:15:28 -07:00
e7cba96c74 Update README 2016-07-21 14:08:00 -07:00
03db443406 Update README 2016-07-20 23:41:55 -07:00
0b65bc7e01 Update README 2016-07-19 21:08:02 -07:00
12e1caaa98 Update README 2016-07-19 21:02:14 -07:00
7a690a789b Update README 2016-07-19 12:21:21 -07:00
8ca419830c art: installer banners 2016-07-17 16:55:12 -07:00
c310d8ea1b art: installer banners 2016-07-17 16:46:54 -07:00
c3ddf73661 art: add installer banners 2016-07-17 16:26:47 -07:00
6b00b8e28a art: add winfsp icon and installer banners 2016-07-17 16:24:21 -07:00
35c722e91b appveyor: enable verifier for FSD 2016-07-15 23:10:44 -07:00
ae8802514b appveyor: enable verifier for FSD 2016-07-15 23:04:45 -07:00
e90aa46a27 build: bump version to 0.15 2016-07-15 22:43:40 -07:00
760cd5e46f opt: cygfuse: bump release number to 3 2016-07-15 17:58:17 -07:00
b36b6c60e2 inc: fuse: allow for future expansion of fsp_fuse_env 2016-07-15 17:52:24 -07:00
e4984bf675 doc: update Changelog 2016-07-15 17:49:08 -07:00
0c8bcd5d7d doc: update Changelog 2016-07-15 17:39:57 -07:00
b5d8cd3ea6 installer: wix: avoid using autogenerated GUID for INSTALLDIR component 2016-07-14 11:13:26 -07:00
af5f409233 dll: np: improve username/password prompts 2016-07-13 23:19:11 -07:00
cffb066d46 ext/test/winfstest: fix build with VS2015 Update 3 2016-07-11 21:21:05 -07:00
804434d836 dll: fuse: respect the uid,gid,umask options which were being ignored 2016-06-30 23:47:01 -07:00
f7595e40b6 dll: np: FSP_NP_CREDENTIAL_MANAGER 2016-06-29 23:31:07 -07:00
669dd07ce2 dll: np: credentials testing 2016-06-29 22:35:00 -07:00
b6fa54d301 update Changelog 2016-06-29 18:09:06 -07:00
342e7e39e2 tst: secret: small program to aid with testing launcher secrets 2016-06-29 16:27:01 -07:00
9dfdd19616 launcher: startWithSecret testing 2016-06-29 16:10:27 -07:00
2c651b1bd8 launcher: check Credentials registry value during svc instance creation 2016-06-29 15:02:15 -07:00
41764f7b41 launcher, launchctl: fixes 2016-06-29 13:05:15 -07:00
08e697c52c launcher: send the password to service instance as UTF-8 2016-06-29 12:34:06 -07:00
66cc043149 dll: np: credentials support 2016-06-29 12:18:53 -07:00
518cd0e8c0 launcher, launchctl: StartWithSecret 2016-06-28 23:09:10 -07:00
c0344f53b0 Merge branch 'master' into launchpass 2016-06-28 12:10:27 -07:00
76445a5403 bump version to 0.14 2016-06-28 12:10:08 -07:00
0577b8febb dll: posix: use the S-1-0-65534 <-> 65534 for the unmapped SID/UID 2016-06-28 11:45:35 -07:00
610a7ac2a6 dll: np: support launcher passwords: WIP 2016-06-28 11:26:25 -07:00
e33fda4d00 doc: Changelog 2016-06-25 16:26:56 -07:00
2151e193dc doc: Changelog 2016-06-25 16:25:14 -07:00
ccfaf04f76 opt: cygfuse: libfuse.dll.a symlink 2016-06-24 22:25:25 -07:00
7e8d9fb986 dll: posix: map unmapped UID to S-1-5-7 (Anonymous) 2016-06-24 16:28:38 -07:00
37b6936ad0 dll: posix: FspNullSid, FspNullUid 2016-06-24 00:19:20 -07:00
3683afe203 dll: posix: FspNullSid, FspNullUid 2016-06-23 23:42:37 -07:00
a3cfc84007 inc,dll: winfsp: FSP_FILE_SYSTEM_INTERFACE
Consolidate SetFileSize/SetAllocationSize
2016-06-23 14:30:01 -07:00
ee5c584614 inc: winfsp: FSP_FILE_SYSTEM_INTERFACE: ensure it has 64 entries 2016-06-23 00:33:18 -07:00
b8b15e8035 dll: FspFileSystemSetMountPoint, FspFileSystemRemoveMountPoint
Ensure that mapped drives get cleaned up even if file system dies
2016-06-22 23:16:22 -07:00
3db09be764 opt: cygfuse: minor fix in fuse.cygport 2016-06-22 11:45:11 -07:00
f2a0eb544e opt: cygfuse: rename cygfuse.cpp to cygfuse.c and fix fork problem 2016-06-22 11:12:33 -07:00
8c1c407b34 opt: cygfuse: undef _WIN32, _WIN64 symbols before including fuse*.h 2016-06-21 21:43:02 -07:00
8dc4225ea1 opt: cygfuse: can build cygport from working tree (make cygport) 2016-06-21 21:17:39 -07:00
ed0b83c84d opt: cygfuse: fuse.cygport now provides primary VERSION 2016-06-21 14:40:18 -07:00
71c68d1e17 opt: cygfuse: fuse.cygport and related changes 2016-06-21 14:16:52 -07:00
053a5f1e4b update README 2016-06-21 10:54:52 -07:00
e5d7f4ee9a opt: cygfuse 2016-06-21 10:50:19 -07:00
d6fb076cad opt: cygfuse 2016-06-21 00:35:36 -07:00
698b711df4 doc: SSHFS Port Case Study: Step 4 2016-06-17 18:17:54 -07:00
842f649f06 update README 2016-06-17 15:28:06 -07:00
b062df9c42 update README 2016-06-17 15:26:57 -07:00
f0385e3c7d update README 2016-06-17 15:24:51 -07:00
10ce221fcc update README and rename Contributors document 2016-06-17 15:20:41 -07:00
3f3092bdae build: update version to 0.13 2016-06-17 15:12:42 -07:00
48 changed files with 1570 additions and 435 deletions

View File

@ -1,5 +1,7 @@
# WinFsp - Windows File System Proxy # WinFsp - Windows File System Proxy
![WinFsp Demo](http://www.secfs.net/winfsp/files/cap.gif)
WinFsp is a set of software components for Windows computers that allows the creation of user mode file systems. In this sense it is similar to FUSE (Filesystem in Userspace), which provides the same functionality on UNIX-like computers. WinFsp is a set of software components for Windows computers that allows the creation of user mode file systems. In this sense it is similar to FUSE (Filesystem in Userspace), which provides the same functionality on UNIX-like computers.
Some of the benefits and features of using WinFsp are listed below: Some of the benefits and features of using WinFsp are listed below:
@ -20,18 +22,54 @@ WinFsp consists of a kernel mode FSD (File System Driver) and a user mode DLL (D
The project source code is organized as follows: The project source code is organized as follows:
* build/VStudio: contains the WinFsp solution and project files. * build/VStudio: WinFsp solution and project files.
* doc: contains the WinFsp license, contributor agreement and additional documentation. The WinFsp design document can be found here. * doc: WinFsp license, contributor agreement and additional documentation. The WinFsp design documents can be found here.
* ext/tlib: contains a small test library originally from the secfs (Secure Cloud File System) project. * ext/tlib: A small test library originally from the secfs (Secure Cloud File System) project.
* inc/winfsp: contains public include files to be used when developing a user mode file system. * ext/test: Submodule pointing to the secfs.test project, which contains a number of tools for testing Windows and POSIX file systems.
* src/dll: contains the source code to the WinFsp DLL. * inc/winfsp: Public headers for the WinFsp API.
* src/sys: contains the source code to the WinFsp FSD. * inc/fuse: Public headers for the FUSE compatibility layer.
* tst/memfs: contains the source code to an example file system written in C++ (memfs). * src/dll: Source code to the WinFsp DLL.
* tst/winfsp-tests: contains the WinFsp test suite. * src/dll/fuse: Source code to the FUSE compatibility layer.
* src/launcher: Source code to the launcher service and the launchctl utility.
* src/sys: Source code to the WinFsp FSD.
* opt/cygfuse: Source code for the Cygwin FUSE package.
* tst/memfs: Source code to an example file system written in C++ (memfs).
* tst/winfsp-tests: WinFsp test suite.
## Building ## Building and Running
In order to build WinFsp you will need Windows 10 and Visual Studio 2015. You will also need the Windows Driver Kit (WDK) 10. In order to build WinFsp you will need the following:
* Windows 10
* Visual Studio 2015
* Windows Driver Kit (WDK) 10
* [Wix toolset](http://wixtoolset.org)
If you build the driver yourself it will not be signed and Windows will refuse to load it unless you enable "testsigning". You can enable "testsigning" using the command `bcdedit.exe -set testsigning`. For more information see this [document](http://www.secfs.net/winfsp/develop/debug/).
WinFsp is designed to run on Vista and above. It has been tested on the following platforms so far:
* Windows 7 Enterprise
* Windows 8 Pro
* Windows 10 Pro
* Windows Server 2012
## How to Help
I am looking for help in the following areas:
* If you have a file system that runs on FUSE please consider porting it to WinFsp. WinFsp has a native API, but it also has a FUSE (high-level) API.
* If you are working with a language other than C/C++ (e.g. Delphi, C#, etc.) and you are interested in porting/wrapping WinFsp I would love to hear from you.
* There are a number of outstanding issues listed in the [GitHub repository](https://github.com/billziss-gh/winfsp/issues) ~~[BitBucket repository](https://bitbucket.org/billziss/winfsp/issues?status=new&status=open)~~. Many of these require knowledge of Windows kernel-mode and an understanding of the internals of WinFsp so they are not for the faint of heart. If you decide to tackle any of those please coordinate with me as I am actively working on that issue list.
In all cases I can provide ideas and/or support.
## Where to Discuss
If you wish to discuss WinFsp there are now two options:
- [WinFsp Google Group](https://groups.google.com/forum/#!forum/winfsp)
- [Author's Twitter](https://twitter.com/BZissimopoulos)
## License ## License

View File

@ -6,6 +6,7 @@ environment:
install: install:
- git submodule update --init --recursive - git submodule update --init --recursive
- appveyor AddMessage "Change boot configuration and reboot" -Category Information - appveyor AddMessage "Change boot configuration and reboot" -Category Information
- verifier /standard /driver winfsp-x64.sys
- bcdedit /set testsigning on - bcdedit /set testsigning on
- ps: Restart-Computer -Force - ps: Restart-Computer -Force
- ps: Start-Sleep -s 10 - ps: Start-Sleep -s 10
@ -19,3 +20,4 @@ test_script:
- for %%f in ("build\VStudio\build\%CONFIGURATION%\winfsp-*.msi") do start /wait msiexec /i %%f /qn INSTALLLEVEL=1000 - for %%f in ("build\VStudio\build\%CONFIGURATION%\winfsp-*.msi") do start /wait msiexec /i %%f /qn INSTALLLEVEL=1000
- tools\nmake-ext-test.bat %CONFIGURATION% - tools\nmake-ext-test.bat %CONFIGURATION%
- tools\run-tests.bat %CONFIGURATION% - tools\run-tests.bat %CONFIGURATION%
- verifier /query

BIN
art/winfsp-outln.afdesign Normal file

Binary file not shown.

BIN
art/winfsp-solid.afdesign Normal file

Binary file not shown.

BIN
art/winfsp-solid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
art/wixbanner.pxm Normal file

Binary file not shown.

BIN
art/wixdialog.pxm Normal file

Binary file not shown.

View File

@ -45,13 +45,14 @@
</Directory> </Directory>
<DirectoryRef Id="INSTALLDIR"> <DirectoryRef Id="INSTALLDIR">
<Component Id="C.INSTALLDIR"> <Component Id="C.INSTALLDIR" Guid="{F876F26E-5016-4AC6-93B3-653C0312A6CE}">
<RegistryValue <RegistryValue
Root="HKLM" Root="HKLM"
Key="[P.RegistryKey]" Key="[P.RegistryKey]"
Name="InstallDir" Name="InstallDir"
Type="string" Type="string"
Value="[INSTALLDIR]" /> Value="[INSTALLDIR]"
KeyPath="yes" />
</Component> </Component>
</DirectoryRef> </DirectoryRef>
<DirectoryRef Id="BINDIR" FileSource="..\build\$(var.Configuration)"> <DirectoryRef Id="BINDIR" FileSource="..\build\$(var.Configuration)">
@ -325,6 +326,8 @@
</Feature> </Feature>
</Feature> </Feature>
<WixVariable Id="WixUIBannerBmp" Value="wixbanner.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="wixdialog.bmp" />
<UI Id="FeatureTree"> <UI Id="FeatureTree">
<UIRef Id="WixUI_FeatureTree" /> <UIRef Id="WixUI_FeatureTree" />
<!-- skip the license agreement dialog; higher Order takes priority (weird) --> <!-- skip the license agreement dialog; higher Order takes priority (weird) -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 KiB

View File

@ -110,6 +110,7 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -128,6 +129,7 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -149,6 +151,7 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -170,6 +173,7 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>

View File

@ -7,7 +7,12 @@
<MyCopyright>2015-2016 Bill Zissimopoulos</MyCopyright> <MyCopyright>2015-2016 Bill Zissimopoulos</MyCopyright>
<!-- build number: concat 2-digit year with 3-digit day of the year (16-bits until 2066) --> <!-- build number: concat 2-digit year with 3-digit day of the year (16-bits until 2066) -->
<MyBuildNumber>$([System.DateTime]::Now.ToString(`yy`))$([System.DateTime]::Now.DayOfYear.ToString(`000`))</MyBuildNumber> <MyBuildNumber>$([System.DateTime]::Now.ToString(`yy`))$([System.DateTime]::Now.DayOfYear.ToString(`000`))</MyBuildNumber>
<MyVersion>0.12.$(MyBuildNumber)</MyVersion> <MyVersion>0.15.$(MyBuildNumber)</MyVersion>
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas> <MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>NTDDI_VERSION=0x06000000;_WIN32_WINNT=0x0600</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
</Project> </Project>

View File

@ -182,7 +182,7 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
<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);version.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);credui.lib;version.lib</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -207,7 +207,7 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
<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);version.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);credui.lib;version.lib</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -235,7 +235,7 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
<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);version.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);credui.lib;version.lib</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -263,7 +263,7 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
<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);version.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);credui.lib;version.lib</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -34,6 +34,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion> <TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType> <ConfigurationType>Driver</ConfigurationType>
<DriverType>WDM</DriverType> <DriverType>WDM</DriverType>
@ -41,6 +42,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion> <TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType> <ConfigurationType>Driver</ConfigurationType>
<DriverType>WDM</DriverType> <DriverType>WDM</DriverType>
@ -48,6 +50,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion> <TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType> <ConfigurationType>Driver</ConfigurationType>
<DriverType>WDM</DriverType> <DriverType>WDM</DriverType>
@ -55,6 +58,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion> <TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib</KernelBufferOverflowLib>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType> <ConfigurationType>Driver</ConfigurationType>
<DriverType>WDM</DriverType> <DriverType>WDM</DriverType>

32
doc/Changelog.adoc Normal file
View File

@ -0,0 +1,32 @@
= Changelog
v0.15::
This is a minor release that brings support for Windows 7 and 32-bit OS'es.
- Fixes a number of issues for Windows 7. Windows 7 is now officially supported.
- Fixes a number of issues with the 32-bit FSD and user mode components. 32-bit versions of Windows are now officially supported.
v0.14::
This release includes support for file systems protected by credentials.
- WinFsp now supports file systems that require username/password to be unlocked (e.g. sshfs/secfs). Such file systems must add a DWORD registry value with name "Credentials" and value 1 under their WinFsp.Launcher service entry. The WinFsp network provider will then prompt for credentials using the `CredUIPromptForWindowsCredentials` API. Credentials can optionally be saved with the Windows Credential Manager.
- WinFsp-FUSE now uses the S-1-0-65534 <--> 65534 mapping for unmapped SID/UID's. The Anonymous SID mapping from the previous release had security issues.
v0.13::
This release includes a Cygwin package, an API change and some other minor changes:
- New Cygwin package includes `cygfuse-2.8.dll` and `libfuse-2.8.dll.a` for easy use in the Cygwin environment. This is currently offered as a separate download.
- Minor but breaking API change: `SetFileSize`/`SetAllocationSize` have been consolidated. Please refer to the documentation for a description of the changes.
- File system drive symbolic links (`DefineDosDeviceW`) now automatically cleaned up even if user mode file system crashes or is terminated forcefully.
- WinFsp-FUSE now maps unmapped UID's to the Anonymous SID (S-1-5-7). See: https://cygwin.com/ml/cygwin/2016-06/msg00359.html
v0.12::
Prior changes are not recorded in this Changelog.

View File

@ -136,3 +136,82 @@ The mappings provided are not perfect, but they come pretty close. They are also
=== WinFsp Implementation === WinFsp Implementation
A WinFsp implementation of the above mappings can be found in the file `src/dll/posix.c`. A WinFsp implementation of the above mappings can be found in the file `src/dll/posix.c`.
== Step 4: Implementing FUSE Core
We are now finally ready to implement the `fuse_operations`. This actually proves to be a straightforward mapping of the WinFSP `FSP_FILE_SYSTEM_INTERACE` to `fuse_operations`:
GetVolumeInfo:: Mapped to `statfs`. Volume labels are not supported by FUSE (see below).
SetVolumeLabel:: No equivalent on FUSE, so simply return `STATUS_INVALID_PARAMETER`. One thought is to map this call into a `setxattr("sys.VolumeLabel")` (or similar) call on the root directory (`/`).
GetSecurityByName:: Mapped to `fgetattr`/`getattr`. The returned `stat` information is translated into a Windows security descriptor using `FspPosixMapPermissionsToSecurityDescriptor`.
Create:: This is used to create a new file or directory. If a file is created this is mapped to `create` or `mknod`;`open`. If a directory is created this is mapped to `mkdir`;`opendir` calls (the reason is that on Windows a directory remains open after being created). In some circumstances a `chown` may be issued as well. After the file or directory has been created a `fgetattr`/`getattr` is issued to get `stat` information to return to the FSD.
Open:: This is used to open a new file or directory. First a `fgetattr`/`getattr` is issued. If the file is not a directory it is followed by `open`. If the file is a directory it is followed by `opendir`.
Overwrite:: This is used to overwrite a file when one of the `FILE_OVERWRITE`, `FILE_SUPERSEDE` or `FILE_OVERWRITE_IF` flags has been set. Mapped to `ftruncate`/`truncate`.
Cleanup:: Mapped to `unlink` when deleting a file and `rmdir` when deleting a directory.
Close:: Mapped to `flush`;`release` when closing a file and `releasedir` when closing a directory.
Read:: Mapped to `read`.
Write:: Mapped to `fgetattr`/`getattr` and `write`.
Flush:: Mapped to `fsync` or `fsyncdir`.
GetFileInfo:: Mapped to `fgetattr`/`getattr`.
SetBasicInfo:: Mapped to `utimens`/`utime`.
SetAllocationSize:: Mapped to `fgetattr`/`getattr` followed by `ftruncate`/`truncate`. Note that this call and `SetFileSize` may be consolidated soon in the WinFsp API.
SetFileSize:: Mapped to `fgetattr`/`getattr` followed by `ftruncate`/`truncate`. Note that this call and `SetAllocationSize` may be consolidated soon in the WinFsp API.
CanDelete:: For directories only: mapped to a `getdir`/`readdir` call to determine if they are empty and can therefore be deleted.
Rename:: Mapped to `fgetattr`/`getattr` on the destination file name and `rename`.
GetSecurity:: Mapped to `fgetattr`/`getattr`. The returned `stat` information is translated into a Windows security descriptor using `FspPosixMapPermissionsToSecurityDescriptor`.
SetSecurity:: Mapped to `fgetattr`/`getattr` followed by `chmod` and/or `chown`.
ReadDirectory:: Mapped to `getdir`/`readdir`. Note that because of how the Windows directory enumeration API's work there is a further `fgetattr`/`getattr` per file returned!
=== Some Additional Challenges
Let us now discuss a couple of final challenges in getting a proper FUSE port working under Cygwin: the implementation of `fuse_set_signal_handlers`/`fuse_remove_signal_handlers` and `fuse_daemonize`.
Let us start with `fuse_set_signal_handlers`/`fuse_remove_signal_handlers`. Cygwin supports POSIX signals and we can simply set up signal handlers similar to what libfuse does. However this simple approach does not work within WinFsp, because it uses native API's that Cygwin cannot interrupt with its signal mechanism. For example, the `fuse_loop` FUSE call eventually results in a `WaitForSingleObject` API call that Cygwin cannot interrupt. Even trying with an alertable `WaitForSingleObjectEx` did not work as unfortunately Cygwin does not issue a `QueueUserAPC` when issuing a signal. So we need an alternative mechanism to support signals.
The alternative is to use `sigwait` in a separate thread. `Fsp_fuse_signal_handler` is a WinFsp API that knows how to interrupt that `WaitForSingleObject` (actually it just signals the waited event).
----
static inline void *fsp_fuse_signal_thread(void *psigmask)
{
int sig;
if (0 == sigwait(psigmask, &sig))
fsp_fuse_signal_handler(sig);
return 0;
}
----
Let us now move to `fuse_daemonize`. This FUSE call allows a FUSE file system to become a (UNIX) daemon. This is achieved by using the POSIX fork call, which unfortunately has many limitations in Cygwin. One such limitation (and the one that bit us in WinFsp) is that it does not know how to clone Windows heaps (`HeapAlloc`/`HeapFree`).
Recall that WinFsp uses its own memory allocator (just a thin wrapper around `HeapAlloc`/`HeapFree`). This means that any allocations made prior to the fork() call are doomed after a fork(); with good luck the pointers will point to invalid memory and one will get an Access Violation; with bad luck the pointers will point to valid memory that contains bad data and the program may stumble for a while, just enough to hide the actual cause of the problem.
Luckily there is a rather straightforward work-around: "do not allocate any non-Cygwin resources prior to fork". This is actually possible within WinFsp, because we are already capturing the Cygwin environment and its `malloc`/`free` (see `fsp_fuse_env` in "Step 2"). It is also possible, because the typical FUSE program structure looks like this:
----
fuse_new
fuse_daemonize // do not allocate any non-Cygwin resources prior to this
fuse_loop/fuse_loop_mt // safe to allocate non-Cygwin resources
fuse_destroy
----
With this change `fuse_daemonize` works and allows me to declare the Cygwin portion of the SSHFS port complete!

View File

@ -102,95 +102,116 @@ struct fuse_context
#define fuse_main(argc, argv, ops, data)\ #define fuse_main(argc, argv, ops, data)\
fuse_main_real(argc, argv, ops, sizeof *(ops), data) fuse_main_real(argc, argv, ops, sizeof *(ops), data)
FSP_FUSE_API int fsp_fuse_main_real(struct fsp_fuse_env *env, FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_main_real)(struct fsp_fuse_env *env,
int argc, char *argv[], int argc, char *argv[],
const struct fuse_operations *ops, size_t opsize, void *data); const struct fuse_operations *ops, size_t opsize, void *data);
FSP_FUSE_API int fsp_fuse_is_lib_option(struct fsp_fuse_env *env, FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_is_lib_option)(struct fsp_fuse_env *env,
const char *opt); const char *opt);
FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env, FSP_FUSE_API struct fuse *FSP_FUSE_API_NAME(fsp_fuse_new)(struct fsp_fuse_env *env,
struct fuse_chan *ch, struct fuse_args *args, struct fuse_chan *ch, struct fuse_args *args,
const struct fuse_operations *ops, size_t opsize, void *data); const struct fuse_operations *ops, size_t opsize, void *data);
FSP_FUSE_API void fsp_fuse_destroy(struct fsp_fuse_env *env, FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_destroy)(struct fsp_fuse_env *env,
struct fuse *f); struct fuse *f);
FSP_FUSE_API int fsp_fuse_loop(struct fsp_fuse_env *env, FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_loop)(struct fsp_fuse_env *env,
struct fuse *f); struct fuse *f);
FSP_FUSE_API int fsp_fuse_loop_mt(struct fsp_fuse_env *env, FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_loop_mt)(struct fsp_fuse_env *env,
struct fuse *f); struct fuse *f);
FSP_FUSE_API void fsp_fuse_exit(struct fsp_fuse_env *env, FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_exit)(struct fsp_fuse_env *env,
struct fuse *f); struct fuse *f);
FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env); FSP_FUSE_API struct fuse_context *FSP_FUSE_API_NAME(fsp_fuse_get_context)(struct fsp_fuse_env *env);
FSP_FUSE_SYM int fuse_main_real(int argc, char *argv[], FSP_FUSE_SYM(
const struct fuse_operations *ops, size_t opsize, void *data) int fuse_main_real(int argc, char *argv[],
const struct fuse_operations *ops, size_t opsize, void *data),
{ {
return fsp_fuse_main_real(fsp_fuse_env(), argc, argv, ops, opsize, data); return FSP_FUSE_API_CALL(fsp_fuse_main_real)
} (fsp_fuse_env(), argc, argv, ops, opsize, data);
})
FSP_FUSE_SYM int fuse_is_lib_option(const char *opt) FSP_FUSE_SYM(
int fuse_is_lib_option(const char *opt),
{ {
return fsp_fuse_is_lib_option(fsp_fuse_env(), opt); return FSP_FUSE_API_CALL(fsp_fuse_is_lib_option)
} (fsp_fuse_env(), opt);
})
FSP_FUSE_SYM struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, FSP_FUSE_SYM(
const struct fuse_operations *ops, size_t opsize, void *data) struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
const struct fuse_operations *ops, size_t opsize, void *data),
{ {
return fsp_fuse_new(fsp_fuse_env(), ch, args, ops, opsize, data); return FSP_FUSE_API_CALL(fsp_fuse_new)
} (fsp_fuse_env(), ch, args, ops, opsize, data);
})
FSP_FUSE_SYM void fuse_destroy(struct fuse *f) FSP_FUSE_SYM(
void fuse_destroy(struct fuse *f),
{ {
fsp_fuse_destroy(fsp_fuse_env(), f); FSP_FUSE_API_CALL(fsp_fuse_destroy)
} (fsp_fuse_env(), f);
})
FSP_FUSE_SYM int fuse_loop(struct fuse *f) FSP_FUSE_SYM(
int fuse_loop(struct fuse *f),
{ {
return fsp_fuse_loop(fsp_fuse_env(), f); return FSP_FUSE_API_CALL(fsp_fuse_loop)
} (fsp_fuse_env(), f);
})
FSP_FUSE_SYM int fuse_loop_mt(struct fuse *f) FSP_FUSE_SYM(
int fuse_loop_mt(struct fuse *f),
{ {
return fsp_fuse_loop_mt(fsp_fuse_env(), f); return FSP_FUSE_API_CALL(fsp_fuse_loop_mt)
} (fsp_fuse_env(), f);
})
FSP_FUSE_SYM void fuse_exit(struct fuse *f) FSP_FUSE_SYM(
void fuse_exit(struct fuse *f),
{ {
fsp_fuse_exit(fsp_fuse_env(), f); FSP_FUSE_API_CALL(fsp_fuse_exit)
} (fsp_fuse_env(), f);
})
FSP_FUSE_SYM struct fuse_context *fuse_get_context(void) FSP_FUSE_SYM(
struct fuse_context *fuse_get_context(void),
{ {
return fsp_fuse_get_context(fsp_fuse_env()); return FSP_FUSE_API_CALL(fsp_fuse_get_context)
} (fsp_fuse_env());
})
FSP_FUSE_SYM int fuse_getgroups(int size, fuse_gid_t list[]) FSP_FUSE_SYM(
int fuse_getgroups(int size, fuse_gid_t list[]),
{ {
(void)size; (void)size;
(void)list; (void)list;
return -ENOSYS; return -ENOSYS;
} })
FSP_FUSE_SYM int fuse_interrupted(void) FSP_FUSE_SYM(
int fuse_interrupted(void),
{ {
return 0; return 0;
} })
FSP_FUSE_SYM int fuse_invalidate(struct fuse *f, const char *path) FSP_FUSE_SYM(
int fuse_invalidate(struct fuse *f, const char *path),
{ {
(void)f; (void)f;
(void)path; (void)path;
return -EINVAL; return -EINVAL;
} })
FSP_FUSE_SYM int fuse_notify_poll(struct fuse_pollhandle *ph) FSP_FUSE_SYM(
int fuse_notify_poll(struct fuse_pollhandle *ph),
{ {
(void)ph; (void)ph;
return 0; return 0;
} })
FSP_FUSE_SYM struct fuse_session *fuse_get_session(struct fuse *f) FSP_FUSE_SYM(
struct fuse_session *fuse_get_session(struct fuse *f),
{ {
return (void *)f; return (struct fuse_session *)f;
} })
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -77,58 +77,70 @@ struct fuse_session;
struct fuse_chan; struct fuse_chan;
struct fuse_pollhandle; struct fuse_pollhandle;
FSP_FUSE_API int fsp_fuse_version(struct fsp_fuse_env *env); FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_version)(struct fsp_fuse_env *env);
FSP_FUSE_API struct fuse_chan *fsp_fuse_mount(struct fsp_fuse_env *env, FSP_FUSE_API struct fuse_chan *FSP_FUSE_API_NAME(fsp_fuse_mount)(struct fsp_fuse_env *env,
const char *mountpoint, struct fuse_args *args); const char *mountpoint, struct fuse_args *args);
FSP_FUSE_API void fsp_fuse_unmount(struct fsp_fuse_env *env, FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_unmount)(struct fsp_fuse_env *env,
const char *mountpoint, struct fuse_chan *ch); const char *mountpoint, struct fuse_chan *ch);
FSP_FUSE_API int fsp_fuse_parse_cmdline(struct fsp_fuse_env *env, FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_parse_cmdline)(struct fsp_fuse_env *env,
struct fuse_args *args, struct fuse_args *args,
char **mountpoint, int *multithreaded, int *foreground); char **mountpoint, int *multithreaded, int *foreground);
FSP_FUSE_API int32_t fsp_fuse_ntstatus_from_errno(struct fsp_fuse_env *env, FSP_FUSE_API int32_t FSP_FUSE_API_NAME(fsp_fuse_ntstatus_from_errno)(struct fsp_fuse_env *env,
int err); int err);
FSP_FUSE_SYM int fuse_version(void) FSP_FUSE_SYM(
int fuse_version(void),
{ {
return fsp_fuse_version(fsp_fuse_env()); return FSP_FUSE_API_CALL(fsp_fuse_version)
} (fsp_fuse_env());
})
FSP_FUSE_SYM struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args) FSP_FUSE_SYM(
struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args),
{ {
return fsp_fuse_mount(fsp_fuse_env(), mountpoint, args); return FSP_FUSE_API_CALL(fsp_fuse_mount)
} (fsp_fuse_env(), mountpoint, args);
})
FSP_FUSE_SYM void fuse_unmount(const char *mountpoint, struct fuse_chan *ch) FSP_FUSE_SYM(
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch),
{ {
fsp_fuse_unmount(fsp_fuse_env(), mountpoint, ch); FSP_FUSE_API_CALL(fsp_fuse_unmount)
} (fsp_fuse_env(), mountpoint, ch);
})
FSP_FUSE_SYM int fuse_parse_cmdline(struct fuse_args *args, FSP_FUSE_SYM(
char **mountpoint, int *multithreaded, int *foreground) int fuse_parse_cmdline(struct fuse_args *args,
char **mountpoint, int *multithreaded, int *foreground),
{ {
return fsp_fuse_parse_cmdline(fsp_fuse_env(), args, mountpoint, multithreaded, foreground); return FSP_FUSE_API_CALL(fsp_fuse_parse_cmdline)
} (fsp_fuse_env(), args, mountpoint, multithreaded, foreground);
})
FSP_FUSE_SYM void fuse_pollhandle_destroy(struct fuse_pollhandle *ph) FSP_FUSE_SYM(
void fuse_pollhandle_destroy(struct fuse_pollhandle *ph),
{ {
(void)ph; (void)ph;
} })
FSP_FUSE_SYM int fuse_daemonize(int foreground) FSP_FUSE_SYM(
int fuse_daemonize(int foreground),
{ {
return fsp_fuse_daemonize(foreground); return fsp_fuse_daemonize(foreground);
} })
FSP_FUSE_SYM int fuse_set_signal_handlers(struct fuse_session *se) FSP_FUSE_SYM(
int fuse_set_signal_handlers(struct fuse_session *se),
{ {
return fsp_fuse_set_signal_handlers(se); return fsp_fuse_set_signal_handlers(se);
} })
FSP_FUSE_SYM void fuse_remove_signal_handlers(struct fuse_session *se) FSP_FUSE_SYM(
void fuse_remove_signal_handlers(struct fuse_session *se),
{ {
(void)se; (void)se;
fsp_fuse_set_signal_handlers(0); fsp_fuse_set_signal_handlers(0);
} })
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -56,57 +56,71 @@ struct fuse_args
typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key, typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
struct fuse_args *outargs); struct fuse_args *outargs);
FSP_FUSE_API int fsp_fuse_opt_parse(struct fsp_fuse_env *env, FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_parse)(struct fsp_fuse_env *env,
struct fuse_args *args, void *data, struct fuse_args *args, void *data,
const struct fuse_opt opts[], fuse_opt_proc_t proc); const struct fuse_opt opts[], fuse_opt_proc_t proc);
FSP_FUSE_API int fsp_fuse_opt_add_arg(struct fsp_fuse_env *env, FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_add_arg)(struct fsp_fuse_env *env,
struct fuse_args *args, const char *arg); struct fuse_args *args, const char *arg);
FSP_FUSE_API int fsp_fuse_opt_insert_arg(struct fsp_fuse_env *env, FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_insert_arg)(struct fsp_fuse_env *env,
struct fuse_args *args, int pos, const char *arg); struct fuse_args *args, int pos, const char *arg);
FSP_FUSE_API void fsp_fuse_opt_free_args(struct fsp_fuse_env *env, FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_opt_free_args)(struct fsp_fuse_env *env,
struct fuse_args *args); struct fuse_args *args);
FSP_FUSE_API int fsp_fuse_opt_add_opt(struct fsp_fuse_env *env, FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_add_opt)(struct fsp_fuse_env *env,
char **opts, const char *opt); char **opts, const char *opt);
FSP_FUSE_API int fsp_fuse_opt_add_opt_escaped(struct fsp_fuse_env *env, FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_add_opt_escaped)(struct fsp_fuse_env *env,
char **opts, const char *opt); char **opts, const char *opt);
FSP_FUSE_API int fsp_fuse_opt_match(struct fsp_fuse_env *env, FSP_FUSE_API int FSP_FUSE_API_NAME(fsp_fuse_opt_match)(struct fsp_fuse_env *env,
const struct fuse_opt opts[], const char *opt); const struct fuse_opt opts[], const char *opt);
FSP_FUSE_SYM int fuse_opt_parse(struct fuse_args *args, void *data, FSP_FUSE_SYM(
const struct fuse_opt opts[], fuse_opt_proc_t proc) int fuse_opt_parse(struct fuse_args *args, void *data,
const struct fuse_opt opts[], fuse_opt_proc_t proc),
{ {
return fsp_fuse_opt_parse(fsp_fuse_env(), args, data, opts, proc); return FSP_FUSE_API_CALL(fsp_fuse_opt_parse)
} (fsp_fuse_env(), args, data, opts, proc);
})
FSP_FUSE_SYM int fuse_opt_add_arg(struct fuse_args *args, const char *arg) FSP_FUSE_SYM(
int fuse_opt_add_arg(struct fuse_args *args, const char *arg),
{ {
return fsp_fuse_opt_add_arg(fsp_fuse_env(), args, arg); return FSP_FUSE_API_CALL(fsp_fuse_opt_add_arg)
} (fsp_fuse_env(), args, arg);
})
FSP_FUSE_SYM int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg) FSP_FUSE_SYM(
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg),
{ {
return fsp_fuse_opt_insert_arg(fsp_fuse_env(), args, pos, arg); return FSP_FUSE_API_CALL(fsp_fuse_opt_insert_arg)
} (fsp_fuse_env(), args, pos, arg);
})
FSP_FUSE_SYM void fuse_opt_free_args(struct fuse_args *args) FSP_FUSE_SYM(
void fuse_opt_free_args(struct fuse_args *args),
{ {
fsp_fuse_opt_free_args(fsp_fuse_env(), args); FSP_FUSE_API_CALL(fsp_fuse_opt_free_args)
} (fsp_fuse_env(), args);
})
FSP_FUSE_SYM int fuse_opt_add_opt(char **opts, const char *opt) FSP_FUSE_SYM(
int fuse_opt_add_opt(char **opts, const char *opt),
{ {
return fsp_fuse_opt_add_opt(fsp_fuse_env(), opts, opt); return FSP_FUSE_API_CALL(fsp_fuse_opt_add_opt)
} (fsp_fuse_env(), opts, opt);
})
FSP_FUSE_SYM int fuse_opt_add_opt_escaped(char **opts, const char *opt) FSP_FUSE_SYM(
int fuse_opt_add_opt_escaped(char **opts, const char *opt),
{ {
return fsp_fuse_opt_add_opt_escaped(fsp_fuse_env(), opts, opt); return FSP_FUSE_API_CALL(fsp_fuse_opt_add_opt_escaped)
} (fsp_fuse_env(), opts, opt);
})
FSP_FUSE_SYM int fuse_opt_match(const struct fuse_opt opts[], const char *opt) FSP_FUSE_SYM(
int fuse_opt_match(const struct fuse_opt opts[], const char *opt),
{ {
return fsp_fuse_opt_match(fsp_fuse_env(), opts, opt); return FSP_FUSE_API_CALL(fsp_fuse_opt_match)
} (fsp_fuse_env(), opts, opt);
})
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -29,14 +29,28 @@
extern "C" { extern "C" {
#endif #endif
#if !defined(FSP_FUSE_API)
#if defined(WINFSP_DLL_INTERNAL) #if defined(WINFSP_DLL_INTERNAL)
#define FSP_FUSE_API __declspec(dllexport) #define FSP_FUSE_API __declspec(dllexport)
#else #else
#define FSP_FUSE_API __declspec(dllimport) #define FSP_FUSE_API __declspec(dllimport)
#endif #endif
#endif
#if !defined(FSP_FUSE_API_NAME)
#define FSP_FUSE_API_NAME(n) (n)
#endif
#if !defined(FSP_FUSE_API_CALL)
#define FSP_FUSE_API_CALL(n) (n)
#endif
#if !defined(FSP_FUSE_SYM) #if !defined(FSP_FUSE_SYM)
#define FSP_FUSE_SYM static inline #if !defined(CYGFUSE)
#define FSP_FUSE_SYM(proto, ...) static inline proto { __VA_ARGS__ }
#else
#define FSP_FUSE_SYM(proto, ...) proto;
#endif
#endif #endif
/* /*
@ -230,9 +244,10 @@ struct fsp_fuse_env
void (*memfree)(void *); void (*memfree)(void *);
int (*daemonize)(int); int (*daemonize)(int);
int (*set_signal_handlers)(void *); int (*set_signal_handlers)(void *);
void (*reserved[4])();
}; };
FSP_FUSE_API void fsp_fuse_signal_handler(int sig); FSP_FUSE_API void FSP_FUSE_API_NAME(fsp_fuse_signal_handler)(int sig);
#if defined(_WIN64) || defined(_WIN32) #if defined(_WIN64) || defined(_WIN32)
@ -270,8 +285,8 @@ static inline void *fsp_fuse_signal_thread(void *psigmask)
{ {
int sig; int sig;
if (0 == sigwait(psigmask, &sig)) if (0 == sigwait((sigset_t *)psigmask, &sig))
fsp_fuse_signal_handler(sig); FSP_FUSE_API_CALL(fsp_fuse_signal_handler)(sig);
return 0; return 0;
} }

View File

@ -402,41 +402,35 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime, UINT64 CreationTime, UINT64 LastAccessTime, UINT64 LastWriteTime,
FSP_FSCTL_FILE_INFO *FileInfo); FSP_FSCTL_FILE_INFO *FileInfo);
/** /**
* Set file allocation size. * Set file/allocation size.
*
* This function is used to change a file's sizes. Windows file systems maintain two kinds
* of sizes: the file size is where the End Of File (EOF) is, and the allocation size is the
* actual size that a file takes up on the "disk".
*
* The rules regarding file/allocation size are:
* <ul>
* <li>Allocation size must always be aligned to the allocation unit boundary. The allocation
* unit is the product <code>(UINT64)SectorSize * (UINT64)SectorsPerAllocationUnit</code> from
* the FSP_FSCTL_VOLUME_PARAMS structure. The FSD will always send properly aligned allocation
* sizes when setting the allocation size.</li>
* <li>Allocation size is always greater or equal to the file size.</li>
* <li>A file size of more than the current allocation size will also extend the allocation
* size to the next allocation unit boundary.</li>
* <li>An allocation size of less than the current file size should also truncate the current
* file size.</li>
* </ul>
* *
* @param FileSystem * @param FileSystem
* The file system on which this request is posted. * The file system on which this request is posted.
* @param Request * @param Request
* The request posted by the kernel mode FSD. * The request posted by the kernel mode FSD.
* @param FileNode * @param FileNode
* The file node of the file to set the allocation size for. * The file node of the file to set the file/allocation size for.
* @param AllocationSize * @param NewSize
* Allocation size to apply to the file. Allocation size is always greater than file size. * New file/allocation size to apply to the file.
* An allocation size of less than the current file size should also truncate the current * @param SetAllocationSize
* file size. * If TRUE, then the allocation size is being set. if FALSE, then the file size is being set.
* @param FileInfo [out]
* Pointer to a structure that will receive the file information on successful return
* from this call. This information includes file attributes, file times, etc.
* @return
* STATUS_SUCCESS on error code.
*/
NTSTATUS (*SetAllocationSize)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, UINT64 AllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo);
/**
* Set file size.
*
* @param FileSystem
* The file system on which this request is posted.
* @param Request
* The request posted by the kernel mode FSD.
* @param FileNode
* The file node of the file to set the size for.
* @param FileSize
* FileSize size to apply to the file. Allocation size is always greater than file size.
* A file size of more than the current allocation size will also extend the allocation
* size to the next allocation unit boundary.
* @param FileInfo [out] * @param FileInfo [out]
* Pointer to a structure that will receive the file information on successful return * Pointer to a structure that will receive the file information on successful return
* from this call. This information includes file attributes, file times, etc. * from this call. This information includes file attributes, file times, etc.
@ -445,7 +439,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*/ */
NTSTATUS (*SetFileSize)(FSP_FILE_SYSTEM *FileSystem, NTSTATUS (*SetFileSize)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, UINT64 FileSize, PVOID FileNode, UINT64 NewSize, BOOLEAN SetAllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo); FSP_FSCTL_FILE_INFO *FileInfo);
/** /**
* Determine whether a file or directory can be deleted. * Determine whether a file or directory can be deleted.
@ -454,6 +448,12 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* not need to perform access checks, but may performs tasks such as check for empty * not need to perform access checks, but may performs tasks such as check for empty
* directories, etc. * directories, etc.
* *
* This function should <b>NEVER</b> delete the file or directory in question. Deletion should
* happen during Cleanup with Delete==TRUE.
*
* This function gets called when Win32 API's such as DeleteFile or RemoveDirectory are used.
* It does not get called when a file or directory is opened with FILE_DELETE_ON_CLOSE.
*
* @param FileSystem * @param FileSystem
* The file system on which this request is posted. * The file system on which this request is posted.
* @param Request * @param Request
@ -576,7 +576,21 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length, PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length,
PWSTR Pattern, PWSTR Pattern,
PULONG PBytesTransferred); PULONG PBytesTransferred);
/*
* This ensures that this interface will always contain 64 function pointers.
* Please update when changing the interface as it is important for future compatibility.
*/
NTSTATUS (*Reserved[45])();
} FSP_FILE_SYSTEM_INTERFACE; } FSP_FILE_SYSTEM_INTERFACE;
#if defined(WINFSP_DLL_INTERNAL)
/*
* Static_assert is a C++11 feature, but seems to work with C on MSVC 2015.
* Use it to verify that FSP_FILE_SYSTEM_INTERFACE has the right size.
*/
static_assert(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
#endif
typedef enum typedef enum
{ {
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE = 0, FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE = 0,
@ -595,7 +609,7 @@ typedef struct _FSP_FILE_SYSTEM
ULONG DispatcherThreadCount; ULONG DispatcherThreadCount;
NTSTATUS DispatcherResult; NTSTATUS DispatcherResult;
PWSTR MountPoint; PWSTR MountPoint;
LIST_ENTRY MountEntry; HANDLE MountHandle;
UINT32 DebugLog; UINT32 DebugLog;
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy; FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
SRWLOCK OpGuardLock; SRWLOCK OpGuardLock;

20
opt/cygfuse/Makefile Normal file
View File

@ -0,0 +1,20 @@
Version = $(shell sed -n '/^VERSION=/s/VERSION=\(.*\)/\1/p' fuse.cygport)
#Debug = -g
cygfuse-$(Version).dll libfuse-$(Version).dll.a fuse.pc: cygfuse.c fuse.pc.in
gcc $(Debug) -shared -o cygfuse-$(Version).dll -Wl,--out-implib=libfuse-$(Version).dll.a -I../../inc/fuse cygfuse.c
[ -n "$(Debug)" ] || strip cygfuse-$(Version).dll
sed "s/@Version@/$(Version)/g" fuse.pc.in > fuse.pc
cygfuse-test.exe: cygfuse-test.c cygfuse-$(Version).dll libfuse-$(Version).dll.a
gcc $(Debug) -o cygfuse-test.exe -I../../inc/fuse -DCYGFUSE cygfuse-test.c -L$(PWD) -lfuse-$(Version)
cygport:
git clean -dfx
(\
cd `git rev-parse --show-toplevel` &&\
Stash=`git stash create` &&\
git archive --prefix=winfsp-work/ --format=tar.gz $${Stash:-HEAD}\
> opt/cygfuse/winfsp-work.tar.gz\
)
CYGPORT_SRC_URI=winfsp-work.tar.gz CYGPORT_SRC_DIR=winfsp-work cygport fuse.cygport download prep compile install package

View File

@ -0,0 +1,6 @@
#include <fuse.h>
int main()
{
return !(FUSE_VERSION == fuse_version());
}

146
opt/cygfuse/cygfuse.c Normal file
View File

@ -0,0 +1,146 @@
/**
* @file cygfuse/cygfuse.c
*
* @copyright 2015-2016 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License version 3 as published by the
* Free Software Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
#include <dlfcn.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <sys/cygwin.h>
static void *cygfuse_init_winfsp();
static void *cygfuse_init_fail();
static pthread_mutex_t cygfuse_mutex = PTHREAD_MUTEX_INITIALIZER;
static void *cygfuse_handle = 0;
static inline void cygfuse_init(int force)
{
pthread_mutex_lock(&cygfuse_mutex);
if (force || 0 == cygfuse_handle)
cygfuse_handle = cygfuse_init_winfsp();
pthread_mutex_unlock(&cygfuse_mutex);
}
/*
* Unfortunately Cygwin fork is very fragile and cannot even correctly
* handle dlopen'ed DLL's if they are native (rather than Cygwin ones).
*
* So we have this very nasty hack where we reset the dlopen'ed handle
* immediately after daemonization. This will force cygfuse_init() to
* reload the WinFsp DLL and reset all API pointers in the daemonized
* process.
*/
static inline int cygfuse_daemon(int nochdir, int noclose)
{
if (-1 == daemon(nochdir, noclose))
return -1;
/* force reload of WinFsp DLL to workaround fork() problems */
cygfuse_init(1);
return 0;
}
#define daemon cygfuse_daemon
#define FSP_FUSE_API static
#define FSP_FUSE_API_NAME(api) (* pfn_ ## api)
#define FSP_FUSE_API_CALL(api) (cygfuse_init(0), pfn_ ## api)
#define FSP_FUSE_SYM(proto, ...) __attribute__ ((visibility("default"))) proto { __VA_ARGS__ }
#include <fuse_common.h>
#include <fuse.h>
#include <fuse_opt.h>
#if defined(__LP64__)
#define CYGFUSE_WINFSP_NAME "winfsp-x64.dll"
#else
#define CYGFUSE_WINFSP_NAME "winfsp-x86.dll"
#endif
#define CYGFUSE_WINFSP_PATH "bin\\" CYGFUSE_WINFSP_NAME
#define CYGFUSE_GET_API(h, n) \
if (0 == (*(void **)&(pfn_ ## n) = dlsym(h, #n)))\
return cygfuse_init_fail();
static void *cygfuse_init_winfsp()
{
void *h;
h = dlopen(CYGFUSE_WINFSP_NAME, RTLD_NOW);
if (0 == h)
{
char winpath[260], *psxpath;
int regfd, bytes;
regfd = open("/proc/registry32/HKEY_LOCAL_MACHINE/Software/WinFsp/InstallDir", O_RDONLY);
if (-1 == regfd)
return cygfuse_init_fail();
bytes = read(regfd, winpath, sizeof winpath - sizeof CYGFUSE_WINFSP_PATH);
close(regfd);
if (-1 == bytes || 0 == bytes)
return cygfuse_init_fail();
if ('\0' == winpath[bytes - 1])
bytes--;
memcpy(winpath + bytes, CYGFUSE_WINFSP_PATH, sizeof CYGFUSE_WINFSP_PATH);
psxpath = (char *)cygwin_create_path(CCP_WIN_A_TO_POSIX | CCP_PROC_CYGDRIVE, winpath);
if (0 == psxpath)
return cygfuse_init_fail();
h = dlopen(psxpath, RTLD_NOW);
free(psxpath);
if (0 == h)
return cygfuse_init_fail();
}
/* winfsp_fuse.h */
CYGFUSE_GET_API(h, fsp_fuse_signal_handler);
/* fuse_common.h */
CYGFUSE_GET_API(h, fsp_fuse_version);
CYGFUSE_GET_API(h, fsp_fuse_mount);
CYGFUSE_GET_API(h, fsp_fuse_unmount);
CYGFUSE_GET_API(h, fsp_fuse_parse_cmdline);
CYGFUSE_GET_API(h, fsp_fuse_ntstatus_from_errno);
/* fuse.h */
CYGFUSE_GET_API(h, fsp_fuse_main_real);
CYGFUSE_GET_API(h, fsp_fuse_is_lib_option);
CYGFUSE_GET_API(h, fsp_fuse_new);
CYGFUSE_GET_API(h, fsp_fuse_destroy);
CYGFUSE_GET_API(h, fsp_fuse_loop);
CYGFUSE_GET_API(h, fsp_fuse_loop_mt);
CYGFUSE_GET_API(h, fsp_fuse_exit);
CYGFUSE_GET_API(h, fsp_fuse_get_context);
/* fuse_opt.h */
CYGFUSE_GET_API(h, fsp_fuse_opt_parse);
CYGFUSE_GET_API(h, fsp_fuse_opt_add_arg);
CYGFUSE_GET_API(h, fsp_fuse_opt_insert_arg);
CYGFUSE_GET_API(h, fsp_fuse_opt_free_args);
CYGFUSE_GET_API(h, fsp_fuse_opt_add_opt);
CYGFUSE_GET_API(h, fsp_fuse_opt_add_opt_escaped);
CYGFUSE_GET_API(h, fsp_fuse_opt_match);
return h;
}
static void *cygfuse_init_fail()
{
abort();
return 0;
}

35
opt/cygfuse/fuse.cygport Normal file
View File

@ -0,0 +1,35 @@
NAME="fuse"
VERSION=2.8
RELEASE=3
CATEGORY="Utils"
SUMMARY="WinFsp-FUSE compatibility layer"
DESCRIPTION="WinFsp-FUSE enables FUSE file systems to be run on Cygwin."
HOMEPAGE="http://www.secfs.net/winfsp/"
SRC_URI=${CYGPORT_SRC_URI:-"https://github.com/billziss-gh/winfsp/archive/master.tar.gz"}
SRC_DIR=${CYGPORT_SRC_DIR:-winfsp-master}
src_compile()
{
lndirs
cd ${B}/opt/cygfuse
make
}
src_install()
{
cd ${B}/inc/fuse
includeinto fuse
doinclude fuse.h
doinclude fuse_common.h
doinclude fuse_opt.h
doinclude winfsp_fuse.h
cd ${B}/opt/cygfuse
dobin cygfuse-${VERSION}.dll
dolib libfuse-${VERSION}.dll.a
dosym libfuse-${VERSION}.dll.a /usr/lib/libfuse.dll.a
dopkgconfig fuse.pc
}
RESTRICT="strip postinst-doc"

9
opt/cygfuse/fuse.pc.in Normal file
View File

@ -0,0 +1,9 @@
prefix=/usr
incdir=${prefix}/include/fuse
Name: fuse
Description: WinFsp FUSE compatible API
Version: @Version@
URL: http://www.secfs.net/winfsp/
Libs: -lfuse-@Version@
Cflags: -I"${incdir}" -DCYGFUSE

View File

@ -25,60 +25,34 @@ enum
static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface; static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface;
static INIT_ONCE FspFileSystemInitOnce = INIT_ONCE_STATIC_INIT; static INIT_ONCE FspFileSystemInitOnce = INIT_ONCE_STATIC_INIT;
static BOOLEAN FspFileSystemInitialized; static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)(
static CRITICAL_SECTION FspFileSystemMountListGuard; PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
static LIST_ENTRY FspFileSystemMountList = { &FspFileSystemMountList, &FspFileSystemMountList }; static NTSTATUS (NTAPI *FspNtMakeTemporaryObject)(
HANDLE Handle);
static NTSTATUS (NTAPI *FspNtClose)(
HANDLE Handle);
static BOOL WINAPI FspFileSystemInitialize( static BOOL WINAPI FspFileSystemInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{ {
InitializeCriticalSection(&FspFileSystemMountListGuard); HANDLE Handle;
return FspFileSystemInitialized = TRUE;
}
VOID FspFileSystemFinalize(BOOLEAN Dynamic) Handle = GetModuleHandleW(L"ntdll.dll");
{ if (0 != Handle)
/*
* This function is called during DLL_PROCESS_DETACH. We must therefore keep
* finalization tasks to a minimum.
*
* We enter our FspFileSystemMountListGuard critical section here and then attempt to cleanup
* our mount points using DefineDosDeviceW. On Vista and later orphaned critical sections
* become "electrified", so our process will be forcefully terminated if one of its threads
* was already modifying the list when the ExitProcess happened. This is a good thing!
*
* The use of DefineDosDeviceW is rather suspect and probably unsafe. DefineDosDeviceW reaches
* out to CSRSS, which is probably not the safest thing to do when in DllMain! There is also
* some evidence that it may attempt to load DLL's under some circumstances, which is a
* definite no-no as we are under the loader lock!
*
* We only delete the criticaly section when being dynamically unloaded. On process exit the
* OS will clean it up for us.
*/
if (!FspFileSystemInitialized)
return;
FSP_FILE_SYSTEM *FileSystem;
PLIST_ENTRY MountEntry;
EnterCriticalSection(&FspFileSystemMountListGuard);
for (MountEntry = FspFileSystemMountList.Flink;
&FspFileSystemMountList != MountEntry;
MountEntry = MountEntry->Flink)
{ {
FileSystem = CONTAINING_RECORD(MountEntry, FSP_FILE_SYSTEM, MountEntry); FspNtOpenSymbolicLinkObject = (PVOID)GetProcAddress(Handle, "NtOpenSymbolicLinkObject");
FspNtMakeTemporaryObject = (PVOID)GetProcAddress(Handle, "NtMakeTemporaryObject");
FspNtClose = (PVOID)GetProcAddress(Handle, "NtClose");
DefineDosDeviceW( if (0 == FspNtOpenSymbolicLinkObject || 0 == FspNtMakeTemporaryObject || 0 == FspNtClose)
DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, {
FileSystem->MountPoint, FileSystem->VolumeName); FspNtOpenSymbolicLinkObject = 0;
FspNtMakeTemporaryObject = 0;
FspNtClose = 0;
}
} }
LeaveCriticalSection(&FspFileSystemMountListGuard); return TRUE;
if (Dynamic)
DeleteCriticalSection(&FspFileSystemMountListGuard);
} }
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath, FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
@ -95,8 +69,6 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
Interface = &FspFileSystemNullInterface; Interface = &FspFileSystemNullInterface;
InitOnceExecuteOnce(&FspFileSystemInitOnce, FspFileSystemInitialize, 0, 0); InitOnceExecuteOnce(&FspFileSystemInitOnce, FspFileSystemInitialize, 0, 0);
if (!FspFileSystemInitialized)
return STATUS_INSUFFICIENT_RESOURCES;
FileSystem = MemAlloc(sizeof *FileSystem); FileSystem = MemAlloc(sizeof *FileSystem);
if (0 == FileSystem) if (0 == FileSystem)
@ -151,6 +123,7 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
NTSTATUS Result; NTSTATUS Result;
HANDLE MountHandle = 0;
if (0 == MountPoint) if (0 == MountPoint)
{ {
@ -203,13 +176,41 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M
} }
exit: exit:
if (NT_SUCCESS(Result) && 0 != FspNtOpenSymbolicLinkObject)
{
WCHAR SymlinkBuf[6];
UNICODE_STRING Symlink;
OBJECT_ATTRIBUTES Obja;
memcpy(SymlinkBuf, L"\\??\\X:", sizeof SymlinkBuf);
SymlinkBuf[4] = MountPoint[0];
Symlink.Length = Symlink.MaximumLength = sizeof SymlinkBuf;
Symlink.Buffer = SymlinkBuf;
memset(&Obja, 0, sizeof Obja);
Obja.Length = sizeof Obja;
Obja.ObjectName = &Symlink;
Obja.Attributes = OBJ_CASE_INSENSITIVE;
Result = FspNtOpenSymbolicLinkObject(&MountHandle, DELETE, &Obja);
if (NT_SUCCESS(Result))
{
Result = FspNtMakeTemporaryObject(MountHandle);
if (!NT_SUCCESS(Result))
{
FspNtClose(MountHandle);
MountHandle = 0;
}
}
/* this path always considered successful regardless if we made symlink temporary */
Result = STATUS_SUCCESS;
}
if (NT_SUCCESS(Result)) if (NT_SUCCESS(Result))
{ {
FileSystem->MountPoint = MountPoint; FileSystem->MountPoint = MountPoint;
FileSystem->MountHandle = MountHandle;
EnterCriticalSection(&FspFileSystemMountListGuard);
InsertTailList(&FspFileSystemMountList, &FileSystem->MountEntry);
LeaveCriticalSection(&FspFileSystemMountListGuard);
} }
else else
MemFree(MountPoint); MemFree(MountPoint);
@ -222,15 +223,16 @@ FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem)
if (0 == FileSystem->MountPoint) if (0 == FileSystem->MountPoint)
return; return;
EnterCriticalSection(&FspFileSystemMountListGuard);
RemoveEntryList(&FileSystem->MountEntry);
LeaveCriticalSection(&FspFileSystemMountListGuard);
DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
FileSystem->MountPoint, FileSystem->VolumeName); FileSystem->MountPoint, FileSystem->VolumeName);
MemFree(FileSystem->MountPoint); MemFree(FileSystem->MountPoint);
FileSystem->MountPoint = 0; FileSystem->MountPoint = 0;
if (0 != FileSystem->MountHandle)
{
FspNtClose(FileSystem->MountHandle);
FileSystem->MountHandle = 0;
}
} }
static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0) static DWORD WINAPI FspFileSystemDispatcherThread(PVOID FileSystem0)

View File

@ -132,7 +132,9 @@ exit:
FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle) FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle)
{ {
if (!DeviceIoControl(VolumeHandle, FSP_FSCTL_STOP, 0, 0, 0, 0, 0, 0)) DWORD Bytes;
if (!DeviceIoControl(VolumeHandle, FSP_FSCTL_STOP, 0, 0, 0, 0, &Bytes, 0))
return FspNtStatusFromWin32(GetLastError()); return FspNtStatusFromWin32(GetLastError());
return STATUS_SUCCESS; return STATUS_SUCCESS;

View File

@ -690,32 +690,17 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
&FileInfo); &FileInfo);
break; break;
case 19/*FileAllocationInformation*/: case 19/*FileAllocationInformation*/:
if (0 != FileSystem->Interface->SetAllocationSize) if (0 != FileSystem->Interface->SetFileSize)
Result = FileSystem->Interface->SetAllocationSize(FileSystem, Request,
(PVOID)Request->Req.SetInformation.UserContext,
Request->Req.SetInformation.Info.Allocation.AllocationSize,
&FileInfo);
else
if (0 != FileSystem->Interface->GetFileInfo &&
0 != FileSystem->Interface->SetFileSize)
{
Result = FileSystem->Interface->GetFileInfo(FileSystem, Request,
(PVOID)Request->Req.SetInformation.UserContext, &FileInfo);
if (NT_SUCCESS(Result) &&
Request->Req.SetInformation.Info.Allocation.AllocationSize < FileInfo.FileSize)
{
Result = FileSystem->Interface->SetFileSize(FileSystem, Request, Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
(PVOID)Request->Req.SetInformation.UserContext, (PVOID)Request->Req.SetInformation.UserContext,
Request->Req.SetInformation.Info.Allocation.AllocationSize, Request->Req.SetInformation.Info.Allocation.AllocationSize, TRUE,
&FileInfo); &FileInfo);
}
}
break; break;
case 20/*FileEndOfFileInformation*/: case 20/*FileEndOfFileInformation*/:
if (0 != FileSystem->Interface->SetFileSize) if (0 != FileSystem->Interface->SetFileSize)
Result = FileSystem->Interface->SetFileSize(FileSystem, Request, Result = FileSystem->Interface->SetFileSize(FileSystem, Request,
(PVOID)Request->Req.SetInformation.UserContext, (PVOID)Request->Req.SetInformation.UserContext,
Request->Req.SetInformation.Info.EndOfFile.FileSize, Request->Req.SetInformation.Info.EndOfFile.FileSize, FALSE,
&FileInfo); &FileInfo);
break; break;
case 13/*FileDispositionInformation*/: case 13/*FileDispositionInformation*/:

View File

@ -463,9 +463,9 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
return 1; return 1;
case 'U': case 'U':
if ('U' == arg[2]) if ('U' == arg[2])
arg += sizeof "--UNC" - 1; arg += sizeof "--UNC=" - 1;
else if ('V' == arg[2]) else if ('V' == arg[2])
arg += sizeof "--VolumePrefix" - 1; arg += sizeof "--VolumePrefix=" - 1;
if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1, if (0 == MultiByteToWideChar(CP_UTF8, 0, arg, -1,
opt_data->VolumeParams.Prefix, sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR))) opt_data->VolumeParams.Prefix, sizeof opt_data->VolumeParams.Prefix / sizeof(WCHAR)))
return -1; return -1;
@ -507,6 +507,9 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
goto fail; goto fail;
f->env = env; f->env = env;
f->set_umask = opt_data.set_umask; f->umask = opt_data.umask;
f->set_uid = opt_data.set_uid; f->uid = opt_data.uid;
f->set_gid = opt_data.set_gid; f->gid = opt_data.gid;
memcpy(&f->ops, ops, opsize); memcpy(&f->ops, ops, opsize);
f->data = data; f->data = data;
f->DebugLog = opt_data.debug ? -1 : 0; f->DebugLog = opt_data.debug ? -1 : 0;

View File

@ -205,6 +205,13 @@ static NTSTATUS fsp_fuse_intf_GetFileInfoEx(FSP_FILE_SYSTEM *FileSystem,
if (0 != err) if (0 != err)
return fsp_fuse_ntstatus_from_errno(f->env, err); return fsp_fuse_ntstatus_from_errno(f->env, err);
if (f->set_umask)
stbuf.st_mode = (stbuf.st_mode & 0170000) | (0777 & ~f->umask);
if (f->set_uid)
stbuf.st_uid = f->uid;
if (f->set_gid)
stbuf.st_gid = f->gid;
*PUid = stbuf.st_uid; *PUid = stbuf.st_uid;
*PGid = stbuf.st_gid; *PGid = stbuf.st_gid;
*PMode = stbuf.st_mode; *PMode = stbuf.st_mode;
@ -935,9 +942,9 @@ static NTSTATUS fsp_fuse_intf_SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS fsp_fuse_intf_SetFileSizeCommon(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, UINT64 NewFileSize, BOOLEAN OnlyIfTruncate, PVOID FileNode, UINT64 NewSize, BOOLEAN SetAllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo) FSP_FSCTL_FILE_INFO *FileInfo)
{ {
struct fuse *f = FileSystem->UserContext; struct fuse *f = FileSystem->UserContext;
@ -962,21 +969,21 @@ static NTSTATUS fsp_fuse_intf_SetFileSizeCommon(FSP_FILE_SYSTEM *FileSystem,
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
if (!OnlyIfTruncate || FileInfoBuf.FileSize > NewFileSize) if (!SetAllocationSize || FileInfoBuf.FileSize > NewSize)
{ {
/* /*
* OnlyIfTruncate explanation: * "FileInfoBuf.FileSize > NewSize" explanation:
* FUSE 2.8 does not support allocation size. However if the new AllocationSize * FUSE 2.8 does not support allocation size. However if the new AllocationSize
* is less than the current FileSize we must truncate the file. * is less than the current FileSize we must truncate the file.
*/ */
if (0 != f->ops.ftruncate) if (0 != f->ops.ftruncate)
{ {
err = f->ops.ftruncate(filedesc->PosixPath, NewFileSize, &fi); err = f->ops.ftruncate(filedesc->PosixPath, NewSize, &fi);
Result = fsp_fuse_ntstatus_from_errno(f->env, err); Result = fsp_fuse_ntstatus_from_errno(f->env, err);
} }
else else
{ {
err = f->ops.truncate(filedesc->PosixPath, NewFileSize); err = f->ops.truncate(filedesc->PosixPath, NewSize);
Result = fsp_fuse_ntstatus_from_errno(f->env, err); Result = fsp_fuse_ntstatus_from_errno(f->env, err);
} }
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
@ -984,7 +991,7 @@ static NTSTATUS fsp_fuse_intf_SetFileSizeCommon(FSP_FILE_SYSTEM *FileSystem,
AllocationUnit = (UINT64)f->VolumeParams.SectorSize * AllocationUnit = (UINT64)f->VolumeParams.SectorSize *
(UINT64)f->VolumeParams.SectorsPerAllocationUnit; (UINT64)f->VolumeParams.SectorsPerAllocationUnit;
FileInfoBuf.FileSize = NewFileSize; FileInfoBuf.FileSize = NewSize;
FileInfoBuf.AllocationSize = FileInfoBuf.AllocationSize =
(FileInfoBuf.FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit; (FileInfoBuf.FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
} }
@ -994,24 +1001,6 @@ static NTSTATUS fsp_fuse_intf_SetFileSizeCommon(FSP_FILE_SYSTEM *FileSystem,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS fsp_fuse_intf_SetAllocationSize(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, UINT64 AllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo)
{
return fsp_fuse_intf_SetFileSizeCommon(FileSystem, Request, FileNode, AllocationSize, TRUE,
FileInfo);
}
static NTSTATUS fsp_fuse_intf_SetFileSize(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, UINT64 FileSize,
FSP_FSCTL_FILE_INFO *FileInfo)
{
return fsp_fuse_intf_SetFileSizeCommon(FileSystem, Request, FileNode, FileSize, FALSE,
FileInfo);
}
static int fsp_fuse_intf_CanDeleteAddDirInfo(void *buf, const char *name, static int fsp_fuse_intf_CanDeleteAddDirInfo(void *buf, const char *name,
const struct fuse_stat *stbuf, fuse_off_t off) const struct fuse_stat *stbuf, fuse_off_t off)
{ {
@ -1448,7 +1437,6 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
fsp_fuse_intf_Flush, fsp_fuse_intf_Flush,
fsp_fuse_intf_GetFileInfo, fsp_fuse_intf_GetFileInfo,
fsp_fuse_intf_SetBasicInfo, fsp_fuse_intf_SetBasicInfo,
fsp_fuse_intf_SetAllocationSize,
fsp_fuse_intf_SetFileSize, fsp_fuse_intf_SetFileSize,
fsp_fuse_intf_CanDelete, fsp_fuse_intf_CanDelete,
fsp_fuse_intf_Rename, fsp_fuse_intf_Rename,

View File

@ -32,6 +32,9 @@
struct fuse struct fuse
{ {
struct fsp_fuse_env *env; struct fsp_fuse_env *env;
int set_umask, umask;
int set_uid, uid;
int set_gid, gid;
struct fuse_operations ops; struct fuse_operations ops;
void *data; void *data;
UINT32 DebugLog; UINT32 DebugLog;

View File

@ -42,7 +42,6 @@ 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);
break; break;

View File

@ -38,7 +38,6 @@
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

@ -18,10 +18,29 @@
#include <dll/library.h> #include <dll/library.h>
#include <launcher/launcher.h> #include <launcher/launcher.h>
#include <npapi.h> #include <npapi.h>
#include <wincred.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 the following macro to use CredUIPromptForWindowsCredentials.
* Otherwise CredUIPromptForCredentials will be used.
*/
#define FSP_NP_CREDUI_PROMPT_NEW
/*
* Define the following macro to include support for the credential manager.
*/
#define FSP_NP_CREDENTIAL_MANAGER
enum
{
FSP_NP_CREDENTIALS_NONE = 0,
FSP_NP_CREDENTIALS_PASSWORD = 1,
FSP_NP_CREDENTIALS_USERPASS = 3,
};
DWORD APIENTRY NPGetCaps(DWORD Index) DWORD APIENTRY NPGetCaps(DWORD Index)
{ {
switch (Index) switch (Index)
@ -102,6 +121,9 @@ static inline BOOLEAN FspNpParseRemoteName(PWSTR RemoteName,
PWSTR ClassName, InstanceName, P; PWSTR ClassName, InstanceName, P;
ULONG ClassNameLen, InstanceNameLen; ULONG ClassNameLen, InstanceNameLen;
if (!FspNpCheckRemoteName(RemoteName))
return FALSE;
ClassName = RemoteName + 2; /* skip \\ */ ClassName = RemoteName + 2; /* skip \\ */
for (P = ClassName; *P; P++) for (P = ClassName; *P; P++)
if (L'\\' == *P) if (L'\\' == *P)
@ -129,6 +151,27 @@ static inline BOOLEAN FspNpParseRemoteName(PWSTR RemoteName,
return TRUE; return TRUE;
} }
static inline BOOLEAN FspNpParseUserName(PWSTR RemoteName,
PWSTR UserName, ULONG UserNameSize/* in chars */)
{
PWSTR ClassName, InstanceName, P;
ULONG ClassNameLen, InstanceNameLen;
if (FspNpParseRemoteName(RemoteName,
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
{
for (P = InstanceName; *P; P++)
if ('@' == *P && (ULONG)(P - InstanceName) < UserNameSize)
{
memcpy(UserName, InstanceName, (P - InstanceName) * sizeof(WCHAR));
UserName[P - InstanceName] = L'\0';
return TRUE;
}
}
return FALSE;
}
static inline DWORD FspNpCallLauncherPipe(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize) static inline DWORD FspNpCallLauncherPipe(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
{ {
DWORD NpResult; DWORD NpResult;
@ -225,6 +268,144 @@ static WCHAR FspNpGetDriveLetter(PDWORD PLogicalDrives, PWSTR VolumeName)
return 0; return 0;
} }
static DWORD FspNpGetCredentialsKind(PWSTR RemoteName, PDWORD PCredentialsKind)
{
HKEY RegKey = 0;
DWORD NpResult, RegSize;
DWORD Credentials;
PWSTR ClassName, InstanceName;
ULONG ClassNameLen, InstanceNameLen;
WCHAR ClassNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
*PCredentialsKind = FSP_NP_CREDENTIALS_NONE;
if (!FspNpParseRemoteName(RemoteName,
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
return WN_BAD_NETNAME;
if (ClassNameLen > sizeof ClassNameBuf / sizeof ClassNameBuf[0] - 1)
ClassNameLen = sizeof ClassNameBuf / sizeof ClassNameBuf[0] - 1;
memcpy(ClassNameBuf, ClassName, ClassNameLen * sizeof(WCHAR));
ClassNameBuf[ClassNameLen] = '\0';
NpResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY, 0, KEY_READ, &RegKey);
if (ERROR_SUCCESS != NpResult)
goto exit;
RegSize = sizeof Credentials;
Credentials = 0; /* default is NO credentials */
NpResult = RegGetValueW(RegKey, ClassNameBuf, L"Credentials", RRF_RT_REG_DWORD, 0,
&Credentials, &RegSize);
if (ERROR_SUCCESS != NpResult && ERROR_FILE_NOT_FOUND != NpResult)
goto exit;
switch (Credentials)
{
case FSP_NP_CREDENTIALS_NONE:
case FSP_NP_CREDENTIALS_PASSWORD:
case FSP_NP_CREDENTIALS_USERPASS:
*PCredentialsKind = Credentials;
break;
}
NpResult = ERROR_SUCCESS;
exit:
if (0 != RegKey)
RegCloseKey(RegKey);
return NpResult;
}
static DWORD FspNpGetCredentials(
HWND hwndOwner, PWSTR Caption, DWORD PrevNpResult,
DWORD CredentialsKind,
PBOOL PSave,
PWSTR UserName, ULONG UserNameSize/* in chars */,
PWSTR Password, ULONG PasswordSize/* in chars */)
{
DWORD NpResult;
CREDUI_INFOW UiInfo;
memset(&UiInfo, 0, sizeof UiInfo);
UiInfo.cbSize = sizeof UiInfo;
UiInfo.hwndParent = hwndOwner;
UiInfo.pszCaptionText = Caption;
UiInfo.pszMessageText = L"Enter credentials to unlock this file system.";
#if !defined(FSP_NP_CREDUI_PROMPT_NEW)
NpResult = CredUIPromptForCredentialsW(&UiInfo, L"NONE", 0, 0,
UserName, UserNameSize,
Password, PasswordSize,
PSave,
CREDUI_FLAGS_GENERIC_CREDENTIALS |
CREDUI_FLAGS_DO_NOT_PERSIST |
CREDUI_FLAGS_ALWAYS_SHOW_UI |
(0 != PrevNpResult ? CREDUI_FLAGS_INCORRECT_PASSWORD : 0) |
(0 != PSave ? CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX : 0) |
(FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind ? 0/*CREDUI_FLAGS_KEEP_USERNAME*/ : 0));
#else
WCHAR Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1];
ULONG AuthPackage = 0;
PVOID InAuthBuf = 0, OutAuthBuf = 0;
ULONG InAuthSize, OutAuthSize, DomainSize;
InAuthSize = 0;
if (!CredPackAuthenticationBufferW(
CRED_PACK_GENERIC_CREDENTIALS, UserName, Password, 0, &InAuthSize) &&
ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
NpResult = GetLastError();
goto exit;
}
InAuthBuf = MemAlloc(InAuthSize);
if (0 == InAuthBuf)
{
NpResult = ERROR_NO_SYSTEM_RESOURCES;
goto exit;
}
if (!CredPackAuthenticationBufferW(
CRED_PACK_GENERIC_CREDENTIALS, UserName, Password, InAuthBuf, &InAuthSize))
{
NpResult = GetLastError();
goto exit;
}
NpResult = CredUIPromptForWindowsCredentialsW(&UiInfo, PrevNpResult,
&AuthPackage, InAuthBuf, InAuthSize, &OutAuthBuf, &OutAuthSize, PSave,
CREDUIWIN_GENERIC | (0 != PSave ? CREDUIWIN_CHECKBOX : 0));
if (ERROR_SUCCESS != NpResult)
goto exit;
DomainSize = sizeof Domain / sizeof Domain[0];
if (!CredUnPackAuthenticationBufferW(0, OutAuthBuf, OutAuthSize,
UserName, &UserNameSize, Domain, &DomainSize, Password, &PasswordSize))
{
NpResult = GetLastError();
goto exit;
}
NpResult = ERROR_SUCCESS;
exit:
if (0 != OutAuthBuf)
{
SecureZeroMemory(OutAuthBuf, OutAuthSize);
CoTaskMemFree(OutAuthBuf);
}
if (0 != InAuthBuf)
{
SecureZeroMemory(InAuthBuf, InAuthSize);
MemFree(InAuthBuf);
}
#endif
return NpResult;
}
DWORD APIENTRY NPGetConnection( DWORD APIENTRY NPGetConnection(
LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpnBufferLen) LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpnBufferLen)
{ {
@ -303,12 +484,6 @@ DWORD APIENTRY NPGetConnection(
} }
DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName) DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName)
{
return NPAddConnection3(0, lpNetResource, lpPassword, lpUserName, 0);
}
DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName, DWORD dwFlags)
{ {
DWORD NpResult; DWORD NpResult;
DWORD dwType = lpNetResource->dwType; DWORD dwType = lpNetResource->dwType;
@ -317,14 +492,15 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
WCHAR LocalNameBuf[3]; WCHAR LocalNameBuf[3];
PWSTR ClassName, InstanceName, RemoteName, P; PWSTR ClassName, InstanceName, RemoteName, P;
ULONG ClassNameLen, InstanceNameLen; ULONG ClassNameLen, InstanceNameLen;
DWORD CredentialsKind;
PWSTR PipeBuf = 0; PWSTR PipeBuf = 0;
#if defined(FSP_NP_CREDENTIAL_MANAGER)
PCREDENTIALW Credential = 0;
#endif
if (dwType & RESOURCETYPE_PRINT) if (dwType & RESOURCETYPE_PRINT)
return WN_BAD_VALUE; return WN_BAD_VALUE;
if (!FspNpCheckRemoteName(lpRemoteName))
return WN_BAD_NETNAME;
if (!FspNpParseRemoteName(lpRemoteName, if (!FspNpParseRemoteName(lpRemoteName,
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen)) &ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
return WN_BAD_NETNAME; return WN_BAD_NETNAME;
@ -344,22 +520,75 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
return WN_ALREADY_CONNECTED; return WN_ALREADY_CONNECTED;
} }
FspNpGetCredentialsKind(lpRemoteName, &CredentialsKind);
#if defined(FSP_NP_CREDENTIAL_MANAGER)
/* if we need credentials and none were passed check with the credential manager */
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind && 0 == lpPassword &&
CredReadW(lpRemoteName, CRED_TYPE_GENERIC, 0, &Credential))
{
if (sizeof(WCHAR) <= Credential->CredentialBlobSize &&
L'\0' == ((PWSTR)(Credential->CredentialBlob))
[(Credential->CredentialBlobSize / sizeof(WCHAR)) - 1])
{
lpUserName = Credential->UserName;
lpPassword = (PVOID)Credential->CredentialBlob;
}
}
#endif
/* if we need credentials and we don't have any return ACCESS DENIED */
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind)
{
int Length;
if (0 == lpPassword ||
(0 == (Length = lstrlenW(lpPassword))) || CREDUI_MAX_PASSWORD_LENGTH < Length)
{
NpResult = WN_ACCESS_DENIED;
goto exit;
}
}
if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
{
int Length;
if (0 == lpUserName ||
(0 == (Length = lstrlenW(lpUserName))) || CREDUI_MAX_USERNAME_LENGTH < Length)
{
NpResult = WN_ACCESS_DENIED;
goto exit;
}
}
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE); PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE);
if (0 == PipeBuf) if (0 == PipeBuf)
return WN_OUT_OF_MEMORY; {
NpResult = WN_OUT_OF_MEMORY;
goto exit;
}
/* we do not explicitly check, but assumption is it all fits in LAUNCHER_PIPE_BUFFER_SIZE */
P = PipeBuf; P = PipeBuf;
*P++ = LauncherSvcInstanceStart; *P++ = FSP_NP_CREDENTIALS_NONE != CredentialsKind ?
LauncherSvcInstanceStartWithSecret : LauncherSvcInstanceStart;
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0'; memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0';
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0'; memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
lstrcpyW(P, RemoteName); P += lstrlenW(RemoteName) + 1; lstrcpyW(P, RemoteName); P += lstrlenW(RemoteName) + 1;
lstrcpyW(P, LocalNameBuf); P += lstrlenW(LocalNameBuf) + 1; lstrcpyW(P, LocalNameBuf); P += lstrlenW(LocalNameBuf) + 1;
if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
{
lstrcpyW(P, lpUserName); P += lstrlenW(lpUserName) + 1;
}
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind)
{
lstrcpyW(P, lpPassword); P += lstrlenW(lpPassword) + 1;
}
NpResult = FspNpCallLauncherPipe( NpResult = FspNpCallLauncherPipe(
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE); PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE);
switch (NpResult) switch (NpResult)
{ {
case WN_SUCCESS: case WN_SUCCESS:
case WN_ACCESS_DENIED:
break; break;
case ERROR_ALREADY_EXISTS: case ERROR_ALREADY_EXISTS:
/* /*
@ -393,8 +622,89 @@ DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
break; break;
} }
exit:
MemFree(PipeBuf); MemFree(PipeBuf);
#if defined(FSP_NP_CREDENTIAL_MANAGER)
if (0 != Credential)
CredFree(Credential);
#endif
return NpResult;
}
DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName, DWORD dwFlags)
{
DWORD NpResult;
PWSTR RemoteName = lpNetResource->lpRemoteName;
DWORD CredentialsKind;
WCHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1], Password[CREDUI_MAX_PASSWORD_LENGTH + 1];
#if defined(FSP_NP_CREDENTIAL_MANAGER)
BOOL Save = TRUE;
#endif
//dwFlags |= CONNECT_INTERACTIVE | CONNECT_PROMPT; /* TESTING ONLY! */
/* CONNECT_PROMPT is only valid if CONNECT_INTERACTIVE is also set */
if (CONNECT_PROMPT == (dwFlags & (CONNECT_INTERACTIVE | CONNECT_PROMPT)))
return WN_BAD_VALUE;
/* if not CONNECT_PROMPT go ahead and attempt to NPAddConnection once */
if (0 == (dwFlags & CONNECT_PROMPT))
{
NpResult = NPAddConnection(lpNetResource, lpPassword, lpUserName);
if (WN_ACCESS_DENIED != NpResult || 0 == (dwFlags & CONNECT_INTERACTIVE))
return NpResult;
}
FspNpGetCredentialsKind(RemoteName, &CredentialsKind);
if (FSP_NP_CREDENTIALS_NONE == CredentialsKind)
return WN_CANCEL;
/* if CONNECT_INTERACTIVE keep asking the user for valid credentials or cancel */
NpResult = WN_SUCCESS;
lstrcpyW(UserName, L"UNSPECIFIED");
Password[0] = L'\0';
if (FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind)
FspNpParseUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]);
do
{
NpResult = FspNpGetCredentials(
hwndOwner, RemoteName, NpResult,
CredentialsKind,
#if defined(FSP_NP_CREDENTIAL_MANAGER)
&Save,
#else
0,
#endif
UserName, sizeof UserName / sizeof UserName[0],
Password, sizeof Password / sizeof Password[0]);
if (WN_SUCCESS != NpResult)
break;
NpResult = NPAddConnection(lpNetResource, Password, UserName);
} while (WN_ACCESS_DENIED == NpResult);
#if defined(FSP_NP_CREDENTIAL_MANAGER)
if (WN_SUCCESS == NpResult && Save)
{
CREDENTIALW Credential;
memset(&Credential, 0, sizeof Credential);
Credential.Type = CRED_TYPE_GENERIC;
Credential.Persist = CRED_PERSIST_LOCAL_MACHINE;
Credential.TargetName = RemoteName;
Credential.UserName = UserName;
Credential.CredentialBlobSize = (lstrlenW(Password) + 1) * sizeof(WCHAR);
Credential.CredentialBlob = (PVOID)Password;
CredWriteW(&Credential, 0);
}
#endif
SecureZeroMemory(Password, sizeof Password);
return NpResult; return NpResult;
} }

View File

@ -36,8 +36,23 @@
static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...); static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...);
static INIT_ONCE FspPosixInitOnce = INIT_ONCE_STATIC_INIT; static INIT_ONCE FspPosixInitOnce = INIT_ONCE_STATIC_INIT;
union
{
SID V;
UINT8 B[sizeof(SID) - sizeof(DWORD) + (1 * sizeof(DWORD))];
} FspUnmappedSidBuf =
{
/* S-1-0-65534 */
.V.Revision = SID_REVISION,
.V.SubAuthorityCount = 1,
.V.IdentifierAuthority.Value[5] = 0,
.V.SubAuthority[0] = 65534,
};
static PISID FspAccountDomainSid, FspPrimaryDomainSid; static PISID FspAccountDomainSid, FspPrimaryDomainSid;
#define FspUnmappedSid (&FspUnmappedSidBuf.V)
#define FspUnmappedUid (65534)
static BOOL WINAPI FspPosixInitialize( static BOOL WINAPI FspPosixInitialize(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{ {
@ -104,6 +119,8 @@ VOID FspPosixFinalize(BOOLEAN Dynamic)
FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid) FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
{ {
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
*PSid = 0; *PSid = 0;
/* /*
@ -157,8 +174,6 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
*/ */
else if (0x30000 <= Uid && Uid < 0x40000) else if (0x30000 <= Uid && Uid < 0x40000)
{ {
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
if (0 != FspAccountDomainSid && if (0 != FspAccountDomainSid &&
5 == FspAccountDomainSid->IdentifierAuthority.Value[5] && 5 == FspAccountDomainSid->IdentifierAuthority.Value[5] &&
4 == FspAccountDomainSid->SubAuthorityCount) 4 == FspAccountDomainSid->SubAuthorityCount)
@ -173,8 +188,6 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
} }
else if (0x100000 <= Uid && Uid < 0x200000) else if (0x100000 <= Uid && Uid < 0x200000)
{ {
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
if (0 != FspPrimaryDomainSid && if (0 != FspPrimaryDomainSid &&
5 == FspPrimaryDomainSid->IdentifierAuthority.Value[5] && 5 == FspPrimaryDomainSid->IdentifierAuthority.Value[5] &&
4 == FspPrimaryDomainSid->SubAuthorityCount) 4 == FspPrimaryDomainSid->SubAuthorityCount)
@ -210,17 +223,19 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid)
* Other well-known SIDs in the NT_AUTHORITY domain (S-1-5-X-RID): * Other well-known SIDs in the NT_AUTHORITY domain (S-1-5-X-RID):
* S-1-5-X-RID <=> uid/gid: 0x1000 * X + RID * S-1-5-X-RID <=> uid/gid: 0x1000 * X + RID
*/ */
else if (0x1000 <= Uid && Uid < 0x100000) else if (FspUnmappedUid != Uid && 0x1000 <= Uid && Uid < 0x100000)
*PSid = FspPosixCreateSid(5, 2, Uid >> 12, Uid & 0xfff); *PSid = FspPosixCreateSid(5, 2, Uid >> 12, Uid & 0xfff);
if (0 == *PSid) if (0 == *PSid)
return STATUS_NONE_MAPPED; *PSid = FspUnmappedSid;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid) FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
{ {
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
BYTE Authority; BYTE Authority;
BYTE Count; BYTE Count;
UINT32 SubAuthority0, Rid; UINT32 SubAuthority0, Rid;
@ -274,8 +289,6 @@ FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
*/ */
else if (5 <= Count && 21 == SubAuthority0) else if (5 <= Count && 21 == SubAuthority0)
{ {
InitOnceExecuteOnce(&FspPosixInitOnce, FspPosixInitialize, 0, 0);
/* /*
* The order is important! A server that is also a domain controller * The order is important! A server that is also a domain controller
* has PrimaryDomainSid == AccountDomainSid. * has PrimaryDomainSid == AccountDomainSid.
@ -312,7 +325,9 @@ FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
*/ */
*PUid = 0x60000 + Rid; *PUid = 0x60000 + Rid;
} }
else else if (
FspUnmappedSid->IdentifierAuthority.Value[5] != Authority ||
FspUnmappedSid->SubAuthority[0] != Rid)
{ {
/* [IDMAP] /* [IDMAP]
* Other well-known SIDs: * Other well-known SIDs:
@ -322,7 +337,7 @@ FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid)
} }
if (-1 == *PUid) if (-1 == *PUid)
return STATUS_NONE_MAPPED; *PUid = FspUnmappedUid;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -351,7 +366,9 @@ static PISID FspPosixCreateSid(BYTE Authority, ULONG Count, ...)
FSP_API VOID FspDeleteSid(PSID Sid, NTSTATUS (*CreateFunc)()) FSP_API VOID FspDeleteSid(PSID Sid, NTSTATUS (*CreateFunc)())
{ {
if ((NTSTATUS (*)())FspPosixMapUidToSid == CreateFunc) if (FspUnmappedSid == Sid)
;
else if ((NTSTATUS (*)())FspPosixMapUidToSid == CreateFunc)
MemFree(Sid); MemFree(Sid);
} }

View File

@ -55,6 +55,7 @@ static void usage(void)
"\n" "\n"
"commands:\n" "commands:\n"
" start ClassName InstanceName Args...\n" " start ClassName InstanceName Args...\n"
" startWithSecret ClassName InstanceName Args... Secret\n"
" stop ClassName InstanceName\n" " stop ClassName InstanceName\n"
" info ClassName InstanceName\n" " info ClassName InstanceName\n"
" list\n", " list\n",
@ -115,7 +116,8 @@ static int call_pipe_and_report(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
} }
int start(PWSTR PipeBuf, ULONG PipeBufSize, int start(PWSTR PipeBuf, ULONG PipeBufSize,
PWSTR ClassName, PWSTR InstanceName, DWORD Argc, PWSTR *Argv) PWSTR ClassName, PWSTR InstanceName, DWORD Argc, PWSTR *Argv,
BOOLEAN HasSecret)
{ {
PWSTR P; PWSTR P;
DWORD ClassNameSize, InstanceNameSize, ArgvSize; DWORD ClassNameSize, InstanceNameSize, ArgvSize;
@ -130,7 +132,7 @@ int start(PWSTR PipeBuf, ULONG PipeBufSize,
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
P = PipeBuf; P = PipeBuf;
*P++ = LauncherSvcInstanceStart; *P++ = HasSecret ? LauncherSvcInstanceStartWithSecret : LauncherSvcInstanceStart;
memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize; memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize;
memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize; memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize;
for (DWORD Argi = 0; Argc > Argi; Argi++) for (DWORD Argi = 0; Argc > Argi; Argi++)
@ -230,7 +232,17 @@ int wmain(int argc, wchar_t **argv)
if (3 > argc || argc > 12) if (3 > argc || argc > 12)
usage(); usage();
return start(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3); return start(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3,
FALSE);
}
else
if (0 == lstrcmpW(L"startWithSecret", argv[0]))
{
if (4 > argc || argc > 13)
usage();
return start(PipeBuf, LAUNCHER_PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3,
TRUE);
} }
else else
if (0 == lstrcmpW(L"stop", argv[0])) if (0 == lstrcmpW(L"stop", argv[0]))

View File

@ -19,7 +19,54 @@
#include <sddl.h> #include <sddl.h>
#define PROGNAME "WinFsp.Launcher" #define PROGNAME "WinFsp.Launcher"
#define REGKEY "SYSTEM\\CurrentControlSet\\Services\\" PROGNAME "\\Services" #define REGKEY LAUNCHER_REGKEY
BOOL CreateOverlappedPipe(
PHANDLE PReadPipe, PHANDLE PWritePipe, PSECURITY_ATTRIBUTES SecurityAttributes, DWORD Size,
DWORD ReadMode, DWORD WriteMode)
{
RPC_STATUS RpcStatus;
UUID Uuid;
WCHAR PipeNameBuf[MAX_PATH];
HANDLE ReadPipe, WritePipe;
DWORD LastError;
RpcStatus = UuidCreate(&Uuid);
if (S_OK != RpcStatus && RPC_S_UUID_LOCAL_ONLY != RpcStatus)
{
SetLastError(ERROR_INTERNAL_ERROR);
return FALSE;
}
wsprintfW(PipeNameBuf, L"\\\\.\\pipe\\"
"%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
Uuid.Data1, Uuid.Data2, Uuid.Data3,
Uuid.Data4[0], Uuid.Data4[1], Uuid.Data4[2], Uuid.Data4[3],
Uuid.Data4[4], Uuid.Data4[5], Uuid.Data4[6], Uuid.Data4[7]);
ReadPipe = CreateNamedPipeW(PipeNameBuf,
PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | ReadMode,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
1, Size, Size, 120 * 1000, SecurityAttributes);
if (INVALID_HANDLE_VALUE == ReadPipe)
return FALSE;
WritePipe = CreateFileW(PipeNameBuf,
GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
SecurityAttributes, OPEN_EXISTING, WriteMode, 0);
if (INVALID_HANDLE_VALUE == WritePipe)
{
LastError = GetLastError();
CloseHandle(ReadPipe);
SetLastError(LastError);
return FALSE;
}
*PReadPipe = ReadPipe;
*PWritePipe = WritePipe;
return TRUE;
}
typedef struct typedef struct
{ {
@ -80,6 +127,7 @@ static VOID CALLBACK KillProcessWait(PVOID Context, BOOLEAN Timeout)
typedef struct typedef struct
{ {
LONG RefCount;
PWSTR ClassName; PWSTR ClassName;
PWSTR InstanceName; PWSTR InstanceName;
PWSTR CommandLine; PWSTR CommandLine;
@ -87,6 +135,7 @@ typedef struct
DWORD ProcessId; DWORD ProcessId;
HANDLE Process; HANDLE Process;
HANDLE ProcessWait; HANDLE ProcessWait;
HANDLE StdioHandles[2];
LIST_ENTRY ListEntry; LIST_ENTRY ListEntry;
WCHAR Buffer[]; WCHAR Buffer[];
} SVC_INSTANCE; } SVC_INSTANCE;
@ -231,8 +280,132 @@ static NTSTATUS SvcInstanceAccessCheck(HANDLE ClientToken, ULONG DesiredAccess,
return Result; return Result;
} }
NTSTATUS SvcInstanceCreateProcess(PWSTR Executable, PWSTR CommandLine,
HANDLE StdioHandles[2],
PPROCESS_INFORMATION ProcessInfo)
{
STARTUPINFOEXW StartupInfoEx;
HANDLE ChildHandles[3] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0/* DO NOT CLOSE!*/ };
HANDLE ParentHandles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
SECURITY_ATTRIBUTES PipeAttributes = { sizeof(SECURITY_ATTRIBUTES), 0, TRUE };
PPROC_THREAD_ATTRIBUTE_LIST AttrList = 0;
SIZE_T Size;
NTSTATUS Result;
memset(&StartupInfoEx, 0, sizeof StartupInfoEx);
StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx.StartupInfo;
if (0 != StdioHandles)
{
/*
* Create child process and redirect stdin/stdout. Do *not* inherit other handles.
*
* For explanation see:
* https://blogs.msdn.microsoft.com/oldnewthing/20111216-00/?p=8873/
*/
/* create stdin read/write ends; make them inheritable */
if (!CreateOverlappedPipe(&ChildHandles[0], &ParentHandles[0], &PipeAttributes, 0,
0, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
/* create stdout read/write ends; make them inheritable */
if (!CreateOverlappedPipe(&ParentHandles[1], &ChildHandles[1], &PipeAttributes, 0,
FILE_FLAG_OVERLAPPED, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
ChildHandles[2] = GetStdHandle(STD_ERROR_HANDLE);
Size = 0;
if (!InitializeProcThreadAttributeList(0, 1, 0, &Size) &&
ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
AttrList = MemAlloc(Size);
if (0 == AttrList)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!InitializeProcThreadAttributeList(AttrList, 1, 0, &Size))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
/* only the child ends of stdin/stdout are actually inherited */
if (!UpdateProcThreadAttribute(AttrList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
ChildHandles, sizeof ChildHandles, 0, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
StartupInfoEx.StartupInfo.cb = sizeof StartupInfoEx;
StartupInfoEx.lpAttributeList = AttrList;
StartupInfoEx.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
StartupInfoEx.StartupInfo.hStdInput = ChildHandles[0];
StartupInfoEx.StartupInfo.hStdOutput = ChildHandles[1];
StartupInfoEx.StartupInfo.hStdError = ChildHandles[2];
if (!CreateProcessW(Executable, CommandLine, 0, 0, TRUE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT, 0, 0,
&StartupInfoEx.StartupInfo, ProcessInfo))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
else
{
if (!CreateProcessW(Executable, CommandLine, 0, 0, FALSE,
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP, 0, 0,
&StartupInfoEx.StartupInfo, ProcessInfo))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
}
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
{
if (INVALID_HANDLE_VALUE != ParentHandles[0])
CloseHandle(ParentHandles[0]);
if (INVALID_HANDLE_VALUE != ParentHandles[0])
CloseHandle(ParentHandles[1]);
}
else if (0 != StdioHandles)
{
StdioHandles[0] = ParentHandles[0];
StdioHandles[1] = ParentHandles[1];
}
if (INVALID_HANDLE_VALUE != ChildHandles[0])
CloseHandle(ChildHandles[0]);
if (INVALID_HANDLE_VALUE != ChildHandles[1])
CloseHandle(ChildHandles[1]);
MemFree(AttrList);
return Result;
}
NTSTATUS SvcInstanceCreate(HANDLE ClientToken, NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv0, HANDLE Job, PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv0, HANDLE Job,
BOOLEAN RedirectStdio,
SVC_INSTANCE **PSvcInstance) SVC_INSTANCE **PSvcInstance)
{ {
SVC_INSTANCE *SvcInstance = 0; SVC_INSTANCE *SvcInstance = 0;
@ -241,10 +414,9 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
DWORD ClassNameSize, InstanceNameSize; DWORD ClassNameSize, InstanceNameSize;
WCHAR Executable[MAX_PATH], CommandLineBuf[512], SecurityBuf[512]; WCHAR Executable[MAX_PATH], CommandLineBuf[512], SecurityBuf[512];
PWSTR CommandLine, Security; PWSTR CommandLine, Security;
DWORD JobControl; DWORD JobControl, Credentials;
PSECURITY_DESCRIPTOR SecurityDescriptor = 0; PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
PWSTR Argv[10]; PWSTR Argv[10];
STARTUPINFOW StartupInfo;
PROCESS_INFORMATION ProcessInfo; PROCESS_INFORMATION ProcessInfo;
NTSTATUS Result; NTSTATUS Result;
@ -259,7 +431,6 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
Argv[0] = 0; Argv[0] = 0;
Argc++; Argc++;
memset(&StartupInfo, 0, sizeof StartupInfo);
memset(&ProcessInfo, 0, sizeof ProcessInfo); memset(&ProcessInfo, 0, sizeof ProcessInfo);
EnterCriticalSection(&SvcInstanceLock); EnterCriticalSection(&SvcInstanceLock);
@ -277,6 +448,22 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
goto exit; goto exit;
} }
RegSize = sizeof Credentials;
Credentials = 0;
RegResult = RegGetValueW(RegKey, ClassName, L"Credentials", RRF_RT_REG_DWORD, 0,
&Credentials, &RegSize);
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
{
Result = FspNtStatusFromWin32(RegResult);
goto exit;
}
if ((!RedirectStdio && 0 != Credentials) ||
( RedirectStdio && 0 == Credentials))
{
Result = STATUS_DEVICE_CONFIGURATION_ERROR;
goto exit;
}
RegSize = sizeof Executable; RegSize = sizeof Executable;
Executable[0] = L'\0'; Executable[0] = L'\0';
RegResult = RegGetValueW(RegKey, ClassName, L"Executable", RRF_RT_REG_SZ, 0, RegResult = RegGetValueW(RegKey, ClassName, L"Executable", RRF_RT_REG_SZ, 0,
@ -336,7 +523,7 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
goto exit; goto exit;
} }
FspDebugLogSD(__FUNCTION__ ": SDDL = %s\n", SecurityDescriptor); //FspDebugLogSD(__FUNCTION__ ": SDDL = %s\n", SecurityDescriptor);
Result = SvcInstanceAccessCheck(ClientToken, SERVICE_START, SecurityDescriptor); Result = SvcInstanceAccessCheck(ClientToken, SERVICE_START, SecurityDescriptor);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
@ -353,23 +540,23 @@ NTSTATUS SvcInstanceCreate(HANDLE ClientToken,
} }
memset(SvcInstance, 0, sizeof *SvcInstance); memset(SvcInstance, 0, sizeof *SvcInstance);
SvcInstance->RefCount = 2;
memcpy(SvcInstance->Buffer, ClassName, ClassNameSize); memcpy(SvcInstance->Buffer, ClassName, ClassNameSize);
memcpy(SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR), InstanceName, InstanceNameSize); memcpy(SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR), InstanceName, InstanceNameSize);
SvcInstance->ClassName = SvcInstance->Buffer; SvcInstance->ClassName = SvcInstance->Buffer;
SvcInstance->InstanceName = SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR); SvcInstance->InstanceName = SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR);
SvcInstance->SecurityDescriptor = SecurityDescriptor; SvcInstance->SecurityDescriptor = SecurityDescriptor;
SvcInstance->StdioHandles[0] = INVALID_HANDLE_VALUE;
SvcInstance->StdioHandles[1] = INVALID_HANDLE_VALUE;
Result = SvcInstanceReplaceArguments(CommandLine, Argc, Argv, &SvcInstance->CommandLine); Result = SvcInstanceReplaceArguments(CommandLine, Argc, Argv, &SvcInstance->CommandLine);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
StartupInfo.cb = sizeof StartupInfo; Result = SvcInstanceCreateProcess(Executable, SvcInstance->CommandLine,
if (!CreateProcessW(Executable, SvcInstance->CommandLine, 0, 0, FALSE, RedirectStdio ? SvcInstance->StdioHandles : 0, &ProcessInfo);
CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP, 0, 0, &StartupInfo, &ProcessInfo)) if (!NT_SUCCESS(Result))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit; goto exit;
}
SvcInstance->ProcessId = ProcessInfo.dwProcessId; SvcInstance->ProcessId = ProcessInfo.dwProcessId;
SvcInstance->Process = ProcessInfo.hProcess; SvcInstance->Process = ProcessInfo.hProcess;
@ -413,6 +600,11 @@ exit:
if (0 != SvcInstance) if (0 != SvcInstance)
{ {
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[0])
CloseHandle(SvcInstance->StdioHandles[0]);
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[1])
CloseHandle(SvcInstance->StdioHandles[1]);
if (0 != SvcInstance->ProcessWait) if (0 != SvcInstance->ProcessWait)
UnregisterWaitEx(SvcInstance->ProcessWait, 0); UnregisterWaitEx(SvcInstance->ProcessWait, 0);
@ -435,13 +627,21 @@ exit:
return Result; return Result;
} }
VOID SvcInstanceDelete(SVC_INSTANCE *SvcInstance) static VOID SvcInstanceRelease(SVC_INSTANCE *SvcInstance)
{ {
if (0 != InterlockedDecrement(&SvcInstance->RefCount))
return;
EnterCriticalSection(&SvcInstanceLock); EnterCriticalSection(&SvcInstanceLock);
if (RemoveEntryList(&SvcInstance->ListEntry)) if (RemoveEntryList(&SvcInstance->ListEntry))
SetEvent(SvcInstanceEvent); SetEvent(SvcInstanceEvent);
LeaveCriticalSection(&SvcInstanceLock); LeaveCriticalSection(&SvcInstanceLock);
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[0])
CloseHandle(SvcInstance->StdioHandles[0]);
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[1])
CloseHandle(SvcInstance->StdioHandles[1]);
if (0 != SvcInstance->ProcessWait) if (0 != SvcInstance->ProcessWait)
UnregisterWaitEx(SvcInstance->ProcessWait, 0); UnregisterWaitEx(SvcInstance->ProcessWait, 0);
if (0 != SvcInstance->Process) if (0 != SvcInstance->Process)
@ -457,15 +657,102 @@ static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Timeout)
{ {
SVC_INSTANCE *SvcInstance = Context; SVC_INSTANCE *SvcInstance = Context;
SvcInstanceDelete(SvcInstance); SvcInstanceRelease(SvcInstance);
} }
NTSTATUS SvcInstanceStart(HANDLE ClientToken, NTSTATUS SvcInstanceStart(HANDLE ClientToken,
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv, HANDLE Job) PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv, HANDLE Job,
BOOLEAN HasSecret)
{ {
SVC_INSTANCE *SvcInstance; SVC_INSTANCE *SvcInstance;
NTSTATUS Result;
return SvcInstanceCreate(ClientToken, ClassName, InstanceName, Argc, Argv, Job, &SvcInstance); if (HasSecret && (0 == Argc || L'\0' == Argv[Argc - 1][0]))
return STATUS_INVALID_PARAMETER;
HasSecret = !!HasSecret;
Result = SvcInstanceCreate(ClientToken, ClassName, InstanceName,
Argc - HasSecret, Argv, Job, HasSecret,
&SvcInstance);
if (!NT_SUCCESS(Result))
return Result;
if (!HasSecret)
Result = STATUS_SUCCESS;
else
{
PWSTR Secret = Argv[Argc - 1];
UINT8 ReqBuf[256];
UINT8 RspBuf[2];
DWORD BytesTransferred;
OVERLAPPED Overlapped;
DWORD WaitResult;
if (0 == (BytesTransferred =
WideCharToMultiByte(CP_UTF8, 0, Secret, lstrlenW(Secret), ReqBuf, sizeof ReqBuf, 0, 0)))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
if (!WriteFile(SvcInstance->StdioHandles[0], ReqBuf, BytesTransferred, &BytesTransferred, 0))
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
CloseHandle(SvcInstance->StdioHandles[0]);
SvcInstance->StdioHandles[0] = INVALID_HANDLE_VALUE;
memset(&Overlapped, 0, sizeof Overlapped);
if (!ReadFile(SvcInstance->StdioHandles[1], RspBuf, sizeof RspBuf, 0, &Overlapped) &&
ERROR_IO_PENDING != GetLastError())
{
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
/*
* We need to perform a GetOverlappedResult with a timeout. GetOverlappedResultEx would
* be perfect except that it is a Windows 8 and above API. We will therefore replace with
* WaitForSingleObject followed by GetOverlappedResult on success.
*/
WaitResult = WaitForSingleObject(SvcInstance->StdioHandles[1],
LAUNCHER_START_WITH_SECRET_TIMEOUT);
if (WAIT_OBJECT_0 == WaitResult)
Result = GetOverlappedResult(SvcInstance->StdioHandles[1], &Overlapped, &BytesTransferred, TRUE) ?
STATUS_SUCCESS : FspNtStatusFromWin32(GetLastError());
else if (WAIT_TIMEOUT == WaitResult)
Result = STATUS_TIMEOUT;
else
Result = FspNtStatusFromWin32(GetLastError());
if (!NT_SUCCESS(Result) || STATUS_TIMEOUT == Result)
{
CancelIoEx(SvcInstance->StdioHandles[1], &Overlapped);
goto exit;
}
if (sizeof RspBuf <= BytesTransferred && 'O' == RspBuf[0] && 'K' == RspBuf[1])
Result = STATUS_SUCCESS;
else
Result = STATUS_ACCESS_DENIED;
}
exit:
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[0])
{
CloseHandle(SvcInstance->StdioHandles[0]);
SvcInstance->StdioHandles[0] = INVALID_HANDLE_VALUE;
}
if (INVALID_HANDLE_VALUE != SvcInstance->StdioHandles[1])
{
CloseHandle(SvcInstance->StdioHandles[1]);
SvcInstance->StdioHandles[1] = INVALID_HANDLE_VALUE;
}
SvcInstanceRelease(SvcInstance);
return Result;
} }
NTSTATUS SvcInstanceStop(HANDLE ClientToken, NTSTATUS SvcInstanceStop(HANDLE ClientToken,
@ -625,7 +912,7 @@ static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
&SecurityAttributes.lpSecurityDescriptor, 0)) &SecurityAttributes.lpSecurityDescriptor, 0))
goto fail; goto fail;
FspDebugLogSD(__FUNCTION__ ": SDDL = %s\n", SecurityAttributes.lpSecurityDescriptor); //FspDebugLogSD(__FUNCTION__ ": SDDL = %s\n", SecurityAttributes.lpSecurityDescriptor);
SvcInstanceEvent = CreateEventW(0, TRUE, TRUE, 0); SvcInstanceEvent = CreateEventW(0, TRUE, TRUE, 0);
if (0 == SvcInstanceEvent) if (0 == SvcInstanceEvent)
@ -909,12 +1196,16 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
PWSTR P = PipeBuf, PipeBufEnd = PipeBuf + *PSize / sizeof(WCHAR); PWSTR P = PipeBuf, PipeBufEnd = PipeBuf + *PSize / sizeof(WCHAR);
PWSTR ClassName, InstanceName; PWSTR ClassName, InstanceName;
ULONG Argc; PWSTR Argv[9]; ULONG Argc; PWSTR Argv[9];
BOOLEAN HasSecret = FALSE;
NTSTATUS Result; NTSTATUS Result;
*PSize = 0; *PSize = 0;
switch (*P++) switch (*P++)
{ {
case LauncherSvcInstanceStartWithSecret:
HasSecret = TRUE;
/* fall through! */
case LauncherSvcInstanceStart: case LauncherSvcInstanceStart:
ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd); ClassName = SvcPipeTransactGetPart(&P, PipeBufEnd);
InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd); InstanceName = SvcPipeTransactGetPart(&P, PipeBufEnd);
@ -924,7 +1215,8 @@ static VOID SvcPipeTransact(HANDLE ClientToken, PWSTR PipeBuf, PULONG PSize)
Result = STATUS_INVALID_PARAMETER; Result = STATUS_INVALID_PARAMETER;
if (0 != ClassName && 0 != InstanceName) if (0 != ClassName && 0 != InstanceName)
Result = SvcInstanceStart(ClientToken, ClassName, InstanceName, Argc, Argv, SvcJob); Result = SvcInstanceStart(ClientToken, ClassName, InstanceName, Argc, Argv, SvcJob,
HasSecret);
SvcPipeTransactResult(Result, PipeBuf, PSize); SvcPipeTransactResult(Result, PipeBuf, PSize);
break; break;

View File

@ -21,13 +21,17 @@
#include <winfsp/winfsp.h> #include <winfsp/winfsp.h>
#include <shared/minimal.h> #include <shared/minimal.h>
#define LAUNCHER_REGKEY "SYSTEM\\CurrentControlSet\\Services\\WinFsp.Launcher\\Services"
#define LAUNCHER_STOP_TIMEOUT 5500 #define LAUNCHER_STOP_TIMEOUT 5500
#define LAUNCHER_KILL_TIMEOUT 5000 #define LAUNCHER_KILL_TIMEOUT 5000
#define LAUNCHER_PIPE_NAME "\\\\.\\pipe\\WinFsp.{14E7137D-22B4-437A-B0C1-D21D1BDF3767}" #define LAUNCHER_PIPE_NAME "\\\\.\\pipe\\WinFsp.{14E7137D-22B4-437A-B0C1-D21D1BDF3767}"
#define LAUNCHER_PIPE_BUFFER_SIZE 2048 #define LAUNCHER_PIPE_BUFFER_SIZE 4096
#define LAUNCHER_PIPE_DEFAULT_TIMEOUT 3000 #define LAUNCHER_PIPE_DEFAULT_TIMEOUT 3000
#define LAUNCHER_START_WITH_SECRET_TIMEOUT 15000
/* /*
* The launcher named pipe SDDL gives full access to LocalSystem and Administrators and * The launcher named pipe SDDL gives full access to LocalSystem and Administrators and
* GENERIC_READ and FILE_WRITE_DATA access to Everyone. We are careful not to give the * GENERIC_READ and FILE_WRITE_DATA access to Everyone. We are careful not to give the
@ -53,6 +57,7 @@
enum enum
{ {
LauncherSvcInstanceStart = 'S', /* requires: SERVICE_START */ LauncherSvcInstanceStart = 'S', /* requires: SERVICE_START */
LauncherSvcInstanceStartWithSecret = 'X', /* requires: SERVICE_START */
LauncherSvcInstanceStop = 'T', /* requires: SERVICE_STOP */ LauncherSvcInstanceStop = 'T', /* requires: SERVICE_STOP */
LauncherSvcInstanceInfo = 'I', /* requires: SERVICE_QUERY_STATUS */ LauncherSvcInstanceInfo = 'I', /* requires: SERVICE_QUERY_STATUS */
LauncherSvcInstanceList = 'L', /* requires: none*/ LauncherSvcInstanceList = 'L', /* requires: none*/

View File

@ -655,13 +655,14 @@ enum
#define FspIopPostWorkRequestBestEffort(D, R)\ #define FspIopPostWorkRequestBestEffort(D, R)\
FspIopPostWorkRequestFunnel(D, R, TRUE) FspIopPostWorkRequestFunnel(D, R, TRUE)
#define FspIopCompleteIrp(I, R) FspIopCompleteIrpEx(I, R, TRUE) #define FspIopCompleteIrp(I, R) FspIopCompleteIrpEx(I, R, TRUE)
#define REQ_ALIGN_SIZE 16
typedef VOID FSP_IOP_REQUEST_FINI(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4]); typedef VOID FSP_IOP_REQUEST_FINI(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4]);
typedef struct typedef struct
{ {
FSP_IOP_REQUEST_FINI *RequestFini; FSP_IOP_REQUEST_FINI *RequestFini;
PVOID Context[4]; PVOID Context[4];
FSP_FSCTL_TRANSACT_RSP *Response; FSP_FSCTL_TRANSACT_RSP *Response;
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 RequestBuf[]; __declspec(align(REQ_ALIGN_SIZE)) UINT8 RequestBuf[];
} FSP_FSCTL_TRANSACT_REQ_HEADER; } FSP_FSCTL_TRANSACT_REQ_HEADER;
static inline static inline
PVOID *FspIopRequestContextAddress(FSP_FSCTL_TRANSACT_REQ *Request, ULONG I) PVOID *FspIopRequestContextAddress(FSP_FSCTL_TRANSACT_REQ *Request, ULONG I)
@ -1034,4 +1035,26 @@ extern WCHAR FspFileDescDirectoryPatternMatchAll[];
extern FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache; extern FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache;
extern ULONG FspMvMdlMappingNoWrite; extern ULONG FspMvMdlMappingNoWrite;
/*
* Fixes
*/
/* ObCloseHandle: add missing prototype */
#if (NTDDI_VERSION < NTDDI_WIN7)
NTKERNELAPI
NTSTATUS
ObCloseHandle(
_In_ HANDLE Handle,
_In_ KPROCESSOR_MODE PreviousMode
);
#endif
/* RtlEqualMemory: this is defined as memcmp, which does not exist on Win7 x86! */
#undef RtlEqualMemory
static inline
LOGICAL RtlEqualMemory(const VOID *Source1, const VOID *Source2, SIZE_T Length)
{
return Length == RtlCompareMemory(Source1, Source2, Length);
}
#endif #endif

View File

@ -89,82 +89,82 @@ SYM(FSCTL_DFSR_SET_GHOST_HANDLE_STATE)
SYM(FSCTL_TXFS_LIST_TRANSACTIONS) SYM(FSCTL_TXFS_LIST_TRANSACTIONS)
SYM(FSCTL_QUERY_PAGEFILE_ENCRYPTION) SYM(FSCTL_QUERY_PAGEFILE_ENCRYPTION)
SYM(FSCTL_RESET_VOLUME_ALLOCATION_HINTS) SYM(FSCTL_RESET_VOLUME_ALLOCATION_HINTS)
SYM(FSCTL_QUERY_DEPENDENT_VOLUME) //SYM(FSCTL_QUERY_DEPENDENT_VOLUME)
SYM(FSCTL_SD_GLOBAL_CHANGE) //SYM(FSCTL_SD_GLOBAL_CHANGE)
SYM(FSCTL_TXFS_READ_BACKUP_INFORMATION2) SYM(FSCTL_TXFS_READ_BACKUP_INFORMATION2)
SYM(FSCTL_LOOKUP_STREAM_FROM_CLUSTER) //SYM(FSCTL_LOOKUP_STREAM_FROM_CLUSTER)
SYM(FSCTL_TXFS_WRITE_BACKUP_INFORMATION2) //SYM(FSCTL_TXFS_WRITE_BACKUP_INFORMATION2)
SYM(FSCTL_FILE_TYPE_NOTIFICATION) //SYM(FSCTL_FILE_TYPE_NOTIFICATION)
SYM(FSCTL_FILE_LEVEL_TRIM) //SYM(FSCTL_FILE_LEVEL_TRIM)
SYM(FSCTL_GET_BOOT_AREA_INFO) //SYM(FSCTL_GET_BOOT_AREA_INFO)
SYM(FSCTL_GET_RETRIEVAL_POINTER_BASE) //SYM(FSCTL_GET_RETRIEVAL_POINTER_BASE)
SYM(FSCTL_SET_PERSISTENT_VOLUME_STATE) //SYM(FSCTL_SET_PERSISTENT_VOLUME_STATE)
SYM(FSCTL_QUERY_PERSISTENT_VOLUME_STATE) //SYM(FSCTL_QUERY_PERSISTENT_VOLUME_STATE)
SYM(FSCTL_REQUEST_OPLOCK) //SYM(FSCTL_REQUEST_OPLOCK)
SYM(FSCTL_CSV_TUNNEL_REQUEST) //SYM(FSCTL_CSV_TUNNEL_REQUEST)
SYM(FSCTL_IS_CSV_FILE) //SYM(FSCTL_IS_CSV_FILE)
SYM(FSCTL_QUERY_FILE_SYSTEM_RECOGNITION) //SYM(FSCTL_QUERY_FILE_SYSTEM_RECOGNITION)
SYM(FSCTL_CSV_GET_VOLUME_PATH_NAME) //SYM(FSCTL_CSV_GET_VOLUME_PATH_NAME)
SYM(FSCTL_CSV_GET_VOLUME_NAME_FOR_VOLUME_MOUNT_POINT) //SYM(FSCTL_CSV_GET_VOLUME_NAME_FOR_VOLUME_MOUNT_POINT)
SYM(FSCTL_CSV_GET_VOLUME_PATH_NAMES_FOR_VOLUME_NAME) //SYM(FSCTL_CSV_GET_VOLUME_PATH_NAMES_FOR_VOLUME_NAME)
SYM(FSCTL_IS_FILE_ON_CSV_VOLUME) //SYM(FSCTL_IS_FILE_ON_CSV_VOLUME)
SYM(FSCTL_CORRUPTION_HANDLING) //SYM(FSCTL_CORRUPTION_HANDLING)
SYM(FSCTL_OFFLOAD_READ) //SYM(FSCTL_OFFLOAD_READ)
SYM(FSCTL_OFFLOAD_WRITE) //SYM(FSCTL_OFFLOAD_WRITE)
SYM(FSCTL_CSV_INTERNAL) //SYM(FSCTL_CSV_INTERNAL)
SYM(FSCTL_SET_PURGE_FAILURE_MODE) //SYM(FSCTL_SET_PURGE_FAILURE_MODE)
SYM(FSCTL_QUERY_FILE_LAYOUT) //SYM(FSCTL_QUERY_FILE_LAYOUT)
SYM(FSCTL_IS_VOLUME_OWNED_BYCSVFS) //SYM(FSCTL_IS_VOLUME_OWNED_BYCSVFS)
SYM(FSCTL_GET_INTEGRITY_INFORMATION) //SYM(FSCTL_GET_INTEGRITY_INFORMATION)
SYM(FSCTL_SET_INTEGRITY_INFORMATION) //SYM(FSCTL_SET_INTEGRITY_INFORMATION)
SYM(FSCTL_QUERY_FILE_REGIONS) //SYM(FSCTL_QUERY_FILE_REGIONS)
SYM(FSCTL_DEDUP_FILE) //SYM(FSCTL_DEDUP_FILE)
SYM(FSCTL_DEDUP_QUERY_FILE_HASHES) //SYM(FSCTL_DEDUP_QUERY_FILE_HASHES)
SYM(FSCTL_DEDUP_QUERY_RANGE_STATE) //SYM(FSCTL_DEDUP_QUERY_RANGE_STATE)
SYM(FSCTL_DEDUP_QUERY_REPARSE_INFO) //SYM(FSCTL_DEDUP_QUERY_REPARSE_INFO)
SYM(FSCTL_RKF_INTERNAL) //SYM(FSCTL_RKF_INTERNAL)
SYM(FSCTL_SCRUB_DATA) //SYM(FSCTL_SCRUB_DATA)
SYM(FSCTL_REPAIR_COPIES) //SYM(FSCTL_REPAIR_COPIES)
SYM(FSCTL_DISABLE_LOCAL_BUFFERING) //SYM(FSCTL_DISABLE_LOCAL_BUFFERING)
SYM(FSCTL_CSV_MGMT_LOCK) //SYM(FSCTL_CSV_MGMT_LOCK)
SYM(FSCTL_CSV_QUERY_DOWN_LEVEL_FILE_SYSTEM_CHARACTERISTICS) //SYM(FSCTL_CSV_QUERY_DOWN_LEVEL_FILE_SYSTEM_CHARACTERISTICS)
SYM(FSCTL_ADVANCE_FILE_ID) //SYM(FSCTL_ADVANCE_FILE_ID)
SYM(FSCTL_CSV_SYNC_TUNNEL_REQUEST) //SYM(FSCTL_CSV_SYNC_TUNNEL_REQUEST)
SYM(FSCTL_CSV_QUERY_VETO_FILE_DIRECT_IO) //SYM(FSCTL_CSV_QUERY_VETO_FILE_DIRECT_IO)
SYM(FSCTL_WRITE_USN_REASON) //SYM(FSCTL_WRITE_USN_REASON)
SYM(FSCTL_CSV_CONTROL) //SYM(FSCTL_CSV_CONTROL)
SYM(FSCTL_GET_REFS_VOLUME_DATA) //SYM(FSCTL_GET_REFS_VOLUME_DATA)
SYM(FSCTL_CSV_H_BREAKING_SYNC_TUNNEL_REQUEST) //SYM(FSCTL_CSV_H_BREAKING_SYNC_TUNNEL_REQUEST)
SYM(FSCTL_QUERY_STORAGE_CLASSES) //SYM(FSCTL_QUERY_STORAGE_CLASSES)
SYM(FSCTL_QUERY_REGION_INFO) //SYM(FSCTL_QUERY_REGION_INFO)
SYM(FSCTL_USN_TRACK_MODIFIED_RANGES) //SYM(FSCTL_USN_TRACK_MODIFIED_RANGES)
SYM(FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT) //SYM(FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT)
SYM(FSCTL_SVHDX_SYNC_TUNNEL_REQUEST) //SYM(FSCTL_SVHDX_SYNC_TUNNEL_REQUEST)
SYM(FSCTL_SVHDX_SET_INITIATOR_INFORMATION) //SYM(FSCTL_SVHDX_SET_INITIATOR_INFORMATION)
SYM(FSCTL_SET_EXTERNAL_BACKING) //SYM(FSCTL_SET_EXTERNAL_BACKING)
SYM(FSCTL_GET_EXTERNAL_BACKING) //SYM(FSCTL_GET_EXTERNAL_BACKING)
SYM(FSCTL_DELETE_EXTERNAL_BACKING) //SYM(FSCTL_DELETE_EXTERNAL_BACKING)
SYM(FSCTL_ENUM_EXTERNAL_BACKING) //SYM(FSCTL_ENUM_EXTERNAL_BACKING)
SYM(FSCTL_ENUM_OVERLAY) //SYM(FSCTL_ENUM_OVERLAY)
SYM(FSCTL_ADD_OVERLAY) //SYM(FSCTL_ADD_OVERLAY)
SYM(FSCTL_REMOVE_OVERLAY) //SYM(FSCTL_REMOVE_OVERLAY)
SYM(FSCTL_UPDATE_OVERLAY) //SYM(FSCTL_UPDATE_OVERLAY)
SYM(FSCTL_DUPLICATE_EXTENTS_TO_FILE) //SYM(FSCTL_DUPLICATE_EXTENTS_TO_FILE)
SYM(FSCTL_SPARSE_OVERALLOCATE) //SYM(FSCTL_SPARSE_OVERALLOCATE)
SYM(FSCTL_STORAGE_QOS_CONTROL) //SYM(FSCTL_STORAGE_QOS_CONTROL)
SYM(FSCTL_INITIATE_FILE_METADATA_OPTIMIZATION) //SYM(FSCTL_INITIATE_FILE_METADATA_OPTIMIZATION)
SYM(FSCTL_QUERY_FILE_METADATA_OPTIMIZATION) //SYM(FSCTL_QUERY_FILE_METADATA_OPTIMIZATION)
SYM(FSCTL_SVHDX_ASYNC_TUNNEL_REQUEST) //SYM(FSCTL_SVHDX_ASYNC_TUNNEL_REQUEST)
SYM(FSCTL_GET_WOF_VERSION) //SYM(FSCTL_GET_WOF_VERSION)
SYM(FSCTL_HCS_SYNC_TUNNEL_REQUEST) //SYM(FSCTL_HCS_SYNC_TUNNEL_REQUEST)
SYM(FSCTL_HCS_ASYNC_TUNNEL_REQUEST) //SYM(FSCTL_HCS_ASYNC_TUNNEL_REQUEST)
SYM(FSCTL_QUERY_EXTENT_READ_CACHE_INFO) //SYM(FSCTL_QUERY_EXTENT_READ_CACHE_INFO)
SYM(FSCTL_QUERY_REFS_VOLUME_COUNTER_INFO) //SYM(FSCTL_QUERY_REFS_VOLUME_COUNTER_INFO)
SYM(FSCTL_CLEAN_VOLUME_METADATA) //SYM(FSCTL_CLEAN_VOLUME_METADATA)
SYM(FSCTL_SET_INTEGRITY_INFORMATION_EX) //SYM(FSCTL_SET_INTEGRITY_INFORMATION_EX)
SYM(FSCTL_SUSPEND_OVERLAY) //SYM(FSCTL_SUSPEND_OVERLAY)
SYM(FSCTL_VIRTUAL_STORAGE_QUERY_PROPERTY) //SYM(FSCTL_VIRTUAL_STORAGE_QUERY_PROPERTY)
SYM(FSCTL_FILESYSTEM_GET_STATISTICS_EX) //SYM(FSCTL_FILESYSTEM_GET_STATISTICS_EX)
SYM(FSCTL_LMR_GET_LINK_TRACKING_INFORMATION) SYM(FSCTL_LMR_GET_LINK_TRACKING_INFORMATION)
SYM(FSCTL_LMR_SET_LINK_TRACKING_INFORMATION) SYM(FSCTL_LMR_SET_LINK_TRACKING_INFORMATION)
SYM(IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER) SYM(IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER)

View File

@ -48,10 +48,12 @@ NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response
#endif #endif
/* Requests (and RequestHeaders) must be 16-byte aligned, because we use the low 4 bits for flags */ /* Requests (and RequestHeaders) must be 16-byte aligned, because we use the low 4 bits for flags */
#if 16 != MEMORY_ALLOCATION_ALIGNMENT #if REQ_ALIGN_SIZE <= MEMORY_ALLOCATION_ALIGNMENT
#define REQ_HEADER_ALIGNMASK 15 #define REQ_HEADER_ALIGN_MASK 0
#define REQ_HEADER_ALIGN_OVERHEAD 0
#else #else
#define REQ_HEADER_ALIGNMASK 0 #define REQ_HEADER_ALIGN_MASK (REQ_ALIGN_SIZE - 1)
#define REQ_HEADER_ALIGN_OVERHEAD (sizeof(PVOID) + REQ_HEADER_ALIGN_MASK)
#endif #endif
NTSTATUS FspIopCreateRequestFunnel( NTSTATUS FspIopCreateRequestFunnel(
@ -74,20 +76,23 @@ NTSTATUS FspIopCreateRequestFunnel(
if (FlagOn(Flags, FspIopRequestMustSucceed)) if (FlagOn(Flags, FspIopRequestMustSucceed))
RequestHeader = FspAllocatePoolMustSucceed( RequestHeader = FspAllocatePoolMustSucceed(
FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool, FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool,
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGNMASK, sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGN_OVERHEAD,
FSP_ALLOC_INTERNAL_TAG); FSP_ALLOC_INTERNAL_TAG);
else else
{ {
RequestHeader = ExAllocatePoolWithTag( RequestHeader = ExAllocatePoolWithTag(
FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool, FlagOn(Flags, FspIopRequestNonPaged) ? NonPagedPool : PagedPool,
sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGNMASK, sizeof *RequestHeader + sizeof *Request + ExtraSize + REQ_HEADER_ALIGN_OVERHEAD,
FSP_ALLOC_INTERNAL_TAG); FSP_ALLOC_INTERNAL_TAG);
if (0 == RequestHeader) if (0 == RequestHeader)
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
#if 0 != REQ_HEADER_ALIGNMASK #if 0 != REQ_HEADER_ALIGN_MASK
RequestHeader = (PVOID)(((UINT_PTR)RequestHeader + REQ_HEADER_ALIGNMASK) & REQ_HEADER_ALIGNMASK); PVOID Allocation = RequestHeader;
RequestHeader = (PVOID)(((UINT_PTR)RequestHeader + REQ_HEADER_ALIGN_OVERHEAD) &
~REQ_HEADER_ALIGN_MASK);
((PVOID *)RequestHeader)[-1] = Allocation;
#endif #endif
RtlZeroMemory(RequestHeader, sizeof *RequestHeader + sizeof *Request + ExtraSize); RtlZeroMemory(RequestHeader, sizeof *RequestHeader + sizeof *Request + ExtraSize);
@ -127,6 +132,10 @@ VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request)
if (0 != RequestHeader->Response) if (0 != RequestHeader->Response)
FspFree(RequestHeader->Response); FspFree(RequestHeader->Response);
#if 0 != REQ_HEADER_ALIGN_MASK
RequestHeader = ((PVOID *)RequestHeader)[-1];
#endif
FspFree(RequestHeader); FspFree(RequestHeader);
} }

View File

@ -20,6 +20,7 @@
#include <sddl.h> #include <sddl.h>
#include <map> #include <map>
#include <cassert> #include <cassert>
#include <VersionHelpers.h>
/* /*
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes * Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
@ -273,7 +274,7 @@ BOOLEAN MemfsFileNodeMapEnumerateDescendants(MEMFS_FILE_NODE_MAP *FileNodeMap, M
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode0, UINT64 FileSize, PVOID FileNode0, UINT64 NewSize, BOOLEAN SetAllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo); FSP_FSCTL_FILE_INFO *FileInfo);
static NTSTATUS GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
@ -539,7 +540,8 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
__try __try
{ {
*P = *P | 0; *P = *P | 0;
assert(0); assert(!IsWindows8OrGreater());
/* only on Windows 8 we can make the buffer read-only! */
} }
__except (EXCEPTION_EXECUTE_HANDLER) __except (EXCEPTION_EXECUTE_HANDLER)
{ {
@ -564,7 +566,7 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
Offset = FileNode->FileInfo.FileSize; Offset = FileNode->FileInfo.FileSize;
EndOffset = Offset + Length; EndOffset = Offset + Length;
if (EndOffset > FileNode->FileInfo.FileSize) if (EndOffset > FileNode->FileInfo.FileSize)
SetFileSize(FileSystem, Request, FileNode, EndOffset, FileInfo); SetFileSize(FileSystem, Request, FileNode, EndOffset, FALSE, FileInfo);
} }
memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset)); memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset));
@ -617,59 +619,52 @@ static NTSTATUS SetBasicInfo(FSP_FILE_SYSTEM *FileSystem,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS SetAllocationSize(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode0, UINT64 AllocationSize, PVOID FileNode0, UINT64 NewSize, BOOLEAN SetAllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo) FSP_FSCTL_FILE_INFO *FileInfo)
{ {
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0; MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
PVOID FileData;
if (FileNode->FileInfo.AllocationSize != AllocationSize) if (SetAllocationSize)
{ {
if (AllocationSize > Memfs->MaxFileSize) if (FileNode->FileInfo.AllocationSize != NewSize)
{
if (NewSize > Memfs->MaxFileSize)
return STATUS_DISK_FULL; return STATUS_DISK_FULL;
FileData = realloc(FileNode->FileData, (size_t)AllocationSize); PVOID FileData = realloc(FileNode->FileData, (size_t)NewSize);
if (0 == FileData && 0 != AllocationSize) if (0 == FileData && 0 != NewSize)
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
FileNode->FileData = FileData; FileNode->FileData = FileData;
FileNode->FileInfo.AllocationSize = AllocationSize; FileNode->FileInfo.AllocationSize = NewSize;
if (FileNode->FileInfo.FileSize > AllocationSize) if (FileNode->FileInfo.FileSize > NewSize)
FileNode->FileInfo.FileSize = AllocationSize; FileNode->FileInfo.FileSize = NewSize;
} }
}
*FileInfo = FileNode->FileInfo; else
return STATUS_SUCCESS;
}
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode0, UINT64 FileSize,
FSP_FSCTL_FILE_INFO *FileInfo)
{
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
if (FileNode->FileInfo.FileSize != FileSize)
{ {
if (FileNode->FileInfo.AllocationSize < FileSize) if (FileNode->FileInfo.FileSize != NewSize)
{
if (FileNode->FileInfo.AllocationSize < NewSize)
{ {
UINT64 AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT; UINT64 AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT;
UINT64 AllocationSize = (FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit; UINT64 AllocationSize = (NewSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
NTSTATUS Result = SetAllocationSize(FileSystem, Request, FileNode, AllocationSize, FileInfo); NTSTATUS Result = SetFileSize(FileSystem, Request, FileNode, AllocationSize, TRUE,
FileInfo);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
} }
if (FileNode->FileInfo.FileSize < FileSize) if (FileNode->FileInfo.FileSize < NewSize)
memset((PUINT8)FileNode->FileData + FileNode->FileInfo.FileSize, 0, memset((PUINT8)FileNode->FileData + FileNode->FileInfo.FileSize, 0,
(size_t)(FileSize - FileNode->FileInfo.FileSize)); (size_t)(NewSize - FileNode->FileInfo.FileSize));
FileNode->FileInfo.FileSize = FileSize; FileNode->FileInfo.FileSize = NewSize;
}
} }
*FileInfo = FileNode->FileInfo; *FileInfo = FileNode->FileInfo;
@ -952,7 +947,6 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
Flush, Flush,
GetFileInfo, GetFileInfo,
SetBasicInfo, SetBasicInfo,
SetAllocationSize,
SetFileSize, SetFileSize,
CanDelete, CanDelete,
Rename, Rename,

32
tst/secret/secret.c Normal file
View File

@ -0,0 +1,32 @@
/*
* Compile:
* - cl secret.c
*
* Register:
* - secret.reg (fix Executable path first)
*
* Run:
* - launchctl-x64 startWithSecret secret 1 nopass
* - launchctl-x64 startWithSecret secret 1 foobar
*/
#include <stdio.h>
int main()
{
char pass[256];
gets(pass);
if (0 == strcmp("foobar", pass))
{
puts("OK");
fprintf(stderr, "OK secret=\"%s\"\n", pass);
}
else
{
puts("KO");
fprintf(stderr, "KO secret=\"%s\"\n", pass);
}
return 0;
}

BIN
tst/secret/secret.reg Normal file

Binary file not shown.

View File

@ -10,6 +10,7 @@ void posix_map_sid_test(void)
UINT32 Uid; UINT32 Uid;
} map[] = } map[] =
{ {
{ L"S-1-0-65534", 65534 },
{ L"S-1-0-0", 0x10000 }, { L"S-1-0-0", 0x10000 },
{ L"S-1-1-0", 0x10100 }, { L"S-1-1-0", 0x10100 },
{ L"S-1-2-0", 0x10200 }, { L"S-1-2-0", 0x10200 },