diff --git a/inc/winfsp/winfsp.h b/inc/winfsp/winfsp.h index ec63a0d0..d1bb1120 100644 --- a/inc/winfsp/winfsp.h +++ b/inc/winfsp/winfsp.h @@ -37,10 +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 *); + NTSTATUS (*AccessCheck)(FSP_FILE_SYSTEM *, + FSP_FSCTL_TRANSACT_REQ *, DWORD, PDWORD); + NTSTATUS (*QuerySecurity)(FSP_FILE_SYSTEM *, + PWSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, SIZE_T *); } FSP_FILE_SYSTEM; FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath, @@ -87,6 +87,15 @@ FSP_API NTSTATUS FspSendResponse(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspSendResponseWithStatus(FSP_FILE_SYSTEM *FileSystem, FSP_FSCTL_TRANSACT_REQ *Request, NTSTATUS Result); +/* + * Access Checks + */ +FSP_API PGENERIC_MAPPING FspGetFileGenericMapping(VOID); +FSP_API NTSTATUS FspOpenAccessToken(FSP_FILE_SYSTEM *FileSystem, + FSP_FSCTL_TRANSACT_REQ *Request, PHANDLE PAccessToken); +FSP_API NTSTATUS FspAccessCheck(FSP_FILE_SYSTEM *FileSystem, + FSP_FSCTL_TRANSACT_REQ *Request, DWORD DesiredAccess, PDWORD PGrantedAccess); + /* * Path Handling */ diff --git a/src/dll/access.c b/src/dll/access.c index 2969c67a..7bc94c68 100644 --- a/src/dll/access.c +++ b/src/dll/access.c @@ -25,46 +25,109 @@ FSP_API NTSTATUS FspOpenAccessToken(FSP_FILE_SYSTEM *FileSystem, return FspFsctlOpenAccessToken(FileSystem->VolumeHandle, Request->Hint, PAccessToken); } -#if 0 +static NTSTATUS FspGetFileSecurityDescriptor(FSP_FILE_SYSTEM *FileSystem, + PWSTR FileName, PSECURITY_DESCRIPTOR *PSecurityDescriptor, SIZE_T *PSecurityDescriptorSize) +{ + for (;;) + { + NTSTATUS Result = FileSystem->QuerySecurity(FileSystem, + FileName, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + *PSecurityDescriptor, PSecurityDescriptorSize); + if (STATUS_BUFFER_OVERFLOW != Result) + return Result; + + MemFree(*PSecurityDescriptor); + *PSecurityDescriptor = MemAlloc(*PSecurityDescriptorSize); + if (0 == *PSecurityDescriptor) + return STATUS_INSUFFICIENT_RESOURCES; + } +} + FSP_API NTSTATUS FspAccessCheck(FSP_FILE_SYSTEM *FileSystem, - FSP_FSCTL_TRANSACT_REQ *Request, PUINT32 PGrantedAccess) + FSP_FSCTL_TRANSACT_REQ *Request, DWORD DesiredAccess, PDWORD PGrantedAccess) { if (0 != FileSystem->AccessCheck) - return FileSystem->AccessCheck(FileSystem, Request, PGrantedAccess); + return FileSystem->AccessCheck(FileSystem, Request, DesiredAccess, PGrantedAccess); + + if (0 == FileSystem->QuerySecurity) + { + *PGrantedAccess = DesiredAccess; + return STATUS_SUCCESS; + } NTSTATUS Result; - PWSTR FileName = (PVOID)Request->Buffer; - PSECURITY_DESCRIPTOR SecurityDescriptor = 0; HANDLE AccessToken = 0; + PSECURITY_DESCRIPTOR SecurityDescriptor = 0; + SIZE_T SecurityDescriptorSize; DWORD PrivilegeSetLength; - BOOLEAN AccessStatus; - s + BOOL AccessStatus; + *PGrantedAccess = 0; - SecurityDescriptor = MemAlloc(1024); + Result = FspOpenAccessToken(FileSystem, Request, &AccessToken); + if (!NT_SUCCESS(Result)) + goto exit; + + SecurityDescriptorSize = 1024; + SecurityDescriptor = MemAlloc(SecurityDescriptorSize); if (0 == SecurityDescriptor) { Result = STATUS_INSUFFICIENT_RESOURCES; goto exit; } - Result = FspGetSecurityDescriptor(); + if (!Request->Req.Create.HasTraversePrivilege) + { + PWSTR Path = (PWSTR)Request->Buffer, Prefix; + DWORD TraverseAccess; - Result = FspOpenAccessToken(FileSystem, Request, &AccessToken); + for (;;) + { + FspPathPrefix(Path, &Prefix, &Path); + if (L'\0' == Path[0]) + { + FspPathCombine((PWSTR)Request->Buffer, Path); + break; + } + + Prefix = L'\0' == Prefix[0] ? L"\\" : (PWSTR)Request->Buffer; + Result = FspGetFileSecurityDescriptor(FileSystem, Prefix, + &SecurityDescriptor, &SecurityDescriptorSize); + + FspPathCombine((PWSTR)Request->Buffer, Path); + + if (!NT_SUCCESS(Result)) + goto exit; + + if (AccessCheck(SecurityDescriptor, AccessToken, FILE_TRAVERSE, + &FspFileGenericMapping, 0, &PrivilegeSetLength, &TraverseAccess, &AccessStatus)) + Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED; + else + Result = FspNtStatusFromWin32(GetLastError()); + + if (!NT_SUCCESS(Result)) + goto exit; + } + } + + Result = FspGetFileSecurityDescriptor(FileSystem, (PWSTR)Request->Buffer, + &SecurityDescriptor, &SecurityDescriptorSize); if (!NT_SUCCESS(Result)) goto exit; - if (AccessCheck(&SecurityDescriptor, AccessToken, Request->Req.Create.DesiredAccess, + if (AccessCheck(SecurityDescriptor, AccessToken, DesiredAccess, &FspFileGenericMapping, 0, &PrivilegeSetLength, PGrantedAccess, &AccessStatus)) Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED; else Result = FspNtStatusFromWin32(GetLastError()); exit: + + MemFree(SecurityDescriptor); + if (0 != AccessToken) CloseHandle(AccessToken); - MemFree(SecurityDescriptor); return Result; } -#endif