rpms/autofs/devel autofs-5.0.4-always-read-file-maps-key-lookup-fixes.patch, NONE, 1.1 autofs-5.0.4-always-read-file-maps-multi-map-fix.patch, NONE, 1.1 autofs-5.0.4-dont-fail-on-ipv6-address-adding-host.patch, NONE, 1.1 autofs-5.0.4-dont-umount-existing-direct-mount-on-reread.patch, NONE, 1.1 autofs-5.0.4-fix-kernel-includes.patch, NONE, 1.1 autofs-5.0.4-improve-manual-umount-recovery.patch, NONE, 1.1 autofs-5.0.4-library-reload-fix-update-fix.patch, NONE, 1.1 autofs-5.0.4-use-intr-as-hosts-mount-default.patch, NONE, 1.1 autofs-5.0.4-use-srv-query-for-domain-dn.patch, NONE, 1.1 autofs.spec, 1.279, 1.280

Ian Kent iankent at fedoraproject.org
Mon May 18 02:21:09 UTC 2009


Author: iankent

Update of /cvs/pkgs/rpms/autofs/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv14932

Modified Files:
	autofs.spec 
Added Files:
	autofs-5.0.4-always-read-file-maps-key-lookup-fixes.patch 
	autofs-5.0.4-always-read-file-maps-multi-map-fix.patch 
	autofs-5.0.4-dont-fail-on-ipv6-address-adding-host.patch 
	autofs-5.0.4-dont-umount-existing-direct-mount-on-reread.patch 
	autofs-5.0.4-fix-kernel-includes.patch 
	autofs-5.0.4-improve-manual-umount-recovery.patch 
	autofs-5.0.4-library-reload-fix-update-fix.patch 
	autofs-5.0.4-use-intr-as-hosts-mount-default.patch 
	autofs-5.0.4-use-srv-query-for-domain-dn.patch 
Log Message:
* Mon May 18 2009 Ian Kent <ikent at redhat.com> - 1:5.0.4-28
- use intr option as hosts mount default.
- sync kernel includes with upstream kernel.
- dont umount existing direct mount on master re-read.
- fix incorrect shutdown introduced by library relaod fixes.
- improve manual umount recovery.
- dont fail on ipv6 address when adding host.
- always read file maps multi map fix.
- always read file maps key lookup fixes.
- add support for LDAP_URI="ldap:///<domain db>" SRV RR lookup.


autofs-5.0.4-always-read-file-maps-key-lookup-fixes.patch:

--- NEW FILE autofs-5.0.4-always-read-file-maps-key-lookup-fixes.patch ---
autofs-5.0.4 - always read file maps key lookup fixes

From: Ian Kent <raven at themaw.net>

Since we always read file maps at start we need to ensure that
we return a not found if the key isn't found in the cache. Also,
if we're looking through a "multi" map we can't use the cache
lookup optimisation because, in this case, there is a single map
source shared by the "multi" maps so we may not get correct results
from the lookup if a map later in the search has been modified.
---

 CHANGELOG             |    1 +
 modules/lookup_file.c |   17 +++++++++++------
 2 files changed, 12 insertions(+), 6 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index 972ef63..5000f0c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -48,6 +48,7 @@
 - improve manual umount recovery.
 - dont fail on ipv6 address when adding host.
 - always read file maps multi map fix.
+- always read file maps key lookup fixes.
 
 4/11/2008 autofs-5.0.4
 -----------------------
diff --git a/modules/lookup_file.c b/modules/lookup_file.c
index bd30bc5..a4ca39d 100644
--- a/modules/lookup_file.c
+++ b/modules/lookup_file.c
@@ -1003,13 +1003,15 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
 			 * If any map instances are present for this source
 			 * then either we have plus included entries or we
 			 * are looking through the list of nsswitch sources.
-			 * In either case we cannot avoid reading through the
-			 * map because we must preserve the key order over
-			 * multiple sources. But also, we can't know, at this
-			 * point, if a source instance has been changed since
-			 * the last time we checked it.
+			 * In either case, or if it's a "multi" source, we
+			 * cannot avoid reading through the map because we
+			 * must preserve the key order over multiple sources
+			 * or maps. But also, we can't know, at this point,
+			 * if a source instance has been changed since the
+			 * last time we checked it.
 			 */
-			if (!source->instance)
+			if (!source->instance &&
+			    source->type && strcmp(source->type, "multi"))
 				goto do_cache_lookup;
 		} else
 			source->stale = 1;
@@ -1055,6 +1057,9 @@ do_cache_lookup:
 	}
 	cache_unlock(mc);
 
+	if (!me)
+		return NSS_STATUS_NOTFOUND;
+
 	if (!mapent)
 		return NSS_STATUS_TRYAGAIN;
 

autofs-5.0.4-always-read-file-maps-multi-map-fix.patch:

--- NEW FILE autofs-5.0.4-always-read-file-maps-multi-map-fix.patch ---
autofs-5.0.4 - always read file maps multi map fix

From: Ian Kent <raven at themaw.net>

Since "multi" map entries may contain file maps themselves and we
always want to read file maps we need to move the chack of whether
to read the map from lookup_nss_read_map() into the individual
map type lookup modules.
---

 CHANGELOG                |    1 +
 daemon/lookup.c          |   14 --------------
 modules/lookup_hosts.c   |    8 ++++++++
 modules/lookup_ldap.c    |    8 ++++++++
 modules/lookup_nisplus.c |    8 ++++++++
 modules/lookup_yp.c      |    8 ++++++++
 6 files changed, 33 insertions(+), 14 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index 7e1012f..972ef63 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -47,6 +47,7 @@
 - fix incorrect shutdown introduced by library relaod fixes.
 - improve manual umount recovery.
 - dont fail on ipv6 address when adding host.
+- always read file maps multi map fix.
 
 4/11/2008 autofs-5.0.4
 -----------------------
diff --git a/daemon/lookup.c b/daemon/lookup.c
index bc94655..9d5a5c8 100644
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -278,20 +278,6 @@ static int do_read_map(struct autofs_point *ap, struct map_source *map, time_t a
 	map->lookup = lookup;
 	master_source_unlock(ap->entry);
 
-	/* If we don't need to create directories then there's no use
-	 * reading the map. We just need to test that the map is valid
-	 * for the fail cases to function correctly and to cache the
-	 * lookup handle.
-	 *
-	 * We always need to read the whole map for direct mounts in
-	 * order to mount the triggers. We also want to read the whole
-	 * map if it's a file map to avoid potentially lengthy linear
-	 * file scanning.
-	 */
-	if (strcmp(map->type, "file") &&
-	    !(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT)
-		return NSS_STATUS_SUCCESS;
-
 	if (!map->stale)
 		return NSS_STATUS_SUCCESS;
 
diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
index d3ae0e2..a213780 100644
--- a/modules/lookup_hosts.c
+++ b/modules/lookup_hosts.c
@@ -89,6 +89,14 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
 	ap->entry->current = NULL;
 	master_source_current_signal(ap->entry);
 
+	/*
+	 * If we don't need to create directories then there's no use
+	 * reading the map. We always need to read the whole map for
+	 * direct mounts in order to mount the triggers.
+	 */
+	if (!(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT)
+		return NSS_STATUS_SUCCESS;
+
 	mc = source->mc;
 
 	status = pthread_mutex_lock(&hostent_mutex);
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index 8c6a8f2..a847622 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -2236,6 +2236,14 @@ static int read_one_map(struct autofs_point *ap,
 	ap->entry->current = NULL;
 	master_source_current_signal(ap->entry);
 
+	/*
+	 * If we don't need to create directories then there's no use
+	 * reading the map. We always need to read the whole map for
+	 * direct mounts in order to mount the triggers.
+	 */
+	if (!(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT)
+		return NSS_STATUS_SUCCESS;
+
 	sp.ap = ap;
 	sp.age = age;
 
diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c
index 0c75905..ae53481 100644
--- a/modules/lookup_nisplus.c
+++ b/modules/lookup_nisplus.c
@@ -180,6 +180,14 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
 	ap->entry->current = NULL;
 	master_source_current_signal(ap->entry);
 
+	/*
+	 * If we don't need to create directories then there's no use
+	 * reading the map. We always need to read the whole map for
+	 * direct mounts in order to mount the triggers.
+	 */
+	if (!(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT)
+		return NSS_STATUS_SUCCESS;
+
 	mc = source->mc;
 
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
index ce438e8..208f95e 100644
--- a/modules/lookup_yp.c
+++ b/modules/lookup_yp.c
@@ -322,6 +322,14 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
 	ap->entry->current = NULL;
 	master_source_current_signal(ap->entry);
 
+	/*
+	 * If we don't need to create directories then there's no use
+	 * reading the map. We always need to read the whole map for
+	 * direct mounts in order to mount the triggers.
+	 */
+	if (!(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT)
+		return NSS_STATUS_SUCCESS;
+
 	ypcb_data.ap = ap;
 	ypcb_data.source = source;
 	ypcb_data.logopt = logopt;

autofs-5.0.4-dont-fail-on-ipv6-address-adding-host.patch:

--- NEW FILE autofs-5.0.4-dont-fail-on-ipv6-address-adding-host.patch ---
autofs-5.0.4 - dont fail on ipv6 address adding host

From: Ian Kent <raven at themaw.net>

We don't have IPv6 support enabled in libtirpc yet. When we
perform name (or address) lookup and we get a mixture of IPv4
and IPv6 addresses the lack of IPv6 support can cause the
parse_location() function to fail to add any valid hosts when
in fact it should.
---

 CHANGELOG            |    1 +
 include/replicated.h |    1 +
 modules/replicated.c |    9 ++++++++-
 3 files changed, 10 insertions(+), 1 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index 89aaa99..7e1012f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -46,6 +46,7 @@
 - dont umount existing direct mount on master re-read.
 - fix incorrect shutdown introduced by library relaod fixes.
 - improve manual umount recovery.
+- dont fail on ipv6 address when adding host.
 
 4/11/2008 autofs-5.0.4
 -----------------------
diff --git a/include/replicated.h b/include/replicated.h
index e0133ff..fd87c08 100644
--- a/include/replicated.h
+++ b/include/replicated.h
@@ -21,6 +21,7 @@
 #define PROXIMITY_SUBNET        0x0002
 #define PROXIMITY_NET           0x0004
 #define PROXIMITY_OTHER         0x0008
+#define PROXIMITY_UNSUPPORTED   0x0010
 
 #define NFS2_SUPPORTED		0x0010
 #define NFS3_SUPPORTED		0x0020
diff --git a/modules/replicated.c b/modules/replicated.c
index 79845d0..a66de9f 100644
--- a/modules/replicated.c
+++ b/modules/replicated.c
@@ -181,7 +181,7 @@ static unsigned int get_proximity(struct sockaddr *host_addr)
 
 	case AF_INET6:
 #ifndef INET6
-		return PROXIMITY_ERROR;
+		return PROXIMITY_UNSUPPORTED;
 #else
 		addr6 = (struct sockaddr_in6 *) host_addr;
 		hst6_addr = (struct in6_addr *) &addr6->sin6_addr;
@@ -1048,6 +1048,13 @@ static int add_new_host(struct host **list,
 	int addr_len;
 
 	prx = get_proximity(host_addr->ai_addr);
+	/*
+	 * If we tried to add an IPv6 address and we don't have IPv6
+	 * support return success in the hope of getting an IPv4
+	 * address later.
+	 */
+	if (prx == PROXIMITY_UNSUPPORTED)
+		return 1;
 	if (prx == PROXIMITY_ERROR)
 		return 0;
 

autofs-5.0.4-dont-umount-existing-direct-mount-on-reread.patch:

--- NEW FILE autofs-5.0.4-dont-umount-existing-direct-mount-on-reread.patch ---
autofs-5.0.4 - dont umount existing direct mount on master re-read

From: Ian Kent <raven at themaw.net>

Since direct mounts can have multiple entries in the master map they each
have an instance associated with them. If one entry changes, such as the
mount options, the instance comparison test fails and a new instance is
added. This causes autofs to get confused because there are now two
entries that contain the same mount information in different internal
caches. There are several consequences of this, most of which are just
noise in the log, but it also causes confuion for the expiration of mounts
since, for an active mount, the old cache entry can't be pruned until it's
umounted. Also, the map caches were not being properly pruned.
---

 CHANGELOG           |    1 
 daemon/lookup.c     |  160 ++++++++++++++++++++++++++++-----------------------
 daemon/state.c      |   90 +++++++++++++++++++++--------
 include/automount.h |    1 
 4 files changed, 156 insertions(+), 96 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index 387af5e..7ca45fd 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -43,6 +43,7 @@
 - use percent hack for master map keys.
 - use intr option as hosts mount default.
 - fix kernel includes.
+- dont umount existing direct mount on master re-read.
 
 4/11/2008 autofs-5.0.4
 -----------------------
diff --git a/daemon/lookup.c b/daemon/lookup.c
index fd2ce55..bc94655 100644
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -1016,96 +1016,114 @@ static char *make_fullpath(const char *root, const char *key)
 	return path;
 }
 
-int lookup_prune_cache(struct autofs_point *ap, time_t age)
+void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, time_t age)
 {
-	struct master_mapent *entry = ap->entry;
-	struct map_source *map;
-	struct mapent_cache *mc;
 	struct mapent *me, *this;
 	char *path;
 	int status = CHE_FAIL;
 
-	pthread_cleanup_push(master_source_lock_cleanup, entry);
-	master_source_readlock(entry);
+	me = cache_enumerate(mc, NULL);
+	while (me) {
+		struct mapent *valid;
+		char *key = NULL, *next_key = NULL;
 
-	map = entry->maps;
-	while (map) {
-		/* Is the map stale */
-		if (!map->stale) {
-			map = map->next;
+		if (me->age >= age) {
+			me = cache_enumerate(mc, me);
 			continue;
 		}
-		mc = map->mc;
-		pthread_cleanup_push(cache_lock_cleanup, mc);
-		cache_readlock(mc);
-		me = cache_enumerate(mc, NULL);
-		while (me) {
-			char *key = NULL, *next_key = NULL;
 
-			if (me->age >= age) {
-				me = cache_enumerate(mc, me);
-				continue;
-			}
+		key = strdup(me->key);
+		me = cache_enumerate(mc, me);
+		if (!key || *key == '*') {
+			if (key)
+				free(key);
+			continue;
+		}
 
-			key = strdup(me->key);
-			me = cache_enumerate(mc, me);
-			if (!key || *key == '*') {
-				if (key)
-					free(key);
-				continue;
-			}
+		path = make_fullpath(ap->path, key);
+		if (!path) {
+			warn(ap->logopt, "can't malloc storage for path");
+			free(key);
+			continue;
+		}
 
-			path = make_fullpath(ap->path, key);
-			if (!path) {
-				warn(ap->logopt,
-				     "can't malloc storage for path");
-				free(key);
-				continue;
-			}
+		/*
+		 * If this key has another valid entry we want to prune it,
+		 * even if it's a mount, as the valid entry will take the
+		 * mount if it is a direct mount or it's just a stale indirect
+		 * cache entry.
+		 */
+		valid = lookup_source_valid_mapent(ap, key, LKP_DISTINCT);
+		if (!valid &&
+		    is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) {
+			debug(ap->logopt,
+			      "prune check posponed, %s mounted", path);
+			free(key);
+			free(path);
+			continue;
+		}
+		if (valid)
+			cache_unlock(valid->mc);
 
-			if (is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) {
-				debug(ap->logopt,
-				      "prune check posponed, %s mounted", path);
-				free(key);
-				free(path);
-				continue;
-			}
+		if (me)
+			next_key = strdup(me->key);
 
-			if (me)
-				next_key = strdup(me->key);
+		cache_unlock(mc);
 
+		cache_writelock(mc);
+		this = cache_lookup_distinct(mc, key);
+		if (!this) {
 			cache_unlock(mc);
+			goto next;
+		}
 
-			cache_writelock(mc);
-			this = cache_lookup_distinct(mc, key);
-			if (!this) {
-				cache_unlock(mc);
-				goto next;
-			}
-
-			if (!is_mounted(_PROC_MOUNTS, path, MNTS_AUTOFS)) {
-				status = CHE_FAIL;
-				if (this->ioctlfd == -1)
-					status = cache_delete(mc, key);
-				if (status != CHE_FAIL) {
-					if (ap->type == LKP_INDIRECT) {
-						if (ap->flags & MOUNT_FLAG_GHOST)
-							rmdir_path(ap, path, ap->dev);
-					} else
-						rmdir_path(ap, path, this->dev);
-				}
+		if (valid)
+			cache_delete(mc, key);
+		else if (!is_mounted(_PROC_MOUNTS, path, MNTS_AUTOFS)) {
+			status = CHE_FAIL;
+			if (this->ioctlfd == -1)
+				status = cache_delete(mc, key);
+			if (status != CHE_FAIL) {
+				if (ap->type == LKP_INDIRECT) {
+					if (ap->flags & MOUNT_FLAG_GHOST)
+						rmdir_path(ap, path, ap->dev);
+				} else
+					rmdir_path(ap, path, this->dev);
 			}
-			cache_unlock(mc);
+		}
+		cache_unlock(mc);
 
 next:
-			cache_readlock(mc);
-			if (next_key) {
-				me = cache_lookup_distinct(mc, next_key);
-				free(next_key);
-			}
-			free(key);
-			free(path);
+		cache_readlock(mc);
+		if (next_key) {
+			me = cache_lookup_distinct(mc, next_key);
+			free(next_key);
 		}
+		free(key);
+		free(path);
+	}
+
+	return;
+}
+
+int lookup_prune_cache(struct autofs_point *ap, time_t age)
+{
+	struct master_mapent *entry = ap->entry;
+	struct map_source *map;
+
+	pthread_cleanup_push(master_source_lock_cleanup, entry);
+	master_source_readlock(entry);
+
+	map = entry->maps;
+	while (map) {
+		/* Is the map stale */
+		if (!map->stale) {
+			map = map->next;
+			continue;
+		}
+		pthread_cleanup_push(cache_lock_cleanup, map->mc);
+		cache_readlock(map->mc);
+		lookup_prune_one_cache(ap, map->mc, age);
 		pthread_cleanup_pop(1);
 		map->stale = 0;
 		map = map->next;
@@ -1124,7 +1142,6 @@ struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *k
 	struct mapent_cache *mc;
 	struct mapent *me = NULL;
 
-	master_source_readlock(entry);
 	map = entry->maps;
 	while (map) {
 		/*
@@ -1147,7 +1164,6 @@ struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *k
 		cache_unlock(mc);
 		map = map->next;
 	}
-	master_source_unlock(entry);
 
 	return me;
 }
diff --git a/daemon/state.c b/daemon/state.c
index 533e241..84ccba3 100644
--- a/daemon/state.c
+++ b/daemon/state.c
@@ -352,6 +352,68 @@ static void tree_mnts_cleanup(void *arg)
 	return;
 }
 
+static void do_readmap_mount(struct autofs_point *ap, struct mnt_list *mnts,
+			     struct map_source *map, struct mapent *me, time_t now)
+{
+	struct mapent_cache *nc;
+	struct mapent *ne, *nested, *valid;
+
+	nc = ap->entry->master->nc;
+
+	ne = cache_lookup_distinct(nc, me->key);
+	if (!ne) {
+		nested = cache_partial_match(nc, me->key);
+		if (nested) {
+			error(ap->logopt,
+			      "removing invalid nested null entry %s",
+			      nested->key);
+			nested = cache_partial_match(nc, me->key);
+			if (nested)
+				cache_delete(nc, nested->key);
+		}
+	}
+
+	if (me->age < now || (ne && map->master_line > ne->age)) {
+		/*
+		 * The map instance may have changed, such as the map name or
+		 * the mount options, but the direct map entry may still exist
+		 * in one of the other maps. If so then update the new cache
+		 * entry device and inode so we can find it at lookup. Later,
+		 * the mount for the new cache entry will just update the
+		 * timeout.
+		 *
+		 * TODO: how do we recognise these orphaned map instances. We
+		 * can't just delete these instances when the cache becomes
+		 * empty because that is a valid state for a master map entry.
+		 * This is becuase of the requirement to continue running with
+		 * an empty cache awaiting a map re-load.
+		 */
+		valid = lookup_source_valid_mapent(ap, me->key, LKP_DISTINCT);
+		if (valid) {
+			struct mapent_cache *vmc = valid->mc;
+			cache_unlock(vmc);
+			debug(ap->logopt,
+			     "updating cache entry for valid direct trigger %s",
+			     me->key);
+			cache_writelock(vmc);
+			valid = cache_lookup_distinct(vmc, me->key);
+			/* Take over the mount if there is one */
+			valid->ioctlfd = me->ioctlfd;
+			me->ioctlfd = -1;
+			/* Set device and inode number of the new mapent */
+			cache_set_ino_index(vmc, me->key, me->dev, me->ino);
+			cache_unlock(vmc);
+		} else if (!tree_is_mounted(mnts, me->key, MNTS_REAL))
+			do_umount_autofs_direct(ap, mnts, me);
+		else
+			debug(ap->logopt,
+			      "%s is mounted", me->key);
+	} else
+		do_mount_autofs_direct(ap, mnts, me);
+
+	return;
+}
+
 static void *do_readmap(void *arg)
 {
 	struct autofs_point *ap;
@@ -398,7 +460,8 @@ static void *do_readmap(void *arg)
 		lookup_prune_cache(ap, now);
 		status = lookup_ghost(ap, ap->path);
 	} else {
-		struct mapent *me, *ne, *nested;
+		struct mapent *me;
+
 		mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/");
 		pthread_cleanup_push(tree_mnts_cleanup, mnts);
 		pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
@@ -418,31 +481,10 @@ static void *do_readmap(void *arg)
 			cache_readlock(mc);
 			me = cache_enumerate(mc, NULL);
 			while (me) {
-				ne = cache_lookup_distinct(nc, me->key);
-				if (!ne) {
-					nested = cache_partial_match(nc, me->key);
-					if (nested) {
-						error(ap->logopt,
-						"removing invalid nested null entry %s",
-						nested->key);
-						nested = cache_partial_match(nc, me->key);
-						if (nested)
-							cache_delete(nc, nested->key);
-					}
-				}
-
-				/* TODO: check return of do_... */
-				if (me->age < now || (ne && map->master_line > ne->age)) {
-					if (!tree_is_mounted(mnts, me->key, MNTS_REAL))
-						do_umount_autofs_direct(ap, mnts, me);
-					else
-                                		debug(ap->logopt,
-						      "%s is mounted", me->key);
-				} else
-					do_mount_autofs_direct(ap, mnts, me);
-
+				do_readmap_mount(ap, mnts, map, me, now);
 				me = cache_enumerate(mc, me);
 			}
+			lookup_prune_one_cache(ap, map->mc, now);
 			pthread_cleanup_pop(1);
 			map->stale = 0;
 			map = map->next;
diff --git a/include/automount.h b/include/automount.h
index d4675bd..ae517a7 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -238,6 +238,7 @@ int lookup_enumerate(struct autofs_point *ap,
 int lookup_ghost(struct autofs_point *ap, const char *root);
 int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len);
 void lookup_close_lookup(struct autofs_point *ap);
+void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, time_t age);
 int lookup_prune_cache(struct autofs_point *ap, time_t age);
 struct mapent *lookup_source_valid_mapent(struct autofs_point *ap, const char *key, unsigned int type);
 struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, unsigned int type);

autofs-5.0.4-fix-kernel-includes.patch:

--- NEW FILE autofs-5.0.4-fix-kernel-includes.patch ---
autofs-5.0.4 - fix kernel includes

From: Valerie Aurora Henson <vaurora at redhat.com>

autofs_dev-ioctl.h is included by both the kernel module and autofs,
and it includes two kernel header files. The compile worked if the
kernel headers were installed but failed otherwise.

imk: there are a couple of other instances were we include kernel
headers. I've tried to fix that up too.
---

 CHANGELOG                      |    1 +
 include/automount.h            |    3 +--
 include/dev-ioctl-lib.h        |    3 +--
 include/linux/auto_dev-ioctl.h |    7 ++++++-
 include/linux/auto_fs.h        |    6 ++++--
 5 files changed, 13 insertions(+), 7 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index a42dd14..387af5e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -42,6 +42,7 @@
 - zero s_magic is valid.
 - use percent hack for master map keys.
 - use intr option as hosts mount default.
+- fix kernel includes.
 
 4/11/2008 autofs-5.0.4
 -----------------------
diff --git a/include/automount.h b/include/automount.h
index 615e07d..d4675bd 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -8,12 +8,11 @@
 #ifndef AUTOMOUNT_H
 #define AUTOMOUNT_H
 
-#include <sys/types.h>
 #include <paths.h>
 #include <limits.h>
 #include <time.h>
 #include <syslog.h>
-#include <linux/types.h>
+#include <sys/types.h>
 #include <pthread.h>
 #include <sched.h>
 #include <errno.h>
diff --git a/include/dev-ioctl-lib.h b/include/dev-ioctl-lib.h
index b7b8211..6d35da2 100644
--- a/include/dev-ioctl-lib.h
+++ b/include/dev-ioctl-lib.h
@@ -21,8 +21,7 @@
 #ifndef AUTOFS_DEV_IOCTL_LIB_H
 #define AUTOFS_DEV_IOCTL_LIB_H
 
-#include <sys/types.h>
-#include "linux/auto_dev-ioctl.h"
+#include <linux/auto_dev-ioctl.h>
 
 #define CONTROL_DEVICE  "/dev/autofs"
 
diff --git a/include/linux/auto_dev-ioctl.h b/include/linux/auto_dev-ioctl.h
index 91a7739..850f39b 100644
--- a/include/linux/auto_dev-ioctl.h
+++ b/include/linux/auto_dev-ioctl.h
@@ -10,8 +10,13 @@
 #ifndef _LINUX_AUTO_DEV_IOCTL_H
 #define _LINUX_AUTO_DEV_IOCTL_H
 
+#include <linux/auto_fs.h>
+
+#ifdef __KERNEL__
 #include <linux/string.h>
-#include <linux/types.h>
+#else
+#include <string.h>
+#endif /* __KERNEL__ */
 
 #define AUTOFS_DEVICE_NAME		"autofs"
 
diff --git a/include/linux/auto_fs.h b/include/linux/auto_fs.h
index bd39f09..91d414f 100644
--- a/include/linux/auto_fs.h
+++ b/include/linux/auto_fs.h
@@ -17,11 +17,13 @@
 #ifdef __KERNEL__
 #include <linux/fs.h>
 #include <linux/limits.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#else
 #include <asm/types.h>
+#include <sys/ioctl.h>
 #endif /* __KERNEL__ */
 
-#include <linux/ioctl.h>
-
 /* This file describes autofs v3 */
 #define AUTOFS_PROTO_VERSION	3
 

autofs-5.0.4-improve-manual-umount-recovery.patch:

--- NEW FILE autofs-5.0.4-improve-manual-umount-recovery.patch ---
autofs-5.0.4 - improve manual umount recovery

From: Ian Kent <raven at themaw.net>

The check for manually umounted mounts in the expire of direct mounts is
racy and the check itself is inadequate in that it can incorrectly clear
the descriptor of an active mount. Also, we do a similar test following
the expire which is a waste since we can catch this on the next expire.
So these two tests have been combined and the check done only prior to
the expire. In the indirect expire we don't have a check at all so we
add one.
---

 CHANGELOG         |    1 +
 daemon/direct.c   |   28 ++++++++++------------------
 daemon/indirect.c |   47 ++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 57 insertions(+), 19 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index 5e01812..89aaa99 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -45,6 +45,7 @@
 - fix kernel includes.
 - dont umount existing direct mount on master re-read.
 - fix incorrect shutdown introduced by library relaod fixes.
+- improve manual umount recovery.
 
 4/11/2008 autofs-5.0.4
 -----------------------
diff --git a/daemon/direct.c b/daemon/direct.c
index 4f4ff20..1ed2b15 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -881,13 +881,14 @@ void *expire_proc_direct(void *arg)
 			 * avoid maintaining a file handle for control
 			 * functions as once it's mounted all opens are
 			 * directed to the mount not the trigger.
-			 * But first expire possible rootless offsets first.
 			 */
 
-			/* Offsets always have a real mount at their base */
+			/* Check for manual umount */
 			cache_writelock(me->mc);
-			if (strstr(next->opts, "offset")) {
-				ops->close(ap->logopt, me->ioctlfd);
+			if (me->ioctlfd != -1 && 
+			    fstat(ioctlfd, &st) != -1 &&
+			    !count_mounts(ap->logopt, next->path, st.st_dev)) {
+				ops->close(ap->logopt, ioctlfd);
 				me->ioctlfd = -1;
 				cache_unlock(me->mc);
 				pthread_setcancelstate(cur_state, NULL);
@@ -904,15 +905,6 @@ void *expire_proc_direct(void *arg)
 				continue;
 			}
 
-			cache_writelock(me->mc);
-			if (me->ioctlfd != -1 && 
-			    fstat(ioctlfd, &st) != -1 &&
-			    !count_mounts(ap->logopt, next->path, st.st_dev)) {
-				ops->close(ap->logopt, ioctlfd);
-				me->ioctlfd = -1;
-			}
-			cache_unlock(me->mc);
-
 			pthread_setcancelstate(cur_state, NULL);
 			continue;
 		}
@@ -1068,7 +1060,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
 	map = ap->entry->maps;
 	while (map) {
 		mc = map->mc;
-		cache_readlock(mc);
+		cache_writelock(mc);
 		me = cache_lookup_ino(mc, pkt->dev, pkt->ino);
 		if (me)
 			break;
@@ -1345,7 +1337,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
 		}
 
 		mc = map->mc;
-		cache_readlock(mc);
+		cache_writelock(mc);
 		me = cache_lookup_ino(mc, pkt->dev, pkt->ino);
 		if (me)
 			break;
@@ -1367,10 +1359,10 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
 
 	if (me->ioctlfd != -1) {
 		/* Maybe someone did a manual umount, clean up ! */
-		ioctlfd = me->ioctlfd;
+		close(me->ioctlfd);
 		me->ioctlfd = -1;
-	} else
-		ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
+	}
+	ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
 
 	if (ioctlfd == -1) {
 		cache_unlock(mc);
diff --git a/daemon/indirect.c b/daemon/indirect.c
index 2539282..bc39e63 100644
--- a/daemon/indirect.c
+++ b/daemon/indirect.c
@@ -428,8 +428,53 @@ void *expire_proc_indirect(void *arg)
 			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
 			if (strstr(next->opts, "indirect"))
 				master_notify_submount(ap, next->path, ap->state);
-			pthread_setcancelstate(cur_state, NULL);
+			else if (strstr(next->opts, "offset")) {
+				struct map_source *map;
+				struct mapent_cache *mc = NULL;
+				struct mapent *me = NULL;
+				struct stat st;
+
+				master_source_readlock(ap->entry);
+
+				map = ap->entry->maps;
+				while (map) {
+					mc = map->mc;
+					cache_writelock(mc);
+					me = cache_lookup_distinct(mc, next->path);
+					if (me)
+						break;
+					cache_unlock(mc);
+					map = map->next;
+				}
 
+				if (!mc || !me) {
+					master_source_unlock(ap->entry);
+					pthread_setcancelstate(cur_state, NULL);
+					continue;
+				}
+
+				/* Check for manual umount */
+				if (me->ioctlfd != -1 &&
+				    (fstat(me->ioctlfd, &st) == -1 ||
+				     !count_mounts(ap->logopt, me->key, st.st_dev))) {
+					if (is_mounted(_PROC_MOUNTS, me->key, MNTS_REAL)) {
+						error(ap->logopt,
+						      "error: possible mtab mismatch %s",
+						      me->key);
+						cache_unlock(mc);
+						master_source_unlock(ap->entry);
+						pthread_setcancelstate(cur_state, NULL);
+						continue;
+					}
+					close(me->ioctlfd);
+					me->ioctlfd = -1;
+				}
+
+				cache_unlock(mc);
+				master_source_unlock(ap->entry);
+			}
+
+			pthread_setcancelstate(cur_state, NULL);
 			continue;
 		}
 

autofs-5.0.4-library-reload-fix-update-fix.patch:

--- NEW FILE autofs-5.0.4-library-reload-fix-update-fix.patch ---
autofs-5.0.4 - library reload fix update fix

From: Ian Kent <raven at themaw.net>

The library reload fixes introduced a bug which causes autofs to
incorrectly shutdown. Previously the signal handling thread only
recieved signals either when they were explicity sent or it was
time to shutdown so continuing on to call the signal handling
routine was the correct thing to do. Now we need to join with
the mount handling thread at exit but, in this case, we don't
want to continue on to the signal handling routine as that will
incorrectly cause the signal to be passed on to other mount
handling threads.
---

 CHANGELOG          |    1 +
 daemon/automount.c |   18 ++++++++++++++++--
 lib/master.c       |    2 --
 3 files changed, 17 insertions(+), 4 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index 7ca45fd..5e01812 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -44,6 +44,7 @@
 - use intr option as hosts mount default.
 - fix kernel includes.
 - dont umount existing direct mount on master re-read.
+- fix incorrect shutdown introduced by library relaod fixes.
 
 4/11/2008 autofs-5.0.4
 -----------------------
diff --git a/daemon/automount.c b/daemon/automount.c
index 80691fa..3a0fe0b 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -1332,8 +1332,22 @@ static void *statemachine(void *arg)
 		case SIGTERM:
 		case SIGINT:
 		case SIGUSR2:
-			if (master_done(master_list))
-				return NULL;
+			master_mutex_lock();
+			if (list_empty(&master_list->completed)) {
+				if (list_empty(&master_list->mounts)) {
+					master_mutex_unlock();
+					return NULL;
+				}
+			} else {
+				if (master_done(master_list)) {
+					master_mutex_unlock();
+					return NULL;
+				}
+				master_mutex_unlock();
+				break;
+			}
+			master_mutex_unlock();
+
 		case SIGUSR1:
 			do_signals(master_list, sig);
 			break;
diff --git a/lib/master.c b/lib/master.c
index 762094f..e43f835 100644
--- a/lib/master.c
+++ b/lib/master.c
@@ -1182,7 +1182,6 @@ int master_done(struct master *master)
 	struct master_mapent *entry;
 	int res = 0;
 
-	master_mutex_lock();
 	head = &master->completed;
 	p = head->next;
 	while (p != head) {
@@ -1195,7 +1194,6 @@ int master_done(struct master *master)
 	}
 	if (list_empty(&master->mounts))
 		res = 1;
-	master_mutex_unlock();
 
 	return res;
 }

autofs-5.0.4-use-intr-as-hosts-mount-default.patch:

--- NEW FILE autofs-5.0.4-use-intr-as-hosts-mount-default.patch ---
autofs-5.0.4 - use intr option as hosts mount default

From: Ian Kent <raven at themaw.net>

Use the "intr" option as default mount option for the hosts map
unless explicily overridden.
---

 CHANGELOG            |    1 +
 man/auto.master.5.in |    5 +++--
 modules/parse_sun.c  |   11 +++++++----
 3 files changed, 11 insertions(+), 6 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index 8258e00..a42dd14 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -41,6 +41,7 @@
 - reset flex scanner when setting buffer.
 - zero s_magic is valid.
 - use percent hack for master map keys.
+- use intr option as hosts mount default.
 
 4/11/2008 autofs-5.0.4
 -----------------------
diff --git a/man/auto.master.5.in b/man/auto.master.5.in
index aaa6324..7b7004f 100644
--- a/man/auto.master.5.in
+++ b/man/auto.master.5.in
@@ -208,8 +208,9 @@ For example, with an entry in the master map of
 accessing /net/myserver will mount exports from myserver on directories below
 /net/myserver.
 .P
-NOTE: mounts done from a hosts map will be mounted with the "nosuid" and "nodev" options
-unless the options "suid" and "dev" are explicitly given in the master map entry.
+NOTE: mounts done from a hosts map will be mounted with the "nosuid,nodev,intr" options
+unless overridden by explicily specifying the "suid", "dev" or "nointr" options in the
+master map entry.
 .SH LDAP MAPS
 If the map type \fBldap\fP is specified the mapname is of the form
 \fB[//servername/]dn\fP, where the optional \fBservername\fP is
diff --git a/modules/parse_sun.c b/modules/parse_sun.c
index 65417e1..db36ae2 100644
--- a/modules/parse_sun.c
+++ b/modules/parse_sun.c
@@ -607,9 +607,10 @@ static int sun_mount(struct autofs_point *ap, const char *root,
 			int len = strlen(options);
 			int suid = strstr(options, "suid") ? 0 : 7;
 			int dev = strstr(options, "dev") ? 0 : 6;
+			int nointr = strstr(options, "nointr") ? 0 : 5;
 
-			if (suid || dev) {
-				char *tmp = alloca(len + suid + dev + 1);
+			if (suid || dev || nointr) {
+				char *tmp = alloca(len + suid + dev + nointr + 1);
 				if (!tmp) {
 					error(ap->logopt, MODPREFIX
 					      "alloca failed for options");
@@ -623,10 +624,12 @@ static int sun_mount(struct autofs_point *ap, const char *root,
 					strcat(tmp, ",nosuid");
 				if (dev)
 					strcat(tmp, ",nodev");
+				if (nointr)
+					strcat(tmp, ",intr");
 				options = tmp;
 			}
 		} else {
-			char *tmp = alloca(13);
+			char *tmp = alloca(18);
 			if (!tmp) {
 				error(ap->logopt,
 				      MODPREFIX "alloca failed for options");
@@ -634,7 +637,7 @@ static int sun_mount(struct autofs_point *ap, const char *root,
 					return -1;
 				return 1;
 			}
-			strcpy(tmp, "nosuid,nodev");
+			strcpy(tmp, "nosuid,nodev,intr");
 			options = tmp;
 		}
 	}

autofs-5.0.4-use-srv-query-for-domain-dn.patch:

--- NEW FILE autofs-5.0.4-use-srv-query-for-domain-dn.patch ---
autofs-5.0.4 - use srv query for domain dn

From: Ian Kent <raven at themaw.net>

Add the ability to use a domain dn in the LDAP_URI configuration
entry. If a domain dn is encountered in the LDAP_URI the list of
servers will be queried and used for the LDAP connection. The list
won't be queried again until the minimum ttl found in the SRV RR
records is reached or, if ttl isn't given in any SRV RR records,
after 1 hour.
---

 CHANGELOG                      |    1 
 include/dclist.h               |   14 +
 include/lookup_ldap.h          |    3 
 man/auto.master.5.in           |    8 
 modules/Makefile               |    5 
 modules/dclist.c               |  785 ++++++++++++++++++++++++++++++++++++++++
 modules/lookup_ldap.c          |   86 ++++
 redhat/autofs.sysconfig.in     |   11 +
 samples/autofs.conf.default.in |   11 +
 9 files changed, 911 insertions(+), 13 deletions(-)
 create mode 100644 include/dclist.h
 create mode 100644 modules/dclist.c


diff --git a/CHANGELOG b/CHANGELOG
index 5000f0c..f49784a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -49,6 +49,7 @@
 - dont fail on ipv6 address when adding host.
 - always read file maps multi map fix.
 - always read file maps key lookup fixes.
+- use srv query for domain dn.
 
 4/11/2008 autofs-5.0.4
 -----------------------
diff --git a/include/dclist.h b/include/dclist.h
new file mode 100644
index 0000000..ed89f97
--- /dev/null
+++ b/include/dclist.h
@@ -0,0 +1,14 @@
+#ifndef __DCLIST_H
+#define __DCLIST_H
+
+#include <sys/types.h>
+
+struct dclist {
+	time_t expire;
+	const char *uri;
+};
+
+struct dclist *get_dc_list(unsigned int logopt, const char *uri);
+void free_dclist(struct dclist *dclist);
+
+#endif
diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
index b47bf5d..dcae220 100644
--- a/include/lookup_ldap.h
+++ b/include/lookup_ldap.h
@@ -10,6 +10,8 @@
 #include <krb5.h>
 #endif
 
+#include "dclist.h"
+
 struct ldap_schema {
 	char *map_class;
 	char *map_attr;
@@ -57,6 +59,7 @@ struct lookup_context {
 	pthread_mutex_t uris_mutex;
 	struct list_head *uris;
 	struct ldap_uri *uri;
+	struct dclist *dclist;
 	char *cur_host;
 	struct ldap_searchdn *sdns;
 
diff --git a/man/auto.master.5.in b/man/auto.master.5.in
index 7b7004f..71c4402 100644
--- a/man/auto.master.5.in
+++ b/man/auto.master.5.in
@@ -271,6 +271,14 @@ Map entries that include a server name override this option and it is then
 not used. Default is an empty list in which case either the server given
 in a map entry or the LDAP configured default is used. This uri list is read at
 startup and whenever the daemon receives a HUP signal.
+.P
+This configuration option can also be used to request autofs lookup SRV RRs
+for a domain of the form <proto>:///[<domain dn>]. Note that a trailing
+"/" is not allowed when using this form. If the domain dn is not specified
+the dns domain name (if any) is used to construct the domain dn for the
+SRV RR lookup. The server list returned from an SRV RR lookup is refreshed
+according to the minimum ttl found in the SRV RR records or after one hour,
+whichever is less.
 .TP
 .B SEARCH_BASE
 The base dn to use when searching for amap base dn. This entry may be
diff --git a/modules/Makefile b/modules/Makefile
index 0d12f01..13b3bd8 100644
--- a/modules/Makefile
+++ b/modules/Makefile
@@ -86,9 +86,10 @@ lookup_hesiod.so: lookup_hesiod.c
 cyrus-sasl.o: cyrus-sasl.c
 	$(CC) $(CFLAGS) $(LDAP_FLAGS) -c $<
 
-lookup_ldap.so: lookup_ldap.c $(SASL_OBJ)
+lookup_ldap.so: lookup_ldap.c dclist.o $(SASL_OBJ)
 	$(CC) $(SOLDFLAGS) $(CFLAGS) $(LDAP_FLAGS) -o lookup_ldap.so \
-		lookup_ldap.c $(SASL_OBJ) $(AUTOFS_LIB) $(LIBLDAP)
+		lookup_ldap.c dclist.o $(SASL_OBJ) \
+		$(AUTOFS_LIB) $(LIBLDAP) $(LIBRESOLV)
 	$(STRIP) lookup_ldap.so
 
 mount_nfs.so: mount_nfs.c replicated.o
diff --git a/modules/dclist.c b/modules/dclist.c
new file mode 100644
index 0000000..5b0e577
--- /dev/null
+++ b/modules/dclist.c
@@ -0,0 +1,785 @@
+/*
+ * Copyright 2009 Ian Kent <raven at themaw.net>
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * This module was apapted from code contained in the Samba distribution
+ * file source/libads/dns.c which contained the following copyright
+ * information:
+ *
+ * Unix SMB/CIFS implementation.
+ * DNS utility library
+ * Copyright (C) Gerald (Jerry) Carter           2006.
+ * Copyright (C) Jeremy Allison                  2007.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <stdlib.h>
+#include <string.h>
+#include <resolv.h>
+#include <netdb.h>
+#include <ldap.h>
+#include <sys/param.h>
+#include <errno.h>
+
+#include "automount.h"
+#include "dclist.h"
+
+#define	MAX_DNS_PACKET_SIZE	0xffff
+#define	MAX_DNS_NAME_LENGTH	MAXHOSTNAMELEN
+/* The longest time we will cache dns srv records */
+#define MAX_TTL			(60*60*1) /* 1 hours */
+
+#ifdef NS_HFIXEDSZ	/* Bind 8/9 interface */
+#if !defined(C_IN)	/* AIX 5.3 already defines C_IN */
+#  define C_IN		ns_c_in
+#endif
+#if !defined(T_A)	/* AIX 5.3 already defines T_A */
+#  define T_A   	ns_t_a
+#endif
+
+#  define T_SRV 	ns_t_srv
+#if !defined(T_NS)	/* AIX 5.3 already defines T_NS */
+#  define T_NS 		ns_t_ns
+#endif
+#else
+#  ifdef HFIXEDSZ
+#    define NS_HFIXEDSZ HFIXEDSZ
+#  else
+#    define NS_HFIXEDSZ sizeof(HEADER)
+#  endif	/* HFIXEDSZ */
+#  ifdef PACKETSZ
+#    define NS_PACKETSZ	PACKETSZ
+#  else	/* 512 is usually the default */
+#    define NS_PACKETSZ	512
+#  endif	/* PACKETSZ */
+#  define T_SRV 	33
+#endif
+
+#define SVAL(buf, pos) (*(const uint16_t *)((const char *)(buf) + (pos)))
+#define IVAL(buf, pos) (*(const uint32_t *)((const char *)(buf) + (pos)))
+
+#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
+
+#define RSVAL(buf, pos) SREV(SVAL(buf, pos))
+#define RIVAL(buf, pos) IREV(IVAL(buf, pos))
+
+#define QSORT_CAST	(int (*)(const void *, const void *))
+
+/* DNS query section in replies */
+
+struct dns_query {
+	const char *hostname;
+	uint16_t type;
+	uint16_t in_class;
+};
+
+/* DNS RR record in reply */
+
+struct dns_rr {
+	const char *hostname;
+	uint16_t type;
+	uint16_t in_class;
+	uint32_t ttl;
+	uint16_t rdatalen;
+	uint8_t *rdata;
+};
+
+/* SRV records */
+
+struct dns_rr_srv {
+	const char *hostname;
+	uint16_t priority;
+	uint16_t weight;
+	uint16_t port;
+	uint32_t ttl;
+};
+
+static pthread_mutex_t dclist_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void dclist_mutex_lock(void)
+{
+	int status = pthread_mutex_lock(&dclist_mutex);
+	if (status)
+		fatal(status);
+	return;
+}
+
+static void dclist_mutex_unlock(void)
+{
+	int status = pthread_mutex_unlock(&dclist_mutex);
+	if (status)
+		fatal(status);
+	return;
+}
+
+static int dns_parse_query(unsigned int logopt,
+			   uint8_t *start, uint8_t *end,
+			   uint8_t **ptr, struct dns_query *q)
+{
+	uint8_t *p = *ptr;
+	char hostname[MAX_DNS_NAME_LENGTH];
+	char buf[MAX_ERR_BUF];
+	int namelen;
+
+	if (!start || !end || !q || !*ptr)
+		return 0;
+
+	memset(q, 0, sizeof(*q));
+
+	/* See RFC 1035 for details. If this fails, then return. */
+
+	namelen = dn_expand(start, end, p, hostname, sizeof(hostname));
+	if (namelen < 0) {
+		error(logopt, "failed to expand query hostname");
+		return 0;
+	}
+
+	p += namelen;
+	q->hostname = strdup(hostname);
+	if (!q) {
+		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		error(logopt, "strdup: %s", estr);
+		return 0;
+	}
+
+	/* check that we have space remaining */
+
+	if (p + 4 > end) {
+		error(logopt, "insufficient buffer space for result");
+		free((void *) q->hostname);
+		return 0;
+	}
+
+	q->type     = RSVAL(p, 0);
+	q->in_class = RSVAL(p, 2);
+	p += 4;
+
+	*ptr = p;
+
+	return 1;
+}
+
+static int dns_parse_rr(unsigned int logopt,
+			uint8_t *start, uint8_t *end,
+			uint8_t **ptr, struct dns_rr *rr)
+{
+	uint8_t *p = *ptr;
+	char hostname[MAX_DNS_NAME_LENGTH];
+	char buf[MAX_ERR_BUF];
+	int namelen;
+
+	if (!start || !end || !rr || !*ptr)
+		return 0;
+
+	memset(rr, 0, sizeof(*rr));
+
+	/* pull the name from the answer */
+
+	namelen = dn_expand(start, end, p, hostname, sizeof(hostname));
+	if (namelen < 0) {
+		error(logopt, "failed to expand query hostname");
+		return 0;
+	}
+	p += namelen;
+	rr->hostname = strdup(hostname);
+	if (!rr->hostname) {
+		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		error(logopt, "strdup: %s", estr);
+		return 0;
+	}
+
+	/* check that we have space remaining */
+
+	if (p + 10 > end) {
+		error(logopt, "insufficient buffer space for result");
+		free((void *) rr->hostname);
+		return 0;
+	}
+
+	/* pull some values and then skip onto the string */
+
+	rr->type     = RSVAL(p, 0);
+	rr->in_class = RSVAL(p, 2);
+	rr->ttl      = RIVAL(p, 4);
+	rr->rdatalen = RSVAL(p, 8);
+
+	p += 10;
+
+	/* sanity check the available space */
+
+	if (p + rr->rdatalen > end) {
+		error(logopt, "insufficient buffer space for data");
+		free((void *) rr->hostname);
+		return 0;
+	}
+
+	/* save a point to the rdata for this section */
+
+	rr->rdata = p;
+	p += rr->rdatalen;
+
+	*ptr = p;
+
+	return 1;
+}
+
+static int dns_parse_rr_srv(unsigned int logopt,
+			    uint8_t *start, uint8_t *end,
+			    uint8_t **ptr, struct dns_rr_srv *srv)
+{
+	struct dns_rr rr;
+	uint8_t *p;
+	char dcname[MAX_DNS_NAME_LENGTH];
+	char buf[MAX_ERR_BUF];
+	int namelen;
+
+	if (!start || !end || !srv || !*ptr)
+		return 0;
+
+	/* Parse the RR entry.  Coming out of the this, ptr is at the beginning
+	   of the next record */
+
+	if (!dns_parse_rr(logopt, start, end, ptr, &rr)) {
+		error(logopt, "Failed to parse RR record");
+		return 0;
+	}
+
+	if (rr.type != T_SRV) {
+		error(logopt, "Bad answer type (%d)", rr.type);
+		return 0;
+	}
+
+	p = rr.rdata;
+
+	srv->priority = RSVAL(p, 0);
+	srv->weight   = RSVAL(p, 2);
+	srv->port     = RSVAL(p, 4);
+	srv->ttl      = rr.ttl;
+
+	p += 6;
+
+	namelen = dn_expand(start, end, p, dcname, sizeof(dcname));
+	if (namelen < 0) {
+		error(logopt, "Failed to expand dcname");
+		return 0;
+	}
+
+	srv->hostname = strdup(dcname);
+	if (!srv->hostname) {
+		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		error(logopt, "strdup: %s", estr);
+		return 0;
+	}
+
+	debug(logopt, "Parsed %s [%u, %u, %u]",
+	      srv->hostname, srv->priority, srv->weight, srv->port);
+
+	return 1;
+}
+
+/*********************************************************************
+ Sort SRV record list based on weight and priority.  See RFC 2782.
+*********************************************************************/
+
+static int dnssrvcmp(struct dns_rr_srv *a, struct dns_rr_srv *b)
+{
+	if (a->priority == b->priority) {
+		/* randomize entries with an equal weight and priority */
+		if (a->weight == b->weight)
+			return 0;
+
+		/* higher weights should be sorted lower */
+		if (a->weight > b->weight)
+			return -1;
+		else
+			return 1;
+	}
+
+	if (a->priority < b->priority)
+		return -1;
+
+	return 1;
+}
+
+#define DNS_FAILED_WAITTIME          30
+
+static int dns_send_req(unsigned int logopt,
+			const char *name, int q_type, uint8_t **rbuf,
+			int *resp_length)
+{
+	uint8_t *buffer = NULL;
+	size_t buf_len = 0;
+	int resp_len = NS_PACKETSZ;
+	static time_t last_dns_check = 0;
+	static unsigned int last_dns_status = 0;
+	time_t now = time(NULL);
+	char buf[MAX_ERR_BUF];
+
+	/* Try to prevent bursts of DNS lookups if the server is down */
+
+	/* Protect against large clock changes */
+
+	if (last_dns_check > now)
+		last_dns_check = 0;
+
+	/* IF we had a DNS timeout or a bad server and we are still
+	   in the 30 second cache window, just return the previous
+	   status and save the network timeout. */
+
+	if ((last_dns_status == ETIMEDOUT ||
+	     last_dns_status == ECONNREFUSED) &&
+	     ((last_dns_check + DNS_FAILED_WAITTIME) > now)) {
+		char *estr = strerror_r(last_dns_status, buf, MAX_ERR_BUF);
+		debug(logopt, "Returning cached status (%s)", estr);
+		return last_dns_status;
+	}
+
+	/* Send the Query */
+	do {
+		if (buffer)
+			free(buffer);
+
+		buf_len = resp_len * sizeof(uint8_t);
+
+		if (buf_len) {
+			buffer = malloc(buf_len);
+			if (!buffer) {
+				char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+				error(logopt, "malloc: %s", estr);
+				last_dns_status = ENOMEM;
+				last_dns_check = time(NULL);
+				return last_dns_status;
+			}
+		}
+
+		resp_len = res_query(name, C_IN, q_type, buffer, buf_len);
+		if (resp_len < 0) {
+			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+			error(logopt, "Failed to resolve %s (%s)", name, estr);
+			free(buffer);
+			last_dns_status = ENOENT;
+			last_dns_check = time(NULL);
+			return last_dns_status;
+		}
+
+		/* On AIX, Solaris, and possibly some older glibc systems (e.g. SLES8)
+		   truncated replies never give back a resp_len > buflen
+		   which ends up causing DNS resolve failures on large tcp DNS replies */
+
+		if (buf_len == resp_len) {
+			if (resp_len == MAX_DNS_PACKET_SIZE) {
+				error(logopt,
+				      "DNS reply too large when resolving %s",
+				      name);
+				free(buffer);
+				last_dns_status = EMSGSIZE;
+				last_dns_check = time(NULL);
+				return last_dns_status;
+			}
+
+			resp_len = MIN(resp_len * 2, MAX_DNS_PACKET_SIZE);
+		}
+	} while (buf_len < resp_len && resp_len <= MAX_DNS_PACKET_SIZE);
+
+	*rbuf = buffer;
+	*resp_length = resp_len;
+
+	last_dns_check = time(NULL);
+	last_dns_status = 0;
+
+	return 0;
+}
+
+static int dns_lookup_srv(unsigned int logopt, const char *name,
+			  struct dns_rr_srv **dclist, int *numdcs)
+{
+	uint8_t *buffer = NULL;
+	int resp_len = 0;
+	struct dns_rr_srv *dcs = NULL;
+	int query_count, answer_count;
+	uint8_t *p = buffer;
+	int rrnum;
+	int idx = 0;
+	char buf[MAX_ERR_BUF];
+	int ret;
+
+	if (!name || !dclist)
+		return -EINVAL;
+
+	/* Send the request.  May have to loop several times in case
+	   of large replies */
+
+	ret = dns_send_req(logopt, name, T_SRV, &buffer, &resp_len);
+	if (ret) {
+		error(logopt, "Failed to send DNS query");
+		return ret;
+	}
+	p = buffer;
+
+	/* For some insane reason, the ns_initparse() et. al. routines are only
+	   available in libresolv.a, and not the shared lib.  Who knows why....
+	   So we have to parse the DNS reply ourselves */
+
+	/* Pull the answer RR's count from the header.
+	 * Use the NMB ordering macros */
+
+	query_count      = RSVAL(p, 4);
+	answer_count     = RSVAL(p, 6);
+
+	debug(logopt,
+	      "%d records returned in the answer section.",
+	       answer_count);
+
+	if (answer_count) {
+		dcs = malloc(sizeof(struct dns_rr_srv) * answer_count);
+		if (!dcs) {
+			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+			error(logopt, "malloc: %s", estr);
+			free(buffer);
+			return ENOMEM;
+		}
+	}
+
+	/* now skip the header */
+
+	p += NS_HFIXEDSZ;
+
+	/* parse the query section */
+
+	for (rrnum = 0; rrnum < query_count; rrnum++) {
+		struct dns_query q;
+
+		ret = dns_parse_query(logopt, buffer, buffer+resp_len, &p, &q);
+		if (!ret) {
+			error(logopt,
+			      "Failed to parse query record [%d]", rrnum);
+			free(buffer);
+			free(dcs);
+			return EBADMSG;
+		}
+	}
+
+	/* now we are at the answer section */
+
+	for (rrnum = 0; rrnum < answer_count; rrnum++) {
+		ret = dns_parse_rr_srv(logopt,
+				       buffer, buffer+resp_len,
+				       &p, &dcs[rrnum]);
+		if (!ret) {
+			error(logopt,
+			      "Failed to parse answer record [%d]", rrnum);
+			free(buffer);
+			free(dcs);
+			return EBADMSG;
+		}
+	}
+	idx = rrnum;
+
+	qsort(dcs, idx, sizeof(struct dns_rr_srv), QSORT_CAST dnssrvcmp);
+
+	*dclist = dcs;
+	*numdcs = idx;
+
+	return 0;
+}
+
+static char *escape_dn_commas(const char *uri)
+{
+	size_t len = strlen(uri);
+	char *new, *tmp, *ptr;
+
+	ptr = (char *) uri;
+	while (*ptr) {
+		if (*ptr == '\\')
+			ptr += 2;
+		if (*ptr == ',')
+			len += 2;
+		ptr++;
+	}
+
+	new = malloc(len + 1);
+	if (!new)
+		return NULL;
+	memset(new, 0, len + 1);
+
+	ptr = (char *) uri;
+	tmp = new;
+	while (*ptr) {
+		if (*ptr == '\\') {
+			ptr++;
+			*tmp++ = *ptr++;
+			continue;
+		}
+		if (*ptr == ',') {
+			strcpy(tmp, "%2c");
+			ptr++;
+			tmp += 3;
+			continue;
+		}
+		*tmp++ = *ptr++;
+	}
+
+	return new;
+}
+
+void free_dclist(struct dclist *dclist)
+{
+	if (dclist->uri)
+		free((void *) dclist->uri);
+	free(dclist);
+}
+
+static char *getdnsdomainname(unsigned int logopt)
+{
+	struct addrinfo hints, *ni;
+	char name[MAX_DNS_NAME_LENGTH + 1];
+	char buf[MAX_ERR_BUF];
+	char *dnsdomain = NULL;
+	char *ptr;
+	int ret;
+
+	memset(name, 0, sizeof(name));
+	if (gethostname(name, MAX_DNS_NAME_LENGTH) == -1) {
+		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		error(logopt, "gethostname: %s", estr);
+		return NULL;
+	}
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_flags = AI_CANONNAME;
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_DGRAM;
+
+	ret = getaddrinfo(name, NULL, &hints, &ni);
+	if (ret) {
+		error(logopt, "hostname lookup failed: %s", gai_strerror(ret));
+		return NULL;
+	}
+
+	ptr = ni->ai_canonname;
+	while (*ptr && *ptr != '.')
+		ptr++;
+
+	if (*++ptr)
+		dnsdomain = strdup(ptr);
+
+	freeaddrinfo(ni);
+
+	return dnsdomain;
+}
+
+struct dclist *get_dc_list(unsigned int logopt, const char *uri)
+{
+	LDAPURLDesc *ludlist = NULL;
+	LDAPURLDesc **ludp;
+	struct dns_rr_srv *dcs;
+	unsigned int min_ttl = MAX_TTL;
+	struct dclist *dclist = NULL;;
+	char buf[MAX_ERR_BUF];
+	char *dn_uri, *esc_uri;
+	char *domain;
+	char *list;
+	int numdcs;
+	int ret;
+
+	if (strcmp(uri, "ldap:///") && strcmp(uri, "ldaps:///")) {
+		dn_uri = strdup(uri);
+		if (!dn_uri) {
+			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+			error(logopt, "strdup: %s", estr);
+			return NULL;
+		}
+	} else {
+		char *dnsdomain;
+		char *hdn;
+
+		dnsdomain = getdnsdomainname(logopt);
+		if (!dnsdomain) {
+			error(logopt, "failed to get dns domainname");
+			return NULL;
+		}
+
+		if (ldap_domain2dn(dnsdomain, &hdn) || hdn == NULL) {
+			error(logopt,
+			      "Could not turn domain \"%s\" into a dn\n",
+			      dnsdomain);
+			free(dnsdomain);
+			return NULL;
+		}
+		free(dnsdomain);
+
+		dn_uri = malloc(strlen(uri) + strlen(hdn) + 1);
+		if (!dn_uri) {
+			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+			error(logopt, "malloc: %s", estr);
+			ber_memfree(hdn);
+			return NULL;
+		}
+
+		strcpy(dn_uri, uri);
+		strcat(dn_uri, hdn);
+		ber_memfree(hdn);
+	}
+
+	esc_uri = escape_dn_commas(dn_uri);
+	if (!esc_uri) {
+		error(logopt, "Could not escape commas in uri %s", dn_uri);
+		free(dn_uri);
+		return NULL;
+	}
+
+	ret = ldap_url_parse(esc_uri, &ludlist);
+	if (ret != LDAP_URL_SUCCESS) {
+		error(logopt, "Could not parse uri %s (%d)", dn_uri, ret);
+		free(esc_uri);
+		free(dn_uri);
+		return NULL;
+	}
+
+	free(esc_uri);
+
+	if (!ludlist) {
+		error(logopt, "No dn found in uri %s", dn_uri);
+		free(dn_uri);
+		return NULL;
+	}
+
+	free(dn_uri);
+
+	dclist = malloc(sizeof(struct dclist));
+	if (!dclist) {
+		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		error(logopt, "malloc: %s", estr);
+		ldap_free_urldesc(ludlist);
+		return NULL;
+	}
+	memset(dclist, 0, sizeof(struct dclist));
+
+	list = NULL;
+	for (ludp = &ludlist; *ludp != NULL;) {
+		LDAPURLDesc *lud = *ludp;
+		size_t req_len, len;
+		char *request = NULL;
+		char *tmp;
+		int i;
+
+		if (!lud->lud_dn && !lud->lud_dn[0] &&
+		   (!lud->lud_host || !lud->lud_host[0])) {
+			*ludp = lud->lud_next;
+			continue;
+		}
+
+		domain = NULL;
+		if (ldap_dn2domain(lud->lud_dn, &domain) || domain == NULL) {
+			error(logopt,
+			      "Could not turn dn \"%s\" into a domain",
+			      lud->lud_dn);
+			*ludp = lud->lud_next;
+			continue;
+		}
+
+		debug(logopt, "doing lookup of SRV RRs for domain %s", domain);
+
+		req_len = sizeof("_ldap._tcp.") + strlen(domain);
+		request = malloc(req_len);
+		if (!request) {
+			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+			error(logopt, "malloc: %s", estr);
+			goto out_error;
+		}
+
+		ret = snprintf(request, req_len, "_ldap._tcp.%s", domain);
+		if (ret >= req_len) {
+			free(request);
+			goto out_error;
+		}
+
+		dclist_mutex_lock();
+		if (dns_lookup_srv(logopt, request, &dcs, &numdcs)) {
+			error(logopt,
+			      "DNS SRV query failed for domain %s", domain);
+			dclist_mutex_unlock();
+			free(request);
+			goto out_error;
+		}
+		dclist_mutex_unlock();
+		free(request);
+
+		len = strlen(lud->lud_scheme);
+		len += sizeof("://");
+		len *= numdcs;
+
+		for (i = 0; i < numdcs; i++) {
+			if (dcs[i].ttl > 0 && dcs[i].ttl < min_ttl)
+				min_ttl = dcs[i].ttl;
+			len += strlen(dcs[i].hostname);
+			if (dcs[i].port > 0)
+				len += sizeof(":65535");
+		}
+
+		tmp = realloc(list, len);
+		if (!tmp) {
+			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+			error(logopt, "realloc: %s", estr);
+			goto out_error;
+		}
+
+		if (!list)
+			memset(tmp, 0, len);
+		else
+			strcat(tmp, " ");
+
+		for (i = 0; i < numdcs; i++) {
+			if (i > 0)
+				strcat(tmp, " ");
+			strcat(tmp, lud->lud_scheme);
+			strcat(tmp, "://");
+			strcat(tmp, dcs[i].hostname);
+			if (dcs[i].port > 0) {
+				char port[7];
+				ret = snprintf(port, 7, ":%d", dcs[i].port);
+				if (ret > 6) {
+					error(logopt,
+					      "invalid port: %u", dcs[i].port);
+					goto out_error;
+				}
+				strcat(tmp, port);
+			}
+		}
+		list = tmp;
+
+		*ludp = lud->lud_next;
+		ber_memfree(domain);
+	}
+
+	ldap_free_urldesc(ludlist);
+
+	dclist->expire = time(NULL) + min_ttl;
+	dclist->uri = list;
+
+	return dclist;
+
+out_error:
+	if (list)
+		free(list);
+	if (domain)
+		ber_memfree(domain);
+	ldap_free_urldesc(ludlist);
+	free_dclist(dclist);
+	return NULL;
+}
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index a847622..f6b3f42 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -643,14 +643,26 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt)
 	LDAP *ldap = NULL;
 	struct ldap_uri *this;
 	struct list_head *p, *first;
+	struct dclist *dclist = NULL;
+	char *uri = NULL;
 
-	/* Try each uri in list, add connect fails to tmp list */
 	uris_mutex_lock(ctxt);
+	if (ctxt->dclist) {
+		dclist = ctxt->dclist;
+		if (ctxt->dclist->expire < time(NULL)) {
+			free_dclist(ctxt->dclist);
+			ctxt->dclist = NULL;
+			dclist = NULL;
+		}
+	}
 	if (!ctxt->uri)
 		first = ctxt->uris;
 	else
 		first = &ctxt->uri->list;
 	uris_mutex_unlock(ctxt);
+
+
+	/* Try each uri, save point in server list upon success */
 	p = first->next;
 	while(p != first) {
 		/* Skip list head */
@@ -659,25 +671,62 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt)
 			continue;
 		}
 		this = list_entry(p, struct ldap_uri, list);
-		debug(logopt, "trying server %s", this->uri);
-		ldap = connect_to_server(logopt, this->uri, ctxt);
+		if (!strstr(this->uri, ":///"))
+			uri = strdup(this->uri);
+		else {
+			if (dclist)
+				uri = strdup(dclist->uri);
+			else {
+				struct dclist *tmp;
+				tmp = get_dc_list(logopt, this->uri);
+				if (!tmp) {
+					p = p->next;
+					continue;
+				}
+				dclist = tmp;
+				uri = strdup(dclist->uri);
+			}
+		}
+		if (!uri) {
+			p = p->next;
+			continue;
+		}
+		debug(logopt, "trying server uri %s", uri);
+		ldap = connect_to_server(logopt, uri, ctxt);
 		if (ldap) {
-			info(logopt, "connected to uri %s", this->uri);
-			uris_mutex_lock(ctxt);
-			ctxt->uri = this;
-			uris_mutex_unlock(ctxt);
+			info(logopt, "connected to uri %s", uri);
+			free(uri);
 			break;
 		}
+		free(uri);
+		uri = NULL;
+		free_dclist(dclist);
+		dclist = NULL;
 		p = p->next;
 	}
 
+	uris_mutex_lock(ctxt);
+	if (ldap)
+		ctxt->uri = this;
+	if (dclist) {
+		if (!ctxt->dclist)
+			ctxt->dclist = dclist;
+		else {
+			if (ctxt->dclist != dclist) {
+				free_dclist(ctxt->dclist);
+				ctxt->dclist = dclist;
+			}
+		}
+	}
+	uris_mutex_unlock(ctxt);
+
 	return ldap;
 }
 
 static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt)
 {
-	struct ldap_uri *this;
 	LDAP *ldap;
+	char *uri;
 
 	if (ctxt->server || !ctxt->uris) {
 		ldap = do_connect(logopt, ctxt->server, ctxt);
@@ -692,9 +741,20 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt)
 	}
 
 	uris_mutex_lock(ctxt);
-	this = ctxt->uri;
+	if (ctxt->dclist)
+		uri = strdup(ctxt->dclist->uri);
+	else
+		uri = strdup(ctxt->uri->uri);
 	uris_mutex_unlock(ctxt);
-	ldap = do_connect(logopt, this->uri, ctxt);
+
+	if (!uri) {
+		char buf[MAX_ERR_BUF];
+		char *estr = strerror_r(errno, buf, sizeof(buf));
+		crit(logopt, MODPREFIX "strdup: %s", estr);
+		return NULL;
+	}
+
+	ldap = do_connect(logopt, uri, ctxt);
 #ifdef WITH_SASL
 	/*
 	 * Dispose of the sasl authentication connection and try the
@@ -702,9 +762,11 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt)
 	 */
 	if (!ldap) {
 		autofs_sasl_dispose(ctxt);
-		ldap = connect_to_server(logopt, this->uri, ctxt);
+		ldap = connect_to_server(logopt, uri, ctxt);
 	}
 #endif
+	free(uri);
+
 	if (ldap)
 		return ldap;
 
@@ -1296,6 +1358,8 @@ static void free_context(struct lookup_context *ctxt)
 		fatal(ret);
 	if (ctxt->sdns)
 		defaults_free_searchdns(ctxt->sdns);
+	if (ctxt->dclist)
+		free_dclist(ctxt->dclist);
 	free(ctxt);
 
 	return;
diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in
index 97e20fe..37448ea 100644
--- a/redhat/autofs.sysconfig.in
+++ b/redhat/autofs.sysconfig.in
@@ -50,6 +50,17 @@ BROWSE_MODE="no"
 # 	     Map entries that include a server name override
 # 	     this option.
 #
+#	     This configuration option can also be used to
+#	     request autofs lookup SRV RRs for a domain of
+#	     the form <proto>:///[<domain dn>]. Note that a
+#	     trailing "/" is not allowed when using this form.
+#	     If the domain dn is not specified the dns domain
+#	     name (if any) is used to construct the domain dn
+#	     for the SRV RR lookup. The server list returned
+#	     from an SRV RR lookup is refreshed according to
+#	     the minimum ttl found in the SRV RR records or
+#	     after one hour, whichever is less.
+#
 #LDAP_URI=""
 #
 # LDAP__TIMEOUT - timeout value for the synchronous API  calls
diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in
index 62084c2..7dee5fd 100644
--- a/samples/autofs.conf.default.in
+++ b/samples/autofs.conf.default.in
@@ -48,6 +48,17 @@ BROWSE_MODE="no"
 # 	     Map entries that include a server name override
 # 	     this option.
 #
+#	     This configuration option can also be used to
+#	     request autofs lookup SRV RRs for a domain of
+#	     the form <proto>:///[<domain dn>]. Note that a
+#	     trailing "/" is not allowed when using this form.
+#	     If the domain dn is not specified the dns domain
+#	     name (if any) is used to construct the domain dn
+#	     for the SRV RR lookup. The server list returned
+#	     from an SRV RR lookup is refreshed according to
+#	     the minimum ttl found in the SRV RR records or
+#	     after one hour, whichever is less.
+#
 #LDAP_URI=""
 #
 # LDAP__TIMEOUT - timeout value for the synchronous API  calls


Index: autofs.spec
===================================================================
RCS file: /cvs/pkgs/rpms/autofs/devel/autofs.spec,v
retrieving revision 1.279
retrieving revision 1.280
diff -u -p -r1.279 -r1.280
--- autofs.spec	16 Apr 2009 04:03:30 -0000	1.279
+++ autofs.spec	18 May 2009 02:21:02 -0000	1.280
@@ -4,7 +4,7 @@
 Summary: A tool for automatically mounting and unmounting filesystems
 Name: autofs
 Version: 5.0.4
-Release: 26
+Release: 28
 Epoch: 1
 License: GPLv2+
 Group: System Environment/Daemons
@@ -51,6 +51,15 @@ Patch38: autofs-5.0.4-fix-st_remove_task
 Patch39: autofs-5.0.4-reset-flex-scanner-when-setting-buffer.patch
 Patch40: autofs-5.0.4-zero-s_magic-is-valid.patch
 Patch41: autofs-5.0.4-use-percent-hack-for-master.patch
+Patch42: autofs-5.0.4-use-intr-as-hosts-mount-default.patch
+Patch43: autofs-5.0.4-fix-kernel-includes.patch
+Patch44: autofs-5.0.4-dont-umount-existing-direct-mount-on-reread.patch
+Patch45: autofs-5.0.4-library-reload-fix-update-fix.patch
+Patch46: autofs-5.0.4-improve-manual-umount-recovery.patch
+Patch47: autofs-5.0.4-dont-fail-on-ipv6-address-adding-host.patch
+Patch48: autofs-5.0.4-always-read-file-maps-multi-map-fix.patch
+Patch49: autofs-5.0.4-always-read-file-maps-key-lookup-fixes.patch
+Patch50: autofs-5.0.4-use-srv-query-for-domain-dn.patch
 Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 BuildRequires: autoconf, hesiod-devel, openldap-devel, bison, flex, libxml2-devel, cyrus-sasl-devel, openssl-devel module-init-tools util-linux nfs-utils e2fsprogs libtirpc-devel
 Requires: kernel >= 2.6.17
@@ -133,6 +142,15 @@ echo %{version}-%{release} > .version
 %patch39 -p1
 %patch40 -p1
 %patch41 -p1
+%patch42 -p1
+%patch43 -p1
+%patch44 -p1
+%patch45 -p1
+%patch46 -p1
+%patch47 -p1
+%patch48 -p1
+%patch49 -p1
+%patch50 -p1
 
 %build
 #CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=/usr --libdir=%{_libdir}
@@ -185,6 +203,17 @@ fi
 %{_libdir}/autofs/
 
 %changelog
+* Mon May 18 2009 Ian Kent <ikent at redhat.com> - 1:5.0.4-28
+- use intr option as hosts mount default.
+- sync kernel includes with upstream kernel.
+- dont umount existing direct mount on master re-read.
+- fix incorrect shutdown introduced by library relaod fixes.
+- improve manual umount recovery.
+- dont fail on ipv6 address when adding host.
+- always read file maps multi map fix.
+- always read file maps key lookup fixes.
+- add support for LDAP_URI="ldap:///<domain db>" SRV RR lookup.
+
 * Thu Apr 16 2009 Ian Kent <ikent at redhat.com> - 1:5.0.4-26
 - fix lsb init script header.
 - fix memory leak reading ldap master map.




More information about the scm-commits mailing list