From f06235864d75bd7d3871567dd871f43bdda73faa Mon Sep 17 00:00:00 2001 From: Marton Balassa <7115274+BalassaMarton@users.noreply.github.com> Date: Wed, 31 May 2023 12:00:02 +0200 Subject: [PATCH] =?UTF-8?q?=EF=BB=BFFix=20memory=20leaks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LdapForNet/BerConverter.cs | 43 +++--- LdapForNet/LdapConnection.cs | 122 ++++++++++-------- LdapForNet/Native/LdapNative.cs | 9 +- LdapForNet/Native/LdapNativeLinux.cs | 68 +++++++++- LdapForNet/Native/LdapNativeOsx.cs | 45 ++++++- LdapForNet/Native/LdapNativeWindows.cs | 49 +++++-- LdapForNet/Native/NativeMethodsLinux.cs | 10 +- LdapForNet/Native/NativeMethodsOsx.cs | 8 +- LdapForNet/Native/NativeMethodsWindows.cs | 4 +- .../RequestHandlers/SearchRequestHandler.cs | 65 +++++----- 10 files changed, 291 insertions(+), 132 deletions(-) diff --git a/LdapForNet/BerConverter.cs b/LdapForNet/BerConverter.cs index da929fc..31329ff 100644 --- a/LdapForNet/BerConverter.cs +++ b/LdapForNet/BerConverter.cs @@ -502,8 +502,8 @@ private static int BerScanfBitString(BerSafeHandle berElement, char fmt, out obj byte[] byteArray = null; var rc = LdapNative.Instance.ber_scanf_bitstring(berElement, new string(fmt, 1), ref ptrResult, ref length); - // try - // { + try + { if (rc != -1) { if (ptrResult != IntPtr.Zero) @@ -525,14 +525,14 @@ private static int BerScanfBitString(BerSafeHandle berElement, char fmt, out obj result = byteArray; } - // } - // finally - // { - // if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && ptrResult != IntPtr.Zero) - // { - // LdapNative.Instance.ber_memfree(ptrResult); - // } - // } + } + finally + { + if (ptrResult != IntPtr.Zero) + { + LdapNative.Instance.BerScanfFree(fmt, ptrResult); + } + } return rc; } @@ -582,7 +582,7 @@ private static int BerScanfaString(BerSafeHandle berElement, char fmt, out objec { if (result != IntPtr.Zero) { - LdapNative.Instance.ber_memfree(result); + LdapNative.Instance.BerScanfFree(fmt, result); } } @@ -591,12 +591,12 @@ private static int BerScanfaString(BerSafeHandle berElement, char fmt, out objec private static int BerScanfString(BerSafeHandle berElement, char fmt, out object result) { int rc; - var ptr = Marshal.AllocHGlobal(IntPtr.Size); + var ptr = IntPtr.Zero; var length = -1; result = null; try { - rc = LdapNative.Instance.ber_scanf_string(berElement, new string(fmt, 1), ptr, ref length); + rc = LdapNative.Instance.ber_scanf_string(berElement, new string(fmt, 1), ref ptr, ref length); if (rc != -1) { var byteArray = new byte[length]; @@ -608,7 +608,7 @@ private static int BerScanfString(BerSafeHandle berElement, char fmt, out object { if (ptr != IntPtr.Zero) { - Marshal.FreeHGlobal(ptr); + LdapNative.Instance.BerScanfFree(fmt, ptr); } } @@ -688,11 +688,11 @@ private static int EncodingByteArrayHelper(BerSafeHandle berElement, byte[] valu private static int DecodingBerValOstringHelper(BerSafeHandle berElement, char fmt, out byte[] byteArray) { - var result = Marshal.AllocHGlobal(IntPtr.Size); + var result = IntPtr.Zero; var binaryValue = new Native.Native.berval(); byteArray = null; - var error = LdapNative.Instance.ber_scanf_ostring(berElement, new string(fmt, 1), result); + var error = LdapNative.Instance.ber_scanf_ostring(berElement, new string(fmt, 1), ref result); try { @@ -708,7 +708,7 @@ private static int DecodingBerValOstringHelper(BerSafeHandle berElement, char fm { if (result != IntPtr.Zero) { - LdapNative.Instance.ber_memfree(result); + LdapNative.Instance.BerScanfFree(fmt, result); } } @@ -742,7 +742,7 @@ private static int DecodingBerValByteArrayHelper(BerSafeHandle berElement, char { if (result != IntPtr.Zero) { - LdapNative.Instance.ber_bvfree(result); + LdapNative.Instance.BerScanfFree(fmt, result); } } @@ -771,6 +771,7 @@ private static int EncodingBerValHelper(BerSafeHandle berElement, byte[] value, } return rc; } + private static int EncodingMultiByteArrayHelper(BerSafeHandle berElement, byte[][] value, char fmt) { var stringArray = IntPtr.Zero; @@ -947,7 +948,7 @@ private static int DecodingBerValMultiByteArrayHelper(BerSafeHandle berElement, { if (ptrResult != IntPtr.Zero) { - LdapNative.Instance.ber_bvecfree(ptrResult); + LdapNative.Instance.BerScanfFree(fmt, ptrResult); } } @@ -989,7 +990,7 @@ private static int DecodingBerValMultiByteArrayHelperW(BerSafeHandle berElement, { if (ptrResult != IntPtr.Zero) { - //LdapNative.Instance.ber_bvarrayfree(ptrResult); + LdapNative.Instance.BerScanfFree(fmt, ptrResult); } } @@ -1019,7 +1020,7 @@ private static int DecodingMultiByteArrayHelper(BerSafeHandle berElement, char f { if (ptrResult != IntPtr.Zero) { - LdapNative.Instance.ber_memfree(ptrResult); + LdapNative.Instance.BerScanfFree(fmt, ptrResult); } } diff --git a/LdapForNet/LdapConnection.cs b/LdapForNet/LdapConnection.cs index 04a4419..b5030e3 100644 --- a/LdapForNet/LdapConnection.cs +++ b/LdapForNet/LdapConnection.cs @@ -111,31 +111,41 @@ public async Task BindAsync(Native.Native.LdapAuthType authType, LdapCredential _native.LdapConnect(_ld, _connectionTimeOut); var timeout = GetConnectionTimeval(); var result = IntPtr.Zero; - if (authType == Native.Native.LdapAuthType.Simple) - { - result = await _native.BindSimpleAsync(_ld, ldapCredential.UserName, ldapCredential.Password, timeout); - } - else if (authType == Native.Native.LdapAuthType.Anonymous) - { - result = await _native.BindSimpleAsync(_ld, null, null, timeout); - } - else if (authType == Native.Native.LdapAuthType.ExternalAd) - { - // no action required - } - else if (authType != Native.Native.LdapAuthType.Unknown) + try { - result = await _native.BindSaslAsync(_ld, authType, ldapCredential, timeout); - } - else - { - throw new LdapAuthMethodNotSupportedException( - new LdapExceptionData($"Not implemented mechanism: {authType.ToString()}. Available: {Native.Native.LdapAuthType.Simple.ToString()} | {Native.Native.LdapAuthType.GssApi}. ")); + if (authType == Native.Native.LdapAuthType.Simple) + { + result = await _native.BindSimpleAsync(_ld, ldapCredential.UserName, ldapCredential.Password, timeout); + } + else if (authType == Native.Native.LdapAuthType.Anonymous) + { + result = await _native.BindSimpleAsync(_ld, null, null, timeout); + } + else if (authType == Native.Native.LdapAuthType.ExternalAd) + { + // no action required + } + else if (authType != Native.Native.LdapAuthType.Unknown) + { + result = await _native.BindSaslAsync(_ld, authType, ldapCredential, timeout); + } + else + { + throw new LdapAuthMethodNotSupportedException( + new LdapExceptionData($"Not implemented mechanism: {authType.ToString()}. Available: {Native.Native.LdapAuthType.Simple.ToString()} | {Native.Native.LdapAuthType.GssApi}. ")); + } + + if (result != IntPtr.Zero) + { + ThrowIfParseResultError(result); + } } - - if (result != IntPtr.Zero) + finally { - ThrowIfParseResultError(result); + if (result != IntPtr.Zero) + { + _native.ldap_msgfree(result); + } } _bound = true; @@ -347,7 +357,6 @@ private DirectoryResponse ProcessResponse(DirectoryRequest directoryRequest, CancellationToken token) { var status = LdapResultCompleteStatus.Unknown; - var msg = Marshal.AllocHGlobal(IntPtr.Size); var timeout = GetConnectionTimeval(); @@ -357,39 +366,50 @@ private DirectoryResponse ProcessResponse(DirectoryRequest directoryRequest, DirectoryResponse response = default; while (status != LdapResultCompleteStatus.Complete && !token.IsCancellationRequested) { + var msg = IntPtr.Zero; var resType = _native.ldap_result(_ld, messageId, 0, timeout, ref msg); - ThrowIfResultError(directoryRequest, resType, response); - - status = requestHandler.Handle(_ld, resType, msg, out response); - response.MessageId = messageId; - - if (status == LdapResultCompleteStatus.Unknown) + try { - throw new LdapException(new LdapExceptionData($"Unknown search type {resType}", nameof(_native.ldap_result), 1){ Response = response}); + ThrowIfResultError(directoryRequest, resType, response); + + status = requestHandler.Handle(_ld, resType, msg, out response); + response.MessageId = messageId; + + if (status == LdapResultCompleteStatus.Unknown) + { + throw new LdapException(new LdapExceptionData($"Unknown search type {resType}", nameof(_native.ldap_result), 1){ Response = response}); + } + + if (status == LdapResultCompleteStatus.Complete) + { + var responseReferral = new Uri[0]; + var responseControl = new DirectoryControl[0]; + var res = ParseResultError(msg, out var errorMessage, out var matchedDn, ref responseReferral, ref responseControl); + + if (res == (int)Native.Native.ResultCode.SizeLimitExceeded + && directoryRequest is SearchRequest searchRequest + && response is SearchResponse searchResponse + && searchRequest.SizeLimit != 0 + && searchResponse.Entries.Count >= searchRequest.SizeLimit) + { + Debug.WriteLine("ldap_parse_result returned ResultCode.SizeLimitExceeded but the correct number of entries were already returned"); + res = (int)Native.Native.ResultCode.Success; + errorMessage = null; + } + + response.ResultCode = (Native.Native.ResultCode)res; + response.ErrorMessage = errorMessage; + response.Referral = responseReferral; + response.Controls = responseControl; + response.MatchedDN = matchedDn; + } } - - if (status == LdapResultCompleteStatus.Complete) + finally { - var responseReferral = new Uri[0]; - var responseControl = new DirectoryControl[0]; - var res = ParseResultError(msg, out var errorMessage, out var matchedDn, ref responseReferral, ref responseControl); - - if (res == (int)Native.Native.ResultCode.SizeLimitExceeded - && directoryRequest is SearchRequest searchRequest - && response is SearchResponse searchResponse - && searchRequest.SizeLimit != 0 - && searchResponse.Entries.Count >= searchRequest.SizeLimit) + if (msg != IntPtr.Zero) { - Debug.WriteLine("ldap_parse_result returned ResultCode.SizeLimitExceeded but the correct number of entries were already returned"); - res = (int)Native.Native.ResultCode.Success; - errorMessage = null; + _native.ldap_msgfree(msg); } - - response.ResultCode = (Native.Native.ResultCode)res; - response.ErrorMessage = errorMessage; - response.Referral = responseReferral; - response.Controls = responseControl; - response.MatchedDN = matchedDn; } } @@ -457,7 +477,7 @@ private int ParseResultError(IntPtr msg, out string errorMessage, out string mat var referrals = IntPtr.Zero; var serverctrls = IntPtr.Zero; _native.ThrowIfError(_ld, _native.ldap_parse_result(_ld, msg, ref rc, ref matchedDnPtr, ref errorMessagePtr, - ref referrals, ref serverctrls, 1), nameof(_native.ldap_parse_result)); + ref referrals, ref serverctrls, 0), nameof(_native.ldap_parse_result)); errorMessage = Encoder.Instance.PtrToString(errorMessagePtr); matchedDn = Encoder.Instance.PtrToString(matchedDnPtr); if (referrals != IntPtr.Zero) diff --git a/LdapForNet/Native/LdapNative.cs b/LdapForNet/Native/LdapNative.cs index b570ee4..7a83646 100644 --- a/LdapForNet/Native/LdapNative.cs +++ b/LdapForNet/Native/LdapNative.cs @@ -66,6 +66,7 @@ internal abstract int Search(SafeHandle ld, string @base, int scope, string filt internal abstract LdapResultType ldap_result(SafeHandle ld, int msgid, int all, LDAP_TIMEVAL timeout, ref IntPtr pMessage); + internal abstract int ldap_parse_result(SafeHandle ld, IntPtr result, ref int errcodep, ref IntPtr matcheddnp, ref IntPtr errmsgp, ref IntPtr referralsp, ref IntPtr serverctrlsp, int freeit); @@ -140,19 +141,21 @@ internal abstract int ldap_start_tls_s(SafeHandle ld, ref int serverReturnValue, internal abstract int ber_peek_tag(SafeHandle berElement, ref int length); internal abstract int ber_scanf_ptr(SafeHandle berElement, string format, ref IntPtr value); - internal abstract int ber_scanf_ostring(SafeHandle berElement, string format, IntPtr value); + internal abstract int ber_scanf_ostring(SafeHandle berElement, string format, ref IntPtr value); - internal abstract int ber_scanf_string(SafeHandle berElement, string format, IntPtr value, ref int length); + internal abstract int ber_scanf_string(SafeHandle berElement, string format, ref IntPtr value, ref int length); internal abstract int ber_scanf_bitstring(SafeHandle berElement, string format, ref IntPtr value, ref int length); internal abstract int ber_bvfree(IntPtr value); internal abstract int ber_bvecfree(IntPtr value); - internal abstract IntPtr ber_free([In] IntPtr berelement, int option); + internal abstract IntPtr ber_free(IntPtr berelement, int option); internal abstract void ber_memfree(IntPtr value); internal abstract bool BerScanfSupports(char fmt); + + internal abstract void BerScanfFree(char fmt, IntPtr ptr); internal void ThrowIfError(int res, string method, IDictionary details = default) { diff --git a/LdapForNet/Native/LdapNativeLinux.cs b/LdapForNet/Native/LdapNativeLinux.cs index c45de5e..2df14f3 100644 --- a/LdapForNet/Native/LdapNativeLinux.cs +++ b/LdapForNet/Native/LdapNativeLinux.cs @@ -167,6 +167,7 @@ internal override async Task BindSaslAsync(SafeHandle ld, Native.LdapAut } ldap_msgfree(result); + result = IntPtr.Zero; if (ldap_result(ld, msgid, 0, timeout, ref result) == Native.LdapResultType.LDAP_ERROR) { @@ -355,8 +356,26 @@ internal override int Compare(SafeHandle ld, string dn, string attr, string valu IntPtr serverctrls, IntPtr clientctrls, ref int msgidp) { - var ptr = bvalue == IntPtr.Zero && value != null ? StringToBerVal(value) : bvalue; - return NativeMethodsLinux.ldap_compare_ext(ld, dn, attr, ptr, serverctrls, clientctrls, ref msgidp); + bool freeBuffer; + + if (bvalue == IntPtr.Zero && value != null) + { + bvalue = StringToBerVal(value); + freeBuffer = true; + } + else + { + freeBuffer = false; + } + + var result = NativeMethodsLinux.ldap_compare_ext(ld, dn, attr, bvalue, serverctrls, clientctrls, ref msgidp); + + if (freeBuffer) + { + Marshal.FreeHGlobal(bvalue); + } + + return result; } private static IntPtr StringToBerVal(string value) @@ -441,14 +460,14 @@ internal override int ber_scanf_int(SafeHandle berElement, string format, ref in internal override int ber_scanf_ptr(SafeHandle berElement, string format, ref IntPtr value) => NativeMethodsLinux.ber_scanf_ptr(berElement, format, ref value); - internal override int ber_scanf_ostring(SafeHandle berElement, string format, IntPtr value) => - NativeMethodsLinux.ber_scanf_ostring(berElement, format, value); + internal override int ber_scanf_ostring(SafeHandle berElement, string format, ref IntPtr value) => + NativeMethodsLinux.ber_scanf_ostring(berElement, format, ref value); internal override int ber_scanf_bitstring(SafeHandle berElement, string format, ref IntPtr value, ref int length) => NativeMethodsLinux.ber_scanf_bitstring(berElement, format, ref value, ref length); - internal override int ber_scanf_string(SafeHandle berElement, string format, IntPtr value, ref int length) - => NativeMethodsLinux.ber_scanf_string(berElement, format, value, ref length); + internal override int ber_scanf_string(SafeHandle berElement, string format, ref IntPtr value, ref int length) + => NativeMethodsLinux.ber_scanf_string(berElement, format, ref value, ref length); internal override int ber_peek_tag(SafeHandle berElement, ref int length) => NativeMethodsLinux.ber_peek_tag(berElement, ref length); internal override int ber_bvfree(IntPtr value) @@ -460,6 +479,43 @@ internal override int ber_bvecfree(IntPtr value) internal override IntPtr ber_free(IntPtr berelem, int option) => NativeMethodsLinux.ber_free(berelem, option); + internal override void BerScanfFree(char fmt, IntPtr ptr) + { + switch (fmt) + { + case 'a': + case 'A': + case 'o': + case 'M': + NativeMethodsLinux.ber_memfree(ptr); + break; + + case 'O': + NativeMethodsLinux.ber_bvfree(ptr); + break; + + case 'v': + foreach (var itemPtr in MarshalUtils.GetPointerArray(ptr)) + { + if (itemPtr != IntPtr.Zero) + { + NativeMethodsLinux.ber_memvfree(ptr); + } + } + + NativeMethodsLinux.ber_memvfree(ptr); + break; + + case 'V': + NativeMethodsLinux.ber_bvecfree(ptr); + break; + + case 'W': + NativeMethodsLinux.ber_bvarray_free(ptr); + break; + } + } + internal override void ber_memfree(IntPtr value) => NativeMethodsLinux.ber_memfree(value); internal override bool BerScanfSupports(char fmt) => true; } diff --git a/LdapForNet/Native/LdapNativeOsx.cs b/LdapForNet/Native/LdapNativeOsx.cs index df5731a..b32b0ca 100644 --- a/LdapForNet/Native/LdapNativeOsx.cs +++ b/LdapForNet/Native/LdapNativeOsx.cs @@ -362,11 +362,11 @@ internal override int ber_scanf_int(SafeHandle berElement, string format, ref in internal override int ber_scanf_ptr(SafeHandle berElement, string format, ref IntPtr value) => NativeMethodsOsx.ber_scanf_ptr(berElement, format, ref value); - internal override int ber_scanf_ostring(SafeHandle berElement, string format, IntPtr value) => - NativeMethodsOsx.ber_scanf_ostring(berElement, format, value); + internal override int ber_scanf_ostring(SafeHandle berElement, string format, ref IntPtr value) => + NativeMethodsOsx.ber_scanf_ostring(berElement, format, ref value); - internal override int ber_scanf_string(SafeHandle berElement, string format, IntPtr value, ref int length) - => NativeMethodsOsx.ber_scanf_string(berElement, format, value, ref length); + internal override int ber_scanf_string(SafeHandle berElement, string format, ref IntPtr value, ref int length) + => NativeMethodsOsx.ber_scanf_string(berElement, format, ref value, ref length); internal override void ber_memfree(IntPtr value) => NativeMethodsOsx.ber_memfree(value); @@ -383,6 +383,43 @@ internal override IntPtr ber_free(IntPtr berelem, int option) => NativeMethodsOsx.ber_free(berelem, option); internal override bool BerScanfSupports(char fmt) => true; + internal override void BerScanfFree(char fmt, IntPtr ptr) + { + switch (fmt) + { + case 'a': + case 'A': + case 'o': + case 'M': + NativeMethodsOsx.ber_memfree(ptr); + break; + + case 'O': + NativeMethodsOsx.ber_bvfree(ptr); + break; + + case 'v': + foreach (var itemPtr in MarshalUtils.GetPointerArray(ptr)) + { + if (itemPtr != IntPtr.Zero) + { + NativeMethodsOsx.ber_memvfree(ptr); + } + } + + NativeMethodsOsx.ber_memvfree(ptr); + break; + + case 'V': + NativeMethodsOsx.ber_bvecfree(ptr); + break; + + case 'W': + NativeMethodsOsx.ber_bvarray_free(ptr); + break; + } + } + private Native.LdapSaslDefaults GetSaslDefaults(SafeHandle ld, string mech) { var defaults = new Native.LdapSaslDefaults {mech = mech}; diff --git a/LdapForNet/Native/LdapNativeWindows.cs b/LdapForNet/Native/LdapNativeWindows.cs index 28bfd5a..afe35b5 100644 --- a/LdapForNet/Native/LdapNativeWindows.cs +++ b/LdapForNet/Native/LdapNativeWindows.cs @@ -273,8 +273,8 @@ internal override int ldap_rename(SafeHandle ld, string dn, string newrdn, strin serverctrls, clientctrls, ref msgidp); } - internal override int ldap_parse_extended_result(SafeHandle ldapHandle, IntPtr result, ref IntPtr oid, ref IntPtr data, byte freeIt) => - NativeMethodsWindows.ldap_parse_extended_result(ldapHandle, result, ref oid, ref data, freeIt); + internal override int ldap_parse_extended_result(SafeHandle ldapHandle, IntPtr result, ref IntPtr oid, ref IntPtr data, byte freeIt) => + NativeMethodsWindows.ldap_parse_extended_result(ldapHandle, result, ref oid, ref data, freeIt); internal override void ldap_controls_free(IntPtr ctrls) => NativeMethodsWindows.ldap_controls_free(ctrls); internal override int ldap_control_free(IntPtr control) => NativeMethodsWindows.ldap_control_free(control); @@ -302,7 +302,7 @@ internal override IntPtr ber_init(IntPtr value) => NativeMethodsWindows.ber_init(value); internal override int ber_scanf(SafeHandle berElement, string format) - => NativeMethodsWindows.ber_scanf(berElement,format); + => NativeMethodsWindows.ber_scanf(berElement, format); internal override int ber_scanf_int(SafeHandle berElement, string format, ref int value) => NativeMethodsWindows.ber_scanf_int(berElement, format, ref value); @@ -312,16 +312,16 @@ internal override int ber_scanf_int(SafeHandle berElement, string format, ref in internal override int ber_scanf_ptr(SafeHandle berElement, string format, ref IntPtr value) => NativeMethodsWindows.ber_scanf_ptr(berElement, format, ref value); - internal override int ber_scanf_ostring(SafeHandle berElement, string format, IntPtr value) - => NativeMethodsWindows.ber_scanf_ostring(berElement, format, value); + internal override int ber_scanf_ostring(SafeHandle berElement, string format, ref IntPtr value) + => NativeMethodsWindows.ber_scanf_ostring(berElement, format, ref value); internal override int ber_scanf_bitstring(SafeHandle berElement, string format, ref IntPtr value, ref int length) => NativeMethodsWindows.ber_scanf_bitstring(berElement, format, ref value, ref length); - internal override int ber_scanf_string(SafeHandle berElement, string format, IntPtr value, ref int length) - => NativeMethodsWindows.ber_scanf_string(berElement, format, value, ref length); + internal override int ber_scanf_string(SafeHandle berElement, string format, ref IntPtr value, ref int length) + => NativeMethodsWindows.ber_scanf_string(berElement, format, ref value, ref length); + - internal override int ber_bvfree(IntPtr value) => NativeMethodsWindows.ber_bvfree(value); @@ -334,9 +334,40 @@ internal override IntPtr ber_free(IntPtr berelem, int option) internal override void ber_memfree(IntPtr value) => NativeMethodsWindows.ldap_memfree(value); - internal override bool BerScanfSupports(char fmt) => + internal override bool BerScanfSupports(char fmt) => _supportedFormats.Contains(fmt); + internal override void BerScanfFree(char fmt, IntPtr ptr) + { + switch (fmt) + { + case 'a': + case 'B': + NativeMethodsWindows.ldap_memfree(ptr); + break; + + case 'O': + NativeMethodsWindows.ber_bvfree(ptr); + break; + + case 'v': + foreach (var itemPtr in MarshalUtils.GetPointerArray(ptr)) + { + if (itemPtr != IntPtr.Zero) + { + NativeMethodsWindows.ldap_memfree(ptr); + } + } + + NativeMethodsWindows.ldap_memfree(ptr); + break; + + case 'V': + NativeMethodsWindows.ber_bvecfree(ptr); + break; + } + } + internal override int ldap_start_tls_s(SafeHandle ld, ref int serverReturnValue, ref IntPtr message, IntPtr serverctrls, IntPtr clientctrls) { diff --git a/LdapForNet/Native/NativeMethodsLinux.cs b/LdapForNet/Native/NativeMethodsLinux.cs index c6ef13b..1203371 100644 --- a/LdapForNet/Native/NativeMethodsLinux.cs +++ b/LdapForNet/Native/NativeMethodsLinux.cs @@ -328,7 +328,7 @@ internal static extern int ber_scanf_bitstring(SafeHandle berElement, string for ref int length); [DllImport(LIB_LBER_PATH, EntryPoint = "ber_scanf")] - internal static extern int ber_scanf_ostring(SafeHandle berElement, string format, IntPtr value); + internal static extern int ber_scanf_ostring(SafeHandle berElement, string format, ref IntPtr value); [DllImport(LIB_LBER_PATH)] internal static extern int ber_bvfree(IntPtr value); @@ -336,14 +336,20 @@ internal static extern int ber_scanf_bitstring(SafeHandle berElement, string for [DllImport(LIB_LBER_PATH)] internal static extern int ber_bvecfree(IntPtr value); + [DllImport(LIB_LBER_PATH)] + internal static extern int ber_bvarray_free(IntPtr value); + [DllImport(LIB_LBER_PATH)] internal static extern IntPtr ber_free(IntPtr berelement, int option); [DllImport(LIB_LBER_PATH)] internal static extern void ber_memfree(IntPtr value); + [DllImport(LIB_LBER_PATH)] + internal static extern void ber_memvfree(IntPtr value); + [DllImport(LIB_LBER_PATH, EntryPoint = "ber_scanf")] - internal static extern int ber_scanf_string(SafeHandle berElement, string format, IntPtr value, ref int length); + internal static extern int ber_scanf_string(SafeHandle berElement, string format, ref IntPtr value, ref int length); [DllImport(LIB_LBER_PATH)] internal static extern int ber_peek_tag(SafeHandle berElement, ref int length); diff --git a/LdapForNet/Native/NativeMethodsOsx.cs b/LdapForNet/Native/NativeMethodsOsx.cs index a17b783..1452a91 100644 --- a/LdapForNet/Native/NativeMethodsOsx.cs +++ b/LdapForNet/Native/NativeMethodsOsx.cs @@ -301,17 +301,21 @@ internal static extern int ber_printf_bytearray(SafeHandle berElement, string fo [DllImport(LIB_LBER_PATH,EntryPoint = "ber_scanf")] internal static extern int ber_scanf_bitstring(SafeHandle berElement, string format, ref IntPtr value, ref int length); [DllImport(LIB_LBER_PATH, EntryPoint = "ber_scanf")] - internal static extern int ber_scanf_ostring(SafeHandle berElement, string format, IntPtr value); + internal static extern int ber_scanf_ostring(SafeHandle berElement, string format, ref IntPtr value); [DllImport(LIB_LBER_PATH)] internal static extern int ber_bvfree(IntPtr value); [DllImport(LIB_LBER_PATH)] internal static extern int ber_bvecfree(IntPtr value); [DllImport(LIB_LBER_PATH)] + internal static extern int ber_bvarray_free(IntPtr value); + [DllImport(LIB_LBER_PATH)] internal static extern IntPtr ber_free(IntPtr berelement, int option); [DllImport(LIB_LBER_PATH)] internal static extern void ber_memfree(IntPtr value); + [DllImport(LIB_LBER_PATH)] + internal static extern void ber_memvfree(IntPtr value); [DllImport(LIB_LBER_PATH,EntryPoint = "ber_scanf")] - internal static extern int ber_scanf_string(SafeHandle berElement, string format, IntPtr value, ref int length); + internal static extern int ber_scanf_string(SafeHandle berElement, string format, ref IntPtr value, ref int length); [DllImport(LIB_LBER_PATH)] internal static extern int ber_peek_tag(SafeHandle berElement, ref int length); [DllImport(LIB_LDAP_PATH)] diff --git a/LdapForNet/Native/NativeMethodsWindows.cs b/LdapForNet/Native/NativeMethodsWindows.cs index 96ee072..d506259 100644 --- a/LdapForNet/Native/NativeMethodsWindows.cs +++ b/LdapForNet/Native/NativeMethodsWindows.cs @@ -335,7 +335,7 @@ internal static string GetAdditionalErrorInfo(SafeHandle ld) [DllImport(LIB_LDAP_PATH, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)] internal static extern int ber_scanf_bitstring(SafeHandle berElement, string format, ref IntPtr value, ref int length); [DllImport(LIB_LDAP_PATH, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)] - internal static extern int ber_scanf_ostring(SafeHandle berElement, string format, IntPtr value); + internal static extern int ber_scanf_ostring(SafeHandle berElement, string format, ref IntPtr value); [DllImport(LIB_LDAP_PATH, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_bvfree", CharSet = CharSet.Unicode)] internal static extern int ber_bvfree(IntPtr value); @@ -354,7 +354,7 @@ internal static extern int ldap_create_sort_control(SafeHandle handle, IntPtr ke ref IntPtr control); [DllImport(LIB_LDAP_PATH, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)] - internal static extern int ber_scanf_string(SafeHandle berElement, string format, IntPtr value, ref int length); + internal static extern int ber_scanf_string(SafeHandle berElement, string format, ref IntPtr value, ref int length); [DllImport(LIB_LDAP_PATH, CallingConvention = CallingConvention.Cdecl)] internal static extern int ber_peek_tag(SafeHandle berElement, ref int length); [DllImport(LIB_LDAP_PATH, CallingConvention = CallingConvention.Cdecl)] diff --git a/LdapForNet/RequestHandlers/SearchRequestHandler.cs b/LdapForNet/RequestHandlers/SearchRequestHandler.cs index 4aa2caa..193b208 100644 --- a/LdapForNet/RequestHandlers/SearchRequestHandler.cs +++ b/LdapForNet/RequestHandlers/SearchRequestHandler.cs @@ -46,20 +46,10 @@ public override LdapResultCompleteStatus Handle(SafeHandle handle, Native.Native switch (resType) { case LdapForNet.Native.Native.LdapResultType.LDAP_RES_SEARCH_ENTRY: - var ber = Marshal.AllocHGlobal(IntPtr.Size); - try - { - var directoryEntries = GetLdapEntries(handle, msg, ber).ToList(); - _response.Entries.AddRange(directoryEntries); - - OnPartialResult(_response.MessageId, directoryEntries); - } - finally - { - Marshal.FreeHGlobal(ber); - Native.ldap_msgfree(msg); - } - + + var directoryEntries = GetLdapEntries(handle, msg).ToList(); + _response.Entries.AddRange(directoryEntries); + OnPartialResult(_response.MessageId, directoryEntries); resultStatus = LdapResultCompleteStatus.Partial; break; @@ -101,7 +91,7 @@ private void OnPartialResult(int messageId, List directoryEntrie } - private IEnumerable GetLdapEntries(SafeHandle ld, IntPtr msg, IntPtr ber) + private IEnumerable GetLdapEntries(SafeHandle ld, IntPtr msg) { for (var entry = Native.ldap_first_entry(ld, msg); entry != IntPtr.Zero; entry = Native.ldap_next_entry(ld, entry)) @@ -109,35 +99,46 @@ private IEnumerable GetLdapEntries(SafeHandle ld, IntPtr msg, In yield return new DirectoryEntry { Dn = GetLdapDn(ld, entry), - Attributes = GetLdapAttributes(ld, entry, ref ber) + Attributes = GetLdapAttributes(ld, entry) }; } } - private SearchResultAttributeCollection GetLdapAttributes(SafeHandle ld, IntPtr entry, ref IntPtr ber) + private SearchResultAttributeCollection GetLdapAttributes(SafeHandle ld, IntPtr entry) { var attributes = new SearchResultAttributeCollection(); - for (var attr = Native.ldap_first_attribute(ld, entry, ref ber); - attr != IntPtr.Zero; - attr = Native.ldap_next_attribute(ld, entry, ber)) + var ber = IntPtr.Zero; + try { - var vals = Native.ldap_get_values_len(ld, entry, attr); - if (vals != IntPtr.Zero) + for (var attr = Native.ldap_first_attribute(ld, entry, ref ber); + attr != IntPtr.Zero; + attr = Native.ldap_next_attribute(ld, entry, ber)) { - var attrName = Encoder.Instance.PtrToString(attr); - if (attrName != null) + var vals = Native.ldap_get_values_len(ld, entry, attr); + if (vals != IntPtr.Zero) { - var directoryAttribute = new DirectoryAttribute + var attrName = Encoder.Instance.PtrToString(attr); + if (attrName != null) { - Name = attrName - }; - directoryAttribute.AddValues(MarshalUtils.BerValArrayToByteArrays(vals)); - attributes.Add(directoryAttribute); + var directoryAttribute = new DirectoryAttribute + { + Name = attrName + }; + directoryAttribute.AddValues(MarshalUtils.BerValArrayToByteArrays(vals)); + attributes.Add(directoryAttribute); + } + Native.ldap_value_free_len(vals); } - Native.ldap_value_free_len(vals); + + Native.ldap_memfree(attr); + } + } + finally + { + if (ber != IntPtr.Zero) + { + Native.ber_free(ber, 0); } - - Native.ldap_memfree(attr); } return attributes;