---
 CHANGELOG             |    9 ++
 daemon/automount.c    |    8 +-
 include/automount.h   |    1 +
 man/automount.8       |    8 ++
 modules/lookup_ldap.c |  275 ++++++++++++++++++++++++++++++++-----------------
 5 files changed, 206 insertions(+), 95 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index c40a670..04043c5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,10 @@
+29/06/2010 autofs-4.1.4-p40
+---------------------------
+  Reinstates the jmoyer ldap-cleanup.patch from 4.1.3 which does cleaner LDAP 
schema handling. 
+  It only looks up the schema once and then remembers it for every requested 
path under a mount point.
+  It  includes the --use_old_ldap_lookup or -u option to make the code search 
every schema every time the way it used to.
+  bryder changed the original patch is to invert the search order so the most 
modern schema (rfc2307bis) is checked first
+  bryder added the option to the man page and help output from automount.c
 
 18/6/2010 autofs-4.1.4 - bryder p39
 -----------------------------------
@@ -19,6 +26,8 @@ Also help to the automount.c command for this option and 
updated the man page.
 Only tested with LDAP.
 
 
+
+
 11/4/2005 autofs-4.1.4
 ----------------------
 - add /proc/modules check to Debian init script.
diff --git a/daemon/automount.c b/daemon/automount.c
index 93e3ff7..0ef9cbb 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -1382,7 +1382,7 @@ static void usage(void)
 {
        fprintf(stderr, "Usage: %s [options] path map_type [args...]\n", 
program);
        fprintf(stderr, "   -D|--dumpmap dumps out the maps read and exits\n");
-
+       fprintf(stderr, "   -u|--use-old-ldap-lookup instead of figuring out 
the schema once do it every single time a mount is requested. This is the old 
behaviour\n");
 }
 
 static void setup_signals(__sighandler_t event_handler, __sighandler_t 
cld_handler)
@@ -1675,6 +1675,7 @@ int main(int argc, char *argv[])
                {"ghost", 0, 0, 'g'},
                {"submount", 0, &submount, 1},
                {"dumpmap", 0, 0, 'D'},
+               {"use-old-ldap-lookup", 0, 0, 'u'},
                {0, 0, 0, 0}
        };
 
@@ -1687,7 +1688,7 @@ int main(int argc, char *argv[])
        ap.dir_created = 0; /* We haven't created the main directory yet */
 
        opterr = 0;
-       while ((opt = getopt_long(argc, argv, "+hp:t:vdVgD", long_options, 
NULL)) != EOF) {
+       while ((opt = getopt_long(argc, argv, "+hp:t:vdVgDu", long_options, 
NULL)) != EOF) {
                switch (opt) {
                case 'h':
                        usage();
@@ -1720,6 +1721,9 @@ int main(int argc, char *argv[])
                case 'D':
                        dumpmap = 1;
                        break;
+               case 'u':
+                       ap.use_old_ldap_lookup = 1;
+                       break;
                case '?':
                case ':':
                        printf("%s: Ambiguous or unknown options\n", program);
diff --git a/include/automount.h b/include/automount.h
index 64ff83d..fa97764 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -113,6 +113,7 @@ struct autofs_point {
        int state_pipe[2];
        unsigned dir_created;           /* Was a directory created for this
                                           mount? */
+       unsigned use_old_ldap_lookup;   /* query all schemas every time instead 
of sticking with the first one found */
 };
 
 extern struct autofs_point ap; 
diff --git a/man/automount.8 b/man/automount.8
index e640656..5dc597b 100644
--- a/man/automount.8
+++ b/man/automount.8
@@ -46,6 +46,14 @@ Display the version number, then exit.
 .TP
 .I "\-D, \-\-dumpmap"
 Dumps the maps read and exits.
+.TP
+.I "\-u, \-\-use\-old\-ldap\-lookup"
+By default automount will use new code for finding the correct ldap
+schema. It starts with rfc2307bis, then does the netscape one, then
+the original rfc2307 schema. It only checks once for each mount point
+and remembers the schema for the rest of the automount invocation.
+If you set this flag it will do it the old way which involves looking
+for the schema every time a mount is requested.
 .SH ARGUMENTS
 \fBautomount\fP takes at least three arguments.  Mandatory arguments 
 include \fImount-point\fP, \fImap-type\fP, and \fImap\fP.  Both mandatory
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index f8ed7fc..1c5c62a 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -39,14 +39,57 @@
 
 #define MODPREFIX "lookup(ldap): "
 
+/*
+ *  Automount entries are stored hierarchically, with the map name as the base
+ *  dn for searches on entries for that map.  Thus, to obtain the base dn for
+ *  the master map, one would use the following filter:
+ *    (&(objectclass=<map_object_class>)(<map_name_attr>="auto.master"))
+ *  Once the base dn is obtained (using ldap_get_first_entry, followed by
+ *  ldap_get_dn), the following filter will return all entries for the given
+ *  map:
+ *    (objectclass=<entry_object_class>)
+ *  The attributes of interest are <entry_key_attr>, or the key, and
+ *  <entry_value_attr> or the value portion of the automount map entry.
+ */
+struct autofs_schema {
+       char *map_object_class;
+       char *map_name_attr;
+
+       char *entry_object_class;
+       char *entry_key_attr;
+       char *entry_value_attr;
+};
+
+
+#define NR_SCHEMAS     3
+struct autofs_schema supported_schemas[NR_SCHEMAS] = {
+       { "automountMap", "automountMapName",
+         "automount", "automountKey", "automountInformation" },
+       { "automountMap", "ou", "automount", "cn", "automountInformation" },
+       { "nisMap", "nisMapName", "nisObject", "cn", "nisMapEntry" },
+};
+
 struct lookup_context {
        char *server, *base;
        int port;
+
+       /* once we find a schema that works, save it for future lookups  -
+        * unless the use_old_ldap_lookup optoin is in effect in which case 
every schema is search every time.
+        */
+       struct autofs_schema *schema;
+
        struct parse_mod *parse;
 };
 
 int lookup_version = AUTOFS_LOOKUP_VERSION;    /* Required by protocol */
 
+void set_schema(struct lookup_context *ctxt, struct autofs_schema *schema)
+{
+       if (!ap.use_old_ldap_lookup) 
+               ctxt->schema = schema;
+}
+
+
 static LDAP *do_connect(struct lookup_context *ctxt, int *result_ldap)
 {
        LDAP *ldap;
@@ -57,8 +100,8 @@ static LDAP *do_connect(struct lookup_context *ctxt, int 
*result_ldap)
        /* Initialize the LDAP context. */
        ldap = ldap_init(ctxt->server, ctxt->port);
        if (!ldap) {
-               crit(MODPREFIX "couldn't initialize LDAP connection"
-                    " to %s", ctxt->server ? ctxt->server : "default server");
+               crit(MODPREFIX "%s: couldn't initialize LDAP connection"
+                    " to %s", __func__, ctxt->server ? ctxt->server : "default 
server");
                return NULL;
        }
 
@@ -69,7 +112,7 @@ static LDAP *do_connect(struct lookup_context *ctxt, int 
*result_ldap)
                ldap_unbind(ldap);
                ldap = ldap_init(ctxt->server, ctxt->port);
                if (!ldap) {
-                       crit(MODPREFIX "couldn't initialize LDAP");
+                       crit(MODPREFIX "%s: couldn't initialize LDAP for v2", 
__func__ );
                        return NULL;
                } else {
                        version = 2;
@@ -79,7 +122,7 @@ static LDAP *do_connect(struct lookup_context *ctxt, int 
*result_ldap)
        /* Sane network connection timeout */
        rv = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
        if (rv != LDAP_SUCCESS) {
-               warn(MODPREFIX
+               warn(MODPREFIX 
                     "%s: failed to set connection timeout to %d", __func__, 
timeout);
        }
 
@@ -188,9 +231,8 @@ int lookup_init(const char *mapfmt, int argc, const char 
*const *argv, void **co
        return !(ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 
1));
 }
 
-static int read_one_map(const char *root,
-                       const char *class, char *key,
-                       const char *keyval, int keyvallen, char *type,
+static int read_one_map(LDAP *ldap, const char *root,
+                       struct autofs_schema *schema,                   
                        struct lookup_context *ctxt,
                        time_t age, int *result_ldap)
 {
@@ -199,8 +241,13 @@ static int read_one_map(const char *root,
        LDAPMessage *result, *e;
        char **keyValue = NULL;
        char **values = NULL;
-       char *attrs[] = { key, type, NULL };
-       LDAP *ldap;
+       char *attrs[] = { schema->entry_key_attr,
+                         schema->entry_value_attr,
+                         NULL };
+       const char *class = schema->entry_object_class,
+                  *key = schema->entry_key_attr,
+                  *type = schema->entry_value_attr;
+       int found_entry = 0;
 
        if (ctxt == NULL) {
                crit(MODPREFIX "%s: context was NULL", __func__);
@@ -209,9 +256,6 @@ static int read_one_map(const char *root,
 
        /* Build a query string. */
        l = strlen("(objectclass=)") + strlen(class) + 1;
-       if (keyvallen > 0) {
-               l += strlen(key) +keyvallen + strlen("(&(=))");
-       }
 
        query = alloca(l);
        if (query == NULL) {
@@ -220,22 +264,11 @@ static int read_one_map(const char *root,
        }
 
        memset(query, '\0', l);
-       if (keyvallen > 0) {
-               if (sprintf(query, "(&(objectclass=%s)(%s=%.*s))", class,
-                           key, keyvallen, keyval) >= l) {
-                       debug(MODPREFIX "%s: error forming query string", 
__func__);
-               }
-       } else {
-               if (sprintf(query, "(objectclass=%s)", class) >= l) {
-                       debug(MODPREFIX "%s: error forming query string", 
__func__);
-               }
+       if (sprintf(query, "(objectclass=%s)", class) >= l) {
+               debug(MODPREFIX "error forming query string");
        }
        query[l - 1] = '\0';
 
-       /* Initialize the LDAP context. */
-       ldap = do_connect(ctxt, result_ldap);
-       if (!ldap)
-               return 0;
 
        /* Look around. */
        debug(MODPREFIX "%s: searching for \"%s\" under \"%s\"", __func__, 
query, ctxt->base);
@@ -245,7 +278,6 @@ static int read_one_map(const char *root,
 
        if ((rv != LDAP_SUCCESS) || !result) {
                crit(MODPREFIX "%s: query failed for %s: %s", __func__, query, 
ldap_err2string(rv));
-               ldap_unbind(ldap);
                *result_ldap = rv;
                return 0;
        }
@@ -254,7 +286,6 @@ static int read_one_map(const char *root,
        if (!e) {
                debug(MODPREFIX "%s: query succeeded, no matches for %s", 
__func__, query);
                ldap_msgfree(result);
-               ldap_unbind(ldap);
                return 0;
        } else
                debug(MODPREFIX "%s: examining entries", __func__ );
@@ -267,6 +298,8 @@ static int read_one_map(const char *root,
                        continue;
                }
 
+               found_entry = 1;
+
                values = ldap_get_values(ldap, e, type);
                if (!values) {
                        info(MODPREFIX "%s: no %s defined for %s", __func__, 
type, query);
@@ -295,37 +328,55 @@ static int read_one_map(const char *root,
 
        /* Clean up. */
        ldap_msgfree(result);
-       ldap_unbind(ldap);
 
-       return 1;
+       if (found_entry) 
+               return 1;
+       else
+               return 0;
 }
 
 static int read_map(const char *root, struct lookup_context *ctxt,
-                   const char *key, int keyvallen, time_t age, int 
*result_ldap)
+                   time_t age, int *result_ldap)
 {
-       int rv1 = LDAP_SUCCESS, rv2 = LDAP_SUCCESS;
-       int ret;
-
-       /* all else fails read entire map */
-       ret = read_one_map(root, "nisObject", "cn", 
-                         key, keyvallen, "nisMapEntry", ctxt, age, &rv1);
-       if (ret)
-               goto ret_ok;
+       LDAP *ldap;
+       int rv = LDAP_SUCCESS;
+       int ret, i;
 
-       ret = read_one_map(root, "automount", "cn", key, keyvallen, 
-                         "automountInformation", ctxt, age, &rv2);
-       if (ret)
-               goto ret_ok;
+       /* Initialize the LDAP context. */
+       ldap = do_connect(ctxt, &rv);
+       if (!ldap) {
+               if (rv != LDAP_SUCCESS)
+                       *result_ldap = rv;
+               return 0;
+       }
 
+       /* all else fails read entire map */
+       if (ctxt->schema) {
+               ret = read_one_map(ldap, root, ctxt->schema, ctxt, age, &rv);
+               if (ret == 1 && rv == LDAP_SUCCESS)
+                       goto ret_ok;
+       } else {
+               for (i = 0; i < NR_SCHEMAS; i++) {
+                       ret = read_one_map(ldap, root,
+                                          &supported_schemas[i],
+                                          ctxt, age, &rv);
+                       if (ret == 1 && rv == LDAP_SUCCESS) {
+                               set_schema(ctxt, &supported_schemas[i]);
+                               goto ret_ok;
+                       }
+               }
+       }
+ 
+       ldap_unbind(ldap);
        if (result_ldap)
-               *result_ldap = (rv1 == LDAP_SUCCESS ? rv2 : rv1);
+               *result_ldap = rv;
 
        return 0;
 
 ret_ok:
        /* Clean stale entries from the cache */
        cache_clean(root, age);
-
+       ldap_unbind(ldap);
        return 1;
 }
 
@@ -339,7 +390,7 @@ int lookup_ghost(const char *root, int ghost, time_t now, 
void *context)
 
        chdir("/");
 
-       if (!read_map(root, ctxt, NULL, 0, age, &rv))
+       if (!read_map(root, ctxt, age, &rv))
                switch (rv) {
                case LDAP_SIZELIMIT_EXCEEDED:
                case LDAP_UNWILLING_TO_PERFORM:
@@ -378,17 +429,21 @@ int lookup_ghost(const char *root, int ghost, time_t now, 
void *context)
        return status;
 }
 
-static int lookup_one(const char *root, const char *qKey,
-                     const char *class, char *key, char *type,
-                     struct lookup_context *ctxt)
+static int lookup_one_schema(LDAP *ldap, const char *root, const char *qKey,
+                            struct autofs_schema *schema,
+                            struct lookup_context *ctxt)
 {
        int rv, i, l, ql;
        time_t age = time(NULL);
        char *query;
        LDAPMessage *result, *e;
        char **values = NULL;
-       char *attrs[] = { key, type, NULL };
-       LDAP *ldap;
+       char *attrs[] = { schema->entry_key_attr,
+                         schema->entry_value_attr,
+                         NULL };
+       const char *class = schema->entry_object_class,
+                  *key = schema->entry_key_attr,
+                  *type = schema->entry_value_attr;
        struct mapent_cache *me = NULL;
        int ret = CHE_OK;
 
@@ -419,38 +474,29 @@ static int lookup_one(const char *root, const char *qKey,
 
        debug(MODPREFIX "%s: searching for \"%s\" under \"%s\"", __func__, 
query, ctxt->base);
 
-       /* Initialize the LDAP context. */
-       ldap = do_connect(ctxt, &rv);
-       if (!ldap)
-               return 0;
-
        rv = ldap_search_s(ldap, ctxt->base, LDAP_SCOPE_SUBTREE,
                           query, attrs, 0, &result);
 
        if ((rv != LDAP_SUCCESS) || !result) {
                crit(MODPREFIX "%s: query failed for %s", __func__, query);
-               ldap_unbind(ldap);
                return 0;
        }
 
-
        debug(MODPREFIX "%s: getting first entry for %s=\"%s\"", __func__, key, 
qKey);
+
        e = ldap_first_entry(ldap, result);
        if (!e) {
                debug(MODPREFIX "%s: got answer, but no first entry for %s", 
__func__, query);
                ldap_msgfree(result);
-               ldap_unbind(ldap);
                return CHE_MISSING;
        }
 
-
        debug(MODPREFIX "%s: examining first entry", __func__);
 
        values = ldap_get_values(ldap, e, type);
        if (!values) {
                debug(MODPREFIX "%s: no %s defined for %s", __func__, type, 
query);
                ldap_msgfree(result);
-               ldap_unbind(ldap);
                return CHE_MISSING;
        }
 
@@ -478,22 +524,51 @@ static int lookup_one(const char *root, const char *qKey,
        /* Clean up. */
        ldap_value_free(values);
        ldap_msgfree(result);
-       ldap_unbind(ldap);
 
        return ret;
 }
 
-static int lookup_wild(const char *root,
-                     const char *class, char *key, char *type,
+static int lookup_one(LDAP *ldap, const char *root, const char *qKey,
                      struct lookup_context *ctxt)
 {
+       int ret, i;
+
+       if (ctxt->schema) {
+               ret = lookup_one_schema(ldap, root, qKey, ctxt->schema, ctxt);
+               debug("lookup_one with schema %s,%s,%s returns %d\n",
+                     ctxt->schema->entry_key_attr,
+                     ctxt->schema->entry_object_class,
+                     ctxt->schema->entry_value_attr, ret);
+       } else {
+               for (i = 0; i < NR_SCHEMAS; i++) {
+                       ret = lookup_one_schema(ldap, root, qKey,
+                                        &supported_schemas[i], ctxt);
+                       debug("lookup_one with schema %d returns %d\n",i, ret);
+                       if (ret != CHE_FAIL) {
+                               set_schema(ctxt, &supported_schemas[i]);
+                               break;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+static int lookup_wild_schema(LDAP *ldap, const char *root,
+                             struct autofs_schema *schema,
+                             struct lookup_context *ctxt)
+{
        int rv, i, l, ql;
        time_t age = time(NULL);
        char *query;
        LDAPMessage *result, *e;
        char **values = NULL;
-       char *attrs[] = { key, type, NULL };
-       LDAP *ldap;
+       char *attrs[] = { schema->entry_key_attr,
+                         schema->entry_value_attr,
+                         NULL };
+       const char *class = schema->entry_object_class,
+                  *key = schema->entry_key_attr,
+                  *type = schema->entry_value_attr;
        struct mapent_cache *me = NULL;
        int ret = CHE_OK;
        char qKey[KEY_MAX_LEN + 1];
@@ -528,28 +603,20 @@ static int lookup_wild(const char *root,
 
        debug(MODPREFIX "%s: searching for \"%s\" under \"%s\"", __func__, 
query, ctxt->base);
 
-       /* Initialize the LDAP context. */
-       ldap = do_connect(ctxt, &rv);
-       if (!ldap)
-               return 0;
-
        rv = ldap_search_s(ldap, ctxt->base, LDAP_SCOPE_SUBTREE,
                           query, attrs, 0, &result);
 
        if ((rv != LDAP_SUCCESS) || !result) {
                crit(MODPREFIX "%s: query failed for %s", __func__, query);
-               ldap_unbind(ldap);
                return 0;
        }
 
-
        debug(MODPREFIX "%s: getting first entry for %s=\"%s\"", __func__, key, 
qKey);
 
        e = ldap_first_entry(ldap, result);
        if (!e) {
                debug(MODPREFIX "%s: got answer, but no first entry for %s", 
__func__, query);
                ldap_msgfree(result);
-               ldap_unbind(ldap);
                return CHE_MISSING;
        }
 
@@ -559,7 +626,6 @@ static int lookup_wild(const char *root,
        if (!values) {
                debug(MODPREFIX "%s: no %s defined for %s", __func__, type, 
query);
                ldap_msgfree(result);
-               ldap_unbind(ldap);
                return CHE_MISSING;
        }
 
@@ -587,15 +653,38 @@ static int lookup_wild(const char *root,
        /* Clean up. */
        ldap_value_free(values);
        ldap_msgfree(result);
-       ldap_unbind(ldap);
 
        return ret;
 }
 
+
+static int lookup_wild(LDAP *ldap, const char *root,
+                      struct lookup_context *ctxt)
+{
+       int ret, i;
+
+       if (ctxt->schema)
+               return lookup_wild_schema(ldap, root, ctxt->schema, ctxt);
+
+
+       for (i = 0; i < NR_SCHEMAS; i++) {
+               ret = lookup_wild_schema(ldap, root,
+                                        &supported_schemas[i], ctxt);
+               if (ret != CHE_FAIL) {
+                       set_schema(ctxt, &supported_schemas[i]);
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+/* lookup_mount returns 1 if there was some kind of error */
 int lookup_mount(const char *root, const char *name, int name_len, void 
*context)
 {
        struct lookup_context *ctxt = (struct lookup_context *) context;
-       int ret, ret2;
+       LDAP *ldap;
+       int ret;
        char key[KEY_MAX_LEN + 1];
        int key_len;
        char mapent[MAPENT_MAX_LEN + 1];
@@ -613,42 +702,42 @@ int lookup_mount(const char *root, const char *name, int 
name_len, void *context
        if (key_len > KEY_MAX_LEN)
                return 1;
 
-       ret = lookup_one(root, key, "nisObject", "cn", "nisMapEntry", ctxt);
-       ret2 = lookup_one(root, key,
-                           "automount", "cn", "automountInformation", ctxt);
-       
-       debug("ret = %d, ret2 = %d", ret, ret2);
 
-       if (!ret && !ret2)
+       /* Initialize the LDAP context. */
+       ldap = do_connect(ctxt, NULL);
+       if (!ldap)
+               return 0;
+       
+       ret = lookup_one(ldap, root, key, ctxt);
+       if (ret == CHE_FAIL) {
+               ldap_unbind(ldap);
                return 1;
+       }
 
        me = cache_lookup_first();
        t_last_read = me ? now - me->age : ap.exp_runfreq + 1;
 
        if (t_last_read > ap.exp_runfreq) 
-               if ((ret & (CHE_MISSING | CHE_UPDATED)) && 
-                   (ret2 & (CHE_MISSING | CHE_UPDATED)))
+               if (ret & (CHE_MISSING | CHE_UPDATED))
                        need_hup = 1;
 
-       if (ret == CHE_MISSING && ret2 == CHE_MISSING) {
+
+       if (ret == CHE_MISSING) {
                int wild = CHE_MISSING;
 
                /* Maybe update wild card map entry */
                if (ap.type == LKP_INDIRECT) {
-                       ret = lookup_wild(root, "nisObject",
-                                         "cn", "nisMapEntry", ctxt);
-                       ret2 = lookup_wild(root, "automount",
-                                          "cn", "automountInformation", ctxt);
-                       wild = (ret & (CHE_MISSING | CHE_FAIL)) &&
-                                       (ret2 & (CHE_MISSING | CHE_FAIL));
-
-                       if (ret & CHE_MISSING && ret2 & CHE_MISSING)
+                       ret = lookup_wild(ldap, root, ctxt);
+                       wild = (ret & (CHE_MISSING | CHE_FAIL));
+
+                       if (ret & CHE_MISSING)
                                cache_delete(root, "*", 0);
                }
 
                if (cache_delete(root, key, 0) && wild)
                        rmdir_path(key);
        }
+       ldap_unbind(ldap);
 
        me = cache_lookup(key);
        if (me) {
-- 
1.7.3.3

_______________________________________________
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs

Reply via email to