1 diff --git a/CHANGELOG b/CHANGELOG
2 index 08afa7c..c208b31 100644
6 - fix couple of edge case parse fails of timeout option.
7 - check for "*" when looking up wildcard in LDAP.
8 - fix LDAP schema discovery.
9 +- add SEARCH_BASE configuration option.
11 18/06/2007 autofs-5.0.2
12 -----------------------
13 diff --git a/include/defaults.h b/include/defaults.h
14 index 9aec11a..0984b1c 100644
15 --- a/include/defaults.h
16 +++ b/include/defaults.h
18 #define DEFAULT_APPEND_OPTIONS 1
19 #define DEFAULT_AUTH_CONF_FILE AUTOFS_MAP_DIR "/autofs_ldap_auth.conf"
22 +struct ldap_searchdn;
24 unsigned int defaults_read_config(void);
25 const char *defaults_get_master_map(void);
26 unsigned int defaults_get_timeout(void);
27 @@ -45,6 +48,8 @@ unsigned int defaults_get_logging(void);
28 const char *defaults_get_ldap_server(void);
29 struct ldap_schema *defaults_get_default_schema(void);
30 struct ldap_schema *defaults_get_schema(void);
31 +struct ldap_searchdn *defaults_get_searchdns(void);
32 +void defaults_free_searchdns(struct ldap_searchdn *);
33 unsigned int defaults_get_append_options(void);
34 const char *defaults_get_auth_conf_file(void);
36 diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
37 index 1378b9e..1a924be 100644
38 --- a/include/lookup_ldap.h
39 +++ b/include/lookup_ldap.h
40 @@ -18,6 +18,11 @@ struct ldap_schema {
44 +struct ldap_searchdn {
46 + struct ldap_searchdn *next;
49 struct lookup_context {
52 @@ -32,6 +37,10 @@ struct lookup_context {
53 /* LDAP lookup configuration */
54 struct ldap_schema *schema;
56 + /* List of base dns for searching */
58 + struct ldap_searchdn *sdns;
60 /* TLS and SASL authentication information */
63 diff --git a/lib/defaults.c b/lib/defaults.c
64 index b146f13..c2f86c0 100644
69 #define ENV_LDAP_SERVER "LDAP_SERVER"
71 +#define SEARCH_BASE "SEARCH_BASE"
73 #define ENV_NAME_MAP_OBJ_CLASS "MAP_OBJECT_CLASS"
74 #define ENV_NAME_ENTRY_OBJ_CLASS "ENTRY_OBJECT_CLASS"
75 #define ENV_NAME_MAP_ATTR "MAP_ATTRIBUTE"
76 @@ -130,6 +132,52 @@ static int check_set_config_value(const char *res, const char *name, const char
80 +static int parse_line(char *line, char **res, char **value)
82 + volatile char *key, *val, *trailer;
87 + if (*key == '#' || !isalpha(*key))
90 + while (*key && *key == ' ')
96 + if (!(val = strchr(key, '=')))
101 + while (*val && (*val == '"' || isblank(*val)))
106 + if (val[len - 1] == '\n') {
107 + val[len - 1] = '\0';
111 + trailer = strchr(val, '#');
113 + trailer = val + len - 1;
117 + while (*trailer && (*trailer == '"' || isblank(*trailer)))
118 + *(trailer--) = '\0';;
127 * Read config env variables and check they have been set.
129 @@ -141,61 +189,30 @@ unsigned int defaults_read_config(void)
132 char buf[MAX_LINE_LEN];
136 f = fopen(DEFAULTS_CONFIG_FILE, "r");
140 while ((res = fgets(buf, MAX_LINE_LEN, f))) {
144 - if (*res == '#' || !isalpha(*res))
147 - while (*res && *res == ' ')
154 - if (!(value = strchr(res, '=')))
155 + if (!parse_line(res, &key, &value))
160 - while (*value && (*value == '"' || isblank(*value)))
163 - len = strlen(value);
165 - if (value[len - 1] == '\n') {
166 - value[len - 1] = '\0';
170 - trailer = strchr(value, '#');
172 - trailer = value + len - 1;
176 - while (*trailer && (*trailer == '"' || isblank(*trailer)))
177 - *(trailer--) = '\0';;
179 - if (check_set_config_value(res, ENV_NAME_MASTER_MAP, value) ||
180 - check_set_config_value(res, ENV_NAME_TIMEOUT, value) ||
181 - check_set_config_value(res, ENV_NAME_BROWSE_MODE, value) ||
182 - check_set_config_value(res, ENV_NAME_LOGGING, value) ||
183 - check_set_config_value(res, ENV_LDAP_SERVER, value) ||
184 - check_set_config_value(res, ENV_NAME_MAP_OBJ_CLASS, value) ||
185 - check_set_config_value(res, ENV_NAME_ENTRY_OBJ_CLASS, value) ||
186 - check_set_config_value(res, ENV_NAME_MAP_ATTR, value) ||
187 - check_set_config_value(res, ENV_NAME_ENTRY_ATTR, value) ||
188 - check_set_config_value(res, ENV_NAME_VALUE_ATTR, value) ||
189 - check_set_config_value(res, ENV_APPEND_OPTIONS, value) ||
190 - check_set_config_value(res, ENV_AUTH_CONF_FILE, value))
191 + if (check_set_config_value(key, ENV_NAME_MASTER_MAP, value) ||
192 + check_set_config_value(key, ENV_NAME_TIMEOUT, value) ||
193 + check_set_config_value(key, ENV_NAME_BROWSE_MODE, value) ||
194 + check_set_config_value(key, ENV_NAME_LOGGING, value) ||
195 + check_set_config_value(key, ENV_LDAP_SERVER, value) ||
196 + check_set_config_value(key, ENV_NAME_MAP_OBJ_CLASS, value) ||
197 + check_set_config_value(key, ENV_NAME_ENTRY_OBJ_CLASS, value) ||
198 + check_set_config_value(key, ENV_NAME_MAP_ATTR, value) ||
199 + check_set_config_value(key, ENV_NAME_ENTRY_ATTR, value) ||
200 + check_set_config_value(key, ENV_NAME_VALUE_ATTR, value) ||
201 + check_set_config_value(key, ENV_APPEND_OPTIONS, value) ||
202 + check_set_config_value(key, ENV_AUTH_CONF_FILE, value))
206 @@ -336,6 +353,86 @@ struct ldap_schema *defaults_get_default_schema(void)
210 +static struct ldap_searchdn *alloc_searchdn(const char *value)
212 + struct ldap_searchdn *sdn;
215 + sdn = malloc(sizeof(struct ldap_searchdn));
219 + val = strdup(value);
231 +void defaults_free_searchdns(struct ldap_searchdn *sdn)
233 + struct ldap_searchdn *this = sdn;
234 + struct ldap_searchdn *next;
239 + free(this->basedn);
247 +struct ldap_searchdn *defaults_get_searchdns(void)
250 + char buf[MAX_LINE_LEN];
252 + struct ldap_searchdn *sdn, *last;
254 + f = fopen(DEFAULTS_CONFIG_FILE, "r");
260 + while ((res = fgets(buf, MAX_LINE_LEN, f))) {
263 + if (!parse_line(res, &key, &value))
266 + if (!strcasecmp(key, SEARCH_BASE)) {
267 + struct ldap_searchdn *new = alloc_searchdn(value);
270 + defaults_free_searchdns(sdn);
290 struct ldap_schema *defaults_get_schema(void)
292 struct ldap_schema *schema;
293 diff --git a/man/auto.master.5.in b/man/auto.master.5.in
294 index ab5ab1e..0cb2f07 100644
295 --- a/man/auto.master.5.in
296 +++ b/man/auto.master.5.in
297 @@ -230,6 +230,11 @@ values must be set, any partial schema specification will be ignored.
299 The configuration settings available are:
302 +The base dn to use when searching for amap base dn. This entry may be
303 +given multiple times and each will be checked for a map base dn in
304 +the order they occur in the configuration.
307 The map object class. In the \fBnisMap\fP schema this corresponds to the class
308 \fBnisMap\fP and in the \fBautomountMap\fP schema it corresponds to the class
309 diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
310 index 9c18ca1..da52e71 100644
311 --- a/modules/lookup_ldap.c
312 +++ b/modules/lookup_ldap.c
313 @@ -171,10 +171,207 @@ LDAP *init_ldap_connection(struct lookup_context *ctxt)
317 +static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
319 + char buf[PARSE_MAX_BUF];
321 + LDAPMessage *result = NULL, *e;
322 + struct ldap_searchdn *sdns = NULL;
327 + attrs[0] = LDAP_NO_ATTRS;
330 + if (!ctxt->mapname && !ctxt->base) {
331 + error(LOGOPT_ANY, MODPREFIX "no master map to lookup");
335 + /* Build a query string. */
336 + l = strlen("(objectclass=)") + strlen(class) + 1;
338 + l += strlen(key) + strlen(ctxt->mapname) + strlen("(&(=))");
341 + if (query == NULL) {
342 + char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
343 + crit(LOGOPT_ANY, MODPREFIX "alloca: %s", estr);
344 + return NSS_STATUS_UNAVAIL;
348 + * If we have a master mapname construct a query using it
349 + * otherwise assume the base dn will catch it.
351 + if (ctxt->mapname) {
352 + if (sprintf(query, "(&(objectclass=%s)(%s=%.*s))", class,
353 + key, (int) strlen(ctxt->mapname), ctxt->mapname) >= l) {
355 + MODPREFIX "error forming query string");
358 + scope = LDAP_SCOPE_SUBTREE;
360 + if (sprintf(query, "(objectclass=%s)", class) >= l) {
362 + MODPREFIX "error forming query string");
365 + scope = LDAP_SCOPE_SUBTREE;
370 + sdns = defaults_get_searchdns();
376 + rv = ldap_search_s(ldap, ctxt->base,
377 + scope, query, attrs, 0, &result);
379 + struct ldap_searchdn *this = sdns;
381 + debug(LOGOPT_NONE, MODPREFIX
382 + "check search base list");
385 + rv = ldap_search_s(ldap, this->basedn,
386 + scope, query, attrs, 0, &result);
388 + if ((rv == LDAP_SUCCESS) && result) {
389 + debug(LOGOPT_NONE, MODPREFIX
390 + "found search base under %s",
398 + ldap_msgfree(result);
404 + if ((rv != LDAP_SUCCESS) || !result) {
406 + MODPREFIX "query failed for %s: %s",
407 + query, ldap_err2string(rv));
411 + e = ldap_first_entry(ldap, result);
413 + dn = ldap_get_dn(ldap, e);
414 + debug(LOGOPT_NONE, MODPREFIX "query dn %s", dn);
415 + ldap_msgfree(result);
418 + MODPREFIX "query succeeded, no matches for %s",
420 + ldap_msgfree(result);
429 +static struct ldap_schema *alloc_common_schema(struct ldap_schema *s)
431 + struct ldap_schema *schema;
432 + char *mc, *ma, *ec, *ea, *va;
434 + mc = strdup(s->map_class);
438 + ma = strdup(s->map_attr);
444 + ec = strdup(s->entry_class);
451 + ea = strdup(s->entry_attr);
459 + va = strdup(s->value_attr);
468 + schema = malloc(sizeof(struct ldap_schema));
478 + schema->map_class = mc;
479 + schema->map_attr = ma;
480 + schema->entry_class = ec;
481 + schema->entry_attr = ea;
482 + schema->value_attr = va;
487 +static int find_query_dn(LDAP *ldap, struct lookup_context *ctxt)
489 + struct ldap_schema *schema;
495 + for (i = 0; i < common_schema_count; i++) {
496 + const char *class = common_schema[i].map_class;
497 + const char *key = common_schema[i].map_attr;
498 + if (get_query_dn(ldap, ctxt, class, key)) {
499 + schema = alloc_common_schema(&common_schema[i]);
502 + MODPREFIX "failed to allocate schema");
505 + ctxt->schema = schema;
513 static LDAP *do_connect(struct lookup_context *ctxt)
517 + char *host = NULL, *nhost;
518 + int rv, need_base = 1;
520 ldap = init_ldap_connection(ctxt);
522 @@ -204,6 +401,61 @@ static LDAP *do_connect(struct lookup_context *ctxt)
526 + rv = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host);
527 + if (rv != LDAP_SUCCESS || !host) {
528 + unbind_ldap_connection(ldap, ctxt);
529 + debug(LOGOPT_ANY, "failed to get hostname for connection");
533 + nhost = strdup(host);
535 + unbind_ldap_connection(ldap, ctxt);
536 + debug(LOGOPT_ANY, "failed to alloc context for hostname");
539 + ldap_memfree(host);
541 + if (!ctxt->cur_host) {
542 + ctxt->cur_host = nhost;
543 + /* Check if schema defined in conf first time only */
544 + ctxt->schema = defaults_get_schema();
546 + /* If connection host has changed update */
547 + if (strcmp(ctxt->cur_host, nhost)) {
548 + free(ctxt->cur_host);
549 + ctxt->cur_host = nhost;
560 + * If the schema isn't defined in the configuration then check for
561 + * presence of a map dn with a the common schema. Then calculate the
562 + * base dn for searches.
564 + if (!ctxt->schema) {
565 + if (!find_query_dn(ldap, ctxt)) {
566 + unbind_ldap_connection(ldap, ctxt);
568 + MODPREFIX "failed to find valid query dn");
572 + const char *class = ctxt->schema->map_class;
573 + const char *key = ctxt->schema->map_attr;
574 + if (!get_query_dn(ldap, ctxt, class, key)) {
575 + unbind_ldap_connection(ldap, ctxt);
576 + error(LOGOPT_ANY, MODPREFIX "failed to get query dn");
584 @@ -769,175 +1021,17 @@ static void free_context(struct lookup_context *ctxt)
585 ldap_memfree(ctxt->qdn);
588 + if (ctxt->cur_host)
589 + free(ctxt->cur_host);
593 + defaults_free_searchdns(ctxt->sdns);
599 -static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
601 - char buf[PARSE_MAX_BUF];
603 - LDAPMessage *result, *e;
608 - attrs[0] = LDAP_NO_ATTRS;
611 - if (!ctxt->mapname && !ctxt->base) {
612 - error(LOGOPT_ANY, MODPREFIX "no master map to lookup");
616 - /* Build a query string. */
617 - l = strlen("(objectclass=)") + strlen(class) + 1;
619 - l += strlen(key) + strlen(ctxt->mapname) + strlen("(&(=))");
622 - if (query == NULL) {
623 - char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
624 - crit(LOGOPT_ANY, MODPREFIX "alloca: %s", estr);
625 - return NSS_STATUS_UNAVAIL;
629 - * If we have a master mapname construct a query using it
630 - * otherwise assume the base dn will catch it.
632 - if (ctxt->mapname) {
633 - if (sprintf(query, "(&(objectclass=%s)(%s=%.*s))", class,
634 - key, (int) strlen(ctxt->mapname), ctxt->mapname) >= l) {
636 - MODPREFIX "error forming query string");
639 - scope = LDAP_SCOPE_SUBTREE;
641 - if (sprintf(query, "(objectclass=%s)", class) >= l) {
643 - MODPREFIX "error forming query string");
646 - scope = LDAP_SCOPE_SUBTREE;
650 - rv = ldap_search_s(ldap, ctxt->base, scope, query, attrs, 0, &result);
652 - if ((rv != LDAP_SUCCESS) || !result) {
654 - MODPREFIX "query failed for %s: %s",
655 - query, ldap_err2string(rv));
659 - e = ldap_first_entry(ldap, result);
661 - dn = ldap_get_dn(ldap, e);
662 - debug(LOGOPT_NONE, MODPREFIX "query dn %s", dn);
663 - ldap_msgfree(result);
666 - MODPREFIX "query succeeded, no matches for %s",
668 - ldap_msgfree(result);
677 -static struct ldap_schema *alloc_common_schema(struct ldap_schema *s)
679 - struct ldap_schema *schema;
680 - char *mc, *ma, *ec, *ea, *va;
682 - mc = strdup(s->map_class);
686 - ma = strdup(s->map_attr);
692 - ec = strdup(s->entry_class);
699 - ea = strdup(s->entry_attr);
707 - va = strdup(s->value_attr);
716 - schema = malloc(sizeof(struct ldap_schema));
726 - schema->map_class = mc;
727 - schema->map_attr = ma;
728 - schema->entry_class = ec;
729 - schema->entry_attr = ea;
730 - schema->value_attr = va;
735 -static int find_query_dn(LDAP *ldap, struct lookup_context *ctxt)
737 - struct ldap_schema *schema;
743 - for (i = 0; i < common_schema_count; i++) {
744 - const char *class = common_schema[i].map_class;
745 - const char *key = common_schema[i].map_attr;
746 - if (get_query_dn(ldap, ctxt, class, key)) {
747 - schema = alloc_common_schema(&common_schema[i]);
750 - MODPREFIX "failed to allocate schema");
753 - ctxt->schema = schema;
762 * This initializes a context (persistent non-global data) for queries to
763 * this module. Return zero if we succeed.
764 @@ -994,31 +1088,6 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
770 - * Get default schema for queries.
771 - * If the schema isn't defined in the configuration then check for
772 - * presence of a map dn in the common schemas.
774 - ctxt->schema = defaults_get_schema();
775 - if (!ctxt->schema) {
776 - if (!find_query_dn(ldap, ctxt)) {
777 - unbind_ldap_connection(ldap, ctxt);
779 - MODPREFIX "failed to find valid query dn");
780 - free_context(ctxt);
784 - const char *class = ctxt->schema->map_class;
785 - const char *key = ctxt->schema->map_attr;
786 - if (!get_query_dn(ldap, ctxt, class, key)) {
787 - unbind_ldap_connection(ldap, ctxt);
788 - error(LOGOPT_ANY, MODPREFIX "failed to get query dn");
789 - free_context(ctxt);
793 unbind_ldap_connection(ldap, ctxt);
795 /* Open the parser, if we can. */
796 diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in
797 index 85f4e34..2b1e20a 100644
798 --- a/redhat/autofs.sysconfig.in
799 +++ b/redhat/autofs.sysconfig.in
800 @@ -21,6 +21,14 @@ BROWSE_MODE="no"
804 +# Define base dn for map dn lookup.
806 +# SEARCH_BASE - base dn to use for searching for map search dn.
807 +# Multiple entries can be given and they are checked
808 +# in the order they occur here.
812 # Define the LDAP schema to used for lookups
814 # If no schema is set autofs will check each of the schemas
815 diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in
816 index 85f4e34..2b1e20a 100644
817 --- a/samples/autofs.conf.default.in
818 +++ b/samples/autofs.conf.default.in
819 @@ -21,6 +21,14 @@ BROWSE_MODE="no"
823 +# Define base dn for map dn lookup.
825 +# SEARCH_BASE - base dn to use for searching for map search dn.
826 +# Multiple entries can be given and they are checked
827 +# in the order they occur here.
831 # Define the LDAP schema to used for lookups
833 # If no schema is set autofs will check each of the schemas