dll: fuse: uidmap option and AzureAD support

This commit is contained in:
Bill Zissimopoulos 2022-05-23 17:53:39 +01:00
parent 74bb51ae07
commit 9ae9b8ff2c
2 changed files with 234 additions and 15 deletions

View File

@ -82,6 +82,8 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FUSE_OPT_KEY("fstypename=", 'F'),
FUSE_OPT_KEY("volname=", 'v'),
FUSE_OPT_KEY("uidmap=", 'm'),
FSP_FUSE_CORE_OPT("SectorSize=%hu", VolumeParams.SectorSize, 4096),
FSP_FUSE_CORE_OPT("SectorsPerAllocationUnit=%hu", VolumeParams.SectorsPerAllocationUnit, 1),
FSP_FUSE_CORE_OPT("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0),
@ -293,43 +295,241 @@ static int fsp_fuse_sddl_to_security(const char *Sddl, PUINT8 Security, PULONG P
return res;
}
static int fsp_fuse_username_to_uid(const char *username, int *puid)
static int fsp_fuse_tokenuser_to_sid(HANDLE Token, PSID Sid, PULONG PSidSize)
{
union
{
TOKEN_USER V;
UINT8 B[128];
} InfoBuf;
PTOKEN_USER InfoPtr = &InfoBuf.V;
DWORD Size;
int res = -1;
if (!GetTokenInformation(Token, TokenUser, InfoPtr, sizeof InfoBuf, &Size))
{
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
goto exit;
InfoPtr = MemAlloc(Size);
if (0 == InfoPtr)
goto exit;
if (!GetTokenInformation(Token, TokenUser, InfoPtr, Size, &Size))
goto exit;
}
Size = GetLengthSid(InfoPtr->User.Sid);
if (*PSidSize >= Size)
{
memcpy(Sid, InfoPtr->User.Sid, Size);
*PSidSize = Size;
res = 0;
}
exit:
if (InfoPtr != &InfoBuf.V)
MemFree(InfoPtr);
return res;
}
static int fsp_fuse_tokenuser_is_azuread(HANDLE Token)
{
union
{
SID V;
UINT8 B[SECURITY_MAX_SID_SIZE];
} SidBuf;
ULONG Size;
PSID Sid = &SidBuf.V;
BYTE Count, Authority;
UINT32 SubAuthority0;
Size = sizeof SidBuf;
if (-1 == fsp_fuse_tokenuser_to_sid(Token, &SidBuf.V, &Size))
return 0;
Count = *GetSidSubAuthorityCount(Sid);
Authority = GetSidIdentifierAuthority(Sid)->Value[5];
SubAuthority0 = 2 <= Count ? *GetSidSubAuthority(Sid, 0) : 0;
return 12 == Authority && 1 == SubAuthority0;
}
static int fsp_fuse_username_to_sid(const char *UserName, PSID Sid, PULONG PSidSize)
{
union
{
SID V;
UINT8 B[SECURITY_MAX_SID_SIZE];
} SidBuf;
PSID SidPtr = &SidBuf.V;
char Name[256], Domn[256];
DWORD SidSize, NameSize, DomnSize;
DWORD Size, NameSize, DomnSize;
SID_NAME_USE Use;
UINT32 Uid;
NTSTATUS Result;
int res = -1;
*puid = 0;
NameSize = lstrlenA(username) + 1;
if ('S' == UserName[0] && '-' == UserName[1] && '1' == UserName[2] && '-' == UserName[3])
{
if (!ConvertStringSidToSidA(UserName, &SidPtr))
goto exit;
}
else
{
NameSize = lstrlenA(UserName) + 1;
if (sizeof Name / sizeof Name[0] < NameSize)
return -1;
memcpy(Name, username, NameSize);
goto exit;
memcpy(Name, UserName, NameSize);
for (PSTR P = Name, EndP = P + NameSize; EndP > P; P++)
if ('+' == *P)
*P = '\\';
SidSize = sizeof SidBuf;
Size = sizeof SidBuf;
DomnSize = sizeof Domn / sizeof Domn[0];
if (!LookupAccountNameA(0, Name, &SidBuf, &SidSize, Domn, &DomnSize, &Use))
if (!LookupAccountNameA(0, Name, SidPtr, &Size, Domn, &DomnSize, &Use))
goto exit;
}
Size = GetLengthSid(SidPtr);
if (*PSidSize >= Size)
{
memcpy(Sid, SidPtr, Size);
*PSidSize = Size;
res = 0;
}
exit:
if (SidPtr != &SidBuf.V)
LocalFree(SidPtr);
return res;
}
static int fsp_fuse_username_to_uid(const char *UserName, int *PUid)
{
union
{
SID V;
UINT8 B[SECURITY_MAX_SID_SIZE];
} SidBuf;
ULONG SidSize;
UINT32 Uid;
NTSTATUS Result;
*PUid = 0;
SidSize = sizeof SidBuf;
if (-1 == fsp_fuse_username_to_sid(UserName, &SidBuf.V, &SidSize))
return -1;
Result = FspPosixMapSidToUid(&SidBuf, &Uid);
Result = FspPosixMapSidToUid(&SidBuf.V, &Uid);
if (!NT_SUCCESS(Result))
return -1;
*puid = Uid;
*PUid = Uid;
return 0;
}
static int fsp_fuse_set_uidmap(const char *Spec)
{
char Buf[1024], *P = Buf, *UidP, *UserP, C;
int Len;
UINT32 Uid[8];
PSID Sid[8];
union
{
SID V;
UINT8 B[SECURITY_MAX_SID_SIZE];
} SidBuf[8];
ULONG SidSize;
ULONG Count;
NTSTATUS Result;
int res = -1;
Len = lstrlenA(Spec);
if (sizeof Buf <= Len)
return -1;
memcpy(Buf, Spec, Len + 1);
Count = 0;
for (;;)
{
if (sizeof Uid / sizeof Uid[0] <= Count)
{
/* out of space */
goto exit;
}
UidP = P;
for (; '\0' != (C = *P) && ';' != C && ':' != C; P++)
;
*P = '\0';
if (UidP == P)
break;
Uid[Count] = strtouint(UidP, 0, 10, 0);
if (0 == Uid[Count])
{
/* invalid uid */
goto exit;
}
UserP = 0;
if (':' == C)
{
UserP = ++P;
for (; '\0' != (C = *P) && ';' != C; P++)
;
*P = '\0';
}
if (0 != UserP && '\0' != *UserP)
{
SidSize = sizeof SidBuf[Count];
if (-1 == fsp_fuse_username_to_sid(UserP, &SidBuf[Count].V, &SidSize))
{
/* invalid SID */
goto exit;
}
Sid[Count] = &SidBuf[Count].V;
}
else
{
HANDLE Token;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token))
{
SidSize = sizeof SidBuf[Count];
if (-1 == fsp_fuse_tokenuser_to_sid(Token, &SidBuf[Count].V, &SidSize))
{
/* invalid SID */
CloseHandle(Token);
goto exit;
}
CloseHandle(Token);
Sid[Count] = &SidBuf[Count].V;
}
}
Count++;
if ('\0' == C)
break;
P++;
}
Result = FspPosixSetUidMap(Uid, Sid, Count);
res = NT_SUCCESS(Result) ? 0 : -1;
exit:
return res;
}
static int fsp_fuse_utf8towcs_trunc(
const char *Str, int StrLen,
PWSTR Wcs, int WcsLen)
@ -424,6 +624,7 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
" -o KeepFileCache do not discard cache when files are closed\n"
" -o LegacyUnlinkRename do not support new POSIX unlink/rename\n"
" -o ThreadCount number of file system dispatcher threads\n"
" -o uidmap=UID:SID[;...] explicit UID <-> SID map (max 8 entries)\n"
);
opt_data->help = 1;
return 1;
@ -531,6 +732,14 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
if (0 == opt_data->VolumeLabelLength)
return -1;
return 0;
case 'm':
arg += sizeof "uidmap=" - 1;
if (-1 == fsp_fuse_set_uidmap(arg))
{
opt_data->set_uidmap = -1;
return -1;
}
return 0;
}
}
@ -579,6 +788,11 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
ErrorMessage = L": invalid user or group name.";
goto fail;
}
else if (-1 == opt_data.set_uidmap)
{
ErrorMessage = L": invalid uidmap.";
goto fail;
}
return 0;
}
if (opt_data.help)
@ -601,6 +815,10 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token))
{
/* if an AzureAD user and no uidmap specified, set a default uidmap that matches Cygwin */
if (!opt_data.set_uidmap && fsp_fuse_tokenuser_is_azuread(Token))
fsp_fuse_set_uidmap("4096:");
fsp_fuse_get_token_uidgid(Token, TokenUser,
opt_data.set_uid && -1 == opt_data.uid ? &opt_data.uid : 0,
opt_data.set_gid && -1 == opt_data.gid ? &opt_data.gid : 0);

View File

@ -147,6 +147,7 @@ struct fsp_fuse_core_opt_data
set_create_dir_umask, create_dir_umask,
set_uid, uid, username_to_uid_result,
set_gid, gid,
set_uidmap,
set_attr_timeout, attr_timeout,
rellinks,
dothidden;