Hi, Ian, list, (again, sorry if this is a dup)
Here is an implementation of included map support for autofs v4. This
supports included maps in both the master map, and regular direct or
indirect file maps.
Because I dread writing bash code, I implemented the included map
checking for the master map in C. We basically just call into the
daemon with a bogus mount point, asking for it to dump out all of the
maps. This works well for 2 reasons: 1) it's not bash, and 2) it
re-uses the code that the daemon will use to read the included maps
anyway.
Review would be greatly appreciated. I tested this in my environment
by creating a number of included maps, and modifying
/etc/nsswitch.conf to ensure that it works as expected for file and
NIS maps.
-Jeff
diff --git a/daemon/Makefile b/daemon/Makefile
index 4cf1907..7789c79 100644
--- a/daemon/Makefile
+++ b/daemon/Makefile
@@ -13,7 +13,7 @@ version := $(shell cat ../.version)
CFLAGS += -rdynamic $(DAEMON_CFLAGS) -DAUTOFS_LIB_DIR=\"$(autofslibdir)\"
-DVERSION_STRING=\"$(version)\" -I../include
LDFLAGS += -rdynamic
-LIBS = -ldl
+LIBS = -ldl -lldap
all: automount
diff --git a/daemon/automount.c b/daemon/automount.c
index eb0cdd3..3c42c8a 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -82,6 +82,7 @@ struct daemon_status_msg {
int kproto_version; /* Kernel protocol version used */
int kproto_sub_version = 0; /* Kernel protocol version used */
+int dumpmap = 0; /* cmdline arg to dump map contents */
static int submount = 0;
@@ -99,6 +100,10 @@ #define AUTOFS_SYSLOG_CONTEXT {-1, 0, 0,
volatile struct pending_mount *junk_mounts = NULL;
+/* this has to go in the automounter proper, so that each shared library
+ * doesn't get its own copy */
+struct mapent_cache *mapent_hash[HASHSIZE];
+
#define CHECK_RATIO 4 /* exp_runfreq = exp_timeout/CHECK_RATIO */
#define DEFAULT_GHOST_MODE 0
@@ -1848,6 +1853,7 @@ int main(int argc, char *argv[])
{"version", 0, 0, 'V'},
{"ghost", 0, 0, 'g'},
{"submount", 0, &submount, 1},
+ {"dumpmap", 0, 0, 'D'},
{0, 0, 0, 0}
};
@@ -1860,7 +1866,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:vdVg", long_options,
NULL)) != EOF) {
+ while ((opt = getopt_long(argc, argv, "+hp:t:vdVgD", long_options,
NULL)) != EOF) {
switch (opt) {
case 'h':
usage();
@@ -1890,6 +1896,9 @@ int main(int argc, char *argv[])
ap.ghost = LKP_GHOST;
break;
+ case 'D':
+ dumpmap = 1;
+ break;
case '?':
case ':':
printf("%s: Ambiguous or unknown options\n", program);
@@ -1911,7 +1920,8 @@ int main(int argc, char *argv[])
exit(1);
}
- become_daemon();
+ if (!dumpmap)
+ become_daemon();
path = argv[0];
map = argv[1];
@@ -1942,6 +1952,16 @@ #endif
cleanup_exit(path, 1);
}
+ if (dumpmap) {
+ int ret;
+ openlog("automount", LOG_PID, LOG_DAEMON);
+ ret = ap.lookup->lookup_ghost(ap.path, ap.ghost,
+ 0, ap.lookup->context);
+ if (ret & LKP_FAIL)
+ exit(ret);
+ exit(0);
+ }
+
if (!strncmp(path, "/-", 2)) {
supervisor(path);
} else {
diff --git a/include/automount.h b/include/automount.h
index d256b3e..14ec07b 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -161,6 +161,9 @@ typedef int (*lookup_init_t) (const char
typedef int (*lookup_ghost_t) (const char *, int, time_t, void *);
typedef int (*lookup_mount_t) (const char *, const char *, int, void *);
typedef int (*lookup_done_t) (void *);
+/* the following two are used by the included map (+mapname) code */
+typedef int (*lookup_one_t) (const char *, const char *, const char *, int);
+typedef int (*lookup_readmap_t) (const char *, const char *, time_t);
struct lookup_mod {
lookup_init_t lookup_init;
@@ -241,6 +244,8 @@ struct mapent_cache {
char *mapent;
time_t age;
};
+#define HASHSIZE 27
+extern struct mapent_cache *mapent_hash[];
void cache_init(void);
struct mapent_cache *cache_lookup(const char *key);
@@ -294,17 +299,15 @@ int has_fstab_option(const char *path, c
int allow_owner_mount(const char *);
/* nsswitch parsing */
-#define MAPTYPE_FILE 1
-#define MAPTYPE_PROGRAM 2
-
-char *get_nsswitch_map(const char *);
-int isfilemap(const char *);
-int isypmap(const char *);
+char *get_nsswitch_map(const char *, char *);
/* log notification */
extern int do_verbose;
extern int do_debug;
+/* command line option to print out included map contents */
+extern int dumpmap;
+
#define info(msg, args...) \
if (do_verbose || do_debug) \
syslog(LOG_INFO, msg, ##args);
diff --git a/lib/Makefile b/lib/Makefile
index 92931b0..a35b208 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -16,12 +16,13 @@ OBJS = cache.o mount_clnt.o mount_xdr.o
cat_path.o rpc_subs.o mounts.o lock.o syslog.o vsprintf.o nsswitch.o
LIB = autofs.a
+NSSWITCH = nsswitch
CFLAGS += -I../include -fPIC -D_GNU_SOURCE -DHAVE_TCP_WRAPPER -DNFS3_SUPPORTED
.PHONY: all install clean
-all: autofs.a
+all: autofs.a nsswitch
autofs.a: $(OBJS)
rm -f $(LIB)
@@ -49,8 +50,12 @@ listmount.o: listmount.c
$(CC) $(CFLAGS) -o listmount.o -c listmount.c
$(STRIP) listmount.o
+nsswitch: nsswitch.c
+ $(CC) $(CFLAGS) -DSTANDALONE -o nsswitch nsswitch.c -lnsl -lldap
+
install: all
+ install -c nsswitch -m 755 $(INSTALLROOT)$(autofslibdir)
clean:
- rm -f $(LIB) $(RPCS) $(OBJS) *~
+ rm -f $(LIB) $(RPCS) $(OBJS) $(NSSWITCH) *~
diff --git a/lib/cache.c b/lib/cache.c
index e49edf0..0f71fe2 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -33,8 +33,6 @@ #include "automount.h"
extern int kproto_version; /* Kernel protocol major version */
extern int kproto_sub_version; /* Kernel protocol minor version */
-#define HASHSIZE 27
-
struct ghost_context {
const char *root;
char *mapname;
@@ -43,8 +41,6 @@ struct ghost_context {
char mapent[MAPENT_MAX_LEN + 1];
};
-static struct mapent_cache *mapent_hash[HASHSIZE];
-
static unsigned long ent_check(struct ghost_context *gc, char **key, int
ghost);
static char *cache_fullpath(const char *root, const char *key)
@@ -169,6 +165,11 @@ int cache_add(const char *root, const ch
char *pkey, *pent;
unsigned int hashval = hash(key);
+ if (dumpmap) {
+ fprintf(stdout, "%s %s\n", key, mapent);
+ return CHE_OK;
+ }
+
me = (struct mapent_cache *) malloc(sizeof(struct mapent_cache));
if (!me)
return CHE_FAIL;
@@ -221,6 +222,11 @@ int cache_update(const char *root, const
char *pent;
int ret = CHE_OK;
+ if (dumpmap) {
+ fprintf(stdout, "%s %s\n", key, mapent);
+ return CHE_OK;
+ }
+
for (s = mapent_hash[hash(key)]; s != NULL; s = s->next)
if (strcmp(key, s->key) == 0)
me = s;
diff --git a/lib/nsswitch.c b/lib/nsswitch.c
index 277b8d4..6ff097f 100644
--- a/lib/nsswitch.c
+++ b/lib/nsswitch.c
@@ -1,23 +1,69 @@
+/*
+ * Copyright 2005,2006 Red Hat, Inc.
+ *
+ * Author: Chris Feist <[EMAIL PROTECTED]>
+ *
+ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <ctype.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <errno.h>
+#include <ldap.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <unistd.h>
#include <rpcsvc/ypclnt.h>
-#include <netdb.h>
#include "automount.h"
#define MODPREFIX "nsswitch: "
+#define MAPTYPE_FILE 1
+#define MAPTYPE_PROGRAM 2
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+int underscore_to_dot = 0;
+
+static int isfilemap(const char *);
+static int isypmap(const char *);
+static int isldapmap(const char *);
+
+char *make_mapname(const char *loc, const char *type)
+{
+ int retsize, needs_etc = 0;
+ char *retval;
+
+ retsize = strlen(loc) + strlen(type) + 2;
+ if (*loc != '/') {
+ retsize += 5; /* "/etc/" */
+ needs_etc = 1;
+ }
+
+ retval = malloc(retsize);
+ if (!retval)
+ return NULL;
+
+ snprintf(retval, retsize, "%s:%s%s", type,
+ needs_etc ? "/etc/" : "", loc);
+
+ return retval;
+}
+
/*
* Function which takes in a partial map name (ie. auto.misc), parses the
* nsswitch.conf file and returns a valid map name (ie. yp:auto.misc or
- * file:/etc/auto.misc
+ * file:/etc/auto.misc). "cur" is the current map we are reading. This
+ * is used when determining the source of an included map. For example.
+ * if we are parsing /etc/auto.master, and it has the line "+auto.master",
+ * we need to grab the auto.master from nis, if nis is specified in
+ * nsswitch.conf.
*/
-char *get_nsswitch_map(const char *loc)
+char *get_nsswitch_map(const char *loc, char *cur)
{
char buf[1024];
char *ordering;
@@ -27,8 +73,9 @@ char *get_nsswitch_map(const char *loc)
int found_automount = 0;
char *retval = NULL;
int retsize = 0;
+ char *ypmapname = (char *)loc;
- debug(MODPREFIX "called nsswitch with: '%s'", loc);
+ debug(MODPREFIX "called nsswitch with: '%s' '%s'", loc, cur);
nsswitch = fopen(_PATH_NSSWITCH_CONF, "r");
if (!nsswitch) {
error(MODPREFIX "Unable to open %s", _PATH_NSSWITCH_CONF);
@@ -51,41 +98,62 @@ char *get_nsswitch_map(const char *loc)
if (!found_automount)
return NULL;
+ /*
+ * We support an option to convert underscores to dots when looking
+ * up yp maps.
+ */
+ if (underscore_to_dot) {
+ char *u;
+
+ ypmapname = strdup(loc);
+ if (!ypmapname)
+ return NULL;
+ while ((u = strchr(ypmapname, '_')))
+ *u = '.';
+ }
+
while (*ordering != '\0') {
- while (isspace(*ordering)) ordering++;
+ while (isspace(*ordering) && (*ordering != '\0')) ordering++;
if (!strncmp(ordering, "files", 5)) {
switch (isfilemap(loc)) {
- case MAPTYPE_FILE:
- retsize = strlen(loc) + 11;
- retval = malloc(retsize);
- if (!retval)
- return NULL;
- snprintf(retval, retsize,
- "file:/etc/%s", loc);
- return retval;
- case MAPTYPE_PROGRAM:
- retsize = strlen(loc) + 14;
- retval = malloc(retsize);
- if (!retval)
- return NULL;
- snprintf(retval, retsize,
- "program:/etc/%s", loc);
- return retval;
- default: // filemap doesn't exist
+ case MAPTYPE_FILE:
+ retval = make_mapname(loc, "file");
+ debug("comparing %s to %s\n", retval+5,cur);
+ if (cur && !strcmp(cur, retval+5)) {
+ free(retval);
+ retval = NULL;
+ break;
+ }
+ return retval;
+ case MAPTYPE_PROGRAM:
+ retval = make_mapname(loc, "program");
+ debug("comparing %s to %s\n", retval+5,cur);
+ if (cur && !strcmp(cur, retval+5)) {
+ free(retval);
+ retval = NULL;
break;
+ }
+ return retval;
+ default: // filemap doesn't exist
+ break;
}
} else if ((!strncmp(ordering, "yp", 2) ||
- !strncmp(ordering,"nis", 3)) &&
- isypmap(loc)) {
- retsize = strlen(loc) + 4;
+ !strncmp(ordering,"nis", 3)) &&
+ isypmap(ypmapname)) {
+ retsize = strlen(ypmapname) + 4;
retval = malloc(retsize);
- snprintf(retval, retsize, "yp:%s", loc);
+ snprintf(retval, retsize, "yp:%s", ypmapname);
+ return retval;
+ } else if (!strncmp(ordering, "ldap", 4) && isldapmap(loc)) {
+ retsize = strlen(loc) + 6;
+ retval = malloc(retsize);
+ snprintf(retval, retsize, "ldap:%s", loc);
return retval;
}
while (!isspace(*ordering) && (*ordering != '\0')) ordering++;
}
- error(MODPREFIX "couldn't find map");
+ error(MODPREFIX "couldn't find map %s", loc);
return retval;
}
@@ -95,22 +163,23 @@ char *get_nsswitch_map(const char *loc)
* is executable and 0 if it doesn't exists or has incorrect permissions.
*/
-int isfilemap(const char *loc)
+static int isfilemap(const char *loc)
{
struct stat st;
int ret = 0;
char *realfilemap;
- realfilemap = malloc(strlen(loc) + 6); /* '/etc/' + '\0' */
- if (!realfilemap) {
- crit(MODPREFIX "malloc failed.");
- return 0;
- }
-
- snprintf(realfilemap, strlen(loc) + 6, "/etc/%s", loc);
-
- ret = stat(realfilemap, &st);
- free (realfilemap);
+ if (*loc != '/') {
+ realfilemap = malloc(strlen(loc) + 6); /* '/etc/' + '\0' */
+ if (!realfilemap) {
+ crit(MODPREFIX "malloc failed.");
+ return 0;
+ }
+ snprintf(realfilemap, strlen(loc) + 6, "/etc/%s", loc);
+ ret = stat(realfilemap, &st);
+ free(realfilemap);
+ } else
+ ret = stat(loc, &st);
if (!ret) {
if (st.st_uid != 0) {
@@ -124,6 +193,7 @@ int isfilemap(const char *loc)
return MAPTYPE_FILE;
}
}
+ debug(MODPREFIX "stat(%s) returned errno %d\n", loc, errno);
return 0;
}
@@ -141,14 +211,164 @@ int isypmap(const char *loc)
unsigned int order;
if ((err = yp_get_default_domain(&domainname)) != YPERR_SUCCESS) {
- error (MODPREFIX "unable to get default yp domain");
+ error(MODPREFIX "unable to get default yp domain");
return 0;
}
if ((err = yp_order(domainname, loc, &order)) != YPERR_SUCCESS) {
- error (MODPREFIX "unable to find map, %s in domain, %s",
- loc, domainname);
+ debug(MODPREFIX "unable to find map, %s in domain, %s",
+ loc, domainname);
return 0;
}
return 1;
}
+
+/*
+ * boolean function: it returns 1 if 'mapname' exists in the ldap sever, and
+ * 0 if it can't be found.
+ */
+static int ldap_map_exists(const char *mapname,
+ const char *class, const char *attr)
+{
+ LDAP *ld = NULL;
+ LDAPControl *server = NULL, *client = NULL;
+ LDAPMessage *messages = NULL, *entry = NULL;
+ char *attrs[2];
+ char filter[LINE_MAX] = "";
+ int result, ret = 0;
+ int c;
+
+ /* Initialize the LDAP library, pointing it at the default server. */
+ ld = ldap_init(NULL, LDAP_PORT);
+ if (ld == NULL) {
+ crit(MODPREFIX "error initializing LDAP\n");
+ return 0;
+ }
+
+ /* Try to switch to protocol 3. */
+ c = 3;
+ if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &c)
+ != LDAP_SUCCESS) {
+ /* Just retry with the default protocol version. */
+ ldap_unbind(ld);
+ ld = ldap_init(NULL, LDAP_PORT);
+ if (ld == NULL) {
+ crit(MODPREFIX "error initializing LDAP\n");
+ return 0;
+ }
+ }
+
+ /* Connect to the server anonymously. */
+ result = ldap_simple_bind_s(ld, NULL, NULL);
+ if (result != LDAP_SUCCESS) {
+ crit(MODPREFIX "error binding to ldap server: %s\n",
+ ldap_err2string(result));
+ goto out;
+ }
+
+ /* We only want the key and value attributes from entries which
+ * match the query we'll perform. */
+ attrs[0] = LDAP_NO_ATTRS;
+ attrs[1] = NULL;
+
+ /* Set the filter to only find the map we're looking at. */
+ snprintf(filter, sizeof(filter), "(&(objectclass=%s)(%s=%s))",
+ class, attr, mapname);
+
+ debug(MODPREFIX "searching for map %s with filter %s\n",
+ mapname, filter);
+ /* Perform a synchronous query to find the DN of the map. */
+ result = ldap_search_ext_s(ld, NULL,
+ LDAP_SCOPE_SUBTREE,
+ filter,
+ attrs, FALSE,
+ &server, &client,
+ NULL,
+ LDAP_NO_LIMIT,
+ &messages);
+ if (result != LDAP_SUCCESS)
+ goto out;
+
+ /* We expected only one match. Pull it from the results list. */
+ entry = ldap_first_entry(ld, messages);
+ if (entry != NULL)
+ ret = 1; /* success */
+
+out:
+ ldap_unbind(ld);
+ if (server)
+ ldap_control_free(server);
+ if (client)
+ ldap_control_free(client);
+ if (messages)
+ ldap_msgfree(messages);
+
+ return ret;
+
+}
+
+static int isldapmap(const char *loc)
+{
+ /*
+ * search for the three schemas:
+ * (&(objectclass=nisMap)(nisMapName=%s))
+ * (&(objectclass=automountMap)(ou=%s))
+ * (&(objectclass=automountMap)(automountMapName=%s))
+ */
+ if (ldap_map_exists(loc, "nisMap", "nisMapName")) {
+ debug(MODPREFIX "map %s found on the ldap server\n", loc);
+ return 1;
+ }
+ if (ldap_map_exists(loc, "automountMap", "ou")) {
+ debug(MODPREFIX "map %s found on the ldap server\n", loc);
+ return 1;
+ }
+ if (ldap_map_exists(loc, "automountMap", "automountMapName")) {
+ debug(MODPREFIX "map %s found on the ldap server\n", loc);
+ return 1;
+ }
+
+ debug(MODPREFIX "map %s not found on the ldap server\n", loc);
+ return 0;
+}
+
+#ifdef STANDALONE
+int do_debug = 0;
+
+void print_usage(const char *prog)
+{
+ fprintf(stderr, "Usage %s [-u] <mapname>\n", basename(prog));
+}
+
+int main(int argc, char **argv)
+{
+ char *map;
+ int opt;
+
+ if (argc < 2) {
+ print_usage(argv[0]);
+ exit(1);
+ }
+
+ while ((opt = getopt(argc, argv, "u")) != -1) {
+ switch (opt) {
+ case 'u':
+ underscore_to_dot = 1;
+ break;
+ case '?':
+ default:
+ print_usage(argv[0]);
+ exit(1);
+
+ }
+ }
+
+ map = get_nsswitch_map(argv[optind], (char *)"auto.master");
+ if (!map)
+ exit(2);
+
+ fprintf(stdout, "%s\n", map);
+ free(map);
+ exit(0);
+}
+#endif
diff --git a/modules/Makefile b/modules/Makefile
index 1e5bece..f87721a 100644
--- a/modules/Makefile
+++ b/modules/Makefile
@@ -68,6 +68,10 @@ endif
#
# Ad hoc compilation rules for modules which need auxilliary libraries
#
+lookup_file.so: lookup_file.c
+ $(CC) $(SOLDFLAGS) $(CFLAGS) -o lookup_file.so lookup_file.c
$(AUTOFS_LIB) $(LIBNSL)
+ $(STRIP) lookup_file.so
+
lookup_yp.so: lookup_yp.c
$(CC) $(SOLDFLAGS) $(CFLAGS) -o lookup_yp.so lookup_yp.c $(AUTOFS_LIB)
$(LIBNSL)
$(STRIP) lookup_yp.so
diff --git a/modules/lookup_file.c b/modules/lookup_file.c
index 49d1155..b3881f6 100644
--- a/modules/lookup_file.c
+++ b/modules/lookup_file.c
@@ -24,15 +24,21 @@ #include <time.h>
#include <ctype.h>
#include <syslog.h>
#include <signal.h>
+#include <dlfcn.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <rpcsvc/ypclnt.h>
#define MODULE_LOOKUP
#include "automount.h"
#define MAPFMT_DEFAULT "sun"
+#define MAPTYPE_FILE 1
+#define MAPTYPE_YP 2
+#define MAPTYPE_LDAP 3
+
#define MODPREFIX "lookup(file): "
typedef enum {
@@ -42,13 +48,71 @@ typedef enum {
typedef enum { got_nothing, got_star, got_real } FOUND_STATE;
typedef enum { esc_none, esc_char, esc_val } ESCAPES;
+/*
+ * This is the basic data structure used to store information about a map.
+ *
+ * next: linked list pointer pointing at the next map in the list. There
+ * will only be multiple entries in this list if there are included
+ * maps (map entries of the form "+mapname").
+ * name: This is the expanded name of the map. For example, given a map
+ * entry "+auto.foo", this would be either "auto.foo" if it is resolved
+ * to a yp map, or "/etc/auto.foo" if it is a file map. The type of
+ * map is determined by consulting the nsswitch.conf file. The
+ * expanded map name is stored so that we don't have to lookup the
+ * file system path name more than once. For an example of where
+ * this is useful, see the map_modified function.
+ * mapentry: If this is an included map, then this field represents the
+ * name specified in the "+auto.xyz" entry. It can be the same as
+ * the "name" entry (annotated above) if the included map is a yp
+ * map or specifies an absolute path.
+ * type: Either MAPTYPE_FILE (which includes both file maps and program
+ * maps), MAPTYPE_YP, or MAPTYPE_LDAP.
+ * u: This union contains the maptype specific modification time. For
+ * file maps, this is simply the mtime. For yp maps, we use the yp
+ * order, or version number. LDAP does not provide an easy way to
+ * determine modification time, so we always assume the map has
+ * changed.
+ *
+ * When adding a map to the list, the name, type, and mapentry must be
+ * specified.
+ */
+struct map {
+ struct map *next;
+ char *name;
+ char *mapentry;
+ int type;
+ union {
+ time_t mtime;
+ unsigned int order;
+ } u;
+};
struct lookup_context {
const char *mapname;
- time_t mtime;
struct parse_mod *parse;
+ struct map *maps; /* linked list of maps associated with ctxt */
+
+ /* The following are used for included yp maps */
+ void *yplib_dh; /* handle returned from dlopen */
+ lookup_one_t yp_lookup_one_included;
+ lookup_readmap_t yp_lookup_readmap_included;
+
+ void *ldaplib_dh;
+ lookup_one_t ldap_lookup_one_included;
+ lookup_readmap_t ldap_lookup_readmap_included;
};
+static int read_map(const char *root, time_t now, struct lookup_context *ctxt);
+static int __read_map(char *, const char *,
+ time_t, struct lookup_context *);
+static int __lookup_one(const char *map, const char *root, const char *key,
+ int key_len, struct lookup_context *ctxt);
+static int lookup_one(const char *root, const char *key, int key_len,
+ struct lookup_context *ctxt);
+static int add_map(struct lookup_context *ctxt, int type, const char *mapname,
+ const char *mapentry);
+unsigned int map_order(const char *mapname);
+
int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
int lookup_init(const char *mapfmt, int argc, const char *const *argv, void
**context)
@@ -60,6 +124,7 @@ int lookup_init(const char *mapfmt, int
crit(MODPREFIX "malloc: %m");
return 1;
}
+ memset(ctxt, 0, sizeof(*ctxt));
if (argc < 1) {
crit(MODPREFIX "No map name");
@@ -67,7 +132,6 @@ int lookup_init(const char *mapfmt, int
}
ctxt->mapname = argv[0];
-
if (ctxt->mapname[0] != '/') {
crit(MODPREFIX "file map %s is not an absolute pathname",
ctxt->mapname);
@@ -81,12 +145,9 @@ int lookup_init(const char *mapfmt, int
}
if (stat(ctxt->mapname, &st)) {
- crit(MODPREFIX "file map %s, could not stat",
- ctxt->mapname);
+ crit(MODPREFIX "could not stat file map: %s", ctxt->mapname);
return 1;
}
-
- ctxt->mtime = st.st_mtime;
if (!mapfmt)
mapfmt = MAPFMT_DEFAULT;
@@ -96,10 +157,341 @@ int lookup_init(const char *mapfmt, int
return !(ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv +
1));
}
+static void recursion_detected(struct lookup_context *ctxt, const char
*mapname)
+{
+ struct map *cur = ctxt->maps;
+
+ crit(MODPREFIX "Recursion in included maps detected.\n");
+ for (cur = ctxt->maps; cur; cur = cur->next)
+ crit(MODPREFIX "%s", cur->name);
+ crit(MODPREFIX "%s\n", mapname);
+}
+
+static void map_list_init(struct lookup_context *ctxt)
+{
+ struct map *cur, *next;
+
+ cur = ctxt->maps;
+ ctxt->maps = NULL;
+
+ while (cur) {
+ next = cur->next;
+ free(cur->name);
+ free(cur->mapentry);
+ free(cur);
+ cur = next;
+ }
+}
+
+/*
+ * Add this map to the list of maps associated with this context. Check
+ * for recursion in included maps, here.
+ *
+ * Returns 1 on success, 0 on failure.
+ */
+static int add_map(struct lookup_context *ctxt, int type, const char *mapname,
+ const char *mapentry)
+{
+ struct map *map, *cur, *tail;
+
+ debug(MODPREFIX "Adding map %s,%s\n", mapname, mapentry);
+ if (type < MAPTYPE_FILE || type > MAPTYPE_LDAP)
+ return 0;
+
+ map = malloc(sizeof(*map));
+ if (!map) {
+ crit("malloc of size %d failed while trying to read map %s."
+ " Continuing, but map contents may not be complete.\n",
+ sizeof(*map), mapname);
+ return 0;
+ }
+ memset(map, 0, sizeof(*map));
+
+ map->type = type;
+ map->name = strdup(mapname);
+ map->mapentry = strdup(mapentry);
+ if (!map->name || !map->mapentry) {
+ crit("memory allocation failed while trying read map %s."
+ " Continuing, but map contents may not be complete.\n",
+ mapname);
+ free(map->name);
+ free(map->mapentry);
+ free(map);
+ return 0;
+ }
+
+ /* check for recursive includes */
+ for (cur = tail = ctxt->maps; cur; cur = cur->next) {
+ if (!strcmp(cur->name, mapname)) {
+ recursion_detected(ctxt, mapname);
+ free(map->name);
+ free(map);
+ return 0;
+ }
+ tail = cur;
+ }
+ if (tail)
+ tail->next = map;
+ else
+ ctxt->maps = map;
+
+ debug("added map name=\"%s\", entry=\"%s\" to context\n", map->name,
+ map->mapentry);
+ return 1;
+}
+
+/*
+ * Remove this map from the list of maps associated with this context.
+ *
+ * Returns 1 on success, 0 on failure.
+ */
+static int del_map(struct lookup_context *ctxt, const char *mapname)
+{
+ struct map *cur, *prev = ctxt->maps;
+
+ for (cur = ctxt->maps; cur; cur = cur->next) {
+ if (strcmp(cur->name, mapname)) {
+ prev->next = cur->next;
+ free(cur->name);
+ free(cur);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static struct map *find_map_byname(struct lookup_context *ctxt, char *mapname)
+{
+ struct map *cur;
+
+ for (cur = ctxt->maps; cur; cur = cur->next) {
+ if (!strcmp(cur->name, mapname))
+ return cur;
+ }
+
+ return NULL;
+}
+
+static struct map *find_map_byentry(struct lookup_context *ctxt, char *entry)
+{
+ struct map *cur;
+
+ for (cur = ctxt->maps; cur; cur = cur->next) {
+ if (!strcmp(cur->mapentry, entry))
+ return cur;
+ }
+
+ return NULL;
+}
+
+static int init_yplib(struct lookup_context *ctxt)
+{
+ void *dh = NULL;
+ int yplib_len;
+ char *yplib_path;
+ char *error_string;
+ const char *yplib_name = "lookup_yp.so";
+
+
+ yplib_len = strlen(AUTOFS_LIB_DIR) + strlen(yplib_name);
+ yplib_path = alloca(yplib_len + 2);
+ if (!yplib_path) {
+ crit(MODPREFIX "unable to alloca memory");
+ return 0;
+ }
+ snprintf(yplib_path, yplib_len + 2, "%s/%s",AUTOFS_LIB_DIR,
+ yplib_name);
+ if (!(dh = dlopen(yplib_path, RTLD_NOW))) {
+ crit(MODPREFIX "cannot open yp lookup module (%s)",
+ dlerror());
+ return 0;
+ }
+
+ dlerror(); /* clear any existing error */
+ ctxt->yp_lookup_one_included =
+ (lookup_one_t)dlsym(dh, "lookup_one_included");
+ error_string = dlerror();
+ if (error_string) {
+ crit(MODPREFIX "dlsym failed for symbol %s, error %s",
+ "lookup_one_included", error_string);
+ dlclose(dh);
+ return 0;
+ }
+
+ ctxt->yp_lookup_readmap_included =
+ (lookup_readmap_t)dlsym(dh, "lookup_readmap_included");
+ error_string = dlerror();
+ if (error_string != NULL) {
+ crit(MODPREFIX "dlsym failed for symbol %s, error %s",
+ "lookup_map_included", error_string);
+ dlclose(dh);
+ ctxt->yp_lookup_one_included = NULL;
+ return 0;
+ }
+
+ ctxt->yplib_dh = dh;
+ return 1;
+}
+
+static int init_ldaplib(struct lookup_context *ctxt)
+{
+ void *dh = NULL;
+ int ldaplib_len;
+ char *ldaplib_path;
+ char *error_string;
+ const char *ldaplib_name = "lookup_ldap.so";
+
+
+ ldaplib_len = strlen(AUTOFS_LIB_DIR) + strlen(ldaplib_name);
+ ldaplib_path = alloca(ldaplib_len + 2);
+ if (!ldaplib_path) {
+ crit(MODPREFIX "unable to alloca memory");
+ return 0;
+ }
+ snprintf(ldaplib_path, ldaplib_len + 2, "%s/%s",AUTOFS_LIB_DIR,
+ ldaplib_name);
+ if (!(dh = dlopen(ldaplib_path, RTLD_NOW))) {
+ crit(MODPREFIX "cannot open ldap lookup module (%s)",
+ dlerror());
+ return 0;
+ }
+
+ dlerror(); /* clear any existing error */
+ ctxt->ldap_lookup_one_included =
+ (lookup_one_t)dlsym(dh, "lookup_one_included");
+ error_string = dlerror();
+ if (error_string) {
+ crit(MODPREFIX "dlsym failed for symbol %s, error %s",
+ "lookup_one_included", error_string);
+ dlclose(dh);
+ return 0;
+ }
+
+ ctxt->ldap_lookup_readmap_included =
+ (lookup_readmap_t)dlsym(dh, "lookup_readmap_included");
+ error_string = dlerror();
+ if (error_string != NULL) {
+ crit(MODPREFIX "dlsym failed for symbol %s, error %s",
+ "lookup_map_included", error_string);
+ dlclose(dh);
+ ctxt->ldap_lookup_one_included = NULL;
+ return 0;
+ }
+
+ ctxt->ldaplib_dh = dh;
+ return 1;
+}
+
+/*
+ * Takes a string of the form "maptype:mapname" and returns an integer
+ * maptype of either MAPTYPE_YP or MAPTYPE_FILE. Returns -1 on error.
+ */
+static int maptype(const char *mapname)
+{
+ if (!strncmp(mapname, "yp:", 3))
+ return MAPTYPE_YP;
+ if (!strncmp(mapname, "file:", 5))
+ return MAPTYPE_FILE;
+ if (!strncmp(mapname, "ldap:", 5))
+ return MAPTYPE_LDAP;
+ return -1;
+}
+
+/*
+ * Return Values:
+ * CHE_OK - Success
+ * CHE_FAIL - malloc or yp_get_default_domain failed, or there is no
+ * record of the mapname in the context->maps list, or the
+ * specified map type is invalid.
+ * CHE_MISSING - key does not exist in the map
+ * CHE_UPDATED - either the key was newly added to the cache, or the
+ * value associated with key changed.
+ *
+ */
+static int lookup_one_included(struct lookup_context *ctxt, char *map,
+ const char *root, const char *key, int key_len)
+{
+ struct map *mt;
+
+ debug(MODPREFIX "lookup_one_included: looking for map %s, key %s\n",
+ map, key);
+ mt = find_map_byentry(ctxt, map);
+ if (!mt) {
+ debug("find_map_byentry failed\n");
+ return CHE_FAIL;
+ }
+
+ switch (mt->type) {
+ case MAPTYPE_FILE:
+ return __lookup_one(mt->name, root, key, key_len, ctxt);
+
+ case MAPTYPE_YP:
+ if (!ctxt->yp_lookup_one_included && !init_yplib(ctxt))
+ return CHE_FAIL;
+ return ctxt->yp_lookup_one_included(map, root, key, key_len);
+ case MAPTYPE_LDAP:
+ if (!ctxt->ldap_lookup_one_included && !init_ldaplib(ctxt))
+ return CHE_FAIL;
+ return ctxt->ldap_lookup_one_included(map, root, key, key_len);
+ default:
+ break;
+ }
+
+ return CHE_FAIL;
+}
+
+/*
+ * This function calls the maptype-specific read_map function. For file
+ * maps, that simply entails calling __read_map. For yp maps, we have to
+ * call into the yp module's lookup_map_included function.
+ *
+ * Return values:
+ *
+ * 1 - Success
+ * 0 - Failure
+ */
+static int read_included_map(struct lookup_context *ctxt, char *map,
+ int type, const char *root, time_t age)
+{
+ struct map *mt;
+
+ debug("read_included_map: %s\n", map);
+
+ if (map == NULL)
+ return 0;
+
+ mt = find_map_byname(ctxt, map);
+ if (!mt)
+ return 0;
+
+ switch (type) {
+ case MAPTYPE_FILE:
+ return __read_map(map, root, age, ctxt);
+ case MAPTYPE_YP:
+ if (!ctxt->yp_lookup_readmap_included && !init_yplib(ctxt))
+ return 0;
+
+ mt->u.order = map_order(map);
+ return ctxt->yp_lookup_readmap_included(map, root, age);
+ case MAPTYPE_LDAP:
+ if (!ctxt->ldap_lookup_readmap_included && !init_ldaplib(ctxt))
+ return 0;
+
+ return ctxt->ldap_lookup_readmap_included(map, root, age);
+ default:
+ error(MODPREFIX "maptype not recognized in map %s.\n", map);
+ error(MODPREFIX "valid map types include \"file:\" and
\"yp:\"");
+ break;
+ }
+ return 0;
+}
+
static int read_one(FILE *f, char *key, char *mapent)
{
char *kptr, *p;
int mapent_len, key_len;
+ int is_plus_map = 0;
int ch, nch;
LOOKUP_STATE state;
FOUND_STATE getting, gotten;
@@ -141,6 +533,8 @@ static int read_one(FILE *f, char *key,
switch (state) {
case st_begin:
if (!escape) {
+ if (ch == '+')
+ is_plus_map = 1;
if (isspace(ch));
else if (ch == '#')
state = st_badent;
@@ -159,9 +553,12 @@ static int read_one(FILE *f, char *key,
break;
case st_compare:
- if (ch == '\n')
- state = st_begin;
- else if (isspace(ch) && !escape) {
+ if (ch == '\n') {
+ if (is_plus_map)
+ goto got_it;
+ else
+ state = st_begin;
+ } else if (isspace(ch) && !escape) {
getting = got_real;
state = st_entspc;
} else if (escape == esc_char);
@@ -231,6 +628,8 @@ static int read_one(FILE *f, char *key,
continue;
got_it:
+ if (is_plus_map)
+ return 1;
if (gotten == got_nothing)
goto next;
@@ -249,7 +648,14 @@ static int read_one(FILE *f, char *key,
return 0;
}
-static int read_map(const char *root, time_t now, struct lookup_context *ctxt)
+/*
+ * Return values:
+ *
+ * 1 - Success
+ * 0 - Failure
+ */
+static int __read_map(char *map, const char *root,
+ time_t now, struct lookup_context *ctxt)
{
char key[KEY_MAX_LEN + 1];
char mapent[MAPENT_MAX_LEN + 1];
@@ -257,25 +663,62 @@ static int read_map(const char *root, ti
FILE *f;
int entry;
time_t age = now ? now : time(NULL);
+ struct stat st;
+ struct map *mt;
- mapname = alloca(strlen(ctxt->mapname) + 6);
- sprintf(mapname, "file:%s", ctxt->mapname);
+ mt = find_map_byname(ctxt, map);
+ if (!mt) {
+ crit(MODPREFIX "__read_map: requested map %s not found in"
+ " lookup_context.\n", map);
+ return 0;
+ }
+
+ if (stat(map, &st) < 0) {
+ error(MODPREFIX "stat failed on map %s with error %d\n",
+ map, errno);
+ return 0;
+ }
+ mt->u.mtime = st.st_mtime;
- f = fopen(ctxt->mapname, "r");
+ f = fopen(map, "r");
if (!f) {
- error(MODPREFIX "could not open map file %s", ctxt->mapname);
+ error(MODPREFIX "could not open map file %s", map);
return 0;
}
while(1) {
entry = read_one(f, key, mapent);
- if (entry)
+ if (entry && *key == '+') {
+ int type;
+ char *pathname;
+
+ debug("Looking for plus map: %s, root: %s", key, root);
+ mapname = get_nsswitch_map(key+1, mt->name);
+ if (!mapname)
+ continue;
+ type = maptype(mapname);
+
+ pathname = strchr(mapname, ':');
+ pathname++;
+
+ if (!add_map(ctxt, type, pathname, key+1)) {
+ free(mapname);
+ continue;
+ }
+
+ if (!read_included_map(ctxt, pathname, type, root,
age)) {
+ debug("Unable to read included map: %s\n",
+ key+1);
+ del_map(ctxt, key+1);
+ }
+ free(mapname);
+
+ } else if (entry)
cache_add(root, key, mapent, age);
if (feof(f))
break;
}
-
fclose(f);
/* Clean stale entries from the cache */
@@ -284,24 +727,39 @@ static int read_map(const char *root, ti
return 1;
}
+/*
+ * This is called for the top-level map. That is to say, the one
+ * specified on the command line. Included maps go through the __read_map
+ * function. So, here we can make a valid assumption that the map type
+ * is file.
+ */
+static int read_map(const char *root, time_t now, struct lookup_context *ctxt)
+{
+ if (!add_map(ctxt, MAPTYPE_FILE, ctxt->mapname, ctxt->mapname))
+ return 0;
+
+ if (!__read_map((char *)ctxt->mapname, root, now, ctxt)) {
+ del_map(ctxt, ctxt->mapname);
+ return 0;
+ }
+
+ return 1;
+}
+
int lookup_ghost(const char *root, int ghost, time_t now, void *context)
{
struct lookup_context *ctxt = (struct lookup_context *) context;
struct mapent_cache *me;
- struct stat st;
int status = 1;
+ /* Clear out the map list. This is necessary, as otherwise
+ * subsequent calls to lookup_ghost (when re-reading maps, for
+ * example) would result in a failure.
+ */
+ map_list_init(ctxt);
if (!read_map(root, now, ctxt))
return LKP_FAIL;
- if (stat(ctxt->mapname, &st)) {
- crit(MODPREFIX "file map %s, could not stat",
- ctxt->mapname);
- return 1;
- }
-
- ctxt->mtime = st.st_mtime;
-
status = cache_ghost(root, ghost, ctxt->mapname, "file", ctxt->parse);
me = cache_lookup_first();
@@ -322,29 +780,36 @@ int lookup_ghost(const char *root, int g
return status;
}
-static int lookup_one(const char *root,
- const char *key, int key_len,
- struct lookup_context *ctxt)
+static int __lookup_one(const char *map, const char *root, const char *key,
+ int key_len, struct lookup_context *ctxt)
{
char mkey[KEY_MAX_LEN + 1];
char mapent[MAPENT_MAX_LEN + 1];
- char *mapname;
FILE *f;
int entry;
+ int result = 0;
time_t age = time(NULL);
- mapname = alloca(strlen(ctxt->mapname) + 6);
- sprintf(mapname, "file:%s", ctxt->mapname);
-
- f = fopen(ctxt->mapname, "r");
+ debug("__lookup_one: called with map \"%s\".", map);
+ f = fopen(map, "r");
if (!f) {
- error(MODPREFIX "could not open map file %s", ctxt->mapname);
+ error(MODPREFIX "could not open map file %s", map);
return 0;
}
while(1) {
entry = read_one(f, mkey, mapent);
- if (entry)
+
+ if (entry && *mkey == '+') {
+ debug("Looking for included map: %s", mkey);
+ result = lookup_one_included(ctxt, mkey+1,
+ root, key, key_len);
+ if (result == CHE_OK || result == CHE_UPDATED) {
+ fclose(f);
+ return result;
+ }
+ debug("Unable to find %s in included map", mkey+1);
+ } else if (entry)
if (strlen(mkey) == key_len &&
strncmp(mkey, key, key_len) == 0) {
fclose(f);
@@ -360,18 +825,21 @@ static int lookup_one(const char *root,
return CHE_MISSING;
}
+static int lookup_one(const char *root,
+ const char *key, int key_len,
+ struct lookup_context *ctxt)
+{
+ return __lookup_one(ctxt->mapname, root, key, key_len, ctxt);
+}
+
static int lookup_wild(const char *root, struct lookup_context *ctxt)
{
char mkey[KEY_MAX_LEN + 1];
char mapent[MAPENT_MAX_LEN + 1];
- char *mapname;
FILE *f;
int entry;
time_t age = time(NULL);
- mapname = alloca(strlen(ctxt->mapname) + 6);
- sprintf(mapname, "file:%s", ctxt->mapname);
-
f = fopen(ctxt->mapname, "r");
if (!f) {
error(MODPREFIX "could not open map file %s", ctxt->mapname);
@@ -395,10 +863,88 @@ static int lookup_wild(const char *root,
return CHE_MISSING;
}
+/*
+ * Routine which looks up the yp order (or version number) of the specified
+ * map name.
+ *
+ * Returns 0 on failure, or the map order on success.
+ */
+unsigned int map_order(const char *mapname)
+{
+ int err;
+ char *domainname;
+ unsigned int order;
+
+ if ((err = yp_get_default_domain(&domainname)) != YPERR_SUCCESS) {
+ error (MODPREFIX "unable to get default yp domain");
+ return 0;
+ }
+ if ((err = yp_order(domainname, mapname, &order)) != YPERR_SUCCESS) {
+ error (MODPREFIX "unable to find map, %s in domain, %s",
+ mapname, domainname);
+ return 0;
+ }
+
+ return order;
+}
+
+/*
+ * Boolean function which tells whether the map, or any of the included
+ * maps, has changed.
+ */
+int map_modified(struct lookup_context *ctxt)
+{
+ struct stat st;
+ struct map *mt;
+ unsigned int order;
+
+ /* walk through the list of maps to see if they've changed */
+ for (mt = ctxt->maps; mt; mt = mt->next) {
+ debug("checking for modifications to map %s\n", mt->name);
+ switch (mt->type) {
+ case MAPTYPE_YP:
+ /* test for != instead of >, because an error is
+ * returned as 0 from map_order. */
+ order = map_order(mt->name);
+ debug("nis map %s order %u, last order %u\n",
+ mt->name, order, mt->u.order);
+ if (order != mt->u.order)
+ return 1;
+ break;
+
+ case MAPTYPE_FILE:
+ if (stat(mt->name, &st)) {
+ crit(MODPREFIX
+ "file map %s, stat returned %d.",
+ mt->name, errno);
+ return 1;
+ }
+ debug("file map %s mtime %ld, last %ld\n", mt->name,
+ st.st_mtime, mt->u.mtime);
+ if (st.st_mtime > mt->u.mtime)
+ return 1;
+ break;
+
+ case MAPTYPE_LDAP:
+ /* There is no easy way to tell if an ldap map was
+ * modified. So, we trigger a real lookup every
+ * time. */
+ return 1;
+ default:
+ crit(MODPREFIX "Unrecognized map type %d\n", mt->type);
+ }
+ }
+
+ debug("map_modified: no changes\n");
+ return 0;
+}
+
+/*
+ * Returns 0 on success, non-zero on failure.
+ */
int lookup_mount(const char *root, const char *name, int name_len, void
*context)
{
struct lookup_context *ctxt = (struct lookup_context *) context;
- struct stat st;
char key[KEY_MAX_LEN + 1];
int key_len;
char mapent[MAPENT_MAX_LEN + 1];
@@ -406,12 +952,7 @@ int lookup_mount(const char *root, const
time_t now = time(NULL);
time_t t_last_read;
int need_hup = 0;
- int ret = 1;
-
- if (stat(ctxt->mapname, &st)) {
- crit(MODPREFIX "file map %s, could not stat", ctxt->mapname);
- return 1;
- }
+ int ret = 0;
if (ap.type == LKP_DIRECT)
key_len = snprintf(key, KEY_MAX_LEN, "%s/%s", root, name);
@@ -424,14 +965,12 @@ int lookup_mount(const char *root, const
me = cache_lookup_first();
t_last_read = me ? now - me->age : ap.exp_runfreq + 1;
- /* only if it has been modified */
- if (st.st_mtime > ctxt->mtime) {
+ /* only perform a real lookup if the map was modified */
+ if (map_modified(ctxt)) {
ret = lookup_one(root, key, key_len, ctxt);
if (!ret)
return 1;
- debug("ret = %d", ret);
-
if (t_last_read > ap.exp_runfreq)
if (ret & (CHE_UPDATED | CHE_MISSING))
need_hup = 1;
@@ -478,6 +1017,9 @@ int lookup_done(void *context)
{
struct lookup_context *ctxt = (struct lookup_context *) context;
int rv = close_parse(ctxt->parse);
+
+ if (ctxt->yplib_dh)
+ dlclose(ctxt->yplib_dh);
free(ctxt);
cache_release();
return rv;
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index 36fd8e2..3d0cba0 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -99,48 +99,34 @@ static LDAP *do_connect(struct lookup_co
return ldap;
}
-/*
- * 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 *context_init(const char *mapname)
{
struct lookup_context *ctxt = NULL;
- int l, rv;
- LDAP *ldap;
+ int l;
char *ptr = NULL;
- /* If we can't build a context, bail. */
- ctxt = (struct lookup_context *) malloc(sizeof(struct lookup_context));
- *context = ctxt;
+ ctxt = (struct lookup_context *)malloc(sizeof(struct lookup_context));
if (ctxt == NULL) {
crit(MODPREFIX "malloc: %m");
- return 1;
+ return NULL;
}
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. */
-
+ /* Now we sanity-check by binding to the server temporarily. Be
+ * sure to allow for use of the "default" server, which is set in
+ * an ldap.conf file somewhere. */
ctxt->server = NULL;
ctxt->port = LDAP_PORT;
ctxt->base = NULL;
- ptr = (char *) argv[0];
-
+ ptr = (char *)mapname;
if (!strncmp(ptr, "//", 2)) {
char *s = ptr + 2;
char *p = NULL, *q = NULL;
- /* Isolate the server's name and possibly port. But the : breaks
- the SUN parser for submounts so we can't actually use it.
+ /* Isolate the server's name and possibly port. But the :
+ breaks the SUN parser for submounts so we can't actually
+ use it.
*/
if ((q = strchr(s, '/'))) {
if ((p = strchr(s, ':'))) {
@@ -162,7 +148,7 @@ int lookup_init(const char *mapfmt, int
/* Isolate the server's name. */
ctxt->server = malloc(l + 1);
memset(ctxt->server, 0, l + 1);
- memcpy(ctxt->server, argv[0], l);
+ memcpy(ctxt->server, mapname, l);
ptr += l+1;
}
@@ -176,8 +162,30 @@ int lookup_init(const char *mapfmt, int
ctxt->server ? ctxt->server : "(default)",
ctxt->port, ctxt->base);
+ return ctxt;
+}
+
+/*
+ * 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;
+ LDAP *ldap;
+
+ /* If we can't build a context, bail. */
+ ctxt = context_init(argv[0]);
+ *context = ctxt;
+ if (ctxt == NULL)
+ return 1;
+
+ /* If a map type isn't explicitly given, parse it like sun entries. */
+ if (mapfmt == NULL)
+ mapfmt = MAPFMT_DEFAULT;
+
/* Initialize the LDAP context. */
- ldap = do_connect(ctxt, &rv);
+ ldap = do_connect(ctxt, NULL);
if (!ldap)
return 1;
@@ -185,7 +193,7 @@ int lookup_init(const char *mapfmt, int
ldap_unbind(ldap);
/* Open the parser, if we can. */
- return !(ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv +
1));
+ return !(ctxt->parse = open_parse(mapfmt, MODPREFIX, argc-1, argv+1));
}
static int read_one_map(const char *root,
@@ -722,3 +730,71 @@ int lookup_done(void *context)
free(ctxt);
return rv;
}
+
+/*
+ * Check for an entry in an included ldap map. Named lookup_one_included,
+ * as it is the included map counterpart to lookup_one.
+ *
+ * Return Values:
+ * CHE_OK - Success
+ * CHE_FAIL - malloc or yp_get_default_domain failed
+ * CHE_MISSING - key does not exist in the map
+ * CHE_UPDATED - either the key was newly added to the cache, or the
+ * value associated with key changed.
+ */
+int lookup_one_included(char *map, char *root, char *key, int key_len)
+{
+ struct lookup_context *ctxt;
+ int ret = 0;
+
+ ctxt = context_init(map);
+ if (!ctxt)
+ return CHE_FAIL;
+ ctxt->base = NULL;
+
+ ret = lookup_one(root, key, "nisObject", "cn", "nisMapEntry", ctxt);
+ if (ret & (CHE_UPDATED | CHE_OK))
+ goto done;
+
+ ret = lookup_one(root, key, "automount",
+ "cn", "automountInformation", ctxt);
+ if (ret & (CHE_UPDATED | CHE_OK))
+ goto done;
+
+ ret = lookup_one(root, key, "automount", "automountKey",
+ "automountInformation", ctxt);
+done:
+ free(ctxt->server);
+ free(ctxt->base);
+ free(ctxt);
+ return ret;
+}
+
+/*
+ * Check for the existence of "map", and read in its contents if it
+ * exists. This is named lookup_map_included as it is the included map
+ * counterpart to read_map.
+ *
+ * Return Values:
+ * 1 - Success
+ * 0 - Failure: malloc, yp_get_default_domain, or the yp lookup failed.
+ */
+int lookup_readmap_included(char *map, char *root, time_t age)
+{
+ struct lookup_context *ctxt;
+ int rv = 0;
+
+ ctxt = context_init(map);
+ if (!ctxt)
+ return 0;
+ ctxt->base = NULL;
+
+ /* read_map returns 0 for failure, 1 for success */
+ rv = read_map(root, ctxt, NULL, 0, age, &rv);
+
+ free(ctxt->server);
+ free(ctxt->base);
+ free(ctxt);
+
+ return rv;
+}
diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
index b55d04a..d4cc4a0 100644
--- a/modules/lookup_yp.c
+++ b/modules/lookup_yp.c
@@ -50,30 +50,55 @@ struct callback_data {
int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
-int lookup_init(const char *mapfmt, int argc, const char *const *argv, void
**context)
+/*
+ * Create a lookup context for the given map.
+ */
+struct lookup_context *context_init(const char *map)
{
struct lookup_context *ctxt;
int err;
- if (!(*context = ctxt = malloc(sizeof(struct lookup_context)))) {
- crit(MODPREFIX "%m");
- return 1;
+ if (map == NULL) {
+ crit(MODPREFIX "No map name");
+ return NULL;
}
- if (argc < 1) {
- crit(MODPREFIX "No map name");
- return 1;
+ if (!(ctxt = malloc(sizeof(struct lookup_context)))) {
+ crit(MODPREFIX "%m");
+ return NULL;
}
- ctxt->mapname = argv[0];
+ memset(ctxt, 0, sizeof(*ctxt));
+
+ ctxt->mapname = map;
/* This should, but doesn't, take a const char ** */
err = yp_get_default_domain((char **) &ctxt->domainname);
if (err) {
crit(MODPREFIX "map %s: %s\n", ctxt->mapname,
- yperr_string(err));
+ yperr_string(err));
+ free(ctxt);
+ return NULL;
+ }
+
+ return ctxt;
+}
+
+int lookup_init(const char *mapfmt, int argc, const char *const *argv, void
**context)
+{
+ struct lookup_context *ctxt;
+
+ if (argc < 1) {
+ crit(MODPREFIX "No map name");
return 1;
}
+ ctxt = context_init(argv[0]);
+ if (!ctxt) {
+ crit(MODPREFIX "%m");
+ return 1;
+ }
+ *context = ctxt;
+
if (!mapfmt)
mapfmt = MAPFMT_DEFAULT;
@@ -123,7 +148,7 @@ static int read_map(const char *root, ti
err = yp_all((char *) ctxt->domainname, (char *) ctxt->mapname, &ypcb);
if (err != YPERR_SUCCESS) {
- warn(MODPREFIX "lookup_ghost for %s failed: %s",
+ warn(MODPREFIX "read_map for %s failed: %s",
root, yperr_string(err));
return 0;
}
@@ -161,6 +186,15 @@ int lookup_ghost(const char *root, int g
return status;
}
+/*
+ * Return Values:
+ * CHE_OK - Success
+ * CHE_FAIL - malloc or yp_get_default_domain failed
+ * CHE_UPDATED - either the key was newly added to the cache, or the
+ * value associated with key changed.
+ * CHE_MISSING - the key does not exist in the nis map
+ * yp error code - negated error returned from yp_match.
+ */
static int lookup_one(const char *root,
const char *key, int key_len,
struct lookup_context *ctxt)
@@ -238,11 +272,10 @@ int lookup_mount(const char *root, const
/* check map and if change is detected re-read map */
ret = lookup_one(root, key, key_len, ctxt);
- if (!ret)
+ if (ret == CHE_FAIL)
return 1;
- debug("ret = %d", ret);
-
+ /* was there a yp error? */
if (ret < 0) {
warn(MODPREFIX
"lookup for %s failed: %s", name, yperr_string(-ret));
@@ -308,3 +341,51 @@ int lookup_done(void *context)
cache_release();
return rv;
}
+
+/*
+ * Check for an entry in an included yp map. Named lookup_one_included,
+ * as it is the included map counterpart to lookup_one.
+ *
+ * Return Values:
+ * CHE_OK - Success
+ * CHE_FAIL - malloc or yp_get_default_domain failed
+ * CHE_MISSING - key does not exist in the map
+ * CHE_UPDATED - either the key was newly added to the cache, or the
+ * value associated with key changed.
+ */
+int lookup_one_included(char *map, char *root, char *key, int key_len)
+{
+ struct lookup_context *ctxt;
+ int rv = 0;
+
+ ctxt = context_init(map);
+ if (!ctxt)
+ return CHE_FAIL;
+
+ rv = lookup_one(root, key, key_len, ctxt);
+ free(ctxt);
+ return rv;
+}
+
+/*
+ * Check for the existence of "map", and read in its contents if it
+ * exists. This is named lookup_map_included as it is the included map
+ * counterpart to read_map.
+ *
+ * Return Values:
+ * 1 - Success
+ * 0 - Failure: malloc, yp_get_default_domain, or the yp lookup failed.
+ */
+int lookup_readmap_included(char *map, char *root, time_t age)
+{
+ struct lookup_context *ctxt;
+ int rv = 0;
+
+ ctxt = context_init(map);
+ if (!ctxt)
+ return 0;
+
+ rv = read_map(root, age, ctxt);
+ free(ctxt);
+ return rv;
+}
diff --git a/modules/parse_sun.c b/modules/parse_sun.c
index 2e95a45..9c8bca2 100644
--- a/modules/parse_sun.c
+++ b/modules/parse_sun.c
@@ -661,7 +661,7 @@ static int sun_mount(const char *root, c
* to detect what type of map it is.
*/
if (!strcmp(fstype, "autofs") && strchr(loc, ':') == NULL) {
- nsswitch_map = get_nsswitch_map(loc);
+ nsswitch_map = get_nsswitch_map(loc, NULL);
if (!nsswitch_map) {
error(MODPREFIX "unable to find map %s",loc);
return 1;
diff --git a/samples/rc.autofs.in b/samples/rc.autofs.in
index d00f2ab..27ef6bb 100644
--- a/samples/rc.autofs.in
+++ b/samples/rc.autofs.in
@@ -143,10 +143,11 @@ function getfilemounts()
if [ "`echo $auto_master_in | grep '^+'`" = "" ]; then
echo $auto_master_in
else
- for nismap in `cat /etc/auto.master | grep '^\+' |
- sed -e '/^#/d' -e '/^$/d'`; do
- catnismap `echo "$nismap" | sed -e 's/^\+//'`
- done
+ mapname=`echo $auto_master_in | sed -e 's/\+//g'`
+ expanded_mapname=`@@autofslibdir@@/nsswitch $mapname
2>/dev/null`
+ expanded_mapname=`echo $expanded_mapname | sed -e 's/:/ /g'`
+ : $DAEMON -D /bogus $expanded_mapname
+ $DAEMON -D /bogus $expanded_mapname
fi
done
)
@@ -177,7 +178,7 @@ function getrawmounts()
files)
if [ -z "$filescheme" ] ; then
FILEMOUNTS=`getfilemounts`
- if [ -n "$FILEMOUNTS" ] && [ "$ONE_AUTO_MASTER" -eq 1 ];
+ if [ -n "$FILEMOUNTS" -o -f /etc/auto.master ] && [
"$ONE_AUTO_MASTER" -eq 1 ];
then
getfilemounts
return
@@ -333,24 +334,18 @@ function getmounts()
elif [ "$map" = "multi" ] ; then
maptype=$map
map=
-# elif echo "$map" | grep -q '^!'; then
-# map=`echo "$map"| sed -e 's/^!//g'`
- elif `echo $map | grep -q "^/"` && [ -x "$map" ]; then
- maptype=program
- elif [ -x "/etc/$map" ]; then
- maptype=program
- map=`echo /etc/$map | sed 's^//^/^g'`
- elif `echo $map | grep -q "^/"` && [ -f "$map" ]; then
- maptype=file
- elif [ -f "/etc/$map" ]; then
- maptype=file
- map=`echo /etc/$map | sed 's^//^/^g'`
else
- maptype=yp
if [ "$UNDERSCORETODOT" = "1" ] ; then
- map=`basename $map | sed -e s/^auto_/auto./`
+ nsswitch_opts="-u"
else
- map=`basename $map | sed 's^//^/^g'`
+ nsswitch_opts=""
+ fi
+ nsswitch_output=`@@autofslibdir@@/nsswitch
$nsswitch_opts $map 2>/dev/null`
+ if [ $? -eq 0 ]; then
+ maptype=`echo $nsswitch_output | cut -d: -f 1`
+ map=`echo $nsswitch_output | cut -d: -f 2`
+ else
+ continue;
fi
fi
fi
_______________________________________________
autofs mailing list
[email protected]
http://linux.kernel.org/mailman/listinfo/autofs