diff --git a/build/VStudio/testing/winfsp-tests.vcxproj b/build/VStudio/testing/winfsp-tests.vcxproj index 3447dde0..c1cb3345 100644 --- a/build/VStudio/testing/winfsp-tests.vcxproj +++ b/build/VStudio/testing/winfsp-tests.vcxproj @@ -177,6 +177,7 @@ TurnOffAllWarnings + diff --git a/build/VStudio/testing/winfsp-tests.vcxproj.filters b/build/VStudio/testing/winfsp-tests.vcxproj.filters index d017e9d8..47ab4f4b 100644 --- a/build/VStudio/testing/winfsp-tests.vcxproj.filters +++ b/build/VStudio/testing/winfsp-tests.vcxproj.filters @@ -22,6 +22,9 @@ Source + + Source + diff --git a/build/VStudio/winfsp_dll.vcxproj b/build/VStudio/winfsp_dll.vcxproj index 0384b7ed..3ca1fa0a 100644 --- a/build/VStudio/winfsp_dll.vcxproj +++ b/build/VStudio/winfsp_dll.vcxproj @@ -24,11 +24,14 @@ + + + diff --git a/build/VStudio/winfsp_dll.vcxproj.filters b/build/VStudio/winfsp_dll.vcxproj.filters index a868f31b..878ca2ac 100644 --- a/build/VStudio/winfsp_dll.vcxproj.filters +++ b/build/VStudio/winfsp_dll.vcxproj.filters @@ -40,6 +40,15 @@ Source + + Source + + + Source + + + Source + diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index 625657b8..60906990 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -110,7 +110,6 @@ typedef struct UINT32 FileAttributes; /* FILE_ATTRIBUTE_{NORMAL,DIRECTORY,etc.} */ FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; /* security descriptor for new files */ UINT64 AllocationSize; /* initial allocation size */ - UINT64 AccessToken; /* (HANDLE); request access token; sent if NoAccessCheck is 0 */ UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */ UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */ FSP_FSCTL_TRANSACT_BUF Ea; /* reserved; not currently implemented */ @@ -214,6 +213,8 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath, FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle, PVOID ResponseBuf, SIZE_T ResponseBufSize, PVOID RequestBuf, SIZE_T *PRequestBufSize); +FSP_API NTSTATUS FspFsctlOpenAccessToken(HANDLE VolumeHandle, + UINT64 Hint, PHANDLE PAccessToken); #endif #endif diff --git a/inc/winfsp/winfsp.h b/inc/winfsp/winfsp.h index 61b84482..ec63a0d0 100644 --- a/inc/winfsp/winfsp.h +++ b/inc/winfsp/winfsp.h @@ -21,6 +21,9 @@ #include +/* + * File System + */ typedef struct _FSP_FILE_SYSTEM FSP_FILE_SYSTEM; typedef VOID FSP_FILE_SYSTEM_DISPATCHER(FSP_FILE_SYSTEM *, FSP_FSCTL_TRANSACT_REQ *); typedef NTSTATUS FSP_FILE_SYSTEM_OPERATION(FSP_FILE_SYSTEM *, FSP_FSCTL_TRANSACT_REQ *); @@ -34,6 +37,10 @@ typedef struct _FSP_FILE_SYSTEM FSP_FILE_SYSTEM_DISPATCHER *Dispatcher; FSP_FILE_SYSTEM_DISPATCHER *EnterOperation, *LeaveOperation; FSP_FILE_SYSTEM_OPERATION *Operations[FspFsctlTransactKindCount]; + NTSTATUS (*AccessCheck)(FSP_FILE_SYSTEM *, FSP_FSCTL_TRANSACT_REQ *, + PDWORD); + NTSTATUS (*QuerySecurity)(FSP_FILE_SYSTEM *, FSP_FSCTL_TRANSACT_REQ *, + SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, SIZE_T *); } FSP_FILE_SYSTEM; FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath, @@ -80,6 +87,17 @@ FSP_API NTSTATUS FspSendResponse(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspSendResponseWithStatus(FSP_FILE_SYSTEM *FileSystem, FSP_FSCTL_TRANSACT_REQ *Request, NTSTATUS Result); +/* + * Path Handling + */ +FSP_API VOID FspPathPrefix(PWSTR Path, PWSTR *PPrefix, PWSTR *PRemain); +FSP_API VOID FspPathSuffix(PWSTR Path, PWSTR *PRemain, PWSTR *PSuffix); +FSP_API VOID FspPathCombine(PWSTR Prefix, PWSTR Suffix); + +/* + * Utility + */ +FSP_API PGENERIC_MAPPING FspGetFileGenericMapping(VOID); FSP_API NTSTATUS FspNtStatusFromWin32(DWORD Error); FSP_API VOID FspDebugLog(const char *format, ...); diff --git a/src/dll/access.c b/src/dll/access.c new file mode 100644 index 00000000..2969c67a --- /dev/null +++ b/src/dll/access.c @@ -0,0 +1,70 @@ +/** + * @file dll/access.c + * + * @copyright 2015 Bill Zissimopoulos + */ + +#include + +static GENERIC_MAPPING FspFileGenericMapping = +{ + .GenericRead = FILE_GENERIC_READ, + .GenericWrite = FILE_GENERIC_WRITE, + .GenericExecute = FILE_GENERIC_EXECUTE, + .GenericAll = FILE_ALL_ACCESS, +}; + +FSP_API PGENERIC_MAPPING FspGetFileGenericMapping(VOID) +{ + return &FspFileGenericMapping; +} + +FSP_API NTSTATUS FspOpenAccessToken(FSP_FILE_SYSTEM *FileSystem, + FSP_FSCTL_TRANSACT_REQ *Request, PHANDLE PAccessToken) +{ + return FspFsctlOpenAccessToken(FileSystem->VolumeHandle, Request->Hint, PAccessToken); +} + +#if 0 +FSP_API NTSTATUS FspAccessCheck(FSP_FILE_SYSTEM *FileSystem, + FSP_FSCTL_TRANSACT_REQ *Request, PUINT32 PGrantedAccess) +{ + if (0 != FileSystem->AccessCheck) + return FileSystem->AccessCheck(FileSystem, Request, PGrantedAccess); + + NTSTATUS Result; + PWSTR FileName = (PVOID)Request->Buffer; + PSECURITY_DESCRIPTOR SecurityDescriptor = 0; + HANDLE AccessToken = 0; + DWORD PrivilegeSetLength; + BOOLEAN AccessStatus; + s + *PGrantedAccess = 0; + + SecurityDescriptor = MemAlloc(1024); + if (0 == SecurityDescriptor) + { + Result = STATUS_INSUFFICIENT_RESOURCES; + goto exit; + } + + Result = FspGetSecurityDescriptor(); + + Result = FspOpenAccessToken(FileSystem, Request, &AccessToken); + if (!NT_SUCCESS(Result)) + goto exit; + + if (AccessCheck(&SecurityDescriptor, AccessToken, Request->Req.Create.DesiredAccess, + &FspFileGenericMapping, 0, &PrivilegeSetLength, PGrantedAccess, &AccessStatus)) + Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED; + else + Result = FspNtStatusFromWin32(GetLastError()); + +exit: + if (0 != AccessToken) + CloseHandle(AccessToken); + MemFree(SecurityDescriptor); + + return Result; +} +#endif diff --git a/src/dll/create.c b/src/dll/create.c new file mode 100644 index 00000000..a831eb06 --- /dev/null +++ b/src/dll/create.c @@ -0,0 +1,112 @@ +/** + * @file dll/create.c + * + * @copyright 2015 Bill Zissimopoulos + */ + +#include + +#if 0 +static NTSTATUS FspFileSystemOpCreate_FileCreate(FSP_FILE_SYSTEM *FileSystem, + FSP_FSCTL_TRANSACT_REQ *Request) +{ + NTSTATUS Result; + DWORD GrantedAccess; + PVOID File; + FSP_FSCTL_TRANSACT_RSP Response; + + Result = FspAccessCheck(FileSystem, Request, TRUE, &GrantedAccess); + if (!NT_SUCCESS(Result)) + return FspSendResponseWithStatus(FileSystem, Request, Result); + + Result = FileSystem->FileCreate(FileSystem, Request, &File); + if (!NT_SUCCESS(Result)) + return FspSendResponseWithStatus(FileSystem, Request, Result); + + /* !!!: set share access */ + + memset(&Response, 0, sizeof Response); + Response.Size = sizeof Response; + Response.Kind = Request->Kind; + Response.Hint = Request->Hint; + Response.IoStatus.Status = STATUS_SUCCESS; + Response.IoStatus.Information = FILE_CREATED; + Response.Rsp.Create.Opened.UserContext = (UINT_PTR)File; + Response.Rsp.Create.Opened.GrantedAccess = GrantedAccess; + return FspSendResponse(FileSystem, &Response); +} + +static NTSTATUS FspFileSystemOpCreate_FileOpen(FSP_FILE_SYSTEM *FileSystem, + FSP_FSCTL_TRANSACT_REQ *Request) +{ + NTSTATUS Result; + DWORD GrantedAccess; + PVOID File; + FSP_FSCTL_TRANSACT_RSP Response; + + Result = FspAccessCheck(FileSystem, Request, FALSE, &GrantedAccess); + if (!NT_SUCCESS(Result)) + return FspSendResponseWithStatus(FileSystem, Request, Result); + + Result = FileSystem->FileOpen(FileSystem, Request, &File); + if (!NT_SUCCESS(Result)) + return FspSendResponseWithStatus(FileSystem, Request, Result); + + Result = FspShareCheck(FileSystem, Request, GrantedAccess, File); + if (!NT_SUCCESS(Result)) + { + FileSystem->FileCleanupClose(FileSystem, Request, File); + return FspSendResponseWithStatus(FileSystem, Request, Result); + } + + memset(&Response, 0, sizeof Response); + Response.Size = sizeof Response; + Response.Kind = Request->Kind; + Response.Hint = Request->Hint; + Response.IoStatus.Status = STATUS_SUCCESS; + Response.IoStatus.Information = FILE_CREATED; + Response.Rsp.Create.Opened.UserContext = (UINT_PTR)File; + Response.Rsp.Create.Opened.GrantedAccess = GrantedAccess; + return FspSendResponse(FileSystem, &Response); +} + +static NTSTATUS FspFileSystemOpCreate_FileOpenIf(FSP_FILE_SYSTEM *FileSystem, + FSP_FSCTL_TRANSACT_REQ *Request) +{ + return STATUS_INVALID_PARAMETER; +} + +static NTSTATUS FspFileSystemOpCreate_FileOverwrite(FSP_FILE_SYSTEM *FileSystem, + FSP_FSCTL_TRANSACT_REQ *Request, BOOLEAN Supersede) +{ + return STATUS_INVALID_PARAMETER; +} + +static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSystem, + FSP_FSCTL_TRANSACT_REQ *Request) +{ + return STATUS_INVALID_PARAMETER; +} + +FSP_API NTSTATUS FspFileSystemOpCreate(FSP_FILE_SYSTEM *FileSystem, + FSP_FSCTL_TRANSACT_REQ *Request) +{ + switch ((Request->Req.Create.CreateOptions >> 24) & 0xff) + { + case FILE_CREATE: + return FspFileSystemOpCreate_FileCreate(FileSystem, Request); + case FILE_OPEN: + return FspFileSystemOpCreate_FileOpen(FileSystem, Request); + case FILE_OPEN_IF: + return FspFileSystemOpCreate_FileOpenIf(FileSystem, Request); + case FILE_OVERWRITE: + return FspFileSystemOpCreate_FileOverwrite(FileSystem, Request, FALSE); + case FILE_SUPERSEDE: + return FspFileSystemOpCreate_FileOverwrite(FileSystem, Request, TRUE); + case FILE_OVERWRITE_IF: + return FspFileSystemOpCreate_FileOverwriteIf(FileSystem, Request); + default: + return FspSendResponseWithStatus(FileSystem, Request, STATUS_INVALID_PARAMETER); + } +} +#endif diff --git a/src/dll/fsctl.c b/src/dll/fsctl.c index 8bc56ece..81be2cbf 100644 --- a/src/dll/fsctl.c +++ b/src/dll/fsctl.c @@ -109,3 +109,11 @@ FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle, exit: return Result; } + +FSP_API NTSTATUS FspFsctlOpenAccessToken(HANDLE VolumeHandle, + UINT64 Hint, PHANDLE PAccessToken) +{ + *PAccessToken = 0; + + return STATUS_NOT_IMPLEMENTED; +} diff --git a/src/dll/path.c b/src/dll/path.c new file mode 100644 index 00000000..1e100506 --- /dev/null +++ b/src/dll/path.c @@ -0,0 +1,56 @@ +/** + * @file dll/path.c + * + * @copyright 2015 Bill Zissimopoulos + */ + +#include + +FSP_API VOID FspPathPrefix(PWSTR Path, PWSTR *PPrefix, PWSTR *PRemain) +{ + PWSTR Pointer; + + for (Pointer = Path; *Pointer; Pointer++) + if (L'\\' == *Pointer) + { + *Pointer++ = L'\0'; + for (; L'\\' == *Pointer; Pointer++) + ; + break; + } + + *PPrefix = Path; + *PRemain = Pointer; +} + +FSP_API VOID FspPathSuffix(PWSTR Path, PWSTR *PRemain, PWSTR *PSuffix) +{ + PWSTR Pointer, RemainEnd, Suffix = 0; + + for (Pointer = Path; *Pointer;) + if (L'\\' == *Pointer) + { + RemainEnd = Pointer++; + for (; L'\\' == *Pointer; Pointer++) + ; + Suffix = Pointer; + } + else + Pointer++; + + *PRemain = Path; + if (Path < Suffix) + { + *RemainEnd = L'\0'; + *PSuffix = Suffix; + } + else + *PSuffix = Pointer; +} + +FSP_API VOID FspPathCombine(PWSTR Prefix, PWSTR Suffix) +{ + for (; Prefix < Suffix; Prefix++) + if (L'\0' == *Prefix) + *Prefix = L'\\'; +} diff --git a/src/sys/create.c b/src/sys/create.c index ca142995..2cc7b336 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -256,7 +256,6 @@ static NTSTATUS FspFsvolCreate( FSP_FSCTL_DEFAULT_ALIGN_UP(Request->FileName.Size); Request->Req.Create.SecurityDescriptor.Size = (UINT16)SecurityDescriptorSize; Request->Req.Create.AllocationSize = AllocationSize.QuadPart; - Request->Req.Create.AccessToken = 0; Request->Req.Create.DesiredAccess = DesiredAccess; Request->Req.Create.ShareAccess = ShareAccess; Request->Req.Create.Ea.Offset = 0; diff --git a/tst/winfsp-tests/path-test.c b/tst/winfsp-tests/path-test.c new file mode 100644 index 00000000..a65df42d --- /dev/null +++ b/tst/winfsp-tests/path-test.c @@ -0,0 +1,108 @@ +#include +#include + +void path_prefix_test(void) +{ + PWSTR ipaths[] = + { + L"", + L"\\", + L"\\\\", + L"\\a", + L"\\\\a", + L"\\\\a\\", + L"\\\\a\\\\", + L"a\\", + L"a\\\\", + L"a\\b", + L"a\\\\b", + L"foo\\\\\\bar\\\\baz", + L"foo\\\\\\bar\\\\baz\\", + L"foo\\\\\\bar\\\\baz\\\\", + }; + PWSTR opaths[] = + { + L"", L"", + L"", L"", + L"", L"", + L"", L"a", + L"", L"a", + L"", L"a\\", + L"", L"a\\\\", + L"a", L"", + L"a", L"", + L"a", L"b", + L"a", L"b", + L"foo", L"bar\\\\baz", + L"foo", L"bar\\\\baz\\", + L"foo", L"bar\\\\baz\\\\", + }; + + for (size_t i = 0; sizeof ipaths / sizeof ipaths[0] > i; i++) + { + PWSTR Prefix, Remain; + WCHAR buf[32]; + wcscpy_s(buf, 32, ipaths[i]); + FspPathPrefix(buf, &Prefix, &Remain); + ASSERT(0 == wcscmp(opaths[2 * i + 0], Prefix)); + ASSERT(0 == wcscmp(opaths[2 * i + 1], Remain)); + FspPathCombine(Prefix, Remain); + ASSERT(0 == wcscmp(ipaths[i], buf)); + } +} + +void path_suffix_test(void) +{ + PWSTR ipaths[] = + { + L"", + L"\\", + L"\\\\", + L"\\a", + L"\\\\a", + L"\\\\a\\", + L"\\\\a\\\\", + L"a\\", + L"a\\\\", + L"a\\b", + L"a\\\\b", + L"foo\\\\\\bar\\\\baz", + L"foo\\\\\\bar\\\\baz\\", + L"foo\\\\\\bar\\\\baz\\\\", + }; + PWSTR opaths[] = + { + L"", L"", + L"", L"", + L"", L"", + L"", L"a", + L"", L"a", + L"\\\\a", L"", + L"\\\\a", L"", + L"a", L"", + L"a", L"", + L"a", L"b", + L"a", L"b", + L"foo\\\\\\bar", L"baz", + L"foo\\\\\\bar\\\\baz", L"", + L"foo\\\\\\bar\\\\baz", L"", + }; + + for (size_t i = 0; sizeof ipaths / sizeof ipaths[0] > i; i++) + { + PWSTR Remain, Suffix; + WCHAR buf[32]; + wcscpy_s(buf, 32, ipaths[i]); + FspPathSuffix(buf, &Remain, &Suffix); + ASSERT(0 == wcscmp(opaths[2 * i + 0], Remain)); + ASSERT(0 == wcscmp(opaths[2 * i + 1], Suffix)); + FspPathCombine(Remain, Suffix); + ASSERT(0 == wcscmp(ipaths[i], buf)); + } +} + +void path_tests(void) +{ + TEST(path_prefix_test); + TEST(path_suffix_test); +} diff --git a/tst/winfsp-tests/winfsp-tests.c b/tst/winfsp-tests/winfsp-tests.c index 848a4bca..cde6c340 100644 --- a/tst/winfsp-tests/winfsp-tests.c +++ b/tst/winfsp-tests/winfsp-tests.c @@ -5,6 +5,7 @@ int WinFspNetTests = 1; int main(int argc, char *argv[]) { + TESTSUITE(path_tests); TESTSUITE(mount_tests); TESTSUITE(timeout_tests);