I am currently using Mac OS X 10.6.2 and am attempting to use the ldap_sasl_interactive_bind_s API to do a digest-md5 authentication against Active Directory (2008, though I don't think it matters what flavor of AD is used). The bind works fine the first time. However, if I unbind and attempt to rebind as the same user, it fails with ldap_sasl_interactive_bind_s: Invalid credentials (49). If I bind with a different user, then unbind, and bind as the original user, it works. I created a simple program that illustrates the issue. When run, it binds correctly, unbinds, and then fails on the second bind after unbinding:

trying
ldap_sasl_interactive_bind_s
callback
callback done
ldap_sasl_interactive_bind_s Done
Unbinding
Unbound.
ldap_sasl_interactive_bind_s
callback
callback done
ldap_sasl_interactive_bind_s: Invalid credentials (49)
additional info: 80090308: LdapErr: DSID-0C0904D1, comment: AcceptSecurityContext error, data 57, v1772


Any idea why it is not possible to use the same credentials twice?

Here is the test program. I tried reinitializing the sasl library with sasl_done and sasl_client_init, but that doesn't seem to make a difference.

#include <ldap.h>
#include <sasl/sasl.h>
#include <stdio.h>

typedef struct sasl_defaults {
    char *mech;
    char *realm;
    char *authcid;
    char *passwd;
    char *authzid;
} sasl_defaults;

int callback(LDAP *ld, unsigned flags, void* defaults, void *interact ) {
    printf("callback\n");
    sasl_interact_t *in_out=(sasl_interact_t *)interact;
    sasl_defaults *in_defaults=(sasl_defaults *)defaults;

    while (in_out->id !=SASL_CB_LIST_END) {

        switch (in_out->id) {
            case SASL_CB_USER: 
in_out->result=in_defaults->authcid;
in_out->len=strlen(in_defaults->authcid); 
                break;
            case SASL_CB_AUTHNAME: 
in_out->result=in_defaults->authcid;
                in_out->len=strlen(in_defaults->authcid);    
                break;
            case SASL_CB_PASS:     
in_out->result=in_defaults->passwd;
                in_out->len=strlen(in_defaults->passwd);
                break;
            case SASL_CB_GETREALM:
in_out->result="";
                in_out->len=strlen("");
                break;

        }

        in_out++;
    }
    printf("callback done\n");
    return 0; 
}



int main (int argv, char ** argc) {
    
    printf("trying\n");
    for (;;) {
        LDAP *ld;

        ldap_initialize(&ld, "ldap://dc.ad.domain.com:389");

        ldap_set_option(ld,LDAP_OPT_REFERRALS,LDAP_OPT_OFF);    
        
         int version=3;
        ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
        int timelimit=5;
        if (ldap_set_option( ld, LDAP_OPT_TIMELIMIT, (void *) &timelimit ) != LDAP_OPT_SUCCESS )
        {
            printf("err\n");
            return -1;
        }
        
        sasl_defaults defaults;
        defaults.mech = "DIGEST-MD5";
        defaults.passwd="password";
        defaults.authcid="user";
        defaults.realm="realm.com";
        defaults.authzid="user";
        
        printf("ldap_sasl_interactive_bind_s\n");
        int rc=ldap_sasl_interactive_bind_s( ld, NULL,defaults.mech, NULL, NULL, LDAP_SASL_QUIET, callback, &defaults );

        if( rc != LDAP_SUCCESS ) {
                    
            ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
                ldap_unbind(ld);
            return -1;
        }
        printf("ldap_sasl_interactive_bind_s Done\n");

        printf("Unbinding\n");
        ldap_unbind(ld);
        printf("Unbound.\n");
        sleep(5);

    }
}