异常调用CertFreeCertificateContext在回调期间使用PInvoke访问ldap功能
本文关键字:PInvoke 访问 ldap 功能 CertFreeCertificateContext 调用 回调 异常 | 更新日期: 2023-09-27 18:06:13
当调用CertFreeCertificateContext方法时运行下面的代码时,我正在获得访问违反异常。
我想这是因为pServerCert参数在LdapServerCertDelegate上被mash化的方式,但一直无法找到解决方案。
using System;
using System.Runtime.InteropServices;
namespace ldaptest
{
class Program
{
static void Main(string[] args)
{
new LdapAuthenticationProvider().AuthenticateUser("a.qas", "a", "administrator", "test123");
}
}
public class LdapAuthenticationProvider
{
public void AuthenticateUser(string server, string domain, string username, string password)
{
IntPtr ld = ldap_sslinit(server, LDAP_SSL_PORT, 1);
if (IntPtr.Zero == ld) throw new Exception("ldap_sslinit");
var version = new IntPtr(LDAP_VERSION3);
var ret = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, version);
if (ret != LDAP_SUCCESS) throw new Exception(string.Format("LDAP_OPT_PROTOCOL_VERSION 0x{0:X}", ret));
var ldapOn = new IntPtr(LDAP_OPT_ON);
ret = ldap_set_option(ld, LDAP_OPT_SSL, ldapOn);
if (ret != LDAP_SUCCESS) throw new Exception(string.Format("LDAP_OPT_SSL 0x{0:X}", ret));
// note the necessity to convert the delegate to a function pointer
var callback = new LdapServerCertDelegate(AcceptAnySslCertificate);
IntPtr pFn = Marshal.GetFunctionPointerForDelegate(callback);
ret = ldap_set_option(ld, LDAP_OPT_SERVER_CERTIFICATE, pFn);
if (ret != LDAP_SUCCESS) throw new Exception(string.Format("LDAP_OPT_SERVER_CERTIFICATE 0x{0:X}", ret));
var tv = new l_timeval();
ret = ldap_connect(ld, ref tv);
if (ret != LDAP_SUCCESS) throw new Exception(string.Format("ldap_connect 0x{0:X}", ret));
string login = string.Format(@"{0}'{1}", domain, username);
ret = ldap_bind_s(ld, login, password, LDAP_AUTH_SIMPLE); // triggers the callback
if (ret != LDAP_SUCCESS) throw new Exception(string.Format("ldap_bind_s 0x{0:X}", ret));
ldap_unbind_s(ld);
Console.WriteLine("Success");
Console.Read();
}
private delegate bool LdapServerCertDelegate(IntPtr connection, IntPtr pServerCert);
private bool AcceptAnySslCertificate(IntPtr connection, IntPtr pServerCert)
{
CertFreeCertificateContext(pServerCert); // << System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
return true;
}
#region crypt32.dll functions
[DllImport("crypt32.dll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CertFreeCertificateContext(IntPtr pCertContext);
#endregion
#region Winldap.h definitions
private const int LDAP_PORT = 389;
private const uint LDAP_SSL_PORT = 636;
private const int LDAP_VERSION3 = 3;
private const int LDAP_OPT_PROTOCOL_VERSION = 17;
private const int LDAP_OPT_SSL = 10;
private const int LDAP_OPT_ON = 1;
private const int LDAP_AUTH_SIMPLE = 128;
private const int LDAP_OPT_SERVER_CERTIFICATE = 129;
private const uint LDAP_SUCCESS = 0;
[StructLayoutAttribute(LayoutKind.Sequential)]
private struct l_timeval
{
private int tv_sec;
private int tv_usec;
}
#endregion
#region wldap32.dll functions
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_sslinit.asp?frame=true
[DllImport("wldap32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_sslinitW",
SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr ldap_sslinit(string hostName, uint portNumber, int secure);
[DllImport("wldap32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_set_optionW",
SetLastError = true, CharSet = CharSet.Unicode)]
private static extern uint ldap_set_option([In] IntPtr ldapHandle, int option, IntPtr invalue);
[DllImport("wldap32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_unbind_s",
SetLastError = true, CharSet = CharSet.Unicode)]
private static extern uint ldap_unbind_s([In] IntPtr ldapHandle);
[DllImport("wldap32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_connect",
SetLastError = true, CharSet = CharSet.Unicode)]
private static extern uint ldap_connect([In] IntPtr ld, [In] ref l_timeval timeout);
[DllImport("wldap32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_bind_sW",
SetLastError = true, CharSet = CharSet.Unicode)]
private static extern uint ldap_bind_s([In] IntPtr ld, string dn, string cred, uint method);
#endregion
}
}
最好的办法是避免使用PInvoke而使用c++/CLI。