Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nslcd/myldap.c603
-rw-r--r--nslcd/myldap.h4
2 files changed, 296 insertions, 311 deletions
diff --git a/nslcd/myldap.c b/nslcd/myldap.c
index 77fab77..0c64b60 100644
--- a/nslcd/myldap.c
+++ b/nslcd/myldap.c
@@ -23,24 +23,28 @@
02110-1301 USA
*/
+/*
+ This library expects to use an LDAP library to provide the real
+ functionality and only provides a convenient wrapper.
+ Some pointers for more information on the LDAP API:
+ http://tools.ietf.org/id/draft-ietf-ldapext-ldap-c-api-05.txt
+ http://www.mozilla.org/directory/csdk-docs/function.htm
+ http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/dirserv1.htm
+ http://www.openldap.org/software/man.cgi?query=ldap
+*/
+
#include "config.h"
-#include <assert.h>
+#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
-#ifdef HAVE_STRINGS_H
#include <strings.h>
-#endif
-#include <stdio.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <time.h>
#include <sys/time.h>
+#include <time.h>
+#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/param.h>
#include <errno.h>
-#include <netinet/in.h>
#include <ldap.h>
#ifdef HAVE_LDAP_SSL_H
#include <ldap_ssl.h>
@@ -74,10 +78,8 @@
/* the maximum number of searches per session */
#define MAX_SEARCHES_IN_SESSION 4
-/*
- * convenient wrapper around pointer into global config list, and a
- * connection to an LDAP server.
- */
+/* This refers to a current LDAP session that contains the connection
+ information. */
struct ldap_session
{
/* the connection */
@@ -103,7 +105,7 @@ struct myldap_search
/* a pointer to the current result entry, used for
freeing resource allocated with that entry */
MYLDAP_ENTRY *entry;
- /* LDAP message id */
+ /* LDAP message id for the search, -1 indicates absense of an active search */
int msgid;
/* the last result that was returned by ldap_result() */
LDAPMessage *msg;
@@ -282,43 +284,7 @@ PURE static inline int is_valid_entry(MYLDAP_ENTRY *entry)
return (entry!=NULL)&&is_valid_search(entry->search)&&(entry->search->msg!=NULL);
}
-static enum nss_status do_map_error(int rc)
-{
- switch (rc)
- {
- case LDAP_SUCCESS:
- case LDAP_SIZELIMIT_EXCEEDED:
- case LDAP_TIMELIMIT_EXCEEDED:
- return NSS_STATUS_SUCCESS;
- break;
- case LDAP_NO_SUCH_ATTRIBUTE:
- case LDAP_UNDEFINED_TYPE:
- case LDAP_INAPPROPRIATE_MATCHING:
- case LDAP_CONSTRAINT_VIOLATION:
- case LDAP_TYPE_OR_VALUE_EXISTS:
- case LDAP_INVALID_SYNTAX:
- case LDAP_NO_SUCH_OBJECT:
- case LDAP_ALIAS_PROBLEM:
- case LDAP_INVALID_DN_SYNTAX:
- case LDAP_IS_LEAF:
- case LDAP_ALIAS_DEREF_PROBLEM:
- case LDAP_FILTER_ERROR:
- return NSS_STATUS_NOTFOUND;
- break;
- case LDAP_SERVER_DOWN:
- case LDAP_TIMEOUT:
- case LDAP_UNAVAILABLE:
- case LDAP_BUSY:
-#ifdef LDAP_CONNECT_ERROR
- case LDAP_CONNECT_ERROR:
-#endif /* LDAP_CONNECT_ERROR */
- case LDAP_LOCAL_ERROR:
- case LDAP_INVALID_CREDENTIALS:
- default:
- return NSS_STATUS_UNAVAIL;
- }
-}
-
+/* this is registered with ldap_sasl_interactive_bind_s() in do_bind() */
static int do_sasl_interact(LDAP UNUSED(*ld),unsigned UNUSED(flags),void *defaults,void *_interact)
{
char *authzid=(char *)defaults;
@@ -347,17 +313,25 @@ static int do_sasl_interact(LDAP UNUSED(*ld),unsigned UNUSED(flags),void *defaul
return LDAP_SUCCESS;
}
-/* this returns an LDAP result code */
+#define LDAP_SET_OPTION(ld,option,invalue) \
+ rc=ldap_set_option(ld,option,invalue); \
+ if (rc!=LDAP_SUCCESS) \
+ { \
+ log_log(LOG_ERR,"ldap_set_option("__STRING(option)") failed: %s",ldap_err2string(rc)); \
+ return rc; \
+ }
+
+/* This function performs the authentication phase of opening a connection.
+ This returns an LDAP result code. */
static int do_bind(MYLDAP_SESSION *session)
{
int rc;
char *binddn,*bindarg;
int usesasl;
- /*
- * If we're running as root, let us bind as a special
- * user, so we can fake shadow passwords.
- */
+ /* If we're running as root, let us bind as a special
+ user, so we can fake shadow passwords. */
/* TODO: store this information in the session */
+ /* FIXME: this is wrong, we should not do this!!!!!!! */
if ((geteuid()==0)&&(nslcd_cfg->ldc_rootbinddn!=NULL))
{
binddn=nslcd_cfg->ldc_rootbinddn;
@@ -385,12 +359,7 @@ static int do_bind(MYLDAP_SESSION *session)
log_log(LOG_DEBUG,"SASL bind as %s",binddn);
if (nslcd_cfg->ldc_sasl_secprops!=NULL)
{
- rc=ldap_set_option(session->ls_conn,LDAP_OPT_X_SASL_SECPROPS,(void *)nslcd_cfg->ldc_sasl_secprops);
- if (rc!=LDAP_SUCCESS)
- {
- log_log(LOG_ERR,"unable to set SASL security properties: %s",ldap_err2string(rc));
- return -1;
- }
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_X_SASL_SECPROPS,(void *)nslcd_cfg->ldc_sasl_secprops);
}
rc=ldap_sasl_interactive_bind_s(session->ls_conn,binddn,"GSSAPI",NULL,NULL,
LDAP_SASL_QUIET,
@@ -399,10 +368,8 @@ static int do_bind(MYLDAP_SESSION *session)
}
}
-/*
- * This function is called by the LDAP library when chasing referrals.
- * It is configured with the ldap_set_rebind_proc() below.
- */
+/* This function is called by the LDAP library when chasing referrals.
+ It is configured with the ldap_set_rebind_proc() below. */
static int do_rebind(LDAP *UNUSED(ld),LDAP_CONST char UNUSED(*url),
ber_tag_t UNUSED(request),
ber_int_t UNUSED(msgid),void *arg)
@@ -410,102 +377,95 @@ static int do_rebind(LDAP *UNUSED(ld),LDAP_CONST char UNUSED(*url),
return do_bind((MYLDAP_SESSION *)arg);
}
-/*
- * Close the global session, sending an unbind.
- * Closes connection to the LDAP server.
- */
-static void do_close(MYLDAP_SESSION *session)
-{
- log_log(LOG_DEBUG,"==> do_close");
- if (session->ls_conn!=NULL)
- ldap_unbind(session->ls_conn);
- session->ls_conn=NULL;
- log_log(LOG_DEBUG,"<== do_close");
-}
-
-static int do_ssl_options(void)
+/* This function sets a number of properties on the connection, based
+ what is configured in the configfile. This function returns an
+ LDAP status code. */
+static int do_set_options(MYLDAP_SESSION *session)
{
- /* TODO: save return value of ldap_set_option() and include it in the error message */
- /* rand file */
- if (nslcd_cfg->ldc_tls_randfile!=NULL)
+ int rc;
+ struct timeval tv;
+ int tls=LDAP_OPT_X_TLS_HARD;
+ /* turn on debugging */
+ if (nslcd_cfg->ldc_debug)
{
- if (ldap_set_option(NULL,LDAP_OPT_X_TLS_RANDOM_FILE,
- nslcd_cfg->ldc_tls_randfile)!=LDAP_SUCCESS)
+ rc=ber_set_option(NULL,LBER_OPT_DEBUG_LEVEL,&nslcd_cfg->ldc_debug);
+ if (rc!=LDAP_SUCCESS)
{
- log_log(LOG_ERR,"setting of LDAP_OPT_X_TLS_RANDOM_FILE failed");
- return LDAP_OPERATIONS_ERROR;
+ log_log(LOG_ERR,"ber_set_option(LBER_OPT_DEBUG_LEVEL) failed: %s",ldap_err2string(rc));
+ return rc;
}
+ LDAP_SET_OPTION(NULL,LDAP_OPT_DEBUG_LEVEL,&nslcd_cfg->ldc_debug);
}
- /* ca cert file */
- if (nslcd_cfg->ldc_tls_cacertfile!=NULL)
+ /* the rebind function that is called when chasing referrals, see
+ http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/ldap_set_rebind_proc.htm
+ http://www.openldap.org/software/man.cgi?query=ldap_set_rebind_proc&manpath=OpenLDAP+2.4-Release */
+ /* TODO: probably only set this if we should chase referrals */
+ rc=ldap_set_rebind_proc(session->ls_conn,do_rebind,session);
+ if (rc!=LDAP_SUCCESS)
{
- if (ldap_set_option(NULL,LDAP_OPT_X_TLS_CACERTFILE,
- nslcd_cfg->ldc_tls_cacertfile)!=LDAP_SUCCESS)
- {
- log_log(LOG_ERR,"setting of LDAP_OPT_X_TLS_CACERTFILE failed");
- return LDAP_OPERATIONS_ERROR;
- }
+ log_log(LOG_ERR,"ldap_set_rebind_proc() failed: %s",ldap_err2string(rc));
+ return rc;
}
- /* ca cert directory */
- if (nslcd_cfg->ldc_tls_cacertdir!=NULL)
+ /* set the protocol version to use */
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_PROTOCOL_VERSION,&nslcd_cfg->ldc_version);
+ /* set some other options */
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_DEREF,&nslcd_cfg->ldc_deref);
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_TIMELIMIT,&nslcd_cfg->ldc_timelimit);
+ tv.tv_sec=nslcd_cfg->ldc_bind_timelimit;
+ tv.tv_usec=0;
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_TIMEOUT,&tv);
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_NETWORK_TIMEOUT,&tv);
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_REFERRALS,nslcd_cfg->ldc_referrals?LDAP_OPT_ON:LDAP_OPT_OFF);
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_RESTART,nslcd_cfg->ldc_restart?LDAP_OPT_ON:LDAP_OPT_OFF);
+ /* if SSL is desired, then enable it */
+ if (nslcd_cfg->ldc_ssl_on==SSL_LDAPS)
{
- if (ldap_set_option(NULL,LDAP_OPT_X_TLS_CACERTDIR,
- nslcd_cfg->ldc_tls_cacertdir)!=LDAP_SUCCESS)
+ /* use tls */
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_X_TLS,&tls);
+ /* rand file */
+ if (nslcd_cfg->ldc_tls_randfile!=NULL)
{
- log_log(LOG_ERR,"setting of LDAP_OPT_X_TLS_CACERTDIR failed");
- return LDAP_OPERATIONS_ERROR;
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_X_TLS_RANDOM_FILE,nslcd_cfg->ldc_tls_randfile);
}
- }
- /* require cert? */
- if (nslcd_cfg->ldc_tls_checkpeer > -1)
- {
- if (ldap_set_option(NULL,LDAP_OPT_X_TLS_REQUIRE_CERT,
- &nslcd_cfg->ldc_tls_checkpeer)!=LDAP_SUCCESS)
+ /* ca cert file */
+ if (nslcd_cfg->ldc_tls_cacertfile!=NULL)
{
- log_log(LOG_ERR,"setting of LDAP_OPT_X_TLS_REQUIRE_CERT failed");
- return LDAP_OPERATIONS_ERROR;
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_X_TLS_CACERTFILE,nslcd_cfg->ldc_tls_cacertfile);
}
- }
- /* set cipher suite, certificate and private key: */
- if (nslcd_cfg->ldc_tls_ciphers != NULL)
- {
- if (ldap_set_option(NULL,LDAP_OPT_X_TLS_CIPHER_SUITE,
- nslcd_cfg->ldc_tls_ciphers)!=LDAP_SUCCESS)
+ /* ca cert directory */
+ if (nslcd_cfg->ldc_tls_cacertdir!=NULL)
{
- log_log(LOG_ERR,"setting of LDAP_OPT_X_TLS_CIPHER_SUITE failed");
- return LDAP_OPERATIONS_ERROR;
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_X_TLS_CACERTDIR,nslcd_cfg->ldc_tls_cacertdir);
}
- }
-
- if (nslcd_cfg->ldc_tls_cert != NULL)
- {
- if (ldap_set_option(NULL,LDAP_OPT_X_TLS_CERTFILE,
- nslcd_cfg->ldc_tls_cert)!=LDAP_SUCCESS)
+ /* require cert? */
+ if (nslcd_cfg->ldc_tls_checkpeer>-1)
{
- log_log(LOG_ERR,"setting of LDAP_OPT_X_TLS_CERTFILE failed");
- return LDAP_OPERATIONS_ERROR;
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_X_TLS_REQUIRE_CERT,&nslcd_cfg->ldc_tls_checkpeer);
}
- }
- if (nslcd_cfg->ldc_tls_key != NULL)
- {
- if (ldap_set_option(NULL,LDAP_OPT_X_TLS_KEYFILE,
- nslcd_cfg->ldc_tls_key)!=LDAP_SUCCESS)
+ /* set cipher suite, certificate and private key */
+ if (nslcd_cfg->ldc_tls_ciphers!=NULL)
+ {
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_X_TLS_CIPHER_SUITE,nslcd_cfg->ldc_tls_ciphers);
+ }
+ /* set certificate */
+ if (nslcd_cfg->ldc_tls_cert!=NULL)
+ {
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_X_TLS_CERTFILE,nslcd_cfg->ldc_tls_cert);
+ }
+ /* set up key */
+ if (nslcd_cfg->ldc_tls_key!=NULL)
{
- log_log(LOG_ERR,"setting of LDAP_OPT_X_TLS_KEYFILE failed");
- return LDAP_OPERATIONS_ERROR;
+ LDAP_SET_OPTION(session->ls_conn,LDAP_OPT_X_TLS_KEYFILE,nslcd_cfg->ldc_tls_key);
}
}
+ /* if nothing above failed, everything should be fine */
return LDAP_SUCCESS;
}
-/*
- * Opens connection to an LDAP server, sets all connection options
- * and binds to the server. This returns a simple (0/-1) status code.
- * TODO: this should return an LDAP error code
- */
+/* This opens connection to an LDAP server, sets all connection options
+ and binds to the server. This returns an LDAP status code. */
static int do_open(MYLDAP_SESSION *session)
{
- struct timeval tv;
int rc;
time_t current_time;
int sd=-1;
@@ -516,15 +476,14 @@ static int do_open(MYLDAP_SESSION *session)
if ((session->ls_timestamp+nslcd_cfg->ldc_idle_timelimit)<current_time)
{
log_log(LOG_DEBUG,"do_open(): idle_timelimit reached");
- do_close(session);
+ ldap_unbind(session->ls_conn);
+ session->ls_conn=NULL;
}
}
- /* if the connection is still there (ie. do_close() wasn't
+ /* if the connection is still there (ie. ldap_unbind() wasn't
called) then we can return the cached connection */
if (session->ls_conn!=NULL)
- {
- return 0;
- }
+ return LDAP_SUCCESS;
/* we should build a new session now */
session->ls_conn=NULL;
session->ls_timestamp=0;
@@ -535,51 +494,25 @@ static int do_open(MYLDAP_SESSION *session)
log_log(LOG_WARNING,"ldap_initialize(%s) failed: %s: %s",
nslcd_cfg->ldc_uris[session->ls_current_uri],
ldap_err2string(rc),strerror(errno));
- return -1;
+ if (session->ls_conn!=NULL)
+ {
+ ldap_unbind(session->ls_conn);
+ session->ls_conn=NULL;
+ }
+ return rc;
}
else if (session->ls_conn==NULL)
{
log_log(LOG_WARNING,"ldap_initialize() returned NULL");
- return -1;
+ return LDAP_LOCAL_ERROR;
}
- /* turn on debugging */
- if (nslcd_cfg->ldc_debug)
- {
- ber_set_option(NULL,LBER_OPT_DEBUG_LEVEL,&nslcd_cfg->ldc_debug);
- ldap_set_option(NULL,LDAP_OPT_DEBUG_LEVEL,&nslcd_cfg->ldc_debug);
- }
- /* the rebind function that is called when chasing referrals, see
- http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/ldap_set_rebind_proc.htm
- http://www.openldap.org/software/man.cgi?query=ldap_set_rebind_proc&manpath=OpenLDAP+2.4-Release */
- /* TODO: probably only set this if we should chase referrals */
- ldap_set_rebind_proc(session->ls_conn,do_rebind,session);
- /* set the protocol version to use */
- ldap_set_option(session->ls_conn,LDAP_OPT_PROTOCOL_VERSION,&nslcd_cfg->ldc_version);
- ldap_set_option(session->ls_conn,LDAP_OPT_DEREF,&nslcd_cfg->ldc_deref);
- ldap_set_option(session->ls_conn,LDAP_OPT_TIMELIMIT,&nslcd_cfg->ldc_timelimit);
- tv.tv_sec=nslcd_cfg->ldc_bind_timelimit;
- tv.tv_usec=0;
- ldap_set_option(session->ls_conn,LDAP_OPT_TIMEOUT,&tv);
- ldap_set_option(session->ls_conn,LDAP_OPT_NETWORK_TIMEOUT,&tv);
- ldap_set_option(session->ls_conn,LDAP_OPT_REFERRALS,nslcd_cfg->ldc_referrals?LDAP_OPT_ON:LDAP_OPT_OFF);
- ldap_set_option(session->ls_conn,LDAP_OPT_RESTART,nslcd_cfg->ldc_restart?LDAP_OPT_ON:LDAP_OPT_OFF);
- /* if SSL is desired, then enable it */
- if (nslcd_cfg->ldc_ssl_on==SSL_LDAPS)
+ /* set the options for the connection */
+ rc=do_set_options(session);
+ if (rc!=LDAP_SUCCESS)
{
- int tls=LDAP_OPT_X_TLS_HARD;
- if (ldap_set_option(session->ls_conn,LDAP_OPT_X_TLS,&tls)!=LDAP_SUCCESS)
- {
- do_close(session);
- log_log(LOG_DEBUG,"<== do_open(TLS setup failed)");
- return -1;
- }
- /* set up SSL context */
- if (do_ssl_options()!=LDAP_SUCCESS)
- {
- do_close(session);
- log_log(LOG_DEBUG,"<== do_open(SSL setup failed)");
- return -1;
- }
+ ldap_unbind(session->ls_conn);
+ session->ls_conn=NULL;
+ return rc;
}
/* bind to the server */
rc=do_bind(session);
@@ -589,34 +522,31 @@ static int do_open(MYLDAP_SESSION *session)
log_log(LOG_WARNING,"failed to bind to LDAP server %s: %s: %s",
nslcd_cfg->ldc_uris[session->ls_current_uri],
ldap_err2string(rc),strerror(errno));
- do_close(session);
- return -1;
+ ldap_unbind(session->ls_conn);
+ session->ls_conn=NULL;
+ return rc;
}
- /* disable keepalive on a LDAP connection socket */
+ /* disable keepalive on the LDAP connection socket */
if (ldap_get_option(session->ls_conn,LDAP_OPT_DESC,&sd)==0)
{
int off=0;
/* ignore errors */
(void)setsockopt(sd,SOL_SOCKET,SO_KEEPALIVE,(void *)&off,sizeof(off));
- (void)fcntl(sd,F_SETFD,FD_CLOEXEC);
}
/* update last activity and finish off state */
time(&(session->ls_timestamp));
log_log(LOG_DEBUG,"do_open(): connected to %s",nslcd_cfg->ldc_uris[session->ls_current_uri]);
- return 0;
+ return LDAP_SUCCESS;
}
-/*
- * Wrapper around ldap_result() to skip over search references
- * and deal transparently with the last entry.
- */
-static enum nss_status do_result(MYLDAP_SEARCH *search)
+/* Wrapper around ldap_result() to skip over search references and deal
+ transparently with the last entry. */
+static int do_result(MYLDAP_SEARCH *search)
{
- int rc=LDAP_UNAVAILABLE;
- enum nss_status stat=NSS_STATUS_TRYAGAIN;
+ int rc=LDAP_RES_SEARCH_REFERENCE;
struct timeval tv,*tvp;
int parserc;
- LDAPControl **resultControls;
+ LDAPControl **resultcontrols;
/* set up a timelimit value for operations */
if (nslcd_cfg->ldc_timelimit==LDAP_NO_LIMIT)
tvp=NULL;
@@ -626,10 +556,10 @@ static enum nss_status do_result(MYLDAP_SEARCH *search)
tv.tv_usec=0;
tvp=&tv;
}
- /* loop until we have something else than a LDAP_RES_SEARCH_REFERENCE */
- do
+ /* loop while we have search references */
+ while (rc==LDAP_RES_SEARCH_REFERENCE)
{
- /* free the previous message */
+ /* free the previous message if there was any */
if (search->msg!=NULL)
{
ldap_msgfree(search->msg);
@@ -637,105 +567,121 @@ static enum nss_status do_result(MYLDAP_SEARCH *search)
}
/* get the next result */
rc=ldap_result(search->session->ls_conn,search->msgid,LDAP_MSG_ONE,tvp,&(search->msg));
- switch (rc)
- {
- case -1:
- case 0:
- if (ldap_get_option(search->session->ls_conn,LDAP_OPT_ERROR_NUMBER,&rc)!=LDAP_SUCCESS)
- rc=LDAP_UNAVAILABLE;
- log_log(LOG_ERR,"could not get LDAP result: %s",ldap_err2string(rc));
- stat=NSS_STATUS_UNAVAIL;
- break;
- case LDAP_RES_SEARCH_ENTRY:
- /* update timestamp on success */
- time(&(search->session->ls_timestamp));
- stat=NSS_STATUS_SUCCESS;
- break;
- case LDAP_RES_SEARCH_RESULT:
- resultControls=NULL;
- if (search->cookie!=NULL)
- ber_bvfree(search->cookie);
+ }
+ /* handle result */
+ switch (rc)
+ {
+ case -1:
+ /* we have an error condition, try to get error code */
+ if (ldap_get_option(search->session->ls_conn,LDAP_OPT_ERROR_NUMBER,&rc)!=LDAP_SUCCESS)
+ rc=LDAP_UNAVAILABLE;
+ log_log(LOG_ERR,"ldap_result(): %s",ldap_err2string(rc));
+ return rc;
+ case 0:
+ /* the timeout expired */
+ log_log(LOG_ERR,"ldap_result() timed out");
+ return LDAP_TIMELIMIT_EXCEEDED;
+ case LDAP_RES_SEARCH_ENTRY:
+ /* we have a normal search entry, update timestamp and we're done */
+ time(&(search->session->ls_timestamp));
+ return LDAP_SUCCESS;
+ case LDAP_RES_SEARCH_RESULT:
+ /* we have a search result, parse it */
+ resultcontrols=NULL;
+ if (search->cookie!=NULL)
+ {
+ ber_bvfree(search->cookie);
search->cookie=NULL;
- /* NB: this frees search->msg */
- parserc=ldap_parse_result(search->session->ls_conn,search->msg,&rc,NULL,
- NULL,NULL,&resultControls,1);
- search->msg=NULL;
- if ((parserc!=LDAP_SUCCESS)&&(parserc!=LDAP_MORE_RESULTS_TO_RETURN))
- {
- stat = NSS_STATUS_UNAVAIL;
- ldap_abandon(search->session->ls_conn,search->msgid);
- log_log(LOG_ERR,"could not get LDAP result: %s",ldap_err2string(rc));
- }
- else if (resultControls!=NULL)
- {
- /* See if there are any more pages to come */
- parserc=ldap_parse_page_control(search->session->ls_conn,
- resultControls,NULL,
- &(search->cookie));
- /* TODO: handle the above return code?? */
- ldap_controls_free(resultControls);
- stat=NSS_STATUS_NOTFOUND;
- }
- else
- stat=NSS_STATUS_NOTFOUND;
- search->msgid=-1;
- break;
- default:
- stat = NSS_STATUS_UNAVAIL;
- break;
- }
+ }
+ /* NB: this frees search->msg */
+ parserc=ldap_parse_result(search->session->ls_conn,search->msg,&rc,NULL,
+ NULL,NULL,&resultcontrols,1);
+ search->msg=NULL;
+ /* check for errors during parsing */
+ if ((parserc!=LDAP_SUCCESS)&&(parserc!=LDAP_MORE_RESULTS_TO_RETURN))
+ {
+ if (resultcontrols!=NULL)
+ ldap_controls_free(resultcontrols);
+ ldap_abandon(search->session->ls_conn,search->msgid);
+ log_log(LOG_ERR,"could not parse LDAP result: %s",ldap_err2string(parserc));
+ return parserc;
+ }
+ /* check for errors in message */
+ if ((rc!=LDAP_SUCCESS)&&(rc!=LDAP_MORE_RESULTS_TO_RETURN))
+ {
+ if (resultcontrols!=NULL)
+ ldap_controls_free(resultcontrols);
+ ldap_abandon(search->session->ls_conn,search->msgid);
+ log_log(LOG_ERR,"could not get LDAP result: %s",ldap_err2string(rc));
+ return rc;
+ }
+ /* handle result controls */
+ if (resultcontrols!=NULL)
+ {
+ /* see if there are any more pages to come */
+ ldap_parse_page_control(search->session->ls_conn,
+ resultcontrols,NULL,
+ &(search->cookie));
+ /* TODO: handle the above return code?? */
+ ldap_controls_free(resultcontrols);
+ }
+ search->msgid=-1;
+ return LDAP_SUCCESS;
+ default:
+ log_log(LOG_WARNING,"ldap_result() returned unexpected result type");
+ return LDAP_LOCAL_ERROR;
}
- while (rc==LDAP_RES_SEARCH_REFERENCE);
- /* TODO: check which statement could actually return LDAP_RES_SEARCH_REFERENCE
- and try to get as much error handling code outside of the loop */
- return stat;
}
-static int do_search(MYLDAP_SEARCH *search,int *msgidp)
+/* TODO: this is only called from do_with_reconnect(), we should probably move it there */
+static enum nss_status do_map_error(int rc)
{
- int rc;
- LDAPControl *serverCtrls[2];
- LDAPControl **pServerCtrls;
- /* ensure that we have an open connection */
- if (do_open(search->session))
- return LDAP_SERVER_DOWN;
- /* if we're using paging, build a page control */
- if (nslcd_cfg->ldc_pagesize>0)
- {
- rc=ldap_create_page_control(search->session->ls_conn,nslcd_cfg->ldc_pagesize,
- NULL,0,&serverCtrls[0]);
- if (rc!=LDAP_SUCCESS)
- return rc;
- serverCtrls[1]=NULL;
- pServerCtrls=serverCtrls;
- }
- else
- pServerCtrls=NULL;
- /* perform the search */
- rc=ldap_search_ext(search->session->ls_conn,search->base,search->scope,
- search->filter,search->attrs,0,pServerCtrls,NULL,
- LDAP_NO_LIMIT,LDAP_NO_LIMIT,msgidp);
- /* free the controls if we had them */
- if (pServerCtrls!=NULL)
+ switch (rc)
{
- ldap_control_free(serverCtrls[0]);
- serverCtrls[0]=NULL;
+ case LDAP_SUCCESS:
+ case LDAP_SIZELIMIT_EXCEEDED:
+ case LDAP_TIMELIMIT_EXCEEDED:
+ return NSS_STATUS_SUCCESS;
+ break;
+ case LDAP_NO_SUCH_ATTRIBUTE:
+ case LDAP_UNDEFINED_TYPE:
+ case LDAP_INAPPROPRIATE_MATCHING:
+ case LDAP_CONSTRAINT_VIOLATION:
+ case LDAP_TYPE_OR_VALUE_EXISTS:
+ case LDAP_INVALID_SYNTAX:
+ case LDAP_NO_SUCH_OBJECT:
+ case LDAP_ALIAS_PROBLEM:
+ case LDAP_INVALID_DN_SYNTAX:
+ case LDAP_IS_LEAF:
+ case LDAP_ALIAS_DEREF_PROBLEM:
+ case LDAP_FILTER_ERROR:
+ return NSS_STATUS_NOTFOUND;
+ break;
+ case LDAP_SERVER_DOWN:
+ case LDAP_TIMEOUT:
+ case LDAP_UNAVAILABLE:
+ case LDAP_BUSY:
+#ifdef LDAP_CONNECT_ERROR
+ case LDAP_CONNECT_ERROR:
+#endif /* LDAP_CONNECT_ERROR */
+ case LDAP_LOCAL_ERROR:
+ case LDAP_INVALID_CREDENTIALS:
+ default:
+ return NSS_STATUS_UNAVAIL;
}
- return rc;
}
-/*
- * Function to call do_search() with reconnection logic (depending on
- * wheter res or msgid is not NULL).
- */
-static enum nss_status do_with_reconnect(
- MYLDAP_SEARCH *search)
+/* Perform a search with reconnection logic.
+ TODO: this is only called from myldap_search(), probably move the code there */
+static int do_with_reconnect(MYLDAP_SEARCH *search)
{
int rc=LDAP_UNAVAILABLE, tries=0, backoff=0;
int hard=1, start_uri=0, log=0;
enum nss_status stat=NSS_STATUS_UNAVAIL;
int msgid;
int maxtries;
+ LDAPControl *serverCtrls[2];
+ LDAPControl **pServerCtrls;
/* get the maximum number of tries */
maxtries=nslcd_cfg->ldc_reconnect_tries;
/* keep trying until we have success or a hard failure */
@@ -751,11 +697,39 @@ static enum nss_status do_with_reconnect(
log_log(LOG_INFO,"reconnecting to LDAP server (sleeping %d seconds)...",backoff);
(void)sleep(backoff);
}
- /* for each "try", attempt to connect to all configured URIs */
+ /* try each configured URL once */
start_uri=search->session->ls_current_uri;
do
{
- stat=do_map_error(do_search(search,&msgid));
+ /* ensure that we have an open connection */
+ rc=do_open(search->session);
+ if (rc==LDAP_SUCCESS)
+ {
+ /* if we're using paging, build a page control */
+ if (nslcd_cfg->ldc_pagesize>0)
+ {
+ rc=ldap_create_page_control(search->session->ls_conn,nslcd_cfg->ldc_pagesize,
+ NULL,0,&serverCtrls[0]);
+ if (rc!=LDAP_SUCCESS)
+ return rc;
+ serverCtrls[1]=NULL;
+ pServerCtrls=serverCtrls;
+ }
+ else
+ pServerCtrls=NULL;
+ /* perform the search */
+ rc=ldap_search_ext(search->session->ls_conn,
+ search->base,search->scope,search->filter,
+ search->attrs,0,pServerCtrls,NULL,NULL,
+ LDAP_NO_LIMIT,&msgid);
+ /* free the controls if we had them */
+ if (pServerCtrls!=NULL)
+ {
+ ldap_control_free(serverCtrls[0]);
+ serverCtrls[0]=NULL;
+ }
+ }
+ stat=do_map_error(rc);
/* if we got any feedback from the server, don't try any other URIs */
if (stat!=NSS_STATUS_UNAVAIL)
break;
@@ -770,26 +744,29 @@ static enum nss_status do_with_reconnect(
/* TODO: we should probably close in the loop above */
if (stat==NSS_STATUS_UNAVAIL)
{
- do_close(search->session);
+ /* close the connection */
+ if (search->session!=NULL)
+ {
+ ldap_unbind(search->session->ls_conn);
+ search->session->ls_conn=NULL;
+ }
/* If a soft reconnect policy is specified, then do not
- * try to reconnect to the LDAP server if it is down.
- */
+ try to reconnect to the LDAP server if it is down. */
if (nslcd_cfg->ldc_reconnect_pol == LP_RECONNECT_SOFT)
hard = 0;
++tries;
}
}
-
switch (stat)
{
case NSS_STATUS_UNAVAIL:
log_log(LOG_ERR,"could not search LDAP server - %s",ldap_err2string(rc));
- return NSS_STATUS_UNAVAIL;
+ return rc;
case NSS_STATUS_TRYAGAIN:
log_log(LOG_ERR,"could not %s %sconnect to LDAP server - %s",
hard?"hard":"soft", tries?"re":"",
ldap_err2string(rc));
- return NSS_STATUS_UNAVAIL;
+ return rc;
case NSS_STATUS_SUCCESS:
if (log)
{
@@ -805,11 +782,11 @@ static enum nss_status do_with_reconnect(
/* update the last activity on the connection */
time(&(search->session->ls_timestamp));
search->msgid=msgid;
- return NSS_STATUS_SUCCESS;
+ return LDAP_SUCCESS;
case NSS_STATUS_NOTFOUND:
case NSS_STATUS_RETURN:
default:
- return stat;
+ return rc;
}
}
@@ -876,7 +853,7 @@ MYLDAP_SEARCH *myldap_search(
/* allocate a new search entry */
search=myldap_search_new(session,base,scope,filter,attrs);
/* set up a new search */
- if (do_with_reconnect(search)!=NSS_STATUS_SUCCESS)
+ if (do_with_reconnect(search)!=LDAP_SUCCESS)
{
myldap_search_free(search);
return NULL;
@@ -900,9 +877,18 @@ void myldap_search_close(MYLDAP_SEARCH *search)
int i;
if (!is_valid_search(search))
return;
+ /* free any messages */
+ if (search->msg!=NULL)
+ {
+ ldap_msgfree(search->msg);
+ search->msg=NULL;
+ }
/* abandon the search if there were more results to fetch */
- if ((search->msgid>-1)&&(do_result(search)==NSS_STATUS_SUCCESS))
+ if (search->msgid!=-1)
+ {
ldap_abandon(search->session->ls_conn,search->msgid);
+ search->msgid=-1;
+ }
/* find the reference to this search in the session */
for (i=0;i<MAX_SEARCHES_IN_SESSION;i++)
{
@@ -915,13 +901,12 @@ void myldap_search_close(MYLDAP_SEARCH *search)
MYLDAP_ENTRY *myldap_get_entry(MYLDAP_SEARCH *search)
{
- enum nss_status stat=NSS_STATUS_SUCCESS;
int msgid;
int rc;
/* check parameters */
if (!is_valid_search(search))
{
- log_log(LOG_ERR,"myldap_get_entry(): invalid search entry passed");
+ log_log(LOG_ERR,"myldap_get_entry(): invalid search passed");
errno=EINVAL;
return NULL;
}
@@ -936,15 +921,16 @@ MYLDAP_ENTRY *myldap_get_entry(MYLDAP_SEARCH *search)
{
/* get an entry from the LDAP server, the result
is stored in context->ec_res */
- stat=do_result(search);
+ rc=do_result(search);
/* we we have an entry construct a search entry from it */
- if (stat==NSS_STATUS_SUCCESS)
+ if ((rc==LDAP_SUCCESS)&&(search->msg!=NULL))
{
/* we have a normal entry, return it */
search->entry=myldap_entry_new(search);
return search->entry;
}
- else if ( (stat==NSS_STATUS_NOTFOUND) &&
+ else if ( (rc==LDAP_SUCCESS) &&
+ (search->msgid==-1) &&
(search->cookie!=NULL) &&
(search->cookie->bv_len!=0) )
{
@@ -960,16 +946,16 @@ MYLDAP_ENTRY *myldap_get_entry(MYLDAP_SEARCH *search)
/* FIXME: figure out if we need to free something */
return NULL;
}
+ /* set up a new search for the next page */
rc=ldap_search_ext(search->session->ls_conn,
search->base,search->scope,search->filter,
- search->attrs,0,serverctrls,NULL,LDAP_NO_LIMIT,
+ search->attrs,0,serverctrls,NULL,NULL,
LDAP_NO_LIMIT,&msgid);
ldap_control_free(serverctrls[0]);
- if (msgid<0)
+ if (rc!=LDAP_SUCCESS)
{
log_log(LOG_WARNING,"myldap_get_entry(): ldap_search_ext() failed: %s",
ldap_err2string(rc));
- /* FIXME: figure out if we need to free something */
return NULL;
}
search->msgid=msgid;
@@ -977,18 +963,17 @@ MYLDAP_ENTRY *myldap_get_entry(MYLDAP_SEARCH *search)
}
else
{
- log_log(LOG_DEBUG,"myldap_get_entry(): do_result() returned error code");
- /* there was another problem, bail out */
+ /* there was another problem, bail out
+ (do_result() already logged an error if any)
+ most likely there were no more results */
return NULL;
}
}
}
-/*
- * Get the DN from the entry. This function only returns NULL (and sets
- * errno) if an incorrect entry is passed. If the DN value cannot be
- * retreived "unknown" is returned instead.
- */
+/* Get the DN from the entry. This function only returns NULL (and sets
+ errno) if an incorrect entry is passed. If the DN value cannot be
+ retreived "unknown" is returned instead. */
const char *myldap_get_dn(MYLDAP_ENTRY *entry)
{
int rc;
diff --git a/nslcd/myldap.h b/nslcd/myldap.h
index 83b97ba..a34111d 100644
--- a/nslcd/myldap.h
+++ b/nslcd/myldap.h
@@ -23,9 +23,9 @@
#ifndef _MYLDAP_H
#define _MYLDAP_H
-/* for size_t: */
+/* for size_t */
#include <stdlib.h>
-/* for LDAP_SCOPE_*: */
+/* for LDAP_SCOPE_* */
#include <ldap.h>
#include "compat/attrs.h"