Search code examples
c++visual-studioactive-directoryldap

Can not "ldap_bind_s" to AD in C++ (0x31 error code)


I'm trying to connect to AD in Windows Server 2008 according to these instructions from MSDN. Until calling ldap_bind_s all is ok, but then I got error with 0x31 code(The supplied credential is invalid).

Username and password are correct, I've checked for several times.

Using C++ MSVS 2015. Here is my code sample.

PWSTR host_name = L"ad.server.ip.address";

LDAP* pLdapConnection = NULL;
pLdapConnection = ldap_init(host_name, LDAP_PORT);

if (pLdapConnection == NULL)
{
    printf("ldap_init failed with 0x%x.\n", LdapGetLastError());
    ldap_unbind(pLdapConnection);
    return -1;
}
else
    printf("ldap_init succeeded \n");

ULONG version = LDAP_VERSION3;
ULONG lRtn = 0;

lRtn = ldap_set_option(
    pLdapConnection,          
    LDAP_OPT_PROTOCOL_VERSION, 
    (void*)&version);         

if (lRtn == LDAP_SUCCESS)
    printf("ldap version set to 3.0 \n");
else
{
    printf("SetOption Error:%0lX\n", lRtn);
    ldap_unbind(pLdapConnection);
    return hr;
}

lRtn = ldap_connect(pLdapConnection, NULL);

if (lRtn == LDAP_SUCCESS)
    printf("ldap_connect succeeded \n");
else
{
    printf("ldap_connect failed with 0x%lx.\n", lRtn);
    ldap_unbind(pLdapConnection);
    return -1;
}

PWSTR pMyDN = L"DC=ad,DC=domain,DC=name";
SEC_WINNT_AUTH_IDENTITY secIdent;

//[email protected]
unsigned short login[18] = { 'a', 'd', 'm', '@', 'a', 'd', '.', 'd', 'o', 'm', 'a', 'i', 'n', '.', 'n', 'a', 'm', 'e' }; //18
secIdent.User = login;
secIdent.UserLength = 18;

//mypassword
unsigned short password[10] = { 'm', 'y', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' }; //10
secIdent.Password = password;
secIdent.PasswordLength = 10;

//ad.domain.name
unsigned short domain[14] = { 'a', 'd', '.', 'd', 'o', 'm', 'a', 'i', 'n', '.', 'n', 'a', 'm', 'e' }; //14
secIdent.Domain = dmn;
secIdent.DomainLength = 14;
secIdent.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;

lRtn = ldap_bind_s(
    pLdapConnection,      // Session Handle
    pMyDN,                // Domain DN
    (PWCHAR)&secIdent,     // Credential structure
    LDAP_AUTH_NEGOTIATE); // Auth mode
if (lRtn == LDAP_SUCCESS)
{
    printf("ldap_bind_s succeeded \n");
    secIdent.Password = NULL; // Remove password pointer
    pPassword = NULL;         // Remove password pointer
}
else
{
    printf("ldap_bind_s failed with 0x%lx.\n", lRtn);
    ldap_unbind(pLdapConnection);
    return -1;
}

Console output:

ldap_init succeeded
ldap version set to 3.0
ldap_connect succeeded
ldap_bind_s failed with 0x31.
Cannot execute query. Cannot bind to LDAP

It seems to me that the error can be occured by encoding or domain name. But according to this answer, domain field in SEC_WINNT_AUTH_IDENTITYstructure is ignored. Also I tried to set secIdent.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; without any result.


UPD.

Below is PHP code snippet that performs successful connection to same AD Server

$this->c = ldap_connect("ad.server.ip.address");
ldap_set_option($this->c, LDAP_OPT_PROTOCOL_VERSION, 3);
$r = ldap_bind($this->c,'[email protected]','mypassword');

Solution

  • Just found a solution after watching this example

    I should use LDAP_AUTH_SIMPLE authentication method instead of LDAP_AUTH_NEGOTIATE in ldap_bind_s() or simply use ldap_simple_bind_s().

    Working code snippet

    PWSTR host_name = L"ad.server.ip.address";
    
    LDAP* pLdapConnection = NULL;
    pLdapConnection = ldap_init(host_name, LDAP_PORT);
    if (pLdapConnection == NULL)
    {
        printf("ldap_init failed with 0x%x.\n", LdapGetLastError());
        ldap_unbind(pLdapConnection);
        return -1;
    }
    else
        printf("ldap_init succeeded \n");
    
    ULONG version = LDAP_VERSION3;
    ULONG lRtn = 0;
    
    lRtn = ldap_set_option(
        pLdapConnection,           // Session handle
        LDAP_OPT_PROTOCOL_VERSION, // Option
        (void*)&version);         // Option value
    
    if (lRtn == LDAP_SUCCESS)
        printf("ldap version set to 3.0 \n");
    else
    {
        printf("SetOption Error:%0lX\n", lRtn);
        ldap_unbind(pLdapConnection);
        return 0;
    }
    
    
    lRtn = ldap_connect(pLdapConnection, NULL);
    
    if (lRtn == LDAP_SUCCESS)
        printf("ldap_connect succeeded \n");
    else
    {
        printf("ldap_connect failed with 0x%lx.\n", lRtn);
        ldap_unbind(pLdapConnection);
        return -1;
    }
    
    
    PWCHAR user_name = L"[email protected]";
    PWCHAR password = L"mypassword";
    
    lRtn = ldap_simple_bind_s(pLdapConnection, user_name, password);
    if (lRtn == LDAP_SUCCESS)
    {
        printf("ldap_simple_bind_s succeeded \n");
    }
    else
    {
        printf("ldap_simple_bind_s failed with 0x%lx.\n", lRtn);
        ldap_unbind(pLdapConnection);
        return -1;
    }