Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 130701790bf2d95e902edf16031ff596 > files > 209

autofs-5.0.1-0.rc2.164.el5_8.src.rpm

autofs-5.0.3 - uris list locking fix

From: Ian Kent <raven@themaw.net>

Locking was inadvertantly ommitted ifor the uris list in the LDAP
module. The list doesn't need to change so we just need to keep
track of current server uri in the list and try to connect in
a round robin order. Alsoi, as it was, it's possible multiple
concurrent connection attempts may not be able to use the full
list of requested servers (if one was present).
---

 include/lookup_ldap.h |    4 +-
 modules/lookup_ldap.c |   97 ++++++++++++++++++++++++++++++++------------------
 2 files changed, 66 insertions(+), 35 deletions(-)


--- autofs-5.0.1.orig/include/lookup_ldap.h
+++ autofs-5.0.1/include/lookup_ldap.h
@@ -53,7 +53,9 @@ struct lookup_context {
  	 * sdns is the list of basdns to check, done in the order
  	 * given in configuration.
  	 */
-	struct list_head *uri;
+	pthread_mutex_t uris_mutex;
+	struct list_head *uris;
+	struct ldap_uri *uri;
 	char *cur_host;
 	struct ldap_searchdn *sdns;
 
--- autofs-5.0.1.orig/modules/lookup_ldap.c
+++ autofs-5.0.1/modules/lookup_ldap.c
@@ -51,7 +51,23 @@ static unsigned int common_schema_count 
 
 static LDAP *auth_init(unsigned logopt, const char *, struct lookup_context *);
 
-int bind_ldap_anonymous(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+static void uris_mutex_lock(struct lookup_context *ctxt)
+{
+	int status = pthread_mutex_lock(&ctxt->uris_mutex);
+	if (status)
+		fatal(status);
+	return;
+}
+
+static void uris_mutex_unlock(struct lookup_context *ctxt)
+{
+	int status = pthread_mutex_unlock(&ctxt->uris_mutex);
+	if (status)
+		fatal(status);
+	return;
+}
+
+int bind_ldap_anonymous(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_context *ctxt)
 {
 	int rv;
 
@@ -61,16 +77,14 @@ int bind_ldap_anonymous(unsigned logopt,
 		rv = ldap_simple_bind_s(ldap, NULL, NULL);
 
 	if (rv != LDAP_SUCCESS) {
-		if (!ctxt->uri) {
+		if (!ctxt->uris) {
 			crit(logopt, MODPREFIX
 			     "Unable to bind to the LDAP server: "
 			     "%s, error %s", ctxt->server ? "" : "(default)",
 			     ldap_err2string(rv));
 		} else {
-			struct ldap_uri *uri;
-			uri = list_entry(ctxt->uri->next, struct ldap_uri, list);
 			info(logopt, MODPREFIX "Unable to bind to the LDAP server: "
-			     "%s, error %s", uri->uri, ldap_err2string(rv));
+			     "%s, error %s", uri, ldap_err2string(rv));
 		}
 		return -1;
 	}
@@ -412,7 +426,7 @@ static int find_query_dn(unsigned logopt
 	return 0;
 }
 
-static int do_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+static int do_bind(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_context *ctxt)
 {
 	char *host = NULL, *nhost;
 	int rv, need_base = 1;
@@ -425,11 +439,11 @@ static int do_bind(unsigned logopt, LDAP
 		rv = autofs_sasl_bind(logopt, ldap, ctxt);
 		debug(logopt, MODPREFIX "autofs_sasl_bind returned %d", rv);
 	} else {
-		rv = bind_ldap_anonymous(logopt, ldap, ctxt);
+		rv = bind_ldap_anonymous(logopt, ldap, uri, ctxt);
 		debug(logopt, MODPREFIX "ldap anonymous bind returned %d", rv);
 	}
 #else
-	rv = bind_ldap_anonymous(logopt, ldap, ctxt);
+	rv = bind_ldap_anonymous(logopt, ldap, uri, ctxt);
 	debug(logopt, MODPREFIX "ldap anonymous bind returned %d", rv);
 #endif
 
@@ -498,7 +512,7 @@ static LDAP *do_connect(unsigned logopt,
 	if (!ldap)
 		return NULL;
 
-	if (!do_bind(logopt, ldap, ctxt)) {
+	if (!do_bind(logopt, ldap, uri, ctxt)) {
 		unbind_ldap_connection(logopt, ldap, ctxt);
 		return NULL;
 	}
@@ -526,7 +540,7 @@ static LDAP *connect_to_server(unsigned 
 			return NULL;
 		}
 
-		if (!do_bind(logopt, ldap, ctxt)) {
+		if (!do_bind(logopt, ldap, uri, ctxt)) {
 			unbind_ldap_connection(logopt, ldap, ctxt);
 			autofs_sasl_dispose(ctxt);
 			error(logopt, MODPREFIX "cannot bind to server");
@@ -552,31 +566,34 @@ static LDAP *find_server(unsigned logopt
 {
 	LDAP *ldap = NULL;
 	struct ldap_uri *this;
-	struct list_head *p;
-	LIST_HEAD(tmp);
+	struct list_head *p, *first;
 
 	/* Try each uri in list, add connect fails to tmp list */
-	p = ctxt->uri->next;
-	while(p != ctxt->uri) {
+	uris_mutex_lock(ctxt);
+	if (!ctxt->uri)
+		first = ctxt->uris;
+	else
+		first = &ctxt->uri->list;
+	uris_mutex_unlock(ctxt);
+	p = first->next;
+	while(p != first) {
+		/* Skip list head */
+		if (p == ctxt->uris) {
+			p = p->next;
+			continue;
+		}
 		this = list_entry(p, struct ldap_uri, list);
-		p = p->next;
 		debug(logopt, "trying server %s", this->uri);
 		ldap = connect_to_server(logopt, this->uri, ctxt);
 		if (ldap) {
 			info(logopt, "connected to uri %s", this->uri);
+			uris_mutex_lock(ctxt);
+			ctxt->uri = this;
+			uris_mutex_unlock(ctxt);
 			break;
 		}
-		list_del_init(&this->list);
-		list_add_tail(&this->list, &tmp);
+		p = p->next;
 	}
-	/*
-	 * Successfuly connected uri (head of list) and untried uris are
-	 * in ctxt->uri list. Make list of remainder and failed uris with
-	 * failed uris at end and assign back to ctxt-uri.
-	 */
-	list_splice(ctxt->uri, &tmp);
-	INIT_LIST_HEAD(ctxt->uri);
-	list_splice(&tmp, ctxt->uri);
 
 	return ldap;
 }
@@ -586,19 +603,19 @@ static LDAP *do_reconnect(unsigned logop
 	struct ldap_uri *this;
 	LDAP *ldap;
 
-	if (ctxt->server || !ctxt->uri) {
+	if (ctxt->server || !ctxt->uris) {
 		ldap = do_connect(logopt, ctxt->server, ctxt);
 		return ldap;
 	}
 
-	this = list_entry(ctxt->uri->next, struct ldap_uri, list);
+	uris_mutex_lock(ctxt);
+	this = ctxt->uri;
+	uris_mutex_unlock(ctxt);
 	ldap = do_connect(logopt, this->uri, ctxt);
 	if (ldap)
 		return ldap;
 
-	/* Failed to connect, put at end of list */
-	list_del_init(&this->list);
-	list_add_tail(&this->list, ctxt->uri);
+	/* Failed to connect, try to find a new server */
 
 #ifdef WITH_SASL
 	autofs_sasl_dispose(ctxt);
@@ -1132,6 +1149,8 @@ done:
 
 static void free_context(struct lookup_context *ctxt)
 {
+	int ret;
+
 	if (ctxt->schema) {
 		free(ctxt->schema->map_class);
 		free(ctxt->schema->map_attr);
@@ -1162,8 +1181,11 @@ static void free_context(struct lookup_c
 		free(ctxt->cur_host);
 	if (ctxt->base)
 		free(ctxt->base);
-	if (ctxt->uri)
-		defaults_free_uris(ctxt->uri);
+	if (ctxt->uris)
+		defaults_free_uris(ctxt->uris);
+	ret = pthread_mutex_destroy(&ctxt->uris_mutex);
+	if (ret)
+		fatal(ret);
 	if (ctxt->sdns)
 		defaults_free_searchdns(ctxt->sdns);
 	free(ctxt);
@@ -1215,6 +1237,13 @@ int lookup_init(const char *mapfmt, int 
 	}
 	memset(ctxt, 0, sizeof(struct lookup_context));
 
+	ret = pthread_mutex_init(&ctxt->uris_mutex, NULL);
+	if (ret) {
+		error(LOGOPT_ANY, MODPREFIX "failed to init uris mutex");
+		free(ctxt);
+		return 1;
+	}
+
 	/* If a map type isn't explicitly given, parse it like sun entries. */
 	if (mapfmt == NULL)
 		mapfmt = MAPFMT_DEFAULT;
@@ -1237,7 +1266,7 @@ int lookup_init(const char *mapfmt, int 
 		if (uris) {
 			validate_uris(uris);
 			if (!list_empty(uris))
-				ctxt->uri = uris;
+				ctxt->uris = uris;
 			else {
 				error(LOGOPT_ANY,
 				      "no valid uris found in config list"
@@ -1268,7 +1297,7 @@ int lookup_init(const char *mapfmt, int 
 	}
 #endif
 
-	if (ctxt->server || !ctxt->uri) {
+	if (ctxt->server || !ctxt->uris) {
 		ldap = connect_to_server(LOGOPT_NONE, ctxt->server, ctxt);
 		if (!ldap) {
 			free_context(ctxt);