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 f38bb375b34..e2cd61e0b85 100644 --- a/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs +++ b/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs @@ -137,7 +137,7 @@ static Ldap() public static extern int ldap_set_option_referral([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref LdapReferralCallback outValue); [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([In] 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/Interop/LdapPal.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Linux.cs index 701fae26108..39b825f9d9a 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,7 @@ 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, IntPtr serverControls, IntPtr clientControls) => Interop.Ldap.ldap_start_tls(ldapHandle, serverControls, clientControls); // 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/ldap/LdapConnection.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Linux.cs index 02c8f0c2395..a253d255b0d 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 @@ -12,6 +12,7 @@ public partial class LdapConnection { // Linux doesn't support setting FQDN so we mark the flag as if it is already set so we don't make a call to set it again. private bool _setFQDNDone = true; + internal bool _startTls; private void InternalInitConnectionHandle(string hostname) { @@ -73,7 +74,12 @@ private int InternalConnectToServer() uris = $"{scheme}:{directoryIdentifier.PortNumber}"; } - return LdapPal.SetStringOption(_ldapHandle, LdapOption.LDAP_OPT_URI, uris); + int error = LdapPal.SetStringOption(_ldapHandle, LdapOption.LDAP_OPT_URI, uris); + if (error == 0 && _startTls) + { + error = LdapPal.StartTls(_ldapHandle, IntPtr.Zero, IntPtr.Zero); + } + return error; } private int InternalBind(NetworkCredential tempCredential, SEC_WINNT_AUTH_IDENTITY_EX cred, BindMethod method) diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs index 22f0b62bb04..f4f70e4c2cd 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs @@ -40,6 +40,11 @@ public ReferralChasingOptions ReferralChasing } } + public void StartTransportLayerSecurity(DirectoryControlCollection controls) + { + _connection._startTls = true; + } + private bool GetBoolValueHelper(LdapOption option) { if (_connection._disposed) diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs index 587bccc52cc..c4954d08b96 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections; using System.ComponentModel; +using System.Runtime.InteropServices; using System.Runtime.Versioning; namespace System.DirectoryServices.Protocols @@ -48,5 +50,196 @@ public ReferralChasingOptions ReferralChasing SetIntValueHelper(LdapOption.LDAP_OPT_REFERRALS, (int)value); } } + + public unsafe void StartTransportLayerSecurity(DirectoryControlCollection controls) + { + IntPtr serverControlArray = IntPtr.Zero; + LdapControl[] managedServerControls = null; + IntPtr clientControlArray = IntPtr.Zero; + LdapControl[] managedClientControls = null; + IntPtr ldapResult = IntPtr.Zero; + IntPtr referral = IntPtr.Zero; + + int serverError = 0; + Uri[] responseReferral = null; + + if (_connection._disposed) + { + throw new ObjectDisposedException(GetType().Name); + } + + try + { + IntPtr tempPtr = IntPtr.Zero; + + // build server control + managedServerControls = _connection.BuildControlArray(controls, true); + int structSize = Marshal.SizeOf(typeof(LdapControl)); + if (managedServerControls != null) + { + serverControlArray = Utility.AllocHGlobalIntPtrArray(managedServerControls.Length + 1); + for (int i = 0; i < managedServerControls.Length; i++) + { + IntPtr controlPtr = Marshal.AllocHGlobal(structSize); + Marshal.StructureToPtr(managedServerControls[i], controlPtr, false); + tempPtr = (IntPtr)((long)serverControlArray + IntPtr.Size * i); + Marshal.WriteIntPtr(tempPtr, controlPtr); + } + + tempPtr = (IntPtr)((long)serverControlArray + IntPtr.Size * managedServerControls.Length); + Marshal.WriteIntPtr(tempPtr, IntPtr.Zero); + } + + // Build client control. + managedClientControls = _connection.BuildControlArray(controls, false); + if (managedClientControls != null) + { + clientControlArray = Utility.AllocHGlobalIntPtrArray(managedClientControls.Length + 1); + for (int i = 0; i < managedClientControls.Length; i++) + { + IntPtr controlPtr = Marshal.AllocHGlobal(structSize); + Marshal.StructureToPtr(managedClientControls[i], controlPtr, false); + tempPtr = (IntPtr)((long)clientControlArray + IntPtr.Size * i); + Marshal.WriteIntPtr(tempPtr, controlPtr); + } + + tempPtr = (IntPtr)((long)clientControlArray + IntPtr.Size * managedClientControls.Length); + Marshal.WriteIntPtr(tempPtr, IntPtr.Zero); + } + + int error = LdapPal.StartTls(_connection._ldapHandle, ref serverError, ref ldapResult, serverControlArray, clientControlArray); + if (ldapResult != IntPtr.Zero) + { + // Parse the referral. + int resultError = LdapPal.ParseResultReferral(_connection._ldapHandle, ldapResult, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref referral, IntPtr.Zero, 0 /* not free it */); + if (resultError == 0 && referral != IntPtr.Zero) + { + char** referralPtr = (char**)referral; + char* singleReferral = referralPtr[0]; + int i = 0; + ArrayList referralList = new ArrayList(); + while (singleReferral != null) + { + string s = LdapPal.PtrToString((IntPtr)singleReferral); + referralList.Add(s); + + i++; + singleReferral = referralPtr[i]; + } + + // Free heap memory. + if (referral != IntPtr.Zero) + { + LdapPal.FreeValue(referral); + referral = IntPtr.Zero; + } + + if (referralList.Count > 0) + { + responseReferral = new Uri[referralList.Count]; + for (int j = 0; j < referralList.Count; j++) + { + responseReferral[j] = new Uri((string)referralList[j]); + } + } + } + } + + if (error != (int)ResultCode.Success) + { + if (Utility.IsResultCode((ResultCode)error)) + { + // If the server failed request for whatever reason, the ldap_start_tls returns LDAP_OTHER + // and the ServerReturnValue will contain the error code from the server. + if (error == (int)ResultCode.Other) + { + error = serverError; + } + + string errorMessage = OperationErrorMappings.MapResultCode(error); + ExtendedResponse response = new ExtendedResponse(null, null, (ResultCode)error, errorMessage, responseReferral); + response.ResponseName = "1.3.6.1.4.1.1466.20037"; + throw new TlsOperationException(response); + } + else if (LdapErrorMappings.IsLdapError(error)) + { + string errorMessage = LdapErrorMappings.MapResultCode(error); + throw new LdapException(error, errorMessage); + } + } + } + finally + { + if (serverControlArray != IntPtr.Zero) + { + // Release the memory from the heap. + for (int i = 0; i < managedServerControls.Length; i++) + { + IntPtr tempPtr = Marshal.ReadIntPtr(serverControlArray, IntPtr.Size * i); + if (tempPtr != IntPtr.Zero) + { + Marshal.FreeHGlobal(tempPtr); + } + } + Marshal.FreeHGlobal(serverControlArray); + } + + if (managedServerControls != null) + { + for (int i = 0; i < managedServerControls.Length; i++) + { + if (managedServerControls[i].ldctl_oid != IntPtr.Zero) + { + Marshal.FreeHGlobal(managedServerControls[i].ldctl_oid); + } + + if (managedServerControls[i].ldctl_value != null) + { + if (managedServerControls[i].ldctl_value.bv_val != IntPtr.Zero) + { + Marshal.FreeHGlobal(managedServerControls[i].ldctl_value.bv_val); + } + } + } + } + + if (clientControlArray != IntPtr.Zero) + { + // Release the memor from the heap. + for (int i = 0; i < managedClientControls.Length; i++) + { + IntPtr tempPtr = Marshal.ReadIntPtr(clientControlArray, IntPtr.Size * i); + if (tempPtr != IntPtr.Zero) + { + Marshal.FreeHGlobal(tempPtr); + } + } + + Marshal.FreeHGlobal(clientControlArray); + } + + if (managedClientControls != null) + { + for (int i = 0; i < managedClientControls.Length; i++) + { + if (managedClientControls[i].ldctl_oid != IntPtr.Zero) + { + Marshal.FreeHGlobal(managedClientControls[i].ldctl_oid); + } + + if (managedClientControls[i].ldctl_value != null) + { + if (managedClientControls[i].ldctl_value.bv_val != IntPtr.Zero) + Marshal.FreeHGlobal(managedClientControls[i].ldctl_value.bv_val); + } + } + } + + if (referral != IntPtr.Zero) + { + LdapPal.FreeValue(referral); + } + } + } } } 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 5b28020eed2..d7d6e07203f 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 @@ -531,197 +531,6 @@ public void FastConcurrentBind() ErrorChecking.CheckAndSetLdapError(error); } - public unsafe void StartTransportLayerSecurity(DirectoryControlCollection controls) - { - IntPtr serverControlArray = IntPtr.Zero; - LdapControl[] managedServerControls = null; - IntPtr clientControlArray = IntPtr.Zero; - LdapControl[] managedClientControls = null; - IntPtr ldapResult = IntPtr.Zero; - IntPtr referral = IntPtr.Zero; - - int serverError = 0; - Uri[] responseReferral = null; - - if (_connection._disposed) - { - throw new ObjectDisposedException(GetType().Name); - } - - try - { - IntPtr tempPtr = IntPtr.Zero; - - // build server control - managedServerControls = _connection.BuildControlArray(controls, true); - int structSize = Marshal.SizeOf(typeof(LdapControl)); - if (managedServerControls != null) - { - serverControlArray = Utility.AllocHGlobalIntPtrArray(managedServerControls.Length + 1); - for (int i = 0; i < managedServerControls.Length; i++) - { - IntPtr controlPtr = Marshal.AllocHGlobal(structSize); - Marshal.StructureToPtr(managedServerControls[i], controlPtr, false); - tempPtr = (IntPtr)((long)serverControlArray + IntPtr.Size * i); - Marshal.WriteIntPtr(tempPtr, controlPtr); - } - - tempPtr = (IntPtr)((long)serverControlArray + IntPtr.Size * managedServerControls.Length); - Marshal.WriteIntPtr(tempPtr, IntPtr.Zero); - } - - // Build client control. - managedClientControls = _connection.BuildControlArray(controls, false); - if (managedClientControls != null) - { - clientControlArray = Utility.AllocHGlobalIntPtrArray(managedClientControls.Length + 1); - for (int i = 0; i < managedClientControls.Length; i++) - { - IntPtr controlPtr = Marshal.AllocHGlobal(structSize); - Marshal.StructureToPtr(managedClientControls[i], controlPtr, false); - tempPtr = (IntPtr)((long)clientControlArray + IntPtr.Size * i); - Marshal.WriteIntPtr(tempPtr, controlPtr); - } - - tempPtr = (IntPtr)((long)clientControlArray + IntPtr.Size * managedClientControls.Length); - Marshal.WriteIntPtr(tempPtr, IntPtr.Zero); - } - - int error = LdapPal.StartTls(_connection._ldapHandle, ref serverError, ref ldapResult, serverControlArray, clientControlArray); - if (ldapResult != IntPtr.Zero) - { - // Parse the referral. - int resultError = LdapPal.ParseResultReferral(_connection._ldapHandle, ldapResult, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref referral, IntPtr.Zero, 0 /* not free it */); - if (resultError == 0 && referral != IntPtr.Zero) - { - char** referralPtr = (char**)referral; - char* singleReferral = referralPtr[0]; - int i = 0; - ArrayList referralList = new ArrayList(); - while (singleReferral != null) - { - string s = LdapPal.PtrToString((IntPtr)singleReferral); - referralList.Add(s); - - i++; - singleReferral = referralPtr[i]; - } - - // Free heap memory. - if (referral != IntPtr.Zero) - { - LdapPal.FreeValue(referral); - referral = IntPtr.Zero; - } - - if (referralList.Count > 0) - { - responseReferral = new Uri[referralList.Count]; - for (int j = 0; j < referralList.Count; j++) - { - responseReferral[j] = new Uri((string)referralList[j]); - } - } - } - } - - if (error != (int)ResultCode.Success) - { - if (Utility.IsResultCode((ResultCode)error)) - { - // If the server failed request for whatever reason, the ldap_start_tls returns LDAP_OTHER - // and the ServerReturnValue will contain the error code from the server. - if (error == (int)ResultCode.Other) - { - error = serverError; - } - - string errorMessage = OperationErrorMappings.MapResultCode(error); - ExtendedResponse response = new ExtendedResponse(null, null, (ResultCode)error, errorMessage, responseReferral); - response.ResponseName = "1.3.6.1.4.1.1466.20037"; - throw new TlsOperationException(response); - } - else if (LdapErrorMappings.IsLdapError(error)) - { - string errorMessage = LdapErrorMappings.MapResultCode(error); - throw new LdapException(error, errorMessage); - } - } - } - finally - { - if (serverControlArray != IntPtr.Zero) - { - // Release the memory from the heap. - for (int i = 0; i < managedServerControls.Length; i++) - { - IntPtr tempPtr = Marshal.ReadIntPtr(serverControlArray, IntPtr.Size * i); - if (tempPtr != IntPtr.Zero) - { - Marshal.FreeHGlobal(tempPtr); - } - } - Marshal.FreeHGlobal(serverControlArray); - } - - if (managedServerControls != null) - { - for (int i = 0; i < managedServerControls.Length; i++) - { - if (managedServerControls[i].ldctl_oid != IntPtr.Zero) - { - Marshal.FreeHGlobal(managedServerControls[i].ldctl_oid); - } - - if (managedServerControls[i].ldctl_value != null) - { - if (managedServerControls[i].ldctl_value.bv_val != IntPtr.Zero) - { - Marshal.FreeHGlobal(managedServerControls[i].ldctl_value.bv_val); - } - } - } - } - - if (clientControlArray != IntPtr.Zero) - { - // Release the memor from the heap. - for (int i = 0; i < managedClientControls.Length; i++) - { - IntPtr tempPtr = Marshal.ReadIntPtr(clientControlArray, IntPtr.Size * i); - if (tempPtr != IntPtr.Zero) - { - Marshal.FreeHGlobal(tempPtr); - } - } - - Marshal.FreeHGlobal(clientControlArray); - } - - if (managedClientControls != null) - { - for (int i = 0; i < managedClientControls.Length; i++) - { - if (managedClientControls[i].ldctl_oid != IntPtr.Zero) - { - Marshal.FreeHGlobal(managedClientControls[i].ldctl_oid); - } - - if (managedClientControls[i].ldctl_value != null) - { - if (managedClientControls[i].ldctl_value.bv_val != IntPtr.Zero) - Marshal.FreeHGlobal(managedClientControls[i].ldctl_value.bv_val); - } - } - } - - if (referral != IntPtr.Zero) - { - LdapPal.FreeValue(referral); - } - } - } - public void StopTransportLayerSecurity() { if (_connection._disposed)