]>
Commit | Line | Data |
---|---|---|
3d551623 PG |
1 | diff --git a/CHANGELOG b/CHANGELOG |
2 | index 9a2a8c1..933b1a1 100644 | |
3 | --- a/CHANGELOG | |
4 | +++ b/CHANGELOG | |
5 | @@ -27,6 +27,7 @@ | |
6 | - add SEARCH_BASE configuration option. | |
7 | - work around segv at exit due to libxml2 tsd usage. | |
8 | - re-read config on HUP signal. | |
9 | +- add LDAP_URI, LDAP_TIMEOUT and LDAP_NETWORK_TIMEOUT configuration options. | |
10 | ||
11 | 18/06/2007 autofs-5.0.2 | |
12 | ----------------------- | |
13 | diff --git a/include/defaults.h b/include/defaults.h | |
14 | index 0984b1c..46393d9 100644 | |
15 | --- a/include/defaults.h | |
16 | +++ b/include/defaults.h | |
17 | @@ -26,7 +26,8 @@ | |
18 | #define DEFAULT_BROWSE_MODE 1 | |
19 | #define DEFAULT_LOGGING 0 | |
20 | ||
21 | -#define DEFAULT_LDAP_SERVER NULL | |
22 | +#define DEFAULT_LDAP_TIMEOUT -1 | |
23 | +#define DEFAULT_LDAP_NETWORK_TIMEOUT 8 | |
24 | ||
25 | #define DEFAULT_MAP_OBJ_CLASS "nisMap" | |
26 | #define DEFAULT_ENTRY_OBJ_CLASS "nisObject" | |
27 | @@ -46,6 +47,10 @@ unsigned int defaults_get_timeout(void); | |
28 | unsigned int defaults_get_browse_mode(void); | |
29 | unsigned int defaults_get_logging(void); | |
30 | const char *defaults_get_ldap_server(void); | |
31 | +unsigned int defaults_get_ldap_timeout(void); | |
32 | +unsigned int defaults_get_ldap_network_timeout(void); | |
33 | +struct list_head *defaults_get_uris(void); | |
34 | +void defaults_free_uris(struct list_head *); | |
35 | struct ldap_schema *defaults_get_default_schema(void); | |
36 | struct ldap_schema *defaults_get_schema(void); | |
37 | struct ldap_searchdn *defaults_get_searchdns(void); | |
38 | diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h | |
39 | index 1a924be..ca8d658 100644 | |
40 | --- a/include/lookup_ldap.h | |
41 | +++ b/include/lookup_ldap.h | |
42 | @@ -18,6 +18,11 @@ struct ldap_schema { | |
43 | char *value_attr; | |
44 | }; | |
45 | ||
46 | +struct ldap_uri { | |
47 | + char *uri; | |
48 | + struct list_head list; | |
49 | +}; | |
50 | + | |
51 | struct ldap_searchdn { | |
52 | char *basedn; | |
53 | struct ldap_searchdn *next; | |
54 | @@ -30,6 +35,8 @@ struct lookup_context { | |
55 | int port; | |
56 | char *base; | |
57 | char *qdn; | |
58 | + unsigned int timeout; | |
59 | + unsigned int network_timeout; | |
60 | ||
61 | /* LDAP version 2 or 3 */ | |
62 | int version; | |
63 | @@ -37,7 +44,17 @@ struct lookup_context { | |
64 | /* LDAP lookup configuration */ | |
65 | struct ldap_schema *schema; | |
66 | ||
67 | - /* List of base dns for searching */ | |
68 | + /* | |
69 | + * List of servers and base dns for searching. | |
70 | + * uri is the list of servers to attempt connection to and is | |
71 | + * used only if server, above, is NULL. The head of the list | |
72 | + * is the server which we are currently connected to. | |
73 | + * cur_host tracks chnages to connected server, triggering | |
74 | + * a scan of basedns when it changes. | |
75 | + * sdns is the list of basdns to check, done in the order | |
76 | + * given in configuration. | |
77 | + */ | |
78 | + struct list_head *uri; | |
79 | char *cur_host; | |
80 | struct ldap_searchdn *sdns; | |
81 | ||
82 | @@ -77,7 +94,7 @@ struct lookup_context { | |
83 | #define LDAP_AUTH_AUTODETECT 0x0004 | |
84 | ||
85 | /* lookup_ldap.c */ | |
86 | -LDAP *init_ldap_connection(struct lookup_context *ctxt); | |
87 | +LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt); | |
88 | int unbind_ldap_connection(LDAP *ldap, struct lookup_context *ctxt); | |
89 | int authtype_requires_creds(const char *authtype); | |
90 | ||
91 | diff --git a/lib/defaults.c b/lib/defaults.c | |
92 | index 7da4631..bf1ceed 100644 | |
93 | --- a/lib/defaults.c | |
94 | +++ b/lib/defaults.c | |
95 | @@ -17,6 +17,7 @@ | |
96 | #include <ctype.h> | |
97 | #include <string.h> | |
98 | ||
99 | +#include "list.h" | |
100 | #include "defaults.h" | |
101 | #include "lookup_ldap.h" | |
102 | #include "log.h" | |
103 | @@ -30,7 +31,9 @@ | |
104 | #define ENV_NAME_BROWSE_MODE "BROWSE_MODE" | |
105 | #define ENV_NAME_LOGGING "LOGGING" | |
106 | ||
107 | -#define ENV_LDAP_SERVER "LDAP_SERVER" | |
108 | +#define LDAP_URI "LDAP_URI" | |
109 | +#define ENV_LDAP_TIMEOUT "LDAP_TIMEOUT" | |
110 | +#define ENV_LDAP_NETWORK_TIMEOUT "LDAP_NETWORK_TIMEOUT" | |
111 | ||
112 | #define SEARCH_BASE "SEARCH_BASE" | |
113 | ||
114 | @@ -44,7 +47,6 @@ | |
115 | #define ENV_AUTH_CONF_FILE "AUTH_CONF_FILE" | |
116 | ||
117 | static const char *default_master_map_name = DEFAULT_MASTER_MAP_NAME; | |
118 | -static const char *default_ldap_server = DEFAULT_LDAP_SERVER; | |
119 | static const char *default_auth_conf_file = DEFAULT_AUTH_CONF_FILE; | |
120 | ||
121 | static char *get_env_string(const char *name) | |
122 | @@ -178,6 +180,99 @@ static int parse_line(char *line, char **res, char **value) | |
123 | return 1; | |
124 | } | |
125 | ||
126 | +void defaults_free_uris(struct list_head *list) | |
127 | +{ | |
128 | + struct list_head *next; | |
129 | + struct ldap_uri *uri; | |
130 | + | |
131 | + if (list_empty(list)) { | |
132 | + free(list); | |
133 | + return; | |
134 | + } | |
135 | + | |
136 | + next = list->next; | |
137 | + while (next != list) { | |
138 | + uri = list_entry(next, struct ldap_uri, list); | |
139 | + next = next->next; | |
140 | + list_del(&uri->list); | |
141 | + free(uri->uri); | |
142 | + free(uri); | |
143 | + } | |
144 | + free(list); | |
145 | + | |
146 | + return; | |
147 | +} | |
148 | + | |
149 | +static unsigned int add_uris(char *value, struct list_head *list) | |
150 | +{ | |
151 | + char *str, *tok, *ptr = NULL; | |
152 | + size_t len = strlen(value); | |
153 | + | |
154 | + str = alloca(len); | |
155 | + if (!str) | |
156 | + return 0; | |
157 | + strcpy(str, value); | |
158 | + | |
159 | + tok = strtok_r(str, " ", &ptr); | |
160 | + while (tok) { | |
161 | + struct ldap_uri *new; | |
162 | + char *uri; | |
163 | + | |
164 | + new = malloc(sizeof(struct ldap_uri)); | |
165 | + if (!new) | |
166 | + continue; | |
167 | + | |
168 | + uri = strdup(tok); | |
169 | + if (!uri) | |
170 | + free(new); | |
171 | + else { | |
172 | + new->uri = uri; | |
173 | + list_add_tail(&new->list, list); | |
174 | + } | |
175 | + | |
176 | + tok = strtok_r(NULL, " ", &ptr); | |
177 | + } | |
178 | + | |
179 | + return 1; | |
180 | +} | |
181 | + | |
182 | +struct list_head *defaults_get_uris(void) | |
183 | +{ | |
184 | + FILE *f; | |
185 | + char buf[MAX_LINE_LEN]; | |
186 | + char *res; | |
187 | + struct list_head *list; | |
188 | + | |
189 | + f = fopen(DEFAULTS_CONFIG_FILE, "r"); | |
190 | + if (!f) | |
191 | + return NULL; | |
192 | + | |
193 | + list = malloc(sizeof(struct list_head)); | |
194 | + if (!list) { | |
195 | + fclose(f); | |
196 | + return NULL; | |
197 | + } | |
198 | + INIT_LIST_HEAD(list); | |
199 | + | |
200 | + while ((res = fgets(buf, MAX_LINE_LEN, f))) { | |
201 | + char *key, *value; | |
202 | + | |
203 | + if (!parse_line(res, &key, &value)) | |
204 | + continue; | |
205 | + | |
206 | + if (!strcasecmp(res, LDAP_URI)) | |
207 | + add_uris(value, list); | |
208 | + } | |
209 | + | |
210 | + if (list_empty(list)) { | |
211 | + free(list); | |
212 | + list = NULL; | |
213 | + } | |
214 | + | |
215 | + fclose(f); | |
216 | + return list; | |
217 | +} | |
218 | + | |
219 | /* | |
220 | * Read config env variables and check they have been set. | |
221 | * | |
222 | @@ -205,7 +300,8 @@ unsigned int defaults_read_config(void) | |
223 | check_set_config_value(key, ENV_NAME_TIMEOUT, value) || | |
224 | check_set_config_value(key, ENV_NAME_BROWSE_MODE, value) || | |
225 | check_set_config_value(key, ENV_NAME_LOGGING, value) || | |
226 | - check_set_config_value(key, ENV_LDAP_SERVER, value) || | |
227 | + check_set_config_value(key, ENV_LDAP_TIMEOUT, value) || | |
228 | + check_set_config_value(key, ENV_LDAP_NETWORK_TIMEOUT, value) || | |
229 | check_set_config_value(key, ENV_NAME_MAP_OBJ_CLASS, value) || | |
230 | check_set_config_value(key, ENV_NAME_ENTRY_OBJ_CLASS, value) || | |
231 | check_set_config_value(key, ENV_NAME_MAP_ATTR, value) || | |
232 | @@ -284,15 +380,26 @@ unsigned int defaults_get_logging(void) | |
233 | return logging; | |
234 | } | |
235 | ||
236 | -const char *defaults_get_ldap_server(void) | |
237 | +unsigned int defaults_get_ldap_timeout(void) | |
238 | { | |
239 | - char *server; | |
240 | + int res; | |
241 | ||
242 | - server = get_env_string(ENV_LDAP_SERVER); | |
243 | - if (!server) | |
244 | - return default_ldap_server; | |
245 | + res = get_env_number(ENV_LDAP_TIMEOUT); | |
246 | + if (res < 0) | |
247 | + res = DEFAULT_LDAP_TIMEOUT; | |
248 | ||
249 | - return (const char *) server; | |
250 | + return res; | |
251 | +} | |
252 | + | |
253 | +unsigned int defaults_get_ldap_network_timeout(void) | |
254 | +{ | |
255 | + int res; | |
256 | + | |
257 | + res = get_env_number(ENV_LDAP_NETWORK_TIMEOUT); | |
258 | + if (res < 0) | |
259 | + res = DEFAULT_LDAP_NETWORK_TIMEOUT; | |
260 | + | |
261 | + return res; | |
262 | } | |
263 | ||
264 | struct ldap_schema *defaults_get_default_schema(void) | |
265 | diff --git a/man/auto.master.5.in b/man/auto.master.5.in | |
266 | index 0cb2f07..68447e0 100644 | |
267 | --- a/man/auto.master.5.in | |
268 | +++ b/man/auto.master.5.in | |
269 | @@ -230,10 +230,27 @@ values must be set, any partial schema specification will be ignored. | |
270 | .P | |
271 | The configuration settings available are: | |
272 | .TP | |
273 | +.B LDAP_TIMEOUT | |
274 | +Set the network response timeout (default 8). | |
275 | +Set timeout value for the synchronous API calls. The default is the LDAP | |
276 | +library default of an infinite timeout. | |
277 | +.TP | |
278 | +.B LDAP_NETWORK_TIMEOUT | |
279 | +Set the network response timeout (default 8). | |
280 | +.TP | |
281 | +.B LDAP_URI | |
282 | +A space seperated list of server uris of the form <proto>://<server>[/] | |
283 | +where <proto> can be ldap or ldaps. The option can be given multiple times. | |
284 | +Map entries that include a server name override this option and it is then | |
285 | +not used. Default is an empty list in which case either the server given | |
286 | +in a map entry or the LDAP configured default is used. This uri list is read at | |
287 | +startup and whenever the daemon receives a HUP signal. | |
288 | +.TP | |
289 | .B SEARCH_BASE | |
290 | The base dn to use when searching for amap base dn. This entry may be | |
291 | given multiple times and each will be checked for a map base dn in | |
292 | -the order they occur in the configuration. | |
293 | +the order they occur in the configuration. The search base list is read | |
294 | +at startup and whenever the daemon recieves a HUP signal. | |
295 | .TP | |
296 | .B MAP_OBJECT_CLASS | |
297 | The map object class. In the \fBnisMap\fP schema this corresponds to the class | |
298 | diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c | |
299 | index 2baf8b8..4068561 100644 | |
300 | --- a/modules/lookup_ldap.c | |
301 | +++ b/modules/lookup_ldap.c | |
302 | @@ -49,6 +49,8 @@ static struct ldap_schema common_schema[] = { | |
303 | }; | |
304 | static unsigned int common_schema_count = sizeof(common_schema)/sizeof(struct ldap_schema); | |
305 | ||
306 | +static LDAP *auth_init(const char *, struct lookup_context *); | |
307 | + | |
308 | int bind_ldap_anonymous(LDAP *ldap, struct lookup_context *ctxt) | |
309 | { | |
310 | int rv; | |
311 | @@ -59,10 +61,18 @@ int bind_ldap_anonymous(LDAP *ldap, struct lookup_context *ctxt) | |
312 | rv = ldap_simple_bind_s(ldap, NULL, NULL); | |
313 | ||
314 | if (rv != LDAP_SUCCESS) { | |
315 | - crit(LOGOPT_ANY, | |
316 | - MODPREFIX "Unable to bind to the LDAP server: " | |
317 | - "%s, error %s", ctxt->server ? "" : "(default)", | |
318 | - ldap_err2string(rv)); | |
319 | + if (!ctxt->uri) { | |
320 | + crit(LOGOPT_ANY, | |
321 | + MODPREFIX "Unable to bind to the LDAP server: " | |
322 | + "%s, error %s", ctxt->server ? "" : "(default)", | |
323 | + ldap_err2string(rv)); | |
324 | + } else { | |
325 | + struct ldap_uri *uri; | |
326 | + uri = list_entry(ctxt->uri->next, struct ldap_uri, list); | |
327 | + warn(LOGOPT_ANY, | |
328 | + MODPREFIX "Unable to bind to the LDAP server: " | |
329 | + "%s, error %s", uri->uri, ldap_err2string(rv)); | |
330 | + } | |
331 | return -1; | |
332 | } | |
333 | ||
334 | @@ -98,20 +108,21 @@ int unbind_ldap_connection(LDAP *ldap, struct lookup_context *ctxt) | |
335 | return rv; | |
336 | } | |
337 | ||
338 | -LDAP *init_ldap_connection(struct lookup_context *ctxt) | |
339 | +LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt) | |
340 | { | |
341 | LDAP *ldap = NULL; | |
342 | - int timeout = 8; | |
343 | + struct timeval timeout = { ctxt->timeout, 0 }; | |
344 | + struct timeval net_timeout = { ctxt->network_timeout, 0 }; | |
345 | int rv; | |
346 | ||
347 | ctxt->version = 3; | |
348 | ||
349 | /* Initialize the LDAP context. */ | |
350 | - rv = ldap_initialize(&ldap, ctxt->server); | |
351 | + rv = ldap_initialize(&ldap, uri); | |
352 | if (rv != LDAP_OPT_SUCCESS) { | |
353 | crit(LOGOPT_ANY, | |
354 | MODPREFIX "couldn't initialize LDAP connection to %s", | |
355 | - ctxt->server ? ctxt->server : "default server"); | |
356 | + uri ? uri : "default server"); | |
357 | return NULL; | |
358 | } | |
359 | ||
360 | @@ -120,7 +131,7 @@ LDAP *init_ldap_connection(struct lookup_context *ctxt) | |
361 | if (rv != LDAP_OPT_SUCCESS) { | |
362 | /* fall back to LDAPv2 */ | |
363 | ldap_unbind_ext(ldap, NULL, NULL); | |
364 | - rv = ldap_initialize(&ldap, ctxt->server); | |
365 | + rv = ldap_initialize(&ldap, uri); | |
366 | if (rv != LDAP_OPT_SUCCESS) { | |
367 | crit(LOGOPT_ANY, MODPREFIX "couldn't initialize LDAP"); | |
368 | return NULL; | |
369 | @@ -128,12 +139,22 @@ LDAP *init_ldap_connection(struct lookup_context *ctxt) | |
370 | ctxt->version = 2; | |
371 | } | |
372 | ||
373 | - /* Sane network connection timeout */ | |
374 | - rv = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout); | |
375 | + | |
376 | + if (ctxt->timeout != -1) { | |
377 | + /* Set synchronous call timeout */ | |
378 | + rv = ldap_set_option(ldap, LDAP_OPT_TIMEOUT, &timeout); | |
379 | + if (rv != LDAP_OPT_SUCCESS) | |
380 | + info(LOGOPT_ANY, MODPREFIX | |
381 | + "failed to set synchronous call timeout to %d", | |
382 | + timeout.tv_sec); | |
383 | + } | |
384 | + | |
385 | + /* Sane network timeout */ | |
386 | + rv = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &net_timeout); | |
387 | if (rv != LDAP_OPT_SUCCESS) | |
388 | info(LOGOPT_ANY, | |
389 | MODPREFIX "failed to set connection timeout to %d", | |
390 | - timeout); | |
391 | + net_timeout.tv_sec); | |
392 | ||
393 | #ifdef WITH_SASL | |
394 | if (ctxt->use_tls) { | |
395 | @@ -159,7 +180,7 @@ LDAP *init_ldap_connection(struct lookup_context *ctxt) | |
396 | return NULL; | |
397 | } | |
398 | ctxt->use_tls = LDAP_TLS_DONT_USE; | |
399 | - ldap = init_ldap_connection(ctxt); | |
400 | + ldap = init_ldap_connection(uri, ctxt); | |
401 | if (ldap) | |
402 | ctxt->use_tls = LDAP_TLS_INIT; | |
403 | return ldap; | |
404 | @@ -271,7 +292,7 @@ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *cla | |
405 | e = ldap_first_entry(ldap, result); | |
406 | if (e) { | |
407 | dn = ldap_get_dn(ldap, e); | |
408 | - debug(LOGOPT_NONE, MODPREFIX "query dn %s", dn); | |
409 | + debug(LOGOPT_NONE, MODPREFIX "found query dn %s", dn); | |
410 | } else { | |
411 | debug(LOGOPT_NONE, | |
412 | MODPREFIX "query succeeded, no matches for %s", | |
413 | @@ -378,16 +399,11 @@ static int find_query_dn(LDAP *ldap, struct lookup_context *ctxt) | |
414 | return 0; | |
415 | } | |
416 | ||
417 | -static LDAP *do_connect(struct lookup_context *ctxt) | |
418 | +static int do_bind(LDAP *ldap, struct lookup_context *ctxt) | |
419 | { | |
420 | - LDAP *ldap; | |
421 | char *host = NULL, *nhost; | |
422 | int rv, need_base = 1; | |
423 | ||
424 | - ldap = init_ldap_connection(ctxt); | |
425 | - if (!ldap) | |
426 | - return NULL; | |
427 | - | |
428 | #ifdef WITH_SASL | |
429 | debug(LOGOPT_NONE, "auth_required: %d, sasl_mech %s", | |
430 | ctxt->auth_required, ctxt->sasl_mech); | |
431 | @@ -407,23 +423,19 @@ static LDAP *do_connect(struct lookup_context *ctxt) | |
432 | debug(LOGOPT_NONE, MODPREFIX "ldap anonymous bind returned %d", rv); | |
433 | #endif | |
434 | ||
435 | - if (rv != 0) { | |
436 | - unbind_ldap_connection(ldap, ctxt); | |
437 | - return NULL; | |
438 | - } | |
439 | + if (rv != 0) | |
440 | + return 0; | |
441 | ||
442 | rv = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host); | |
443 | if (rv != LDAP_SUCCESS || !host) { | |
444 | - unbind_ldap_connection(ldap, ctxt); | |
445 | debug(LOGOPT_ANY, "failed to get hostname for connection"); | |
446 | - return NULL; | |
447 | + return 0; | |
448 | } | |
449 | ||
450 | nhost = strdup(host); | |
451 | if (!nhost) { | |
452 | - unbind_ldap_connection(ldap, ctxt); | |
453 | debug(LOGOPT_ANY, "failed to alloc context for hostname"); | |
454 | - return NULL; | |
455 | + return 0; | |
456 | } | |
457 | ldap_memfree(host); | |
458 | ||
459 | @@ -443,7 +455,7 @@ static LDAP *do_connect(struct lookup_context *ctxt) | |
460 | } | |
461 | ||
462 | if (!need_base) | |
463 | - return ldap; | |
464 | + return 1; | |
465 | ||
466 | /* | |
467 | * If the schema isn't defined in the configuration then check for | |
468 | @@ -452,20 +464,134 @@ static LDAP *do_connect(struct lookup_context *ctxt) | |
469 | */ | |
470 | if (!ctxt->schema) { | |
471 | if (!find_query_dn(ldap, ctxt)) { | |
472 | - unbind_ldap_connection(ldap, ctxt); | |
473 | error(LOGOPT_ANY, | |
474 | MODPREFIX "failed to find valid query dn"); | |
475 | - return NULL; | |
476 | + return 0; | |
477 | } | |
478 | } else { | |
479 | const char *class = ctxt->schema->map_class; | |
480 | const char *key = ctxt->schema->map_attr; | |
481 | if (!get_query_dn(ldap, ctxt, class, key)) { | |
482 | - unbind_ldap_connection(ldap, ctxt); | |
483 | error(LOGOPT_ANY, MODPREFIX "failed to get query dn"); | |
484 | + return 0; | |
485 | + } | |
486 | + } | |
487 | + | |
488 | + return 1; | |
489 | +} | |
490 | + | |
491 | +static LDAP *do_connect(const char *uri, struct lookup_context *ctxt) | |
492 | +{ | |
493 | + LDAP *ldap; | |
494 | + | |
495 | + ldap = init_ldap_connection(uri, ctxt); | |
496 | + if (!ldap) | |
497 | + return NULL; | |
498 | + | |
499 | + if (!do_bind(ldap, ctxt)) { | |
500 | + unbind_ldap_connection(ldap, ctxt); | |
501 | + return NULL; | |
502 | + } | |
503 | + | |
504 | + return ldap; | |
505 | +} | |
506 | + | |
507 | +static LDAP *connect_to_server(const char *uri, struct lookup_context *ctxt) | |
508 | +{ | |
509 | + LDAP *ldap; | |
510 | + | |
511 | +#ifdef WITH_SASL | |
512 | + /* | |
513 | + * Determine which authentication mechanism to use if we require | |
514 | + * authentication. | |
515 | + */ | |
516 | + if (ctxt->auth_required & LDAP_AUTH_REQUIRED) { | |
517 | + ldap = auth_init(uri, ctxt); | |
518 | + if (!ldap && ctxt->auth_required & LDAP_AUTH_AUTODETECT) | |
519 | + warn(LOGOPT_NONE, | |
520 | + "no authentication mechanisms auto detected."); | |
521 | + if (!ldap) { | |
522 | + error(LOGOPT_ANY, MODPREFIX | |
523 | + "cannot initialize authentication setup"); | |
524 | return NULL; | |
525 | } | |
526 | + | |
527 | + if (!do_bind(ldap, ctxt)) { | |
528 | + unbind_ldap_connection(ldap, ctxt); | |
529 | + error(LOGOPT_ANY, MODPREFIX "cannot bind to server"); | |
530 | + return NULL; | |
531 | + } | |
532 | + | |
533 | + return ldap; | |
534 | + } | |
535 | +#endif | |
536 | + | |
537 | + ldap = do_connect(uri, ctxt); | |
538 | + if (!ldap) { | |
539 | + error(LOGOPT_ANY, MODPREFIX "cannot connect to server"); | |
540 | + return NULL; | |
541 | + } | |
542 | + | |
543 | + return ldap; | |
544 | +} | |
545 | + | |
546 | +static LDAP *find_server(struct lookup_context *ctxt) | |
547 | +{ | |
548 | + LDAP *ldap = NULL; | |
549 | + struct ldap_uri *this; | |
550 | + struct list_head *p; | |
551 | + LIST_HEAD(tmp); | |
552 | + | |
553 | + /* Try each uri in list, add connect fails to tmp list */ | |
554 | + p = ctxt->uri->next; | |
555 | + while(p != ctxt->uri) { | |
556 | + this = list_entry(p, struct ldap_uri, list); | |
557 | + p = p->next; | |
558 | + debug(LOGOPT_ANY, "check uri %s", this->uri); | |
559 | + ldap = connect_to_server(this->uri, ctxt); | |
560 | + if (ldap) { | |
561 | + debug(LOGOPT_ANY, "connexted to uri %s", this->uri); | |
562 | + break; | |
563 | + } | |
564 | + list_del_init(&this->list); | |
565 | + list_add_tail(&this->list, &tmp); | |
566 | } | |
567 | + /* | |
568 | + * Successfuly connected uri (head of list) and untried uris are | |
569 | + * in ctxt->uri list. Make list of remainder and failed uris with | |
570 | + * failed uris at end and assign back to ctxt-uri. | |
571 | + */ | |
572 | + list_splice(ctxt->uri, &tmp); | |
573 | + INIT_LIST_HEAD(ctxt->uri); | |
574 | + list_splice(&tmp, ctxt->uri); | |
575 | + | |
576 | + return ldap; | |
577 | +} | |
578 | + | |
579 | +static LDAP *do_reconnect(struct lookup_context *ctxt) | |
580 | +{ | |
581 | + LDAP *ldap; | |
582 | + | |
583 | + if (ctxt->server || !ctxt->uri) { | |
584 | + ldap = do_connect(ctxt->server, ctxt); | |
585 | + return ldap; | |
586 | + } else { | |
587 | + struct ldap_uri *this; | |
588 | + this = list_entry(ctxt->uri->next, struct ldap_uri, list); | |
589 | + ldap = do_connect(this->uri, ctxt); | |
590 | + if (ldap) | |
591 | + return ldap; | |
592 | + /* Failed to connect, put at end of list */ | |
593 | + list_del_init(&this->list); | |
594 | + list_add_tail(&this->list, ctxt->uri); | |
595 | + } | |
596 | + | |
597 | + autofs_sasl_done(ctxt); | |
598 | + | |
599 | + /* Current server failed connect, try the rest */ | |
600 | + ldap = find_server(ctxt); | |
601 | + if (!ldap) | |
602 | + error(LOGOPT_ANY, MODPREFIX "failed to find available server"); | |
603 | ||
604 | return ldap; | |
605 | } | |
606 | @@ -760,10 +886,10 @@ out: | |
607 | * information. If there is no configuration file, then we fall back to | |
608 | * trying all supported authentication mechanisms until one works. | |
609 | * | |
610 | - * Returns 0 on success, with authtype, user and secret filled in as | |
611 | - * appropriate. Returns -1 on failre. | |
612 | + * Returns ldap connection on success, with authtype, user and secret | |
613 | + * filled in as appropriate. Returns NULL on failre. | |
614 | */ | |
615 | -int auth_init(struct lookup_context *ctxt) | |
616 | +static LDAP *auth_init(const char *uri, struct lookup_context *ctxt) | |
617 | { | |
618 | int ret; | |
619 | LDAP *ldap; | |
620 | @@ -776,14 +902,11 @@ int auth_init(struct lookup_context *ctxt) | |
621 | */ | |
622 | ret = parse_ldap_config(ctxt); | |
623 | if (ret) | |
624 | - return -1; | |
625 | - | |
626 | - if (ctxt->auth_required & LDAP_AUTH_NOTREQUIRED) | |
627 | - return 0; | |
628 | + return NULL; | |
629 | ||
630 | - ldap = init_ldap_connection(ctxt); | |
631 | + ldap = init_ldap_connection(uri, ctxt); | |
632 | if (!ldap) | |
633 | - return -1; | |
634 | + return NULL; | |
635 | ||
636 | /* | |
637 | * Initialize the sasl library. It is okay if user and secret | |
638 | @@ -794,18 +917,12 @@ int auth_init(struct lookup_context *ctxt) | |
639 | * the credential cache and the client and service principals. | |
640 | */ | |
641 | ret = autofs_sasl_init(ldap, ctxt); | |
642 | - unbind_ldap_connection(ldap, ctxt); | |
643 | if (ret) { | |
644 | ctxt->sasl_mech = NULL; | |
645 | - if (ctxt->auth_required & LDAP_AUTH_AUTODETECT) { | |
646 | - warn(LOGOPT_NONE, | |
647 | - "no authentication mechanisms auto detected."); | |
648 | - return 0; | |
649 | - } | |
650 | - return -1; | |
651 | + return NULL; | |
652 | } | |
653 | ||
654 | - return 0; | |
655 | + return ldap; | |
656 | } | |
657 | #endif | |
658 | ||
659 | @@ -1036,6 +1153,8 @@ static void free_context(struct lookup_context *ctxt) | |
660 | free(ctxt->cur_host); | |
661 | if (ctxt->base) | |
662 | free(ctxt->base); | |
663 | + if (ctxt->uri) | |
664 | + defaults_free_uris(ctxt->uri); | |
665 | if (ctxt->sdns) | |
666 | defaults_free_searchdns(ctxt->sdns); | |
667 | free(ctxt); | |
668 | @@ -1043,6 +1162,30 @@ static void free_context(struct lookup_context *ctxt) | |
669 | return; | |
670 | } | |
671 | ||
672 | +static void validate_uris(struct list_head *list) | |
673 | +{ | |
674 | + struct list_head *next; | |
675 | + | |
676 | + next = list->next; | |
677 | + while (next != list) { | |
678 | + struct ldap_uri *this; | |
679 | + | |
680 | + this = list_entry(next, struct ldap_uri, list); | |
681 | + next = next->next; | |
682 | + | |
683 | + /* At least we get some basic validation */ | |
684 | + if (!ldap_is_ldap_url(this->uri)) { | |
685 | + warn(LOGOPT_ANY, | |
686 | + "removed invalid uri from list, %s", this->uri); | |
687 | + list_del(&this->list); | |
688 | + free(this->uri); | |
689 | + free(this); | |
690 | + } | |
691 | + } | |
692 | + | |
693 | + return; | |
694 | +} | |
695 | + | |
696 | /* | |
697 | * This initializes a context (persistent non-global data) for queries to | |
698 | * this module. Return zero if we succeed. | |
699 | @@ -1051,7 +1194,6 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co | |
700 | { | |
701 | struct lookup_context *ctxt; | |
702 | char buf[MAX_ERR_BUF]; | |
703 | - int ret; | |
704 | LDAP *ldap = NULL; | |
705 | ||
706 | *context = NULL; | |
707 | @@ -1079,33 +1221,42 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co | |
708 | return 1; | |
709 | } | |
710 | ||
711 | -#ifdef WITH_SASL | |
712 | - /* | |
713 | - * Determine which authentication mechanism to use. We sanity- | |
714 | - * check by binding to the server temporarily. | |
715 | - */ | |
716 | - ret = auth_init(ctxt); | |
717 | - if (ret && (ctxt->auth_required & LDAP_AUTH_REQUIRED)) { | |
718 | - error(LOGOPT_ANY, MODPREFIX | |
719 | - "cannot initialize authentication setup"); | |
720 | - free_context(ctxt); | |
721 | - return 1; | |
722 | + ctxt->timeout = defaults_get_ldap_timeout(); | |
723 | + ctxt->network_timeout = defaults_get_ldap_network_timeout(); | |
724 | + | |
725 | + if (!ctxt->server) { | |
726 | + struct list_head *uris = defaults_get_uris(); | |
727 | + if (uris) { | |
728 | + validate_uris(uris); | |
729 | + if (!list_empty(uris)) | |
730 | + ctxt->uri = uris; | |
731 | + else | |
732 | + free(uris); | |
733 | + } | |
734 | } | |
735 | -#endif | |
736 | ||
737 | - ldap = do_connect(ctxt); | |
738 | - if (!ldap) { | |
739 | - error(LOGOPT_ANY, MODPREFIX "cannot connect to server"); | |
740 | - free_context(ctxt); | |
741 | - return 1; | |
742 | + if (ctxt->server || !ctxt->uri) { | |
743 | + ldap = connect_to_server(ctxt->server, ctxt); | |
744 | + if (!ldap) { | |
745 | + free_context(ctxt); | |
746 | + return 1; | |
747 | + } | |
748 | + } else { | |
749 | + ldap = find_server(ctxt); | |
750 | + if (!ldap) { | |
751 | + free_context(ctxt); | |
752 | + error(LOGOPT_ANY, MODPREFIX | |
753 | + "failed to find available server"); | |
754 | + return 1; | |
755 | + } | |
756 | } | |
757 | unbind_ldap_connection(ldap, ctxt); | |
758 | ||
759 | /* Open the parser, if we can. */ | |
760 | ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1); | |
761 | if (!ctxt->parse) { | |
762 | - crit(LOGOPT_ANY, MODPREFIX "failed to open parse context"); | |
763 | free_context(ctxt); | |
764 | + crit(LOGOPT_ANY, MODPREFIX "failed to open parse context"); | |
765 | return 1; | |
766 | } | |
767 | *context = ctxt; | |
768 | @@ -1153,7 +1304,7 @@ int lookup_read_master(struct master *master, time_t age, void *context) | |
769 | query[l] = '\0'; | |
770 | ||
771 | /* Initialize the LDAP context. */ | |
772 | - ldap = do_connect(ctxt); | |
773 | + ldap = do_reconnect(ctxt); | |
774 | if (!ldap) | |
775 | return NSS_STATUS_UNAVAIL; | |
776 | ||
777 | @@ -1305,7 +1456,7 @@ static int read_one_map(struct autofs_point *ap, | |
778 | query[l] = '\0'; | |
779 | ||
780 | /* Initialize the LDAP context. */ | |
781 | - ldap = do_connect(ctxt); | |
782 | + ldap = do_reconnect(ctxt); | |
783 | if (!ldap) | |
784 | return NSS_STATUS_UNAVAIL; | |
785 | ||
786 | @@ -1536,6 +1687,9 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context) | |
787 | if (ret != NSS_STATUS_SUCCESS) { | |
788 | switch (rv) { | |
789 | case LDAP_SIZELIMIT_EXCEEDED: | |
790 | + crit(ap->logopt, MODPREFIX | |
791 | + "Unable to download entire LDAP map for: %s", | |
792 | + ap->path); | |
793 | case LDAP_UNWILLING_TO_PERFORM: | |
794 | pthread_setcancelstate(cur_state, NULL); | |
795 | return NSS_STATUS_UNAVAIL; | |
796 | @@ -1612,7 +1766,7 @@ static int lookup_one(struct autofs_point *ap, | |
797 | query[ql] = '\0'; | |
798 | ||
799 | /* Initialize the LDAP context. */ | |
800 | - ldap = do_connect(ctxt); | |
801 | + ldap = do_reconnect(ctxt); | |
802 | if (!ldap) | |
803 | return CHE_FAIL; | |
804 | ||
805 | diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in | |
806 | index 2b1e20a..f01ee5f 100644 | |
807 | --- a/redhat/autofs.sysconfig.in | |
808 | +++ b/redhat/autofs.sysconfig.in | |
809 | @@ -23,6 +23,25 @@ BROWSE_MODE="no" | |
810 | # | |
811 | # Define base dn for map dn lookup. | |
812 | # | |
813 | +# Define server URIs | |
814 | +# | |
815 | +# LDAP_URI - space seperated list of server uris of the form | |
816 | +# <proto>://<server>[/] where <proto> can be ldap | |
817 | +# or ldaps. The option can be given multiple times. | |
818 | +# Map entries that include a server name override | |
819 | +# this option. | |
820 | +# | |
821 | +#LDAP_URI="" | |
822 | +# | |
823 | +# LDAP__TIMEOUT - timeout value for the synchronous API calls | |
824 | +# (default is LDAP library default). | |
825 | +# | |
826 | +#LDAP_TIMEOUT=-1 | |
827 | +# | |
828 | +# LDAP_NETWORK_TIMEOUT - set the network response timeout (default 8). | |
829 | +# | |
830 | +#LDAP_NETWORK_TIMEOUT=8 | |
831 | +# | |
832 | # SEARCH_BASE - base dn to use for searching for map search dn. | |
833 | # Multiple entries can be given and they are checked | |
834 | # in the order they occur here. | |
835 | diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in | |
836 | index 2b1e20a..028341c 100644 | |
837 | --- a/samples/autofs.conf.default.in | |
838 | +++ b/samples/autofs.conf.default.in | |
839 | @@ -21,6 +21,25 @@ BROWSE_MODE="no" | |
840 | # | |
841 | #LOGGING="none" | |
842 | # | |
843 | +# Define server URIs | |
844 | +# | |
845 | +# LDAP_URI - space seperated list of server uris of the form | |
846 | +# <proto>://<server>[/] where <proto> can be ldap | |
847 | +# or ldaps. The option can be given multiple times. | |
848 | +# Map entries that include a server name override | |
849 | +# this option. | |
850 | +# | |
851 | +#LDAP_URI="" | |
852 | +# | |
853 | +# LDAP__TIMEOUT - timeout value for the synchronous API calls | |
854 | +# (default is LDAP library default). | |
855 | +# | |
856 | +#LDAP_TIMEOUT=-1 | |
857 | +# | |
858 | +# LDAP_NETWORK_TIMEOUT - set the network response timeout (default 8). | |
859 | +# | |
860 | +#LDAP_NETWORK_TIMEOUT=8 | |
861 | +# | |
862 | # Define base dn for map dn lookup. | |
863 | # | |
864 | # SEARCH_BASE - base dn to use for searching for map search dn. |