diff --git a/build/VStudio/winfsp_dll.vcxproj b/build/VStudio/winfsp_dll.vcxproj index 41a7a4d3..349b1b02 100644 --- a/build/VStudio/winfsp_dll.vcxproj +++ b/build/VStudio/winfsp_dll.vcxproj @@ -52,6 +52,7 @@ + @@ -224,7 +225,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf $(OutDir)$(TargetFileName).map false ..\..\src\dll\library.def - %(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib + %(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib;netapi32.lib;wldap32.lib $(OutDir)$(TargetFileName).public.pdb @@ -251,7 +252,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf $(OutDir)$(TargetFileName).map true ..\..\src\dll\library.def - %(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib + %(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib;netapi32.lib;wldap32.lib $(OutDir)$(TargetFileName).public.pdb @@ -281,7 +282,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf $(OutDir)$(TargetFileName).map false ..\..\src\dll\library.def - %(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib + %(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib;netapi32.lib;wldap32.lib $(OutDir)$(TargetFileName).public.pdb /PDBALTPATH:$(TargetFileName).pdb %(AdditionalOptions) @@ -312,7 +313,7 @@ copy /b $(OutDir)fuse3-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse3-$(Platf $(OutDir)$(TargetFileName).map true ..\..\src\dll\library.def - %(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib + %(AdditionalDependencies);rpcrt4.lib;credui.lib;secur32.lib;version.lib;netapi32.lib;wldap32.lib $(OutDir)$(TargetFileName).public.pdb /PDBALTPATH:$(TargetFileName).pdb %(AdditionalOptions) diff --git a/build/VStudio/winfsp_dll.vcxproj.filters b/build/VStudio/winfsp_dll.vcxproj.filters index 95efcf6a..bfd29ef4 100644 --- a/build/VStudio/winfsp_dll.vcxproj.filters +++ b/build/VStudio/winfsp_dll.vcxproj.filters @@ -169,6 +169,9 @@ Source\shared\ku + + Source + diff --git a/src/dll/ldap.c b/src/dll/ldap.c new file mode 100644 index 00000000..18459925 --- /dev/null +++ b/src/dll/ldap.c @@ -0,0 +1,157 @@ +/** + * @file dll/ldap.c + * + * @copyright 2015-2020 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this software + * in accordance with the commercial license agreement provided in + * conjunction with the software. The terms and conditions of any such + * commercial license agreement shall govern, supersede, and render + * ineffective any application of the GPLv3 license to this software, + * notwithstanding of any reference thereto in the software or + * associated repository. + */ + +#include +#include + +ULONG FspLdapConnect(PWSTR HostName, PVOID *PLdap) +{ + LDAP *Ldap = 0; + ULONG LdapResult; + + *PLdap = 0; + + Ldap = ldap_initW(HostName, LDAP_PORT); + if (0 == Ldap) + { + LdapResult = LdapGetLastError(); + goto exit; + } + + /* enable signing and encryption */ + ldap_set_optionW(Ldap, LDAP_OPT_SIGN, LDAP_OPT_ON); + ldap_set_optionW(Ldap, LDAP_OPT_ENCRYPT, LDAP_OPT_ON); + + LdapResult = ldap_bind_sW(Ldap, 0, 0, LDAP_AUTH_NEGOTIATE); + if (LDAP_SUCCESS != LdapResult) + goto exit; + + *PLdap = Ldap; + LdapResult = LDAP_SUCCESS; + +exit: + if (LDAP_SUCCESS != LdapResult) + { + if (0 != Ldap) + ldap_unbind(Ldap); + } + + return LdapResult; +} + +VOID FspLdapClose(PVOID Ldap0) +{ + LDAP *Ldap = Ldap0; + + ldap_unbind(Ldap); +} + +ULONG FspLdapGetValue(PVOID Ldap0, PWSTR Base, ULONG Scope, PWSTR Filter, PWSTR Attribute, + PWSTR *PValue) +{ + LDAP *Ldap = Ldap0; + PWSTR Attributes[2]; + LDAPMessage *Message = 0, *Entry; + PWSTR *Values = 0; + int Size; + PWSTR Value; + ULONG LdapResult; + + *PValue = 0; + + Attributes[0] = Attribute; + Attributes[1] = 0; + LdapResult = ldap_search_sW(Ldap, Base, Scope, Filter, Attributes, 0, &Message); + if (LDAP_SUCCESS != LdapResult) + goto exit; + + Entry = ldap_first_entry(Ldap, Message); + if (0 == Entry) + { + LdapResult = LDAP_OTHER; + goto exit; + } + + Values = ldap_get_valuesW(Ldap, Entry, Attributes[0]); + if (0 == Values || 0 == ldap_count_valuesW(Values)) + { + LdapResult = LDAP_OTHER; + goto exit; + } + + Size = (lstrlenW(Values[0]) + 1) * sizeof(WCHAR); + Value = MemAlloc(Size); + if (0 == Value) + { + LdapResult = LDAP_NO_MEMORY; + goto exit; + } + memcpy(Value, Values[0], Size); + + *PValue = Value; + LdapResult = LDAP_SUCCESS; + +exit: + if (0 != Values) + ldap_value_freeW(Values); + if (0 != Message) + ldap_msgfree(Message); + + return LdapResult; +} + +ULONG FspLdapGetDefaultNamingContext(PVOID Ldap, PWSTR *PValue) +{ + return FspLdapGetValue(Ldap, 0, LDAP_SCOPE_BASE, L"(objectClass=*)", L"defaultNamingContext", + PValue); +} + +ULONG FspLdapGetTrustPosixOffset(PVOID Ldap, PWSTR Context, PWSTR Domain, PWSTR *PValue) +{ + WCHAR Base[1024]; + WCHAR Filter[512]; + BOOLEAN IsFlatName; + + *PValue = 0; + + if (sizeof Base / sizeof Base[0] - 64 < lstrlenW(Context) || + sizeof Filter / sizeof Filter[0] - 64 < lstrlenW(Domain)) + return LDAP_OTHER; + + IsFlatName = TRUE; + for (PWSTR P = Domain; *P; P++) + if (L'.' == *P) + { + IsFlatName = FALSE; + break; + } + + wsprintfW(Base, + L"CN=System,%s", + Context); + wsprintfW(Filter, + IsFlatName ? + L"(&(objectClass=trustedDomain)(flatName=%s))" : + L"(&(objectClass=trustedDomain)(name=%s))", + Domain); + + return FspLdapGetValue(Ldap, Base, LDAP_SCOPE_ONELEVEL, Filter, L"trustPosixOffset", PValue); +} diff --git a/src/dll/library.h b/src/dll/library.h index b90c8528..a79d1c57 100644 --- a/src/dll/library.h +++ b/src/dll/library.h @@ -64,6 +64,13 @@ NTSTATUS FspEventLogUnregister(VOID); PSID FspWksidNew(WELL_KNOWN_SID_TYPE WellKnownSidType, PNTSTATUS PResult); PSID FspWksidGet(WELL_KNOWN_SID_TYPE WellKnownSidType); +ULONG FspLdapConnect(PWSTR HostName, PVOID *PLdap); +VOID FspLdapClose(PVOID Ldap); +ULONG FspLdapGetValue(PVOID Ldap, PWSTR Base, ULONG Scope, PWSTR Filter, PWSTR Attribute, + PWSTR *PValue); +ULONG FspLdapGetDefaultNamingContext(PVOID Ldap, PWSTR *PValue); +ULONG FspLdapGetTrustPosixOffset(PVOID Ldap, PWSTR Context, PWSTR Domain, PWSTR *PValue); + PWSTR FspDiagIdent(VOID); #define FspFileSystemDirectoryBufferEntryInvalid ((ULONG)-1) diff --git a/src/shared/ku/library.h b/src/shared/ku/library.h index 75f87163..f1d33ecf 100644 --- a/src/shared/ku/library.h +++ b/src/shared/ku/library.h @@ -26,6 +26,8 @@ #include #include +#include +#include #define _NTDEF_ #include diff --git a/src/shared/ku/posix.c b/src/shared/ku/posix.c index 79b51aeb..7ba13686 100644 --- a/src/shared/ku/posix.c +++ b/src/shared/ku/posix.c @@ -111,8 +111,89 @@ static union #define FspUnmappedUid (65534) static PISID FspAccountDomainSid, FspPrimaryDomainSid; +static struct +{ + PSID DomainSid; + PWSTR NetbiosDomainName; + PWSTR DnsDomainName; + ULONG TrustPosixOffset; +} *FspTrustedDomains; +ULONG FspTrustedDomainCount; static INIT_ONCE FspPosixInitOnce = INIT_ONCE_STATIC_INIT; #if !defined(_KERNEL_MODE) +static unsigned wcstoint(const wchar_t *p, const wchar_t **endp, int base) +{ + unsigned v; + int maxdig, maxalp; + + maxdig = 10 < base ? '9' : (base - 1) + '0'; + maxalp = 10 < base ? (base - 1 - 10) + 'a' : 0; + + for (v = 0; *p; p++) + { + int c = *p; + + if ('0' <= c && c <= maxdig) + v = base * v + (c - '0'); + else + { + c |= 0x20; + if ('a' <= c && c <= maxalp) + v = base * v + (c - 'a') + 10; + else + break; + } + } + + if (0 != endp) + *endp = (wchar_t *)p; + + return v; +} + +static ULONG FspPosixInitializeTrustPosixOffsets(VOID) +{ + PVOID Ldap = 0; + PWSTR DefaultNamingContext = 0; + PWSTR TrustPosixOffsetString = 0; + ULONG LdapResult; + + LdapResult = FspLdapConnect(0/* default LDAP server */, &Ldap); + if (0 != LdapResult) + goto exit; + + LdapResult = FspLdapGetDefaultNamingContext(Ldap, &DefaultNamingContext); + if (0 != LdapResult) + goto exit; + + /* get the "trustPosixOffset" for each trusted domain */ + for (ULONG I = 0; FspTrustedDomainCount > I; I++) + { + MemFree(TrustPosixOffsetString); + LdapResult = FspLdapGetTrustPosixOffset(Ldap, + DefaultNamingContext, FspTrustedDomains[I].DnsDomainName, &TrustPosixOffsetString); + if (0 == LdapResult) + FspTrustedDomains[I].TrustPosixOffset = wcstoint(TrustPosixOffsetString, 0, 10); + } + + LdapResult = 0; + +exit: + MemFree(TrustPosixOffsetString); + MemFree(DefaultNamingContext); + if (0 != Ldap) + FspLdapClose(Ldap); + + /* if the "trustPosixOffset" looks wrong, fix it up using Cygwin magic value 0xfe500000 */ + for (ULONG I = 0; FspTrustedDomainCount > I; I++) + { + if (0x100000 > FspTrustedDomains[I].TrustPosixOffset) + FspTrustedDomains[I].TrustPosixOffset = 0xfe500000; + } + + return LdapResult; +} + static BOOL WINAPI FspPosixInitialize( PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) { @@ -120,8 +201,10 @@ static BOOL WINAPI FspPosixInitialize( LSA_HANDLE PolicyHandle = 0; PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = 0; PPOLICY_DNS_DOMAIN_INFO PrimaryDomainInfo = 0; + PDS_DOMAIN_TRUSTSW TrustedDomains = 0; + ULONG TrustedDomainCount, RealTrustedDomainCount; BYTE Count; - ULONG Size; + ULONG Size, Temp; NTSTATUS Result; Result = LsaOpenPolicy(0, &Obja, POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle); @@ -148,9 +231,103 @@ static BOOL WINAPI FspPosixInitialize( FspPrimaryDomainSid = MemAlloc(Size); if (0 != FspPrimaryDomainSid) memcpy(FspPrimaryDomainSid, PrimaryDomainInfo->Sid, Size); + + if (ERROR_SUCCESS == DsEnumerateDomainTrustsW( + 0, DS_DOMAIN_DIRECT_INBOUND | DS_DOMAIN_DIRECT_OUTBOUND | DS_DOMAIN_IN_FOREST, + &TrustedDomains, &TrustedDomainCount)) + { + RealTrustedDomainCount = 0; + for (ULONG I = 0; TrustedDomainCount > I; I++) + { + if (0 == TrustedDomains[I].DomainSid || + (0 == TrustedDomains[I].NetbiosDomainName && + 0 == TrustedDomains[I].DnsDomainName) || + EqualSid(TrustedDomains[I].DomainSid, FspPrimaryDomainSid)) + continue; + if (0 != TrustedDomains[I].DomainSid) + { + Size = FSP_FSCTL_DEFAULT_ALIGN_UP(Size); + Size += GetLengthSid(TrustedDomains[I].DomainSid); + } + if (0 != TrustedDomains[I].NetbiosDomainName) + { + Size = FSP_FSCTL_ALIGN_UP(Size, sizeof(WCHAR)); + Size += (lstrlenW(TrustedDomains[I].NetbiosDomainName) + 1) * sizeof(WCHAR); + } + if (0 != TrustedDomains[I].DnsDomainName) + { + Size = FSP_FSCTL_ALIGN_UP(Size, sizeof(WCHAR)); + Size += (lstrlenW(TrustedDomains[I].DnsDomainName) + 1) * sizeof(WCHAR); + } + RealTrustedDomainCount++; + } + Size = FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof FspTrustedDomains[0] * RealTrustedDomainCount) + Size; + if (0 < Size) + { + FspTrustedDomains = MemAlloc(Size); + if (0 != FspTrustedDomains) + { + Size = FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof FspTrustedDomains[0] * RealTrustedDomainCount); + for (ULONG I = 0, J = 0; TrustedDomainCount > I; I++) + { + if (0 == TrustedDomains[I].DomainSid || + (0 == TrustedDomains[I].NetbiosDomainName && + 0 == TrustedDomains[I].DnsDomainName) || + EqualSid(TrustedDomains[I].DomainSid, FspPrimaryDomainSid)) + continue; + FspTrustedDomains[J].DomainSid = 0; + FspTrustedDomains[J].NetbiosDomainName = 0; + FspTrustedDomains[J].DnsDomainName = 0; + FspTrustedDomains[J].TrustPosixOffset = 0; + if (0 != TrustedDomains[I].DomainSid) + { + Size = FSP_FSCTL_DEFAULT_ALIGN_UP(Size); + Size += (Temp = GetLengthSid(TrustedDomains[I].DomainSid)); + FspTrustedDomains[J].DomainSid = + (PVOID)((PUINT8)FspTrustedDomains + Size); + memcpy(FspTrustedDomains[J].DomainSid, + TrustedDomains[I].DomainSid, Temp); + } + if (0 != TrustedDomains[I].NetbiosDomainName) + { + Size = FSP_FSCTL_ALIGN_UP(Size, sizeof(WCHAR)); + Size += (Temp = (lstrlenW(TrustedDomains[I].NetbiosDomainName) + 1) * sizeof(WCHAR)); + FspTrustedDomains[J].NetbiosDomainName = + (PVOID)((PUINT8)FspTrustedDomains + Size); + memcpy(FspTrustedDomains[J].NetbiosDomainName, + TrustedDomains[I].NetbiosDomainName, Temp); + } + if (0 != TrustedDomains[I].DnsDomainName) + { + Size = FSP_FSCTL_ALIGN_UP(Size, sizeof(WCHAR)); + Size += (Temp = (lstrlenW(TrustedDomains[I].DnsDomainName) + 1) * sizeof(WCHAR)); + FspTrustedDomains[J].DnsDomainName = + (PVOID)((PUINT8)FspTrustedDomains + Size); + memcpy(FspTrustedDomains[J].DnsDomainName, + TrustedDomains[I].DnsDomainName, Temp); + } + if (0 == FspTrustedDomains[J].NetbiosDomainName) + FspTrustedDomains[J].NetbiosDomainName = + FspTrustedDomains[J].DnsDomainName; + else + if (0 == FspTrustedDomains[J].DnsDomainName) + FspTrustedDomains[J].DnsDomainName = + FspTrustedDomains[J].NetbiosDomainName; + J++; + } + FspTrustedDomainCount = RealTrustedDomainCount; + } + } + } } + if (0 < FspTrustedDomainCount) + FspPosixInitializeTrustPosixOffsets(); + exit: + if (0 != TrustedDomains) + NetApiBufferFree(TrustedDomains); + if (0 != PrimaryDomainInfo) LsaFreeMemory(PrimaryDomainInfo); @@ -172,6 +349,7 @@ VOID FspPosixFinalize(BOOLEAN Dynamic) if (Dynamic) { + MemFree(FspTrustedDomains); MemFree(FspAccountDomainSid); MemFree(FspPrimaryDomainSid); } @@ -318,7 +496,8 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid) } else if (0x100000 <= Uid && Uid < 0xff000000) { - if (0 != FspPrimaryDomainSid && + if ((Uid < 0x300000 || 0 == FspTrustedDomainCount) && + 0 != FspPrimaryDomainSid && 5 == FspPrimaryDomainSid->IdentifierAuthority.Value[5] && 4 == FspPrimaryDomainSid->SubAuthorityCount) { @@ -329,11 +508,30 @@ FSP_API NTSTATUS FspPosixMapUidToSid(UINT32 Uid, PSID *PSid) FspPrimaryDomainSid->SubAuthority[3], Uid - 0x100000); } + else + { + PISID DomainSid = 0; + ULONG TrustPosixOffset = 0; + for (ULONG I = 0; FspTrustedDomainCount > I; I++) + { + if (FspTrustedDomains[I].TrustPosixOffset <= Uid && + FspTrustedDomains[I].TrustPosixOffset > TrustPosixOffset) + { + DomainSid = FspTrustedDomains[I].DomainSid; + TrustPosixOffset = FspTrustedDomains[I].TrustPosixOffset; + } + } + if (0 != DomainSid) + { + *PSid = FspPosixCreateSid(5, 5, + 21, + DomainSid->SubAuthority[1], + DomainSid->SubAuthority[2], + DomainSid->SubAuthority[3], + Uid - TrustPosixOffset); + } + } } - /* - * I am sorry, I am not going to bother with all that trustPosixOffset stuff. - * But if you need it, I accept patches :) - */ /* [IDMAP] * Mandatory Labels: @@ -432,11 +630,15 @@ FSP_API NTSTATUS FspPosixMapSidToUid(PSID Sid, PUINT32 PUid) else if (0 != FspAccountDomainSid && FspPosixIsRelativeSid(FspAccountDomainSid, Sid)) *PUid = 0x30000 + Rid; - - /* - * I am sorry, I am not going to bother with all that trustPosixOffset stuff. - * But if you need it, I accept patches :) - */ + else + for (ULONG I = 0; FspTrustedDomainCount > I; I++) + { + if (FspPosixIsRelativeSid(FspTrustedDomains[I].DomainSid, Sid)) + { + *PUid = FspTrustedDomains[I].TrustPosixOffset + Rid; + break; + } + } } /* [IDMAP]