Blame SOURCES/autofs-5.1.1-fix-sasl-connection-concurrancy-problem.patch

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