Blame lib/parse_subs.c

Packit 8480eb
/* ----------------------------------------------------------------------- *
Packit 8480eb
 *   
Packit 8480eb
 *  parse_subs.c - misc parser subroutines
Packit 8480eb
 *                automounter map
Packit 8480eb
 * 
Packit 8480eb
 *   Copyright 1997 Transmeta Corporation - All Rights Reserved
Packit 8480eb
 *   Copyright 2000 Jeremy Fitzhardinge <jeremy@goop.org>
Packit 8480eb
 *   Copyright 2004-2006 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 <stdlib.h>
Packit 8480eb
#include <string.h>
Packit 8480eb
#include <ctype.h>
Packit 8480eb
#include <sys/types.h>
Packit 8480eb
#include <sys/socket.h>
Packit 8480eb
#include <ifaddrs.h>
Packit 8480eb
#include <libgen.h>
Packit 8480eb
#include <net/if.h>
Packit 8480eb
#include <arpa/inet.h>
Packit 8480eb
#include <netdb.h>
Packit 8480eb
Packit 8480eb
#include "automount.h"
Packit 8480eb
Packit 8480eb
#define MAX_OPTIONS_LEN		256
Packit 8480eb
#define MAX_OPTION_LEN		40
Packit 8480eb
Packit 8480eb
#define MAX_NETWORK_LEN		255
Packit 8480eb
Packit 8480eb
#define MAX_IFC_BUF		2048
Packit 8480eb
static int volatile ifc_buf_len = MAX_IFC_BUF;
Packit 8480eb
static int volatile ifc_last_len = 0;
Packit 8480eb
Packit 8480eb
#define MASK_A  0x7F000000
Packit 8480eb
#define MASK_B  0xBFFF0000
Packit 8480eb
#define MASK_C  0xDFFFFF00
Packit 8480eb
Packit 8480eb
/* Get numeric value of the n bits starting at position p */
Packit 8480eb
#define getbits(x, p, n)	((x >> (p + 1 - n)) & ~(~0 << n))
Packit 8480eb
Packit 8480eb
#define EXPAND_LEADING_SLASH	0x0001
Packit 8480eb
#define EXPAND_TRAILING_SLASH	0x0002
Packit 8480eb
#define EXPAND_LEADING_DOT	0x0004
Packit 8480eb
#define EXPAND_TRAILING_DOT	0x0008
Packit 8480eb
Packit 8480eb
#define SELECTOR_HASH_SIZE	20
Packit 8480eb
Packit 8480eb
static struct sel sel_table[] = {
Packit 8480eb
	{ SEL_ARCH,	  "arch",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_KARCH,	  "karch",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_OS,	  "os",		SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_OSVER,	  "osver",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_FULL_OS,	  "full_os",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_VENDOR,	  "vendor",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_HOST,	  "host",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_HOSTD,	  "hostd",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_XHOST,	  "xhost",	SEL_FLAG_FUNC1|SEL_FLAG_BOOL, NULL },
Packit 8480eb
	{ SEL_DOMAIN,	  "domain",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_BYTE,	  "byte",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_CLUSTER,	  "cluster",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_NETGRP,	  "netgrp",	SEL_FLAG_FUNC2|SEL_FLAG_BOOL, NULL },
Packit 8480eb
	{ SEL_NETGRPD,	  "netgrpd",	SEL_FLAG_FUNC2|SEL_FLAG_BOOL, NULL },
Packit 8480eb
	{ SEL_IN_NETWORK, "in_network",	SEL_FLAG_FUNC1|SEL_FLAG_BOOL, NULL },
Packit 8480eb
	{ SEL_IN_NETWORK, "netnumber",	SEL_FLAG_FUNC1|SEL_FLAG_BOOL, NULL },
Packit 8480eb
	{ SEL_IN_NETWORK, "network",	SEL_FLAG_FUNC1|SEL_FLAG_BOOL, NULL },
Packit 8480eb
	{ SEL_IN_NETWORK, "wire",	SEL_FLAG_FUNC1|SEL_FLAG_BOOL, NULL },
Packit 8480eb
	{ SEL_UID,	  "uid",	SEL_FLAG_MACRO|SEL_FLAG_NUM, NULL },
Packit 8480eb
	{ SEL_GID,	  "gid",	SEL_FLAG_MACRO|SEL_FLAG_NUM, NULL },
Packit 8480eb
	{ SEL_KEY,	  "key",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_MAP,	  "map",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_PATH,	  "path",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_EXISTS,	  "exists",	SEL_FLAG_FUNC1|SEL_FLAG_BOOL, NULL },
Packit 8480eb
	{ SEL_AUTODIR,	  "autodir",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_DOLLAR,	  "dollar",	SEL_FLAG_MACRO|SEL_FLAG_STR, NULL },
Packit 8480eb
	{ SEL_TRUE,	  "true",	SEL_FLAG_FUNC1|SEL_FLAG_BOOL, NULL },
Packit 8480eb
	{ SEL_FALSE,	  "false",	SEL_FLAG_FUNC1|SEL_FLAG_BOOL, NULL },
Packit 8480eb
};
Packit 8480eb
static unsigned int sel_count = sizeof(sel_table)/sizeof(struct sel);
Packit 8480eb
Packit 8480eb
static struct sel *sel_hash[SELECTOR_HASH_SIZE];
Packit 8480eb
static unsigned int sel_hash_init_done = 0;
Packit 8480eb
static pthread_mutex_t sel_hash_mutex = PTHREAD_MUTEX_INITIALIZER;
Packit 8480eb
Packit 8480eb
struct types {
Packit 8480eb
	char *type;
Packit 8480eb
	unsigned int len;
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
static struct types map_type[] = {
Packit 8480eb
	{ "file", 4 },
Packit 8480eb
	{ "program", 7 },
Packit 8480eb
	{ "yp", 2 },
Packit 8480eb
	{ "nis", 3 },
Packit 8480eb
	{ "nisplus", 7 },
Packit 8480eb
	{ "ldap", 4 },
Packit 8480eb
	{ "ldaps", 5 },
Packit 8480eb
	{ "hesiod", 6 },
Packit 8480eb
	{ "userdir", 7 },
Packit 8480eb
	{ "hosts", 5 },
Packit 8480eb
};
Packit 8480eb
static unsigned int map_type_count = sizeof(map_type)/sizeof(struct types);
Packit 8480eb
Packit 8480eb
static struct types format_type[] = {
Packit 8480eb
	{ "sun", 3 },
Packit 8480eb
	{ "hesiod", 6 },
Packit 8480eb
	{ "amd", 3},
Packit 8480eb
};
Packit 8480eb
static unsigned int format_type_count = sizeof(format_type)/sizeof(struct types);
Packit 8480eb
Packit 8480eb
static void sel_add(struct sel *sel)
Packit 8480eb
{
Packit 8480eb
	u_int32_t hval = hash(sel->name, SELECTOR_HASH_SIZE);
Packit 8480eb
	struct sel *old;
Packit 8480eb
Packit 8480eb
	old = sel_hash[hval];
Packit 8480eb
	sel_hash[hval] = sel;
Packit 8480eb
	sel_hash[hval]->next = old;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void sel_hash_init(void)
Packit 8480eb
{
Packit 8480eb
	int i;
Packit 8480eb
Packit 8480eb
	pthread_mutex_lock(&sel_hash_mutex);
Packit 8480eb
	if (sel_hash_init_done) {
Packit 8480eb
		pthread_mutex_unlock(&sel_hash_mutex);
Packit 8480eb
		return;
Packit 8480eb
	}
Packit 8480eb
	for (i = 0; i < SELECTOR_HASH_SIZE; i++)
Packit 8480eb
		sel_hash[i] = NULL;
Packit 8480eb
Packit 8480eb
	for (i = 0; i < sel_count; i++)
Packit 8480eb
		sel_add(&sel_table[i]);
Packit 8480eb
Packit 8480eb
	sel_hash_init_done = 1;
Packit 8480eb
	pthread_mutex_unlock(&sel_hash_mutex);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
struct sel *sel_lookup(const char *name)
Packit 8480eb
{
Packit 8480eb
	u_int32_t hval = hash(name, SELECTOR_HASH_SIZE);
Packit 8480eb
	struct sel *sel;
Packit 8480eb
Packit 8480eb
	pthread_mutex_lock(&sel_hash_mutex);
Packit 8480eb
	for (sel = sel_hash[hval]; sel != NULL; sel = sel->next) {
Packit 8480eb
		if (strcmp(name, sel->name) == 0) {
Packit 8480eb
			pthread_mutex_unlock(&sel_hash_mutex);
Packit 8480eb
			return sel;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	pthread_mutex_unlock(&sel_hash_mutex);
Packit 8480eb
	return NULL;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
struct selector *get_selector(char *name)
Packit 8480eb
{
Packit 8480eb
	struct sel *sel;
Packit 8480eb
Packit 8480eb
	sel = sel_lookup(name);
Packit 8480eb
	if (sel) {
Packit 8480eb
		struct selector *new = malloc(sizeof(struct selector));
Packit 8480eb
		if (!new)
Packit 8480eb
			return NULL;
Packit 8480eb
		memset(new, 0, sizeof(*new));
Packit 8480eb
		new->sel = sel;
Packit 8480eb
		return new;
Packit 8480eb
	}
Packit 8480eb
	return NULL;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void free_selector(struct selector *selector)
Packit 8480eb
{
Packit 8480eb
	struct selector *s = selector;
Packit 8480eb
	struct selector *next = s;
Packit 8480eb
Packit 8480eb
	while (s) {
Packit 8480eb
		next = s->next;
Packit 8480eb
		if (s->sel->flags & SEL_FREE_VALUE_MASK)
Packit 8480eb
			free(s->comp.value);
Packit 8480eb
		if (s->sel->flags & SEL_FREE_ARG1_MASK)
Packit 8480eb
			free(s->func.arg1);
Packit 8480eb
		if (s->sel->flags & SEL_FREE_ARG2_MASK)
Packit 8480eb
			free(s->func.arg2);
Packit 8480eb
		s = next;
Packit 8480eb
	}
Packit Bot 903c69
	free(selector);
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static unsigned int ipv6_mask_cmp(uint32_t *host, uint32_t *iface, uint32_t *mask)
Packit 8480eb
{
Packit 8480eb
	unsigned int ret = 1;
Packit 8480eb
	unsigned int i;
Packit 8480eb
Packit 8480eb
	for (i = 0; i < 4; i++) {
Packit 8480eb
		if ((host[i] & mask[i]) != (iface[i] & mask[i])) {
Packit 8480eb
			ret = 0;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
unsigned int get_proximity(struct sockaddr *host_addr)
Packit 8480eb
{
Packit 8480eb
	struct ifaddrs *ifa = NULL;
Packit 8480eb
	struct ifaddrs *this;
Packit 8480eb
	struct sockaddr_in *addr, *msk_addr, *if_addr;
Packit 8480eb
	struct sockaddr_in6 *addr6, *msk6_addr, *if6_addr;
Packit 8480eb
	struct in_addr *hst_addr;
Packit 8480eb
	struct in6_addr *hst6_addr;
Packit 8480eb
	int addr_len;
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	uint32_t mask, ha, ia, *mask6, *ha6, *ia6;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	addr = NULL;
Packit 8480eb
	addr6 = NULL;
Packit 8480eb
	hst_addr = NULL;
Packit 8480eb
	hst6_addr = NULL;
Packit 8480eb
	mask6 = NULL;
Packit 8480eb
	ha6 = NULL;
Packit 8480eb
	ia6 = NULL;
Packit 8480eb
	ha = 0;
Packit 8480eb
Packit 8480eb
	switch (host_addr->sa_family) {
Packit 8480eb
	case AF_INET:
Packit 8480eb
		addr = (struct sockaddr_in *) host_addr;
Packit 8480eb
		hst_addr = (struct in_addr *) &addr->sin_addr;
Packit 8480eb
		ha = ntohl((uint32_t) hst_addr->s_addr);
Packit 8480eb
		addr_len = sizeof(*hst_addr);
Packit 8480eb
		break;
Packit 8480eb
Packit 8480eb
	case AF_INET6:
Packit 8480eb
#ifndef WITH_LIBTIRPC
Packit 8480eb
		return PROXIMITY_UNSUPPORTED;
Packit 8480eb
#else
Packit 8480eb
		addr6 = (struct sockaddr_in6 *) host_addr;
Packit 8480eb
		hst6_addr = (struct in6_addr *) &addr6->sin6_addr;
Packit 8480eb
		ha6 = &hst6_addr->s6_addr32[0];
Packit 8480eb
		addr_len = sizeof(*hst6_addr);
Packit 8480eb
		break;
Packit 8480eb
#endif
Packit 8480eb
Packit 8480eb
	default:
Packit 8480eb
		return PROXIMITY_ERROR;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	ret = getifaddrs(&ifa;;
Packit 8480eb
	if (ret) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr("getifaddrs: %s", estr);
Packit 8480eb
		return PROXIMITY_ERROR;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	this = ifa;
Packit 8480eb
	while (this) {
Packit 8480eb
		if (!(this->ifa_flags & IFF_UP) ||
Packit 8480eb
		    this->ifa_flags & IFF_POINTOPOINT ||
Packit 8480eb
		    this->ifa_addr == NULL) {
Packit 8480eb
			this = this->ifa_next;
Packit 8480eb
			continue;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		switch (this->ifa_addr->sa_family) {
Packit 8480eb
		case AF_INET:
Packit 8480eb
			if (host_addr->sa_family == AF_INET6)
Packit 8480eb
				break;
Packit 8480eb
			if_addr = (struct sockaddr_in *) this->ifa_addr;
Packit 8480eb
			ret = memcmp(&if_addr->sin_addr, hst_addr, addr_len);
Packit 8480eb
			if (!ret) {
Packit 8480eb
				freeifaddrs(ifa);
Packit 8480eb
				return PROXIMITY_LOCAL;
Packit 8480eb
			}
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case AF_INET6:
Packit 8480eb
#ifdef WITH_LIBTIRPC
Packit 8480eb
			if (host_addr->sa_family == AF_INET)
Packit 8480eb
				break;
Packit 8480eb
			if6_addr = (struct sockaddr_in6 *) this->ifa_addr;
Packit 8480eb
			ret = memcmp(&if6_addr->sin6_addr, hst6_addr, addr_len);
Packit 8480eb
			if (!ret) {
Packit 8480eb
				freeifaddrs(ifa);
Packit 8480eb
				return PROXIMITY_LOCAL;
Packit 8480eb
			}
Packit 8480eb
#endif
Packit 8480eb
		default:
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
		this = this->ifa_next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	this = ifa;
Packit 8480eb
	while (this) {
Packit 8480eb
		if (!(this->ifa_flags & IFF_UP) ||
Packit 8480eb
		    this->ifa_flags & IFF_POINTOPOINT ||
Packit 8480eb
		    this->ifa_addr == NULL) {
Packit 8480eb
			this = this->ifa_next;
Packit 8480eb
			continue;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		switch (this->ifa_addr->sa_family) {
Packit 8480eb
		case AF_INET:
Packit 8480eb
			if (host_addr->sa_family == AF_INET6)
Packit 8480eb
				break;
Packit 8480eb
			if_addr = (struct sockaddr_in *) this->ifa_addr;
Packit 8480eb
			ia =  ntohl((uint32_t) if_addr->sin_addr.s_addr);
Packit 8480eb
Packit 8480eb
			/* Is the address within a localy attached subnet */
Packit 8480eb
Packit 8480eb
			msk_addr = (struct sockaddr_in *) this->ifa_netmask;
Packit 8480eb
			mask = ntohl((uint32_t) msk_addr->sin_addr.s_addr);
Packit 8480eb
Packit 8480eb
			if ((ia & mask) == (ha & mask)) {
Packit 8480eb
				freeifaddrs(ifa);
Packit 8480eb
				return PROXIMITY_SUBNET;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			/*
Packit 8480eb
			 * Is the address within a local ipv4 network.
Packit 8480eb
			 *
Packit 8480eb
			 * Bit position 31 == 0 => class A.
Packit 8480eb
			 * Bit position 30 == 0 => class B.
Packit 8480eb
			 * Bit position 29 == 0 => class C.
Packit 8480eb
			 */
Packit 8480eb
Packit 8480eb
			if (!getbits(ia, 31, 1))
Packit 8480eb
				mask = MASK_A;
Packit 8480eb
			else if (!getbits(ia, 30, 1))
Packit 8480eb
				mask = MASK_B;
Packit 8480eb
			else if (!getbits(ia, 29, 1))
Packit 8480eb
				mask = MASK_C;
Packit 8480eb
			else
Packit 8480eb
				break;
Packit 8480eb
Packit 8480eb
			if ((ia & mask) == (ha & mask)) {
Packit 8480eb
				freeifaddrs(ifa);
Packit 8480eb
				return PROXIMITY_NET;
Packit 8480eb
			}
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case AF_INET6:
Packit 8480eb
#ifdef WITH_LIBTIRPC
Packit 8480eb
			if (host_addr->sa_family == AF_INET)
Packit 8480eb
				break;
Packit 8480eb
			if6_addr = (struct sockaddr_in6 *) this->ifa_addr;
Packit 8480eb
			ia6 = &if6_addr->sin6_addr.s6_addr32[0];
Packit 8480eb
Packit 8480eb
			/* Is the address within the network of the interface */
Packit 8480eb
Packit 8480eb
			msk6_addr = (struct sockaddr_in6 *) this->ifa_netmask;
Packit 8480eb
			mask6 = &msk6_addr->sin6_addr.s6_addr32[0];
Packit 8480eb
Packit 8480eb
			if (ipv6_mask_cmp(ha6, ia6, mask6)) {
Packit 8480eb
				freeifaddrs(ifa);
Packit 8480eb
				return PROXIMITY_SUBNET;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			/* How do we define "local network" in ipv6? */
Packit 8480eb
#endif
Packit 8480eb
		default:
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
		this = this->ifa_next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	freeifaddrs(ifa);
Packit 8480eb
Packit 8480eb
	return PROXIMITY_OTHER;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static char *inet_fill_net(const char *net_num, char *net)
Packit 8480eb
{
Packit 8480eb
	char *np;
Packit 8480eb
	int dots = 3;
Packit 8480eb
Packit 8480eb
	if (strlen(net_num) > INET_ADDRSTRLEN)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	if (!isdigit(*net_num))
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	*net = '\0';
Packit 8480eb
	strcpy(net, net_num);
Packit 8480eb
Packit 8480eb
	np = net;
Packit 8480eb
	while (*np++) {
Packit 8480eb
		if (*np == '.') {
Packit 8480eb
			np++;
Packit 8480eb
			dots--;
Packit 8480eb
			if (!*np && dots)
Packit 8480eb
				strcat(net, "0");
Packit 8480eb
			continue;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if ((*np && !isdigit(*np)) || dots < 0) {
Packit 8480eb
			*net = '\0';
Packit 8480eb
			return NULL;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	while (dots--)
Packit 8480eb
		strcat(net, ".0");
Packit 8480eb
Packit 8480eb
	return net;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static char *get_network_number(const char *network)
Packit 8480eb
{
Packit 8480eb
	struct netent *netent;
Packit 8480eb
	char cnet[MAX_NETWORK_LEN];
Packit 8480eb
	uint32_t h_net;
Packit 8480eb
	size_t len;
Packit 8480eb
Packit 8480eb
	len = strlen(network) + 1;
Packit 8480eb
	if (len > MAX_NETWORK_LEN)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	netent = getnetbyname(network);
Packit 8480eb
	if (!netent)
Packit 8480eb
		return NULL;
Packit 8480eb
	h_net = ntohl(netent->n_net);
Packit 8480eb
Packit 8480eb
	if (!inet_ntop(AF_INET, &h_net, cnet, INET_ADDRSTRLEN))
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	return strdup(cnet);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
unsigned int get_network_proximity(const char *name)
Packit 8480eb
{
Packit 8480eb
	struct addrinfo hints;
Packit 8480eb
	struct addrinfo *ni, *this;
Packit 8480eb
	char name_or_num[NI_MAXHOST + 1];
Packit 8480eb
	unsigned int proximity;
Packit 8480eb
	char *net;
Packit 8480eb
	int ret;
Packit 8480eb
Packit 8480eb
	if (!name)
Packit 8480eb
		return PROXIMITY_ERROR;
Packit 8480eb
Packit 8480eb
	net = get_network_number(name);
Packit 8480eb
	if (net) {
Packit 8480eb
		strcpy(name_or_num, net);
Packit 8480eb
		free(net);
Packit 8480eb
	} else {
Packit 8480eb
		char this[NI_MAXHOST + 1];
Packit 8480eb
		char *mask;
Packit 8480eb
Packit 8480eb
		if (strlen(name) > NI_MAXHOST)
Packit 8480eb
			return PROXIMITY_ERROR;
Packit 8480eb
		strcpy(this, name);
Packit 8480eb
		if ((mask = strchr(this, '/')))
Packit 8480eb
			*mask++ = '\0';
Packit 8480eb
		if (!strchr(this, '.'))
Packit 8480eb
			strcpy(name_or_num, this);
Packit 8480eb
		else {
Packit 8480eb
			char buf[NI_MAXHOST + 1], *new;
Packit 8480eb
			new = inet_fill_net(this, buf);
Packit 8480eb
			if (!new)
Packit 8480eb
				return PROXIMITY_ERROR;
Packit 8480eb
			strcpy(name_or_num, new);
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	memset(&hints, 0, sizeof(struct addrinfo));
Packit 8480eb
	hints.ai_family = AF_UNSPEC;
Packit 8480eb
	hints.ai_socktype = SOCK_DGRAM;
Packit 8480eb
	hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME;
Packit 8480eb
Packit Bot 7224e5
	ni = NULL;
Packit 8480eb
	ret = getaddrinfo(name_or_num, NULL, &hints, &ni);
Packit 8480eb
	if (ret) {
Packit Bot 3dabcc
		logerr("hostname lookup for %s failed: %s",
Packit Bot 3dabcc
		       name_or_num, gai_strerror(ret));
Packit 8480eb
		return PROXIMITY_ERROR;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	proximity = PROXIMITY_OTHER;
Packit 8480eb
Packit 8480eb
	this = ni;
Packit 8480eb
	while (this) {
Packit 8480eb
		unsigned int prx = get_proximity(this->ai_addr);
Packit 8480eb
		if (prx < proximity)
Packit 8480eb
			proximity = prx;
Packit 8480eb
		this = this->ai_next;
Packit 8480eb
	}
Packit 8480eb
	freeaddrinfo(ni);
Packit 8480eb
Packit 8480eb
	return proximity;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
unsigned int in_network(char *network)
Packit 8480eb
{
Packit 8480eb
	unsigned int proximity = get_network_proximity(network);
Packit 8480eb
	if (proximity == PROXIMITY_ERROR ||
Packit 8480eb
	    proximity > PROXIMITY_SUBNET)
Packit 8480eb
		return 0;
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
struct mapent *match_cached_key(struct autofs_point *ap,
Packit 8480eb
				const char *err_prefix,
Packit 8480eb
				struct map_source *source,
Packit 8480eb
				const char *key)
Packit 8480eb
{
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	struct mapent_cache *mc;
Packit 8480eb
	struct mapent *me;
Packit 8480eb
Packit 8480eb
	mc = source->mc;
Packit 8480eb
Packit 8480eb
	if (!(source->flags & MAP_FLAG_FORMAT_AMD)) {
Packit 8480eb
		int ret;
Packit 8480eb
Packit 8480eb
		me = cache_lookup(mc, key);
Packit 8480eb
		/*
Packit 8480eb
		 * Stale mapent => check for entry in alternate source or
Packit 8480eb
		 * wildcard. Note, plus included direct mount map entries
Packit 8480eb
		 * are included as an instance (same map entry cache), not
Packit 8480eb
		 * in a distinct source.
Packit 8480eb
		 */
Packit 8480eb
		if (me && (!me->mapent ||
Packit 8480eb
		   (me->source != source && *me->key != '/'))) {
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
Packit 8480eb
		if (!me)
Packit 8480eb
			goto done;
Packit 8480eb
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->flags & MOUNT_FLAG_REMOUNT) &&
Packit 8480eb
		    ap->type == LKP_INDIRECT && *me->key == '*') {
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
	} else {
Packit 8480eb
		char *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, "%s strdup: %s", err_prefix, estr);
Packit 8480eb
			return NULL;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		/* If it's found we're done */
Packit 8480eb
		me = cache_lookup_distinct(mc, lkp_key);
Packit 8480eb
		if (me)
Packit 8480eb
			goto free;
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * Otherwise strip successive directory components and try
Packit 8480eb
		 * a match against map entries ending with a wildcard and
Packit 8480eb
		 * finally try the wilcard entry itself.
Packit 8480eb
		*/
Packit 8480eb
		while (!me) {
Packit 8480eb
			char *prefix;
Packit 8480eb
Packit 8480eb
			while ((prefix = strrchr(lkp_key, '/'))) {
Packit 8480eb
				*prefix = '\0';
Packit 8480eb
				me = cache_partial_match_wild(mc, lkp_key);
Packit 8480eb
				if (me)
Packit 8480eb
					goto free;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			me = cache_lookup_distinct(mc, "*");
Packit 8480eb
			if (me)
Packit 8480eb
				goto free;
Packit 8480eb
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
free:
Packit 8480eb
		free(lkp_key);
Packit 8480eb
	}
Packit 8480eb
done:
Packit 8480eb
	return me;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Skip whitespace in a string; if we hit a #, consider the rest of the
Packit 8480eb
 * entry a comment.
Packit 8480eb
 */
Packit 8480eb
const char *skipspace(const char *whence)
Packit 8480eb
{
Packit 8480eb
	while (1) {
Packit 8480eb
		switch (*whence) {
Packit 8480eb
		case ' ':
Packit 8480eb
		case '\b':
Packit 8480eb
		case '\t':
Packit 8480eb
		case '\n':
Packit 8480eb
		case '\v':
Packit 8480eb
		case '\f':
Packit 8480eb
		case '\r':
Packit 8480eb
			whence++;
Packit 8480eb
			break;
Packit 8480eb
		case '#':	/* comment: skip to end of string */
Packit 8480eb
			while (*whence != '\0')
Packit 8480eb
				whence++;
Packit 8480eb
			/* FALLTHROUGH */
Packit 8480eb
Packit 8480eb
		default:
Packit 8480eb
			return whence;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Check a string to see if a colon appears before the next '/'.
Packit 8480eb
 */
Packit 8480eb
int check_colon(const char *str)
Packit 8480eb
{
Packit 8480eb
	char *ptr = (char *) str;
Packit 8480eb
Packit 8480eb
	/* Colon escape */
Packit 8480eb
	if (!strncmp(ptr, ":/", 2))
Packit 8480eb
		return 1;
Packit 8480eb
Packit 8480eb
	while (*ptr && strncmp(ptr, ":/", 2))
Packit 8480eb
		ptr++;
Packit 8480eb
Packit 8480eb
	if (!*ptr)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	return 1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Get the length of a chunk delimitered by whitespace */
Packit 8480eb
int chunklen(const char *whence, int expect_colon)
Packit 8480eb
{
Packit 8480eb
	char *str = (char *) whence;
Packit 8480eb
	int n = 0;
Packit 8480eb
	int quote = 0;
Packit 8480eb
Packit 8480eb
	for (; *str; str++, n++) {
Packit 8480eb
		switch (*str) {
Packit 8480eb
		case '\\':
Packit 8480eb
			if( quote ) {
Packit 8480eb
				break;
Packit 8480eb
			} else {
Packit 8480eb
				quote = 1;
Packit 8480eb
				continue;
Packit 8480eb
			}
Packit 8480eb
		case '"':
Packit 8480eb
			if (quote)
Packit 8480eb
				break;
Packit 8480eb
			while (*str) {
Packit 8480eb
				str++;
Packit 8480eb
				n++;
Packit 8480eb
				if (*str == '"')
Packit 8480eb
					break;
Packit 8480eb
				if (!strncmp(str, ":/", 2))
Packit 8480eb
					expect_colon = 0;
Packit 8480eb
			}
Packit 8480eb
			break;
Packit 8480eb
		case ':':
Packit 8480eb
			if (expect_colon && !strncmp(str, ":/", 2))
Packit 8480eb
				expect_colon = 0;
Packit 8480eb
			continue;
Packit 8480eb
		case ' ':
Packit 8480eb
		case '\t':
Packit 8480eb
			/* Skip space or tab if we expect a colon */
Packit 8480eb
			if (expect_colon)
Packit 8480eb
				continue;
Packit 8480eb
		case '\b':
Packit 8480eb
		case '\n':
Packit 8480eb
		case '\v':
Packit 8480eb
		case '\f':
Packit 8480eb
		case '\r':
Packit 8480eb
		case '\0':
Packit 8480eb
			if (!quote)
Packit 8480eb
				return n;
Packit 8480eb
			/* FALLTHROUGH */
Packit 8480eb
		default:
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
		quote = 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return n;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Compare str with pat.  Return 0 if compare equal or
Packit 8480eb
 * str is an abbreviation of pat of no less than mchr characters.
Packit 8480eb
 */
Packit 8480eb
int strmcmp(const char *str, const char *pat, int mchr)
Packit 8480eb
{
Packit 8480eb
	int nchr = 0;
Packit 8480eb
Packit 8480eb
	while (*str == *pat) {
Packit 8480eb
		if (!*str)
Packit 8480eb
			return 0;
Packit 8480eb
		str++;
Packit 8480eb
		pat++;
Packit 8480eb
		nchr++;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!*str && nchr > mchr)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	return *pat - *str;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
char *dequote(const char *str, int origlen, unsigned int logopt)
Packit 8480eb
{
Packit 8480eb
	char *ret = malloc(origlen + 1);
Packit 8480eb
	char *cp = ret;
Packit 8480eb
	const char *scp;
Packit 8480eb
	int len = origlen;
Packit 8480eb
	int quote = 0, dquote = 0;
Packit 8480eb
	int i, j;
Packit 8480eb
Packit 8480eb
	if (ret == NULL)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	/* first thing to do is strip white space from the end */
Packit 8480eb
	i = len - 1;
Packit 8480eb
	while (isspace(str[i])) {
Packit 8480eb
		/* of course, we have to keep escaped white-space */
Packit 8480eb
		j = i - 1;
Packit 8480eb
		if (j > 0 && (str[j] == '\\' || str[j] == '"'))
Packit 8480eb
			break;
Packit 8480eb
		i--;
Packit 8480eb
		len--;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	for (scp = str; len > 0 && *scp; scp++, len--) {
Packit 8480eb
		if (!quote) {
Packit 8480eb
			if (*scp == '"') {
Packit 8480eb
				if (dquote)
Packit 8480eb
					dquote = 0;
Packit 8480eb
				else
Packit 8480eb
					dquote = 1;
Packit 8480eb
				continue;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			if (!dquote) {
Packit 8480eb
				if (*scp == '\\') {
Packit 8480eb
					quote = 1;
Packit 8480eb
					continue;
Packit 8480eb
				}
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
		quote = 0;
Packit 8480eb
		*cp++ = *scp;
Packit 8480eb
	}
Packit 8480eb
	*cp = '\0';
Packit 8480eb
Packit 8480eb
	if (dquote) {
Packit 8480eb
		debug(logopt, "unmatched quote in %.*s", origlen, str);
Packit 8480eb
		free(ret);
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int span_space(const char *str, unsigned int maxlen)
Packit 8480eb
{
Packit 8480eb
	const char *p = str;
Packit 8480eb
	unsigned int len = 0;
Packit 8480eb
Packit 8480eb
	while (*p && !isblank(*p) && len < maxlen) {
Packit 8480eb
		if (*p == '"') {
Packit 8480eb
			while (*p++ && len++ < maxlen) {
Packit 8480eb
				if (*p == '"')
Packit 8480eb
					break;
Packit 8480eb
			}
Packit 8480eb
		} else if (*p == '\\') {
Packit 8480eb
			p += 2;
Packit 8480eb
			len += 2;
Packit 8480eb
			continue;
Packit 8480eb
		}
Packit 8480eb
		p++;
Packit 8480eb
		len++;
Packit 8480eb
	}
Packit 8480eb
	return len;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
char *sanitize_path(const char *path, int origlen, unsigned int type, unsigned int logopt)
Packit 8480eb
{
Packit 8480eb
	char *slash, *cp, *s_path;
Packit 8480eb
	const char *scp;
Packit 8480eb
	int len = origlen;
Packit 8480eb
	unsigned int seen_slash = 0, quote = 0, dquote = 0;
Packit 8480eb
Packit 8480eb
	if (type & (LKP_INDIRECT | LKP_DIRECT)) {
Packit 8480eb
		const char *tmp = path;
Packit 8480eb
Packit 8480eb
		if (*tmp == '"')
Packit 8480eb
			tmp++;
Packit 8480eb
		slash = strchr(tmp, '/');
Packit 8480eb
		if (slash) {
Packit 8480eb
			if (type == LKP_INDIRECT)
Packit 8480eb
				return NULL;
Packit 8480eb
			if (*tmp != '/')
Packit 8480eb
				return NULL;
Packit 8480eb
		} else {
Packit 8480eb
			if (type == LKP_DIRECT)
Packit 8480eb
				return NULL;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	s_path = malloc(origlen + 1);
Packit 8480eb
	if (!s_path)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	for (cp = s_path, scp = path; len > 0; scp++, len--) {
Packit 8480eb
		if (!quote) {
Packit 8480eb
			if (*scp == '"') {
Packit 8480eb
				if (dquote)
Packit 8480eb
					dquote = 0;
Packit 8480eb
				else
Packit 8480eb
					dquote = 1;
Packit 8480eb
				continue;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			if (!dquote) {
Packit 8480eb
				/* Badness in string - go away */
Packit 8480eb
				if (*scp < 32) {
Packit 8480eb
					free(s_path);
Packit 8480eb
					return NULL;
Packit 8480eb
				}
Packit 8480eb
Packit 8480eb
				if (*scp == '\\') {
Packit 8480eb
					quote = 1;
Packit 8480eb
					continue;
Packit 8480eb
				} 
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			/*
Packit 8480eb
			 * Not really proper but we get problems with
Packit 8480eb
			 * paths with multiple slashes. The kernel
Packit 8480eb
			 * compresses them so when we get a query there
Packit 8480eb
			 * should be only single slashes.
Packit 8480eb
			 */
Packit 8480eb
			if (*scp == '/') {
Packit 8480eb
				if (seen_slash)
Packit 8480eb
					continue;
Packit 8480eb
				seen_slash = 1;
Packit 8480eb
			} else
Packit 8480eb
				seen_slash = 0;
Packit 8480eb
		}
Packit 8480eb
		quote = 0;
Packit 8480eb
		*cp++ = *scp;
Packit 8480eb
	}
Packit 8480eb
	*cp = '\0';
Packit 8480eb
Packit 8480eb
	if (dquote) {
Packit 8480eb
		debug(logopt, "unmatched quote in %.*s", origlen, path);
Packit 8480eb
		free(s_path);
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Remove trailing / but watch out for a quoted / alone */
Packit 8480eb
	if (strlen(cp) > 1 && origlen > 1 && *(cp - 1) == '/')
Packit 8480eb
		*(cp - 1) = '\0';
Packit 8480eb
Packit 8480eb
	return s_path;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static char *hasopt(const char *str, const char *opt)
Packit 8480eb
{
Packit 8480eb
	const size_t optlen = strlen(opt);
Packit 8480eb
	char *rest = (char *) str, *p;
Packit 8480eb
Packit 8480eb
	while ((p = strstr(rest, opt)) != NULL) {
Packit 8480eb
		if ((p == rest || p[-1] == ',') &&
Packit 8480eb
		    (p[optlen] == '\0' || p[optlen] == '=' ||
Packit 8480eb
		     p[optlen] == ','))
Packit 8480eb
			return p;
Packit 8480eb
Packit 8480eb
		rest = strchr (p, ',');
Packit 8480eb
		if (rest == NULL)
Packit 8480eb
			break;
Packit 8480eb
		++rest;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return NULL;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
char *merge_options(const char *opt1, const char *opt2)
Packit 8480eb
{
Packit 8480eb
	char str[MAX_OPTIONS_LEN + 1];
Packit 8480eb
	char result[MAX_OPTIONS_LEN + 1];
Packit 8480eb
	char neg[MAX_OPTION_LEN + 1];
Packit 8480eb
	char *tok, *ptr = NULL;
Packit 8480eb
	size_t resultlen, len;
Packit 8480eb
Packit 8480eb
	if ((!opt1 || !*opt1) && (!opt2 || !*opt2))
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	if (!opt2 || !*opt2) {
Packit 8480eb
		if (!*opt1)
Packit 8480eb
			return NULL;
Packit 8480eb
		return strdup(opt1);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!opt1 || !*opt1) {
Packit 8480eb
		if (!*opt2)
Packit 8480eb
			return NULL;
Packit 8480eb
		return strdup(opt2);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (!strcmp(opt1, opt2))
Packit 8480eb
		return strdup(opt1);
Packit 8480eb
Packit 8480eb
	if (strlen(str) > MAX_OPTIONS_LEN)
Packit 8480eb
		return NULL;
Packit 8480eb
	memset(result, 0, sizeof(result));
Packit 8480eb
	strcpy(str, opt1);
Packit 8480eb
Packit 8480eb
	resultlen = 0;
Packit 8480eb
	tok = strtok_r(str, ",", &ptr);
Packit 8480eb
	while (tok) {
Packit 8480eb
		const char *this = (const char *) tok;
Packit 8480eb
		char *eq = strchr(this, '=');
Packit 8480eb
		if (eq) {
Packit 8480eb
			*eq = '\0';
Packit 8480eb
			if (!hasopt(opt2, this)) {
Packit 8480eb
				if (resultlen + strlen(this) > MAX_OPTIONS_LEN)
Packit 8480eb
					return NULL;
Packit 8480eb
				*eq = '=';
Packit 8480eb
				if (!*result)
Packit 8480eb
					strcpy(result, this);
Packit 8480eb
				else
Packit 8480eb
					strcat(result, this);
Packit 8480eb
				strcat(result, ",");
Packit 8480eb
				resultlen += strlen(this) + 1;
Packit 8480eb
				goto next;
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (!strcmp(this, "rw") && hasopt(opt2, "ro"))
Packit 8480eb
			goto next;
Packit 8480eb
		if (!strcmp(this, "ro") && hasopt(opt2, "rw"))
Packit 8480eb
			goto next;
Packit 8480eb
		if (!strcmp(this, "bg") && hasopt(opt2, "fg"))
Packit 8480eb
			goto next;
Packit 8480eb
		if (!strcmp(this, "fg") && hasopt(opt2, "bg"))
Packit 8480eb
			goto next;
Packit 8480eb
		if (!strcmp(this, "bg") && hasopt(opt2, "fg"))
Packit 8480eb
			goto next;
Packit 8480eb
		if (!strcmp(this, "soft") && hasopt(opt2, "hard"))
Packit 8480eb
			goto next;
Packit 8480eb
		if (!strcmp(this, "hard") && hasopt(opt2, "soft"))
Packit 8480eb
			goto next;
Packit 8480eb
Packit 8480eb
		if (!strncmp(this, "no", 2)) {
Packit 8480eb
			if (strlen(this + 2) > MAX_OPTION_LEN)
Packit 8480eb
				return NULL;
Packit 8480eb
			strcpy(neg, this + 2);
Packit 8480eb
			if (hasopt(opt2, neg))
Packit 8480eb
				goto next;
Packit 8480eb
		} else {
Packit 8480eb
			if ((strlen(this) + 2) > MAX_OPTION_LEN)
Packit 8480eb
				return NULL;
Packit 8480eb
			strcpy(neg, "no");
Packit 8480eb
			strcat(neg, this);
Packit 8480eb
			if (hasopt(opt2, neg))
Packit 8480eb
				goto next;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (hasopt(opt2, tok))
Packit 8480eb
			goto next;
Packit 8480eb
Packit 8480eb
		if (resultlen + strlen(this) + 1 > MAX_OPTIONS_LEN)
Packit 8480eb
			return NULL;
Packit 8480eb
Packit 8480eb
		if (!*result)
Packit 8480eb
			strcpy(result, this);
Packit 8480eb
		else
Packit 8480eb
			strcat(result, this);
Packit 8480eb
		strcat(result, ",");
Packit 8480eb
		resultlen =+ strlen(this) + 1;
Packit 8480eb
next:
Packit 8480eb
		tok = strtok_r(NULL, ",", &ptr);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (resultlen + strlen(opt2) > MAX_OPTIONS_LEN)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	if (!*result)
Packit 8480eb
		strcpy(result, opt2);
Packit 8480eb
	else
Packit 8480eb
		strcat(result, opt2);
Packit 8480eb
Packit 8480eb
	len = strlen(result);
Packit 8480eb
	if (len && result[len - 1] == ',')
Packit 8480eb
		result[len - 1] = '\0';
Packit 8480eb
Packit 8480eb
	return strdup(result);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static char *expand_slash_or_dot(char *str, unsigned int type)
Packit 8480eb
{
Packit 8480eb
	char *val = NULL;
Packit 8480eb
Packit 8480eb
	if (!str)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	if (!type)
Packit 8480eb
		return str;
Packit 8480eb
Packit 8480eb
	if (type & EXPAND_LEADING_SLASH)
Packit 8480eb
		val = basename(str);
Packit 8480eb
	else if (type & EXPAND_TRAILING_SLASH)
Packit 8480eb
		val = dirname(str);
Packit 8480eb
	else if (type & (EXPAND_LEADING_DOT | EXPAND_TRAILING_DOT)) {
Packit 8480eb
		char *dot = strchr(str, '.');
Packit 8480eb
		if (dot)
Packit 8480eb
			*dot++ = '\0';
Packit 8480eb
		if (type & EXPAND_LEADING_DOT)
Packit 8480eb
			val = dot;
Packit 8480eb
		else
Packit 8480eb
			val = str;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return val;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * $-expand an amd-style map entry and return the length of the entry.
Packit 8480eb
 * If "dst" is NULL, just count the length.
Packit 8480eb
 */
Packit 8480eb
int expandamdent(const char *src, char *dst, const struct substvar *svc)
Packit 8480eb
{
Packit 8480eb
	unsigned int flags = conf_amd_get_flags(NULL);
Packit 8480eb
	const struct substvar *sv;
Packit 8480eb
	const char *o_src = src;
Packit 8480eb
	unsigned int squote = 0;
Packit 8480eb
	int len, l;
Packit 8480eb
	const char *p;
Packit 8480eb
	char ch;
Packit 8480eb
Packit 8480eb
	len = 0;
Packit 8480eb
Packit 8480eb
	while ((ch = *src++)) {
Packit 8480eb
		switch (ch) {
Packit 8480eb
		case '$':
Packit 8480eb
			if (*src == '{') {
Packit 8480eb
				char *start, *end;
Packit 8480eb
				unsigned int type = 0;
Packit 8480eb
				p = strchr(++src, '}');
Packit 8480eb
				if (!p) {
Packit 8480eb
					/* Ignore rest of string */
Packit 8480eb
					if (dst)
Packit 8480eb
						*dst = '\0';
Packit 8480eb
					return len;
Packit 8480eb
				}
Packit 8480eb
				start = (char *) src;
Packit 8480eb
				if (*src == '/' || *src == '.') {
Packit 8480eb
					start++;
Packit 8480eb
					type = EXPAND_LEADING_SLASH;
Packit 8480eb
					if (*src == '.')
Packit 8480eb
						type = EXPAND_LEADING_DOT;
Packit 8480eb
				}
Packit 8480eb
				end = (char *) p;
Packit 8480eb
				if (*(p - 1) == '/' || *(p - 1) == '.') {
Packit 8480eb
					end--;
Packit 8480eb
					type = EXPAND_TRAILING_SLASH;
Packit 8480eb
					if (*(p - 1) == '.')
Packit 8480eb
						type = EXPAND_TRAILING_DOT;
Packit 8480eb
				}
Packit 8480eb
				sv = macro_findvar(svc, start, end - start);
Packit 8480eb
				if (sv) {
Packit 8480eb
					char *val;
Packit 8480eb
					char *str = strdup(sv->val);
Packit 8480eb
					val = expand_slash_or_dot(str, type);
Packit 8480eb
					if (!val)
Packit 8480eb
						val = sv->val;
Packit 8480eb
					l = strlen(val);
Packit 8480eb
					if (dst) {
Packit 8480eb
						if (*dst)
Packit 8480eb
							strcat(dst, val);
Packit 8480eb
						else
Packit 8480eb
							strcpy(dst, val);
Packit 8480eb
						dst += l;
Packit 8480eb
					}
Packit 8480eb
					len += l;
Packit 8480eb
					if (str)
Packit 8480eb
						free(str);
Packit 8480eb
				} else {
Packit 8480eb
					if (dst) {
Packit 8480eb
						*dst++ = ch;
Packit 8480eb
						*dst++ = '{';
Packit 8480eb
						strncat(dst, src, p - src);
Packit 8480eb
						dst += (p - src);
Packit 8480eb
						*dst++ = '}';
Packit 8480eb
					}
Packit 8480eb
					len += 1 + 1 + (p - src) + 1;
Packit 8480eb
				}
Packit 8480eb
				src = p + 1;
Packit 8480eb
			} else {
Packit 8480eb
				if (dst)
Packit 8480eb
					*(dst++) = ch;
Packit 8480eb
				len++;
Packit 8480eb
			}
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case '\\':
Packit 8480eb
			if (squote || !(flags & CONF_NORMALIZE_SLASHES)) {
Packit 8480eb
				len++;
Packit 8480eb
				if (dst)
Packit 8480eb
					*dst++ = ch;
Packit 8480eb
				break;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			if (*src) {
Packit 8480eb
				len++;
Packit 8480eb
				if (dst)
Packit 8480eb
					*dst++ = *src;
Packit 8480eb
				src++;
Packit 8480eb
			}
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		case '/':
Packit 8480eb
			len++;
Packit 8480eb
			if (dst)
Packit 8480eb
				*dst++ = ch;
Packit 8480eb
Packit 8480eb
			if (squote || !(flags & CONF_NORMALIZE_SLASHES))
Packit 8480eb
				break;
Packit 8480eb
Packit 8480eb
			/* Double slash at start is allowed */
Packit 8480eb
			if (src == (o_src + 1) && *src == '/') {
Packit 8480eb
				len++;
Packit 8480eb
				if (dst)
Packit 8480eb
					*dst++ = *src;
Packit 8480eb
				src++;
Packit 8480eb
			}
Packit 8480eb
			while (*src == '/')
Packit 8480eb
				src++;
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		/* 39 is single quote */
Packit 8480eb
		case 39:
Packit 8480eb
			len++;
Packit 8480eb
			if (dst)
Packit 8480eb
				*dst++ = ch;
Packit 8480eb
			squote = !squote;
Packit 8480eb
			break;
Packit 8480eb
Packit 8480eb
		default:
Packit 8480eb
			if (dst)
Packit 8480eb
				*(dst++) = ch;
Packit 8480eb
			len++;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	if (dst)
Packit 8480eb
		*dst = '\0';
Packit 8480eb
Packit 8480eb
	return len;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int expand_selectors(struct autofs_point *ap,
Packit 8480eb
		     const char *mapstr, char **pmapstr,
Packit 8480eb
		     struct substvar *sv)
Packit 8480eb
{
Packit 8480eb
	char buf[MAX_ERR_BUF];
Packit 8480eb
	char *expand;
Packit 8480eb
	size_t len;
Packit 8480eb
Packit 8480eb
	if (!mapstr)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	len = expandamdent(mapstr, NULL, sv);
Packit 8480eb
	if (len == 0) {
Packit 8480eb
		error(ap->logopt, "failed to expand map entry");
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	expand = malloc(len + 1);
Packit 8480eb
	if (!expand) {
Packit 8480eb
		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		error(ap->logopt, "malloc: %s", estr);
Packit 8480eb
		return 0;
Packit 8480eb
	}
Packit 8480eb
	memset(expand, 0, len + 1);
Packit 8480eb
Packit 8480eb
	expandamdent(mapstr, expand, sv);
Packit 8480eb
Packit 8480eb
	*pmapstr = expand;
Packit 8480eb
Packit 8480eb
	return len;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Get next space seperated argument, arguments containing
Packit 8480eb
 * space characters may be single quoted.
Packit 8480eb
 */
Packit 8480eb
static char *next_arg(char *str, char **next)
Packit 8480eb
{
Packit 8480eb
	char *start;
Packit 8480eb
	char *ptr;
Packit 8480eb
Packit 8480eb
	if (!*str)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	start = ptr = str;
Packit 8480eb
Packit 8480eb
	/* The amd map format parser should ensure there
Packit 8480eb
	 * are matching single quotes.
Packit 8480eb
	 */
Packit 8480eb
	if (*start == 39) {
Packit 8480eb
		start++;
Packit 8480eb
		ptr++;
Packit 8480eb
		while (*ptr && *ptr != 39)
Packit 8480eb
			ptr++;
Packit 8480eb
	} else {
Packit 8480eb
		while (*ptr && *ptr != ' ')
Packit 8480eb
			ptr++;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (*ptr)
Packit 8480eb
		*ptr++ = 0;
Packit 8480eb
	*next = ptr;
Packit 8480eb
Packit 8480eb
	return start;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Construct program path name plus argument array for use with
Packit 8480eb
 * execv(3).
Packit 8480eb
 */
Packit 8480eb
int construct_argv(char *str, char **prog, char ***argv)
Packit 8480eb
{
Packit 8480eb
	char *program = NULL;
Packit 8480eb
	char *start, *next;
Packit 8480eb
	char **args, *arg;
Packit 8480eb
	int argc;
Packit 8480eb
Packit 8480eb
	start = str;
Packit 8480eb
Packit 8480eb
	args = malloc(sizeof(char *));
Packit 8480eb
	if (!args)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	args[0] = NULL;
Packit 8480eb
	argc = 0;
Packit 8480eb
Packit 8480eb
	next = NULL;
Packit 8480eb
	program = next_arg(str, &next;;
Packit 8480eb
	if (!program) {
Packit 8480eb
		free(args);
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	start = next;
Packit 8480eb
Packit 8480eb
	while (1) {
Packit 8480eb
		if (!*next)
Packit 8480eb
			break;
Packit 8480eb
		arg = next_arg(start, &next;;
Packit 8480eb
		if (arg) {
Packit 8480eb
			argc++;
Packit 8480eb
			args = add_argv(argc, args, arg);
Packit 8480eb
			if (!args)
Packit 8480eb
				return -1;
Packit 8480eb
		}
Packit 8480eb
		start = next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	*prog = program;
Packit 8480eb
	*argv = args;
Packit 8480eb
Packit 8480eb
	return argc;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void free_map_type_info(struct map_type_info *info)
Packit 8480eb
{
Packit 8480eb
	if (info->type)
Packit 8480eb
		free(info->type);
Packit 8480eb
	if (info->format)
Packit 8480eb
		free(info->format);
Packit 8480eb
	if (info->map)
Packit 8480eb
		free(info->map);
Packit 8480eb
	free(info);
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
struct map_type_info *parse_map_type_info(const char *str)
Packit 8480eb
{
Packit 8480eb
	struct map_type_info *info;
Packit 8480eb
	char *buf, *type, *fmt, *map, *tmp;
Packit 8480eb
	char *pos;
Packit 8480eb
Packit 8480eb
	buf = strdup(str);
Packit 8480eb
	if (!buf)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	info = malloc(sizeof(struct map_type_info));
Packit 8480eb
	if (!info) {
Packit 8480eb
		free(buf);
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
	memset(info, 0, sizeof(struct map_type_info));
Packit 8480eb
Packit 8480eb
	type = fmt = map = NULL;
Packit 8480eb
Packit 8480eb
	tmp = strchr(buf, ':');
Packit 8480eb
	if (!tmp) {
Packit 8480eb
		pos = buf;
Packit 8480eb
		while (*pos == ' ')
Packit 8480eb
			*pos++ = '\0';
Packit 8480eb
		map = pos;
Packit 8480eb
	} else {
Packit 8480eb
		int i, j;
Packit 8480eb
Packit 8480eb
		for (i = 0; i < map_type_count; i++) {
Packit 8480eb
			char *m_type = map_type[i].type;
Packit 8480eb
			unsigned int m_len = map_type[i].len;
Packit 8480eb
Packit 8480eb
			pos = buf;
Packit 8480eb
Packit 8480eb
			if (strncmp(m_type, pos, m_len))
Packit 8480eb
				continue;
Packit 8480eb
Packit 8480eb
			type = pos;
Packit 8480eb
			pos += m_len;
Packit 8480eb
Packit 8480eb
			if (*pos == ' ' || *pos == ':') {
Packit 8480eb
				while (*pos == ' ')
Packit 8480eb
					*pos++ = '\0';
Packit 8480eb
				if (*pos != ':') {
Packit 8480eb
					free(buf);
Packit 8480eb
					free(info);
Packit 8480eb
					return NULL;
Packit 8480eb
				} else {
Packit 8480eb
					*pos++ = '\0';
Packit 8480eb
					while (*pos && *pos == ' ')
Packit 8480eb
						*pos++ = '\0';
Packit 8480eb
					map = pos;
Packit 8480eb
					break;
Packit 8480eb
				}
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			if (*pos == ',') {
Packit 8480eb
				*pos++ = '\0';
Packit 8480eb
				for (j = 0; j < format_type_count; j++) {
Packit 8480eb
					char *f_type = format_type[j].type;
Packit 8480eb
					unsigned int f_len = format_type[j].len;
Packit 8480eb
				
Packit 8480eb
					if (strncmp(f_type, pos, f_len))
Packit 8480eb
						continue;
Packit 8480eb
Packit 8480eb
					fmt = pos;
Packit 8480eb
					pos += f_len;
Packit 8480eb
Packit 8480eb
					if (*pos == ' ' || *pos == ':') {
Packit 8480eb
						while (*pos == ' ')
Packit 8480eb
							*pos++ = '\0';
Packit 8480eb
						if (*pos != ':') {
Packit 8480eb
							free(buf);
Packit 8480eb
							free(info);
Packit 8480eb
							return NULL;
Packit 8480eb
						} else {
Packit 8480eb
							*pos++ = '\0';
Packit 8480eb
							while (*pos && *pos == ' ')
Packit 8480eb
								*pos++ = '\0';
Packit 8480eb
							map = pos;
Packit 8480eb
							break;
Packit 8480eb
						}
Packit 8480eb
					}
Packit 8480eb
				}
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		if (!type) {
Packit 8480eb
			pos = buf;
Packit 8480eb
			while (*pos == ' ')
Packit 8480eb
				*pos++ = '\0';
Packit 8480eb
			map = pos;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Look for space terminator - ignore local options */
Packit 8480eb
	for (tmp = buf; *tmp; tmp++) {
Packit 8480eb
		if (*tmp == ' ') {
Packit 8480eb
			*tmp = '\0';
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
		if (*tmp == '\\')
Packit 8480eb
			tmp++;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (type) {
Packit 8480eb
		info->type = strdup(type);
Packit 8480eb
		if (!info->type) {
Packit 8480eb
			free(buf);
Packit 8480eb
			free_map_type_info(info);
Packit 8480eb
			return NULL;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (fmt) {
Packit 8480eb
		info->format = strdup(fmt);
Packit 8480eb
		if (!info->format) {
Packit 8480eb
			free(buf);
Packit 8480eb
			free_map_type_info(info);
Packit 8480eb
			return NULL;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (map) {
Packit 8480eb
		info->map = strdup(map);
Packit 8480eb
		if (!info->map) {
Packit 8480eb
			free(buf);
Packit 8480eb
			free_map_type_info(info);
Packit 8480eb
			return NULL;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	free(buf);
Packit 8480eb
Packit 8480eb
	return info;
Packit 8480eb
}
Packit 8480eb