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

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