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

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