--- /dev/null
+diff -uNr autofs-4.0.0pre7/man/auto.master.5 autofs-4.0.0pre7-redhat/man/auto.master.5
+--- autofs-4.0.0pre7/man/auto.master.5 Tue Apr 18 05:54:44 2000
++++ autofs-4.0.0pre7-redhat/man/auto.master.5 Wed Apr 26 14:41:26 2000
+@@ -31,9 +31,14 @@
+ The file has three fields separated by an arbitrary number of blanks or
+ tabs. Lines beginning with # are comments. The first field is the mount
+ point. Second field is the map file to be consulted for this mount-point.
+-The third field is optional and can contain options to be applied to all
+-entries in the map. Options are cumulative, which is a difference to the
+-behavior of the SunOS automounter.
++This field is of the form
++.IR maptype:mapname ,
++where
++.I maptype
++is one of the supported map types (file, program, yp, nisplus, hesiod, userdir, ldap), and
++.I mapname
++is the name of the map. The third field is optional and can contain options to+ be applied to all entries in the map. Options are cumulative, which is a
++difference from the behavior of the SunOS automounter.
+
+ The format of the map file and the options are described in
+ .BR autofs (5).
+@@ -44,21 +49,27 @@
+ .nf
+ /home /etc/auto.home
+ /misc /etc/auto.misc
++/mnt yp:mnt.map
+ .fi
+ .RE
+ .sp
+-This will generate two mountpoints
+-.I /home
++This will generate three mountpoints
++.IR /home ,
++.IR /misc ,
+ and
+-.IR /misc .
++.IR /mnt .
+ All accesses to
+ .I /home
+ will lead to the consultation of the map in
+ .IR /etc/auto.home ,
+-and all accesses to
++all accesses to
+ .I /misc
+ will consult the map in
+-.IR /etc/auto.misc .
++.IR /etc/auto.misc ,
++and all accesses to
++.I /mnt
++will consult the NIS map
++.IR mnt.map .
+ .SH "SEE ALSO"
+ .BR automount (8),
+ .BR autofs (5),
+diff -uNr autofs-4.0.0pre7/samples/auto.master autofs-4.0.0pre7-redhat/samples/auto.master
+--- autofs-4.0.0pre7/samples/auto.master Tue Apr 18 05:54:44 2000
++++ autofs-4.0.0pre7-redhat/samples/auto.master Wed Apr 26 14:42:27 2000
+@@ -3,5 +3,5 @@
+ # Format of this file:
+ # mountpoint map options
+ # For details of the format look at autofs(8).
+-/misc /etc/auto.misc
+-/net /etc/auto.net
++/misc /etc/auto.misc --timeout=60
++/net /etc/auto.net --timeout=60
+diff -uNr autofs-4.0.0pre7/samples/auto.misc autofs-4.0.0pre7-redhat/samples/auto.misc
+--- autofs-4.0.0pre7/samples/auto.misc Tue Apr 18 05:54:44 2000
++++ autofs-4.0.0pre7-redhat/samples/auto.misc Wed Apr 26 14:41:26 2000
+@@ -3,8 +3,13 @@
+ # key [ -mount-options-separated-by-comma ] location
+ # Details may be found in the autofs(5) manpage
+
+-kernel -ro ftp.kernel.org:/pub/linux
+-boot -fstype=ext2 :/dev/hda1
+-removable -fstype=ext2 :/dev/hdd
+-cd -fstype=iso9660,ro :/dev/hdc
+-floppy -fstype=auto :/dev/fd0
++kernel -ro,soft,intr ftp.kernel.org:/pub/linux
++cd -fstype=iso9660,ro,nosuid,nodev :/dev/cdrom
++
++# the following entries are samples to pique your imagination
++#boot -fstype=ext2 :/dev/hda1
++#floppy -fstype=auto :/dev/fd0
++#floppy -fstype=ext2 :/dev/fd0
++#e2floppy -fstype=ext2 :/dev/fd0
++#jaz -fstype=ext2 :/dev/sdc1
++#removable -fstype=ext2 :/dev/hdd
--- /dev/null
+diff -uNr autofs-3.1.4/Makefile.conf.in autofs-3.1.4/Makefile.conf.in
+--- autofs-3.1.4/Makefile.conf.in Fri Jan 21 14:08:10 2000
++++ autofs-3.1.4/Makefile.conf.in Tue Feb 29 10:34:33 2000
+@@ -12,6 +12,7 @@
+
+ # Hesiod support: yes (1) no (0)
+ HESIOD = @HAVE_HESIOD@
++HESIOD_BIND = @HAVE_HESIOD_BIND@
+ LIBHESIOD = @LIBHESIOD@
+ HESIOD_FLAGS = @HESIOD_FLAGS@
+
+diff -uNr autofs-3.1.4/configure.in autofs-3.1.4/configure.in
+--- autofs-3.1.4/configure.in Fri Jan 21 14:08:10 2000
++++ autofs-3.1.4/configure.in Tue Feb 29 10:40:43 2000
+@@ -73,7 +73,9 @@
+
+ HAVE_HESIOD=0
+ AC_CHECK_LIB(hesiod, hes_resolve, HAVE_HESIOD=1 LIBHESIOD="$LIBHESIOD -lhesiod", , $LIBRESOLV)
++AC_CHECK_LIB(bind, hesiod_resolve, HAVE_HESIOD=1 HAVE_HESIOD_BIND=1 LIBHESIOD="$LIBHESIOD -lbind", , $LIBRESOLV)
+ AC_SUBST(HAVE_HESIOD)
++AC_SUBST(HAVE_HESIOD_BIND)
+ AC_SUBST(LIBHESIOD)
+ AC_SUBST(HESIOD_FLAGS)
+ LDFLAGS="${AF_tmp_ldflags}"
+diff -uNr autofs-3.1.4/modules/Makefile autofs-3.1.4/modules/Makefile
+--- autofs-3.1.4/modules/Makefile Tue Feb 29 10:48:15 2000
++++ autofs-3.1.4/modules/Makefile Tue Feb 29 10:36:07 2000
+@@ -24,6 +24,9 @@
+ endif
+
+ ifeq ($(HESIOD), 1)
++ ifeq ($(HESIOD_BIND), 1)
++ CFLAGS += -DHESIOD_BIND
++ endif
+ SRCS += lookup_hesiod.c parse_hesiod.c
+ MODS += lookup_hesiod.so parse_hesiod.so
+ endif
+diff -uNr autofs-3.1.4/modules/lookup_hesiod.c autofs-3.1.4/modules/lookup_hesiod.c
+--- autofs-3.1.4/modules/lookup_hesiod.c Fri Jan 21 14:08:09 2000
++++ autofs-3.1.4/modules/lookup_hesiod.c Wed Mar 1 10:07:43 2000
+@@ -28,6 +28,9 @@
+
+ struct lookup_context {
+ struct parse_mod *parser;
++#ifdef HESIOD_BIND
++ void *hesiod_context;
++#endif
+ };
+
+ int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
+@@ -49,6 +52,14 @@
+ /* Initialize the resolver. */
+ res_init();
+
++#ifdef HESIOD_BIND
++ /* Initialize the hesiod context. */
++ if(hesiod_init(&(ctxt->hesiod_context)) != 0) {
++ syslog(LOG_CRIT, MODPREFIX "hesiod_init(): %m");
++ return 1;
++ }
++#endif
++
+ /* If a map type isn't explicitly given, parse it as hesiod entries. */
+ if ( !mapfmt )
+ mapfmt = MAPFMT_DEFAULT;
+@@ -73,7 +84,11 @@
+ chdir("/"); /* If this is not here the filesystem stays
+ busy, for some reason... */
+
++#ifdef HESIOD_BIND
++ hes_result = hesiod_resolve(ctxt->hesiod_context, name, "filsys");
++#else
+ hes_result = hes_resolve(name, "filsys");
++#endif
+
+ if ( !hes_result ) {
+ syslog(LOG_NOTICE, MODPREFIX "entry \"%s\" not found in map\n", name);
+@@ -83,7 +98,11 @@
+ syslog(LOG_DEBUG, MODPREFIX "lookup for \"%s\" gave \"%s\"",
+ name, hes_result[0]);
+ rv = ctxt->parser->parse_mount(root,name,name_len,hes_result[0],ctxt->parser->context);
++#ifdef HESIOD_BIND
++ hesiod_free_list(ctxt->hesiod_context, hes_result);
++#else
+ free(hes_result);
++#endif
+ return rv;
+ }
+
+@@ -93,6 +112,9 @@
+ {
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ int rv = close_parse(ctxt->parser);
++#ifdef HESIOD_BIND
++ hesiod_end(ctxt->hesiod_context);
++#endif
+ free(ctxt);
+ return rv;
+ }
--- /dev/null
+diff -uNr autofs-3.1.4/Makefile.conf.in autofs-3.1.4-ldap/Makefile.conf.in
+--- autofs-3.1.4/Makefile.conf.in Tue Apr 11 14:18:08 2000
++++ autofs-3.1.4-ldap/Makefile.conf.in Tue Apr 11 14:17:49 2000
+@@ -16,6 +16,11 @@
+ LIBHESIOD = @LIBHESIOD@
+ HESIOD_FLAGS = @HESIOD_FLAGS@
+
++# LDAP support: yes (1) no (0)
++LDAP = @HAVE_LDAP@
++LDAP_FLAGS = @LDAP_FLAGS@
++LDAP_LIBS= @LDAP_LIBS@
++
+ # NIS+ support: yes (1) no (0)
+ NISPLUS = @HAVE_NISPLUS@
+
+diff -uNr autofs-3.1.4/configure.in autofs-3.1.4-ldap/configure.in
+--- autofs-3.1.4/configure.in Tue Apr 11 14:18:08 2000
++++ autofs-3.1.4-ldap/configure.in Tue Apr 11 14:17:49 2000
+@@ -85,6 +85,20 @@
+ AC_CHECK_HEADER(rpcsvc/nis.h, HAVE_NISPLUS=1)
+ AC_SUBST(HAVE_NISPLUS)
+
++AC_ARG_WITH(openldap,
++--with-openldap=DIR enable LDAP map support (OpenLDAP libs and includes in DIR),
++ CFLAGS="$CFLAGS -I$withval/include"
++ CPPLAGS="$CPPFLAGS -I$withval/include"
++ AC_CHECK_HEADER(ldap.h)
++ AC_CHECK_LIB(ldap, ldap_init,
++ HAVE_LDAP=1
++ LDAP_LIBS="-L$withval/lib -lldap -llber",,
++ -L$withval/lib -llber)
++)
++AC_SUBST(LDAP_FLAGS)
++AC_SUBST(HAVE_LDAP)
++AC_SUBST(LDAP_LIBS)
++
+ #
+ # Location of init.d directory?
+ #
+diff -uNr autofs-3.1.4/man/auto.master.5 autofs-3.1.4-ldap/man/auto.master.5
+--- autofs-3.1.4/man/auto.master.5 Tue Apr 11 14:18:08 2000
++++ autofs-3.1.4-ldap/man/auto.master.5 Tue Apr 11 14:21:11 2000
+@@ -1,6 +1,6 @@
+ .\" t
+ .\" $Id$
+-.TH AUTO.MASTER 5 "9 Sep 1997"
++.TH AUTO.MASTER 5 "11 Apr 2000"
+ .SH NAME
+ /etc/auto.master \- Master Map for automounter
+ .SH "DESCRIPTION"
+@@ -50,14 +50,16 @@
+ /home /etc/auto.home
+ /misc /etc/auto.misc
+ /mnt yp:mnt.map
++/auto ldap:ldapserver:ou=automount,ou=services,dc=example,dc=com
+ .fi
+ .RE
+ .sp
+-This will generate three mountpoints
++This will generate four mountpoints
+ .IR /home ,
+ .IR /misc ,
++.IR /mnt ,
+ and
+-.IR /mnt .
++.IR /auto .
+ All accesses to
+ .I /home
+ will lead to the consultation of the map in
+@@ -66,10 +68,14 @@
+ .I /misc
+ will consult the map in
+ .IR /etc/auto.misc ,
+-and all accesses to
++all accesses to
+ .I /mnt
+ will consult the NIS map
+-.IR mnt.map .
++.IR mnt.map ,
++and all accesses to
++.I /auto
++will access the \fIautomount\fP objects in \fIldapserver\fP's subtree under
++.IR ou=automount,ou=services,dc=example,dc=com .
+ .SH "SEE ALSO"
+ .BR automount (8),
+ .BR autofs (5),
+diff -uNr autofs-3.1.4/man/automount.8 autofs-3.1.4-ldap/man/automount.8
+--- autofs-3.1.4/man/automount.8 Fri Jan 21 14:08:09 2000
++++ autofs-3.1.4-ldap/man/automount.8 Tue Apr 11 14:17:50 2000
+@@ -63,6 +63,16 @@
+ The map is a hesiod database whose
+ .B filsys
+ entries are used for maps.
++.TP
++.B ldap
++map names are of the form \fB[servername:]basedn\fP, where the optional
++\fBservername\fP is the name of the LDAP server to query, and \fBbasedn\fP is
++the DN to do a subtree search under. Entries are \fBautomount\fP objects in
++the specified subtree, where the \fBcn\fP attribute is the key (the wildcard
++key is "/"), and the \fBautomounterInformation\fP attribute contains the
++information used by the automounter. Documentation on the schema
++used by this module is available online at
++http://docs.iplanet.com/docs/manuals/directory/411ext/nis/mapping.htm
+ .RE
+ .TP
+ \fBformat\fP Format of the map data; currently the only formats
+diff -uNr autofs-3.1.4/modules/Makefile autofs-3.1.4-ldap/modules/Makefile
+--- autofs-3.1.4/modules/Makefile Tue Apr 11 14:18:08 2000
++++ autofs-3.1.4-ldap/modules/Makefile Tue Apr 11 14:17:50 2000
+@@ -36,6 +36,11 @@
+ MODS += lookup_nisplus.so
+ endif
+
++ifeq ($(LDAP), 1)
++ SRCS += lookup_ldap.c
++ MODS += lookup_ldap.so
++endif
++
+ CFLAGS += -I../include -fpic -DAUTOFS_LIB_DIR=\"$(autofslibdir)\" -DPATH_AUTOMOUNT=\"$(sbindir)/automount\"
+
+ all: $(MODS)
+@@ -65,3 +70,8 @@
+ $(CC) $(SOLDFLAGS) $(CFLAGS) $(HESIOD_FLAGS) -o lookup_hesiod.so \
+ lookup_hesiod.c $(LIBHESIOD) $(LIBRESOLV)
+ $(STRIP) lookup_hesiod.so
++
++lookup_ldap.so: lookup_ldap.c
++ $(CC) $(SOLDFLAGS) $(CFLAGS) $(LDAP_FLAGS) -o lookup_ldap.so \
++ lookup_ldap.c $(LDAP_LIBS)
++ $(STRIP) lookup_ldap.so
+diff -uNr autofs-3.1.4/modules/lookup_ldap.c autofs-3.1.4-ldap/modules/lookup_ldap.c
+--- autofs-3.1.4/modules/lookup_ldap.c Wed Dec 31 19:00:00 1969
++++ autofs-3.1.4-ldap/modules/lookup_ldap.c Tue Apr 11 14:28:51 2000
+@@ -0,0 +1,238 @@
++/*
++ * lookup_ldap.c
++ *
++ * Module for Linux automountd to access automount maps in LDAP directories.
++ *
++ */
++
++#include <sys/types.h>
++#include <ctype.h>
++#include <string.h>
++#include <syslog.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <netinet/in.h>
++#include <arpa/nameser.h>
++#include <resolv.h>
++#include <lber.h>
++#include <ldap.h>
++
++#define MODULE_LOOKUP
++#include "automount.h"
++
++#define MAPFMT_DEFAULT "sun"
++
++#define MODPREFIX "lookup(ldap): "
++
++#define OBJECTCLASS "automount"
++#define ATTRIBUTE "automountInformation"
++#define WILDCARD "/"
++
++struct lookup_context {
++ char *server, *base;
++ struct parse_mod *parser;
++};
++
++int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
++
++/*
++ * This initializes a context (persistent non-global data) for queries to
++ * this module. Return zero if we succeed.
++ */
++int lookup_init(const char *mapfmt, int argc, const char * const *argv,
++ void **context)
++{
++ struct lookup_context *ctxt = NULL;
++ int rv, l;
++ LDAP *ldap;
++
++ /* If we can't build a context, bail. */
++ ctxt = (struct lookup_context*) malloc(sizeof(struct lookup_context));
++ *context = ctxt;
++ if( ctxt == NULL ) {
++ syslog(LOG_INFO, MODPREFIX "malloc: %m");
++ return 1;
++ }
++ memset(ctxt, 0, sizeof(struct lookup_context));
++
++ /* If a map type isn't explicitly given, parse it like sun entries. */
++ if( mapfmt == NULL ) {
++ mapfmt = MAPFMT_DEFAULT;
++ }
++
++ /* Now we sanity-check by binding to the server temporarily. We have to be
++ * a little strange in here, because we want to provide for use of the
++ * "default" server, which is set in an ldap.conf file somewhere. */
++ if(strchr(argv[0], ':') != NULL) {
++ l = strchr(argv[0], ':') - argv[0];
++ /* Isolate the server's name. */
++ ctxt->server = malloc(l + 1);
++ memset(ctxt->server, 0, l + 1);
++ memcpy(ctxt->server, argv[0], l);
++ /* Isolate the base DN. */
++ ctxt->base = malloc(strlen(argv[0]) - l);
++ memset(ctxt->base, 0, strlen(argv[0]) - l);
++ memcpy(ctxt->base, argv[0] + l + 1, strlen(argv[0]) - l - 1);
++ } else {
++ /* Use the default server; isolate the base DN's name. */
++ l = strlen(argv[0]);
++ ctxt->server = NULL;
++ ctxt->base = malloc(l + 1);
++ memset(ctxt->base, 0, l + 1);
++ memcpy(ctxt->base, argv[0], l);
++ }
++
++ syslog(LOG_DEBUG, MODPREFIX "server = \"%s\", base dn = \"%s\"",
++ ctxt->server ? ctxt->server : "(default)", ctxt->base);
++
++ /* Initialize the LDAP context. */
++ if( ( ldap = ldap_init(ctxt->server, LDAP_PORT)) == NULL ) {
++ syslog(LOG_CRIT, MODPREFIX "couldn't initialize LDAP");
++ return 1;
++ }
++
++ /* Connect to the server as an anonymous user. */
++ rv = ldap_simple_bind_s(ldap, ctxt->base, NULL);
++ if( rv != LDAP_SUCCESS ) {
++ syslog(LOG_CRIT, MODPREFIX "couldn't connect to %s", ctxt->server);
++ return 1;
++ }
++
++ /* Okay, we're done here. */
++ ldap_unbind(ldap);
++
++ /* Open the parser, if we can. */
++ return !(ctxt->parser = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1));
++}
++
++/* Lookup by key and pass a filesystem to a parser. */
++int lookup_mount(const char *root, const char *name, int name_len, void *context)
++{
++ struct lookup_context *ctxt = (struct lookup_context *) context;
++ int rv, i, l;
++ char *query;
++ LDAPMessage *result, *e;
++ char **values;
++ char *attrs[] = {ATTRIBUTE, NULL};
++ LDAP *ldap;
++
++ chdir("/"); /* If this is not here the filesystem stays
++ busy, for some reason... */
++
++ if( ctxt == NULL ) {
++ syslog(LOG_CRIT, MODPREFIX "context was NULL");
++ return 0;
++ }
++
++ /* Build a query string. */
++ l = name_len + strlen("(&(objectclass=" OBJECTCLASS ")(cn=))") + 2;
++
++ query = malloc(l);
++ if( query == NULL ) {
++ syslog(LOG_INFO, MODPREFIX "malloc: %m");
++ return 0;
++ }
++
++ memset(query, '\0', l);
++ if( sprintf(query, "(&(objectclass=" OBJECTCLASS ")(cn=%s))", name) >= l ) {
++ syslog(LOG_DEBUG, MODPREFIX "error forming query string");
++ }
++ query[l - 1] = '\0';
++
++ /* Initialize the LDAP context. */
++ if( (ldap = ldap_init(ctxt->server, LDAP_PORT) ) == NULL ) {
++ syslog(LOG_CRIT, MODPREFIX "couldn't initialize LDAP connection"
++ " to %s", ctxt->server ? ctxt->server : "default server");
++ free(query);
++ return 1;
++ }
++
++ /* Connect to the server as an anonymous user. */
++ rv = ldap_simple_bind_s(ldap, ctxt->base, NULL);
++ if ( rv != LDAP_SUCCESS ) {
++ syslog(LOG_CRIT, MODPREFIX "couldn't bind to %s",
++ ctxt->server ? ctxt->server : "default server");
++ free(query);
++ return 1;
++ }
++
++ /* Look around. */
++ syslog(LOG_DEBUG, MODPREFIX "searching for \"%s\"", query);
++ rv = ldap_search_s(ldap, ctxt->base, LDAP_SCOPE_SUBTREE,
++ query, attrs, 0, &result);
++
++ if( ( rv != LDAP_SUCCESS) || ( result == NULL ) ) {
++ syslog(LOG_INFO, MODPREFIX "query failed for %s", query);
++ free(query);
++ return 1;
++ }
++
++ e = ldap_first_entry(ldap, result);
++
++ /* If we got no answers, try it with "/" instead, which makes a better
++ * wildcard thatn "*" for LDAP, and also happens to be illegal for actual
++ * directory names. */
++ if( e == NULL ) {
++ syslog(LOG_DEBUG, MODPREFIX "no entry for \"%s\" found, trying cn=\"/\"",
++ name);
++
++ sprintf(query, "(&(objectclass=" OBJECTCLASS ")(cn=" WILDCARD "))");
++
++ syslog(LOG_DEBUG, MODPREFIX "searching for \"%s\"", query);
++ rv = ldap_search_s(ldap, ctxt->base, LDAP_SCOPE_SUBTREE,
++ query, attrs, 0, &result);
++ if( ( rv != LDAP_SUCCESS) || ( result == NULL ) ) {
++ syslog(LOG_INFO, MODPREFIX "query failed for %s", query);
++ free(query);
++ return 1;
++ }
++
++ syslog(LOG_DEBUG, MODPREFIX "getting first entry for cn=\"/\"");
++
++ e = ldap_first_entry(ldap, result);
++ }
++
++ if( e == NULL ) {
++ syslog(LOG_INFO, MODPREFIX "got answer, but no first entry for %s", query);
++ free(query);
++ return 1;
++ } else {
++ syslog(LOG_DEBUG, MODPREFIX "examining first entry");
++ }
++
++ values = ldap_get_values(ldap, e, ATTRIBUTE);
++ if( values == NULL ) {
++ syslog(LOG_INFO, MODPREFIX "no " ATTRIBUTE " defined for %s", query);
++ free(query);
++ return 1;
++ }
++
++ /* Try each of the answers in sucession. */
++ rv = 1;
++ for( i = 0 ; ( values[i] != NULL ) && ( rv != 0 ) ; i++ ) {
++ rv = ctxt->parser->parse_mount(root, name, name_len, values[0],
++ ctxt->parser->context);
++ }
++
++ /* Clean up. */
++ ldap_value_free(values);
++ ldap_msgfree(result);
++ ldap_unbind(ldap);
++ free(query);
++
++ return rv;
++}
++
++/*
++ * This destroys a context for queries to this module. It releases the parser
++ * structure (unloading the module) and frees the memory used by the context.
++ */
++int lookup_done(void *context)
++{
++ struct lookup_context *ctxt = (struct lookup_context *) context;
++ int rv = close_parse(ctxt->parser);
++ free(ctxt->server);
++ free(ctxt->base);
++ free(ctxt);
++ return rv;
++}