From: Erez Zadok Date: Tue, 8 Mar 2005 06:05:32 +0000 (+0000) Subject: * NEWS: mention new feature of executable maps. X-Git-Tag: am-utils-6_1_rc1~13 X-Git-Url: https://git.fsl.cs.stonybrook.edu/?a=commitdiff_plain;h=9713925fbe5103c2505259f17469d6d01a01cf1e;p=am-utils-6.0.git * NEWS: mention new feature of executable maps. * AUTHORS: Acknowledge Erik Kline. * scripts/amd.conf.5: document executable maps and exec_map_timeout parameter. * scripts/amd.conf-sample: examples of an executable map and exec_map_timeout. * m4/macros/header_templates.m4: template for HAVE_MAP_EXEC. * doc/am-utils.texi: document Executable maps and exec_map_timeout parameter. * amd/conf.c (gopt_exec_map_timeout): function to parse exec_map_timeout [global] parameter. * amd/amd.h (AMFS_EXEC_MAP_TIMEOUT): define default executable map timeout to 10 seconds, and a global placeholder for the configurable value. * amd/amd.c (init_global_options): initialize default executable map timeout. * amd/Makefile.am (EXTRA_amd_SOURCES): include info_exec.c in tarball. * configure.in: enable executable maps. * amd/mapc.c: define executable map functions and behavior. * amd/info_exec.c: executable map implementation from Erik Kline , modified, cleaned-up, and fixed. This is not the correct behavior. --- diff --git a/AUTHORS b/AUTHORS index 63b1969..8ff68cb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -406,3 +406,6 @@ March 2, 2005: new global amd.conf option debug_mtab_file, to set the debug mtab file when using debug_options=mtab. Default has changed from "./mtab" to "/tmp/mtab" to avoid security problem. Bug fixed to ensure that Amd terminates properly even mtab file doesn't exist. + +* Erik Kline +January 3, 2005: implementation of executable maps for Amd. diff --git a/ChangeLog b/ChangeLog index 81835c9..671d5f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,40 @@ +2005-03-08 Erez Zadok + + * NEWS: mention new feature of executable maps. + + * AUTHORS: Acknowledge Erik Kline. + + * scripts/amd.conf.5: document executable maps and + exec_map_timeout parameter. + + * scripts/amd.conf-sample: examples of an executable map and + exec_map_timeout. + + * m4/macros/header_templates.m4: template for HAVE_MAP_EXEC. + + * doc/am-utils.texi: document Executable maps and exec_map_timeout + parameter. + + * amd/conf.c (gopt_exec_map_timeout): function to parse + exec_map_timeout [global] parameter. + + * amd/amd.h (AMFS_EXEC_MAP_TIMEOUT): define default executable map + timeout to 10 seconds, and a global placeholder for the + configurable value. + + * amd/amd.c (init_global_options): initialize default executable + map timeout. + + * amd/Makefile.am (EXTRA_amd_SOURCES): include info_exec.c in + tarball. + + * configure.in: enable executable maps. + + * amd/mapc.c: define executable map functions and behavior. + + * amd/info_exec.c: executable map implementation from Erik Kline + , modified, cleaned-up, and fixed. + 2005-03-07 Erez Zadok * amd/info_file.c (file_init_or_mtime): consolidate identical @@ -4237,7 +4274,7 @@ amu_ldap_init, aldh->ldap is not set. So when amu_ldap_rebind is called, this function is absolutely sure to return 0. Then amu_ldap_init return 0 without having opened any LDAP connection. - This is not the correct behaviour. + This is not the correct behavior. (get_ldap_timestamp, amu_ldap_search): error to free an object ("entry") that is automatically freed by the library. Patch from Sebastien Bahloul . diff --git a/NEWS b/NEWS index 7f375bb..d6b1d0a 100644 --- a/NEWS +++ b/NEWS @@ -30,6 +30,13 @@ sparc64-unknown-linux-deb3.0 x86_64-unknown-linux-rh2.9.5AS +- support for executable maps ala Sun automounter. Set map_type=exec in + amd.conf, and map_name to a program/script that takes a key as argv[1], + and returns key-value pair on stdout. See also exec_map_timeout [global] + parameter which defines how many seconds (default 10 sec) Amd will wait + for an executable map program to return output before timing out. See + am-utils manual for full details. + - new amd.conf parameter "nfs_allow_insecure_port". Used to work around bugs in certain kernels, which cause them to try and talk to amd from unprivileged ports. diff --git a/amd/Makefile.am b/amd/Makefile.am index c9fcd5f..4d4fcbb 100644 --- a/amd/Makefile.am +++ b/amd/Makefile.am @@ -63,6 +63,7 @@ amd_SOURCES = \ # the complete list of all optional sources EXTRA_amd_SOURCES = \ info_file.c \ + info_exec.c \ info_hesiod.c \ info_ldap.c \ info_ndbm.c \ diff --git a/amd/amd.c b/amd/amd.c index 45b8461..f091c37 100644 --- a/amd/amd.c +++ b/amd/amd.c @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * - * $Id: amd.c,v 1.34 2005/02/27 23:33:34 ezk Exp $ + * $Id: amd.c,v 1.35 2005/03/08 06:05:33 ezk Exp $ * */ @@ -254,6 +254,9 @@ init_global_options(void) /* cluster name */ gopt.cluster = NULL; + /* executable map timeout */ + gopt.exec_map_timeout = AMFS_EXEC_MAP_TIMEOUT; + /* * kernel architecture: this you must get from uname() if possible. */ diff --git a/amd/amd.h b/amd/amd.h index 8982bd0..2a71a0a 100644 --- a/amd/amd.h +++ b/amd/amd.h @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * - * $Id: amd.h,v 1.62 2005/03/06 01:26:30 ib42 Exp $ + * $Id: amd.h,v 1.63 2005/03/08 06:05:33 ezk Exp $ * */ @@ -55,7 +55,7 @@ */ #ifdef MOUNT_TABLE_ON_FILE # define DEBUG_MNTTAB_FILE "/tmp/mnttab" -#endif +#endif /* MOUNT_TABLE_ON_FILE */ /* options for amd.conf */ #define CFM_BROWSABLE_DIRS 0x0001 @@ -177,6 +177,7 @@ #define AM_TTL_W (120) /* Default unmount interval (2 min) */ #define AM_PINGER 30 /* NFS ping interval for live systems */ #define AMFS_AUTO_TIMEO 8 /* Default amfs_auto timeout - .8s */ +#define AMFS_EXEC_MAP_TIMEOUT 10 /* default 10sec exec map timeout */ /* interval between forced retries of a mount */ #define RETRY_INTERVAL 2 @@ -296,6 +297,7 @@ struct amu_global_options { #endif /* HAVE_MAP_NIS */ char *nfs_proto; /* NFS protocol (NULL, udp, tcp) */ int nfs_vers; /* NFS version (0, 2, 3, 4) */ + u_int exec_map_timeout; /* timeout (seconds) for executable maps */ }; /* if you add anything here, update conf.c:reset_cf_map() */ diff --git a/amd/conf.c b/amd/conf.c index d5cd76d..6c152dd 100644 --- a/amd/conf.c +++ b/amd/conf.c @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * - * $Id: conf.c,v 1.30 2005/03/04 18:42:43 ezk Exp $ + * $Id: conf.c,v 1.31 2005/03/08 06:05:33 ezk Exp $ * */ @@ -85,6 +85,7 @@ static int gopt_debug_mtab_file(const char *val); static int gopt_debug_options(const char *val); static int gopt_dismount_interval(const char *val); static int gopt_domain_strip(const char *val); +static int gopt_exec_map_timeout(const char *val); static int gopt_full_os(const char *val); static int gopt_fully_qualified_hosts(const char *val); static int gopt_hesiod_base(const char *val); @@ -160,6 +161,7 @@ static struct _func_map glob_functable[] = { {"debug_options", gopt_debug_options}, {"dismount_interval", gopt_dismount_interval}, {"domain_strip", gopt_domain_strip}, + {"exec_map_timeout", gopt_exec_map_timeout}, {"fully_qualified_hosts", gopt_fully_qualified_hosts}, {"full_os", gopt_full_os}, {"hesiod_base", gopt_hesiod_base}, @@ -478,6 +480,16 @@ gopt_domain_strip(const char *val) } +static int +gopt_exec_map_timeout(const char *val) +{ + gopt.exec_map_timeout = atoi(val); + if (gopt.exec_map_timeout <= 0) + gopt.exec_map_timeout = AMFS_EXEC_MAP_TIMEOUT; /* default exec map timeout */ + return 0; +} + + static int gopt_full_os(const char *val) { diff --git a/amd/info_exec.c b/amd/info_exec.c new file mode 100644 index 0000000..e138882 --- /dev/null +++ b/amd/info_exec.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 1997-2005 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgment: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_exec.c,v 1.1 2005/03/08 06:05:33 ezk Exp $ + * + */ + +/* + * Get info from executable map + * + * Original from Erik Kline, 2004. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +#define MAX_LINE_LEN 1500 + +/* forward declarations */ +int exec_init(mnt_map *m, char *map, time_t *tp); +int exec_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp); + + +/* + * a timed fgets() + */ +static char * +fgets_timed(char *s, int size, int rdfd, int secs) +{ + fd_set fds; + struct timeval timeo; + time_t start, now; + int rval=0, i=0; + + if (!s || size < 0 || rdfd < 0) + return 0; + + s[0] = 0; + if (size == 0) + return s; + + start = clocktime(); + while (s[i] != '\n' && i < size-1) { + s[i+1] = 0; /* places the requisite trailing '\0' */ + + /* ready for reading */ + rval = read(rdfd, (void *)(s+i), 1); + if (rval == 1) { + if (s[i] == 0) { + rval = 0; + break; + } + i++; + continue; + } else if (rval == 0) { + break; + } else if (rval < 0 && errno != EAGAIN && errno != EINTR) { + plog(XLOG_WARNING, "fgets_timed read error: %m"); + break; + } + + timeo.tv_usec = 0; + now = clocktime() - start; + if (secs <= 0) + timeo.tv_sec = 0; + else if (now < secs) + timeo.tv_sec = secs - now; + else { + /* timed out (now>=secs) */ + plog(XLOG_WARNING, "executable map read timed out (> %d secs)", secs); + rval = -1; + break; + } + + FD_ZERO(&fds); + FD_SET(rdfd, &fds); + + rval = select(rdfd+1, &fds, 0, 0, &timeo); + if (rval < 0) { + /* error selecting */ + plog(XLOG_WARNING, "fgets_timed select error: %m"); + if (errno == EINTR) + continue; + rval = -1; + break; + } else if (rval == 0) { + /* timed out */ + plog(XLOG_WARNING, "executable map read timed out (> %d secs)", secs); + rval = -1; + break; + } + } + + if (rval > 0) + return s; + + close(rdfd); + return (rval == 0 ? s : 0); +} + + +static int +read_line(char *buf, int size, int fd) +{ + int done = 0; + + while (fgets_timed(buf, size, fd, gopt.exec_map_timeout)) { + int len = strlen(buf); + done += len; + if (len > 1 && buf[len - 2] == '\\' && + buf[len - 1] == '\n') { + buf += len - 2; + size -= len - 2; + *buf = '\n'; + buf[1] = '\0'; + } else { + return done; + } + } + + return done; +} + + +/* + * Try to locate a value in a query answer + */ +static int +exec_parse_qanswer(int fd, char *map, char *key, char **pval, time_t *tp) +{ + char qanswer[MAX_LINE_LEN], *dc = 0; + int chuck = 0; + int line_no = 0; + + while (read_line(qanswer, sizeof(qanswer), fd)) { + char *cp; + char *hash; + int len = strlen(qanswer); + line_no++; + + /* + * Make sure we got the whole line + */ + if (qanswer[len - 1] != '\n') { + plog(XLOG_WARNING, "line %d in \"%s\" is too long", line_no, map); + chuck = 1; + } else { + qanswer[len - 1] = '\0'; + } + + /* + * Strip comments + */ + hash = strchr(qanswer, '#'); + if (hash) + *hash = '\0'; + + /* + * Find beginning of value (query answer) + */ + for (cp = qanswer; *cp && !isascii((int)*cp) && !isspace((int)*cp); cp++) + ;; + + /* Ignore blank lines */ + if (!*cp) + goto again; + + /* + * Return a copy of the data + */ + dc = strdup(cp); + *pval = dc; + dlog("%s returns %s", key, dc); + + close(fd); + return 0; + + again: + /* + * If the last read didn't get a whole line then + * throw away the remainder before continuing... + */ + if (chuck) { + while (fgets_timed(qanswer, sizeof(qanswer), fd, gopt.exec_map_timeout) && + !strchr(qanswer, '\n')) ; + chuck = 0; + } + } + + return ENOENT; +} + + +static int +set_nonblock(int fd) +{ + int val; + + if (fd < 0) + return 0; + + if ((val = fcntl(fd, F_GETFL, 0)) < 0) { + plog(XLOG_WARNING, "set_nonblock fcntl F_GETFL error: %m"); + return 0; + } + + val |= O_NONBLOCK; + if (fcntl(fd, F_SETFL, val) < 0) { + plog(XLOG_WARNING, "set_nonblock fcntl F_SETFL error: %m"); + return 0; + } + + return 1; +} + + +static int +exec_map_open(char *emap, char *key) +{ + pid_t p1, p2; + int pdes[2], nullfd, i; + char *argv[3]; + + if (!emap) + return 0; + + argv[0] = emap; + argv[1] = key; + argv[2] = NULL; + + if ((nullfd = open("/dev/null", O_WRONLY|O_NOCTTY)) < 0) + return -1; + + if (pipe(pdes) < 0) { + close(nullfd); + return -1; + } + + switch((p1 = vfork())) { + case -1: + /* parent: fork error */ + close(nullfd); + close(pdes[0]); + close(pdes[1]); + return -1; + case 0: + /* child #1 */ + switch((p2 = vfork())) { + case -1: + /* child #1: fork error */ + exit(errno); + case 0: + /* child #2: init will reap our status */ + if (pdes[1] != STDOUT_FILENO) { + dup2(pdes[1], STDOUT_FILENO); + close(pdes[1]); + } + + if (nullfd != STDERR_FILENO) { + dup2(nullfd, STDERR_FILENO); + close(nullfd); + } + + for (i=0; i0 (errno) if failed + * 0 if ok + */ +static int +exec_check_perm(char *map) +{ + struct stat sb; + + /* sanity and permission checks */ + if (!map) { + dlog("exec_check_permission got a NULL map"); + return EINVAL; + } + if (stat(map, &sb)) { + plog(XLOG_ERROR, "map \"%s\" stat failure: %m", map); + return errno; + } + if (!S_ISREG(sb.st_mode)) { + plog(XLOG_ERROR, "map \"%s\" should be regular file", map); + return EINVAL; + } + if (sb.st_uid != 0) { + plog(XLOG_ERROR, "map \"%s\" owned by uid %d (must be 0)", map, sb.st_uid); + return EACCES; + } + if (!(sb.st_mode & S_IXUSR)) { + plog(XLOG_ERROR, "map \"%s\" should be executable", map); + return EACCES; + } + if (sb.st_mode & (S_ISUID|S_ISGID)) { + plog(XLOG_ERROR, "map \"%s\" should not be setuid/setgid", map); + return EACCES; + } + if (sb.st_mode & S_IWOTH) { + plog(XLOG_ERROR, "map \"%s\" should not be world writeable", map); + return EACCES; + } + + return 0; /* all is well */ +} + + +int +exec_init(mnt_map *m, char *map, time_t *tp) +{ + /* + * Basically just test that the executable map can be found + * and has proper permissions. + */ + return exec_check_perm(map); +} + + +int +exec_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) +{ + int mapfd, ret; + + if ((ret = exec_check_perm(map)) != 0) { + return ret; + } + + if (!key) + return 0; + + if (logfp) + fflush(logfp); + dlog("exec_search \"%s\", key: \"%s\"", map, key); + mapfd = exec_map_open(map, key); + + if (mapfd >= 0) { + if (tp) + *tp = clocktime(); + + return exec_parse_qanswer(mapfd, map, key, pval, tp); + } + + return errno; +} diff --git a/amd/mapc.c b/amd/mapc.c index 6953cb4..ac6df92 100644 --- a/amd/mapc.c +++ b/amd/mapc.c @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * - * $Id: mapc.c,v 1.23 2005/03/08 02:51:30 ezk Exp $ + * $Id: mapc.c,v 1.24 2005/03/08 06:05:33 ezk Exp $ * */ @@ -198,6 +198,12 @@ extern int ndbm_search(mnt_map *, char *, char *, char **, time_t *); extern int ndbm_mtime(mnt_map *, char *, time_t *); #endif /* HAVE_MAP_NDBM */ +/* EXECUTABLE MAPS */ +#ifdef HAVE_MAP_EXEC +extern int exec_init(mnt_map *, char *, time_t *); +extern int exec_search(mnt_map *, char *, char *, char **, time_t *); +#endif /* HAVE_MAP_EXEC */ + /* FILE MAPS */ #ifdef HAVE_MAP_FILE extern int file_init_or_mtime(mnt_map *, char *, time_t *); @@ -295,6 +301,17 @@ static map_type maptypes[] = MAPC_INC }, #endif /* HAVE_MAP_NDBM */ +#ifdef HAVE_MAP_EXEC + { + "exec", + exec_init, + error_reload, + NULL, /* isup function */ + exec_search, + error_mtime, + MAPC_INC + }, +#endif /* HAVE_MAP_EXEC */ #ifdef HAVE_MAP_FILE { "file", diff --git a/configure.in b/configure.in index 1166267..ba6a966 100644 --- a/configure.in +++ b/configure.in @@ -53,7 +53,7 @@ AH_BOTTOM([ dnl dnl AC_CONFIG_AUX_DIR(m4) AC_PREREQ(2.52) -AC_REVISION($Revision: 1.79 $) +AC_REVISION($Revision: 1.80 $) AC_COPYRIGHT([Copyright (c) 1997-2005 Erez Zadok]) dnl find out system type AC_MSG_NOTICE(*** SYSTEM TYPES ***) @@ -799,6 +799,7 @@ AC_MSG_NOTICE(*** MAP TYPES ***) dnl DBM is obsolete, use NDBM dnl AMU_CHECK_MAP_FUNCS(dbminit dbmopen, dbm) AMU_CHECK_MAP_FUNCS(fgets, file) +AMU_CHECK_MAP_FUNCS(waitpid, exec) dnl Define HESIOD map if user wanted it, and both headers and libraries exist if test "$with_hesiod" = "yes" && test "$ac_cv_header_hesiod_h" = "yes" then diff --git a/doc/am-utils.texi b/doc/am-utils.texi index db5775b..c53b6c6 100644 --- a/doc/am-utils.texi +++ b/doc/am-utils.texi @@ -38,7 +38,7 @@ @c @c %W% (Berkeley) %G% @c -@c $Id: am-utils.texi,v 1.99 2005/03/06 03:19:01 ezk Exp $ +@c $Id: am-utils.texi,v 1.100 2005/03/08 06:05:33 ezk Exp $ @c @setfilename am-utils.info @@ -841,8 +841,10 @@ list of map types configured on your machine. * Password maps:: * Union maps:: * LDAP maps:: +* Executable maps:: @end menu +@c ---------------------------------------------------------------- @node File maps, ndbm maps, Map Types, Map Types @comment node-name, next, previous, up @subsection File maps @@ -897,6 +899,7 @@ file maps, or ndbm maps built with the @code{mk-amd-map} program. When caching is enabled, file maps have a default cache mode of @code{all} (@pxref{Automount Filesystem}). +@c ---------------------------------------------------------------- @node ndbm maps, NIS maps, File maps, Map Types @comment node-name, next, previous, up @subsection ndbm maps @@ -910,8 +913,10 @@ be sharable across machine architectures. The notion of speed generally only applies to large maps; a small map, less than a single disk block, is almost certainly better implemented as a file map. -ndbm maps have a default cache mode of @samp{all} (@pxref{Automount Filesystem}). +ndbm maps have a default cache mode of @samp{all} +(@pxref{Automount Filesystem}). +@c ---------------------------------------------------------------- @node NIS maps, NIS+ maps, ndbm maps, Map Types @comment node-name, next, previous, up @subsection NIS maps @@ -952,9 +957,10 @@ $(YPTSDIR)/amd.home.time: $(ETCDIR)/amd.home fi @end example -Here @code{$(YPTSDIR)} contains the time stamp files, and @code{$(YPDBDIR)} contains -the dbm format NIS files. +Here @code{$(YPTSDIR)} contains the time stamp files, and +@code{$(YPDBDIR)} contains the dbm format NIS files. +@c ---------------------------------------------------------------- @node NIS+ maps, Hesiod maps, NIS maps, Map Types @comment node-name, next, previous, up @subsection NIS+ maps @@ -965,6 +971,7 @@ enabled, have a default cache mode of @samp{inc}. XXX: FILL IN WITH AN EXAMPLE. +@c ---------------------------------------------------------------- @node Hesiod maps, Password maps, NIS+ maps, Map Types @comment node-name, next, previous, up @subsection Hesiod maps @@ -990,6 +997,7 @@ jsp.homes.automount HS TXT "rfs:=/home/charm;rhost:=charm;sublink:=jsp" njw.homes.automount HS TXT "rfs:=/home/dylan/dk2;rhost:=dylan;sublink:=njw" @end example +@c ---------------------------------------------------------------- @node Password maps, Union maps, Hesiod maps, Map Types @comment node-name, next, previous, up @subsection Password maps @@ -1036,7 +1044,8 @@ the map entry used by @i{Amd} would be rfs:=/home/sugar;rhost:=sugar.cc;sublink:=jsp @end example -@node Union maps, LDAP maps , Password maps, Map Types +@c ---------------------------------------------------------------- +@node Union maps, LDAP maps, Password maps, Map Types @comment node-name, next, previous, up @subsection Union maps @cindex Union file maps @@ -1051,7 +1060,8 @@ directories take precedence over earlier ones. The union filesystem type then uses the map cache to determine the union of the names in all the directories. -@node LDAP maps, , Union maps, Map Types +@c ---------------------------------------------------------------- +@node LDAP maps, Executable maps, Union maps, Map Types @comment node-name, next, previous, up @subsection LDAP maps @cindex LDAP maps @@ -1102,8 +1112,42 @@ amdmapKey : zing amdmapValue : -rhost:=shekel host==shekel host!=shekel;type:=nfs @end example -@c subsection Gdbm +@c ---------------------------------------------------------------- +@node Executable maps, , LDAP maps, Map Types +@comment node-name, next, previous, up +@subsection Executable maps +@cindex Executable maps +An executable map is a dynamic map in which the keys and values for +the maps are generated on the fly by a program or script. The program +is expected to take a single parameter argument which is the key to +lookup. If the key is found, the program should print on stdout the +key-value pair that were found; if the key was not found, nothing +should be printed out. Below is an sample of such a map script: + +@example +#!/bin/sh +# execuatable map example +case "$1" in + "/defaults" ) + echo "/defaults type:=nfs;rfs:=filer" + ;; + "a" ) + echo "a type:=nfs;fs:=/tmp" + ;; + "b" ) + echo "b type:=link;fs:=/usr/local" + ;; + * ) # no match, echo nothing + ;; +esac +@end example + +@xref{exec_map_timeout Parameter}. + +@c ---------------------------------------------------------------- +@c subsection Gdbm +@c ---------------------------------------------------------------- @node Key Lookup, Location Format, Map Types, Mount Maps @comment node-name, next, previous, up @section How keys are looked up @@ -4232,6 +4276,7 @@ The following parameters are applicable to the @samp{[global]} section only. * debug_options Parameter:: * dismount_interval Parameter:: * domain_strip Parameter:: +* exec_map_timeout Parameter:: * full_os Parameter:: * fully_qualified_hosts Parameter:: * hesiod_base Parameter:: @@ -4364,7 +4409,7 @@ values those listed for the -D option. @xref{-D Option}. systems that have exceeded their cached times. @c ---------------------------------------------------------------- -@node domain_strip Parameter, full_os Parameter, dismount_interval Parameter, Global Parameters +@node domain_strip Parameter, exec_map_timeout Parameter, dismount_interval Parameter, Global Parameters @comment node-name, next, previous, up @subsection @t{domain_strip} Parameter @cindex domain_strip Parameter @@ -4376,9 +4421,22 @@ part is left changed. This is useful when using multiple domains with the same maps (as you may have hosts whose domain-stripped name is identical). +@c ---------------------------------------------------------------- +@node exec_map_timeout Parameter, full_os Parameter, domain_strip Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{exec_map_timeout} Parameter +@cindex exec_map_timeout Parameter + +(type=numeric, default=10). The timeout in seconds that @i{Amd} will +wait for an executable map program before an answer is returned from +that program (or script). This value should be set to as small as +possible while still allowing normal replies to be returned before the +timer expires, because during the time that the executable map program +is queried, @i{Amd} is essentially waiting and is thus not responding +to any other queries. @xref{Executable maps}. @c ---------------------------------------------------------------- -@node full_os Parameter, fully_qualified_hosts Parameter, domain_strip Parameter, Global Parameters +@node full_os Parameter, fully_qualified_hosts Parameter, exec_map_timeout Parameter, Global Parameters @comment node-name, next, previous, up @subsection @t{full_os} Parameter @cindex full_os Parameter diff --git a/m4/macros/header_templates.m4 b/m4/macros/header_templates.m4 index 9d59a9b..9af0ae2 100644 --- a/m4/macros/header_templates.m4 +++ b/m4/macros/header_templates.m4 @@ -61,6 +61,9 @@ AH_TEMPLATE([HAVE_MAP_PASSWD], AH_TEMPLATE([HAVE_MAP_UNION], [Define if have UNION maps]) +AH_TEMPLATE([HAVE_MAP_EXEC], +[Define if have executable maps]) + AH_TEMPLATE([HAVE_FS_UFS], [Define if have UFS filesystem]) diff --git a/scripts/amd.conf-sample b/scripts/amd.conf-sample index 5a75532..cf5a156 100644 --- a/scripts/amd.conf-sample +++ b/scripts/amd.conf-sample @@ -102,6 +102,8 @@ use_tcpwrappers = yes | no nfs_allow_insecure_port = yes | no # address used for local NFS mount and RPC server (default to localhost) localhost_address = foo.example.com | 192.168.1.2 +# number of seconds to timeout before map returns output +exec_map_timeout = 10 ############################################################################## # DEFINE AN AMD MOUNT POINT @@ -130,3 +132,10 @@ mount_type = nfs map_defaults = type:=nfs ############################################################################## +# DEFINE ANOTHER AMD MOUNT POINT +[ /test ] +map_name = /etc/lookup-entry.sh +# an executable map type +mount_type = exec + +############################################################################## diff --git a/scripts/amd.conf.5 b/scripts/amd.conf.5 index 0bf20ab..18972a0 100644 --- a/scripts/amd.conf.5 +++ b/scripts/amd.conf.5 @@ -38,7 +38,7 @@ .\" .\" %W% (Berkeley) %G% .\" -.\" $Id: amd.conf.5,v 1.35 2005/03/05 04:49:16 ezk Exp $ +.\" $Id: amd.conf.5,v 1.36 2005/03/08 06:05:33 ezk Exp $ .\" .TH AMD.CONF 5 "7 August 1997" .SH NAME @@ -145,6 +145,7 @@ and can have undesired side-effects such as initializing NIS even if not used. Possible values are .nf +\fBexec\fR executable maps \fBfile\fR plain files \fBhesiod\fR Hesiod name service from MIT \fBldap\fR Lightweight Directory Access Protocol @@ -268,6 +269,17 @@ part is left changed. This is useful when using multiple domains with the same maps (as you may have hosts whose domain-stripped name is identical). +.TP +.BR exec_map_timeout " (numeric, default=10)" +The timeout in seconds that +.I Amd +will wait for an executable map program before an answer is returned from +that program (or script). This value should be set to as small as possible +while still allowing normal replies to be returned before the timer expires, +because during the time that the executable map program is queried, +.I Amd +is essentially waiting and is thus not responding to any other queries. + .TP .BR full_os " (string, default to compiled in value)" The full name of the operating system, along with its version. Allows you