Skip to content

Commit

Permalink
Allow disabling LDAP referral chasing on Linux. (#54380)
Browse files Browse the repository at this point in the history
* Allow disabling LDAP referral chasing on Linux.

Before this, changing SessionOptions.ReferralChasing on Linux was
ineffective, since we were passing `ref int` to OpenLDAP, which does not
follow the pointer passed and interprets any non-zero value as
"enabled".

This passes a boolean directly instead, which the library is able to
detect properly.

* fixup! Allow disabling LDAP referral chasing on Linux.

* fixup! Allow disabling LDAP referral chasing on Linux.

* fixup! Allow disabling LDAP referral chasing on Linux.

* fixup! Allow disabling LDAP referral chasing on Linux.
  • Loading branch information
iinuwa authored Jul 3, 2021
1 parent fe9a54d commit 0605bb3
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ static Ldap()
[DllImport(Libraries.OpenLdap, EntryPoint = "ldap_get_dn", CharSet = CharSet.Ansi)]
public static extern IntPtr ldap_get_dn([In] ConnectionHandle ldapHandle, [In] IntPtr result);

[DllImport(Libraries.OpenLdap, EntryPoint = "ldap_get_option", CharSet = CharSet.Ansi)]
public static extern int ldap_get_option_bool([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref bool outValue);

[DllImport(Libraries.OpenLdap, EntryPoint = "ldap_get_option", CharSet = CharSet.Ansi)]
public static extern int ldap_get_option_secInfo([In] ConnectionHandle ldapHandle, [In] LdapOption option, [In, Out] SecurityPackageContextConnectionInformation outValue);

Expand Down Expand Up @@ -112,6 +115,9 @@ static Ldap()
[DllImport(Libraries.OpenLdap, EntryPoint = "ldap_search_ext", CharSet = CharSet.Ansi)]
public static extern int ldap_search([In] ConnectionHandle ldapHandle, string dn, int scope, string filter, IntPtr attributes, bool attributeOnly, IntPtr servercontrol, IntPtr clientcontrol, int timelimit, int sizelimit, ref int messageNumber);

[DllImport(Libraries.OpenLdap, EntryPoint = "ldap_set_option", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern int ldap_set_option_bool([In] ConnectionHandle ld, [In] LdapOption option, bool value);

[DllImport(Libraries.OpenLdap, EntryPoint = "ldap_set_option", CharSet = CharSet.Ansi)]
public static extern int ldap_set_option_clientcert([In] ConnectionHandle ldapHandle, [In] LdapOption option, QUERYCLIENTCERT outValue);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Expand Down Expand Up @@ -492,4 +492,7 @@
<data name="QuotaControlNotSupported" xml:space="preserve">
<value>System.DirectoryServices.Protocols.QuotaControl is not supported on this platform.</value>
</data>
<data name="ReferralChasingOptionsNotSupported" xml:space="preserve">
<value>Only ReferralChasingOptions.None and ReferralChasingOptions.All are supported on Linux.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ internal static int GetLastErrorFromConnection(ConnectionHandle ldapHandle)
return result;
}

internal static int GetBoolOption(ConnectionHandle ldapHandle, LdapOption option, ref bool outValue) => Interop.Ldap.ldap_get_option_bool(ldapHandle, option, ref outValue);

internal static int GetIntOption(ConnectionHandle ldapHandle, LdapOption option, ref int outValue) => Interop.Ldap.ldap_get_option_int(ldapHandle, option, ref outValue);

internal static int GetPtrOption(ConnectionHandle ldapHandle, LdapOption option, ref IntPtr outValue) => Interop.Ldap.ldap_get_option_ptr(ldapHandle, option, ref outValue);
Expand Down Expand Up @@ -85,6 +87,8 @@ internal static int RenameDirectoryEntry(ConnectionHandle ldapHandle, string dn,
internal static int SearchDirectory(ConnectionHandle ldapHandle, string dn, int scope, string filter, IntPtr attributes, bool attributeOnly, IntPtr servercontrol, IntPtr clientcontrol, int timelimit, int sizelimit, ref int messageNumber) =>
Interop.Ldap.ldap_search(ldapHandle, dn, scope, filter, attributes, attributeOnly, servercontrol, clientcontrol, timelimit, sizelimit, ref messageNumber);

internal static int SetBoolOption(ConnectionHandle ld, LdapOption option, bool value) => Interop.Ldap.ldap_set_option_bool(ld, option, value);

// This option is not supported in Linux, so it would most likely throw.
internal static int SetClientCertOption(ConnectionHandle ldapHandle, LdapOption option, QUERYCLIENTCERT outValue) => Interop.Ldap.ldap_set_option_clientcert(ldapHandle, option, outValue);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// 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.Versioning;
using System.ComponentModel;

namespace System.DirectoryServices.Protocols
{
Expand Down Expand Up @@ -30,5 +30,52 @@ public int ProtocolVersion
get => GetPtrValueHelper(LdapOption.LDAP_OPT_VERSION).ToInt32();
set => SetPtrValueHelper(LdapOption.LDAP_OPT_VERSION, new IntPtr(value));
}

public ReferralChasingOptions ReferralChasing
{
get
{
return GetBoolValueHelper(LdapOption.LDAP_OPT_REFERRALS) ? ReferralChasingOptions.All : ReferralChasingOptions.None;
}
set
{
if (((value) & (~ReferralChasingOptions.All)) != 0)
{
throw new InvalidEnumArgumentException(nameof(value), (int)value, typeof(ReferralChasingOptions));
}
if (value != ReferralChasingOptions.None && value != ReferralChasingOptions.All)
{
throw new PlatformNotSupportedException(SR.ReferralChasingOptionsNotSupported);
}

SetBoolValueHelper(LdapOption.LDAP_OPT_REFERRALS, value == ReferralChasingOptions.All);
}
}

private bool GetBoolValueHelper(LdapOption option)
{
if (_connection._disposed)
{
throw new ObjectDisposedException(GetType().Name);
}

bool outValue = false;
int error = LdapPal.GetBoolOption(_connection._ldapHandle, option, ref outValue);
ErrorChecking.CheckAndSetLdapError(error);

return outValue;
}

private void SetBoolValueHelper(LdapOption option, bool value)
{
if (_connection._disposed)
{
throw new ObjectDisposedException(GetType().Name);
}

int error = LdapPal.SetBoolOption(_connection._ldapHandle, option, value);

ErrorChecking.CheckAndSetLdapError(error);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.ComponentModel;
using System.Runtime.Versioning;

namespace System.DirectoryServices.Protocols
Expand Down Expand Up @@ -28,5 +29,23 @@ public int ProtocolVersion
get => GetIntValueHelper(LdapOption.LDAP_OPT_VERSION);
set => SetIntValueHelper(LdapOption.LDAP_OPT_VERSION, value);
}

public ReferralChasingOptions ReferralChasing
{
get
{
int result = GetIntValueHelper(LdapOption.LDAP_OPT_REFERRALS);
return result == 1 ? ReferralChasingOptions.All : (ReferralChasingOptions)result;
}
set
{
if (((value) & (~ReferralChasingOptions.All)) != 0)
{
throw new InvalidEnumArgumentException(nameof(value), (int)value, typeof(ReferralChasingOptions));
}

SetIntValueHelper(LdapOption.LDAP_OPT_REFERRALS, (int)value);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,24 +136,6 @@ internal LdapSessionOptions(LdapConnection connection)
_serverCertificateRoutine = new VERIFYSERVERCERT(ProcessServerCertificate);
}

public ReferralChasingOptions ReferralChasing
{
get
{
int result = GetIntValueHelper(LdapOption.LDAP_OPT_REFERRALS);
return result == 1 ? ReferralChasingOptions.All : (ReferralChasingOptions)result;
}
set
{
if (((value) & (~ReferralChasingOptions.All)) != 0)
{
throw new InvalidEnumArgumentException(nameof(value), (int)value, typeof(ReferralChasingOptions));
}

SetIntValueHelper(LdapOption.LDAP_OPT_REFERRALS, (int)value);
}
}

public int ReferralHopLimit
{
get => GetIntValueHelper(LdapOption.LDAP_OPT_REFERRAL_HOP_LIMIT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,23 @@ public class LdapSessionOptionsTests
[PlatformSpecific(TestPlatforms.Windows)]
[InlineData(ReferralChasingOptions.None)]
[InlineData(ReferralChasingOptions.External)]
public void ReferralChasing_Set_GetReturnsExpected(ReferralChasingOptions value)
public void ReferralChasing_Set_GetReturnsExpected_On_Windows(ReferralChasingOptions value)
{
using (var connection = new LdapConnection("server"))
{
LdapSessionOptions options = connection.SessionOptions;
Assert.Equal(ReferralChasingOptions.All, options.ReferralChasing);

options.ReferralChasing = value;
Assert.Equal(value, options.ReferralChasing);
}
}

[Theory]
[PlatformSpecific(TestPlatforms.Linux)]
[InlineData(ReferralChasingOptions.None)]
[InlineData(ReferralChasingOptions.All)]
public void ReferralChasing_Set_GetReturnsExpected_On_Linux(ReferralChasingOptions value)
{
using (var connection = new LdapConnection("server"))
{
Expand Down

0 comments on commit 0605bb3

Please sign in to comment.