dll: fuse: FileSecurity option

This commit is contained in:
Bill Zissimopoulos 2021-01-25 16:54:59 -08:00
parent c5b850be35
commit 9d5efe5f98
No known key found for this signature in database
GPG Key ID: 3D4F95D52C7B3EA3
7 changed files with 257 additions and 10 deletions

View File

@ -1826,6 +1826,10 @@ FSP_API VOID FspDeleteSid(PSID Sid, NTSTATUS (*CreateFunc)());
FSP_API NTSTATUS FspPosixMapPermissionsToSecurityDescriptor(
UINT32 Uid, UINT32 Gid, UINT32 Mode,
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
FSP_API NTSTATUS FspPosixMergePermissionsToSecurityDescriptor(
UINT32 Uid, UINT32 Gid, UINT32 Mode,
PSECURITY_DESCRIPTOR ExistingSecurityDescriptor,
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
FSP_API NTSTATUS FspPosixMapSecurityDescriptorToPermissions(
PSECURITY_DESCRIPTOR SecurityDescriptor,
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode);

View File

@ -20,6 +20,7 @@
*/
#include <dll/fuse/library.h>
#include <sddl.h>
struct fuse_chan
{
@ -105,6 +106,8 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FUSE_OPT_KEY("ExactFileSystemName=", 'E'),
FUSE_OPT_KEY("--ExactFileSystemName=", 'E'),
FUSE_OPT_KEY("FileSecurity=", 's'),
FUSE_OPT_KEY("--FileSecurity=", 's'),
FSP_FUSE_CORE_OPT("UserName=", set_uid, 1),
FUSE_OPT_KEY("UserName=", 'u'),
FSP_FUSE_CORE_OPT("--UserName=", set_uid, 1),
@ -266,6 +269,29 @@ FSP_FUSE_API int fsp_fuse_is_lib_option(struct fsp_fuse_env *env,
return fsp_fuse_opt_match(env, fsp_fuse_core_opts, opt);
}
static int fsp_fuse_sddl_to_security(const char *Sddl, PUINT8 Security, PULONG PSecuritySize)
{
PSECURITY_DESCRIPTOR SecurityDescriptor;
ULONG SecurityDescriptorSize;
int res = -1;
if (ConvertStringSecurityDescriptorToSecurityDescriptorA(
Sddl, SDDL_REVISION_1, &SecurityDescriptor, &SecurityDescriptorSize))
{
if (*PSecuritySize >= SecurityDescriptorSize)
{
memcpy(Security, SecurityDescriptor, SecurityDescriptorSize);
*PSecuritySize = SecurityDescriptorSize;
res = 0;
}
LocalFree(SecurityDescriptor);
}
return res;
}
static int fsp_fuse_username_to_uid(const char *username, int *puid)
{
union
@ -374,6 +400,7 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
FspServiceLog(EVENTLOG_ERROR_TYPE, L""
FSP_FUSE_LIBRARY_NAME " options:\n"
" -o umask=MASK set file permissions (octal)\n"
" -o FileSecurity=SDDL set file DACL (SDDL format)\n"
" -o create_umask=MASK set newly created file permissions (octal)\n"
" -o create_file_umask=MASK for files only\n"
" -o create_dir_umask=MASK for directories only\n"
@ -460,6 +487,18 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
opt_data->VolumeParams.FileSystemName
[sizeof opt_data->VolumeParams.FileSystemName / sizeof(WCHAR) - 1] = L'\0';
return 0;
case 's':
if ('F' == arg[0])
arg += sizeof "FileSecurity=" - 1;
else if ('F' == arg[2])
arg += sizeof "--FileSecurity=" - 1;
opt_data->FileSecuritySize = sizeof opt_data->FileSecurityBuf;
if (-1 == fsp_fuse_sddl_to_security(arg, opt_data->FileSecurityBuf, &opt_data->FileSecuritySize))
{
opt_data->FileSecuritySize = (ULONG)-1;
return -1;
}
return 0;
case 'u':
if ('U' == arg[0])
arg += sizeof "UserName=" - 1;
@ -527,7 +566,12 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
if (-1 == fsp_fuse_core_opt_parse(env, args, &opt_data, /*help=*/1))
{
if (-1 == opt_data.username_to_uid_result)
if ((ULONG)-1 == opt_data.FileSecuritySize)
{
ErrorMessage = L": invalid file security.";
goto fail;
}
else if (-1 == opt_data.username_to_uid_result)
{
ErrorMessage = L": invalid user or group name.";
goto fail;
@ -596,7 +640,7 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
f = fsp_fuse_obj_alloc(env, sizeof *f);
f = fsp_fuse_obj_alloc(env, sizeof *f + opt_data.FileSecuritySize);
if (0 == f)
goto fail;
@ -616,6 +660,11 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
memcpy(&f->VolumeParams, &opt_data.VolumeParams, sizeof opt_data.VolumeParams);
f->VolumeLabelLength = opt_data.VolumeLabelLength;
memcpy(&f->VolumeLabel, &opt_data.VolumeLabel, opt_data.VolumeLabelLength);
if (0 != opt_data.FileSecuritySize)
{
memcpy(f->FileSecurityBuf, opt_data.FileSecurityBuf, opt_data.FileSecuritySize);
f->FileSecurity = f->FileSecurityBuf;
}
Size = (lstrlenW(ch->MountPoint) + 1) * sizeof(WCHAR);
f->MountPoint = fsp_fuse_obj_alloc(env, Size);

View File

@ -472,7 +472,8 @@ static NTSTATUS fsp_fuse_intf_GetSecurityEx(FSP_FILE_SYSTEM *FileSystem,
if (0 != PSecurityDescriptorSize)
{
Result = FspPosixMapPermissionsToSecurityDescriptor(Uid, Gid, Mode, &SecurityDescriptor);
Result = FspPosixMergePermissionsToSecurityDescriptor(Uid, Gid, Mode, f->FileSecurity,
&SecurityDescriptor);
if (!NT_SUCCESS(Result))
goto exit;
@ -498,7 +499,7 @@ static NTSTATUS fsp_fuse_intf_GetSecurityEx(FSP_FILE_SYSTEM *FileSystem,
exit:
if (0 != SecurityDescriptor)
FspDeleteSecurityDescriptor(SecurityDescriptor,
FspPosixMapPermissionsToSecurityDescriptor);
FspPosixMergePermissionsToSecurityDescriptor);
return Result;
}
@ -1682,7 +1683,8 @@ static NTSTATUS fsp_fuse_intf_SetSecurity(FSP_FILE_SYSTEM *FileSystem,
if (!NT_SUCCESS(Result))
goto exit;
Result = FspPosixMapPermissionsToSecurityDescriptor(Uid, Gid, Mode, &SecurityDescriptor);
Result = FspPosixMergePermissionsToSecurityDescriptor(Uid, Gid, Mode, f->FileSecurity,
&SecurityDescriptor);
if (!NT_SUCCESS(Result))
goto exit;
@ -1729,7 +1731,7 @@ exit:
if (0 != SecurityDescriptor)
FspDeleteSecurityDescriptor(SecurityDescriptor,
FspPosixMapPermissionsToSecurityDescriptor);
FspPosixMergePermissionsToSecurityDescriptor);
return Result;
}

View File

@ -72,6 +72,8 @@ struct fuse
FSP_FILE_SYSTEM *FileSystem;
volatile int exited;
struct fuse3 *fuse3;
PSECURITY_DESCRIPTOR FileSecurity;
FSP_FSCTL_DECLSPEC_ALIGN UINT8 FileSecurityBuf[];
};
struct fsp_fuse_context_header
{
@ -156,6 +158,8 @@ struct fsp_fuse_core_opt_data
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
UINT16 VolumeLabelLength;
WCHAR VolumeLabel[sizeof ((FSP_FSCTL_VOLUME_INFO *)0)->VolumeLabel / sizeof(WCHAR)];
ULONG FileSecuritySize;
FSP_FSCTL_DECLSPEC_ALIGN UINT8 FileSecurityBuf[1024];
};
FSP_FSCTL_STATIC_ASSERT(
sizeof ((struct fuse *)0)->VolumeLabel == sizeof ((struct fsp_fuse_core_opt_data *)0)->VolumeLabel,

View File

@ -488,7 +488,8 @@ FSP_API VOID FspDeleteSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor
return;
if ((NTSTATUS (*)())FspAccessCheckEx == CreateFunc ||
(NTSTATUS (*)())FspPosixMapPermissionsToSecurityDescriptor == CreateFunc)
(NTSTATUS (*)())FspPosixMapPermissionsToSecurityDescriptor == CreateFunc ||
(NTSTATUS (*)())FspPosixMergePermissionsToSecurityDescriptor == CreateFunc)
MemFree(SecurityDescriptor);
else
if ((NTSTATUS (*)())FspCreateSecurityDescriptor == CreateFunc ||

View File

@ -41,6 +41,10 @@ FSP_API VOID FspDeleteSid(PSID Sid, NTSTATUS (*CreateFunc)());
FSP_API NTSTATUS FspPosixMapPermissionsToSecurityDescriptor(
UINT32 Uid, UINT32 Gid, UINT32 Mode,
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
FSP_API NTSTATUS FspPosixMergePermissionsToSecurityDescriptor(
UINT32 Uid, UINT32 Gid, UINT32 Mode,
PSECURITY_DESCRIPTOR ExistingSecurityDescriptor,
PSECURITY_DESCRIPTOR *PSecurityDescriptor);
FSP_API NTSTATUS FspPosixMapSecurityDescriptorToPermissions(
PSECURITY_DESCRIPTOR SecurityDescriptor,
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode);
@ -59,6 +63,7 @@ FSP_API VOID FspPosixDecodeWindowsPath(PWSTR WindowsPath, ULONG Size);
#pragma alloc_text(PAGE, FspPosixCreateSid)
#pragma alloc_text(PAGE, FspDeleteSid)
#pragma alloc_text(PAGE, FspPosixMapPermissionsToSecurityDescriptor)
#pragma alloc_text(PAGE, FspPosixMergePermissionsToSecurityDescriptor)
#pragma alloc_text(PAGE, FspPosixMapSecurityDescriptorToPermissions)
#pragma alloc_text(PAGE, FspPosixMapWindowsToPosixPathEx)
#pragma alloc_text(PAGE, FspPosixMapPosixToWindowsPathEx)
@ -898,6 +903,101 @@ lasterror:
goto exit;
}
FSP_API NTSTATUS FspPosixMergePermissionsToSecurityDescriptor(
UINT32 Uid, UINT32 Gid, UINT32 Mode,
PSECURITY_DESCRIPTOR ExistingSecurityDescriptor,
PSECURITY_DESCRIPTOR *PSecurityDescriptor)
{
FSP_KU_CODE;
if (0 == ExistingSecurityDescriptor)
return FspPosixMapPermissionsToSecurityDescriptor(Uid, Gid, Mode, PSecurityDescriptor);
PSID ExistingOwnerSid = 0, ExistingGroupSid = 0;
BOOL Defaulted, ExistingDaclPresent;
PACL ExistingAcl = 0;
PSID OwnerSid = 0, GroupSid = 0;
SECURITY_DESCRIPTOR SecurityDescriptor;
PSECURITY_DESCRIPTOR RelativeSecurityDescriptor = 0;
ULONG Size;
NTSTATUS Result;
*PSecurityDescriptor = 0;
if (!GetSecurityDescriptorOwner(ExistingSecurityDescriptor, &ExistingOwnerSid, &Defaulted))
goto lasterror;
if (!GetSecurityDescriptorGroup(ExistingSecurityDescriptor, &ExistingGroupSid, &Defaulted))
goto lasterror;
if (!GetSecurityDescriptorDacl(ExistingSecurityDescriptor, &ExistingDaclPresent, &ExistingAcl, &Defaulted))
goto lasterror;
if (0 == ExistingOwnerSid)
{
Result = FspPosixMapUidToSid(Uid, &OwnerSid);
if (!NT_SUCCESS(Result))
goto exit;
ExistingOwnerSid = OwnerSid;
}
if (0 == ExistingGroupSid)
{
Result = FspPosixMapUidToSid(Gid, &GroupSid);
if (!NT_SUCCESS(Result))
goto exit;
ExistingGroupSid = GroupSid;
}
if (!InitializeSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
goto lasterror;
if (!SetSecurityDescriptorOwner(&SecurityDescriptor, ExistingOwnerSid, FALSE))
goto lasterror;
if (!SetSecurityDescriptorGroup(&SecurityDescriptor, ExistingGroupSid, FALSE))
goto lasterror;
if (0 != ExistingAcl)
{
if (!SetSecurityDescriptorControl(&SecurityDescriptor, SE_DACL_PROTECTED, SE_DACL_PROTECTED))
goto lasterror;
if (!SetSecurityDescriptorDacl(&SecurityDescriptor, TRUE, ExistingAcl, FALSE))
goto lasterror;
}
Size = 0;
if (!MakeSelfRelativeSD(&SecurityDescriptor, 0, &Size) &&
ERROR_INSUFFICIENT_BUFFER != GetLastError())
goto lasterror;
RelativeSecurityDescriptor = MemAlloc(Size);
if (0 == RelativeSecurityDescriptor)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!MakeSelfRelativeSD(&SecurityDescriptor, RelativeSecurityDescriptor, &Size))
goto lasterror;
*PSecurityDescriptor = RelativeSecurityDescriptor;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
MemFree(RelativeSecurityDescriptor);
if (0 != GroupSid)
FspDeleteSid(GroupSid, FspPosixMapUidToSid);
if (0 != OwnerSid)
FspDeleteSid(OwnerSid, FspPosixMapUidToSid);
return Result;
lasterror:
Result = FspNtStatusFromWin32(GetLastError());
goto exit;
}
static inline ACCESS_MASK FspPosixCanonicalizeAccessMask(ACCESS_MASK AccessMask)
{
PGENERIC_MAPPING Mapping = FspGetFileGenericMapping();

View File

@ -25,7 +25,7 @@
#include "winfsp-tests.h"
void posix_map_sid_test(void)
static void posix_map_sid_test(void)
{
struct
{
@ -171,7 +171,7 @@ void posix_map_sid_test(void)
LocalFree(map[sizeof map / sizeof map[0] - 1].SidStr);
}
void posix_map_sd_test(void)
static void posix_map_sd_test(void)
{
struct
{
@ -237,7 +237,93 @@ void posix_map_sd_test(void)
}
}
void posix_map_path_test(void)
static void posix_merge_sd_test(void)
{
struct
{
UINT32 Uid, Gid, Mode;
PWSTR ExistingSddl;
PWSTR Sddl;
} map[] =
{
{
18, 544, 00000,
0,
L"O:SYG:BAD:P(A;;0x1f0198;;;SY)(A;;0x120088;;;BA)(A;;0x120088;;;WD)"
},
{
18, 544, 00000,
L"",
L"O:SYG:BA"
},
{
18, 544, 00000,
L"O:WD",
L"O:WDG:BA"
},
{
18, 544, 00000,
L"G:WD",
L"O:SYG:WD"
},
{
18, 544, 00000,
L"O:WDG:WD",
L"O:WDG:WD"
},
{
18, 544, 00000,
L"D:P",
L"O:SYG:BAD:P"
},
{
18, 544, 00000,
L"D:P(A;;FA;;;SY)",
L"O:SYG:BAD:P(A;;FA;;;SY)"
},
{
18, 544, 00000,
L"O:WDG:WDD:P(A;;FA;;;SY)",
L"O:WDG:WDD:P(A;;FA;;;SY)"
},
};
NTSTATUS Result;
BOOL Success;
PSECURITY_DESCRIPTOR ExistingSecurityDescriptor, SecurityDescriptor;
PWSTR Sddl;
for (size_t i = 0; sizeof map / sizeof map[0] > i; i++)
{
if (0 != map[i].ExistingSddl)
{
Success = ConvertStringSecurityDescriptorToSecurityDescriptorW(
map[i].ExistingSddl, SDDL_REVISION_1,
&ExistingSecurityDescriptor, 0);
ASSERT(Success);
}
else
ExistingSecurityDescriptor = 0;
Result = FspPosixMergePermissionsToSecurityDescriptor(
map[i].Uid, map[i].Gid, map[i].Mode, ExistingSecurityDescriptor, &SecurityDescriptor);
ASSERT(NT_SUCCESS(Result));
Success = ConvertSecurityDescriptorToStringSecurityDescriptorW(
SecurityDescriptor, SDDL_REVISION_1,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
&Sddl, 0);
ASSERT(Success);
ASSERT(0 == wcscmp(map[i].Sddl, Sddl));
LocalFree(Sddl);
FspDeleteSecurityDescriptor(SecurityDescriptor,
FspPosixMergePermissionsToSecurityDescriptor);
LocalFree(ExistingSecurityDescriptor);
}
}
static void posix_map_path_test(void)
{
struct
{
@ -274,5 +360,6 @@ void posix_tests(void)
TEST(posix_map_sid_test);
TEST(posix_map_sd_test);
TEST(posix_merge_sd_test);
TEST(posix_map_path_test);
}