Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,9 @@ static Ldap()
[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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@
<Compile Include="System\DirectoryServices\Protocols\Interop\BerPal.Linux.cs" />
<Compile Include="System\DirectoryServices\Protocols\ldap\LdapConnection.Linux.cs" />
<Compile Include="System\DirectoryServices\Protocols\ldap\LdapSessionOptions.Linux.cs" />
<Compile Include="System\DirectoryServices\Protocols\ldap\LocalAppContextSwitches.cs" />
<Compile Include="System\DirectoryServices\Protocols\Interop\SafeHandles.Linux.cs" />
<Compile Include="$(CommonPath)System\LocalAppContextSwitches.Common.cs">
<Link>Common\System\LocalAppContextSwitches.Common.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Linux\OpenLdap\Interop.Ldap.cs">
<Link>Common\Interop\Linux\OpenLdap\Interop.Ldap.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,31 @@ internal static int BindToDirectory(ConnectionHandle ld, string who, string pass
}
}

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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ public ConnectionHandle()
_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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ private void InternalInitConnectionHandle(string hostname)
throw new NullReferenceException();
}

_ldapHandle = new ConnectionHandle();
_ldapHandle = new ConnectionHandle($"ldap://{hostname}:{((LdapDirectoryIdentifier)_directoryIdentifier).PortNumber}");
}

private int InternalConnectToServer()
Expand Down Expand Up @@ -79,13 +79,39 @@ private int InternalConnectToServer()
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -641,11 +641,14 @@ public unsafe void StartTransportLayerSecurity(DirectoryControlCollection contro
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
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
}