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]