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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +}