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

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