Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 290314bcd05f8d672d45e72918073e43 > files > 147

autofs-5.0.1-0.rc2.102.src.rpm

diff -up autofs-5.0.1/redhat/autofs.sysconfig.in.ldap-search-basedn-list autofs-5.0.1/redhat/autofs.sysconfig.in
--- autofs-5.0.1/redhat/autofs.sysconfig.in.ldap-search-basedn-list	2007-10-18 19:36:24.000000000 +0800
+++ autofs-5.0.1/redhat/autofs.sysconfig.in	2007-10-18 19:36:42.000000000 +0800
@@ -21,6 +21,14 @@
 #
 #LOGGING="none"
 #
+# Define base dn for map dn lookup.
+#
+# SEARCH_BASE - base dn to use for searching for map search dn.
+# 		Multiple entries can be given and they are checked
+# 		in the order they occur here.
+#
+#SEARCH_BASE=""
+#
 # Define the LDAP schema to used for lookups
 #
 # If no schema is set autofs will check each of the schemas
--- autofs-5.0.1/include/lookup_ldap.h.ldap-search-basedn-list	2007-10-18 19:36:24.000000000 +0800
+++ autofs-5.0.1/include/lookup_ldap.h	2007-10-18 19:36:42.000000000 +0800
@@ -17,6 +17,11 @@
 	char *value_attr;
 };
 
+struct ldap_searchdn {
+	char *basedn;
+	struct ldap_searchdn *next;
+};
+
 struct lookup_context {
 	char *mapname;
 
@@ -31,6 +36,10 @@
 	/* LDAP lookup configuration */
 	struct ldap_schema *schema;
 
+	/* List of base dns for searching */
+	char *cur_host;
+	struct ldap_searchdn *sdns;
+
 	/* TLS and SASL authentication information */
 	char        *auth_conf;
 	unsigned     use_tls;
--- autofs-5.0.1/include/defaults.h.ldap-search-basedn-list	2007-10-18 19:36:24.000000000 +0800
+++ autofs-5.0.1/include/defaults.h	2007-10-18 19:36:42.000000000 +0800
@@ -37,6 +37,9 @@
 #define DEFAULT_APPEND_OPTIONS		1
 #define DEFAULT_AUTH_CONF_FILE		AUTOFS_MAP_DIR "/autofs_ldap_auth.conf"
 
+struct ldap_schema;
+struct ldap_searchdn;
+
 unsigned int defaults_read_config(void);
 const char *defaults_get_master_map(void);
 unsigned int defaults_get_timeout(void);
@@ -45,6 +48,8 @@
 const char *defaults_get_ldap_server(void);
 struct ldap_schema *defaults_get_default_schema(void);
 struct ldap_schema *defaults_get_schema(void);
+struct ldap_searchdn *defaults_get_searchdns(void);
+void defaults_free_searchdns(struct ldap_searchdn *);
 unsigned int defaults_get_append_options(void);
 const char *defaults_get_auth_conf_file(void);
 
--- autofs-5.0.1/modules/lookup_ldap.c.ldap-search-basedn-list	2007-10-18 19:36:24.000000000 +0800
+++ autofs-5.0.1/modules/lookup_ldap.c	2007-10-18 19:36:42.000000000 +0800
@@ -171,10 +171,207 @@
 	return ldap;
 }
 
+static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
+{
+	char buf[PARSE_MAX_BUF];
+	char *query, *dn;
+	LDAPMessage *result = NULL, *e;
+	struct ldap_searchdn *sdns = NULL;
+	char *attrs[2];
+	int scope;
+	int rv, l;
+
+	attrs[0] = LDAP_NO_ATTRS;
+	attrs[1] = NULL;
+
+	if (!ctxt->mapname && !ctxt->base) {
+		error(LOGOPT_ANY, MODPREFIX "no master map to lookup");
+		return 0;
+	}
+
+	/* Build a query string. */
+	l = strlen("(objectclass=)") + strlen(class) + 1;
+	if (ctxt->mapname)
+		l += strlen(key) + strlen(ctxt->mapname) + strlen("(&(=))");
+
+	query = alloca(l);
+	if (query == NULL) {
+		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		crit(LOGOPT_ANY, MODPREFIX "alloca: %s", estr);
+		return NSS_STATUS_UNAVAIL;
+	}
+
+	/*
+	 * If we have a master mapname construct a query using it
+	 * otherwise assume the base dn will catch it.
+	 */
+	if (ctxt->mapname) {
+		if (sprintf(query, "(&(objectclass=%s)(%s=%.*s))", class,
+		     key, (int) strlen(ctxt->mapname), ctxt->mapname) >= l) {
+			debug(LOGOPT_NONE,
+			      MODPREFIX "error forming query string");
+			return 0;
+		}
+		scope = LDAP_SCOPE_SUBTREE;
+	} else {
+		if (sprintf(query, "(objectclass=%s)", class) >= l) {
+			debug(LOGOPT_NONE,
+			      MODPREFIX "error forming query string");
+			return 0;
+		}
+		scope = LDAP_SCOPE_SUBTREE;
+	}
+	query[l] = '\0';
+
+	if (!ctxt->base) {
+		sdns = defaults_get_searchdns();
+		if (sdns)
+			ctxt->sdns = sdns;
+	}
+
+	if (!sdns)
+		rv = ldap_search_s(ldap, ctxt->base,
+				   scope, query, attrs, 0, &result);
+	else {
+		struct ldap_searchdn *this = sdns;
+
+		debug(LOGOPT_NONE, MODPREFIX
+			      "check search base list");
+
+		while (this) {
+			rv = ldap_search_s(ldap, this->basedn,
+					   scope, query, attrs, 0, &result);
+
+			if ((rv == LDAP_SUCCESS) && result) {
+				debug(LOGOPT_NONE, MODPREFIX
+				      "found search base under %s",
+				      this->basedn);
+				break;
+			}
+
+			this = this->next;
+
+			if (result) {
+				ldap_msgfree(result);
+				result = NULL;
+			}
+		}
+	}
+
+	if ((rv != LDAP_SUCCESS) || !result) {
+		error(LOGOPT_NONE,
+		      MODPREFIX "query failed for %s: %s",
+		      query, ldap_err2string(rv));
+		return 0;
+	}
+
+	e = ldap_first_entry(ldap, result);
+	if (e) {
+		dn = ldap_get_dn(ldap, e);
+		debug(LOGOPT_NONE, MODPREFIX "query dn %s", dn);
+		ldap_msgfree(result);
+	} else {
+		debug(LOGOPT_NONE,
+		      MODPREFIX "query succeeded, no matches for %s",
+		      query);
+		ldap_msgfree(result);
+		return 0;
+	}
+
+	ctxt->qdn = dn;
+
+	return 1;
+}
+
+static struct ldap_schema *alloc_common_schema(struct ldap_schema *s)
+{
+	struct ldap_schema *schema;
+	char *mc, *ma, *ec, *ea, *va;
+
+	mc = strdup(s->map_class);
+	if (!mc)
+		return NULL;
+
+	ma = strdup(s->map_attr);
+	if (!ma) {
+		free(mc);
+		return NULL;
+	}
+
+	ec = strdup(s->entry_class);
+	if (!ec) {
+		free(mc);
+		free(ma);
+		return NULL;
+	}
+
+	ea = strdup(s->entry_attr);
+	if (!ea) {
+		free(mc);
+		free(ma);
+		free(ec);
+		return NULL;
+	}
+
+	va = strdup(s->value_attr);
+	if (!va) {
+		free(mc);
+		free(ma);
+		free(ec);
+		free(ea);
+		return NULL;
+	}
+
+	schema = malloc(sizeof(struct ldap_schema));
+	if (!schema) {
+		free(mc);
+		free(ma);
+		free(ec);
+		free(ea);
+		free(va);
+		return NULL;
+	}
+
+	schema->map_class = mc;
+	schema->map_attr = ma;
+	schema->entry_class = ec;
+	schema->entry_attr = ea;
+	schema->value_attr = va;
+
+	return schema;
+}
+
+static int find_query_dn(LDAP *ldap, struct lookup_context *ctxt)
+{
+	struct ldap_schema *schema;
+	unsigned int i;
+
+	if (ctxt->schema)
+		return 0;
+
+	for (i = 0; i < common_schema_count; i++) {
+		const char *class = common_schema[i].map_class;
+		const char *key = common_schema[i].map_attr;
+		if (get_query_dn(ldap, ctxt, class, key)) {
+			schema = alloc_common_schema(&common_schema[i]);
+			if (!schema) {
+				error(LOGOPT_ANY,
+				      MODPREFIX "failed to allocate schema");
+				return 0;
+			}
+			ctxt->schema = schema;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
 static LDAP *do_connect(struct lookup_context *ctxt)
 {
 	LDAP *ldap;
-	int rv;
+	char *host = NULL, *nhost;
+	int rv, need_base = 1;
 
 	ldap = init_ldap_connection(ctxt);
 	if (!ldap)
@@ -204,6 +401,61 @@
 		return NULL;
 	}
 
+	rv = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host);
+        if (rv != LDAP_SUCCESS || !host) {
+		unbind_ldap_connection(ldap, ctxt);
+		debug(LOGOPT_ANY, "failed to get hostname for connection");
+		return NULL;
+	}
+
+	nhost = strdup(host);
+	if (!nhost) {
+		unbind_ldap_connection(ldap, ctxt);
+		debug(LOGOPT_ANY, "failed to alloc context for hostname");
+		return NULL;
+	}
+	ldap_memfree(host);
+
+	if (!ctxt->cur_host) {
+		ctxt->cur_host = nhost;
+		/* Check if schema defined in conf first time only */
+		ctxt->schema = defaults_get_schema();
+	} else {
+		/* If connection host has changed update */
+		if (strcmp(ctxt->cur_host, nhost)) {
+			free(ctxt->cur_host);
+			ctxt->cur_host = nhost;
+		} else {
+			free(nhost);
+			need_base = 0;
+		}
+	}
+
+	if (!need_base)
+		return ldap;
+
+	/*
+	 * If the schema isn't defined in the configuration then check for
+	 * presence of a map dn with a the common schema. Then calculate the
+	 * base dn for searches.
+	 */
+	if (!ctxt->schema) {
+		if (!find_query_dn(ldap, ctxt)) {
+			unbind_ldap_connection(ldap, ctxt);
+			error(LOGOPT_ANY,
+		      	      MODPREFIX "failed to find valid query dn");
+			return NULL;
+		}
+	} else {
+		const char *class = ctxt->schema->map_class;
+		const char *key = ctxt->schema->map_attr;
+		if (!get_query_dn(ldap, ctxt, class, key)) {
+			unbind_ldap_connection(ldap, ctxt);
+			error(LOGOPT_ANY, MODPREFIX "failed to get query dn");
+			return NULL;
+		}
+	}
+
 	return ldap;
 }
 
@@ -769,175 +1021,17 @@
 		ldap_memfree(ctxt->qdn);
 	if (ctxt->server)
 		free(ctxt->server);
+	if (ctxt->cur_host)
+		free(ctxt->cur_host);
 	if (ctxt->base)
 		free(ctxt->base);
+	if (ctxt->sdns)
+		defaults_free_searchdns(ctxt->sdns);
 	free(ctxt);
 
 	return;
 }
 
-static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
-{
-	char buf[PARSE_MAX_BUF];
-	char *query, *dn;
-	LDAPMessage *result, *e;
-	char *attrs[2];
-	int scope;
-	int rv, l;
-
-	attrs[0] = LDAP_NO_ATTRS;
-	attrs[1] = NULL;
-
-	if (!ctxt->mapname && !ctxt->base) {
-		error(LOGOPT_ANY, MODPREFIX "no master map to lookup");
-		return 0;
-	}
-
-	/* Build a query string. */
-	l = strlen("(objectclass=)") + strlen(class) + 1;
-	if (ctxt->mapname)
-		l += strlen(key) + strlen(ctxt->mapname) + strlen("(&(=))");
-
-	query = alloca(l);
-	if (query == NULL) {
-		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-		crit(LOGOPT_ANY, MODPREFIX "alloca: %s", estr);
-		return NSS_STATUS_UNAVAIL;
-	}
-
-	/*
-	 * If we have a master mapname construct a query using it
-	 * otherwise assume the base dn will catch it.
-	 */
-	if (ctxt->mapname) {
-		if (sprintf(query, "(&(objectclass=%s)(%s=%.*s))", class,
-		     key, (int) strlen(ctxt->mapname), ctxt->mapname) >= l) {
-			debug(LOGOPT_NONE,
-			      MODPREFIX "error forming query string");
-			return 0;
-		}
-		scope = LDAP_SCOPE_SUBTREE;
-	} else {
-		if (sprintf(query, "(objectclass=%s)", class) >= l) {
-			debug(LOGOPT_NONE,
-			      MODPREFIX "error forming query string");
-			return 0;
-		}
-		scope = LDAP_SCOPE_SUBTREE;
-	}
-	query[l] = '\0';
-
-	rv = ldap_search_s(ldap, ctxt->base, scope, query, attrs, 0, &result);
-
-	if ((rv != LDAP_SUCCESS) || !result) {
-		error(LOGOPT_NONE,
-		      MODPREFIX "query failed for %s: %s",
-		      query, ldap_err2string(rv));
-		return 0;
-	}
-
-	e = ldap_first_entry(ldap, result);
-	if (e) {
-		dn = ldap_get_dn(ldap, e);
-		debug(LOGOPT_NONE, MODPREFIX "query dn %s", dn);
-		ldap_msgfree(result);
-	} else {
-		debug(LOGOPT_NONE,
-		      MODPREFIX "query succeeded, no matches for %s",
-		      query);
-		ldap_msgfree(result);
-		return 0;
-	}
-
-	ctxt->qdn = dn;
-
-	return 1;
-}
-
-static struct ldap_schema *alloc_common_schema(struct ldap_schema *s)
-{
-	struct ldap_schema *schema;
-	char *mc, *ma, *ec, *ea, *va;
-
-	mc = strdup(s->map_class);
-	if (!mc)
-		return NULL;
-
-	ma = strdup(s->map_attr);
-	if (!ma) {
-		free(mc);
-		return NULL;
-	}
-
-	ec = strdup(s->entry_class);
-	if (!ec) {
-		free(mc);
-		free(ma);
-		return NULL;
-	}
-
-	ea = strdup(s->entry_attr);
-	if (!ea) {
-		free(mc);
-		free(ma);
-		free(ec);
-		return NULL;
-	}
-
-	va = strdup(s->value_attr);
-	if (!va) {
-		free(mc);
-		free(ma);
-		free(ec);
-		free(ea);
-		return NULL;
-	}
-
-	schema = malloc(sizeof(struct ldap_schema));
-	if (!schema) {
-		free(mc);
-		free(ma);
-		free(ec);
-		free(ea);
-		free(va);
-		return NULL;
-	}
-
-	schema->map_class = mc;
-	schema->map_attr = ma;
-	schema->entry_class = ec;
-	schema->entry_attr = ea;
-	schema->value_attr = va;
-
-	return schema;
-}
-
-static int find_query_dn(LDAP *ldap, struct lookup_context *ctxt)
-{
-	struct ldap_schema *schema;
-	unsigned int i;
-
-	if (ctxt->schema)
-		return 0;
-
-	for (i = 0; i < common_schema_count; i++) {
-		const char *class = common_schema[i].map_class;
-		const char *key = common_schema[i].map_attr;
-		if (get_query_dn(ldap, ctxt, class, key)) {
-			schema = alloc_common_schema(&common_schema[i]);
-			if (!schema) {
-				error(LOGOPT_ANY,
-				      MODPREFIX "failed to allocate schema");
-				return 0;
-			}
-			ctxt->schema = schema;
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
 /*
  * This initializes a context (persistent non-global data) for queries to
  * this module.  Return zero if we succeed.
@@ -994,31 +1088,6 @@
 		free_context(ctxt);
 		return 1;
 	}
-
-	/*
-	 * Get default schema for queries.
-	 * If the schema isn't defined in the configuration then check for
-	 * presence of a map dn in the common schemas.
-	 */
-	ctxt->schema = defaults_get_schema();
-	if (!ctxt->schema) {
-		if (!find_query_dn(ldap, ctxt)) {
-			unbind_ldap_connection(ldap, ctxt);
-			error(LOGOPT_ANY,
-			      MODPREFIX "failed to find valid query dn");
-			free_context(ctxt);
-			return 1;
-		}
-	} else {
-		const char *class = ctxt->schema->map_class;
-		const char *key = ctxt->schema->map_attr;
-		if (!get_query_dn(ldap, ctxt, class, key)) {
-			unbind_ldap_connection(ldap, ctxt);
-			error(LOGOPT_ANY, MODPREFIX "failed to get query dn");
-			free_context(ctxt);
-			return 1;
-		}
-	}
 	unbind_ldap_connection(ldap, ctxt);
 
 	/* Open the parser, if we can. */
--- autofs-5.0.1/samples/autofs.conf.default.in.ldap-search-basedn-list	2007-10-18 19:36:24.000000000 +0800
+++ autofs-5.0.1/samples/autofs.conf.default.in	2007-10-18 19:36:42.000000000 +0800
@@ -21,6 +21,14 @@
 #
 #LOGGING="none"
 #
+# Define base dn for map dn lookup.
+#
+# SEARCH_BASE - base dn to use for searching for map search dn.
+# 		Multiple entries can be given and they are checked
+# 		in the order they occur here.
+#
+#SEARCH_BASE=""
+#
 # Define the LDAP schema to used for lookups
 #
 # If no schema is set autofs will check each of the schemas
--- autofs-5.0.1/lib/defaults.c.ldap-search-basedn-list	2007-10-18 19:36:24.000000000 +0800
+++ autofs-5.0.1/lib/defaults.c	2007-10-18 19:43:52.000000000 +0800
@@ -32,6 +32,8 @@
 
 #define ENV_LDAP_SERVER			"LDAP_SERVER"
 
+#define SEARCH_BASE			"SEARCH_BASE"
+
 #define ENV_NAME_MAP_OBJ_CLASS		"MAP_OBJECT_CLASS"
 #define ENV_NAME_ENTRY_OBJ_CLASS	"ENTRY_OBJECT_CLASS"
 #define ENV_NAME_MAP_ATTR		"MAP_ATTRIBUTE"
@@ -130,6 +132,52 @@
 	return 0;
 }
 
+static int parse_line(char *line, char **res, char **value)
+{
+	char *key, *val, *trailer;
+	int len;
+
+	key = line;
+
+	if (*key == '#' || !isalpha(*key))
+		return 0;
+
+	while (*key && *key == ' ')
+		key++;
+
+	if (!key)
+		return 0;
+
+	if (!(val = strchr(key, '=')))
+		return 0;
+
+	*val++ = '\0';
+
+	while (*val && (*val == '"' || isblank(*val)))
+		val++;
+
+	len = strlen(val);
+
+	if (val[len - 1] == '\n') {
+		val[len - 1] = '\0';
+		len--;
+	}
+
+	trailer = strchr(val, '#');
+	if (!trailer)
+		trailer = val + len - 1;
+	else
+		trailer--;
+
+	while (*trailer && (*trailer == '"' || isblank(*trailer)))
+		*(trailer--) = '\0';;
+
+	*res = key;
+	*value = val;
+
+	return 1;
+}
+
 /*
  * Read config env variables and check they have been set.
  *
@@ -141,61 +189,30 @@
 {
 	FILE *f;
 	char buf[MAX_LINE_LEN];
-	char *res, *value;
+	char *res;
 
 	f = fopen(DEFAULTS_CONFIG_FILE, "r");
 	if (!f)
 		return 0;
 
 	while ((res = fgets(buf, MAX_LINE_LEN, f))) {
-		char *trailer;
-		int len;
-
-		if (*res == '#' || !isalpha(*res))
-			continue;
-
-		while (*res && *res == ' ')
-			res++;
-
-		if (!res)
-			continue;
+		char *key, *value;
 
-		if (!(value = strchr(res, '=')))
+		if (!parse_line(res, &key, &value))
 			continue;
 
-		*value++ = '\0';
-
-		while (*value && (*value == '"' || isblank(*value)))
-			value++;
-
-		len = strlen(value);
-
-		if (value[len - 1] == '\n') {
-			value[len - 1] = '\0';
-			len--;
-		}
-
-		trailer = strchr(value, '#');
-		if (!trailer)
-			trailer = value + len - 1;
-		else
-			trailer--;
-
-		while (*trailer && (*trailer == '"' || isblank(*trailer)))
-			*(trailer--) = '\0';;
-
-		if (check_set_config_value(res, ENV_NAME_MASTER_MAP, value) ||
-		    check_set_config_value(res, ENV_NAME_TIMEOUT, value) ||
-		    check_set_config_value(res, ENV_NAME_BROWSE_MODE, value) ||
-		    check_set_config_value(res, ENV_NAME_LOGGING, value) ||
-		    check_set_config_value(res, ENV_LDAP_SERVER, value) ||
-		    check_set_config_value(res, ENV_NAME_MAP_OBJ_CLASS, value) ||
-		    check_set_config_value(res, ENV_NAME_ENTRY_OBJ_CLASS, value) ||
-		    check_set_config_value(res, ENV_NAME_MAP_ATTR, value) ||
-		    check_set_config_value(res, ENV_NAME_ENTRY_ATTR, value) ||
-		    check_set_config_value(res, ENV_NAME_VALUE_ATTR, value) ||
-		    check_set_config_value(res, ENV_APPEND_OPTIONS, value) ||
-		    check_set_config_value(res, ENV_AUTH_CONF_FILE, value))
+		if (check_set_config_value(key, ENV_NAME_MASTER_MAP, value) ||
+		    check_set_config_value(key, ENV_NAME_TIMEOUT, value) ||
+		    check_set_config_value(key, ENV_NAME_BROWSE_MODE, value) ||
+		    check_set_config_value(key, ENV_NAME_LOGGING, value) ||
+		    check_set_config_value(key, ENV_LDAP_SERVER, value) ||
+		    check_set_config_value(key, ENV_NAME_MAP_OBJ_CLASS, value) ||
+		    check_set_config_value(key, ENV_NAME_ENTRY_OBJ_CLASS, value) ||
+		    check_set_config_value(key, ENV_NAME_MAP_ATTR, value) ||
+		    check_set_config_value(key, ENV_NAME_ENTRY_ATTR, value) ||
+		    check_set_config_value(key, ENV_NAME_VALUE_ATTR, value) ||
+		    check_set_config_value(key, ENV_APPEND_OPTIONS, value) ||
+		    check_set_config_value(key, ENV_AUTH_CONF_FILE, value))
 			;
 	}
 
@@ -335,6 +352,86 @@
 	return schema;
 }
 
+static struct ldap_searchdn *alloc_searchdn(const char *value)
+{
+	struct ldap_searchdn *sdn;
+	char *val;
+
+	sdn = malloc(sizeof(struct ldap_searchdn));
+	if (!sdn)
+		return NULL;
+
+	val = strdup(value);
+	if (!val) {
+		free(sdn);
+		return NULL;
+	}
+
+	sdn->basedn = val;
+	sdn->next = NULL;
+
+	return sdn;
+}
+
+void defaults_free_searchdns(struct ldap_searchdn *sdn)
+{
+	struct ldap_searchdn *this = sdn;
+	struct ldap_searchdn *next;
+
+	next = this;
+	while (this) {
+		next = this->next;
+		free(this->basedn);
+		free(this);
+		this = next;
+	}
+
+	return;
+}
+
+struct ldap_searchdn *defaults_get_searchdns(void)
+{
+	FILE *f;
+	char buf[MAX_LINE_LEN];
+	char *res;
+	struct ldap_searchdn *sdn, *last;
+
+	f = fopen(DEFAULTS_CONFIG_FILE, "r");
+	if (!f)
+		return NULL;
+
+	sdn = last = NULL;
+
+	while ((res = fgets(buf, MAX_LINE_LEN, f))) {
+		char *key, *value;
+
+		if (!parse_line(res, &key, &value))
+			continue;
+
+		if (!strcasecmp(key, SEARCH_BASE)) {
+			struct ldap_searchdn *new = alloc_searchdn(value);
+
+			if (!new) {
+				defaults_free_searchdns(sdn);
+				return NULL;
+			}
+
+			if (!last)
+				last = new;
+			else {
+				last->next = new;
+				last = new;
+			}
+
+			if (!sdn)
+				sdn = new;
+		}
+	}
+
+	fclose(f);
+	return sdn;
+}
+
 struct ldap_schema *defaults_get_schema(void)
 {
 	struct ldap_schema *schema;
--- autofs-5.0.1/man/auto.master.5.in.ldap-search-basedn-list	2007-10-18 19:36:24.000000000 +0800
+++ autofs-5.0.1/man/auto.master.5.in	2007-10-18 19:36:42.000000000 +0800
@@ -231,6 +231,11 @@
 .P
 The configuration settings available are:
 .TP
+.B SEARCH_BASE
+The base dn to use when searching for amap base dn. This entry may be
+given multiple times and each will be checked for a map base dn in
+the order they occur in the configuration.
+.TP
 .B MAP_OBJECT_CLASS
 The map object class. In the \fBnisMap\fP schema this corresponds to the class
 \fBnisMap\fP and in the \fBautomountMap\fP schema it corresponds to the class