From 9ae9b8ff2cf694ac45b12c5176bf8136388e6575 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 23 May 2022 17:53:39 +0100 Subject: [PATCH] dll: fuse: uidmap option and AzureAD support --- src/dll/fuse/fuse.c | 248 ++++++++++++++++++++++++++++++++++++++--- src/dll/fuse/library.h | 1 + 2 files changed, 234 insertions(+), 15 deletions(-) diff --git a/src/dll/fuse/fuse.c b/src/dll/fuse/fuse.c index 50dbcd9f..79a5cedb 100644 --- a/src/dll/fuse/fuse.c +++ b/src/dll/fuse/fuse.c @@ -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; + int res = -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) + goto exit; + memcpy(Name, UserName, NameSize); + for (PSTR P = Name, EndP = P + NameSize; EndP > P; P++) + if ('+' == *P) + *P = '\\'; + + Size = sizeof SidBuf; + DomnSize = sizeof Domn / sizeof Domn[0]; + 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; - - NameSize = lstrlenA(username) + 1; - if (sizeof Name / sizeof Name[0] < NameSize) - return -1; - memcpy(Name, username, NameSize); - for (PSTR P = Name, EndP = P + NameSize; EndP > P; P++) - if ('+' == *P) - *P = '\\'; + *PUid = 0; SidSize = sizeof SidBuf; - DomnSize = sizeof Domn / sizeof Domn[0]; - if (!LookupAccountNameA(0, Name, &SidBuf, &SidSize, Domn, &DomnSize, &Use)) + 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); diff --git a/src/dll/fuse/library.h b/src/dll/fuse/library.h index 36787048..6c79ab83 100644 --- a/src/dll/fuse/library.h +++ b/src/dll/fuse/library.h @@ -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;