Blame modules/lookup_sss.c

Packit 8480eb
/* ----------------------------------------------------------------------- *
Packit 8480eb
 *
Packit 8480eb
 *  lookup_sss.c - module for Linux automount to query sss service
Packit 8480eb
 *
Packit 8480eb
 *   Copyright 2012 Ian Kent <raven@themaw.net>
Packit 8480eb
 *   Copyright 2012 Red Hat, Inc.
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 <stdlib.h>
Packit 8480eb
#include <ctype.h>
Packit 8480eb
#include <dlfcn.h>
Packit 8480eb
#include <errno.h>
Packit 8480eb
#include <string.h>
Packit 8480eb
#include <sys/param.h>
Packit 8480eb
#include <sys/types.h>
Packit 8480eb
#include <sys/stat.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 Bot 911e0c
/* One second between retries */
Packit Bot 911e0c
#define SSS_WAIT_INTERVAL	1
Packit 8480eb
Packit 8480eb
#define MODPREFIX "lookup(sss): "
Packit 8480eb
Packit 8480eb
#define SSS_SO_NAME "libsss_autofs"
Packit 8480eb
Packit Bot f53394
/* If the sss library protocol version is greater than 0 there are
Packit Bot f53394
 * more possibile error returns from the sss autofs library calls.
Packit Bot f53394
 *
Packit Bot f53394
 * If ECONNREFUSED is returned then sssd is not running or not
Packit Bot f53394
 * configured on the system, immediately return an unavailable
Packit Bot f53394
 * status.
Packit Bot f53394
 *
Packit Bot f53394
 * A return of EHOSTDOWN means sss backend server is down so we
Packit Bot f53394
 * should retry.
Packit Bot f53394
 *
Packit Bot f53394
 * With older sss ilibrary we can get a return of ENOENT for the
Packit Bot f53394
 * above cases so also wait in that case since we can't be sure
Packit Bot f53394
 * the map doesn't exist.
Packit Bot f53394
 */
Packit Bot f53394
#define SSS_PROTO_VERSION 1
Packit Bot f53394
Packit Bot 30c946
#define SSS_DEFAULT_WAIT	10
Packit Bot 30c946
Packit Bot 30c946
/* When the master map is being read a retry loop is used by the
Packit Bot 30c946
 * caller to try harder to read the master map because it is required
Packit Bot 30c946
 * for autofs to start up.
Packit Bot 30c946
 *
Packit Bot 30c946
 * But when reading dependent maps or looking up a key that loop isn't
Packit Bot 30c946
 * used so a longer retry is needed for those cases.
Packit Bot 30c946
 *
Packit Bot 30c946
 * Introduce a flag to indicate which map is being read or if a lookup
Packit Bot 30c946
 * is being done so the number of retries can be adjusted accordingly.
Packit Bot 30c946
 */
Packit Bot 30c946
#define SSS_READ_NONE		0x00
Packit Bot 30c946
#define SSS_READ_MASTER_MAP	0x01
Packit Bot 30c946
#define SSS_REREAD_MASTER_MAP	0x02
Packit Bot 30c946
#define SSS_READ_DEPENDENT_MAP	0x04
Packit Bot 30c946
#define SSS_LOOKUP_KEY		0x08
Packit Bot 30c946
Packit Bot f53394
unsigned int _sss_auto_protocol_version(unsigned int);
Packit 8480eb
int _sss_setautomntent(const char *, void **);
Packit 8480eb
int _sss_getautomntent_r(char **, char **, void *);
Packit 8480eb
int _sss_getautomntbyname_r(char *, char **, void *);
Packit 8480eb
int _sss_endautomntent(void **);
Packit 8480eb
Packit Bot f53394
typedef unsigned int (*protocol_version_t) (unsigned int);
Packit 8480eb
typedef int (*setautomntent_t) (const char *, void **);
Packit 8480eb
typedef int (*getautomntent_t) (char **, char **, void *);
Packit 8480eb
typedef int (*getautomntbyname_t) (char *, char **, void *);
Packit 8480eb
typedef int (*endautomntent_t) (void **);
Packit 8480eb
Packit 8480eb
struct lookup_context {
Packit 8480eb
	const char *mapname;
Packit 8480eb
    	void *dlhandle;
Packit Bot f53394
	protocol_version_t protocol_version;
Packit 8480eb
	setautomntent_t setautomntent;
Packit 8480eb
	getautomntent_t getautomntent_r;
Packit 8480eb
	getautomntbyname_t getautomntbyname_r;
Packit 8480eb
	endautomntent_t endautomntent;
Packit 8480eb
	struct parse_mod *parse;
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
int lookup_version = AUTOFS_LOOKUP_VERSION;	/* Required by protocol */
Packit Bot f53394
int sss_proto_version = SSS_PROTO_VERSION;	/* 0 => initial version,
Packit Bot f53394
						 * >= 1 => new error handling. */
Packit 8480eb
Packit 8480eb
static int open_sss_lib(struct lookup_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	char dlbuf[PATH_MAX];
Packit 8480eb
	char *estr;
Packit 8480eb
	void *dh;
Packit 8480eb
	size_t size;
Packit 8480eb
Packit 8480eb
	size = snprintf(dlbuf, sizeof(dlbuf),
Packit 8480eb
			"%s/%s.so", SSS_LIB_DIR, SSS_SO_NAME);
Packit 8480eb
	if (size >= sizeof(dlbuf)) {
Packit 8480eb
		logmsg(MODPREFIX "sss library path too long");
Packit 8480eb
		return 1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	dh = dlopen(dlbuf, RTLD_LAZY);
Packit 8480eb
	if (!dh)
Packit 8480eb
		return 1;
Packit 8480eb
	ctxt->dlhandle = dh;
Packit 8480eb
Packit Bot f53394
	/* Don't fail on NULL, it's simply not present in this version of the
Packit Bot f53394
	 * sss autofs library.
Packit Bot f53394
	 */
Packit Bot f53394
	ctxt->protocol_version = (protocol_version_t) dlsym(dh, "_sss_auto_protocol_version");
Packit Bot f53394
Packit 8480eb
	ctxt->setautomntent = (setautomntent_t) dlsym(dh, "_sss_setautomntent");
Packit 8480eb
	if (!ctxt->setautomntent)
Packit 8480eb
		goto lib_names_fail;
Packit 8480eb
Packit 8480eb
	ctxt->getautomntent_r = (getautomntent_t) dlsym(dh, "_sss_getautomntent_r");
Packit 8480eb
	if (!ctxt->getautomntent_r)
Packit 8480eb
		goto lib_names_fail;
Packit 8480eb
Packit 8480eb
	ctxt->getautomntbyname_r = (getautomntbyname_t) dlsym(dh, "_sss_getautomntbyname_r");
Packit 8480eb
	if (!ctxt->getautomntbyname_r)
Packit 8480eb
		goto lib_names_fail;
Packit 8480eb
Packit 8480eb
	ctxt->endautomntent = (endautomntent_t) dlsym(dh, "_sss_endautomntent");
Packit Bot 8c7b8f
	if (!ctxt->endautomntent)
Packit 8480eb
		goto lib_names_fail;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
Packit 8480eb
lib_names_fail:
Packit 8480eb
	if ((estr = dlerror()) == NULL)
Packit 8480eb
		logmsg(MODPREFIX "failed to locate sss library entry points");
Packit 8480eb
	else
Packit 8480eb
		logerr(MODPREFIX "dlsym: %s", estr);
Packit 8480eb
	dlclose(dh);
Packit 8480eb
Packit 8480eb
	return 1;
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
	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
Packit 8480eb
	if (!mapfmt)
Packit 8480eb
		mapfmt = MAPFMT_DEFAULT;
Packit 8480eb
Packit 8480eb
	if (!reinit) {
Packit 8480eb
		ret = open_sss_lib(ctxt);
Packit 8480eb
		if (ret)
Packit 8480eb
			goto out;
Packit 8480eb
	}
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
			dlclose(ctxt->dlhandle);
Packit 8480eb
			ret = 1;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
out:
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
	char *estr;
Packit 8480eb
Packit 8480eb
	*context = NULL;
Packit 8480eb
Packit 8480eb
	ctxt = malloc(sizeof(struct lookup_context));
Packit 8480eb
	if (!ctxt) {
Packit 8480eb
		estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr(MODPREFIX "malloc: %s", estr);
Packit 8480eb
		return 1;
Packit 8480eb
	}
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
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
	new->dlhandle = ctxt->dlhandle;
Packit Bot f53394
	new->protocol_version = ctxt->protocol_version;
Packit 8480eb
	new->setautomntent = ctxt->setautomntent;
Packit 8480eb
	new->getautomntent_r = ctxt->getautomntent_r;
Packit 8480eb
	new->getautomntbyname_r = ctxt->getautomntbyname_r;
Packit 8480eb
	new->endautomntent = ctxt->endautomntent;
Packit 8480eb
Packit 8480eb
	*context = new;
Packit 8480eb
Packit 8480eb
	free(ctxt);
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit Bot f53394
static unsigned int proto_version(struct lookup_context *ctxt)
Packit Bot f53394
{
Packit Bot f53394
	unsigned int proto_version = 0;
Packit Bot f53394
Packit Bot f53394
	if (ctxt->protocol_version) {
Packit Bot f53394
		/* If ctxt->protocol_version() is defined it's assumed
Packit Bot f53394
		 * that for sss_proto_version <= sss autofs library
Packit Bot f53394
		 * protocol version ctxt->protocol_version() will
Packit Bot f53394
		 * return the version requested by autofs to indicate
Packit Bot f53394
		 * it userstands what the autofs module is capable of
Packit Bot f53394
		 * handling.
Packit Bot f53394
		 */
Packit Bot f53394
		proto_version = ctxt->protocol_version(sss_proto_version);
Packit Bot f53394
	}
Packit Bot f53394
	return proto_version;
Packit Bot f53394
}
Packit Bot f53394
Packit Bot 30c946
static unsigned int calculate_retry_count(struct lookup_context *ctxt, unsigned int flags)
Packit Service d36279
{
Packit Bot fa8e22
	int retries;
Packit Service d36279
Packit Bot 410fe4
	retries = defaults_get_sss_master_map_wait();
Packit Bot 9e51da
Packit Bot 9e51da
	/* If sss_master_map_wait is not set in the autofs
Packit Bot 9e51da
	 * configuration give it a sensible value since we
Packit Bot 9e51da
	 * want to wait for a host that's down in case it
Packit Bot 9e51da
	 * comes back up.
Packit Bot fa8e22
	 *
Packit Bot fa8e22
	 * Use the sss_master_map_wait configuration option
Packit Bot fa8e22
	 * for the time to wait when reading a dependednt map
Packit Bot fa8e22
	 * or performing a key lookup too.
Packit Bot 9e51da
	 */
Packit Bot 9e51da
	if (retries <= 0) {
Packit Bot 9e51da
		/* Protocol version 0 cant't tell us about
Packit Bot fa8e22
		 * a host being down, return 0 for retries.
Packit Bot 9e51da
		 */
Packit Bot 9e51da
		if (proto_version(ctxt) == 0)
Packit Bot 30c946
			return 0;
Packit Bot fa8e22
		else
Packit Bot 30c946
			retries = SSS_DEFAULT_WAIT;
Packit Bot fa8e22
	}
Packit Bot 30c946
Packit Bot 30c946
	if (proto_version(ctxt) == 0)
Packit Bot 30c946
		return retries;
Packit Bot 30c946
Packit Bot 30c946
	/* When the master map is being read there's an additional
Packit Bot 30c946
	 * outer wait loop.
Packit Bot 30c946
	 *
Packit Bot 30c946
	 * If master map wait is set in the configuration there
Packit Bot 30c946
	 * will be an outer loop interating master_map_wait / 2
Packit Bot 30c946
	 * times so adjust the number of retries here to account
Packit Bot 30c946
	 * for this for the cases where the master map isn't being
Packit Bot 30c946
	 * read.
Packit Bot 30c946
	 */
Packit Bot 30c946
Packit Bot 30c946
	if (!(flags & SSS_READ_MASTER_MAP) ||
Packit Bot 30c946
	     (flags & SSS_REREAD_MASTER_MAP)) {
Packit Bot 30c946
		unsigned int master_map_wait = defaults_get_master_wait();
Packit Bot 30c946
		unsigned int m_wait;
Packit Bot 30c946
Packit Bot 30c946
		m_wait = master_map_wait ? master_map_wait : SSS_DEFAULT_WAIT;
Packit Bot 30c946
		retries *= (m_wait / 2);
Packit Bot 30c946
	}
Packit Bot 30c946
Packit Bot fa8e22
	return retries;
Packit Bot fa8e22
}
Packit Bot fa8e22
Packit Bot fa8e22
static int setautomntent_wait(unsigned int logopt,
Packit Bot 30c946
			      struct lookup_context *ctxt, void **sss_ctxt,
Packit Bot 30c946
			      unsigned int flags)
Packit Bot fa8e22
{
Packit Bot fa8e22
	unsigned int retries;
Packit Bot fa8e22
	unsigned int retry = 0;
Packit Bot fa8e22
	int ret = 0;
Packit Bot fa8e22
Packit Bot fa8e22
	*sss_ctxt = NULL;
Packit Bot fa8e22
Packit Bot 30c946
	retries = calculate_retry_count(ctxt, flags);
Packit Bot fa8e22
	if (retries == 0) {
Packit Bot fa8e22
		if (proto_version(ctxt) == 0)
Packit Bot fa8e22
			return EINVAL;
Packit Bot fa8e22
		return ENOENT;
Packit Bot 9e51da
	}
Packit Bot 9e51da
Packit Bot 9e51da
	warn(logopt,
Packit Bot 9e51da
	     "can't connect to sssd, retry for %d seconds",
Packit Bot 9e51da
	     retries);
Packit Bot 410fe4
Packit Bot 911e0c
	while (++retry <= retries) {
Packit Bot 911e0c
		struct timespec t = { SSS_WAIT_INTERVAL, 0 };
Packit 8480eb
		struct timespec r;
Packit 8480eb
Packit Bot 0162f1
		ret = ctxt->setautomntent(ctxt->mapname, sss_ctxt);
Packit Bot 9e51da
		if (proto_version(ctxt) == 0) {
Packit Bot 9e51da
			if (ret != ENOENT)
Packit Bot 9e51da
				break;
Packit Bot 9e51da
		} else {
Packit Bot 9e51da
			if (ret != EHOSTDOWN)
Packit Bot 9e51da
				break;
Packit Bot 9e51da
		}
Packit 8480eb
Packit 8480eb
		if (*sss_ctxt) {
Packit 8480eb
			free(*sss_ctxt);
Packit 8480eb
			*sss_ctxt = NULL;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		while (nanosleep(&t, &r) == -1 && errno == EINTR)
Packit 8480eb
			memcpy(&t, &r, sizeof(struct timespec));
Packit 8480eb
	}
Packit 8480eb
Packit Bot 9e51da
	if (!ret)
Packit Bot 9e51da
		info(logopt, "successfully connected to sssd");
Packit Bot 9e51da
	else {
Packit 8480eb
		if (*sss_ctxt) {
Packit 8480eb
			free(*sss_ctxt);
Packit 8480eb
			*sss_ctxt = NULL;
Packit 8480eb
		}
Packit 8480eb
Packit Bot 9e51da
		if (proto_version(ctxt) == 0 && retry > retries)
Packit 8480eb
			ret = ETIMEDOUT;
Packit Service f147de
	}
Packit Bot 06041b
	return ret;
Packit Service f147de
}
Packit Service f147de
Packit Bot 410fe4
static int setautomntent(unsigned int logopt,
Packit Bot 30c946
			 struct lookup_context *ctxt, void **sss_ctxt,
Packit Bot 30c946
			 unsigned int flags)
Packit Bot 410fe4
{
Packit Bot 410fe4
	char buf[MAX_ERR_BUF];
Packit Bot 410fe4
	char *estr;
Packit Bot 9e51da
	int err = NSS_STATUS_UNAVAIL;
Packit Bot 410fe4
	int ret;
Packit Bot 410fe4
Packit Bot 410fe4
	ret = ctxt->setautomntent(ctxt->mapname, sss_ctxt);
Packit Bot 410fe4
	if (ret) {
Packit Bot 9e51da
		if (ret == ECONNREFUSED) {
Packit Bot 9e51da
			err = NSS_STATUS_UNKNOWN;
Packit Bot 410fe4
			goto error;
Packit Bot 9e51da
		}
Packit Bot 9e51da
Packit Bot 9e51da
		if (proto_version(ctxt) == 0) {
Packit Bot 9e51da
			if (ret != ENOENT)
Packit Bot 9e51da
				goto error;
Packit Bot 9e51da
		} else {
Packit Bot 9e51da
			if (ret != ENOENT && ret != EHOSTDOWN)
Packit Bot 9e51da
				goto error;
Packit Bot 9e51da
		}
Packit Bot 410fe4
Packit Bot 30c946
		ret = setautomntent_wait(logopt, ctxt, sss_ctxt, flags);
Packit Bot 410fe4
		if (ret) {
Packit Bot 9e51da
			if (ret == ECONNREFUSED) {
Packit Bot 9e51da
				err = NSS_STATUS_UNKNOWN;
Packit Bot 9e51da
				goto error;
Packit Bot 9e51da
			}
Packit Bot 9e51da
			if (ret == ETIMEDOUT)
Packit Bot 9e51da
				goto error;
Packit Bot fa8e22
			/* sss proto version 0 and sss timeout not set */
Packit Bot fa8e22
			if (ret == EINVAL)
Packit Bot fa8e22
				goto free;
Packit Bot 9e51da
			if (ret == ENOENT) {
Packit Bot 9e51da
				err = NSS_STATUS_NOTFOUND;
Packit Bot 9e51da
				goto free;
Packit Bot 9e51da
			}
Packit Bot 410fe4
			goto error;
Packit Bot 410fe4
		}
Packit Bot 410fe4
	}
Packit Bot 9e51da
	return NSS_STATUS_SUCCESS;
Packit Bot 410fe4
Packit Bot 410fe4
error:
Packit Bot 410fe4
	estr = strerror_r(ret, buf, MAX_ERR_BUF);
Packit Bot 410fe4
	error(logopt, MODPREFIX "setautomntent: %s", estr);
Packit Bot 9e51da
free:
Packit Bot 410fe4
	if (*sss_ctxt) {
Packit Bot 410fe4
		free(*sss_ctxt);
Packit Bot 410fe4
		*sss_ctxt = NULL;
Packit Bot 410fe4
	}
Packit Bot 9e51da
	return err;
Packit Bot 410fe4
}
Packit Bot 410fe4
Packit 8480eb
static int endautomntent(unsigned int logopt,
Packit 8480eb
			 struct lookup_context *ctxt, void **sss_ctxt)
Packit 8480eb
{
Packit 8480eb
	int ret = ctxt->endautomntent(sss_ctxt);
Packit 8480eb
	if (ret) {
Packit 8480eb
		char buf[MAX_ERR_BUF];
Packit 8480eb
		char *estr = strerror_r(ret, buf, MAX_ERR_BUF);
Packit 8480eb
		error(logopt, MODPREFIX "endautomntent: %s", estr);
Packit 8480eb
	}
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit Bot 468a14
static int getautomntent_wait(unsigned int logopt,
Packit Bot 468a14
			 struct lookup_context *ctxt,
Packit Bot 30c946
			 char **key, char **value, void *sss_ctxt,
Packit Bot 30c946
			 unsigned int flags)
Packit Bot 468a14
{
Packit Bot 468a14
	unsigned int retries;
Packit Bot 468a14
	unsigned int retry = 0;
Packit Bot 468a14
	int ret = 0;
Packit Bot 468a14
Packit Bot 30c946
	retries = calculate_retry_count(ctxt, flags);
Packit Bot fa8e22
	if (retries == 0) {
Packit Bot 468a14
		if (proto_version(ctxt) == 0)
Packit Bot fa8e22
			return EINVAL;
Packit Bot fa8e22
		return ENOENT;
Packit Bot 468a14
	}
Packit Bot 468a14
Packit Bot 468a14
	warn(logopt,
Packit Bot 468a14
	 "can't contact sssd to to get map entry, retry for %d seconds",
Packit Bot 468a14
	 retries);
Packit Bot 468a14
Packit Bot 468a14
	while (++retry <= retries) {
Packit Bot 468a14
		struct timespec t = { SSS_WAIT_INTERVAL, 0 };
Packit Bot 468a14
		struct timespec r;
Packit Bot 468a14
Packit Bot 468a14
		ret = ctxt->getautomntent_r(key, value, sss_ctxt);
Packit Bot 468a14
		if (proto_version(ctxt) == 0) {
Packit Bot 468a14
			if (ret != ENOENT)
Packit Bot 468a14
				break;
Packit Bot 468a14
		} else {
Packit Bot 468a14
			if (ret != EHOSTDOWN)
Packit Bot 468a14
				break;
Packit Bot 468a14
		}
Packit Bot 468a14
Packit Bot 468a14
		while (nanosleep(&t, &r) == -1 && errno == EINTR)
Packit Bot 468a14
			memcpy(&t, &r, sizeof(struct timespec));
Packit Bot 468a14
	}
Packit Bot 468a14
Packit Bot 468a14
	if (!ret)
Packit Bot 468a14
		info(logopt,
Packit Bot 468a14
		     "successfully contacted sssd to get map entry");
Packit Bot 468a14
	else {
Packit Bot 468a14
		if (retry == retries)
Packit Bot 468a14
			ret = ETIMEDOUT;
Packit Bot 468a14
	}
Packit Bot 468a14
	return ret;
Packit Bot 468a14
}
Packit Bot 468a14
Packit Bot db7f4e
static int getautomntent(unsigned int logopt,
Packit Bot db7f4e
			 struct lookup_context *ctxt,
Packit Bot 30c946
			 char **key, char **value, int count,
Packit Bot 30c946
			 void *sss_ctxt, unsigned int flags)
Packit Bot db7f4e
{
Packit Bot db7f4e
	char buf[MAX_ERR_BUF];
Packit Bot db7f4e
	char *estr;
Packit Bot 468a14
	int err = NSS_STATUS_UNAVAIL;
Packit Bot 468a14
	int ret;
Packit Bot db7f4e
Packit Bot db7f4e
	ret = ctxt->getautomntent_r(key, value, sss_ctxt);
Packit Bot db7f4e
	if (ret) {
Packit Bot db7f4e
		/* Host has gone down */
Packit Bot 468a14
		if (ret == ECONNREFUSED) {
Packit Bot 468a14
			err = NSS_STATUS_UNKNOWN;
Packit Bot db7f4e
			goto error;
Packit Bot 468a14
		}
Packit Bot 468a14
Packit Bot 468a14
		if (proto_version(ctxt) == 0) {
Packit Bot 468a14
			if (ret != ENOENT)
Packit Bot 468a14
				goto error;
Packit Bot 468a14
			/* For prorocol version 0 ENOENT can only be
Packit Bot 468a14
			 * used to indicate we've read all entries.
Packit Bot 468a14
			 * So even if we haven't got any values yet we
Packit Bot 468a14
			 * can't use it to determine if we need to wait
Packit Bot 468a14
			 * on sss.
Packit Bot 468a14
			 */
Packit Bot 468a14
			err = NSS_STATUS_NOTFOUND;
Packit Bot 468a14
			if (count)
Packit Bot 468a14
				err = NSS_STATUS_SUCCESS;
Packit Bot db7f4e
			goto free;
Packit Bot 468a14
		} else {
Packit Bot 468a14
			if (ret == ENOENT) {
Packit Bot 468a14
				err = NSS_STATUS_NOTFOUND;
Packit Bot 468a14
				if (count)
Packit Bot 468a14
					err = NSS_STATUS_SUCCESS;
Packit Bot 468a14
				goto free;
Packit Bot 468a14
			}
Packit Bot 468a14
			if (ret != EHOSTDOWN)
Packit Bot 468a14
				goto error;
Packit Bot 468a14
		}
Packit Bot 468a14
Packit Bot 468a14
		ret = getautomntent_wait(logopt, ctxt,
Packit Bot 30c946
					 key, value, sss_ctxt, flags);
Packit Bot 468a14
		if (ret) {
Packit Bot 468a14
			if (ret == ECONNREFUSED) {
Packit Bot 468a14
				err = NSS_STATUS_UNKNOWN;
Packit Bot 468a14
				goto free;
Packit Bot 468a14
			}
Packit Bot 468a14
			if (ret == ETIMEDOUT)
Packit Bot 468a14
				goto error;
Packit Bot fa8e22
			/* sss proto version 0 and sss timeout not set => EINVAL */
Packit Bot fa8e22
			if (ret == ENOENT || ret == EINVAL) {
Packit Bot 468a14
				err = NSS_STATUS_NOTFOUND;
Packit Bot 468a14
				if (count)
Packit Bot 468a14
					err = NSS_STATUS_SUCCESS;
Packit Bot 468a14
				goto free;
Packit Bot 468a14
			}
Packit Bot 468a14
			goto error;
Packit Bot db7f4e
		}
Packit Bot db7f4e
	}
Packit Bot 468a14
	return NSS_STATUS_SUCCESS;
Packit Bot db7f4e
Packit Bot db7f4e
error:
Packit Bot db7f4e
	estr = strerror_r(ret, buf, MAX_ERR_BUF);
Packit Bot db7f4e
	error(logopt, MODPREFIX "getautomntent: %s", estr);
Packit Bot db7f4e
free:
Packit Bot 468a14
	if (*key) {
Packit Bot db7f4e
		free(*key);
Packit Bot 468a14
		*key = NULL;
Packit Bot 468a14
	}
Packit Bot 468a14
	if (*value) {
Packit Bot db7f4e
		free(*value);
Packit Bot 468a14
		*value = NULL;
Packit Bot 468a14
	}
Packit Bot 468a14
	return err;
Packit Bot db7f4e
}
Packit Bot db7f4e
Packit Bot 64c555
static int getautomntbyname_wait(unsigned int logopt,
Packit Bot 64c555
			 struct lookup_context *ctxt,
Packit Bot 64c555
			 char *key, char **value, void *sss_ctxt,
Packit Bot 64c555
			 unsigned int flags)
Packit Bot 64c555
{
Packit Bot 64c555
	unsigned int retries;
Packit Bot 64c555
	unsigned int retry = 0;
Packit Bot 64c555
	int ret = 0;
Packit Bot 64c555
Packit Bot 64c555
	retries = calculate_retry_count(ctxt, flags);
Packit Bot 64c555
	if (retries == 0) {
Packit Bot 64c555
		if (proto_version(ctxt) == 0)
Packit Bot 64c555
			return EINVAL;
Packit Bot 64c555
		return ENOENT;
Packit Bot 64c555
	}
Packit Bot 64c555
Packit Bot 64c555
	warn(logopt,
Packit Bot 64c555
	"can't contact sssd to to lookup key value, retry for %d seconds",
Packit Bot 64c555
	retries);
Packit Bot 64c555
Packit Bot 64c555
	while (++retry <= retries) {
Packit Bot 64c555
		struct timespec t = { SSS_WAIT_INTERVAL, 0 };
Packit Bot 64c555
		struct timespec r;
Packit Bot 64c555
Packit Bot 64c555
		ret = ctxt->getautomntbyname_r(key, value, sss_ctxt);
Packit Bot 64c555
		if (proto_version(ctxt) == 0) {
Packit Bot 64c555
			if (ret != ENOENT)
Packit Bot 64c555
				break;
Packit Bot 64c555
		} else {
Packit Bot 64c555
			if (ret != EHOSTDOWN)
Packit Bot 64c555
				break;
Packit Bot 64c555
		}
Packit Bot 64c555
Packit Bot 64c555
		while (nanosleep(&t, &r) == -1 && errno == EINTR)
Packit Bot 64c555
			memcpy(&t, &r, sizeof(struct timespec));
Packit Bot 64c555
	}
Packit Bot 64c555
Packit Bot 64c555
	if (!ret)
Packit Bot 64c555
		info(logopt,
Packit Bot 64c555
		     "successfully contacted sssd to lookup key value");
Packit Bot 64c555
	else {
Packit Bot 64c555
		if (proto_version(ctxt) == 0 && retry > retries)
Packit Bot 64c555
			ret = ETIMEDOUT;
Packit Bot 64c555
	}
Packit Bot 64c555
	return ret;
Packit Bot 64c555
}
Packit Bot 64c555
Packit Bot 48deea
static int getautomntbyname(unsigned int logopt,
Packit Bot 48deea
			    struct lookup_context *ctxt,
Packit Bot 64c555
			    char *key, char **value, void *sss_ctxt,
Packit Bot 64c555
			    unsigned int flags)
Packit Bot 48deea
{
Packit Bot 48deea
	char buf[MAX_ERR_BUF];
Packit Bot 48deea
	char *estr;
Packit Bot 64c555
	int err = NSS_STATUS_UNAVAIL;
Packit Bot 64c555
	int ret;
Packit Bot 48deea
Packit Bot 48deea
	ret = ctxt->getautomntbyname_r(key, value, sss_ctxt);
Packit Bot 48deea
	if (ret) {
Packit Bot 48deea
		/* Host has gone down */
Packit Bot 48deea
		if (ret == ECONNREFUSED)
Packit Bot 48deea
			goto error;
Packit Bot 48deea
Packit Bot 64c555
		if (proto_version(ctxt) == 0) {
Packit Bot 64c555
			if (ret != ENOENT)
Packit Bot 64c555
				goto error;
Packit Bot 64c555
			/* For prorocol version 0 ENOENT can only be
Packit Bot 64c555
			 * used to indicate no entry was found. So it
Packit Bot 64c555
			 * can't be used to determine if we need to wait
Packit Bot 64c555
			 * on sss.
Packit Bot 64c555
			 */
Packit Bot 64c555
			err = NSS_STATUS_NOTFOUND;
Packit Bot 64c555
			goto free;
Packit Bot 64c555
		} else {
Packit Bot 64c555
			if (ret == ENOENT) {
Packit Bot 64c555
				err = NSS_STATUS_NOTFOUND;
Packit Bot 64c555
				goto free;
Packit Bot 64c555
			}
Packit Bot 64c555
			if (ret != EHOSTDOWN)
Packit Bot 64c555
				goto error;
Packit Bot 64c555
		}
Packit Bot 64c555
Packit Bot 64c555
		ret = getautomntbyname_wait(logopt, ctxt,
Packit Bot 64c555
					    key, value, sss_ctxt, flags);
Packit Bot 64c555
		if (ret) {
Packit Bot 64c555
			if (ret == ECONNREFUSED)
Packit Bot 64c555
				goto free;
Packit Bot 64c555
			if (ret == ETIMEDOUT)
Packit Bot 64c555
				goto error;
Packit Bot 64c555
			/* sss proto version 0 and sss timeout not set */
Packit Bot 64c555
			if (ret == EINVAL)
Packit Bot 64c555
				goto free;
Packit Bot 64c555
			if (ret == ENOENT) {
Packit Bot 64c555
				err = NSS_STATUS_NOTFOUND;
Packit Bot 64c555
				goto free;
Packit Bot 64c555
			}
Packit Bot 64c555
			goto error;
Packit Bot 64c555
		}
Packit Bot 48deea
	}
Packit Bot 64c555
	return NSS_STATUS_SUCCESS;
Packit Bot 48deea
Packit Bot 48deea
error:
Packit Bot 48deea
	estr = strerror_r(ret, buf, MAX_ERR_BUF);
Packit Bot 48deea
	error(logopt, MODPREFIX "getautomntbyname: %s", estr);
Packit Bot 48deea
free:
Packit Bot 48deea
	if (*value) {
Packit Bot 48deea
		free(*value);
Packit Bot 48deea
		*value = NULL;
Packit Bot 48deea
	}
Packit Bot 64c555
	return err;
Packit Bot 48deea
}
Packit Bot 48deea
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
	unsigned int timeout = master->default_timeout;
Packit 8480eb
	unsigned int logging = master->default_logging;
Packit 8480eb
	unsigned int logopt = master->logopt;
Packit 8480eb
	void *sss_ctxt = NULL;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	char *buffer;
Packit 8480eb
	size_t buffer_len;
Packit 8480eb
	char *key;
Packit 8480eb
	char *value = NULL;
Packit 8480eb
	int count, ret;
Packit Bot 30c946
	unsigned int flags;
Packit Bot 30c946
Packit Bot 30c946
	flags = SSS_READ_MASTER_MAP;
Packit Bot 30c946
	if (master->readall)
Packit Bot 30c946
		flags |= SSS_REREAD_MASTER_MAP;
Packit Service ed9eb2
Packit Bot 30c946
	ret = setautomntent(logopt, ctxt, &sss_ctxt, flags);
Packit Bot 410fe4
	if (ret)
Packit Bot 410fe4
		return ret;
Packit 8480eb
Packit 8480eb
	count = 0;
Packit 8480eb
	while (1) {
Packit 8480eb
	        key = NULL;
Packit 8480eb
	        value = NULL;
Packit Bot 30c946
		ret = getautomntent(logopt, ctxt,
Packit Bot 30c946
				    &key, &value, count,
Packit Bot 30c946
				    sss_ctxt, SSS_READ_MASTER_MAP);
Packit Bot db7f4e
		if (ret) {
Packit 8480eb
			endautomntent(logopt, ctxt, &sss_ctxt);
Packit Bot db7f4e
			return ret;
Packit Bot 06041b
		}
Packit Bot db7f4e
Packit Bot 468a14
		if (!key || !value)
Packit Bot 468a14
			break;
Packit Bot 468a14
Packit 8480eb
		count++;
Packit 8480eb
Packit 8480eb
		buffer_len = strlen(key) + 1 + strlen(value) + 2;
Packit 8480eb
		buffer = malloc(buffer_len);
Packit 8480eb
		if (!buffer) {
Packit 8480eb
			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
			error(logopt, MODPREFIX "malloc: %s", estr);
Packit 8480eb
			endautomntent(logopt, ctxt, &sss_ctxt);
Packit 8480eb
			free(key);
Packit 8480eb
			free(value);
Packit 8480eb
			return NSS_STATUS_UNAVAIL;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * TODO: implement sun % hack for key translation for
Packit 8480eb
		 * mixed case keys in schema that are single case only.
Packit 8480eb
		 */
Packit 8480eb
Packit 8480eb
		strcpy(buffer, key);
Packit 8480eb
		strcat(buffer, " ");
Packit 8480eb
		strcat(buffer, value);
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * TODO: handle cancelation. This almost certainly isn't
Packit 8480eb
		 * handled properly by other lookup modules either so it
Packit 8480eb
		 * should be done when cancelation is reviewed for the
Packit 8480eb
		 * other modules. Ditto for the other lookup module entry
Packit 8480eb
		 * points.
Packit 8480eb
		 */
Packit 8480eb
		master_parse_entry(buffer, timeout, logging, age);
Packit 8480eb
Packit 8480eb
		free(buffer);
Packit 8480eb
		free(key);
Packit 8480eb
		free(value);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	endautomntent(logopt, ctxt, &sss_ctxt);
Packit 8480eb
Packit 8480eb
	return NSS_STATUS_SUCCESS;
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 map_source *source;
Packit 8480eb
	struct mapent_cache *mc;
Packit 8480eb
	void *sss_ctxt = NULL;
Packit 8480eb
	char *key;
Packit 8480eb
	char *value = NULL;
Packit 8480eb
	char *s_key;
Packit 8480eb
	int count, ret;
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
	/*
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 Bot 30c946
	ret = setautomntent(ap->logopt, ctxt,
Packit Bot 30c946
			    &sss_ctxt, SSS_READ_DEPENDENT_MAP);
Packit Bot 410fe4
	if (ret)
Packit Bot 410fe4
		return ret;
Packit 8480eb
Packit 8480eb
	count = 0;
Packit 8480eb
	while (1) {
Packit 8480eb
	        key = NULL;
Packit 8480eb
	        value = NULL;
Packit Bot 30c946
		ret = getautomntent(ap->logopt, ctxt,
Packit Bot 30c946
				    &key, &value, count,
Packit Bot 30c946
				    sss_ctxt, SSS_READ_DEPENDENT_MAP);
Packit Bot db7f4e
		if (ret) {
Packit 8480eb
			endautomntent(ap->logopt, ctxt, &sss_ctxt);
Packit Bot db7f4e
			return ret;
Packit Bot 06041b
		}
Packit Service 81e5af
Packit Bot 468a14
		if (!key || !value)
Packit Bot 468a14
			break;
Packit Bot 468a14
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 (*key == '+') {
Packit 8480eb
			warn(ap->logopt,
Packit 8480eb
			     MODPREFIX "ignoring '+' map entry - not in file map");
Packit 8480eb
			free(key);
Packit 8480eb
			free(value);
Packit 8480eb
			continue;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (*key == '/' && strlen(key) == 1) {
Packit 8480eb
			if (ap->type == LKP_DIRECT) {
Packit 8480eb
				free(key);
Packit 8480eb
				free(value);
Packit 8480eb
				continue;
Packit 8480eb
			}
Packit 8480eb
			*key = '*';
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * TODO: implement sun % hack for key translation for
Packit 8480eb
		 * mixed case keys in schema that are single case only.
Packit 8480eb
		 */
Packit 8480eb
Packit 8480eb
		s_key = sanitize_path(key, strlen(key), ap->type, ap->logopt);
Packit 8480eb
		if (!s_key) {
Packit 8480eb
			error(ap->logopt, MODPREFIX "invalid path %s", key);
Packit 8480eb
			endautomntent(ap->logopt, ctxt, &sss_ctxt);
Packit 8480eb
			free(key);
Packit 8480eb
			free(value);
Packit 8480eb
			return NSS_STATUS_NOTFOUND;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		count++;
Packit 8480eb
Packit 8480eb
		cache_writelock(mc);
Packit 8480eb
		cache_update(mc, source, s_key, value, age);
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
Packit 8480eb
		free(s_key);
Packit 8480eb
		free(key);
Packit 8480eb
		free(value);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	endautomntent(ap->logopt, ctxt, &sss_ctxt);
Packit 8480eb
Packit 8480eb
	source->age = age;
Packit 8480eb
Packit 8480eb
	return NSS_STATUS_SUCCESS;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int lookup_one(struct autofs_point *ap,
Packit 8480eb
		char *qKey, int qKey_len, struct lookup_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	struct map_source *source;
Packit 8480eb
	struct mapent_cache *mc;
Packit 8480eb
	struct mapent *we;
Packit 8480eb
	void *sss_ctxt = NULL;
Packit 8480eb
	time_t age = monotonic_time(NULL);
Packit 8480eb
	char *value = NULL;
Packit 8480eb
	char *s_key;
Packit Bot 2d2ce7
	int err, ret;
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 Bot 30c946
	ret = setautomntent(ap->logopt, ctxt, &sss_ctxt, SSS_LOOKUP_KEY);
Packit Bot 410fe4
	if (ret)
Packit Bot 410fe4
		return ret;
Packit Service 94cc8a
Packit Bot 64c555
	ret = getautomntbyname(ap->logopt, ctxt,
Packit Bot 64c555
			       qKey, &value, sss_ctxt, SSS_LOOKUP_KEY);
Packit Bot 48deea
	if (ret == NSS_STATUS_NOTFOUND)
Packit Bot 48deea
		goto wild;
Packit Bot 48deea
	if (ret) {
Packit Bot 06041b
		endautomntent(ap->logopt, ctxt, &sss_ctxt);
Packit Bot 48deea
		return ret;
Packit Bot 06041b
	}
Packit Bot 48deea
Packit Bot 48deea
	/*
Packit Bot 48deea
	 * TODO: implement sun % hack for key translation for
Packit Bot 48deea
	 * mixed case keys in schema that are single case only.
Packit Bot 48deea
	 */
Packit Bot 48deea
	s_key = sanitize_path(qKey, qKey_len, ap->type, ap->logopt);
Packit Bot 48deea
	if (!s_key) {
Packit 8480eb
		free(value);
Packit Bot 48deea
		value = NULL;
Packit Bot 48deea
		goto wild;
Packit 8480eb
	}
Packit Bot 48deea
	cache_writelock(mc);
Packit Bot 2d2ce7
	err = cache_update(mc, source, s_key, value, age);
Packit Bot 48deea
	cache_unlock(mc);
Packit Bot 2d2ce7
	/* Entry in map but not in cache, map is stale */
Packit Bot 2d2ce7
	if (err & CHE_UPDATED)
Packit Bot 2d2ce7
		source->stale = 1;
Packit Bot 48deea
	endautomntent(ap->logopt, ctxt, &sss_ctxt);
Packit Bot 48deea
	free(s_key);
Packit Bot 48deea
	free(value);
Packit Bot 48deea
	return NSS_STATUS_SUCCESS;
Packit 8480eb
Packit 8480eb
wild:
Packit Bot 64c555
	ret = getautomntbyname(ap->logopt, ctxt,
Packit Bot 64c555
			       "/", &value, sss_ctxt, SSS_LOOKUP_KEY);
Packit Bot 48deea
	if (ret) {
Packit Bot 48deea
		if (ret != NSS_STATUS_NOTFOUND) {
Packit Service 94cc8a
			endautomntent(ap->logopt, ctxt, &sss_ctxt);
Packit Bot 48deea
			return ret;
Packit Bot 48deea
		}
Packit Bot 64c555
		ret = getautomntbyname(ap->logopt, ctxt,
Packit Bot 64c555
				       "*", &value, sss_ctxt, SSS_LOOKUP_KEY);
Packit Bot 48deea
		if (ret && ret != NSS_STATUS_NOTFOUND) {
Packit Bot 48deea
			endautomntent(ap->logopt, ctxt, &sss_ctxt);
Packit Bot 48deea
			return ret;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit Bot 48deea
	if (ret == NSS_STATUS_NOTFOUND) {
Packit 8480eb
		/* Failed to find wild entry, update cache if needed */
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) {
Packit 8480eb
				cache_delete(mc, "*");
Packit 8480eb
				source->stale = 1;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/* Not found in the map but found in the cache */
Packit 8480eb
		struct mapent *exists = cache_lookup_distinct(mc, qKey);
Packit 8480eb
		if (exists && exists->source == source) {
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
		endautomntent(ap->logopt, ctxt, &sss_ctxt);
Packit 8480eb
		return NSS_STATUS_NOTFOUND;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	cache_writelock(mc);
Packit Bot 2d2ce7
	/* Wildcard in map but not in cache, update it */
Packit Bot 2d2ce7
	err = cache_update(mc, source, "*", value, age);
Packit Bot 06041b
	cache_unlock(mc);
Packit Bot 2d2ce7
	/* Wildcard in map but not in cache, map is stale */
Packit Bot 2d2ce7
	if (err & CHE_UPDATED)
Packit Bot 2d2ce7
		source->stale = 1;
Packit 8480eb
Packit 8480eb
	endautomntent(ap->logopt, ctxt, &sss_ctxt);
Packit 8480eb
        free(value);
Packit 8480eb
Packit 8480eb
	return NSS_STATUS_SUCCESS;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int check_map_indirect(struct autofs_point *ap,
Packit 8480eb
			      char *key, int key_len,
Packit 8480eb
			      struct lookup_context *ctxt)
Packit 8480eb
{
Packit 8480eb
	struct map_source *source;
Packit 8480eb
	struct mapent_cache *mc;
Packit 8480eb
	int ret, cur_state;
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
	master_source_current_wait(ap->entry);
Packit 8480eb
	ap->entry->current = source;
Packit 8480eb
Packit 8480eb
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
Packit 8480eb
	ret = lookup_one(ap, key, key_len, ctxt);
Packit 8480eb
	if (ret == NSS_STATUS_NOTFOUND) {
Packit 8480eb
		pthread_setcancelstate(cur_state, NULL);
Packit 8480eb
		return ret;
Packit 8480eb
	} else if (ret == NSS_STATUS_UNAVAIL) {
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
		struct mapent *exists = cache_lookup(mc, key);
Packit 8480eb
		if (exists && exists->source == source) {
Packit 8480eb
			pthread_setcancelstate(cur_state, NULL);
Packit 8480eb
			return NSS_STATUS_SUCCESS;
Packit 8480eb
		}
Packit 8480eb
		pthread_setcancelstate(cur_state, NULL);
Packit 8480eb
Packit 8480eb
		warn(ap->logopt,
Packit 8480eb
		     MODPREFIX "lookup for %s failed: connection failed", key);
Packit 8480eb
Packit 8480eb
		return ret;
Packit 8480eb
	}
Packit 8480eb
	pthread_setcancelstate(cur_state, NULL);
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
	struct mapent *me;
Packit 8480eb
	char key[KEY_MAX_LEN + 1];
Packit 8480eb
	int key_len;
Packit 8480eb
	char *mapent = NULL;
Packit 8480eb
	char mapent_buf[MAPENT_MAX_LEN + 1];
Packit 8480eb
	int ret;
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
	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
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
		int status;
Packit 8480eb
		char *lkp_key;
Packit 8480eb
Packit 8480eb
		cache_readlock(mc);
Packit 8480eb
		me = cache_lookup_distinct(mc, key);
Packit Bot 7bc25c
		if (me && IS_MM(me))
Packit Bot 7bc25c
			lkp_key = strdup(MM_ROOT(me)->key);
Packit 8480eb
		else
Packit 8480eb
			lkp_key = strdup(key);
Packit 8480eb
		cache_unlock(mc);
Packit 8480eb
Packit 8480eb
		if (!lkp_key)
Packit 8480eb
			return NSS_STATUS_UNKNOWN;
Packit 8480eb
Packit 8480eb
		master_source_current_wait(ap->entry);
Packit 8480eb
		ap->entry->current = source;
Packit 8480eb
Packit 8480eb
		status = check_map_indirect(ap, 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
	 */
Packit 8480eb
	if (ap->flags & MOUNT_FLAG_REMOUNT)
Packit Bot 06041b
		cache_readlock(mc);
Packit Bot 0ed855
	else
Packit Bot 0ed855
		cache_writelock(mc);
Packit 8480eb
	me = cache_lookup(mc, 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
			strcpy(mapent_buf, me->mapent);
Packit 8480eb
			mapent = mapent_buf;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	cache_unlock(mc);
Packit 8480eb
Packit 8480eb
	if (!mapent)
Packit 8480eb
		return NSS_STATUS_TRYAGAIN;
Packit 8480eb
Packit 8480eb
	master_source_current_wait(ap->entry);
Packit 8480eb
	ap->entry->current = source;
Packit 8480eb
Packit 8480eb
	debug(ap->logopt, MODPREFIX "%s -> %s", key, mapent);
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
	dlclose(ctxt->dlhandle);
Packit 8480eb
	free(ctxt);
Packit 8480eb
	return rv;
Packit 8480eb
}