Index: nslcd/pam.c =================================================================== --- nslcd/pam.c (revision 1166) +++ nslcd/pam.c (working copy) @@ -44,21 +44,29 @@ /* set up a connection and try to bind with the specified DN and password returns a NSLCD_PAM_* error code */ -static int try_bind(const char *userdn,const char *password) +static int try_bind(const char *userdn,const char *un,const char *password) { MYLDAP_SESSION *session; char *username; - int rc; + int rc=LDAP_SUCCESS; + MYLDAP_ENTRY *e; /* set up a new connection */ session=myldap_create_session(); if (session==NULL) return NSLCD_PAM_AUTH_ERR; - /* set up credentials for the session */ - myldap_set_credentials(session,userdn,password); - /* perform search for own object (just to do any kind of search) */ - username=lookup_dn2uid(session,userdn,&rc); - if (username!=NULL) - free(username); + /* perform search for own object to end up on the correct server */ + e=uid2entry(session,un); + log_log(LOG_DEBUG,"uid2entry(\"%s\") returned %s",un,myldap_get_dn(e)); + /* rebind with the new username and password */ + if (rc==LDAP_SUCCESS) + rc=myldap_rebind(session,userdn,password); + /* perform another search to test whether we can retrieve ower own info */ + if (rc==LDAP_SUCCESS) + { + username=lookup_dn2uid(session,userdn,&rc); + if (username!=NULL) + free(username); + } /* close the session */ myldap_session_close(session); /* handle the results */ @@ -165,7 +173,7 @@ return -1; } /* try authentication */ - rc=try_bind(userdn,password); + rc=try_bind(userdn,username,password); if (rc==NSLCD_PAM_SUCCESS) log_log(LOG_DEBUG,"bind successful"); /* write response */ @@ -402,12 +410,13 @@ session=myldap_create_session(); if (session==NULL) return NSLCD_PAM_AUTH_ERR; - /* set up credentials for the session */ - myldap_set_credentials(session,binddn,oldpassword); - /* perform search for own object (just to do any kind of search) */ + /* perform search for own object to end up on correct server */ username=lookup_dn2uid(session,userdn,&rc); if (username!=NULL) free(username); + /* rebind with the new username and password */ + if (rc==LDAP_SUCCESS) + rc=myldap_rebind(session,userdn,oldpassword); /* perform actual password modification */ if (rc==LDAP_SUCCESS) { Index: nslcd/myldap.c =================================================================== --- nslcd/myldap.c (revision 1166) +++ nslcd/myldap.c (working copy) @@ -87,10 +87,6 @@ { /* the connection */ LDAP *ld; - /* the username to bind with */ - char binddn[256]; - /* the password to bind with if any */ - char bindpw[64]; /* timestamp of last activity */ time_t lastactivity; /* index into ldc_uris: currently connected LDAP uri */ @@ -272,8 +268,6 @@ } /* initialize the session */ session->ld=NULL; - session->binddn[0]='\0'; - session->bindpw[0]='\0'; session->lastactivity=0; session->current_uri=0; for (i=0;ildc_ssl_on==SSL_START_TLS) { @@ -391,22 +376,30 @@ errno=0; rc=ldap_start_tls_s(session->ld,NULL,NULL); if (rc!=LDAP_SUCCESS) - { log_log(LOG_WARNING,"ldap_start_tls_s() failed: %s%s%s (uri=\"%s\")", ldap_err2string(rc),(errno==0)?"":": ", (errno==0)?"":strerror(errno),uri); - return rc; - } } + return rc; +} #endif /* LDAP_OPT_X_TLS */ - /* check if the binddn and bindpw are overwritten in the session */ - if (session->binddn[0]!='\0') - { - /* do a simple bind */ - log_log(LOG_DEBUG,"ldap_simple_bind_s(\"%s\",%s) (uri=\"%s\")",session->binddn, - (session->bindpw[0]!='\0')?"\"***\"":"\"\"",uri); - return ldap_simple_bind_s(session->ld,session->binddn,session->bindpw); - } + +/* This function performs the authentication phase of opening a connection. + This returns an LDAP result code. The binddn */ +static int do_bind(MYLDAP_SESSION *session,const char *uri) +{ + int rc; +#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S +#ifndef HAVE_SASL_INTERACT_T + struct berval cred; +#endif /* not HAVE_SASL_INTERACT_T */ +#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ + /* see if we should use starttls */ +#ifdef LDAP_OPT_X_TLS + rc=do_starttls(session,uri); + if (rc!=LDAP_SUCCESS) + return rc; +#endif /* LDAP_OPT_X_TLS */ /* perform SASL bind if requested and available on platform */ #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S /* TODO: store this information in the session */ @@ -674,8 +667,7 @@ if (rc!=LDAP_SUCCESS) { /* log actual LDAP error code */ - log_log((session->binddn[0]=='\0')?LOG_WARNING:LOG_DEBUG, - "failed to bind to LDAP server %s: %s%s%s", + log_log(LOG_WARNING,"failed to bind to LDAP server %s: %s%s%s", nslcd_cfg->ldc_uris[session->current_uri].uri, ldap_err2string(rc),(errno==0)?"":": ", (errno==0)?"":strerror(errno)); @@ -696,15 +688,30 @@ return LDAP_SUCCESS; } -/* Set alternative credentials for the session. */ -void myldap_set_credentials(MYLDAP_SESSION *session,const char *dn, - const char *password) +/* Re-bind to the server with the given credentials. This always does a + simple bind, regardless of the normal authentication method. This returns + an LDAP status code. */ +int myldap_rebind(MYLDAP_SESSION *session,const char *binddn,const char *bindpw) { - /* copy dn and password into session */ - strncpy(session->binddn,dn,sizeof(session->binddn)); - session->binddn[sizeof(session->binddn)-1]='\0'; - strncpy(session->bindpw,password,sizeof(session->bindpw)); - session->bindpw[sizeof(session->bindpw)-1]='\0'; + int rc; + /* check parameters */ + if (!is_valid_session(session)||(binddn==NULL)||(bindpw==NULL)) + { + log_log(LOG_ERR,"myldap_rebind(): invalid parameter passed"); + return LDAP_OPERATIONS_ERROR; + } + /* get the current URI */ + + + /* do a simple bind */ + log_log(LOG_DEBUG,"ldap_simple_bind_s(\"%s\",%s)",binddn, + (bindpw[0]!='\0')?"\"***\"":"\"\""); + rc=ldap_simple_bind_s(session->ld,binddn,bindpw); + if (rc!=LDAP_SUCCESS) + log_log(LOG_DEBUG,"failed to bind to LDAP server: %s%s%s", + ldap_err2string(rc),(errno==0)?"":": ", + (errno==0)?"":strerror(errno)); + return rc; } static int do_try_search(MYLDAP_SEARCH *search) @@ -867,13 +874,10 @@ /* update time of failure and figure out when we should retry */ pthread_mutex_lock(&uris_mutex); t=time(NULL); - /* update timestaps unless we are doing an authentication search */ - if (search->session->binddn[0]=='\0') - { - if (current_uri->firstfail==0) - current_uri->firstfail=t; - current_uri->lastfail=t; - } + /* update timestaps */ + if (current_uri->firstfail==0) + current_uri->firstfail=t; + current_uri->lastfail=t; /* if it is one of these, retrying this URI is not going to help */ if ((rc==LDAP_INVALID_CREDENTIALS)||(rc==LDAP_INSUFFICIENT_ACCESS)|| (rc==LDAP_AUTH_METHOD_NOT_SUPPORTED)) @@ -896,8 +900,7 @@ /* see if it is any use sleeping */ if (nexttry>=endtime) { - if (search->session->binddn[0]=='\0') - log_log(LOG_ERR,"no available LDAP server found"); + log_log(LOG_ERR,"no available LDAP server found"); return rc; } /* sleep between tries */ Index: nslcd/myldap.h =================================================================== --- nslcd/myldap.h (revision 1166) +++ nslcd/myldap.h (working copy) @@ -68,9 +68,10 @@ uses the configuration to find the URLs to attempt connections to. */ MUST_USE MYLDAP_SESSION *myldap_create_session(void); -/* Set alternative credentials for the session. */ -void myldap_set_credentials(MYLDAP_SESSION *session,const char *dn, - const char *password); +/* Re-bind to the server with the given credentials. This always does a + simple bind, regardless of the normal authentication method. This returns + an LDAP status code. */ +int myldap_rebind(MYLDAP_SESSION *session,const char *binddn,const char *bindpw); /* Closes all pending searches and deallocates any memory that is allocated with these searches. This does not close the session. */