Blame modules/lookup_yp.c

Packit 8480eb
/* ----------------------------------------------------------------------- *
Packit 8480eb
 *   
Packit 8480eb
 *  lookup_yp.c - module for Linux automountd to access a YP (NIS)
Packit 8480eb
 *                automount map
Packit 8480eb
 *
Packit 8480eb
 *   Copyright 1997 Transmeta Corporation - All Rights Reserved
Packit 8480eb
 *   Copyright 2001-2003 Ian Kent <raven@themaw.net>
Packit 8480eb
 *
Packit 8480eb
 *   This program is free software; you can redistribute it and/or modify
Packit 8480eb
 *   it under the terms of the GNU General Public License as published by
Packit 8480eb
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
Packit 8480eb
 *   USA; either version 2 of the License, or (at your option) any later
Packit 8480eb
 *   version; incorporated herein by reference.
Packit 8480eb
 *
Packit 8480eb
 * ----------------------------------------------------------------------- */
Packit 8480eb
Packit 8480eb
#include <stdio.h>
Packit 8480eb
#include <malloc.h>
Packit 8480eb
#include <time.h>
Packit 8480eb
#include <signal.h>
Packit 8480eb
#include <ctype.h>
Packit 8480eb
#include <sys/param.h>
Packit 8480eb
#include <sys/types.h>
Packit 8480eb
#include <sys/stat.h>
Packit 8480eb
#include <rpc/rpc.h>
Packit 8480eb
#include <rpc/xdr.h>
Packit 8480eb
#include <rpcsvc/yp_prot.h>
Packit 8480eb
#include <rpcsvc/ypclnt.h>
Packit 8480eb
Packit 8480eb
#define MODULE_LOOKUP
Packit 8480eb
#include "automount.h"
Packit 8480eb
#include "nsswitch.h"
Packit 8480eb
Packit 8480eb
#define MAPFMT_DEFAULT "sun"
Packit 8480eb
Packit 8480eb
#define MODPREFIX "lookup(yp): "
Packit 8480eb
Packit 8480eb
struct lookup_context {
Packit 8480eb
	char *domainname;
Packit 8480eb
	const char *mapname;
Packit 8480eb
	unsigned long order;
Packit 8480eb
	unsigned int check_defaults;
Packit 8480eb
	struct parse_mod *parse;
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
struct callback_master_data {
Packit 8480eb
	unsigned timeout;
Packit 8480eb
	unsigned logging;
Packit 8480eb
	unsigned logopt;
Packit 8480eb
	time_t age;
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
struct callback_data {
Packit 8480eb
	struct autofs_point *ap;
Packit 8480eb
	struct map_source *source;
Packit 8480eb
	unsigned logopt;
Packit 8480eb
	time_t age;
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
int lookup_version = AUTOFS_LOOKUP_VERSION;	/* Required by protocol */
Packit 8480eb
Packit 8480eb
static unsigned int get_map_order(const char *domain, const char *map)
Packit 8480eb
{
Packit 8480eb
	char key[] = "YP_LAST_MODIFIED";
Packit 8480eb
	int key_len = strlen(key);
Packit 8480eb
	char *order;
Packit 8480eb
	int order_len;
Packit 8480eb
	char *mapname;
Packit 8480eb
	long last_changed;
Packit 8480eb
	int err;
Packit 8480eb
Packit 8480eb
	mapname = alloca(strlen(map) + 1);
Packit 8480eb
	if (!mapname)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	strcpy(mapname, map);
Packit 8480eb
Packit 8480eb
	err = yp_match(domain, mapname, key, key_len, &order, &order_len);
Packit 8480eb
	if (err != YPERR_SUCCESS) {
Packit 8480eb
		if (err == YPERR_MAP) {
Packit 8480eb
			char *usc;
Packit 8480eb
Packit 8480eb
			while ((usc = strchr(mapname, '_')))
Packit 8480eb
				*usc = '.';
Packit 8480eb
Packit 8480eb
			err = yp_match(domain, mapname,
Packit 8480eb
				       key, key_len, &order, &order_len);
Packit 8480eb
Packit 8480eb
			if (err != YPERR_SUCCESS)
Packit 8480eb
				return 0;
Packit 8480eb
Packit 8480eb
			last_changed = atol(order);
Packit 8480eb
			free(order);
Packit 8480eb
Packit 8480eb
			return (unsigned int) last_changed;
Packit 8480eb
		}
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	last_changed = atol(order);
Packit 8480eb
	free(order);
Packit 8480eb
Packit 8480eb
	return (unsigned int) last_changed;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int do_init(const char *mapfmt,
Packit 8480eb
		   int argc, const char *const *argv,
Packit 8480eb
		   struct lookup_context *ctxt, unsigned int reinit)
Packit 8480eb
{
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	int err;
Packit 8480eb
	int ret = 0;
Packit 8480eb
Packit 8480eb
	if (argc < 1) {
Packit 8480eb
		logerr(MODPREFIX "no map name");
Packit 8480eb
		ret = 1;
Packit 8480eb
		goto out;
Packit 8480eb
	}
Packit 8480eb
	ctxt->mapname = argv[0];
Packit 8480eb
	ctxt->check_defaults = 1;
Packit 8480eb
Packit 8480eb
	if (mapfmt && !strcmp(mapfmt, "amd"))
Packit 8480eb
		ctxt->domainname = conf_amd_get_nis_domain();
Packit 8480eb
Packit 8480eb
	if (!ctxt->domainname) {
Packit 8480eb
		char *domainname;
Packit 8480eb
		/* This should, but doesn't, take a const char ** */
Packit 8480eb
		err = yp_get_default_domain(&domainname);
Packit 8480eb
		if (err) {
Packit 8480eb
			ret = 1;
Packit 8480eb
			goto out;
Packit 8480eb
		}
Packit 8480eb
		ctxt->domainname = strdup(domainname);
Packit 8480eb
		if (!ctxt->domainname) {
Packit 8480eb
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
			logerr(MODPREFIX "strdup: %s", estr);
Packit 8480eb
			ret = 1;
Packit 8480eb
			goto out;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ctxt->order = get_map_order(ctxt->domainname, ctxt->mapname);
Packit 8480eb
Packit 8480eb
	if (!mapfmt)
Packit 8480eb
		mapfmt = MAPFMT_DEFAULT;
Packit 8480eb
Packit 8480eb
	if (reinit) {
Packit 8480eb
		ret = reinit_parse(ctxt->parse, mapfmt, MODPREFIX, argc - 1, argv + 1);
Packit 8480eb
		if (ret)
Packit 8480eb
			logmsg(MODPREFIX "failed to reinit parse context");
Packit 8480eb
	} else {
Packit 8480eb
		ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
Packit 8480eb
		if (!ctxt->parse) {
Packit 8480eb
			logmsg(MODPREFIX "failed to open parse context");
Packit 8480eb
			ret = 1;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
out:
Packit 8480eb
	if (ret && ctxt->domainname)
Packit 8480eb
		free(ctxt->domainname);
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int lookup_init(const char *mapfmt,
Packit 8480eb
		int argc, const char *const *argv, void **context)
Packit 8480eb
{
Packit 8480eb
	struct lookup_context *ctxt;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
Packit 8480eb
	*context = NULL;
Packit 8480eb
Packit 8480eb
	ctxt = malloc(sizeof(struct lookup_context));
Packit 8480eb
	if (!ctxt) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr(MODPREFIX "malloc: %s", estr);
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
	memset(ctxt, 0, sizeof(struct lookup_context));
Packit 8480eb
Packit 8480eb
	if (do_init(mapfmt, argc, argv, ctxt, 0)) {
Packit 8480eb
		free(ctxt);
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	*context = ctxt;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int lookup_reinit(const char *mapfmt,
Packit 8480eb
		  int argc, const char *const *argv, void **context)
Packit 8480eb
{
Packit 8480eb
	struct lookup_context *ctxt = (struct lookup_context *) *context;
Packit 8480eb
	struct lookup_context *new;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	new = malloc(sizeof(struct lookup_context));
Packit 8480eb
	if (!new) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr(MODPREFIX "malloc: %s", estr);
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
	memset(new, 0, sizeof(struct lookup_context));
Packit 8480eb
Packit 8480eb
	new->parse = ctxt->parse;
Packit 8480eb
	ret = do_init(mapfmt, argc, argv, new, 1);
Packit 8480eb
	if (ret) {
Packit 8480eb
		free(new);
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	*context = new;
Packit 8480eb
Packit 8480eb
	free(ctxt->domainname);
Packit 8480eb
	free(ctxt);
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int yp_all_master_callback(int status, char *ypkey, int ypkeylen,
Packit 8480eb
		    char *val, int vallen, char *ypcb_data)
Packit 8480eb
{
Packit 8480eb
	struct callback_master_data *cbdata =
Packit 8480eb
			(struct callback_master_data *) ypcb_data;
Packit 8480eb
	unsigned int timeout = cbdata->timeout;
Packit 8480eb
	unsigned int logging = cbdata->logging;
Packit 8480eb
	unsigned int logopt = cbdata->logopt;
Packit 8480eb
	time_t age = cbdata->age;
Packit 8480eb
	char *buffer;
Packit 8480eb
	unsigned int len;
Packit 8480eb
Packit 8480eb
	if (status != YP_TRUE)
Packit 8480eb
		return status;
Packit 8480eb
Packit 8480eb
	/* Ignore zero length and single non-printable char keys */
Packit 8480eb
	if (ypkeylen == 0 || (ypkeylen == 1 && !isprint(*ypkey))) {
Packit 8480eb
		warn(logopt, MODPREFIX
Packit 8480eb
		     "ignoring invalid map entry, zero length or "
Packit 8480eb
		     "single character non-printable key");
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * Ignore keys beginning with '+' as plus map
Packit 8480eb
	 * inclusion is only valid in file maps.
Packit 8480eb
	 */
Packit 8480eb
	if (*ypkey == '+')
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	*(ypkey + ypkeylen) = '\0';
Packit 8480eb
	*(val + vallen) = '\0';
Packit 8480eb
Packit 8480eb
	len = ypkeylen + 1 + vallen + 2;
Packit 8480eb
Packit 8480eb
	buffer = alloca(len);
Packit 8480eb
	if (!buffer) {
Packit 8480eb
		error(logopt, MODPREFIX "could not malloc parse buffer");
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
	memset(buffer, 0, len);
Packit 8480eb
Packit 8480eb
	strcat(buffer, ypkey);
Packit 8480eb
	strcat(buffer, " ");
Packit 8480eb
	strcat(buffer, val);
Packit 8480eb
Packit 8480eb
	master_parse_entry(buffer, timeout, logging, age);
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int lookup_read_master(struct master *master, time_t age, void *context)
Packit 8480eb
{
Packit 8480eb
	struct lookup_context *ctxt = (struct lookup_context *) context;
Packit 8480eb
	struct ypall_callback ypcb;
Packit 8480eb
	struct callback_master_data ypcb_data;
Packit 8480eb
	unsigned int logging = master->default_logging;
Packit 8480eb
	unsigned int logopt = master->logopt;
Packit 8480eb
	char *mapname;
Packit 8480eb
	int err;
Packit 8480eb
Packit 8480eb
	mapname = malloc(strlen(ctxt->mapname) + 1);
Packit 8480eb
	if (!mapname)
Packit 8480eb
		return NSS_STATUS_UNKNOWN;
Packit 8480eb
Packit 8480eb
	strcpy(mapname, ctxt->mapname);
Packit 8480eb
Packit 8480eb
	ypcb_data.timeout = master->default_timeout;
Packit 8480eb
	ypcb_data.logging = logging;
Packit 8480eb
	ypcb_data.logopt = logopt;
Packit 8480eb
	ypcb_data.age = age;
Packit 8480eb
Packit 8480eb
	ypcb.foreach = yp_all_master_callback;
Packit 8480eb
	ypcb.data = (char *) &ypcb_data;
Packit 8480eb
Packit 8480eb
	err = yp_all((char *) ctxt->domainname, mapname, &ypcb);
Packit 8480eb
Packit 8480eb
	if (err != YPERR_SUCCESS) {
Packit 8480eb
		if (err == YPERR_MAP) {
Packit 8480eb
			char *usc;
Packit 8480eb
Packit 8480eb
			while ((usc = strchr(mapname, '_')))
Packit 8480eb
				*usc = '.';
Packit 8480eb
Packit 8480eb
			err = yp_all((char *) ctxt->domainname, mapname, &ypcb);
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (err == YPERR_SUCCESS) {
Packit 8480eb
			free(mapname);
Packit 8480eb
			return NSS_STATUS_SUCCESS;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		info(logopt,
Packit 8480eb
		     MODPREFIX "read of master map %s failed: %s",
Packit 8480eb
		     mapname, yperr_string(err));
Packit 8480eb
Packit 8480eb
		free(mapname);
Packit 8480eb
Packit 8480eb
		if (err == YPERR_YPSERV || err == YPERR_DOMAIN)
Packit 8480eb
			return NSS_STATUS_UNAVAIL;
Packit 8480eb
Packit 8480eb
		return NSS_STATUS_NOTFOUND;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	free(mapname);
Packit 8480eb
	return NSS_STATUS_SUCCESS;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int yp_all_callback(int status, char *ypkey, int ypkeylen,
Packit 8480eb
		    char *val, int vallen, char *ypcb_data)
Packit 8480eb
{
Packit 8480eb
	struct callback_data *cbdata = (struct callback_data *) ypcb_data;
Packit 8480eb
	struct autofs_point *ap = cbdata->ap;
Packit 8480eb
	struct map_source *source = cbdata->source;
Packit 8480eb
	struct mapent_cache *mc = source->mc;
Packit 8480eb
	unsigned int logopt = cbdata->logopt;
Packit 8480eb
	time_t age = cbdata->age;
Packit 8480eb
	char *key, *mapent;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	if (status != YP_TRUE)
Packit 8480eb
		return status;
Packit 8480eb
Packit 8480eb
	/* Ignore zero length and single non-printable char keys */
Packit 8480eb
	if (ypkeylen == 0 || (ypkeylen == 1 && !isprint(*ypkey))) {
Packit 8480eb
		warn(logopt, MODPREFIX
Packit 8480eb
		     "ignoring invalid map entry, zero length or "
Packit 8480eb
		     "single character non-printable key");
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * Ignore keys beginning with '+' as plus map
Packit 8480eb
	 * inclusion is only valid in file maps.
Packit 8480eb
	 */
Packit 8480eb
	if (*ypkey == '+')
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	if (!(source->flags & MAP_FLAG_FORMAT_AMD))
Packit 8480eb
		key = sanitize_path(ypkey, ypkeylen, ap->type, ap->logopt);
Packit 8480eb
	else
Packit 8480eb
		/* Don't fail on "/" in key => type == 0 */
Packit 8480eb
		key = sanitize_path(ypkey, ypkeylen, 0, ap->logopt);
Packit 8480eb
Packit 8480eb
	if (!key) {
Packit 8480eb
		error(logopt, MODPREFIX "invalid path %s", ypkey);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	mapent = alloca(vallen + 1);
Packit 8480eb
	strncpy(mapent, val, vallen);
Packit 8480eb
	*(mapent + vallen) = '\0';
Packit 8480eb
Packit 8480eb
	cache_writelock(mc);
Packit 8480eb
	ret = cache_update(mc, source, key, mapent, age);
Packit 8480eb
	cache_unlock(mc);
Packit 8480eb
Packit 8480eb
	free(key);
Packit 8480eb
Packit 8480eb
	if (ret == CHE_FAIL)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
Packit 8480eb
{
Packit 8480eb
	struct lookup_context *ctxt = (struct lookup_context *) context;
Packit 8480eb
	struct ypall_callback ypcb;
Packit 8480eb
	struct callback_data ypcb_data;
Packit 8480eb
	unsigned int logopt = ap->logopt;
Packit 8480eb
	struct map_source *source;
Packit 8480eb
	char *mapname;
Packit 8480eb
	int err;
Packit 8480eb
Packit 8480eb
	source = ap->entry->current;
Packit 8480eb
	ap->entry->current = NULL;
Packit 8480eb
	master_source_current_signal(ap->entry);
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * If we don't need to create directories (or don't need
Packit 8480eb
	 * to read an amd cache:=all map) then there's no use
Packit 8480eb
	 * reading the map. We always need to read the whole map
Packit 8480eb
	 * for direct mounts in order to mount the triggers.
Packit 8480eb
	 */
Packit 8480eb
	if (ap->type != LKP_DIRECT &&
Packit 8480eb
	    !(ap->flags & (MOUNT_FLAG_GHOST|MOUNT_FLAG_AMD_CACHE_ALL))) {
Packit 8480eb
		debug(ap->logopt, "map read not needed, so not done");
Packit 8480eb
		return NSS_STATUS_SUCCESS;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ypcb_data.ap = ap;
Packit 8480eb
	ypcb_data.source = source;
Packit 8480eb
	ypcb_data.logopt = logopt;
Packit 8480eb
	ypcb_data.age = age;
Packit 8480eb
Packit 8480eb
	ypcb.foreach = yp_all_callback;
Packit 8480eb
	ypcb.data = (char *) &ypcb_data;
Packit 8480eb
Packit 8480eb
	mapname = alloca(strlen(ctxt->mapname) + 1);
Packit 8480eb
	if (!mapname)
Packit 8480eb
		return NSS_STATUS_UNKNOWN;
Packit 8480eb
Packit 8480eb
	strcpy(mapname, ctxt->mapname);
Packit 8480eb
Packit 8480eb
	err = yp_all((char *) ctxt->domainname, mapname, &ypcb);
Packit 8480eb
Packit 8480eb
	if (err != YPERR_SUCCESS) {
Packit 8480eb
		if (err == YPERR_MAP) {
Packit 8480eb
			char *usc;
Packit 8480eb
Packit 8480eb
			while ((usc = strchr(mapname, '_')))
Packit 8480eb
				*usc = '.';
Packit 8480eb
Packit 8480eb
			err = yp_all((char *) ctxt->domainname, mapname, &ypcb);
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (err != YPERR_SUCCESS) {
Packit 8480eb
			warn(ap->logopt,
Packit 8480eb
			     MODPREFIX "read of map %s failed: %s",
Packit 8480eb
			     ap->path, yperr_string(err));
Packit 8480eb
Packit 8480eb
			if (err == YPERR_PMAP || err == YPERR_YPSERV)
Packit 8480eb
				return NSS_STATUS_UNAVAIL;
Packit 8480eb
Packit 8480eb
			return NSS_STATUS_NOTFOUND;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	source->age = age;
Packit 8480eb
	pthread_mutex_lock(&ap->entry->current_mutex);
Packit 8480eb
	ctxt->check_defaults = 0;
Packit 8480eb
	pthread_mutex_unlock(&ap->entry->current_mutex);
Packit 8480eb
Packit 8480eb
	return NSS_STATUS_SUCCESS;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int lookup_one(struct autofs_point *ap,
Packit 8480eb
		      struct map_source *source,
Packit 8480eb
		      const char *key, int key_len,
Packit 8480eb
		      struct lookup_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	struct mapent_cache *mc;
Packit 8480eb
	char *mapname;
Packit 8480eb
	char *mapent;
Packit 8480eb
	int mapent_len;
Packit 8480eb
	time_t age = monotonic_time(NULL);
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	mc = source->mc;
Packit 8480eb
Packit 8480eb
	mapname = alloca(strlen(ctxt->mapname) + 1);
Packit 8480eb
	if (!mapname)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	strcpy(mapname, ctxt->mapname);
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * For reasons unknown, the standard YP definitions doesn't
Packit 8480eb
	 * define input strings as const char *.  However, my
Packit 8480eb
	 * understanding is that they will not be modified by the
Packit 8480eb
	 * library.
Packit 8480eb
	 */
Packit 8480eb
	ret = yp_match((char *) ctxt->domainname, mapname,
Packit 8480eb
		       (char *) key, key_len, &mapent, &mapent_len);
Packit 8480eb
Packit 8480eb
	if (ret != YPERR_SUCCESS) {
Packit 8480eb
		if (ret == YPERR_MAP) {
Packit 8480eb
			char *usc;
Packit 8480eb
Packit 8480eb
			while ((usc = strchr(mapname, '_')))
Packit 8480eb
				*usc = '.';
Packit 8480eb
Packit 8480eb
			ret = yp_match((char *) ctxt->domainname,
Packit 8480eb
				mapname, key, key_len, &mapent, &mapent_len);
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (ret != YPERR_SUCCESS) {
Packit 8480eb
			if (ret == YPERR_KEY)
Packit 8480eb
				return CHE_MISSING;
Packit 8480eb
Packit 8480eb
			return -ret;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	cache_writelock(mc);
Packit 8480eb
	ret = cache_update(mc, source, key, mapent, age);
Packit 8480eb
	cache_unlock(mc);
Packit 8480eb
	free(mapent);
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int match_key(struct autofs_point *ap,
Packit 8480eb
		     struct map_source *source,
Packit 8480eb
		     const char *key, int key_len,
Packit 8480eb
		     struct lookup_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	unsigned int is_amd_format = source->flags & MAP_FLAG_FORMAT_AMD;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	char *lkp_key;
Packit 8480eb
	char *prefix;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	ret = lookup_one(ap, source, key, strlen(key), ctxt);
Packit 8480eb
	if (ret < 0)
Packit 8480eb
		return ret;
Packit 8480eb
	if (ret == CHE_OK || ret == CHE_UPDATED || !is_amd_format)
Packit 8480eb
		return ret;
Packit 8480eb
Packit 8480eb
	lkp_key = strdup(key);
Packit 8480eb
	if (!lkp_key) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		error(ap->logopt, MODPREFIX "strdup: %s", estr);
Packit 8480eb
		return CHE_FAIL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ret = CHE_MISSING;
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * Now strip successive directory components and try a
Packit 8480eb
	 * match against map entries ending with a wildcard and
Packit 8480eb
	 * finally try the wilcard entry itself.
Packit 8480eb
	 */
Packit 8480eb
	while ((prefix = strrchr(lkp_key, '/'))) {
Packit 8480eb
		char *match;
Packit 8480eb
		size_t len;
Packit 8480eb
		*prefix = '\0';
Packit 8480eb
		len = strlen(lkp_key) + 3;
Packit 8480eb
		match = malloc(len);
Packit 8480eb
		if (!match) {
Packit 8480eb
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
			error(ap->logopt, MODPREFIX "malloc: %s", estr);
Packit 8480eb
			ret = CHE_FAIL;
Packit 8480eb
			goto done;
Packit 8480eb
		}
Packit 8480eb
		len--;
Packit 8480eb
		strcpy(match, lkp_key);
Packit 8480eb
		strcat(match, "/*");
Packit 8480eb
		ret = lookup_one(ap, source, match, len, ctxt);
Packit 8480eb
		free(match);
Packit 8480eb
		if (ret < 0)
Packit 8480eb
			goto done;
Packit 8480eb
		if (ret == CHE_OK || ret == CHE_UPDATED)
Packit 8480eb
			goto done;
Packit 8480eb
	}
Packit 8480eb
done:
Packit 8480eb
	free(lkp_key);
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int lookup_wild(struct autofs_point *ap,
Packit 8480eb
		       struct map_source *source, struct lookup_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	struct mapent_cache *mc;
Packit 8480eb
	char *mapname;
Packit 8480eb
	char *mapent;
Packit 8480eb
	int mapent_len;
Packit 8480eb
	time_t age = monotonic_time(NULL);
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	mc = source->mc;
Packit 8480eb
Packit 8480eb
	mapname = alloca(strlen(ctxt->mapname) + 1);
Packit 8480eb
	if (!mapname)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	strcpy(mapname, ctxt->mapname);
Packit 8480eb
Packit 8480eb
	ret = yp_match((char *) ctxt->domainname,
Packit 8480eb
		       mapname, "*", 1, &mapent, &mapent_len);
Packit 8480eb
Packit 8480eb
	if (ret != YPERR_SUCCESS) {
Packit 8480eb
		if (ret == YPERR_MAP) {
Packit 8480eb
			char *usc;
Packit 8480eb
Packit 8480eb
			while ((usc = strchr(mapname, '_')))
Packit 8480eb
				*usc = '.';
Packit 8480eb
Packit 8480eb
			ret = yp_match((char *) ctxt->domainname,
Packit 8480eb
				mapname, "*", 1, &mapent, &mapent_len);
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (ret != YPERR_SUCCESS) {
Packit 8480eb
			if (ret == YPERR_KEY)
Packit 8480eb
				return CHE_MISSING;
Packit 8480eb
Packit 8480eb
			return -ret;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	cache_writelock(mc);
Packit 8480eb
	ret = cache_update(mc, source, "*", mapent, age);
Packit 8480eb
	cache_unlock(mc);
Packit 8480eb
	free(mapent);
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int lookup_amd_defaults(struct autofs_point *ap,
Packit 8480eb
			       struct map_source *source,
Packit 8480eb
			       struct lookup_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	struct mapent_cache *mc = source->mc;
Packit 8480eb
	char *mapname;
Packit 8480eb
	char *mapent;
Packit 8480eb
	int mapent_len;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	mapname = malloc(strlen(ctxt->mapname) + 1);
Packit 8480eb
	if (!mapname)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	strcpy(mapname, ctxt->mapname);
Packit 8480eb
Packit 8480eb
	ret = yp_match((char *) ctxt->domainname, mapname,
Packit 8480eb
		       (char *) "/defaults", 9, &mapent, &mapent_len);
Packit 8480eb
Packit 8480eb
	if (ret != YPERR_SUCCESS) {
Packit 8480eb
		if (ret == YPERR_MAP) {
Packit 8480eb
			char *usc;
Packit 8480eb
Packit 8480eb
			while ((usc = strchr(mapname, '_')))
Packit 8480eb
				*usc = '.';
Packit 8480eb
Packit 8480eb
			ret = yp_match((char *) ctxt->domainname, mapname,
Packit 8480eb
				       "/defaults", 9, &mapent, &mapent_len);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	free(mapname);
Packit 8480eb
Packit 8480eb
	/* No /defaults entry */
Packit 8480eb
	if (ret == YPERR_KEY)
Packit 8480eb
		return CHE_OK;
Packit 8480eb
Packit 8480eb
	if (ret != YPERR_SUCCESS)
Packit 8480eb
		return CHE_FAIL;
Packit 8480eb
Packit 8480eb
	cache_writelock(mc);
Packit 8480eb
	ret = cache_update(mc, source, "/defaults", mapent, monotonic_time(NULL));
Packit 8480eb
	cache_unlock(mc);
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int check_map_indirect(struct autofs_point *ap,
Packit 8480eb
			      struct map_source *source,
Packit 8480eb
			      char *key, int key_len,
Packit 8480eb
			      struct lookup_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	struct mapent_cache *mc;
Packit 8480eb
	struct mapent *exists;
Packit 8480eb
	unsigned int map_order;
Packit 8480eb
	int ret = 0;
Packit 8480eb
Packit 8480eb
	mc = source->mc;
Packit 8480eb
Packit 8480eb
	/* Only read map if it has been modified */
Packit 8480eb
	pthread_mutex_lock(&ap->entry->current_mutex);
Packit 8480eb
	map_order = get_map_order(ctxt->domainname, ctxt->mapname);
Packit 8480eb
	if (map_order > ctxt->order) {
Packit 8480eb
		ctxt->order = map_order;
Packit 8480eb
		source->stale = 1;
Packit 8480eb
		ctxt->check_defaults = 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (source->flags & MAP_FLAG_FORMAT_AMD && ctxt->check_defaults) {
Packit 8480eb
		/* Check for a /defaults entry to update the map source */
Packit 8480eb
		if (lookup_amd_defaults(ap, source, ctxt) == CHE_FAIL) {
Packit 8480eb
			warn(ap->logopt, MODPREFIX
Packit 8480eb
			     "error getting /defaults from map %s",
Packit 8480eb
			     ctxt->mapname);
Packit 8480eb
		} else
Packit 8480eb
			ctxt->check_defaults = 0;
Packit 8480eb
	}
Packit 8480eb
	pthread_mutex_unlock(&ap->entry->current_mutex);
Packit 8480eb
Packit 8480eb
	/* check map and if change is detected re-read map */
Packit 8480eb
	ret = match_key(ap, source, key, key_len, ctxt);
Packit 8480eb
	if (ret == CHE_FAIL)
Packit 8480eb
		return NSS_STATUS_NOTFOUND;
Packit 8480eb
Packit 8480eb
	if (ret < 0) {
Packit 8480eb
		/*
Packit 8480eb
		 * If the server is down and the entry exists in the cache
Packit 8480eb
		 * and belongs to this map return success and use the entry.
Packit 8480eb
		 */
Packit 8480eb
		cache_readlock(mc);
Packit 8480eb
		if (source->flags & MAP_FLAG_FORMAT_AMD)
Packit 8480eb
			exists = match_cached_key(ap, MODPREFIX, source, key);
Packit 8480eb
		else
Packit 8480eb
			exists = cache_lookup(mc, key);
Packit 8480eb
		if (exists && exists->source == source) {
Packit 8480eb
			cache_unlock(mc);
Packit 8480eb
			return NSS_STATUS_SUCCESS;
Packit 8480eb
		}
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
Packit 8480eb
		warn(ap->logopt,
Packit 8480eb
		     MODPREFIX "lookup for %s failed: %s",
Packit 8480eb
		     key, yperr_string(-ret));
Packit 8480eb
Packit 8480eb
		return NSS_STATUS_UNAVAIL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	cache_writelock(mc);
Packit 8480eb
	if (source->flags & MAP_FLAG_FORMAT_AMD)
Packit 8480eb
		exists = match_cached_key(ap, MODPREFIX, source, key);
Packit 8480eb
	else
Packit 8480eb
		exists = cache_lookup_distinct(mc, key);
Packit 8480eb
	/* Not found in the map but found in the cache */
Packit 8480eb
	if (exists && exists->source == source && ret & CHE_MISSING) {
Packit 8480eb
		if (exists->mapent) {
Packit 8480eb
			free(exists->mapent);
Packit 8480eb
			exists->mapent = NULL;
Packit 8480eb
			source->stale = 1;
Packit 8480eb
			exists->status = 0;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	cache_unlock(mc);
Packit 8480eb
Packit 8480eb
	if (ret == CHE_MISSING) {
Packit 8480eb
		struct mapent *we;
Packit 8480eb
		int wild = CHE_MISSING;
Packit 8480eb
Packit 8480eb
		wild = lookup_wild(ap, source, ctxt);
Packit 8480eb
		/*
Packit 8480eb
		 * Check for map change and update as needed for
Packit 8480eb
		 * following cache lookup.
Packit 8480eb
		 */
Packit 8480eb
		cache_writelock(mc);
Packit 8480eb
		we = cache_lookup_distinct(mc, "*");
Packit 8480eb
		if (we) {
Packit 8480eb
			/* Wildcard entry existed and is now gone */
Packit 8480eb
			if (we->source == source && (wild & CHE_MISSING)) {
Packit 8480eb
				cache_delete(mc, "*");
Packit 8480eb
				source->stale = 1;
Packit 8480eb
			}
Packit 8480eb
		} else {
Packit 8480eb
			/* Wildcard not in map but now is */
Packit 8480eb
			if (wild & (CHE_OK | CHE_UPDATED))
Packit 8480eb
				source->stale = 1;
Packit 8480eb
		}
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
Packit 8480eb
		if (wild & (CHE_OK | CHE_UPDATED))
Packit 8480eb
			return NSS_STATUS_SUCCESS;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (ret == CHE_MISSING)
Packit 8480eb
		return NSS_STATUS_NOTFOUND;
Packit 8480eb
Packit 8480eb
	return NSS_STATUS_SUCCESS;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *context)
Packit 8480eb
{
Packit 8480eb
	struct lookup_context *ctxt = (struct lookup_context *) context;
Packit 8480eb
	struct map_source *source;
Packit 8480eb
	struct mapent_cache *mc;
Packit 8480eb
	char key[KEY_MAX_LEN + 1];
Packit 8480eb
	int key_len;
Packit 8480eb
	char *lkp_key;
Packit 8480eb
	char *mapent = NULL;
Packit 8480eb
	int mapent_len;
Packit 8480eb
	struct mapent *me;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	int status = 0;
Packit 8480eb
	int ret = 1;
Packit 8480eb
Packit 8480eb
	source = ap->entry->current;
Packit 8480eb
	ap->entry->current = NULL;
Packit 8480eb
	master_source_current_signal(ap->entry);
Packit 8480eb
Packit 8480eb
	mc = source->mc;
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, MODPREFIX "looking up %s", name);
Packit 8480eb
Packit 8480eb
	if (!(source->flags & MAP_FLAG_FORMAT_AMD)) {
Packit 8480eb
		key_len = snprintf(key, KEY_MAX_LEN + 1, "%s", name);
Packit 8480eb
		if (key_len > KEY_MAX_LEN)
Packit 8480eb
			return NSS_STATUS_NOTFOUND;
Packit 8480eb
	} else {
Packit 8480eb
		key_len = expandamdent(name, NULL, NULL);
Packit 8480eb
		if (key_len > KEY_MAX_LEN)
Packit 8480eb
			return NSS_STATUS_NOTFOUND;
Packit 8480eb
		memset(key, 0, KEY_MAX_LEN + 1);
Packit 8480eb
		expandamdent(name, key, NULL);
Packit 8480eb
		debug(ap->logopt, MODPREFIX "expanded key: \"%s\"", key);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Check if we recorded a mount fail for this key anywhere */
Packit 8480eb
	me = lookup_source_mapent(ap, key, LKP_DISTINCT);
Packit 8480eb
	if (me) {
Packit 8480eb
		if (me->status >= monotonic_time(NULL)) {
Packit 8480eb
			cache_unlock(me->mc);
Packit 8480eb
			return NSS_STATUS_NOTFOUND;
Packit 8480eb
		} else {
Packit 8480eb
			struct mapent_cache *smc = me->mc;
Packit 8480eb
			struct mapent *sme;
Packit 8480eb
Packit 8480eb
			if (me->mapent)
Packit 8480eb
				cache_unlock(smc);
Packit 8480eb
			else {
Packit 8480eb
				cache_unlock(smc);
Packit 8480eb
				cache_writelock(smc);
Packit 8480eb
				sme = cache_lookup_distinct(smc, key);
Packit 8480eb
				/* Negative timeout expired for non-existent entry. */
Packit 8480eb
				if (sme && !sme->mapent) {
Packit 8480eb
					if (cache_pop_mapent(sme) == CHE_FAIL)
Packit 8480eb
						cache_delete(smc, key);
Packit 8480eb
				}
Packit 8480eb
				cache_unlock(smc);
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	 /*
Packit 8480eb
	  * We can't check the direct mount map as if it's not in
Packit 8480eb
	  * the map cache already we never get a mount lookup, so
Packit 8480eb
	  * we never know about it.
Packit 8480eb
	  */
Packit 8480eb
        if (ap->type == LKP_INDIRECT && *key != '/') {
Packit 8480eb
		cache_readlock(mc);
Packit 8480eb
		me = cache_lookup_distinct(mc, key);
Packit Service 1b0899
		if (me && IS_MM(me))
Packit Service 1b0899
			lkp_key = strdup(MM_ROOT(me)->key);
Packit 8480eb
		else if (!ap->pref)
Packit 8480eb
			lkp_key = strdup(key);
Packit 8480eb
		else {
Packit 8480eb
			lkp_key = malloc(strlen(ap->pref) + strlen(key) + 1);
Packit 8480eb
			if (lkp_key) {
Packit 8480eb
				strcpy(lkp_key, ap->pref);
Packit 8480eb
				strcat(lkp_key, key);
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
Packit 8480eb
		if (!lkp_key) {
Packit 8480eb
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
			error(ap->logopt, MODPREFIX "malloc: %s", estr);
Packit 8480eb
			return NSS_STATUS_UNKNOWN;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		status = check_map_indirect(ap, source,
Packit 8480eb
					    lkp_key, strlen(lkp_key), ctxt);
Packit 8480eb
		free(lkp_key);
Packit 8480eb
		if (status)
Packit 8480eb
			return status;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * We can't take the writelock for direct mounts. If we're
Packit 8480eb
	 * starting up or trying to re-connect to an existing direct
Packit 8480eb
	 * mount we could be iterating through the map entries with
Packit 8480eb
	 * the readlock held. But we don't need to update the cache
Packit 8480eb
	 * when we're starting up so just take the readlock in that
Packit 8480eb
	 * case.
Packit 8480eb
	 */
Packit 8480eb
	if (ap->flags & MOUNT_FLAG_REMOUNT)
Packit 8480eb
		cache_readlock(mc);
Packit 8480eb
	else
Packit 8480eb
		cache_writelock(mc);
Packit 8480eb
Packit 8480eb
	if (!ap->pref)
Packit 8480eb
		lkp_key = strdup(key);
Packit 8480eb
	else {
Packit 8480eb
		lkp_key = malloc(strlen(ap->pref) + strlen(key) + 1);
Packit 8480eb
		if (lkp_key) {
Packit 8480eb
			strcpy(lkp_key, ap->pref);
Packit 8480eb
			strcat(lkp_key, key);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!lkp_key) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		error(ap->logopt, MODPREFIX "malloc: %s", estr);
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
		return NSS_STATUS_UNKNOWN;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	me = match_cached_key(ap, MODPREFIX, source, lkp_key);
Packit 8480eb
	/* Stale mapent => check for entry in alternate source or wildcard */
Packit 8480eb
	if (me && !me->mapent) {
Packit 8480eb
		while ((me = cache_lookup_key_next(me)))
Packit 8480eb
			if (me->source == source)
Packit 8480eb
				break;
Packit 8480eb
		if (!me)
Packit 8480eb
			me = cache_lookup_distinct(mc, "*");
Packit 8480eb
	}
Packit 8480eb
	if (me && me->mapent) {
Packit 8480eb
		/*
Packit 8480eb
		 * If this is a lookup add wildcard match for later validation
Packit 8480eb
		 * checks and negative cache lookups.
Packit 8480eb
		 */
Packit 8480eb
		if (ap->type == LKP_INDIRECT && *me->key == '*' &&
Packit 8480eb
		   !(ap->flags & MOUNT_FLAG_REMOUNT)) {
Packit 8480eb
			ret = cache_update(mc, source, key, me->mapent, me->age);
Packit 8480eb
			if (!(ret & (CHE_OK | CHE_UPDATED)))
Packit 8480eb
				me = NULL;
Packit 8480eb
		}
Packit 8480eb
		if (me && (me->source == source || *me->key == '/')) {
Packit 8480eb
			mapent_len = strlen(me->mapent);
Packit 8480eb
			mapent = alloca(mapent_len + 1);
Packit 8480eb
			strcpy(mapent, me->mapent);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	cache_unlock(mc);
Packit 8480eb
Packit 8480eb
	if (!me) {
Packit 8480eb
		free(lkp_key);
Packit 8480eb
		return NSS_STATUS_NOTFOUND;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!mapent) {
Packit 8480eb
		free(lkp_key);
Packit 8480eb
		return NSS_STATUS_TRYAGAIN;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, MODPREFIX "%s -> %s", lkp_key, mapent);
Packit 8480eb
Packit 8480eb
	free(lkp_key);
Packit 8480eb
Packit 8480eb
	master_source_current_wait(ap->entry);
Packit 8480eb
	ap->entry->current = source;
Packit 8480eb
Packit 8480eb
	ret = ctxt->parse->parse_mount(ap, key, key_len,
Packit 8480eb
				       mapent, ctxt->parse->context);
Packit 8480eb
	if (ret) {
Packit 8480eb
		/* Don't update negative cache when re-connecting */
Packit 8480eb
		if (ap->flags & MOUNT_FLAG_REMOUNT)
Packit 8480eb
			return NSS_STATUS_TRYAGAIN;
Packit 8480eb
		cache_writelock(mc);
Packit 8480eb
		cache_update_negative(mc, source, key, ap->negative_timeout);
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
		return NSS_STATUS_TRYAGAIN;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return NSS_STATUS_SUCCESS;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int lookup_done(void *context)
Packit 8480eb
{
Packit 8480eb
	struct lookup_context *ctxt = (struct lookup_context *) context;
Packit 8480eb
	int rv = close_parse(ctxt->parse);
Packit 8480eb
	free(ctxt->domainname);
Packit 8480eb
	free(ctxt);
Packit 8480eb
	return rv;
Packit 8480eb
}