- check for "*" when looking up wildcard in LDAP.
- fix couple of edge case parse fails of timeout option.
- add SEARCH_BASE configuration option.
- add random selection as a master map entry option.
- re-read config on HUP signal.
- add LDAP_URI, LDAP_TIMEOUT and LDAP_NETWORK_TIMEOUT configuration
options.
- fix deadlock in submount mount module.
- fix lack of ferror() checking when reading files.
- fix typo in autofs(5) man page.
- fix map entry expansion when undefined macro is present.
- remove unused export validation code.
- add dynamic logging (adapted from v4 patch from Jeff Moyer).
- fix recursive loopback mounts (Matthias Koenig).
- add map re-load to verbose logging.
- fix handling of LDAP base dns with spaces.
- handle MTAB_NOTUPDATED status return from mount.
- when default master map, auto.master, is used also check for auto_master.
- update negative mount timeout handling.
- fix large group handling (Ryan Thomas).
- fix for dynamic logging breaking non-sasl build (Guillaume Rousse).
- eliminate NULL proc ping for singleton host or local mounts.
853 lines
23 KiB
Diff
853 lines
23 KiB
Diff
diff --git a/include/defaults.h b/include/defaults.h
|
|
index 0984b1c..46393d9 100644
|
|
--- a/include/defaults.h
|
|
+++ b/include/defaults.h
|
|
@@ -26,7 +26,8 @@
|
|
#define DEFAULT_BROWSE_MODE 1
|
|
#define DEFAULT_LOGGING 0
|
|
|
|
-#define DEFAULT_LDAP_SERVER NULL
|
|
+#define DEFAULT_LDAP_TIMEOUT -1
|
|
+#define DEFAULT_LDAP_NETWORK_TIMEOUT 8
|
|
|
|
#define DEFAULT_MAP_OBJ_CLASS "nisMap"
|
|
#define DEFAULT_ENTRY_OBJ_CLASS "nisObject"
|
|
@@ -46,6 +47,10 @@ unsigned int defaults_get_timeout(void);
|
|
unsigned int defaults_get_browse_mode(void);
|
|
unsigned int defaults_get_logging(void);
|
|
const char *defaults_get_ldap_server(void);
|
|
+unsigned int defaults_get_ldap_timeout(void);
|
|
+unsigned int defaults_get_ldap_network_timeout(void);
|
|
+struct list_head *defaults_get_uris(void);
|
|
+void defaults_free_uris(struct list_head *);
|
|
struct ldap_schema *defaults_get_default_schema(void);
|
|
struct ldap_schema *defaults_get_schema(void);
|
|
struct ldap_searchdn *defaults_get_searchdns(void);
|
|
diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
|
|
index 1a924be..ca8d658 100644
|
|
--- a/include/lookup_ldap.h
|
|
+++ b/include/lookup_ldap.h
|
|
@@ -18,6 +18,11 @@ struct ldap_schema {
|
|
char *value_attr;
|
|
};
|
|
|
|
+struct ldap_uri {
|
|
+ char *uri;
|
|
+ struct list_head list;
|
|
+};
|
|
+
|
|
struct ldap_searchdn {
|
|
char *basedn;
|
|
struct ldap_searchdn *next;
|
|
@@ -30,6 +35,8 @@ struct lookup_context {
|
|
int port;
|
|
char *base;
|
|
char *qdn;
|
|
+ unsigned int timeout;
|
|
+ unsigned int network_timeout;
|
|
|
|
/* LDAP version 2 or 3 */
|
|
int version;
|
|
@@ -37,7 +44,17 @@ struct lookup_context {
|
|
/* LDAP lookup configuration */
|
|
struct ldap_schema *schema;
|
|
|
|
- /* List of base dns for searching */
|
|
+ /*
|
|
+ * List of servers and base dns for searching.
|
|
+ * uri is the list of servers to attempt connection to and is
|
|
+ * used only if server, above, is NULL. The head of the list
|
|
+ * is the server which we are currently connected to.
|
|
+ * cur_host tracks chnages to connected server, triggering
|
|
+ * a scan of basedns when it changes.
|
|
+ * sdns is the list of basdns to check, done in the order
|
|
+ * given in configuration.
|
|
+ */
|
|
+ struct list_head *uri;
|
|
char *cur_host;
|
|
struct ldap_searchdn *sdns;
|
|
|
|
@@ -77,7 +94,7 @@ struct lookup_context {
|
|
#define LDAP_AUTH_AUTODETECT 0x0004
|
|
|
|
/* lookup_ldap.c */
|
|
-LDAP *init_ldap_connection(struct lookup_context *ctxt);
|
|
+LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt);
|
|
int unbind_ldap_connection(LDAP *ldap, struct lookup_context *ctxt);
|
|
int authtype_requires_creds(const char *authtype);
|
|
|
|
diff --git a/lib/defaults.c b/lib/defaults.c
|
|
index 7da4631..bf1ceed 100644
|
|
--- a/lib/defaults.c
|
|
+++ b/lib/defaults.c
|
|
@@ -17,6 +17,7 @@
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
+#include "list.h"
|
|
#include "defaults.h"
|
|
#include "lookup_ldap.h"
|
|
#include "log.h"
|
|
@@ -30,7 +31,9 @@
|
|
#define ENV_NAME_BROWSE_MODE "BROWSE_MODE"
|
|
#define ENV_NAME_LOGGING "LOGGING"
|
|
|
|
-#define ENV_LDAP_SERVER "LDAP_SERVER"
|
|
+#define LDAP_URI "LDAP_URI"
|
|
+#define ENV_LDAP_TIMEOUT "LDAP_TIMEOUT"
|
|
+#define ENV_LDAP_NETWORK_TIMEOUT "LDAP_NETWORK_TIMEOUT"
|
|
|
|
#define SEARCH_BASE "SEARCH_BASE"
|
|
|
|
@@ -44,7 +47,6 @@
|
|
#define ENV_AUTH_CONF_FILE "AUTH_CONF_FILE"
|
|
|
|
static const char *default_master_map_name = DEFAULT_MASTER_MAP_NAME;
|
|
-static const char *default_ldap_server = DEFAULT_LDAP_SERVER;
|
|
static const char *default_auth_conf_file = DEFAULT_AUTH_CONF_FILE;
|
|
|
|
static char *get_env_string(const char *name)
|
|
@@ -178,6 +180,99 @@ static int parse_line(char *line, char **res, char **value)
|
|
return 1;
|
|
}
|
|
|
|
+void defaults_free_uris(struct list_head *list)
|
|
+{
|
|
+ struct list_head *next;
|
|
+ struct ldap_uri *uri;
|
|
+
|
|
+ if (list_empty(list)) {
|
|
+ free(list);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ next = list->next;
|
|
+ while (next != list) {
|
|
+ uri = list_entry(next, struct ldap_uri, list);
|
|
+ next = next->next;
|
|
+ list_del(&uri->list);
|
|
+ free(uri->uri);
|
|
+ free(uri);
|
|
+ }
|
|
+ free(list);
|
|
+
|
|
+ return;
|
|
+}
|
|
+
|
|
+static unsigned int add_uris(char *value, struct list_head *list)
|
|
+{
|
|
+ char *str, *tok, *ptr = NULL;
|
|
+ size_t len = strlen(value);
|
|
+
|
|
+ str = alloca(len);
|
|
+ if (!str)
|
|
+ return 0;
|
|
+ strcpy(str, value);
|
|
+
|
|
+ tok = strtok_r(str, " ", &ptr);
|
|
+ while (tok) {
|
|
+ struct ldap_uri *new;
|
|
+ char *uri;
|
|
+
|
|
+ new = malloc(sizeof(struct ldap_uri));
|
|
+ if (!new)
|
|
+ continue;
|
|
+
|
|
+ uri = strdup(tok);
|
|
+ if (!uri)
|
|
+ free(new);
|
|
+ else {
|
|
+ new->uri = uri;
|
|
+ list_add_tail(&new->list, list);
|
|
+ }
|
|
+
|
|
+ tok = strtok_r(NULL, " ", &ptr);
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+struct list_head *defaults_get_uris(void)
|
|
+{
|
|
+ FILE *f;
|
|
+ char buf[MAX_LINE_LEN];
|
|
+ char *res;
|
|
+ struct list_head *list;
|
|
+
|
|
+ f = fopen(DEFAULTS_CONFIG_FILE, "r");
|
|
+ if (!f)
|
|
+ return NULL;
|
|
+
|
|
+ list = malloc(sizeof(struct list_head));
|
|
+ if (!list) {
|
|
+ fclose(f);
|
|
+ return NULL;
|
|
+ }
|
|
+ INIT_LIST_HEAD(list);
|
|
+
|
|
+ while ((res = fgets(buf, MAX_LINE_LEN, f))) {
|
|
+ char *key, *value;
|
|
+
|
|
+ if (!parse_line(res, &key, &value))
|
|
+ continue;
|
|
+
|
|
+ if (!strcasecmp(res, LDAP_URI))
|
|
+ add_uris(value, list);
|
|
+ }
|
|
+
|
|
+ if (list_empty(list)) {
|
|
+ free(list);
|
|
+ list = NULL;
|
|
+ }
|
|
+
|
|
+ fclose(f);
|
|
+ return list;
|
|
+}
|
|
+
|
|
/*
|
|
* Read config env variables and check they have been set.
|
|
*
|
|
@@ -205,7 +300,8 @@ unsigned int defaults_read_config(void)
|
|
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_LDAP_TIMEOUT, value) ||
|
|
+ check_set_config_value(key, ENV_LDAP_NETWORK_TIMEOUT, 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) ||
|
|
@@ -284,15 +380,26 @@ unsigned int defaults_get_logging(void)
|
|
return logging;
|
|
}
|
|
|
|
-const char *defaults_get_ldap_server(void)
|
|
+unsigned int defaults_get_ldap_timeout(void)
|
|
{
|
|
- char *server;
|
|
+ int res;
|
|
|
|
- server = get_env_string(ENV_LDAP_SERVER);
|
|
- if (!server)
|
|
- return default_ldap_server;
|
|
+ res = get_env_number(ENV_LDAP_TIMEOUT);
|
|
+ if (res < 0)
|
|
+ res = DEFAULT_LDAP_TIMEOUT;
|
|
|
|
- return (const char *) server;
|
|
+ return res;
|
|
+}
|
|
+
|
|
+unsigned int defaults_get_ldap_network_timeout(void)
|
|
+{
|
|
+ int res;
|
|
+
|
|
+ res = get_env_number(ENV_LDAP_NETWORK_TIMEOUT);
|
|
+ if (res < 0)
|
|
+ res = DEFAULT_LDAP_NETWORK_TIMEOUT;
|
|
+
|
|
+ return res;
|
|
}
|
|
|
|
struct ldap_schema *defaults_get_default_schema(void)
|
|
diff --git a/man/auto.master.5.in b/man/auto.master.5.in
|
|
index 0cb2f07..68447e0 100644
|
|
--- a/man/auto.master.5.in
|
|
+++ b/man/auto.master.5.in
|
|
@@ -230,10 +230,27 @@ values must be set, any partial schema specification will be ignored.
|
|
.P
|
|
The configuration settings available are:
|
|
.TP
|
|
+.B LDAP_TIMEOUT
|
|
+Set the network response timeout (default 8).
|
|
+Set timeout value for the synchronous API calls. The default is the LDAP
|
|
+library default of an infinite timeout.
|
|
+.TP
|
|
+.B LDAP_NETWORK_TIMEOUT
|
|
+Set the network response timeout (default 8).
|
|
+.TP
|
|
+.B LDAP_URI
|
|
+A space seperated list of server uris of the form <proto>://<server>[/]
|
|
+where <proto> can be ldap or ldaps. The option can be given multiple times.
|
|
+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.
|
|
+.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.
|
|
+the order they occur in the configuration. The search base list is read
|
|
+at startup and whenever the daemon recieves a HUP signal.
|
|
.TP
|
|
.B MAP_OBJECT_CLASS
|
|
The map object class. In the \fBnisMap\fP schema this corresponds to the class
|
|
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
|
|
index 2baf8b8..4068561 100644
|
|
--- a/modules/lookup_ldap.c
|
|
+++ b/modules/lookup_ldap.c
|
|
@@ -49,6 +49,8 @@ static struct ldap_schema common_schema[] = {
|
|
};
|
|
static unsigned int common_schema_count = sizeof(common_schema)/sizeof(struct ldap_schema);
|
|
|
|
+static LDAP *auth_init(const char *, struct lookup_context *);
|
|
+
|
|
int bind_ldap_anonymous(LDAP *ldap, struct lookup_context *ctxt)
|
|
{
|
|
int rv;
|
|
@@ -59,10 +61,18 @@ int bind_ldap_anonymous(LDAP *ldap, struct lookup_context *ctxt)
|
|
rv = ldap_simple_bind_s(ldap, NULL, NULL);
|
|
|
|
if (rv != LDAP_SUCCESS) {
|
|
- crit(LOGOPT_ANY,
|
|
- MODPREFIX "Unable to bind to the LDAP server: "
|
|
- "%s, error %s", ctxt->server ? "" : "(default)",
|
|
- ldap_err2string(rv));
|
|
+ if (!ctxt->uri) {
|
|
+ crit(LOGOPT_ANY,
|
|
+ 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);
|
|
+ warn(LOGOPT_ANY,
|
|
+ MODPREFIX "Unable to bind to the LDAP server: "
|
|
+ "%s, error %s", uri->uri, ldap_err2string(rv));
|
|
+ }
|
|
return -1;
|
|
}
|
|
|
|
@@ -98,20 +108,21 @@ int unbind_ldap_connection(LDAP *ldap, struct lookup_context *ctxt)
|
|
return rv;
|
|
}
|
|
|
|
-LDAP *init_ldap_connection(struct lookup_context *ctxt)
|
|
+LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt)
|
|
{
|
|
LDAP *ldap = NULL;
|
|
- int timeout = 8;
|
|
+ struct timeval timeout = { ctxt->timeout, 0 };
|
|
+ struct timeval net_timeout = { ctxt->network_timeout, 0 };
|
|
int rv;
|
|
|
|
ctxt->version = 3;
|
|
|
|
/* Initialize the LDAP context. */
|
|
- rv = ldap_initialize(&ldap, ctxt->server);
|
|
+ rv = ldap_initialize(&ldap, uri);
|
|
if (rv != LDAP_OPT_SUCCESS) {
|
|
crit(LOGOPT_ANY,
|
|
MODPREFIX "couldn't initialize LDAP connection to %s",
|
|
- ctxt->server ? ctxt->server : "default server");
|
|
+ uri ? uri : "default server");
|
|
return NULL;
|
|
}
|
|
|
|
@@ -120,7 +131,7 @@ LDAP *init_ldap_connection(struct lookup_context *ctxt)
|
|
if (rv != LDAP_OPT_SUCCESS) {
|
|
/* fall back to LDAPv2 */
|
|
ldap_unbind_ext(ldap, NULL, NULL);
|
|
- rv = ldap_initialize(&ldap, ctxt->server);
|
|
+ rv = ldap_initialize(&ldap, uri);
|
|
if (rv != LDAP_OPT_SUCCESS) {
|
|
crit(LOGOPT_ANY, MODPREFIX "couldn't initialize LDAP");
|
|
return NULL;
|
|
@@ -128,12 +139,22 @@ LDAP *init_ldap_connection(struct lookup_context *ctxt)
|
|
ctxt->version = 2;
|
|
}
|
|
|
|
- /* Sane network connection timeout */
|
|
- rv = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
|
|
+
|
|
+ if (ctxt->timeout != -1) {
|
|
+ /* Set synchronous call timeout */
|
|
+ rv = ldap_set_option(ldap, LDAP_OPT_TIMEOUT, &timeout);
|
|
+ if (rv != LDAP_OPT_SUCCESS)
|
|
+ info(LOGOPT_ANY, MODPREFIX
|
|
+ "failed to set synchronous call timeout to %d",
|
|
+ timeout.tv_sec);
|
|
+ }
|
|
+
|
|
+ /* Sane network timeout */
|
|
+ rv = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &net_timeout);
|
|
if (rv != LDAP_OPT_SUCCESS)
|
|
info(LOGOPT_ANY,
|
|
MODPREFIX "failed to set connection timeout to %d",
|
|
- timeout);
|
|
+ net_timeout.tv_sec);
|
|
|
|
#ifdef WITH_SASL
|
|
if (ctxt->use_tls) {
|
|
@@ -159,7 +180,7 @@ LDAP *init_ldap_connection(struct lookup_context *ctxt)
|
|
return NULL;
|
|
}
|
|
ctxt->use_tls = LDAP_TLS_DONT_USE;
|
|
- ldap = init_ldap_connection(ctxt);
|
|
+ ldap = init_ldap_connection(uri, ctxt);
|
|
if (ldap)
|
|
ctxt->use_tls = LDAP_TLS_INIT;
|
|
return ldap;
|
|
@@ -271,7 +292,7 @@ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *cla
|
|
e = ldap_first_entry(ldap, result);
|
|
if (e) {
|
|
dn = ldap_get_dn(ldap, e);
|
|
- debug(LOGOPT_NONE, MODPREFIX "query dn %s", dn);
|
|
+ debug(LOGOPT_NONE, MODPREFIX "found query dn %s", dn);
|
|
} else {
|
|
debug(LOGOPT_NONE,
|
|
MODPREFIX "query succeeded, no matches for %s",
|
|
@@ -378,16 +399,11 @@ static int find_query_dn(LDAP *ldap, struct lookup_context *ctxt)
|
|
return 0;
|
|
}
|
|
|
|
-static LDAP *do_connect(struct lookup_context *ctxt)
|
|
+static int do_bind(LDAP *ldap, struct lookup_context *ctxt)
|
|
{
|
|
- LDAP *ldap;
|
|
char *host = NULL, *nhost;
|
|
int rv, need_base = 1;
|
|
|
|
- ldap = init_ldap_connection(ctxt);
|
|
- if (!ldap)
|
|
- return NULL;
|
|
-
|
|
#ifdef WITH_SASL
|
|
debug(LOGOPT_NONE, "auth_required: %d, sasl_mech %s",
|
|
ctxt->auth_required, ctxt->sasl_mech);
|
|
@@ -407,23 +423,19 @@ static LDAP *do_connect(struct lookup_context *ctxt)
|
|
debug(LOGOPT_NONE, MODPREFIX "ldap anonymous bind returned %d", rv);
|
|
#endif
|
|
|
|
- if (rv != 0) {
|
|
- unbind_ldap_connection(ldap, ctxt);
|
|
- return NULL;
|
|
- }
|
|
+ if (rv != 0)
|
|
+ return 0;
|
|
|
|
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;
|
|
+ return 0;
|
|
}
|
|
|
|
nhost = strdup(host);
|
|
if (!nhost) {
|
|
- unbind_ldap_connection(ldap, ctxt);
|
|
debug(LOGOPT_ANY, "failed to alloc context for hostname");
|
|
- return NULL;
|
|
+ return 0;
|
|
}
|
|
ldap_memfree(host);
|
|
|
|
@@ -443,7 +455,7 @@ static LDAP *do_connect(struct lookup_context *ctxt)
|
|
}
|
|
|
|
if (!need_base)
|
|
- return ldap;
|
|
+ return 1;
|
|
|
|
/*
|
|
* If the schema isn't defined in the configuration then check for
|
|
@@ -452,20 +464,134 @@ static LDAP *do_connect(struct lookup_context *ctxt)
|
|
*/
|
|
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;
|
|
+ return 0;
|
|
}
|
|
} 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 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static LDAP *do_connect(const char *uri, struct lookup_context *ctxt)
|
|
+{
|
|
+ LDAP *ldap;
|
|
+
|
|
+ ldap = init_ldap_connection(uri, ctxt);
|
|
+ if (!ldap)
|
|
+ return NULL;
|
|
+
|
|
+ if (!do_bind(ldap, ctxt)) {
|
|
+ unbind_ldap_connection(ldap, ctxt);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return ldap;
|
|
+}
|
|
+
|
|
+static LDAP *connect_to_server(const char *uri, struct lookup_context *ctxt)
|
|
+{
|
|
+ LDAP *ldap;
|
|
+
|
|
+#ifdef WITH_SASL
|
|
+ /*
|
|
+ * Determine which authentication mechanism to use if we require
|
|
+ * authentication.
|
|
+ */
|
|
+ if (ctxt->auth_required & LDAP_AUTH_REQUIRED) {
|
|
+ ldap = auth_init(uri, ctxt);
|
|
+ if (!ldap && ctxt->auth_required & LDAP_AUTH_AUTODETECT)
|
|
+ warn(LOGOPT_NONE,
|
|
+ "no authentication mechanisms auto detected.");
|
|
+ if (!ldap) {
|
|
+ error(LOGOPT_ANY, MODPREFIX
|
|
+ "cannot initialize authentication setup");
|
|
return NULL;
|
|
}
|
|
+
|
|
+ if (!do_bind(ldap, ctxt)) {
|
|
+ unbind_ldap_connection(ldap, ctxt);
|
|
+ error(LOGOPT_ANY, MODPREFIX "cannot bind to server");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return ldap;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ ldap = do_connect(uri, ctxt);
|
|
+ if (!ldap) {
|
|
+ error(LOGOPT_ANY, MODPREFIX "cannot connect to server");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return ldap;
|
|
+}
|
|
+
|
|
+static LDAP *find_server(struct lookup_context *ctxt)
|
|
+{
|
|
+ LDAP *ldap = NULL;
|
|
+ struct ldap_uri *this;
|
|
+ struct list_head *p;
|
|
+ LIST_HEAD(tmp);
|
|
+
|
|
+ /* Try each uri in list, add connect fails to tmp list */
|
|
+ p = ctxt->uri->next;
|
|
+ while(p != ctxt->uri) {
|
|
+ this = list_entry(p, struct ldap_uri, list);
|
|
+ p = p->next;
|
|
+ debug(LOGOPT_ANY, "check uri %s", this->uri);
|
|
+ ldap = connect_to_server(this->uri, ctxt);
|
|
+ if (ldap) {
|
|
+ debug(LOGOPT_ANY, "connexted to uri %s", this->uri);
|
|
+ break;
|
|
+ }
|
|
+ list_del_init(&this->list);
|
|
+ list_add_tail(&this->list, &tmp);
|
|
}
|
|
+ /*
|
|
+ * 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;
|
|
+}
|
|
+
|
|
+static LDAP *do_reconnect(struct lookup_context *ctxt)
|
|
+{
|
|
+ LDAP *ldap;
|
|
+
|
|
+ if (ctxt->server || !ctxt->uri) {
|
|
+ ldap = do_connect(ctxt->server, ctxt);
|
|
+ return ldap;
|
|
+ } else {
|
|
+ struct ldap_uri *this;
|
|
+ this = list_entry(ctxt->uri->next, struct ldap_uri, list);
|
|
+ ldap = do_connect(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);
|
|
+ }
|
|
+
|
|
+ autofs_sasl_done(ctxt);
|
|
+
|
|
+ /* Current server failed connect, try the rest */
|
|
+ ldap = find_server(ctxt);
|
|
+ if (!ldap)
|
|
+ error(LOGOPT_ANY, MODPREFIX "failed to find available server");
|
|
|
|
return ldap;
|
|
}
|
|
@@ -760,10 +886,10 @@ out:
|
|
* information. If there is no configuration file, then we fall back to
|
|
* trying all supported authentication mechanisms until one works.
|
|
*
|
|
- * Returns 0 on success, with authtype, user and secret filled in as
|
|
- * appropriate. Returns -1 on failre.
|
|
+ * Returns ldap connection on success, with authtype, user and secret
|
|
+ * filled in as appropriate. Returns NULL on failre.
|
|
*/
|
|
-int auth_init(struct lookup_context *ctxt)
|
|
+static LDAP *auth_init(const char *uri, struct lookup_context *ctxt)
|
|
{
|
|
int ret;
|
|
LDAP *ldap;
|
|
@@ -776,14 +902,11 @@ int auth_init(struct lookup_context *ctxt)
|
|
*/
|
|
ret = parse_ldap_config(ctxt);
|
|
if (ret)
|
|
- return -1;
|
|
-
|
|
- if (ctxt->auth_required & LDAP_AUTH_NOTREQUIRED)
|
|
- return 0;
|
|
+ return NULL;
|
|
|
|
- ldap = init_ldap_connection(ctxt);
|
|
+ ldap = init_ldap_connection(uri, ctxt);
|
|
if (!ldap)
|
|
- return -1;
|
|
+ return NULL;
|
|
|
|
/*
|
|
* Initialize the sasl library. It is okay if user and secret
|
|
@@ -794,18 +917,12 @@ int auth_init(struct lookup_context *ctxt)
|
|
* the credential cache and the client and service principals.
|
|
*/
|
|
ret = autofs_sasl_init(ldap, ctxt);
|
|
- unbind_ldap_connection(ldap, ctxt);
|
|
if (ret) {
|
|
ctxt->sasl_mech = NULL;
|
|
- if (ctxt->auth_required & LDAP_AUTH_AUTODETECT) {
|
|
- warn(LOGOPT_NONE,
|
|
- "no authentication mechanisms auto detected.");
|
|
- return 0;
|
|
- }
|
|
- return -1;
|
|
+ return NULL;
|
|
}
|
|
|
|
- return 0;
|
|
+ return ldap;
|
|
}
|
|
#endif
|
|
|
|
@@ -1036,6 +1153,8 @@ static void free_context(struct lookup_context *ctxt)
|
|
free(ctxt->cur_host);
|
|
if (ctxt->base)
|
|
free(ctxt->base);
|
|
+ if (ctxt->uri)
|
|
+ defaults_free_uris(ctxt->uri);
|
|
if (ctxt->sdns)
|
|
defaults_free_searchdns(ctxt->sdns);
|
|
free(ctxt);
|
|
@@ -1043,6 +1162,30 @@ static void free_context(struct lookup_context *ctxt)
|
|
return;
|
|
}
|
|
|
|
+static void validate_uris(struct list_head *list)
|
|
+{
|
|
+ struct list_head *next;
|
|
+
|
|
+ next = list->next;
|
|
+ while (next != list) {
|
|
+ struct ldap_uri *this;
|
|
+
|
|
+ this = list_entry(next, struct ldap_uri, list);
|
|
+ next = next->next;
|
|
+
|
|
+ /* At least we get some basic validation */
|
|
+ if (!ldap_is_ldap_url(this->uri)) {
|
|
+ warn(LOGOPT_ANY,
|
|
+ "removed invalid uri from list, %s", this->uri);
|
|
+ list_del(&this->list);
|
|
+ free(this->uri);
|
|
+ free(this);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return;
|
|
+}
|
|
+
|
|
/*
|
|
* This initializes a context (persistent non-global data) for queries to
|
|
* this module. Return zero if we succeed.
|
|
@@ -1051,7 +1194,6 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
|
|
{
|
|
struct lookup_context *ctxt;
|
|
char buf[MAX_ERR_BUF];
|
|
- int ret;
|
|
LDAP *ldap = NULL;
|
|
|
|
*context = NULL;
|
|
@@ -1079,33 +1221,42 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
|
|
return 1;
|
|
}
|
|
|
|
-#ifdef WITH_SASL
|
|
- /*
|
|
- * Determine which authentication mechanism to use. We sanity-
|
|
- * check by binding to the server temporarily.
|
|
- */
|
|
- ret = auth_init(ctxt);
|
|
- if (ret && (ctxt->auth_required & LDAP_AUTH_REQUIRED)) {
|
|
- error(LOGOPT_ANY, MODPREFIX
|
|
- "cannot initialize authentication setup");
|
|
- free_context(ctxt);
|
|
- return 1;
|
|
+ ctxt->timeout = defaults_get_ldap_timeout();
|
|
+ ctxt->network_timeout = defaults_get_ldap_network_timeout();
|
|
+
|
|
+ if (!ctxt->server) {
|
|
+ struct list_head *uris = defaults_get_uris();
|
|
+ if (uris) {
|
|
+ validate_uris(uris);
|
|
+ if (!list_empty(uris))
|
|
+ ctxt->uri = uris;
|
|
+ else
|
|
+ free(uris);
|
|
+ }
|
|
}
|
|
-#endif
|
|
|
|
- ldap = do_connect(ctxt);
|
|
- if (!ldap) {
|
|
- error(LOGOPT_ANY, MODPREFIX "cannot connect to server");
|
|
- free_context(ctxt);
|
|
- return 1;
|
|
+ if (ctxt->server || !ctxt->uri) {
|
|
+ ldap = connect_to_server(ctxt->server, ctxt);
|
|
+ if (!ldap) {
|
|
+ free_context(ctxt);
|
|
+ return 1;
|
|
+ }
|
|
+ } else {
|
|
+ ldap = find_server(ctxt);
|
|
+ if (!ldap) {
|
|
+ free_context(ctxt);
|
|
+ error(LOGOPT_ANY, MODPREFIX
|
|
+ "failed to find available server");
|
|
+ return 1;
|
|
+ }
|
|
}
|
|
unbind_ldap_connection(ldap, ctxt);
|
|
|
|
/* Open the parser, if we can. */
|
|
ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
|
|
if (!ctxt->parse) {
|
|
- crit(LOGOPT_ANY, MODPREFIX "failed to open parse context");
|
|
free_context(ctxt);
|
|
+ crit(LOGOPT_ANY, MODPREFIX "failed to open parse context");
|
|
return 1;
|
|
}
|
|
*context = ctxt;
|
|
@@ -1153,7 +1304,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
|
|
query[l] = '\0';
|
|
|
|
/* Initialize the LDAP context. */
|
|
- ldap = do_connect(ctxt);
|
|
+ ldap = do_reconnect(ctxt);
|
|
if (!ldap)
|
|
return NSS_STATUS_UNAVAIL;
|
|
|
|
@@ -1305,7 +1456,7 @@ static int read_one_map(struct autofs_point *ap,
|
|
query[l] = '\0';
|
|
|
|
/* Initialize the LDAP context. */
|
|
- ldap = do_connect(ctxt);
|
|
+ ldap = do_reconnect(ctxt);
|
|
if (!ldap)
|
|
return NSS_STATUS_UNAVAIL;
|
|
|
|
@@ -1536,6 +1687,9 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
|
|
if (ret != NSS_STATUS_SUCCESS) {
|
|
switch (rv) {
|
|
case LDAP_SIZELIMIT_EXCEEDED:
|
|
+ crit(ap->logopt, MODPREFIX
|
|
+ "Unable to download entire LDAP map for: %s",
|
|
+ ap->path);
|
|
case LDAP_UNWILLING_TO_PERFORM:
|
|
pthread_setcancelstate(cur_state, NULL);
|
|
return NSS_STATUS_UNAVAIL;
|
|
@@ -1612,7 +1766,7 @@ static int lookup_one(struct autofs_point *ap,
|
|
query[ql] = '\0';
|
|
|
|
/* Initialize the LDAP context. */
|
|
- ldap = do_connect(ctxt);
|
|
+ ldap = do_reconnect(ctxt);
|
|
if (!ldap)
|
|
return CHE_FAIL;
|
|
|
|
diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in
|
|
index 2b1e20a..f01ee5f 100644
|
|
--- a/redhat/autofs.sysconfig.in
|
|
+++ b/redhat/autofs.sysconfig.in
|
|
@@ -23,6 +23,25 @@ BROWSE_MODE="no"
|
|
#
|
|
# Define base dn for map dn lookup.
|
|
#
|
|
+# Define server URIs
|
|
+#
|
|
+# LDAP_URI - space seperated list of server uris of the form
|
|
+# <proto>://<server>[/] where <proto> can be ldap
|
|
+# or ldaps. The option can be given multiple times.
|
|
+# Map entries that include a server name override
|
|
+# this option.
|
|
+#
|
|
+#LDAP_URI=""
|
|
+#
|
|
+# LDAP__TIMEOUT - timeout value for the synchronous API calls
|
|
+# (default is LDAP library default).
|
|
+#
|
|
+#LDAP_TIMEOUT=-1
|
|
+#
|
|
+# LDAP_NETWORK_TIMEOUT - set the network response timeout (default 8).
|
|
+#
|
|
+#LDAP_NETWORK_TIMEOUT=8
|
|
+#
|
|
# 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.
|
|
diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in
|
|
index 2b1e20a..028341c 100644
|
|
--- a/samples/autofs.conf.default.in
|
|
+++ b/samples/autofs.conf.default.in
|
|
@@ -21,6 +21,25 @@ BROWSE_MODE="no"
|
|
#
|
|
#LOGGING="none"
|
|
#
|
|
+# Define server URIs
|
|
+#
|
|
+# LDAP_URI - space seperated list of server uris of the form
|
|
+# <proto>://<server>[/] where <proto> can be ldap
|
|
+# or ldaps. The option can be given multiple times.
|
|
+# Map entries that include a server name override
|
|
+# this option.
|
|
+#
|
|
+#LDAP_URI=""
|
|
+#
|
|
+# LDAP__TIMEOUT - timeout value for the synchronous API calls
|
|
+# (default is LDAP library default).
|
|
+#
|
|
+#LDAP_TIMEOUT=-1
|
|
+#
|
|
+# LDAP_NETWORK_TIMEOUT - set the network response timeout (default 8).
|
|
+#
|
|
+#LDAP_NETWORK_TIMEOUT=8
|
|
+#
|
|
# Define base dn for map dn lookup.
|
|
#
|
|
# SEARCH_BASE - base dn to use for searching for map search dn.
|