From 3bf4140f9179da6beedd1cbe744f71e8048b9ba7 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 21 Oct 2016 19:13:05 -0700 Subject: [PATCH] sys,dll: backup/restore privilege support --- inc/winfsp/fsctl.h | 5 ++++- src/dll/debug.c | 9 +++++++-- src/dll/fsop.c | 17 +++++++++++++---- src/dll/security.c | 4 +++- src/sys/create.c | 18 ++++++++++++++++-- 5 files changed, 43 insertions(+), 10 deletions(-) diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index e5f0d7da..3d78d716 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -218,13 +218,16 @@ typedef struct UINT64 AllocationSize; /* initial allocation size */ UINT64 AccessToken; /* request access token (HANDLE) */ UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */ + UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */ UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */ FSP_FSCTL_TRANSACT_BUF Ea; /* reserved; not currently implemented */ UINT32 UserMode:1; /* request originated in user mode */ UINT32 HasTraversePrivilege:1; /* requestor has TOKEN_HAS_TRAVERSE_PRIVILEGE */ + UINT32 HasBackupPrivilege:1; /* requestor has TOKEN_HAS_BACKUP_PRIVILEGE */ + UINT32 HasRestorePrivilege:1; /* requestor has TOKEN_HAS_RESTORE_PRIVILEGE */ UINT32 OpenTargetDirectory:1; /* open target dir and report FILE_{EXISTS,DOES_NOT_EXIST} */ UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */ - UINT32 ReservedFlags:28; + UINT32 ReservedFlags:26; UINT16 NamedStream; /* request targets named stream; colon offset in FileName */ } Create; struct diff --git a/src/dll/debug.c b/src/dll/debug.c index 1a5b63fc..0a7407fb 100644 --- a/src/dll/debug.c +++ b/src/dll/debug.c @@ -299,12 +299,16 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request) OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, &Sddl, 0); - FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c] \"%S\", " + FspDebugLog("%S[TID=%04lx]: %p: >>Create [%c%c%c%c%c%c] \"%S\", " "%s, CreateOptions=%lx, FileAttributes=%lx, Security=%s%s%s, " - "AllocationSize=%lx:%lx, AccessToken=%p, DesiredAccess=%lx, ShareAccess=%lx\n", + "AllocationSize=%lx:%lx, " + "AccessToken=%p, DesiredAccess=%lx, GrantedAccess=%lx, " + "ShareAccess=%lx\n", FspDiagIdent(), GetCurrentThreadId(), Request->Hint, Request->Req.Create.UserMode ? 'U' : 'K', Request->Req.Create.HasTraversePrivilege ? 'T' : '-', + Request->Req.Create.HasBackupPrivilege ? 'B' : '-', + Request->Req.Create.HasRestorePrivilege ? 'R' : '-', Request->Req.Create.OpenTargetDirectory ? 'D' : '-', Request->Req.Create.CaseSensitive ? 'C' : '-', (PWSTR)Request->Buffer, @@ -317,6 +321,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request) MAKE_UINT32_PAIR(Request->Req.Create.AllocationSize), (PVOID)Request->Req.Create.AccessToken, Request->Req.Create.DesiredAccess, + Request->Req.Create.GrantedAccess, Request->Req.Create.ShareAccess); LocalFree(Sddl); break; diff --git a/src/dll/fsop.c b/src/dll/fsop.c index cd9c24d6..be322b11 100644 --- a/src/dll/fsop.c +++ b/src/dll/fsop.c @@ -137,7 +137,7 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem, PSECURITY_DESCRIPTOR *PSecurityDescriptor) { NTSTATUS Result; - UINT32 GrantedAccess; + UINT32 ParentDesiredAccess, GrantedAccess; /* * CreateCheck does different checks depending on whether we are @@ -161,9 +161,14 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem, if (!Request->Req.Create.NamedStream) { + if (Request->Req.Create.HasRestorePrivilege) + ParentDesiredAccess = 0; + else if (Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) + ParentDesiredAccess = FILE_ADD_SUBDIRECTORY; + else + ParentDesiredAccess = FILE_ADD_FILE; Result = FspAccessCheckEx(FileSystem, Request, TRUE, AllowTraverseCheck, - (Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) ? - FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, + ParentDesiredAccess, &GrantedAccess, PSecurityDescriptor); if (STATUS_REPARSE == Result) Result = FspFileSystemCallResolveReparsePoints(FileSystem, Request, Response, GrantedAccess); @@ -171,6 +176,7 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem, { *PGrantedAccess = (MAXIMUM_ALLOWED & Request->Req.Create.DesiredAccess) ? FspGetFileGenericMapping()->GenericAll : Request->Req.Create.DesiredAccess; + *PGrantedAccess |= Request->Req.Create.GrantedAccess; } } else @@ -190,6 +196,7 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem, if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED)) *PGrantedAccess &= ~(DELETE | FILE_WRITE_DATA) | (Request->Req.Create.DesiredAccess & (DELETE | FILE_WRITE_DATA)); + *PGrantedAccess |= Request->Req.Create.GrantedAccess; } } @@ -225,6 +232,7 @@ NTSTATUS FspFileSystemOpenCheck(FSP_FILE_SYSTEM *FileSystem, *PGrantedAccess = GrantedAccess; if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED)) *PGrantedAccess &= ~DELETE | (Request->Req.Create.DesiredAccess & DELETE); + *PGrantedAccess |= Request->Req.Create.GrantedAccess; } return Result; @@ -263,6 +271,7 @@ NTSTATUS FspFileSystemOverwriteCheck(FSP_FILE_SYSTEM *FileSystem, if (0 == (Request->Req.Create.DesiredAccess & MAXIMUM_ALLOWED)) *PGrantedAccess &= ~(DELETE | FILE_WRITE_DATA) | (Request->Req.Create.DesiredAccess & (DELETE | FILE_WRITE_DATA)); + *PGrantedAccess |= Request->Req.Create.GrantedAccess; } return Result; @@ -286,7 +295,7 @@ NTSTATUS FspFileSystemOpenTargetDirectoryCheck(FSP_FILE_SYSTEM *FileSystem, if (STATUS_REPARSE == Result) Result = FspFileSystemCallResolveReparsePoints(FileSystem, Request, Response, GrantedAccess); else if (NT_SUCCESS(Result)) - *PGrantedAccess = GrantedAccess; + *PGrantedAccess = GrantedAccess | Request->Req.Create.GrantedAccess; return Result; } diff --git a/src/dll/security.c b/src/dll/security.c index f1b0a598..f1fc8169 100644 --- a/src/dll/security.c +++ b/src/dll/security.c @@ -193,7 +193,9 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem, if (Request->Req.Create.UserMode && 0 < SecurityDescriptorSize) { - if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess, + if (0 == DesiredAccess) + Result = STATUS_SUCCESS; + else if (AccessCheck(SecurityDescriptor, (HANDLE)Request->Req.Create.AccessToken, DesiredAccess, &FspFileGenericMapping, PrivilegeSet, &PrivilegeSetLength, PGrantedAccess, &AccessStatus)) Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED; else diff --git a/src/sys/create.c b/src/sys/create.c index 3aa3c607..98ee6bf7 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -163,7 +163,8 @@ static NTSTATUS FspFsvolCreateNoLock( ULONG SecurityDescriptorSize = 0; UINT64 AllocationSize = Irp->Overlay.AllocationSize.QuadPart; UINT64 AllocationUnit; - ACCESS_MASK DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; + ACCESS_MASK DesiredAccess = AccessState->RemainingDesiredAccess; + ACCESS_MASK GrantedAccess = AccessState->PreviouslyGrantedAccess; USHORT ShareAccess = IrpSp->Parameters.Create.ShareAccess; PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer; //ULONG EaLength = IrpSp->Parameters.Create.EaLength; @@ -176,6 +177,10 @@ static NTSTATUS FspFsvolCreateNoLock( CaseSensitiveRequested || FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch; BOOLEAN HasTraversePrivilege = BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE); + BOOLEAN HasBackupPrivilege = + BooleanFlagOn(AccessState->Flags, TOKEN_HAS_BACKUP_PRIVILEGE); + BOOLEAN HasRestorePrivilege = + BooleanFlagOn(AccessState->Flags, TOKEN_HAS_RESTORE_PRIVILEGE); FSP_FILE_NODE *FileNode, *RelatedFileNode; FSP_FILE_DESC *FileDesc; UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 }; @@ -453,6 +458,7 @@ static NTSTATUS FspFsvolCreateNoLock( FileDesc->FileNode = FileNode; FileDesc->CaseSensitive = CaseSensitive; FileDesc->HasTraversePrivilege = HasTraversePrivilege; + if (!MainFileOpen) { FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request); @@ -470,11 +476,14 @@ static NTSTATUS FspFsvolCreateNoLock( Request->Req.Create.AllocationSize = AllocationSize; Request->Req.Create.AccessToken = 0; Request->Req.Create.DesiredAccess = DesiredAccess; + Request->Req.Create.GrantedAccess = GrantedAccess; Request->Req.Create.ShareAccess = ShareAccess; Request->Req.Create.Ea.Offset = 0; Request->Req.Create.Ea.Size = 0; Request->Req.Create.UserMode = UserMode == RequestorMode; Request->Req.Create.HasTraversePrivilege = HasTraversePrivilege; + Request->Req.Create.HasBackupPrivilege = HasBackupPrivilege; + Request->Req.Create.HasRestorePrivilege = HasRestorePrivilege; Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY); Request->Req.Create.CaseSensitive = CaseSensitiveRequested; Request->Req.Create.NamedStream = MainFileName.Length; @@ -600,6 +609,7 @@ NTSTATUS FspFsvolCreateComplete( PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject; FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + PACCESS_STATE AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState; PFILE_OBJECT FileObject = IrpSp->FileObject; FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); FSP_FILE_DESC *FileDesc = FspIopRequestContext(Request, RequestFileDesc); @@ -817,6 +827,10 @@ NTSTATUS FspFsvolCreateComplete( FileDesc->FileNode = FileNode = OpenedFileNode; } + /* set up the AccessState */ + AccessState->RemainingDesiredAccess = 0; + AccessState->PreviouslyGrantedAccess = Response->Rsp.Create.Opened.GrantedAccess; + /* set up the FileObject */ if (0 != FsvolDeviceExtension->FsvrtDeviceObject) #pragma prefast(disable:28175, "We are a filesystem: ok to access Vpb") @@ -1161,7 +1175,7 @@ NTSTATUS FspCreate( "Ea=%p, EaLength=%ld", IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName, IrpSp->Flags, - IrpSp->Parameters.Create.SecurityContext->DesiredAccess, + IrpSp->Parameters.Create.SecurityContext->AccessState->OriginalDesiredAccess, IrpSp->Parameters.Create.ShareAccess, IrpSp->Parameters.Create.Options, IrpSp->Parameters.Create.FileAttributes,