From: Matt Mitchell Date: Tue, 21 Sep 2021 14:28:00 +0000 (+0000) Subject: Merged PR 18242: [Release 6.0 RC2] Fix StartTLS in DirectoryService.Protocols in... X-Git-Tag: accepted/tizen/unified/20220110.054933~76^2^2~22 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e8798b645fe1da4a341be8d1b2986c230838c95e;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Merged PR 18242: [Release 6.0 RC2] Fix StartTLS in DirectoryService.Protocols in 6.0 and backport changes from 5.0 release. Supersedes https://dev.azure.com/dnceng/internal/_git/dotnet-runtime/pullrequest/17428 for release/6.0 branch. Cherry picked from !17575 --- diff --git a/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs b/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs index f38bb37..7fbaf9c 100644 --- a/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs +++ b/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs @@ -136,8 +136,9 @@ internal static partial class Interop [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_set_option", CharSet = CharSet.Ansi)] public static extern int ldap_set_option_referral([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref LdapReferralCallback outValue); + // Note that ldap_start_tls_s has a different signature across Windows LDAP and OpenLDAP [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_start_tls_s", CharSet = CharSet.Ansi)] - public static extern int ldap_start_tls(ConnectionHandle ldapHandle, ref int ServerReturnValue, ref IntPtr Message, IntPtr ServerControls, IntPtr ClientControls); + public static extern int ldap_start_tls(ConnectionHandle ldapHandle, IntPtr serverControls, IntPtr clientControls); [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_parse_result", CharSet = CharSet.Ansi)] public static extern int ldap_parse_result([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref int serverError, ref IntPtr dn, ref IntPtr message, ref IntPtr referral, ref IntPtr control, byte freeIt); diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj index d317292..d9839c1 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj +++ b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj @@ -67,7 +67,11 @@ + + + Common\System\LocalAppContextSwitches.Common.cs + Common\Interop\Linux\OpenLdap\Interop.Ldap.cs diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Linux.cs index 701fae2..d67782f 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Linux.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Linux.cs @@ -123,7 +123,31 @@ namespace System.DirectoryServices.Protocols } } - internal static int StartTls(ConnectionHandle ldapHandle, ref int ServerReturnValue, ref IntPtr Message, IntPtr ServerControls, IntPtr ClientControls) => Interop.Ldap.ldap_start_tls(ldapHandle, ref ServerReturnValue, ref Message, ServerControls, ClientControls); + internal static int StartTls(ConnectionHandle ldapHandle, ref int serverReturnValue, ref IntPtr message, IntPtr serverControls, IntPtr clientControls) + { + // Windows and Linux have different signatures for ldap_start_tls_s. + // On Linux, we don't have a serverReturnValue or the message/result parameter. + // + // So in the PAL here, just emulate. + + int error = Interop.Ldap.ldap_start_tls(ldapHandle, serverControls, clientControls); + + // On Windows, serverReturnValue only has meaning if the result code is LDAP_OTHER. + // If OpenLDAP returns that, we don't have a better code, so assign that through. + // If we get any other error, assign serverReturnValue to 0 since it shouldn't be read. + if (error == (int)ResultCode.Other) + { + serverReturnValue = error; + } + else + { + serverReturnValue = 0; + } + + // We don't have a referrer/message/result value, so just set it to NULL. + message = IntPtr.Zero; + return error; + } // openldap doesn't have a ldap_stop_tls function. Returning true as no-op for Linux. internal static byte StopTls(ConnectionHandle ldapHandle) => 1; diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Linux.cs index 2383e81..a7e4394 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Linux.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Linux.cs @@ -16,6 +16,13 @@ namespace System.DirectoryServices.Protocols _needDispose = true; } + internal ConnectionHandle(string uri) + :base(true) + { + Interop.Ldap.ldap_initialize(out handle, uri); + _needDispose = true; + } + internal ConnectionHandle(IntPtr value, bool disposeHandle) : base(true) { _needDispose = disposeHandle; diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Linux.cs index 02c8f0c..6adf1eb 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Linux.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Linux.cs @@ -20,7 +20,7 @@ namespace System.DirectoryServices.Protocols throw new NullReferenceException(); } - _ldapHandle = new ConnectionHandle(); + _ldapHandle = new ConnectionHandle($"ldap://{hostname}:{((LdapDirectoryIdentifier)_directoryIdentifier).PortNumber}"); } private int InternalConnectToServer() @@ -79,13 +79,39 @@ namespace System.DirectoryServices.Protocols private int InternalBind(NetworkCredential tempCredential, SEC_WINNT_AUTH_IDENTITY_EX cred, BindMethod method) { int error; - if (tempCredential == null && (AuthType == AuthType.External || AuthType == AuthType.Kerberos)) + + if (LocalAppContextSwitches.UseBasicAuthFallback) { - error = BindSasl(); + if (tempCredential == null && (AuthType == AuthType.External || AuthType == AuthType.Kerberos)) + { + error = BindSasl(); + } + else + { + error = LdapPal.BindToDirectory(_ldapHandle, cred.user, cred.password); + } } else { - error = LdapPal.BindToDirectory(_ldapHandle, cred.user, cred.password); + if (method == BindMethod.LDAP_AUTH_NEGOTIATE) + { + if (tempCredential == null) + { + error = BindSasl(); + } + else + { + // Explicit credentials were provided. If we call ldap_bind_s it will + // return LDAP_NOT_SUPPORTED, so just skip the P/Invoke. + error = (int)LdapError.NotSupported; + } + } + else + { + // Basic and Anonymous are handled elsewhere. + Debug.Assert(AuthType != AuthType.Anonymous && AuthType != AuthType.Basic); + error = (int)LdapError.AuthUnknown; + } } return error; diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.cs index 5b28020..9a200fc 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.cs @@ -641,11 +641,14 @@ namespace System.DirectoryServices.Protocols response.ResponseName = "1.3.6.1.4.1.1466.20037"; throw new TlsOperationException(response); } - else if (LdapErrorMappings.IsLdapError(error)) + + if (LdapErrorMappings.IsLdapError(error)) { string errorMessage = LdapErrorMappings.MapResultCode(error); throw new LdapException(error, errorMessage); } + + throw new LdapException(error); } } finally diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LocalAppContextSwitches.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LocalAppContextSwitches.cs new file mode 100644 index 0000000..59ddfdf --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LocalAppContextSwitches.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; + +namespace System +{ + internal static partial class LocalAppContextSwitches + { + private static int s_useBasicAuthFallback; + + public static bool UseBasicAuthFallback + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => GetCachedSwitchValue("System.DirectoryServices.Protocols.UseBasicAuthFallback", ref s_useBasicAuthFallback); + } + } +}