diff options
author | H. Peter Anvin <hpa@zytor.com> | 2000-06-19 23:55:57 +0000 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2000-06-19 23:55:57 +0000 |
commit | 067afb5bb1e831b96c2cab24ef4fd1811ba6b456 (patch) | |
tree | 527aff4c1318ba2a7603b377054b442d7a3a2bc5 | |
parent | fc906a8dd1b83939cdd0b6b182b4ad01e170e76a (diff) | |
download | autofs3-067afb5bb1e831b96c2cab24ef4fd1811ba6b456.tar.gz autofs3-067afb5bb1e831b96c2cab24ef4fd1811ba6b456.tar.xz autofs3-067afb5bb1e831b96c2cab24ef4fd1811ba6b456.zip |
Add LDAP support; update TODO list.
-rw-r--r-- | Makefile.conf.in | 5 | ||||
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | README.options | 15 | ||||
-rw-r--r-- | TODO | 19 | ||||
-rw-r--r-- | configure.in | 55 | ||||
-rw-r--r-- | man/auto.master.5 | 2 | ||||
-rw-r--r-- | man/automount.8 | 12 | ||||
-rw-r--r-- | modules/Makefile | 10 | ||||
-rw-r--r-- | modules/lookup_ldap.c | 238 |
9 files changed, 345 insertions, 15 deletions
diff --git a/Makefile.conf.in b/Makefile.conf.in index 74a5a3a..e465b1c 100644 --- a/Makefile.conf.in +++ b/Makefile.conf.in @@ -15,6 +15,11 @@ HESIOD = @HAVE_HESIOD@ LIBHESIOD = @LIBHESIOD@ HESIOD_FLAGS = @HESIOD_FLAGS@ +# LDAP support: yes (1) no (0) +LDAP = @HAVE_LDAP@ +LIBLDAP= @LIBLDAP@ +LDAP_FLAGS = @LDAP_FLAGS@ + # NIS+ support: yes (1) no (0) NISPLUS = @HAVE_NISPLUS@ @@ -1,3 +1,7 @@ +Since autofs-3.1.5: +------------------- +* Add a lookup method for LDAP (from Nalin Dahyabhai). + Since autofs-3.1.4: ------------------- * Support "bind" mounts introduced in linux-2.3.99-pre7.7 instead of diff --git a/README.options b/README.options index 189c18b..94f1c7b 100644 --- a/README.options +++ b/README.options @@ -64,3 +64,18 @@ include files in /usr/athena/include, please specify: ./configure --with-hesiod=/usr/athena +OpenLDAP support +---------------- + +To enable support, if your OpenLDAP library isn't installed in +/usr/lib with the include files in /usr/include, please specify the +option: + + --with-openldap=<openldap_root> + +For example, if your OpenLDAP library lives in /opt/openldap/lib and the +include files in /opt/openldap/include, please specify: + + ./configure --with-openldap=/opt/openldap + + @@ -2,17 +2,26 @@ $Id$ autofs v3 TODO list ------------------- -* The autofs v3 project is closed, except for bugfixes. I may or may - not choose to accept feature enhancements written by other people; - please contact me directly. +* I am accepting minor changes to autofs v3 such as additional + modules. No major changes. autofs v4 TODO list ------------------- -* Completely rewritten kernel protocol, use multithreading rather than - processes in the daemon. +* autofs 4 is developed by Jeremy Fitzhardinge. It supports + multimounts without being quite as radical a departure + architecturally. + +autofs v5 TODO list +------------------- +* Completely rewritten kernel protocol, using the new VFS features + introduced by Alexander Viro for the 2.4 kernel series. +* Use multithreading rather than processes in the daemon. * Support multimount entries. (Quite messy: can't unmount the tree as a unit, probably needs locking while constructing the tree, and needs scaffolding if no entry for /. Appears *very* difficult to do without threading!) * /net support: need hostname resolver module (easy) as well as mountd query (easy) plus all the multimount entry stuff... +* Direct mount support. +* (Hopefully) some kind of inode spoofing to support browsable + directories. diff --git a/configure.in b/configure.in index 1d4688e..531d0d0 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ # define([AC_CACHE_LOAD], )dnl define([AC_CACHE_SAVE], )dnl -AC_INIT(.autofs-3.1.4) +AC_INIT(.autofs-3.1.6) # # autofs installs by default in /usr @@ -54,25 +54,33 @@ AC_CHECK_LIB(resolv, res_query, LIBRESOLV="-lresolv") AC_SUBST(LIBRESOLV) # -# Hesiod support? Hesiod is tricky, because it may live in /usr/athena -# or some equally weird place; if so, have the user specify -# --with-hesiod=/usr/athena +# Hesiod support? Expect that this may have a special directory... # AF_tmp_ldflags="$LDFLAGS" +LIBHESIOD='' +HAVE_HESIOD='' AC_ARG_WITH(hesiod, --with-hesiod=DIR enable Hesiod support (libs and includes in DIR), - if test -z "$withval" -o "$withval" = "yes" -o "$withval" = "no" + if test "$withval" = no + then + HAVE_HESIOD=0 # Disable + elif -o "$withval" = yes -o -z "$withval" then - LIBHESIOD="" + : Search for Hesiod in normal directory path else + : Search for Hesiod in specific directory LDFLAGS="$LDFLAGS -L${withval}/lib" LIBHESIOD="-L${withval}/lib" HESIOD_FLAGS="-I${withval}/include" fi ) -HAVE_HESIOD=0 -AC_CHECK_LIB(hesiod, hes_resolve, HAVE_HESIOD=1 LIBHESIOD="$LIBHESIOD -lhesiod", , $LIBRESOLV) +if test -z "$HAVE_HESIOD" +then + HAVE_HESIOD=0 + AC_CHECK_LIB(hesiod, hes_resolve, HAVE_HESIOD=1 LIBHESIOD="$LIBHESIOD -lhesiod", , + $LIBRESOLV) +fi AC_SUBST(HAVE_HESIOD) AC_SUBST(LIBHESIOD) AC_SUBST(HESIOD_FLAGS) @@ -84,6 +92,37 @@ AC_CHECK_HEADER(rpcsvc/nis.h, HAVE_NISPLUS=1) AC_SUBST(HAVE_NISPLUS) # +# OpenLDAP support? Expect that this may have a special directory... +# +AF_tmp_ldflags="$LDFLAGS" +LIBLDAP='' +HAVE_LDAP='' +AC_ARG_WITH(openldap, +--with-openldap=DIR enable OpenLDAP map support (libs and includes in DIR), + if test "$withval" = 'no'; then + HAVE_LDAP=0 # Disable + elif test -z "$withval" -o "$withval" = 'yes' + then + : Search for LDAP in normal directory path + else + : Search for LDAP in specific directory + LDFLAGS="$LDFLAGS -L${withval}/lib" + LIBLDAP="-L${withval}/lib" + LDAP_FLAGS="-I${withval}/include" + fi +) +if test -z "$HAVE_LDAP"; then + HAVE_LDAP=0 + AC_CHECK_LIB(ldap, ldap_init, HAVE_LDAP=1 LIBLDAP="$LIBLDAP -lldap -llber", , + -llber) +fi + +AC_SUBST(LDAP_FLAGS) +AC_SUBST(HAVE_LDAP) +AC_SUBST(LIBLDAP) +LDFLAGS="${AF_tmp_ldflags}" + +# # Location of init.d directory? # AF_INIT_D() diff --git a/man/auto.master.5 b/man/auto.master.5 index 7e95f75..880c4a8 100644 --- a/man/auto.master.5 +++ b/man/auto.master.5 @@ -1,6 +1,6 @@ .\" t .\" $Id$ -.TH AUTO.MASTER 5 "9 Sep 1997" +.TH AUTO.MASTER 5 "19 Jun 2000" .SH NAME /etc/auto.master \- Master Map for automounter .SH "DESCRIPTION" diff --git a/man/automount.8 b/man/automount.8 index d7f9045..c36e9ac 100644 --- a/man/automount.8 +++ b/man/automount.8 @@ -8,7 +8,7 @@ .\" .\" $Id$ .\" -.TH AUTOMOUNT 8 "17 Sep 1997" +.TH AUTOMOUNT 8 "19 Jun 2000" .SH NAME automount \- configure mount points for autofs .SH SYNOPSIS @@ -63,6 +63,16 @@ The map is a NIS+ database. 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 +\fIhttp://docs.iplanet.com/docs/manuals/directory/411ext/nis/mapping.htm\fP. .RE .TP \fBformat\fP Format of the map data; currently the only formats diff --git a/modules/Makefile b/modules/Makefile index 5d398a1..b5a7f6b 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -33,6 +33,11 @@ ifeq ($(NISPLUS), 1) 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) @@ -62,3 +67,8 @@ lookup_hesiod.so: lookup_hesiod.c $(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 $(LIBLDAP) + $(STRIP) lookup_ldap.so diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c new file mode 100644 index 0000000..ab068a9 --- /dev/null +++ b/modules/lookup_ldap.c @@ -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; +} |