Skip to content
Draft
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 @@ -895,7 +895,7 @@ private unsafe int ProcessQueryConnection(IntPtr PrimaryConnection, IntPtr Refer
NewDN = LdapPal.PtrToString(NewDNPtr);
}

string target = $"{Marshal.PtrToStringUni(HostNamePtr)}:{PortNumber}";
string target = $"{Marshal.PtrToStringAnsi(HostNamePtr)}:{PortNumber}";
var identifier = new LdapDirectoryIdentifier(target);

NetworkCredential cred = ProcessSecAuthIdentity(SecAuthIdentity);
Expand Down Expand Up @@ -959,7 +959,7 @@ private unsafe Interop.BOOL ProcessNotifyConnection(IntPtr primaryConnection, In
newDN = LdapPal.PtrToString(newDNPtr);
}

string target = $"{Marshal.PtrToStringUni(hostNamePtr)}:{portNumber}";
string target = $"{Marshal.PtrToStringAnsi(hostNamePtr)}:{portNumber}";
var identifier = new LdapDirectoryIdentifier(target);

NetworkCredential cred = ProcessSecAuthIdentity(SecAuthIdentity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using Xunit;

namespace System.DirectoryServices.Protocols.Tests
Expand Down Expand Up @@ -38,6 +40,137 @@ public void QueryForConnection_Set_GetReturnsExpected()
Assert.Equal(QueryForConnection, callback.QueryForConnection);
}

[Fact]
[PlatformSpecific(TestPlatforms.Windows)]
public void ProcessQueryConnection_MarshalsHostNameAsAnsi()
{
const string HostName = "server01";
const int PortNumber = 389;
string[] servers = null;

using (var connection = new LdapConnection("server"))
{
connection.SessionOptions.ReferralCallback = new ReferralCallback
{
QueryForConnection = (primaryConnection, referralFromConnection, newDistinguishedName, identifier, credential, currentUserToken) =>
{
servers = identifier.Servers;
return null;
}
};

InvokeProcessQueryConnection(connection.SessionOptions, HostName, PortNumber);
}

Assert.Equal(new[] { $"{HostName}:{PortNumber}" }, servers);
}

[Fact]
[PlatformSpecific(TestPlatforms.Windows)]
public void ProcessNotifyConnection_MarshalsHostNameAsAnsi()
{
const string HostName = "server01";
const int PortNumber = 389;
string[] servers = null;

using (var connection = new LdapConnection("server"))
using (var newConnection = new LdapConnection("server"))
{
connection.SessionOptions.ReferralCallback = new ReferralCallback
{
NotifyNewConnection = (primaryConnection, referralFromConnection, newDistinguishedName, identifier, notifiedConnection, credential, currentUserToken, errorCodeFromBind) =>
{
servers = identifier.Servers;
return false;
}
};

InvokeProcessNotifyConnection(connection.SessionOptions, HostName, GetConnectionHandle(newConnection), PortNumber);
}

Assert.Equal(new[] { $"{HostName}:{PortNumber}" }, servers);
}

private static unsafe void InvokeProcessQueryConnection(LdapSessionOptions options, string hostName, int portNumber)
{
MethodInfo method = GetCallbackMethod("ProcessQueryConnection");
ParameterInfo[] parameters = method.GetParameters();
IntPtr hostNamePointer = AllocateAnsiString(hostName);
IntPtr currentUserPointer = Marshal.AllocHGlobal(sizeof(long));
IntPtr connectionToUsePointer = Marshal.AllocHGlobal(IntPtr.Size);

try
{
Marshal.WriteInt64(currentUserPointer, 0);
Marshal.WriteIntPtr(connectionToUsePointer, IntPtr.Zero);

method.Invoke(options, new object[]
{
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
hostNamePointer,
portNumber,
null,
Pointer.Box(currentUserPointer.ToPointer(), parameters[6].ParameterType),
Pointer.Box(connectionToUsePointer.ToPointer(), parameters[7].ParameterType)
});
}
finally
{
Marshal.FreeHGlobal(connectionToUsePointer);
Marshal.FreeHGlobal(currentUserPointer);
Marshal.FreeHGlobal(hostNamePointer);
}
}

private static unsafe void InvokeProcessNotifyConnection(LdapSessionOptions options, string hostName, IntPtr newConnection, int portNumber)
{
MethodInfo method = GetCallbackMethod("ProcessNotifyConnection");
ParameterInfo[] parameters = method.GetParameters();
IntPtr hostNamePointer = AllocateAnsiString(hostName);
IntPtr currentUserPointer = Marshal.AllocHGlobal(sizeof(long));

try
{
Marshal.WriteInt64(currentUserPointer, 0);

method.Invoke(options, new object[]
{
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
hostNamePointer,
newConnection,
portNumber,
null,
Pointer.Box(currentUserPointer.ToPointer(), parameters[7].ParameterType),
0
});
}
finally
{
Marshal.FreeHGlobal(currentUserPointer);
Marshal.FreeHGlobal(hostNamePointer);
}
}

private static IntPtr AllocateAnsiString(string value)
{
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(value);
IntPtr pointer = Marshal.AllocHGlobal(bytes.Length + 2);
Marshal.Copy(bytes, 0, pointer, bytes.Length);
Marshal.WriteByte(pointer, bytes.Length, 0);
Marshal.WriteByte(pointer, bytes.Length + 1, 0);
return pointer;
}

private static MethodInfo GetCallbackMethod(string name) =>
typeof(LdapSessionOptions).GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic);

private static IntPtr GetConnectionHandle(LdapConnection connection) =>
((SafeHandle)typeof(LdapConnection).GetField("_ldapHandle", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(connection)).DangerousGetHandle();

internal static void DereferenceConnection(LdapConnection primaryConnection, LdapConnection connectionToDereference) { }
internal static bool NotifyNewConnection(LdapConnection primaryConnection, LdapConnection referralFromConnection, string newDistinguishedName, LdapDirectoryIdentifier identifier, LdapConnection newConnection, NetworkCredential credential, long currentUserToken, int errorCodeFromBind) => true;
internal static LdapConnection QueryForConnection(LdapConnection primaryConnection, LdapConnection referralFromConnection, string newDistinguishedName, LdapDirectoryIdentifier identifier, NetworkCredential credential, long currentUserToken) => null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-osx;$(NetFrameworkCurrent)</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="BerConverterTests.cs" />
Expand Down
Loading