Blob Blame History Raw
autofs-5.1.1 - fix sasl connection concurrancy problem

From: Ian Kent <raven@themaw.net>

After using the contributed Cyrus SASL code in autofs for years I've
finally looked at the Cyrus SASL C API RFC only to find that the
library isn't thread safe unless a connection context per thread is
used, similar to the LDAP library.

To be fair this code originated prior to the threaded version of
autofs so it's my bad I didn't check.

But having seen this I have no choice but to make the sasl context
per thread not per autofs lookup context.

Also extend the mutual exclusion even further.

Signed-off-by: Ian Kent <raven@themaw.net>
---
 CHANGELOG             |    1 
 include/lookup_ldap.h |   16 ++--
 modules/cyrus-sasl.c  |   46 ++++++-----
 modules/lookup_ldap.c |  198 +++++++++++++++++++++++++-------------------------
 4 files changed, 136 insertions(+), 125 deletions(-)

--- autofs-5.0.7.orig/CHANGELOG
+++ autofs-5.0.7/CHANGELOG
@@ -197,6 +197,7 @@
 - fix update_hosts_mounts() return.
 - change lookup to use reinit instead of reopen.
 - fix unbind sasl external mech.
+- fix sasl connection concurrancy problem.
 
 25/07/2012 autofs-5.0.7
 =======================
--- autofs-5.0.7.orig/include/lookup_ldap.h
+++ autofs-5.0.7/include/lookup_ldap.h
@@ -34,6 +34,13 @@ struct ldap_searchdn {
 	struct ldap_searchdn *next;
 };
 
+struct ldap_conn {
+	LDAP *ldap;
+#ifdef WITH_SASL
+	sasl_conn_t *sasl_conn;
+#endif
+};
+
 struct lookup_context {
 	char *mapname;
 	unsigned int format;
@@ -86,7 +93,6 @@ struct lookup_context {
 	/* Kerberos */
 	krb5_context krb5ctxt;
 	krb5_ccache  krb5_ccache;
-	sasl_conn_t  *sasl_conn;
 	/* SASL external */
 	char	     *extern_cert;
 	char	     *extern_key;
@@ -113,16 +119,16 @@ struct lookup_context {
 
 /* lookup_ldap.c */
 LDAP *init_ldap_connection(unsigned logopt, const char *uri, struct lookup_context *ctxt);
-int unbind_ldap_connection(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt);
+int unbind_ldap_connection(unsigned logopt, struct ldap_conn *conn, struct lookup_context *ctxt);
 int authtype_requires_creds(const char *authtype);
 
 #ifdef WITH_SASL
 /* cyrus-sasl.c */
 int autofs_sasl_client_init(unsigned logopt);
 int autofs_sasl_init(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt);
-int autofs_sasl_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt);
-void autofs_sasl_unbind(LDAP *ldap, struct lookup_context *ctxt);
-void autofs_sasl_dispose(LDAP *ldap, struct lookup_context *ctxt);
+int autofs_sasl_bind(unsigned logopt, struct ldap_conn *conn, struct lookup_context *ctxt);
+void autofs_sasl_unbind(struct ldap_conn *conn, struct lookup_context *ctxt);
+void autofs_sasl_dispose(struct ldap_conn *conn, struct lookup_context *ctxt);
 void autofs_sasl_done(void);
 /* cyrus-sasl-extern */
 int do_sasl_extern(LDAP *ldap, struct lookup_context *ctxt);
--- autofs-5.0.7.orig/modules/cyrus-sasl.c
+++ autofs-5.0.7/modules/cyrus-sasl.c
@@ -855,16 +855,19 @@ sasl_choose_mech(unsigned logopt, LDAP *
  *  Routine called when unbinding an ldap connection.
  */
 void
-autofs_sasl_unbind(LDAP *ldap, struct lookup_context *ctxt)
+autofs_sasl_unbind(struct ldap_conn *conn, struct lookup_context *ctxt)
 {
 	if (ctxt->sasl_mech && !strncmp(ctxt->sasl_mech, "EXTERNAL", 8)) {
-		ldap_unbind_s(ldap);
+		if (conn->ldap) {
+			ldap_unbind_s(conn->ldap);
+			conn->ldap = NULL;
+		}
 		return;
 	}
 
-	if (ctxt->sasl_conn) {
-		sasl_dispose(&ctxt->sasl_conn);
-		ctxt->sasl_conn = NULL;
+	if (conn->sasl_conn) {
+		sasl_dispose(&conn->sasl_conn);
+		conn->sasl_conn = NULL;
 	}
 }
 
@@ -878,13 +881,10 @@ autofs_sasl_unbind(LDAP *ldap, struct lo
  * -1  -  Failure
  */
 int
-autofs_sasl_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+autofs_sasl_bind(unsigned logopt,
+		 struct ldap_conn *conn, struct lookup_context *ctxt)
 {
-	sasl_conn_t *conn = NULL;
-
-	/* If we already have a connection use it */
-	if (ctxt->sasl_conn)
-		return 0;
+	sasl_conn_t *sasl_conn = NULL;
 
 	if (ctxt->sasl_mech && !strncmp(ctxt->sasl_mech, "EXTERNAL", 8)) {
 		int result;
@@ -893,7 +893,7 @@ autofs_sasl_bind(unsigned logopt, LDAP *
 		      "Attempting sasl bind with mechanism %s",
 		      ctxt->sasl_mech);
 
-		result = do_sasl_extern(ldap, ctxt);
+		result = do_sasl_extern(conn->ldap, ctxt);
 		if (result)
 			debug(logopt,
 			      "Failed to authenticate with mech %s",
@@ -923,14 +923,16 @@ autofs_sasl_bind(unsigned logopt, LDAP *
 	 *  auth mechanism.
 	 */
 	if (ctxt->sasl_mech)
-		conn = sasl_bind_mech(logopt, ldap, ctxt, ctxt->sasl_mech);
+		sasl_conn = sasl_bind_mech(logopt,
+					   conn->ldap, ctxt, ctxt->sasl_mech);
 	else
-		conn = sasl_choose_mech(logopt, ldap, ctxt);
+		sasl_conn = sasl_choose_mech(logopt, conn->ldap, ctxt);
 
 	if (!conn)
 		return -1;
 
-	ctxt->sasl_conn = conn;
+	conn->sasl_conn = sasl_conn;
+
 	return 0;
 }
 
@@ -938,19 +940,21 @@ autofs_sasl_bind(unsigned logopt, LDAP *
  *  Destructor routine.  This should be called when finished with an ldap
  *  session.
  */
-void autofs_sasl_dispose(LDAP *ldap, struct lookup_context *ctxt)
+void autofs_sasl_dispose(struct ldap_conn *conn, struct lookup_context *ctxt)
 {
 	int status, ret;
 
 	if (ctxt->sasl_mech && !strncmp(ctxt->sasl_mech, "EXTERNAL", 8)) {
-		if (ldap)
-			ldap_unbind_s(ldap);
+		if (conn && conn->ldap) {
+			ldap_unbind_s(conn->ldap);
+			conn->ldap = NULL;
+		}
 		return;
 	}
 
-	if (ctxt->sasl_conn) {
-		sasl_dispose(&ctxt->sasl_conn);
-		ctxt->sasl_conn = NULL;
+	if (conn && conn->sasl_conn) {
+		sasl_dispose(&conn->sasl_conn);
+		conn->sasl_conn = NULL;
 	}
 
 	if (ctxt->kinit_successful) {
--- autofs-5.0.7.orig/modules/lookup_ldap.c
+++ autofs-5.0.7/modules/lookup_ldap.c
@@ -214,7 +214,9 @@ int bind_ldap_simple(unsigned logopt, LD
 	return 0;
 }
 
-int __unbind_ldap_connection(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+int __unbind_ldap_connection(unsigned logopt,
+			     struct ldap_conn *conn,
+			     struct lookup_context *ctxt)
 {
 	int rv = LDAP_SUCCESS;
 
@@ -222,30 +224,35 @@ int __unbind_ldap_connection(unsigned lo
 		ctxt->use_tls = LDAP_TLS_INIT;
 #ifdef WITH_SASL
 	if (ctxt->auth_required & LDAP_NEED_AUTH)
-		autofs_sasl_unbind(ldap, ctxt);
-	else
-		rv = ldap_unbind_ext(ldap, NULL, NULL);
-#else
-	rv = ldap_unbind_ext(ldap, NULL, NULL);
+		autofs_sasl_unbind(conn, ctxt);
+	/* No, sasl_dispose does not release the ldap connection
+	 * unless it's using sasl EXTERNAL
+	 */
 #endif
+	if (conn->ldap) {
+		rv = ldap_unbind_ext(conn->ldap, NULL, NULL);
+		conn->ldap = NULL;
+	}
 	if (rv != LDAP_SUCCESS)
 		error(logopt, "unbind failed: %s", ldap_err2string(rv));
 
 	return rv;
 }
 
-int unbind_ldap_connection(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+int unbind_ldap_connection(unsigned logopt,
+			   struct ldap_conn *conn,
+			   struct lookup_context *ctxt)
 {
 	int rv;
 
 	ldapinit_mutex_lock();
-	rv = __unbind_ldap_connection(logopt, ldap, ctxt);
+	rv = __unbind_ldap_connection(logopt, conn, ctxt);
 	ldapinit_mutex_unlock();
 
 	return rv;
 }
 
-LDAP *__init_ldap_connection(unsigned logopt, const char *uri, struct lookup_context *ctxt)
+LDAP *init_ldap_connection(unsigned logopt, const char *uri, struct lookup_context *ctxt)
 {
 	LDAP *ldap = NULL;
 	struct timeval timeout     = { ctxt->timeout, 0 };
@@ -313,7 +320,7 @@ LDAP *__init_ldap_connection(unsigned lo
 				return NULL;
 			}
 			ctxt->use_tls = LDAP_TLS_DONT_USE;
-			ldap = __init_ldap_connection(logopt, uri, ctxt);
+			ldap = init_ldap_connection(logopt, uri, ctxt);
 			if (ldap)
 				ctxt->use_tls = LDAP_TLS_INIT;
 			return ldap;
@@ -324,17 +331,6 @@ LDAP *__init_ldap_connection(unsigned lo
 	return ldap;
 }
 
-LDAP *init_ldap_connection(unsigned logopt, const char *uri, struct lookup_context *ctxt)
-{
-	LDAP *ldap;
-
-	ldapinit_mutex_lock();
-	ldap = __init_ldap_connection(logopt, uri, ctxt);
-	ldapinit_mutex_unlock();
-
-	return ldap;
-}
-
 static int get_query_dn(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
 {
 	char buf[MAX_ERR_BUF];
@@ -574,33 +570,32 @@ static int find_query_dn(unsigned logopt
 	return 0;
 }
 
-static int do_bind(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_context *ctxt)
+static int do_bind(unsigned logopt, struct ldap_conn *conn,
+		   const char *uri, struct lookup_context *ctxt)
 {
 	char *host = NULL, *nhost;
 	int rv;
 
-	ldapinit_mutex_lock();
 #ifdef WITH_SASL
 	debug(logopt, MODPREFIX "auth_required: %d, sasl_mech %s",
 	      ctxt->auth_required, ctxt->sasl_mech);
 
 	if (ctxt->auth_required & LDAP_NEED_AUTH) {
-		rv = autofs_sasl_bind(logopt, ldap, ctxt);
+		rv = autofs_sasl_bind(logopt, conn, ctxt);
 		debug(logopt, MODPREFIX "autofs_sasl_bind returned %d", rv);
 	} else {
-		rv = bind_ldap_simple(logopt, ldap, uri, ctxt);
+		rv = bind_ldap_simple(logopt, conn->ldap, uri, ctxt);
 		debug(logopt, MODPREFIX "ldap simple bind returned %d", rv);
 	}
 #else
-	rv = bind_ldap_simple(logopt, ldap, uri, ctxt);
+	rv = bind_ldap_simple(logopt, conn->ldap, uri, ctxt);
 	debug(logopt, MODPREFIX "ldap simple bind returned %d", rv);
 #endif
-	ldapinit_mutex_unlock();
 
 	if (rv != 0)
 		return 0;
 
-	rv = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host);
+	rv = ldap_get_option(conn->ldap, LDAP_OPT_HOST_NAME, &host);
         if (rv != LDAP_SUCCESS || !host) {
 		debug(logopt, "failed to get hostname for connection");
 		return 0;
@@ -634,15 +629,12 @@ static int do_bind(unsigned logopt, LDAP
 	return 1;
 }
 
-static int do_connect(unsigned logopt, LDAP **ldap,
+static int do_connect(unsigned logopt, struct ldap_conn *conn,
 		      const char *uri, struct lookup_context *ctxt)
 {
 	char *cur_host = NULL;
-	LDAP *handle;
 	int ret = NSS_STATUS_SUCCESS;
 
-	*ldap = NULL;
-
 #ifdef WITH_SASL
 	if (ctxt->extern_cert && ctxt->extern_key) {
 		set_env(logopt, ENV_LDAPTLS_CERT, ctxt->extern_cert);
@@ -650,8 +642,8 @@ static int do_connect(unsigned logopt, L
 	}
 #endif
 
-	handle = init_ldap_connection(logopt, uri, ctxt);
-	if (!handle) {
+	conn->ldap = init_ldap_connection(logopt, uri, ctxt);
+	if (!conn->ldap) {
 		ret = NSS_STATUS_UNAVAIL;
 		goto out;
 	}
@@ -661,8 +653,8 @@ static int do_connect(unsigned logopt, L
 		cur_host = ctxt->cur_host;
 	uris_mutex_unlock(ctxt);
 
-	if (!do_bind(logopt, handle, uri, ctxt)) {
-		unbind_ldap_connection(logopt, handle, ctxt);
+	if (!do_bind(logopt, conn, uri, ctxt)) {
+		__unbind_ldap_connection(logopt, conn, ctxt);
 		ret = NSS_STATUS_UNAVAIL;
 		goto out;
 	}
@@ -673,7 +665,6 @@ static int do_connect(unsigned logopt, L
 	uris_mutex_lock(ctxt);
 	if (ctxt->schema && ctxt->qdn && (cur_host == ctxt->cur_host)) {
 		uris_mutex_unlock(ctxt);
-		*ldap = handle;
 		goto out;
 	}
 	uris_mutex_unlock(ctxt);
@@ -684,8 +675,8 @@ static int do_connect(unsigned logopt, L
 	 * base dn for searches.
 	 */
 	if (!ctxt->schema) {
-		if (!find_query_dn(logopt, handle, ctxt)) {
-			unbind_ldap_connection(logopt, handle, ctxt);
+		if (!find_query_dn(logopt, conn->ldap, ctxt)) {
+			__unbind_ldap_connection(logopt, conn, ctxt);
 			ret = NSS_STATUS_NOTFOUND;
 			warn(logopt,
 			      MODPREFIX "failed to find valid query dn");
@@ -694,21 +685,21 @@ static int do_connect(unsigned logopt, L
 	} else if (!(ctxt->format & MAP_FLAG_FORMAT_AMD)) {
 		const char *class = ctxt->schema->map_class;
 		const char *key = ctxt->schema->map_attr;
-		if (!get_query_dn(logopt, handle, ctxt, class, key)) {
-			unbind_ldap_connection(logopt, handle, ctxt);
+		if (!get_query_dn(logopt, conn->ldap, ctxt, class, key)) {
+			__unbind_ldap_connection(logopt, conn, ctxt);
 			ret = NSS_STATUS_NOTFOUND;
 			error(logopt, MODPREFIX "failed to get query dn");
 			goto out;
 		}
 	}
 
-	*ldap = handle;
 out:
 	return ret;
 }
 
 static unsigned long get_amd_timestamp(struct lookup_context *ctxt)
 {
+	struct ldap_conn conn;
 	LDAP *ldap;
 	LDAPMessage *result = NULL, *e;
 	char *query;
@@ -719,9 +710,11 @@ static unsigned long get_amd_timestamp(s
 	unsigned long timestamp = 0;
 	int rv, l, ql;
 
-	rv = do_connect(LOGOPT_ANY, &ldap, ctxt->server, ctxt);
+	memset(&conn, 0, sizeof(struct ldap_conn));
+	rv = do_connect(LOGOPT_ANY, &conn, ctxt->server, ctxt);
 	if (rv != NSS_STATUS_SUCCESS)
 		return 0;
+	ldap = conn.ldap;
 
 	map = amd_timestamp.map_attr;
 	class = amd_timestamp.entry_class;
@@ -758,7 +751,7 @@ static unsigned long get_amd_timestamp(s
 	rv = ldap_search_s(ldap, ctxt->base, scope, query, attrs, 0, &result);
 	if ((rv != LDAP_SUCCESS) || !result) {
 		crit(LOGOPT_ANY, MODPREFIX "timestamp query failed %s", query);
-		unbind_ldap_connection(LOGOPT_ANY, ldap, ctxt);
+		unbind_ldap_connection(LOGOPT_ANY, &conn, ctxt);
 		if (result)
 			ldap_msgfree(result);
 		free(query);
@@ -770,7 +763,7 @@ static unsigned long get_amd_timestamp(s
 		debug(LOGOPT_ANY,
 		     MODPREFIX "got answer, but no entry for timestamp");
 		ldap_msgfree(result);
-		unbind_ldap_connection(LOGOPT_ANY, ldap, ctxt);
+		unbind_ldap_connection(LOGOPT_ANY, &conn, ctxt);
 		free(query);
 		return CHE_MISSING;
 	}
@@ -821,18 +814,18 @@ next:
 	}
 
 	ldap_msgfree(result);
-	unbind_ldap_connection(LOGOPT_ANY, ldap, ctxt);
+	unbind_ldap_connection(LOGOPT_ANY, &conn, ctxt);
 	free(query);
 
 	return timestamp;
 }
 
-static int connect_to_server(unsigned logopt, LDAP **ldap,
+static int connect_to_server(unsigned logopt, struct ldap_conn *conn,
 			     const char *uri, struct lookup_context *ctxt)
 {
 	int ret;
 
-	ret = do_connect(logopt, ldap, uri, ctxt);
+	ret = do_connect(logopt, conn, uri, ctxt);
 	if (ret != NSS_STATUS_SUCCESS) {
 		warn(logopt,
 		     MODPREFIX "couldn't connect to server %s",
@@ -842,7 +835,7 @@ static int connect_to_server(unsigned lo
 	return ret;
 }
 
-static int find_dc_server(unsigned logopt, LDAP **ldap,
+static int find_dc_server(unsigned logopt, struct ldap_conn *conn,
 			  const char *uri, struct lookup_context *ctxt)
 {
 	char *str, *tok, *ptr = NULL;
@@ -858,7 +851,7 @@ static int find_dc_server(unsigned logop
 		int rv;
 
 		debug(logopt, "trying server uri %s", this);
-		rv = connect_to_server(logopt, ldap, this, ctxt);
+		rv = connect_to_server(logopt, conn, this, ctxt);
 		if (rv == NSS_STATUS_SUCCESS) {
 			info(logopt, "connected to uri %s", this);
 			free(str);
@@ -875,7 +868,7 @@ static int find_dc_server(unsigned logop
 }
 
 static int find_server(unsigned logopt,
-		       LDAP **ldap, struct lookup_context *ctxt)
+		       struct ldap_conn *conn, struct lookup_context *ctxt)
 {
 	struct ldap_uri *this = NULL;
 	struct list_head *p, *first;
@@ -906,7 +899,7 @@ static int find_server(unsigned logopt,
 		if (!strstr(this->uri, ":///")) {
 			uri = strdup(this->uri);
 			debug(logopt, "trying server uri %s", uri);
-			rv = connect_to_server(logopt, ldap, uri, ctxt);
+			rv = connect_to_server(logopt, conn, uri, ctxt);
 			if (rv == NSS_STATUS_SUCCESS) {
 				ret = NSS_STATUS_SUCCESS;
 				info(logopt, "connected to uri %s", uri);
@@ -928,7 +921,7 @@ static int find_server(unsigned logopt,
 				dclist = tmp;
 				uri = strdup(dclist->uri);
 			}
-			rv = find_dc_server(logopt, ldap, uri, ctxt);
+			rv = find_dc_server(logopt, conn, uri, ctxt);
 			if (rv == NSS_STATUS_SUCCESS) {
 				ret = NSS_STATUS_SUCCESS;
 				free(uri);
@@ -947,7 +940,7 @@ static int find_server(unsigned logopt,
 	}
 
 	uris_mutex_lock(ctxt);
-	if (ldap)
+	if (conn->ldap)
 		ctxt->uri = this;
 	if (dclist) {
 		if (!ctxt->dclist)
@@ -965,37 +958,39 @@ static int find_server(unsigned logopt,
 }
 
 static int do_reconnect(unsigned logopt,
-			LDAP **ldap, struct lookup_context *ctxt)
+			struct ldap_conn *conn, struct lookup_context *ctxt)
 {
 	int ret = NSS_STATUS_UNAVAIL;
 	int dcrv = NSS_STATUS_SUCCESS;
 	int rv = NSS_STATUS_SUCCESS;
 
+	ldapinit_mutex_lock();
 	if (ctxt->server || !ctxt->uris) {
-		ret = do_connect(logopt, ldap, ctxt->server, ctxt);
+		ret = do_connect(logopt, conn, ctxt->server, ctxt);
 #ifdef WITH_SASL
 		/* Dispose of the sasl authentication connection and try again. */
 		if (ctxt->auth_required & LDAP_NEED_AUTH &&
 		    ret != NSS_STATUS_SUCCESS && ret != NSS_STATUS_NOTFOUND) {
-			ldapinit_mutex_lock();
-			autofs_sasl_dispose(*ldap, ctxt);
-			ldapinit_mutex_unlock();
-			ret = connect_to_server(logopt, ldap,
+			autofs_sasl_dispose(conn, ctxt);
+			ret = connect_to_server(logopt, conn,
 						ctxt->server, ctxt);
 		}
 #endif
+		ldapinit_mutex_unlock();
 		return ret;
 	}
 
 	if (ctxt->dclist) {
-		dcrv = find_dc_server(logopt, ldap, ctxt->dclist->uri, ctxt);
-		if (dcrv == NSS_STATUS_SUCCESS)
+		dcrv = find_dc_server(logopt, conn, ctxt->dclist->uri, ctxt);
+		if (dcrv == NSS_STATUS_SUCCESS) {
+			ldapinit_mutex_unlock();
 			return dcrv;
+		}
 	}
 
 	uris_mutex_lock(ctxt);
 	if (ctxt->dclist) {
-		if (!ldap || ctxt->dclist->expire < time(NULL)) {
+		if (!conn->ldap || ctxt->dclist->expire < time(NULL)) {
 			free_dclist(ctxt->dclist);
 			ctxt->dclist = NULL;
 		}
@@ -1009,7 +1004,7 @@ static int do_reconnect(unsigned logopt,
 	if (!ctxt->uri)
 		goto find_server;
 
-	rv = do_connect(logopt, ldap, ctxt->uri->uri, ctxt);
+	rv = do_connect(logopt, conn, ctxt->uri->uri, ctxt);
 #ifdef WITH_SASL
 	/*
 	 * Dispose of the sasl authentication connection and try the
@@ -1017,26 +1012,24 @@ static int do_reconnect(unsigned logopt,
 	 */
 	if (ctxt->auth_required & LDAP_NEED_AUTH &&
 	    rv != NSS_STATUS_SUCCESS && rv != NSS_STATUS_NOTFOUND) {
-		ldapinit_mutex_lock();
-		autofs_sasl_dispose(*ldap, ctxt);
-		ldapinit_mutex_unlock();
-		rv = connect_to_server(logopt, ldap, ctxt->uri->uri, ctxt);
+		autofs_sasl_dispose(conn, ctxt);
+		rv = connect_to_server(logopt, conn, ctxt->uri->uri, ctxt);
 	}
 #endif
-	if (rv == NSS_STATUS_SUCCESS)
+	if (rv == NSS_STATUS_SUCCESS) {
+		ldapinit_mutex_unlock();
 		return rv;
+	}
 
 	/* Failed to connect, try to find a new server */
 
 find_server:
 #ifdef WITH_SASL
-	ldapinit_mutex_lock();
-	autofs_sasl_dispose(*ldap, ctxt);
-	ldapinit_mutex_unlock();
+	autofs_sasl_dispose(conn, ctxt);
 #endif
 
 	/* Current server failed, try the rest or dc connection */
-	ret = find_server(logopt, ldap, ctxt);
+	ret = find_server(logopt, conn, ctxt);
 	if (ret != NSS_STATUS_SUCCESS) {
 		if (ret == NSS_STATUS_NOTFOUND ||
 		    dcrv == NSS_STATUS_NOTFOUND ||
@@ -1044,6 +1037,7 @@ find_server:
 			ret = NSS_STATUS_NOTFOUND;
 		error(logopt, MODPREFIX "failed to find available server");
 	}
+	ldapinit_mutex_unlock();
 
 	return ret;
 }
@@ -1877,11 +1871,6 @@ int lookup_reinit(const char *mapfmt,
 
 	*context = new;
 
-#ifdef WITH_SASL
-	ldapinit_mutex_lock();
-	autofs_sasl_dispose(NULL, ctxt);
-	ldapinit_mutex_unlock();
-#endif
 	free_context(ctxt);
 
 	return 0;
@@ -1893,6 +1882,8 @@ int lookup_read_master(struct master *ma
 	unsigned int timeout = master->default_timeout;
 	unsigned int logging = master->default_logging;
 	unsigned int logopt = master->logopt;
+	struct ldap_conn conn;
+	LDAP *ldap;
 	int rv, l, count;
 	char buf[MAX_ERR_BUF];
 	char parse_buf[PARSE_MAX_BUF];
@@ -1903,12 +1894,13 @@ int lookup_read_master(struct master *ma
 	char **values = NULL;
 	char *attrs[3];
 	int scope = LDAP_SCOPE_SUBTREE;
-	LDAP *ldap = NULL;
 
 	/* Initialize the LDAP context. */
-	rv = do_reconnect(logopt, &ldap, ctxt);
+	memset(&conn, 0, sizeof(struct ldap_conn));
+	rv = do_reconnect(logopt, &conn, ctxt);
 	if (rv)
 		return rv;
+	ldap = conn.ldap;
 
 	class = ctxt->schema->entry_class;
 	entry = ctxt->schema->entry_attr;
@@ -1942,7 +1934,7 @@ int lookup_read_master(struct master *ma
 	if ((rv != LDAP_SUCCESS) || !result) {
 		error(logopt, MODPREFIX "query failed for %s: %s",
 		      query, ldap_err2string(rv));
-		unbind_ldap_connection(logging, ldap, ctxt);
+		unbind_ldap_connection(logging, &conn, ctxt);
 		if (result)
 			ldap_msgfree(result);
 		free(query);
@@ -1955,7 +1947,7 @@ int lookup_read_master(struct master *ma
 		      MODPREFIX "query succeeded, no matches for %s",
 		      query);
 		ldap_msgfree(result);
-		unbind_ldap_connection(logging, ldap, ctxt);
+		unbind_ldap_connection(logging, &conn, ctxt);
 		free(query);
 		return NSS_STATUS_NOTFOUND;
 	} else
@@ -2076,7 +2068,7 @@ next:
 
 	/* Clean up. */
 	ldap_msgfree(result);
-	unbind_ldap_connection(logopt, ldap, ctxt);
+	unbind_ldap_connection(logopt, &conn, ctxt);
 	free(query);
 
 	return NSS_STATUS_SUCCESS;
@@ -2796,6 +2788,7 @@ static int read_one_map(struct autofs_po
 			struct lookup_context *ctxt,
 			time_t age, int *result_ldap)
 {
+	struct ldap_conn conn;
 	struct ldap_search_params sp;
 	char buf[MAX_ERR_BUF];
 	char *class, *info, *entry;
@@ -2816,10 +2809,11 @@ static int read_one_map(struct autofs_po
 	sp.age = age;
 
 	/* Initialize the LDAP context. */
-	sp.ldap = NULL;
-	rv = do_reconnect(ap->logopt, &sp.ldap, ctxt);
+	memset(&conn, 0, sizeof(struct ldap_conn));
+	rv = do_reconnect(ap->logopt, &conn, ctxt);
 	if (rv)
 		return rv;
+	sp.ldap = conn.ldap;
 
 	class = ctxt->schema->entry_class;
 	entry = ctxt->schema->entry_attr;
@@ -2878,7 +2872,7 @@ static int read_one_map(struct autofs_po
 			if (sp.pageSize < 5) {
 				debug(ap->logopt, MODPREFIX
 				      "result size too small");
-				unbind_ldap_connection(ap->logopt, sp.ldap, ctxt);
+				unbind_ldap_connection(ap->logopt, &conn, ctxt);
 				*result_ldap = rv;
 				free(sp.query);
 				return NSS_STATUS_UNAVAIL;
@@ -2887,7 +2881,7 @@ static int read_one_map(struct autofs_po
 		}
 
 		if (rv != LDAP_SUCCESS || !sp.result) {
-			unbind_ldap_connection(ap->logopt, sp.ldap, ctxt);
+			unbind_ldap_connection(ap->logopt, &conn, ctxt);
 			*result_ldap = rv;
 			if (sp.result)
 				ldap_msgfree(sp.result);
@@ -2903,7 +2897,7 @@ static int read_one_map(struct autofs_po
 			rv = do_get_entries(&sp, source, ctxt);
 		if (rv != LDAP_SUCCESS) {
 			ldap_msgfree(sp.result);
-			unbind_ldap_connection(ap->logopt, sp.ldap, ctxt);
+			unbind_ldap_connection(ap->logopt, &conn, ctxt);
 			*result_ldap = rv;
 			if (sp.cookie)
 				ber_bvfree(sp.cookie);
@@ -2916,7 +2910,7 @@ static int read_one_map(struct autofs_po
 
 	debug(ap->logopt, MODPREFIX "done updating map");
 
-	unbind_ldap_connection(ap->logopt, sp.ldap, ctxt);
+	unbind_ldap_connection(ap->logopt, &conn, ctxt);
 
 	source->age = age;
 	if (sp.cookie)
@@ -2959,6 +2953,8 @@ static int lookup_one(struct autofs_poin
 		char *qKey, int qKey_len, struct lookup_context *ctxt)
 {
 	struct mapent_cache *mc;
+	struct ldap_conn conn;
+	LDAP *ldap;
 	int rv, i, l, ql, count;
 	char buf[MAX_ERR_BUF];
 	time_t age = time(NULL);
@@ -2971,7 +2967,6 @@ static int lookup_one(struct autofs_poin
 	struct berval **bvValues;
 	char *attrs[3];
 	int scope = LDAP_SCOPE_SUBTREE;
-	LDAP *ldap = NULL;
 	struct mapent *we;
 	unsigned int wild = 0;
 	int ret = CHE_MISSING;
@@ -2984,11 +2979,13 @@ static int lookup_one(struct autofs_poin
 	}
 
 	/* Initialize the LDAP context. */
-	rv = do_reconnect(ap->logopt, &ldap, ctxt);
+	memset(&conn, 0, sizeof(struct ldap_conn));
+	rv = do_reconnect(ap->logopt, &conn, ctxt);
 	if (rv == NSS_STATUS_UNAVAIL)
 		return CHE_UNAVAIL;
 	if (rv == NSS_STATUS_NOTFOUND)
 		return ret;
+	ldap = conn.ldap;
 
 	class = ctxt->schema->entry_class;
 	entry = ctxt->schema->entry_attr;
@@ -3076,7 +3073,7 @@ static int lookup_one(struct autofs_poin
 
 	if ((rv != LDAP_SUCCESS) || !result) {
 		crit(ap->logopt, MODPREFIX "query failed for %s", query);
-		unbind_ldap_connection(ap->logopt, ldap, ctxt);
+		unbind_ldap_connection(ap->logopt, &conn, ctxt);
 		if (result)
 			ldap_msgfree(result);
 		free(query);
@@ -3091,7 +3088,7 @@ static int lookup_one(struct autofs_poin
 		debug(ap->logopt,
 		     MODPREFIX "got answer, but no entry for %s", query);
 		ldap_msgfree(result);
-		unbind_ldap_connection(ap->logopt, ldap, ctxt);
+		unbind_ldap_connection(ap->logopt, &conn, ctxt);
 		free(query);
 		return CHE_MISSING;
 	}
@@ -3277,7 +3274,7 @@ next:
 	}
 
 	ldap_msgfree(result);
-	unbind_ldap_connection(ap->logopt, ldap, ctxt);
+	unbind_ldap_connection(ap->logopt, &conn, ctxt);
 
 	/* Failed to find wild entry, update cache if needed */
 	cache_writelock(mc);
@@ -3317,7 +3314,8 @@ static int lookup_one_amd(struct autofs_
 			  struct lookup_context *ctxt)
 {
 	struct mapent_cache *mc = source->mc;
-	LDAP *ldap = NULL;
+	struct ldap_conn conn;
+	LDAP *ldap;
 	LDAPMessage *result = NULL, *e;
 	char *query;
 	int scope = LDAP_SCOPE_SUBTREE;
@@ -3336,11 +3334,13 @@ static int lookup_one_amd(struct autofs_
 	}
 
 	/* Initialize the LDAP context. */
-	rv = do_reconnect(ap->logopt, &ldap, ctxt);
+	memset(&conn, 0, sizeof(struct ldap_conn));
+	rv = do_reconnect(ap->logopt, &conn, ctxt);
 	if (rv == NSS_STATUS_UNAVAIL)
 		return CHE_UNAVAIL;
 	if (rv == NSS_STATUS_NOTFOUND)
 		return ret;
+	ldap = conn.ldap;
 
 	map = ctxt->schema->map_attr;
 	class = ctxt->schema->entry_class;
@@ -3382,7 +3382,7 @@ static int lookup_one_amd(struct autofs_
 	rv = ldap_search_s(ldap, ctxt->base, scope, query, attrs, 0, &result);
 	if ((rv != LDAP_SUCCESS) || !result) {
 		crit(ap->logopt, MODPREFIX "query failed for %s", query);
-		unbind_ldap_connection(ap->logopt, ldap, ctxt);
+		unbind_ldap_connection(ap->logopt, &conn, ctxt);
 		if (result)
 			ldap_msgfree(result);
 		free(query);
@@ -3397,7 +3397,7 @@ static int lookup_one_amd(struct autofs_
 		debug(ap->logopt,
 		     MODPREFIX "got answer, but no entry for %s", query);
 		ldap_msgfree(result);
-		unbind_ldap_connection(ap->logopt, ldap, ctxt);
+		unbind_ldap_connection(ap->logopt, &conn, ctxt);
 		free(query);
 		return CHE_MISSING;
 	}
@@ -3459,7 +3459,7 @@ next:
 	}
 
 	ldap_msgfree(result);
-	unbind_ldap_connection(ap->logopt, ldap, ctxt);
+	unbind_ldap_connection(ap->logopt, &conn, ctxt);
 	free(query);
 
 	return ret;