map.c revision 77349
138032Speter/*
273188Sgshapiro * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1992, 1995-1997 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1992, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1438032Speter#ifndef lint
1577349Sgshapirostatic char id[] = "@(#)$Id: map.c,v 8.414.4.53 2001/05/04 01:29:00 gshapiro Exp $";
1664562Sgshapiro#endif /* ! lint */
1738032Speter
1864562Sgshapiro#include <sendmail.h>
1938032Speter
2064562Sgshapiro
2138032Speter#ifdef NDBM
2238032Speter# include <ndbm.h>
2338032Speter# ifdef R_FIRST
2438032Speter  ERROR README:	You are running the Berkeley DB version of ndbm.h.  See
2538032Speter  ERROR README:	the README file about tweaking Berkeley DB so it can
2638032Speter  ERROR README:	coexist with NDBM, or delete -DNDBM from the Makefile
2738032Speter  ERROR README: and use -DNEWDB instead.
2864562Sgshapiro# endif /* R_FIRST */
2964562Sgshapiro#endif /* NDBM */
3038032Speter#ifdef NEWDB
3138032Speter# include <db.h>
3238032Speter# ifndef DB_VERSION_MAJOR
3338032Speter#  define DB_VERSION_MAJOR 1
3464562Sgshapiro# endif /* ! DB_VERSION_MAJOR */
3564562Sgshapiro#endif /* NEWDB */
3638032Speter#ifdef NIS
3738032Speter  struct dom_binding;	/* forward reference needed on IRIX */
3838032Speter# include <rpcsvc/ypclnt.h>
3938032Speter# ifdef NDBM
4038032Speter#  define NDBM_YP_COMPAT	/* create YP-compatible NDBM files */
4164562Sgshapiro# endif /* NDBM */
4264562Sgshapiro#endif /* NIS */
4338032Speter
4464562Sgshapiro#ifdef NEWDB
4564562Sgshapiro# if DB_VERSION_MAJOR < 2
4664562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
4764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
4864562Sgshapiro# if DB_VERSION_MAJOR == 2
4964562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
5064562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
5164562Sgshapiro# if DB_VERSION_MAJOR > 2
5264562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, void **));
5364562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
5464562Sgshapiro#endif /* NEWDB */
5573188Sgshapirostatic bool	extract_canonname __P((char *, char *, char *, char[], int));
5664562Sgshapiro#ifdef LDAPMAP
5764562Sgshapirostatic void	ldapmap_clear __P((LDAPMAP_STRUCT *));
5864562Sgshapirostatic STAB	*ldapmap_findconn __P((LDAPMAP_STRUCT *));
5964562Sgshapirostatic int	ldapmap_geterrno __P((LDAP *));
6064562Sgshapirostatic void	ldapmap_setopts __P((LDAP *, LDAPMAP_STRUCT *));
6164562Sgshapirostatic bool	ldapmap_start __P((MAP *));
6264562Sgshapirostatic void	ldaptimeout __P((int));
6364562Sgshapiro#endif /* LDAPMAP */
6464562Sgshapirostatic void	map_close __P((STAB *, int));
6564562Sgshapirostatic void	map_init __P((STAB *, int));
6664562Sgshapiro#ifdef NISPLUS
6764562Sgshapirostatic bool	nisplus_getcanonname __P((char *, int, int *));
6864562Sgshapiro#endif /* NISPLUS */
6964562Sgshapiro#ifdef NIS
7064562Sgshapirostatic bool	nis_getcanonname __P((char *, int, int *));
7164562Sgshapiro#endif /* NIS */
7264562Sgshapiro#if NETINFO
7364562Sgshapirostatic bool	ni_getcanonname __P((char *, int, int *));
7464562Sgshapiro#endif /* NETINFO */
7564562Sgshapirostatic bool	text_getcanonname __P((char *, int, int *));
7664562Sgshapiro
7738032Speter/*
7838032Speter**  MAP.C -- implementations for various map classes.
7938032Speter**
8038032Speter**	Each map class implements a series of functions:
8138032Speter**
8238032Speter**	bool map_parse(MAP *map, char *args)
8338032Speter**		Parse the arguments from the config file.  Return TRUE
8438032Speter**		if they were ok, FALSE otherwise.  Fill in map with the
8538032Speter**		values.
8638032Speter**
8738032Speter**	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
8838032Speter**		Look up the key in the given map.  If found, do any
8938032Speter**		rewriting the map wants (including "args" if desired)
9038032Speter**		and return the value.  Set *pstat to the appropriate status
9138032Speter**		on error and return NULL.  Args will be NULL if called
9238032Speter**		from the alias routines, although this should probably
9338032Speter**		not be relied upon.  It is suggested you call map_rewrite
9438032Speter**		to return the results -- it takes care of null termination
9538032Speter**		and uses a dynamically expanded buffer as needed.
9638032Speter**
9738032Speter**	void map_store(MAP *map, char *key, char *value)
9838032Speter**		Store the key:value pair in the map.
9938032Speter**
10038032Speter**	bool map_open(MAP *map, int mode)
10138032Speter**		Open the map for the indicated mode.  Mode should
10238032Speter**		be either O_RDONLY or O_RDWR.  Return TRUE if it
10338032Speter**		was opened successfully, FALSE otherwise.  If the open
10438032Speter**		failed an the MF_OPTIONAL flag is not set, it should
10538032Speter**		also print an error.  If the MF_ALIAS bit is set
10638032Speter**		and this map class understands the @:@ convention, it
10738032Speter**		should call aliaswait() before returning.
10838032Speter**
10938032Speter**	void map_close(MAP *map)
11038032Speter**		Close the map.
11138032Speter**
11238032Speter**	This file also includes the implementation for getcanonname.
11338032Speter**	It is currently implemented in a pretty ad-hoc manner; it ought
11438032Speter**	to be more properly integrated into the map structure.
11538032Speter*/
11638032Speter
11738032Speter#define DBMMODE		0644
11838032Speter
11938032Speter#ifndef EX_NOTFOUND
12038032Speter# define EX_NOTFOUND	EX_NOHOST
12164562Sgshapiro#endif /* ! EX_NOTFOUND */
12238032Speter
12338032Speter#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
12438032Speter# define LOCK_ON_OPEN	1	/* we can open/create a locked file */
12564562Sgshapiro#else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
12638032Speter# define LOCK_ON_OPEN	0	/* no such luck -- bend over backwards */
12764562Sgshapiro#endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
12838032Speter
12938032Speter#ifndef O_ACCMODE
13038032Speter# define O_ACCMODE	(O_RDONLY|O_WRONLY|O_RDWR)
13164562Sgshapiro#endif /* ! O_ACCMODE */
13238032Speter/*
13338032Speter**  MAP_PARSEARGS -- parse config line arguments for database lookup
13438032Speter**
13538032Speter**	This is a generic version of the map_parse method.
13638032Speter**
13738032Speter**	Parameters:
13838032Speter**		map -- the map being initialized.
13938032Speter**		ap -- a pointer to the args on the config line.
14038032Speter**
14138032Speter**	Returns:
14238032Speter**		TRUE -- if everything parsed OK.
14338032Speter**		FALSE -- otherwise.
14438032Speter**
14538032Speter**	Side Effects:
14638032Speter**		null terminates the filename; stores it in map
14738032Speter*/
14838032Speter
14938032Speterbool
15038032Spetermap_parseargs(map, ap)
15138032Speter	MAP *map;
15238032Speter	char *ap;
15338032Speter{
15438032Speter	register char *p = ap;
15538032Speter
15664562Sgshapiro	/*
15764562Sgshapiro	**  there is no check whether there is really an argument,
15864562Sgshapiro	**  but that's not important enough to warrant extra code
15964562Sgshapiro	*/
16038032Speter	map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
16164562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
16238032Speter	for (;;)
16338032Speter	{
16438032Speter		while (isascii(*p) && isspace(*p))
16538032Speter			p++;
16638032Speter		if (*p != '-')
16738032Speter			break;
16838032Speter		switch (*++p)
16938032Speter		{
17038032Speter		  case 'N':
17138032Speter			map->map_mflags |= MF_INCLNULL;
17238032Speter			map->map_mflags &= ~MF_TRY0NULL;
17338032Speter			break;
17438032Speter
17538032Speter		  case 'O':
17638032Speter			map->map_mflags &= ~MF_TRY1NULL;
17738032Speter			break;
17838032Speter
17938032Speter		  case 'o':
18038032Speter			map->map_mflags |= MF_OPTIONAL;
18138032Speter			break;
18238032Speter
18338032Speter		  case 'f':
18438032Speter			map->map_mflags |= MF_NOFOLDCASE;
18538032Speter			break;
18638032Speter
18738032Speter		  case 'm':
18838032Speter			map->map_mflags |= MF_MATCHONLY;
18938032Speter			break;
19038032Speter
19138032Speter		  case 'A':
19238032Speter			map->map_mflags |= MF_APPEND;
19338032Speter			break;
19438032Speter
19538032Speter		  case 'q':
19638032Speter			map->map_mflags |= MF_KEEPQUOTES;
19738032Speter			break;
19838032Speter
19938032Speter		  case 'a':
20038032Speter			map->map_app = ++p;
20138032Speter			break;
20238032Speter
20338032Speter		  case 'T':
20438032Speter			map->map_tapp = ++p;
20538032Speter			break;
20638032Speter
20738032Speter		  case 'k':
20838032Speter			while (isascii(*++p) && isspace(*p))
20938032Speter				continue;
21038032Speter			map->map_keycolnm = p;
21138032Speter			break;
21238032Speter
21338032Speter		  case 'v':
21438032Speter			while (isascii(*++p) && isspace(*p))
21538032Speter				continue;
21638032Speter			map->map_valcolnm = p;
21738032Speter			break;
21838032Speter
21938032Speter		  case 'z':
22038032Speter			if (*++p != '\\')
22138032Speter				map->map_coldelim = *p;
22238032Speter			else
22338032Speter			{
22438032Speter				switch (*++p)
22538032Speter				{
22638032Speter				  case 'n':
22738032Speter					map->map_coldelim = '\n';
22838032Speter					break;
22938032Speter
23038032Speter				  case 't':
23138032Speter					map->map_coldelim = '\t';
23238032Speter					break;
23338032Speter
23438032Speter				  default:
23538032Speter					map->map_coldelim = '\\';
23638032Speter				}
23738032Speter			}
23838032Speter			break;
23938032Speter
24038032Speter		  case 't':
24138032Speter			map->map_mflags |= MF_NODEFER;
24238032Speter			break;
24338032Speter
24464562Sgshapiro
24564562Sgshapiro		  case 'S':
24664562Sgshapiro			map->map_spacesub = *++p;
24738032Speter			break;
24838032Speter
24964562Sgshapiro		  case 'D':
25064562Sgshapiro			map->map_mflags |= MF_DEFER;
25138032Speter			break;
25264562Sgshapiro
25364562Sgshapiro		  default:
25464562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
25564562Sgshapiro			break;
25638032Speter		}
25738032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
25838032Speter			p++;
25938032Speter		if (*p != '\0')
26038032Speter			*p++ = '\0';
26138032Speter	}
26238032Speter	if (map->map_app != NULL)
26338032Speter		map->map_app = newstr(map->map_app);
26438032Speter	if (map->map_tapp != NULL)
26538032Speter		map->map_tapp = newstr(map->map_tapp);
26638032Speter	if (map->map_keycolnm != NULL)
26738032Speter		map->map_keycolnm = newstr(map->map_keycolnm);
26838032Speter	if (map->map_valcolnm != NULL)
26938032Speter		map->map_valcolnm = newstr(map->map_valcolnm);
27038032Speter
27138032Speter	if (*p != '\0')
27238032Speter	{
27338032Speter		map->map_file = p;
27438032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
27538032Speter			p++;
27638032Speter		if (*p != '\0')
27738032Speter			*p++ = '\0';
27838032Speter		map->map_file = newstr(map->map_file);
27938032Speter	}
28038032Speter
28138032Speter	while (*p != '\0' && isascii(*p) && isspace(*p))
28238032Speter		p++;
28338032Speter	if (*p != '\0')
28438032Speter		map->map_rebuild = newstr(p);
28538032Speter
28638032Speter	if (map->map_file == NULL &&
28738032Speter	    !bitset(MCF_OPTFILE, map->map_class->map_cflags))
28838032Speter	{
28938032Speter		syserr("No file name for %s map %s",
29038032Speter			map->map_class->map_cname, map->map_mname);
29138032Speter		return FALSE;
29238032Speter	}
29338032Speter	return TRUE;
29438032Speter}
29538032Speter/*
29638032Speter**  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
29738032Speter**
29838032Speter**	It also adds the map_app string.  It can be used as a utility
29938032Speter**	in the map_lookup method.
30038032Speter**
30138032Speter**	Parameters:
30238032Speter**		map -- the map that causes this.
30338032Speter**		s -- the string to rewrite, NOT necessarily null terminated.
30438032Speter**		slen -- the length of s.
30538032Speter**		av -- arguments to interpolate into buf.
30638032Speter**
30738032Speter**	Returns:
30838032Speter**		Pointer to rewritten result.  This is static data that
30938032Speter**		should be copied if it is to be saved!
31038032Speter**
31138032Speter**	Side Effects:
31238032Speter**		none.
31338032Speter*/
31438032Speter
31538032Speterchar *
31638032Spetermap_rewrite(map, s, slen, av)
31738032Speter	register MAP *map;
31838032Speter	register const char *s;
31938032Speter	size_t slen;
32038032Speter	char **av;
32138032Speter{
32238032Speter	register char *bp;
32338032Speter	register char c;
32438032Speter	char **avp;
32538032Speter	register char *ap;
32638032Speter	size_t l;
32738032Speter	size_t len;
32838032Speter	static size_t buflen = 0;
32938032Speter	static char *buf = NULL;
33038032Speter
33138032Speter	if (tTd(39, 1))
33238032Speter	{
33364562Sgshapiro		dprintf("map_rewrite(%.*s), av =", (int)slen, s);
33438032Speter		if (av == NULL)
33564562Sgshapiro			dprintf(" (nullv)");
33638032Speter		else
33738032Speter		{
33838032Speter			for (avp = av; *avp != NULL; avp++)
33964562Sgshapiro				dprintf("\n\t%s", *avp);
34038032Speter		}
34164562Sgshapiro		dprintf("\n");
34238032Speter	}
34338032Speter
34438032Speter	/* count expected size of output (can safely overestimate) */
34538032Speter	l = len = slen;
34638032Speter	if (av != NULL)
34738032Speter	{
34838032Speter		const char *sp = s;
34938032Speter
35038032Speter		while (l-- > 0 && (c = *sp++) != '\0')
35138032Speter		{
35238032Speter			if (c != '%')
35338032Speter				continue;
35438032Speter			if (l-- <= 0)
35538032Speter				break;
35638032Speter			c = *sp++;
35738032Speter			if (!(isascii(c) && isdigit(c)))
35838032Speter				continue;
35938032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
36038032Speter				continue;
36138032Speter			if (*avp == NULL)
36238032Speter				continue;
36338032Speter			len += strlen(*avp);
36438032Speter		}
36538032Speter	}
36638032Speter	if (map->map_app != NULL)
36738032Speter		len += strlen(map->map_app);
36838032Speter	if (buflen < ++len)
36938032Speter	{
37038032Speter		/* need to malloc additional space */
37138032Speter		buflen = len;
37238032Speter		if (buf != NULL)
37377349Sgshapiro			sm_free(buf);
37438032Speter		buf = xalloc(buflen);
37538032Speter	}
37638032Speter
37738032Speter	bp = buf;
37838032Speter	if (av == NULL)
37938032Speter	{
38064562Sgshapiro		memmove(bp, s, slen);
38138032Speter		bp += slen;
38264562Sgshapiro
38364562Sgshapiro		/* assert(len > slen); */
38464562Sgshapiro		len -= slen;
38538032Speter	}
38638032Speter	else
38738032Speter	{
38838032Speter		while (slen-- > 0 && (c = *s++) != '\0')
38938032Speter		{
39038032Speter			if (c != '%')
39138032Speter			{
39238032Speter  pushc:
39364562Sgshapiro				if (--len <= 0)
39464562Sgshapiro					break;
39538032Speter				*bp++ = c;
39638032Speter				continue;
39738032Speter			}
39838032Speter			if (slen-- <= 0 || (c = *s++) == '\0')
39938032Speter				c = '%';
40038032Speter			if (c == '%')
40138032Speter				goto pushc;
40238032Speter			if (!(isascii(c) && isdigit(c)))
40338032Speter			{
40438032Speter				*bp++ = '%';
40564562Sgshapiro				--len;
40638032Speter				goto pushc;
40738032Speter			}
40838032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
40938032Speter				continue;
41038032Speter			if (*avp == NULL)
41138032Speter				continue;
41238032Speter
41338032Speter			/* transliterate argument into output string */
41464562Sgshapiro			for (ap = *avp; (c = *ap++) != '\0' && len > 0; --len)
41538032Speter				*bp++ = c;
41638032Speter		}
41738032Speter	}
41864562Sgshapiro	if (map->map_app != NULL && len > 0)
41964562Sgshapiro		(void) strlcpy(bp, map->map_app, len);
42038032Speter	else
42138032Speter		*bp = '\0';
42238032Speter	if (tTd(39, 1))
42364562Sgshapiro		dprintf("map_rewrite => %s\n", buf);
42438032Speter	return buf;
42538032Speter}
42638032Speter/*
42764562Sgshapiro**  INITMAPS -- rebuild alias maps
42838032Speter**
42938032Speter**	Parameters:
43064562Sgshapiro**		none.
43138032Speter**
43238032Speter**	Returns:
43338032Speter**		none.
43438032Speter*/
43538032Speter
43638032Spetervoid
43764562Sgshapiroinitmaps()
43838032Speter{
43938032Speter#if XDEBUG
44038032Speter	checkfd012("entering initmaps");
44164562Sgshapiro#endif /* XDEBUG */
44238032Speter	stabapply(map_init, 0);
44338032Speter#if XDEBUG
44438032Speter	checkfd012("exiting initmaps");
44564562Sgshapiro#endif /* XDEBUG */
44638032Speter}
44764562Sgshapiro/*
44864562Sgshapiro**  MAP_INIT -- rebuild a map
44964562Sgshapiro**
45064562Sgshapiro**	Parameters:
45164562Sgshapiro**		s -- STAB entry: if map: try to rebuild
45264562Sgshapiro**		unused -- unused variable
45364562Sgshapiro**
45464562Sgshapiro**	Returns:
45564562Sgshapiro**		none.
45664562Sgshapiro**
45764562Sgshapiro**	Side Effects:
45864562Sgshapiro**		will close already open rebuildable map.
45964562Sgshapiro*/
46038032Speter
46164562Sgshapiro/* ARGSUSED1 */
46264562Sgshapirostatic void
46364562Sgshapiromap_init(s, unused)
46438032Speter	register STAB *s;
46564562Sgshapiro	int unused;
46638032Speter{
46738032Speter	register MAP *map;
46838032Speter
46938032Speter	/* has to be a map */
47038032Speter	if (s->s_type != ST_MAP)
47138032Speter		return;
47238032Speter
47338032Speter	map = &s->s_map;
47438032Speter	if (!bitset(MF_VALID, map->map_mflags))
47538032Speter		return;
47638032Speter
47738032Speter	if (tTd(38, 2))
47864562Sgshapiro		dprintf("map_init(%s:%s, %s)\n",
47938032Speter			map->map_class->map_cname == NULL ? "NULL" :
48038032Speter				map->map_class->map_cname,
48138032Speter			map->map_mname == NULL ? "NULL" : map->map_mname,
48264562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
48338032Speter
48464562Sgshapiro	if (!bitset(MF_ALIAS, map->map_mflags) ||
48564562Sgshapiro	    !bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
48638032Speter	{
48738032Speter		if (tTd(38, 3))
48864562Sgshapiro			dprintf("\tnot rebuildable\n");
48938032Speter		return;
49038032Speter	}
49138032Speter
49238032Speter	/* if already open, close it (for nested open) */
49338032Speter	if (bitset(MF_OPEN, map->map_mflags))
49438032Speter	{
49577349Sgshapiro		map->map_mflags |= MF_CLOSING;
49638032Speter		map->map_class->map_close(map);
49777349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
49838032Speter	}
49938032Speter
50064562Sgshapiro	(void) rebuildaliases(map, FALSE);
50164562Sgshapiro	return;
50264562Sgshapiro}
50364562Sgshapiro/*
50464562Sgshapiro**  OPENMAP -- open a map
50564562Sgshapiro**
50664562Sgshapiro**	Parameters:
50764562Sgshapiro**		map -- map to open (it must not be open).
50864562Sgshapiro**
50964562Sgshapiro**	Returns:
51064562Sgshapiro**		whether open succeeded.
51164562Sgshapiro**
51264562Sgshapiro*/
51364562Sgshapiro
51464562Sgshapirobool
51564562Sgshapiroopenmap(map)
51664562Sgshapiro	MAP *map;
51764562Sgshapiro{
51864562Sgshapiro	bool restore = FALSE;
51964562Sgshapiro	bool savehold = HoldErrs;
52064562Sgshapiro	bool savequick = QuickAbort;
52164562Sgshapiro	int saveerrors = Errors;
52264562Sgshapiro
52364562Sgshapiro	if (!bitset(MF_VALID, map->map_mflags))
52464562Sgshapiro		return FALSE;
52564562Sgshapiro
52664562Sgshapiro	/* better safe than sorry... */
52764562Sgshapiro	if (bitset(MF_OPEN, map->map_mflags))
52864562Sgshapiro		return TRUE;
52964562Sgshapiro
53064562Sgshapiro	/* Don't send a map open error out via SMTP */
53164562Sgshapiro	if ((OnlyOneError || QuickAbort) &&
53264562Sgshapiro	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))
53338032Speter	{
53464562Sgshapiro		restore = TRUE;
53564562Sgshapiro		HoldErrs = TRUE;
53664562Sgshapiro		QuickAbort = FALSE;
53738032Speter	}
53838032Speter
53964562Sgshapiro	errno = 0;
54038032Speter	if (map->map_class->map_open(map, O_RDONLY))
54138032Speter	{
54238032Speter		if (tTd(38, 4))
54364562Sgshapiro			dprintf("openmap()\t%s:%s %s: valid\n",
54438032Speter				map->map_class->map_cname == NULL ? "NULL" :
54538032Speter					map->map_class->map_cname,
54638032Speter				map->map_mname == NULL ? "NULL" :
54738032Speter					map->map_mname,
54838032Speter				map->map_file == NULL ? "NULL" :
54938032Speter					map->map_file);
55038032Speter		map->map_mflags |= MF_OPEN;
55142575Speter		map->map_pid = getpid();
55238032Speter	}
55338032Speter	else
55438032Speter	{
55538032Speter		if (tTd(38, 4))
55664562Sgshapiro			dprintf("openmap()\t%s:%s %s: invalid%s%s\n",
55738032Speter				map->map_class->map_cname == NULL ? "NULL" :
55838032Speter					map->map_class->map_cname,
55938032Speter				map->map_mname == NULL ? "NULL" :
56038032Speter					map->map_mname,
56138032Speter				map->map_file == NULL ? "NULL" :
56238032Speter					map->map_file,
56364562Sgshapiro				errno == 0 ? "" : ": ",
56464562Sgshapiro				errno == 0 ? "" : errstring(errno));
56538032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
56638032Speter		{
56738032Speter			extern MAPCLASS BogusMapClass;
56838032Speter
56938032Speter			map->map_class = &BogusMapClass;
57038032Speter			map->map_mflags |= MF_OPEN;
57142575Speter			map->map_pid = getpid();
57266494Sgshapiro			MapOpenErr = TRUE;
57338032Speter		}
57464562Sgshapiro		else
57564562Sgshapiro		{
57664562Sgshapiro			/* don't try again */
57764562Sgshapiro			map->map_mflags &= ~MF_VALID;
57864562Sgshapiro		}
57938032Speter	}
58064562Sgshapiro
58164562Sgshapiro	if (restore)
58264562Sgshapiro	{
58364562Sgshapiro		Errors = saveerrors;
58464562Sgshapiro		HoldErrs = savehold;
58564562Sgshapiro		QuickAbort = savequick;
58664562Sgshapiro	}
58764562Sgshapiro
58864562Sgshapiro	return bitset(MF_OPEN, map->map_mflags);
58938032Speter}
59038032Speter/*
59142575Speter**  CLOSEMAPS -- close all open maps opened by the current pid.
59242575Speter**
59342575Speter**	Parameters:
59442575Speter**		none
59542575Speter**
59642575Speter**	Returns:
59742575Speter**		none.
59842575Speter*/
59942575Speter
60042575Spetervoid
60142575Speterclosemaps()
60242575Speter{
60342575Speter	stabapply(map_close, 0);
60442575Speter}
60564562Sgshapiro/*
60664562Sgshapiro**  MAP_CLOSE -- close a map opened by the current pid.
60764562Sgshapiro**
60864562Sgshapiro**	Parameters:
60964562Sgshapiro**		s -- STAB entry: if map: try to open
61064562Sgshapiro**		second parameter is unused (required by stabapply())
61164562Sgshapiro**
61264562Sgshapiro**	Returns:
61364562Sgshapiro**		none.
61464562Sgshapiro*/
61542575Speter
61642575Speter/* ARGSUSED1 */
61764562Sgshapirostatic void
61842575Spetermap_close(s, unused)
61942575Speter	register STAB *s;
62042575Speter	int unused;
62142575Speter{
62242575Speter	MAP *map;
62342575Speter
62442575Speter	if (s->s_type != ST_MAP)
62542575Speter		return;
62664562Sgshapiro
62742575Speter	map = &s->s_map;
62842575Speter
62942575Speter	if (!bitset(MF_VALID, map->map_mflags) ||
63042575Speter	    !bitset(MF_OPEN, map->map_mflags) ||
63177349Sgshapiro	    bitset(MF_CLOSING, map->map_mflags) ||
63242575Speter	    map->map_pid != getpid())
63342575Speter		return;
63464562Sgshapiro
63542575Speter	if (tTd(38, 5))
63664562Sgshapiro		dprintf("closemaps: closing %s (%s)\n",
63764562Sgshapiro			map->map_mname == NULL ? "NULL" : map->map_mname,
63864562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
63964562Sgshapiro
64077349Sgshapiro	map->map_mflags |= MF_CLOSING;
64142575Speter	map->map_class->map_close(map);
64277349Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
64342575Speter}
64442575Speter/*
64538032Speter**  GETCANONNAME -- look up name using service switch
64638032Speter**
64738032Speter**	Parameters:
64838032Speter**		host -- the host name to look up.
64938032Speter**		hbsize -- the size of the host buffer.
65038032Speter**		trymx -- if set, try MX records.
65138032Speter**
65238032Speter**	Returns:
65338032Speter**		TRUE -- if the host was found.
65438032Speter**		FALSE -- otherwise.
65538032Speter*/
65638032Speter
65738032Speterbool
65838032Spetergetcanonname(host, hbsize, trymx)
65938032Speter	char *host;
66038032Speter	int hbsize;
66138032Speter	bool trymx;
66238032Speter{
66338032Speter	int nmaps;
66438032Speter	int mapno;
66538032Speter	bool found = FALSE;
66638032Speter	bool got_tempfail = FALSE;
66764562Sgshapiro	auto int status;
66838032Speter	char *maptype[MAXMAPSTACK];
66938032Speter	short mapreturn[MAXMAPACTIONS];
67038032Speter
67138032Speter	nmaps = switch_map_find("hosts", maptype, mapreturn);
67238032Speter	for (mapno = 0; mapno < nmaps; mapno++)
67338032Speter	{
67438032Speter		int i;
67538032Speter
67638032Speter		if (tTd(38, 20))
67764562Sgshapiro			dprintf("getcanonname(%s), trying %s\n",
67838032Speter				host, maptype[mapno]);
67938032Speter		if (strcmp("files", maptype[mapno]) == 0)
68038032Speter		{
68164562Sgshapiro			found = text_getcanonname(host, hbsize, &status);
68238032Speter		}
68338032Speter#ifdef NIS
68438032Speter		else if (strcmp("nis", maptype[mapno]) == 0)
68538032Speter		{
68664562Sgshapiro			found = nis_getcanonname(host, hbsize, &status);
68738032Speter		}
68864562Sgshapiro#endif /* NIS */
68938032Speter#ifdef NISPLUS
69038032Speter		else if (strcmp("nisplus", maptype[mapno]) == 0)
69138032Speter		{
69264562Sgshapiro			found = nisplus_getcanonname(host, hbsize, &status);
69338032Speter		}
69464562Sgshapiro#endif /* NISPLUS */
69538032Speter#if NAMED_BIND
69638032Speter		else if (strcmp("dns", maptype[mapno]) == 0)
69738032Speter		{
69864562Sgshapiro			found = dns_getcanonname(host, hbsize, trymx, &status);
69938032Speter		}
70064562Sgshapiro#endif /* NAMED_BIND */
70138032Speter#if NETINFO
70238032Speter		else if (strcmp("netinfo", maptype[mapno]) == 0)
70338032Speter		{
70464562Sgshapiro			found = ni_getcanonname(host, hbsize, &status);
70538032Speter		}
70664562Sgshapiro#endif /* NETINFO */
70738032Speter		else
70838032Speter		{
70938032Speter			found = FALSE;
71064562Sgshapiro			status = EX_UNAVAILABLE;
71138032Speter		}
71238032Speter
71338032Speter		/*
71438032Speter		**  Heuristic: if $m is not set, we are running during system
71538032Speter		**  startup.  In this case, when a name is apparently found
71638032Speter		**  but has no dot, treat is as not found.  This avoids
71738032Speter		**  problems if /etc/hosts has no FQDN but is listed first
71838032Speter		**  in the service switch.
71938032Speter		*/
72038032Speter
72138032Speter		if (found &&
72238032Speter		    (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
72338032Speter			break;
72438032Speter
72538032Speter		/* see if we should continue */
72664562Sgshapiro		if (status == EX_TEMPFAIL)
72738032Speter		{
72838032Speter			i = MA_TRYAGAIN;
72938032Speter			got_tempfail = TRUE;
73038032Speter		}
73164562Sgshapiro		else if (status == EX_NOTFOUND)
73238032Speter			i = MA_NOTFOUND;
73338032Speter		else
73438032Speter			i = MA_UNAVAIL;
73538032Speter		if (bitset(1 << mapno, mapreturn[i]))
73638032Speter			break;
73738032Speter	}
73838032Speter
73938032Speter	if (found)
74038032Speter	{
74138032Speter		char *d;
74238032Speter
74338032Speter		if (tTd(38, 20))
74464562Sgshapiro			dprintf("getcanonname(%s), found\n", host);
74538032Speter
74638032Speter		/*
74738032Speter		**  If returned name is still single token, compensate
74838032Speter		**  by tagging on $m.  This is because some sites set
74938032Speter		**  up their DNS or NIS databases wrong.
75038032Speter		*/
75138032Speter
75238032Speter		if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
75338032Speter		{
75438032Speter			d = macvalue('m', CurEnv);
75538032Speter			if (d != NULL &&
75638032Speter			    hbsize > (int) (strlen(host) + strlen(d) + 1))
75738032Speter			{
75838032Speter				if (host[strlen(host) - 1] != '.')
75964562Sgshapiro					(void) strlcat(host, ".", hbsize);
76064562Sgshapiro				(void) strlcat(host, d, hbsize);
76138032Speter			}
76238032Speter			else
76338032Speter				return FALSE;
76438032Speter		}
76538032Speter		return TRUE;
76638032Speter	}
76738032Speter
76838032Speter	if (tTd(38, 20))
76964562Sgshapiro		dprintf("getcanonname(%s), failed, status=%d\n", host, status);
77038032Speter
77138032Speter#if NAMED_BIND
77238032Speter	if (got_tempfail)
77373188Sgshapiro		SM_SET_H_ERRNO(TRY_AGAIN);
77438032Speter	else
77573188Sgshapiro		SM_SET_H_ERRNO(HOST_NOT_FOUND);
77664562Sgshapiro#endif /* NAMED_BIND */
77738032Speter	return FALSE;
77838032Speter}
77938032Speter/*
78038032Speter**  EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
78138032Speter**
78238032Speter**	Parameters:
78338032Speter**		name -- the name against which to match.
78473188Sgshapiro**		dot -- where to reinsert '.' to get FQDN
78538032Speter**		line -- the /etc/hosts line.
78638032Speter**		cbuf -- the location to store the result.
78738032Speter**		cbuflen -- the size of cbuf.
78838032Speter**
78938032Speter**	Returns:
79038032Speter**		TRUE -- if the line matched the desired name.
79138032Speter**		FALSE -- otherwise.
79238032Speter*/
79338032Speter
79464562Sgshapirostatic bool
79573188Sgshapiroextract_canonname(name, dot, line, cbuf, cbuflen)
79638032Speter	char *name;
79773188Sgshapiro	char *dot;
79838032Speter	char *line;
79938032Speter	char cbuf[];
80038032Speter	int cbuflen;
80138032Speter{
80238032Speter	int i;
80338032Speter	char *p;
80438032Speter	bool found = FALSE;
80538032Speter
80638032Speter	cbuf[0] = '\0';
80738032Speter	if (line[0] == '#')
80838032Speter		return FALSE;
80938032Speter
81038032Speter	for (i = 1; ; i++)
81138032Speter	{
81238032Speter		char nbuf[MAXNAME + 1];
81338032Speter
81438032Speter		p = get_column(line, i, '\0', nbuf, sizeof nbuf);
81538032Speter		if (p == NULL)
81638032Speter			break;
81738032Speter		if (*p == '\0')
81838032Speter			continue;
81938032Speter		if (cbuf[0] == '\0' ||
82038032Speter		    (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
82138032Speter		{
82238032Speter			snprintf(cbuf, cbuflen, "%s", p);
82338032Speter		}
82438032Speter		if (strcasecmp(name, p) == 0)
82538032Speter			found = TRUE;
82673188Sgshapiro		else if (dot != NULL)
82773188Sgshapiro		{
82873188Sgshapiro			/* try looking for the FQDN as well */
82973188Sgshapiro			*dot = '.';
83073188Sgshapiro			if (strcasecmp(name, p) == 0)
83173188Sgshapiro				found = TRUE;
83273188Sgshapiro			*dot = '\0';
83373188Sgshapiro		}
83438032Speter	}
83538032Speter	if (found && strchr(cbuf, '.') == NULL)
83638032Speter	{
83738032Speter		/* try to add a domain on the end of the name */
83838032Speter		char *domain = macvalue('m', CurEnv);
83938032Speter
84038032Speter		if (domain != NULL &&
84164562Sgshapiro		    strlen(domain) + (i = strlen(cbuf)) + 1 < (size_t) cbuflen)
84238032Speter		{
84364562Sgshapiro			p = &cbuf[i];
84438032Speter			*p++ = '.';
84564562Sgshapiro			(void) strlcpy(p, domain, cbuflen - i - 1);
84638032Speter		}
84738032Speter	}
84838032Speter	return found;
84938032Speter}
85038032Speter/*
85138032Speter**  NDBM modules
85238032Speter*/
85338032Speter
85438032Speter#ifdef NDBM
85538032Speter
85638032Speter/*
85738032Speter**  NDBM_MAP_OPEN -- DBM-style map open
85838032Speter*/
85938032Speter
86038032Speterbool
86138032Speterndbm_map_open(map, mode)
86238032Speter	MAP *map;
86338032Speter	int mode;
86438032Speter{
86538032Speter	register DBM *dbm;
86664562Sgshapiro	int save_errno;
86738032Speter	int dfd;
86838032Speter	int pfd;
86964562Sgshapiro	long sff;
87038032Speter	int ret;
87138032Speter	int smode = S_IREAD;
87238032Speter	char dirfile[MAXNAME + 1];
87338032Speter	char pagfile[MAXNAME + 1];
87464562Sgshapiro	struct stat st;
87538032Speter	struct stat std, stp;
87638032Speter
87738032Speter	if (tTd(38, 2))
87864562Sgshapiro		dprintf("ndbm_map_open(%s, %s, %d)\n",
87938032Speter			map->map_mname, map->map_file, mode);
88038032Speter	map->map_lockfd = -1;
88138032Speter	mode &= O_ACCMODE;
88238032Speter
88338032Speter	/* do initial file and directory checks */
88438032Speter	snprintf(dirfile, sizeof dirfile, "%s.dir", map->map_file);
88538032Speter	snprintf(pagfile, sizeof pagfile, "%s.pag", map->map_file);
88638032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
88738032Speter	if (mode == O_RDWR)
88838032Speter	{
88938032Speter		sff |= SFF_CREAT;
89064562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
89138032Speter			sff |= SFF_NOSLINK;
89264562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
89338032Speter			sff |= SFF_NOHLINK;
89438032Speter		smode = S_IWRITE;
89538032Speter	}
89638032Speter	else
89738032Speter	{
89864562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
89938032Speter			sff |= SFF_NOWLINK;
90038032Speter	}
90164562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
90238032Speter		sff |= SFF_SAFEDIRPATH;
90338032Speter	ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
90438032Speter			    sff, smode, &std);
90538032Speter	if (ret == 0)
90638032Speter		ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
90738032Speter			       sff, smode, &stp);
90864562Sgshapiro
90964562Sgshapiro# if !_FFR_REMOVE_AUTOREBUILD
91038032Speter	if (ret == ENOENT && AutoRebuild &&
91138032Speter	    bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
91238032Speter	    (bitset(MF_IMPL_NDBM, map->map_mflags) ||
91338032Speter	     bitset(MF_ALIAS, map->map_mflags)) &&
91438032Speter	    mode == O_RDONLY)
91538032Speter	{
91638032Speter		bool impl = bitset(MF_IMPL_NDBM, map->map_mflags);
91738032Speter
91838032Speter		/* may be able to rebuild */
91938032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
92038032Speter		if (!rebuildaliases(map, TRUE))
92138032Speter			return FALSE;
92238032Speter		if (impl)
92338032Speter			return impl_map_open(map, O_RDONLY);
92438032Speter		else
92538032Speter			return ndbm_map_open(map, O_RDONLY);
92638032Speter	}
92764562Sgshapiro# endif /* !_FFR_REMOVE_AUTOREBUILD */
92864562Sgshapiro
92938032Speter	if (ret != 0)
93038032Speter	{
93138032Speter		char *prob = "unsafe";
93238032Speter
93338032Speter		/* cannot open this map */
93438032Speter		if (ret == ENOENT)
93538032Speter			prob = "missing";
93638032Speter		if (tTd(38, 2))
93764562Sgshapiro			dprintf("\t%s map file: %d\n", prob, ret);
93838032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
93938032Speter			syserr("dbm map \"%s\": %s map file %s",
94038032Speter				map->map_mname, prob, map->map_file);
94138032Speter		return FALSE;
94238032Speter	}
94338032Speter	if (std.st_mode == ST_MODE_NOFILE)
94438032Speter		mode |= O_CREAT|O_EXCL;
94538032Speter
94664562Sgshapiro# if LOCK_ON_OPEN
94738032Speter	if (mode == O_RDONLY)
94838032Speter		mode |= O_SHLOCK;
94938032Speter	else
95038032Speter		mode |= O_TRUNC|O_EXLOCK;
95164562Sgshapiro# else /* LOCK_ON_OPEN */
95238032Speter	if ((mode & O_ACCMODE) == O_RDWR)
95338032Speter	{
95464562Sgshapiro#  if NOFTRUNCATE
95538032Speter		/*
95638032Speter		**  Warning: race condition.  Try to lock the file as
95738032Speter		**  quickly as possible after opening it.
95838032Speter		**	This may also have security problems on some systems,
95938032Speter		**	but there isn't anything we can do about it.
96038032Speter		*/
96138032Speter
96238032Speter		mode |= O_TRUNC;
96364562Sgshapiro#  else /* NOFTRUNCATE */
96438032Speter		/*
96538032Speter		**  This ugly code opens the map without truncating it,
96638032Speter		**  locks the file, then truncates it.  Necessary to
96738032Speter		**  avoid race conditions.
96838032Speter		*/
96938032Speter
97038032Speter		int dirfd;
97138032Speter		int pagfd;
97264562Sgshapiro		long sff = SFF_CREAT|SFF_OPENASROOT;
97338032Speter
97464562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
97538032Speter			sff |= SFF_NOSLINK;
97664562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
97738032Speter			sff |= SFF_NOHLINK;
97838032Speter
97938032Speter		dirfd = safeopen(dirfile, mode, DBMMODE, sff);
98038032Speter		pagfd = safeopen(pagfile, mode, DBMMODE, sff);
98138032Speter
98238032Speter		if (dirfd < 0 || pagfd < 0)
98338032Speter		{
98464562Sgshapiro			save_errno = errno;
98538032Speter			if (dirfd >= 0)
98638032Speter				(void) close(dirfd);
98738032Speter			if (pagfd >= 0)
98838032Speter				(void) close(pagfd);
98938032Speter			errno = save_errno;
99038032Speter			syserr("ndbm_map_open: cannot create database %s",
99138032Speter				map->map_file);
99238032Speter			return FALSE;
99338032Speter		}
99438032Speter		if (ftruncate(dirfd, (off_t) 0) < 0 ||
99538032Speter		    ftruncate(pagfd, (off_t) 0) < 0)
99638032Speter		{
99764562Sgshapiro			save_errno = errno;
99838032Speter			(void) close(dirfd);
99938032Speter			(void) close(pagfd);
100038032Speter			errno = save_errno;
100138032Speter			syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
100238032Speter				map->map_file);
100338032Speter			return FALSE;
100438032Speter		}
100538032Speter
100638032Speter		/* if new file, get "before" bits for later filechanged check */
100738032Speter		if (std.st_mode == ST_MODE_NOFILE &&
100838032Speter		    (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
100938032Speter		{
101064562Sgshapiro			save_errno = errno;
101138032Speter			(void) close(dirfd);
101238032Speter			(void) close(pagfd);
101338032Speter			errno = save_errno;
101438032Speter			syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
101538032Speter				map->map_file);
101638032Speter			return FALSE;
101738032Speter		}
101838032Speter
101938032Speter		/* have to save the lock for the duration (bletch) */
102038032Speter		map->map_lockfd = dirfd;
102164562Sgshapiro		(void) close(pagfd);
102238032Speter
102338032Speter		/* twiddle bits for dbm_open */
102438032Speter		mode &= ~(O_CREAT|O_EXCL);
102564562Sgshapiro#  endif /* NOFTRUNCATE */
102638032Speter	}
102764562Sgshapiro# endif /* LOCK_ON_OPEN */
102838032Speter
102938032Speter	/* open the database */
103038032Speter	dbm = dbm_open(map->map_file, mode, DBMMODE);
103138032Speter	if (dbm == NULL)
103238032Speter	{
103364562Sgshapiro		save_errno = errno;
103438032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
103538032Speter		    aliaswait(map, ".pag", FALSE))
103638032Speter			return TRUE;
103764562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
103838032Speter		if (map->map_lockfd >= 0)
103964562Sgshapiro			(void) close(map->map_lockfd);
104064562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
104138032Speter		errno = save_errno;
104238032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
104338032Speter			syserr("Cannot open DBM database %s", map->map_file);
104438032Speter		return FALSE;
104538032Speter	}
104638032Speter	dfd = dbm_dirfno(dbm);
104738032Speter	pfd = dbm_pagfno(dbm);
104838032Speter	if (dfd == pfd)
104938032Speter	{
105038032Speter		/* heuristic: if files are linked, this is actually gdbm */
105138032Speter		dbm_close(dbm);
105264562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
105338032Speter		if (map->map_lockfd >= 0)
105464562Sgshapiro			(void) close(map->map_lockfd);
105564562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
105638032Speter		errno = 0;
105738032Speter		syserr("dbm map \"%s\": cannot support GDBM",
105838032Speter			map->map_mname);
105938032Speter		return FALSE;
106038032Speter	}
106138032Speter
106238032Speter	if (filechanged(dirfile, dfd, &std) ||
106338032Speter	    filechanged(pagfile, pfd, &stp))
106438032Speter	{
106564562Sgshapiro		save_errno = errno;
106638032Speter		dbm_close(dbm);
106764562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
106838032Speter		if (map->map_lockfd >= 0)
106964562Sgshapiro			(void) close(map->map_lockfd);
107064562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
107138032Speter		errno = save_errno;
107238032Speter		syserr("ndbm_map_open(%s): file changed after open",
107338032Speter			map->map_file);
107438032Speter		return FALSE;
107538032Speter	}
107638032Speter
107738032Speter	map->map_db1 = (ARBPTR_T) dbm;
107864562Sgshapiro
107964562Sgshapiro	/*
108064562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
108164562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
108264562Sgshapiro	**  map_mtime to be set
108364562Sgshapiro	*/
108464562Sgshapiro
108577349Sgshapiro	if (fstat(pfd, &st) >= 0)
108664562Sgshapiro		map->map_mtime = st.st_mtime;
108764562Sgshapiro
108838032Speter	if (mode == O_RDONLY)
108938032Speter	{
109064562Sgshapiro# if LOCK_ON_OPEN
109138032Speter		if (dfd >= 0)
109238032Speter			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
109338032Speter		if (pfd >= 0)
109438032Speter			(void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
109564562Sgshapiro# endif /* LOCK_ON_OPEN */
109638032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
109738032Speter		    !aliaswait(map, ".pag", TRUE))
109838032Speter			return FALSE;
109938032Speter	}
110038032Speter	else
110138032Speter	{
110238032Speter		map->map_mflags |= MF_LOCKED;
110342575Speter		if (geteuid() == 0 && TrustedUid != 0)
110438032Speter		{
110564562Sgshapiro#  if HASFCHOWN
110642575Speter			if (fchown(dfd, TrustedUid, -1) < 0 ||
110742575Speter			    fchown(pfd, TrustedUid, -1) < 0)
110838032Speter			{
110938032Speter				int err = errno;
111038032Speter
111138032Speter				sm_syslog(LOG_ALERT, NOQID,
111238032Speter					  "ownership change on %s failed: %s",
111338032Speter					  map->map_file, errstring(err));
111438032Speter				message("050 ownership change on %s failed: %s",
111538032Speter					map->map_file, errstring(err));
111638032Speter			}
111764562Sgshapiro#  endif /* HASFCHOWN */
111838032Speter		}
111938032Speter	}
112038032Speter	return TRUE;
112138032Speter}
112238032Speter
112338032Speter
112438032Speter/*
112538032Speter**  NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
112638032Speter*/
112738032Speter
112838032Speterchar *
112938032Speterndbm_map_lookup(map, name, av, statp)
113038032Speter	MAP *map;
113138032Speter	char *name;
113238032Speter	char **av;
113338032Speter	int *statp;
113438032Speter{
113538032Speter	datum key, val;
113677349Sgshapiro	int dfd, pfd;
113738032Speter	char keybuf[MAXNAME + 1];
113838032Speter	struct stat stbuf;
113938032Speter
114038032Speter	if (tTd(38, 20))
114164562Sgshapiro		dprintf("ndbm_map_lookup(%s, %s)\n",
114238032Speter			map->map_mname, name);
114338032Speter
114438032Speter	key.dptr = name;
114538032Speter	key.dsize = strlen(name);
114638032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
114738032Speter	{
114838032Speter		if (key.dsize > sizeof keybuf - 1)
114938032Speter			key.dsize = sizeof keybuf - 1;
115064562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
115138032Speter		keybuf[key.dsize] = '\0';
115238032Speter		makelower(keybuf);
115338032Speter		key.dptr = keybuf;
115438032Speter	}
115538032Speterlockdbm:
115677349Sgshapiro	dfd = dbm_dirfno((DBM *) map->map_db1);
115777349Sgshapiro	if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
115877349Sgshapiro		(void) lockfile(dfd, map->map_file, ".dir", LOCK_SH);
115977349Sgshapiro	pfd = dbm_pagfno((DBM *) map->map_db1);
116077349Sgshapiro	if (pfd < 0 || fstat(pfd, &stbuf) < 0 ||
116177349Sgshapiro	    stbuf.st_mtime > map->map_mtime)
116238032Speter	{
116338032Speter		/* Reopen the database to sync the cache */
116438032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
116538032Speter								 : O_RDONLY;
116638032Speter
116777349Sgshapiro		if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
116877349Sgshapiro			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
116977349Sgshapiro		map->map_mflags |= MF_CLOSING;
117038032Speter		map->map_class->map_close(map);
117177349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
117238032Speter		if (map->map_class->map_open(map, omode))
117338032Speter		{
117438032Speter			map->map_mflags |= MF_OPEN;
117542575Speter			map->map_pid = getpid();
117638032Speter			if ((omode && O_ACCMODE) == O_RDWR)
117738032Speter				map->map_mflags |= MF_WRITABLE;
117838032Speter			goto lockdbm;
117938032Speter		}
118038032Speter		else
118138032Speter		{
118238032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
118338032Speter			{
118438032Speter				extern MAPCLASS BogusMapClass;
118538032Speter
118638032Speter				*statp = EX_TEMPFAIL;
118738032Speter				map->map_class = &BogusMapClass;
118838032Speter				map->map_mflags |= MF_OPEN;
118942575Speter				map->map_pid = getpid();
119038032Speter				syserr("Cannot reopen NDBM database %s",
119138032Speter					map->map_file);
119238032Speter			}
119338032Speter			return NULL;
119438032Speter		}
119538032Speter	}
119638032Speter	val.dptr = NULL;
119738032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
119838032Speter	{
119938032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
120038032Speter		if (val.dptr != NULL)
120138032Speter			map->map_mflags &= ~MF_TRY1NULL;
120238032Speter	}
120338032Speter	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
120438032Speter	{
120538032Speter		key.dsize++;
120638032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
120738032Speter		if (val.dptr != NULL)
120838032Speter			map->map_mflags &= ~MF_TRY0NULL;
120938032Speter	}
121077349Sgshapiro	if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
121177349Sgshapiro		(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
121238032Speter	if (val.dptr == NULL)
121338032Speter		return NULL;
121438032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
121538032Speter		return map_rewrite(map, name, strlen(name), NULL);
121638032Speter	else
121738032Speter		return map_rewrite(map, val.dptr, val.dsize, av);
121838032Speter}
121938032Speter
122038032Speter
122138032Speter/*
122238032Speter**  NDBM_MAP_STORE -- store a datum in the database
122338032Speter*/
122438032Speter
122538032Spetervoid
122638032Speterndbm_map_store(map, lhs, rhs)
122738032Speter	register MAP *map;
122838032Speter	char *lhs;
122938032Speter	char *rhs;
123038032Speter{
123138032Speter	datum key;
123238032Speter	datum data;
123364562Sgshapiro	int status;
123438032Speter	char keybuf[MAXNAME + 1];
123538032Speter
123638032Speter	if (tTd(38, 12))
123764562Sgshapiro		dprintf("ndbm_map_store(%s, %s, %s)\n",
123838032Speter			map->map_mname, lhs, rhs);
123938032Speter
124038032Speter	key.dsize = strlen(lhs);
124138032Speter	key.dptr = lhs;
124238032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
124338032Speter	{
124438032Speter		if (key.dsize > sizeof keybuf - 1)
124538032Speter			key.dsize = sizeof keybuf - 1;
124664562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
124738032Speter		keybuf[key.dsize] = '\0';
124838032Speter		makelower(keybuf);
124938032Speter		key.dptr = keybuf;
125038032Speter	}
125138032Speter
125238032Speter	data.dsize = strlen(rhs);
125338032Speter	data.dptr = rhs;
125438032Speter
125538032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
125638032Speter	{
125738032Speter		key.dsize++;
125838032Speter		data.dsize++;
125938032Speter	}
126038032Speter
126164562Sgshapiro	status = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
126264562Sgshapiro	if (status > 0)
126338032Speter	{
126438032Speter		if (!bitset(MF_APPEND, map->map_mflags))
126538032Speter			message("050 Warning: duplicate alias name %s", lhs);
126638032Speter		else
126738032Speter		{
126838032Speter			static char *buf = NULL;
126938032Speter			static int bufsiz = 0;
127038032Speter			auto int xstat;
127138032Speter			datum old;
127238032Speter
127338032Speter			old.dptr = ndbm_map_lookup(map, key.dptr,
127438032Speter						   (char **)NULL, &xstat);
127538032Speter			if (old.dptr != NULL && *(char *) old.dptr != '\0')
127638032Speter			{
127738032Speter				old.dsize = strlen(old.dptr);
127838032Speter				if (data.dsize + old.dsize + 2 > bufsiz)
127938032Speter				{
128038032Speter					if (buf != NULL)
128177349Sgshapiro						sm_free(buf);
128238032Speter					bufsiz = data.dsize + old.dsize + 2;
128338032Speter					buf = xalloc(bufsiz);
128438032Speter				}
128538032Speter				snprintf(buf, bufsiz, "%s,%s",
128638032Speter					data.dptr, old.dptr);
128738032Speter				data.dsize = data.dsize + old.dsize + 1;
128838032Speter				data.dptr = buf;
128938032Speter				if (tTd(38, 9))
129064562Sgshapiro					dprintf("ndbm_map_store append=%s\n",
129164562Sgshapiro						data.dptr);
129238032Speter			}
129338032Speter		}
129464562Sgshapiro		status = dbm_store((DBM *) map->map_db1,
129564562Sgshapiro				   key, data, DBM_REPLACE);
129638032Speter	}
129764562Sgshapiro	if (status != 0)
129864562Sgshapiro		syserr("readaliases: dbm put (%s): %d", lhs, status);
129938032Speter}
130038032Speter
130138032Speter
130238032Speter/*
130338032Speter**  NDBM_MAP_CLOSE -- close the database
130438032Speter*/
130538032Speter
130638032Spetervoid
130738032Speterndbm_map_close(map)
130838032Speter	register MAP  *map;
130938032Speter{
131038032Speter	if (tTd(38, 9))
131164562Sgshapiro		dprintf("ndbm_map_close(%s, %s, %lx)\n",
131238032Speter			map->map_mname, map->map_file, map->map_mflags);
131338032Speter
131438032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
131538032Speter	{
131664562Sgshapiro# ifdef NDBM_YP_COMPAT
131738032Speter		bool inclnull;
131842575Speter		char buf[MAXHOSTNAMELEN];
131938032Speter
132038032Speter		inclnull = bitset(MF_INCLNULL, map->map_mflags);
132138032Speter		map->map_mflags &= ~MF_INCLNULL;
132238032Speter
132338032Speter		if (strstr(map->map_file, "/yp/") != NULL)
132438032Speter		{
132538032Speter			long save_mflags = map->map_mflags;
132638032Speter
132738032Speter			map->map_mflags |= MF_NOFOLDCASE;
132838032Speter
132938032Speter			(void) snprintf(buf, sizeof buf, "%010ld", curtime());
133038032Speter			ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
133138032Speter
133238032Speter			(void) gethostname(buf, sizeof buf);
133338032Speter			ndbm_map_store(map, "YP_MASTER_NAME", buf);
133438032Speter
133538032Speter			map->map_mflags = save_mflags;
133638032Speter		}
133738032Speter
133838032Speter		if (inclnull)
133938032Speter			map->map_mflags |= MF_INCLNULL;
134064562Sgshapiro# endif /* NDBM_YP_COMPAT */
134138032Speter
134238032Speter		/* write out the distinguished alias */
134338032Speter		ndbm_map_store(map, "@", "@");
134438032Speter	}
134538032Speter	dbm_close((DBM *) map->map_db1);
134638032Speter
134738032Speter	/* release lock (if needed) */
134864562Sgshapiro# if !LOCK_ON_OPEN
134938032Speter	if (map->map_lockfd >= 0)
135038032Speter		(void) close(map->map_lockfd);
135164562Sgshapiro# endif /* !LOCK_ON_OPEN */
135238032Speter}
135338032Speter
135464562Sgshapiro#endif /* NDBM */
135538032Speter/*
135638032Speter**  NEWDB (Hash and BTree) Modules
135738032Speter*/
135838032Speter
135938032Speter#ifdef NEWDB
136038032Speter
136138032Speter/*
136238032Speter**  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
136338032Speter**
136438032Speter**	These do rather bizarre locking.  If you can lock on open,
136538032Speter**	do that to avoid the condition of opening a database that
136638032Speter**	is being rebuilt.  If you don't, we'll try to fake it, but
136738032Speter**	there will be a race condition.  If opening for read-only,
136838032Speter**	we immediately release the lock to avoid freezing things up.
136938032Speter**	We really ought to hold the lock, but guarantee that we won't
137038032Speter**	be pokey about it.  That's hard to do.
137138032Speter*/
137238032Speter
137338032Speter/* these should be K line arguments */
137464562Sgshapiro# if DB_VERSION_MAJOR < 2
137564562Sgshapiro#  define db_cachesize	cachesize
137664562Sgshapiro#  define h_nelem	nelem
137764562Sgshapiro#  ifndef DB_CACHE_SIZE
137864562Sgshapiro#   define DB_CACHE_SIZE	(1024 * 1024)	/* database memory cache size */
137964562Sgshapiro#  endif /* ! DB_CACHE_SIZE */
138064562Sgshapiro#  ifndef DB_HASH_NELEM
138164562Sgshapiro#   define DB_HASH_NELEM	4096		/* (starting) size of hash table */
138264562Sgshapiro#  endif /* ! DB_HASH_NELEM */
138364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
138438032Speter
138538032Speterbool
138638032Speterbt_map_open(map, mode)
138738032Speter	MAP *map;
138838032Speter	int mode;
138938032Speter{
139064562Sgshapiro# if DB_VERSION_MAJOR < 2
139138032Speter	BTREEINFO btinfo;
139264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
139364562Sgshapiro# if DB_VERSION_MAJOR == 2
139438032Speter	DB_INFO btinfo;
139564562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
139664562Sgshapiro# if DB_VERSION_MAJOR > 2
139764562Sgshapiro	void *btinfo = NULL;
139864562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
139938032Speter
140038032Speter	if (tTd(38, 2))
140164562Sgshapiro		dprintf("bt_map_open(%s, %s, %d)\n",
140238032Speter			map->map_mname, map->map_file, mode);
140338032Speter
140464562Sgshapiro# if DB_VERSION_MAJOR < 3
140564562Sgshapiro	memset(&btinfo, '\0', sizeof btinfo);
140664562Sgshapiro#  ifdef DB_CACHE_SIZE
140738032Speter	btinfo.db_cachesize = DB_CACHE_SIZE;
140864562Sgshapiro#  endif /* DB_CACHE_SIZE */
140964562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
141064562Sgshapiro
141138032Speter	return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
141238032Speter}
141338032Speter
141438032Speterbool
141538032Speterhash_map_open(map, mode)
141638032Speter	MAP *map;
141738032Speter	int mode;
141838032Speter{
141964562Sgshapiro# if DB_VERSION_MAJOR < 2
142038032Speter	HASHINFO hinfo;
142164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
142264562Sgshapiro# if DB_VERSION_MAJOR == 2
142338032Speter	DB_INFO hinfo;
142464562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
142564562Sgshapiro# if DB_VERSION_MAJOR > 2
142664562Sgshapiro	void *hinfo = NULL;
142764562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
142838032Speter
142938032Speter	if (tTd(38, 2))
143064562Sgshapiro		dprintf("hash_map_open(%s, %s, %d)\n",
143138032Speter			map->map_mname, map->map_file, mode);
143238032Speter
143364562Sgshapiro# if DB_VERSION_MAJOR < 3
143464562Sgshapiro	memset(&hinfo, '\0', sizeof hinfo);
143564562Sgshapiro#  ifdef DB_HASH_NELEM
143638032Speter	hinfo.h_nelem = DB_HASH_NELEM;
143764562Sgshapiro#  endif /* DB_HASH_NELEM */
143864562Sgshapiro#  ifdef DB_CACHE_SIZE
143938032Speter	hinfo.db_cachesize = DB_CACHE_SIZE;
144064562Sgshapiro#  endif /* DB_CACHE_SIZE */
144164562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
144264562Sgshapiro
144338032Speter	return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
144438032Speter}
144538032Speter
144664562Sgshapirostatic bool
144738032Speterdb_map_open(map, mode, mapclassname, dbtype, openinfo)
144838032Speter	MAP *map;
144938032Speter	int mode;
145038032Speter	char *mapclassname;
145138032Speter	DBTYPE dbtype;
145264562Sgshapiro# if DB_VERSION_MAJOR < 2
145338032Speter	const void *openinfo;
145464562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
145564562Sgshapiro# if DB_VERSION_MAJOR == 2
145638032Speter	DB_INFO *openinfo;
145764562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
145864562Sgshapiro# if DB_VERSION_MAJOR > 2
145964562Sgshapiro	void **openinfo;
146064562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
146138032Speter{
146238032Speter	DB *db = NULL;
146338032Speter	int i;
146438032Speter	int omode;
146538032Speter	int smode = S_IREAD;
146638032Speter	int fd;
146764562Sgshapiro	long sff;
146864562Sgshapiro	int save_errno;
146938032Speter	struct stat st;
147038032Speter	char buf[MAXNAME + 1];
147138032Speter
147238032Speter	/* do initial file and directory checks */
147364562Sgshapiro	(void) strlcpy(buf, map->map_file, sizeof buf - 3);
147438032Speter	i = strlen(buf);
147538032Speter	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
147664562Sgshapiro		(void) strlcat(buf, ".db", sizeof buf);
147738032Speter
147838032Speter	mode &= O_ACCMODE;
147938032Speter	omode = mode;
148038032Speter
148138032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
148238032Speter	if (mode == O_RDWR)
148338032Speter	{
148438032Speter		sff |= SFF_CREAT;
148564562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
148638032Speter			sff |= SFF_NOSLINK;
148764562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
148838032Speter			sff |= SFF_NOHLINK;
148938032Speter		smode = S_IWRITE;
149038032Speter	}
149138032Speter	else
149238032Speter	{
149364562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
149438032Speter			sff |= SFF_NOWLINK;
149538032Speter	}
149664562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
149738032Speter		sff |= SFF_SAFEDIRPATH;
149838032Speter	i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
149964562Sgshapiro
150064562Sgshapiro# if !_FFR_REMOVE_AUTOREBUILD
150138032Speter	if (i == ENOENT && AutoRebuild &&
150238032Speter	    bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
150338032Speter	    (bitset(MF_IMPL_HASH, map->map_mflags) ||
150438032Speter	     bitset(MF_ALIAS, map->map_mflags)) &&
150538032Speter	    mode == O_RDONLY)
150638032Speter	{
150738032Speter		bool impl = bitset(MF_IMPL_HASH, map->map_mflags);
150838032Speter
150938032Speter		/* may be able to rebuild */
151038032Speter		map->map_mflags &= ~MF_IMPL_HASH;
151138032Speter		if (!rebuildaliases(map, TRUE))
151238032Speter			return FALSE;
151338032Speter		if (impl)
151438032Speter			return impl_map_open(map, O_RDONLY);
151538032Speter		else
151638032Speter			return db_map_open(map, O_RDONLY, mapclassname,
151738032Speter					   dbtype, openinfo);
151838032Speter	}
151964562Sgshapiro# endif /* !_FFR_REMOVE_AUTOREBUILD */
152038032Speter
152138032Speter	if (i != 0)
152238032Speter	{
152338032Speter		char *prob = "unsafe";
152438032Speter
152538032Speter		/* cannot open this map */
152638032Speter		if (i == ENOENT)
152738032Speter			prob = "missing";
152838032Speter		if (tTd(38, 2))
152964562Sgshapiro			dprintf("\t%s map file: %s\n", prob, errstring(i));
153038032Speter		errno = i;
153138032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
153238032Speter			syserr("%s map \"%s\": %s map file %s",
153338032Speter				mapclassname, map->map_mname, prob, buf);
153438032Speter		return FALSE;
153538032Speter	}
153638032Speter	if (st.st_mode == ST_MODE_NOFILE)
153738032Speter		omode |= O_CREAT|O_EXCL;
153838032Speter
153938032Speter	map->map_lockfd = -1;
154038032Speter
154164562Sgshapiro# if LOCK_ON_OPEN
154238032Speter	if (mode == O_RDWR)
154338032Speter		omode |= O_TRUNC|O_EXLOCK;
154438032Speter	else
154538032Speter		omode |= O_SHLOCK;
154664562Sgshapiro# else /* LOCK_ON_OPEN */
154738032Speter	/*
154838032Speter	**  Pre-lock the file to avoid race conditions.  In particular,
154938032Speter	**  since dbopen returns NULL if the file is zero length, we
155038032Speter	**  must have a locked instance around the dbopen.
155138032Speter	*/
155238032Speter
155338032Speter	fd = open(buf, omode, DBMMODE);
155438032Speter	if (fd < 0)
155538032Speter	{
155638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
155738032Speter			syserr("db_map_open: cannot pre-open database %s", buf);
155838032Speter		return FALSE;
155938032Speter	}
156038032Speter
156138032Speter	/* make sure no baddies slipped in just before the open... */
156238032Speter	if (filechanged(buf, fd, &st))
156338032Speter	{
156464562Sgshapiro		save_errno = errno;
156538032Speter		(void) close(fd);
156638032Speter		errno = save_errno;
156738032Speter		syserr("db_map_open(%s): file changed after pre-open", buf);
156838032Speter		return FALSE;
156938032Speter	}
157038032Speter
157138032Speter	/* if new file, get the "before" bits for later filechanged check */
157238032Speter	if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
157338032Speter	{
157464562Sgshapiro		save_errno = errno;
157538032Speter		(void) close(fd);
157638032Speter		errno = save_errno;
157738032Speter		syserr("db_map_open(%s): cannot fstat pre-opened file",
157838032Speter			buf);
157938032Speter		return FALSE;
158038032Speter	}
158138032Speter
158238032Speter	/* actually lock the pre-opened file */
158338032Speter	if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
158438032Speter		syserr("db_map_open: cannot lock %s", buf);
158538032Speter
158638032Speter	/* set up mode bits for dbopen */
158738032Speter	if (mode == O_RDWR)
158838032Speter		omode |= O_TRUNC;
158938032Speter	omode &= ~(O_EXCL|O_CREAT);
159064562Sgshapiro# endif /* LOCK_ON_OPEN */
159138032Speter
159264562Sgshapiro# if DB_VERSION_MAJOR < 2
159338032Speter	db = dbopen(buf, omode, DBMMODE, dbtype, openinfo);
159464562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
159538032Speter	{
159638032Speter		int flags = 0;
159764562Sgshapiro#  if DB_VERSION_MAJOR > 2
159864562Sgshapiro		int ret;
159964562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
160038032Speter
160138032Speter		if (mode == O_RDONLY)
160238032Speter			flags |= DB_RDONLY;
160338032Speter		if (bitset(O_CREAT, omode))
160438032Speter			flags |= DB_CREATE;
160538032Speter		if (bitset(O_TRUNC, omode))
160638032Speter			flags |= DB_TRUNCATE;
160738032Speter
160864562Sgshapiro#  if !HASFLOCK && defined(DB_FCNTL_LOCKING)
160964562Sgshapiro		flags |= DB_FCNTL_LOCKING;
161064562Sgshapiro#  endif /* !HASFLOCK && defined(DB_FCNTL_LOCKING) */
161164562Sgshapiro
161264562Sgshapiro#  if DB_VERSION_MAJOR > 2
161364562Sgshapiro		ret = db_create(&db, NULL, 0);
161464562Sgshapiro#  ifdef DB_CACHE_SIZE
161564562Sgshapiro		if (ret == 0 && db != NULL)
161664562Sgshapiro		{
161764562Sgshapiro			ret = db->set_cachesize(db, 0, DB_CACHE_SIZE, 0);
161864562Sgshapiro			if (ret != 0)
161964562Sgshapiro			{
162064562Sgshapiro				(void) db->close(db, 0);
162164562Sgshapiro				db = NULL;
162264562Sgshapiro			}
162364562Sgshapiro		}
162464562Sgshapiro#  endif /* DB_CACHE_SIZE */
162564562Sgshapiro#  ifdef DB_HASH_NELEM
162664562Sgshapiro		if (dbtype == DB_HASH && ret == 0 && db != NULL)
162764562Sgshapiro		{
162864562Sgshapiro			ret = db->set_h_nelem(db, DB_HASH_NELEM);
162964562Sgshapiro			if (ret != 0)
163064562Sgshapiro			{
163164562Sgshapiro				(void) db->close(db, 0);
163264562Sgshapiro				db = NULL;
163364562Sgshapiro			}
163464562Sgshapiro		}
163564562Sgshapiro#  endif /* DB_HASH_NELEM */
163664562Sgshapiro		if (ret == 0 && db != NULL)
163764562Sgshapiro		{
163864562Sgshapiro			ret = db->open(db, buf, NULL, dbtype, flags, DBMMODE);
163964562Sgshapiro			if (ret != 0)
164064562Sgshapiro			{
164173188Sgshapiro#ifdef DB_OLD_VERSION
164273188Sgshapiro				if (ret == DB_OLD_VERSION)
164373188Sgshapiro					ret = EINVAL;
164473188Sgshapiro#endif /* DB_OLD_VERSION */
164564562Sgshapiro				(void) db->close(db, 0);
164664562Sgshapiro				db = NULL;
164764562Sgshapiro			}
164864562Sgshapiro		}
164964562Sgshapiro		errno = ret;
165064562Sgshapiro#  else /* DB_VERSION_MAJOR > 2 */
165138032Speter		errno = db_open(buf, dbtype, flags, DBMMODE,
165238032Speter				NULL, openinfo, &db);
165364562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
165438032Speter	}
165564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
165664562Sgshapiro	save_errno = errno;
165738032Speter
165864562Sgshapiro# if !LOCK_ON_OPEN
165938032Speter	if (mode == O_RDWR)
166038032Speter		map->map_lockfd = fd;
166138032Speter	else
166238032Speter		(void) close(fd);
166364562Sgshapiro# endif /* !LOCK_ON_OPEN */
166438032Speter
166538032Speter	if (db == NULL)
166638032Speter	{
166738032Speter		if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
166838032Speter		    aliaswait(map, ".db", FALSE))
166938032Speter			return TRUE;
167064562Sgshapiro# if !LOCK_ON_OPEN
167138032Speter		if (map->map_lockfd >= 0)
167238032Speter			(void) close(map->map_lockfd);
167364562Sgshapiro# endif /* !LOCK_ON_OPEN */
167464562Sgshapiro		errno = save_errno;
167538032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
167638032Speter			syserr("Cannot open %s database %s",
167738032Speter				mapclassname, buf);
167838032Speter		return FALSE;
167938032Speter	}
168038032Speter
168164562Sgshapiro# if DB_VERSION_MAJOR < 2
168238032Speter	fd = db->fd(db);
168364562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
168438032Speter	fd = -1;
168538032Speter	errno = db->fd(db, &fd);
168664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
168738032Speter	if (filechanged(buf, fd, &st))
168838032Speter	{
168964562Sgshapiro		save_errno = errno;
169064562Sgshapiro# if DB_VERSION_MAJOR < 2
169164562Sgshapiro		(void) db->close(db);
169264562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
169338032Speter		errno = db->close(db, 0);
169464562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
169564562Sgshapiro# if !LOCK_ON_OPEN
169638032Speter		if (map->map_lockfd >= 0)
169764562Sgshapiro			(void) close(map->map_lockfd);
169864562Sgshapiro# endif /* !LOCK_ON_OPEN */
169938032Speter		errno = save_errno;
170038032Speter		syserr("db_map_open(%s): file changed after open", buf);
170138032Speter		return FALSE;
170238032Speter	}
170338032Speter
170438032Speter	if (mode == O_RDWR)
170538032Speter		map->map_mflags |= MF_LOCKED;
170664562Sgshapiro# if LOCK_ON_OPEN
170738032Speter	if (fd >= 0 && mode == O_RDONLY)
170838032Speter	{
170938032Speter		(void) lockfile(fd, buf, NULL, LOCK_UN);
171038032Speter	}
171164562Sgshapiro# endif /* LOCK_ON_OPEN */
171238032Speter
171338032Speter	/* try to make sure that at least the database header is on disk */
171438032Speter	if (mode == O_RDWR)
171538032Speter	{
171638032Speter		(void) db->sync(db, 0);
171742575Speter		if (geteuid() == 0 && TrustedUid != 0)
171838032Speter		{
171964562Sgshapiro#  if HASFCHOWN
172042575Speter			if (fchown(fd, TrustedUid, -1) < 0)
172138032Speter			{
172238032Speter				int err = errno;
172338032Speter
172438032Speter				sm_syslog(LOG_ALERT, NOQID,
172538032Speter					  "ownership change on %s failed: %s",
172638032Speter					  buf, errstring(err));
172738032Speter				message("050 ownership change on %s failed: %s",
172838032Speter					buf, errstring(err));
172938032Speter			}
173064562Sgshapiro#  endif /* HASFCHOWN */
173138032Speter		}
173238032Speter	}
173338032Speter
173464562Sgshapiro	map->map_db2 = (ARBPTR_T) db;
173564562Sgshapiro
173664562Sgshapiro	/*
173764562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
173864562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
173964562Sgshapiro	**  map_mtime to be set
174064562Sgshapiro	*/
174164562Sgshapiro
174238032Speter	if (fd >= 0 && fstat(fd, &st) >= 0)
174338032Speter		map->map_mtime = st.st_mtime;
174438032Speter
174538032Speter	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
174638032Speter	    !aliaswait(map, ".db", TRUE))
174738032Speter		return FALSE;
174838032Speter	return TRUE;
174938032Speter}
175038032Speter
175138032Speter
175238032Speter/*
175338032Speter**  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
175438032Speter*/
175538032Speter
175638032Speterchar *
175738032Speterdb_map_lookup(map, name, av, statp)
175838032Speter	MAP *map;
175938032Speter	char *name;
176038032Speter	char **av;
176138032Speter	int *statp;
176238032Speter{
176338032Speter	DBT key, val;
176438032Speter	register DB *db = (DB *) map->map_db2;
176538032Speter	int i;
176638032Speter	int st;
176764562Sgshapiro	int save_errno;
176838032Speter	int fd;
176938032Speter	struct stat stbuf;
177038032Speter	char keybuf[MAXNAME + 1];
177138032Speter	char buf[MAXNAME + 1];
177238032Speter
177364562Sgshapiro	memset(&key, '\0', sizeof key);
177464562Sgshapiro	memset(&val, '\0', sizeof val);
177538032Speter
177638032Speter	if (tTd(38, 20))
177764562Sgshapiro		dprintf("db_map_lookup(%s, %s)\n",
177838032Speter			map->map_mname, name);
177938032Speter
178038032Speter	i = strlen(map->map_file);
178138032Speter	if (i > MAXNAME)
178238032Speter		i = MAXNAME;
178364562Sgshapiro	(void) strlcpy(buf, map->map_file, i + 1);
178438032Speter	if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
178538032Speter		buf[i - 3] = '\0';
178638032Speter
178738032Speter	key.size = strlen(name);
178838032Speter	if (key.size > sizeof keybuf - 1)
178938032Speter		key.size = sizeof keybuf - 1;
179038032Speter	key.data = keybuf;
179164562Sgshapiro	memmove(keybuf, name, key.size);
179238032Speter	keybuf[key.size] = '\0';
179338032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
179438032Speter		makelower(keybuf);
179538032Speter  lockdb:
179664562Sgshapiro# if DB_VERSION_MAJOR < 2
179738032Speter	fd = db->fd(db);
179864562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
179938032Speter	fd = -1;
180038032Speter	errno = db->fd(db, &fd);
180164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
180238032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
180338032Speter		(void) lockfile(fd, buf, ".db", LOCK_SH);
180438032Speter	if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
180538032Speter	{
180638032Speter		/* Reopen the database to sync the cache */
180738032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
180838032Speter								 : O_RDONLY;
180938032Speter
181064562Sgshapiro		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
181164562Sgshapiro			(void) lockfile(fd, buf, ".db", LOCK_UN);
181277349Sgshapiro		map->map_mflags |= MF_CLOSING;
181338032Speter		map->map_class->map_close(map);
181477349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
181538032Speter		if (map->map_class->map_open(map, omode))
181638032Speter		{
181738032Speter			map->map_mflags |= MF_OPEN;
181842575Speter			map->map_pid = getpid();
181938032Speter			if ((omode && O_ACCMODE) == O_RDWR)
182038032Speter				map->map_mflags |= MF_WRITABLE;
182138032Speter			db = (DB *) map->map_db2;
182238032Speter			goto lockdb;
182338032Speter		}
182438032Speter		else
182538032Speter		{
182638032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
182738032Speter			{
182838032Speter				extern MAPCLASS BogusMapClass;
182938032Speter
183038032Speter				*statp = EX_TEMPFAIL;
183138032Speter				map->map_class = &BogusMapClass;
183238032Speter				map->map_mflags |= MF_OPEN;
183342575Speter				map->map_pid = getpid();
183438032Speter				syserr("Cannot reopen DB database %s",
183538032Speter					map->map_file);
183638032Speter			}
183738032Speter			return NULL;
183838032Speter		}
183938032Speter	}
184038032Speter
184138032Speter	st = 1;
184238032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
184338032Speter	{
184464562Sgshapiro# if DB_VERSION_MAJOR < 2
184538032Speter		st = db->get(db, &key, &val, 0);
184664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
184738032Speter		errno = db->get(db, NULL, &key, &val, 0);
184838032Speter		switch (errno)
184938032Speter		{
185038032Speter		  case DB_NOTFOUND:
185138032Speter		  case DB_KEYEMPTY:
185238032Speter			st = 1;
185338032Speter			break;
185438032Speter
185538032Speter		  case 0:
185638032Speter			st = 0;
185738032Speter			break;
185838032Speter
185938032Speter		  default:
186038032Speter			st = -1;
186138032Speter			break;
186238032Speter		}
186364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
186438032Speter		if (st == 0)
186538032Speter			map->map_mflags &= ~MF_TRY1NULL;
186638032Speter	}
186738032Speter	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
186838032Speter	{
186938032Speter		key.size++;
187064562Sgshapiro# if DB_VERSION_MAJOR < 2
187138032Speter		st = db->get(db, &key, &val, 0);
187264562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
187338032Speter		errno = db->get(db, NULL, &key, &val, 0);
187438032Speter		switch (errno)
187538032Speter		{
187638032Speter		  case DB_NOTFOUND:
187738032Speter		  case DB_KEYEMPTY:
187838032Speter			st = 1;
187938032Speter			break;
188038032Speter
188138032Speter		  case 0:
188238032Speter			st = 0;
188338032Speter			break;
188438032Speter
188538032Speter		  default:
188638032Speter			st = -1;
188738032Speter			break;
188838032Speter		}
188964562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
189038032Speter		if (st == 0)
189138032Speter			map->map_mflags &= ~MF_TRY0NULL;
189238032Speter	}
189364562Sgshapiro	save_errno = errno;
189438032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
189538032Speter		(void) lockfile(fd, buf, ".db", LOCK_UN);
189638032Speter	if (st != 0)
189738032Speter	{
189864562Sgshapiro		errno = save_errno;
189938032Speter		if (st < 0)
190038032Speter			syserr("db_map_lookup: get (%s)", name);
190138032Speter		return NULL;
190238032Speter	}
190338032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
190438032Speter		return map_rewrite(map, name, strlen(name), NULL);
190538032Speter	else
190638032Speter		return map_rewrite(map, val.data, val.size, av);
190738032Speter}
190838032Speter
190938032Speter
191038032Speter/*
191138032Speter**  DB_MAP_STORE -- store a datum in the NEWDB database
191238032Speter*/
191338032Speter
191438032Spetervoid
191538032Speterdb_map_store(map, lhs, rhs)
191638032Speter	register MAP *map;
191738032Speter	char *lhs;
191838032Speter	char *rhs;
191938032Speter{
192064562Sgshapiro	int status;
192138032Speter	DBT key;
192238032Speter	DBT data;
192338032Speter	register DB *db = map->map_db2;
192438032Speter	char keybuf[MAXNAME + 1];
192538032Speter
192664562Sgshapiro	memset(&key, '\0', sizeof key);
192764562Sgshapiro	memset(&data, '\0', sizeof data);
192838032Speter
192938032Speter	if (tTd(38, 12))
193064562Sgshapiro		dprintf("db_map_store(%s, %s, %s)\n",
193138032Speter			map->map_mname, lhs, rhs);
193238032Speter
193338032Speter	key.size = strlen(lhs);
193438032Speter	key.data = lhs;
193538032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
193638032Speter	{
193738032Speter		if (key.size > sizeof keybuf - 1)
193838032Speter			key.size = sizeof keybuf - 1;
193964562Sgshapiro		memmove(keybuf, key.data, key.size);
194038032Speter		keybuf[key.size] = '\0';
194138032Speter		makelower(keybuf);
194238032Speter		key.data = keybuf;
194338032Speter	}
194438032Speter
194538032Speter	data.size = strlen(rhs);
194638032Speter	data.data = rhs;
194738032Speter
194838032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
194938032Speter	{
195038032Speter		key.size++;
195138032Speter		data.size++;
195238032Speter	}
195338032Speter
195464562Sgshapiro# if DB_VERSION_MAJOR < 2
195564562Sgshapiro	status = db->put(db, &key, &data, R_NOOVERWRITE);
195664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
195738032Speter	errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE);
195838032Speter	switch (errno)
195938032Speter	{
196038032Speter	  case DB_KEYEXIST:
196164562Sgshapiro		status = 1;
196238032Speter		break;
196338032Speter
196438032Speter	  case 0:
196564562Sgshapiro		status = 0;
196638032Speter		break;
196738032Speter
196838032Speter	  default:
196964562Sgshapiro		status = -1;
197038032Speter		break;
197138032Speter	}
197264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
197364562Sgshapiro	if (status > 0)
197438032Speter	{
197538032Speter		if (!bitset(MF_APPEND, map->map_mflags))
197638032Speter			message("050 Warning: duplicate alias name %s", lhs);
197738032Speter		else
197838032Speter		{
197938032Speter			static char *buf = NULL;
198038032Speter			static int bufsiz = 0;
198138032Speter			DBT old;
198238032Speter
198364562Sgshapiro			memset(&old, '\0', sizeof old);
198438032Speter
198564562Sgshapiro			old.data = db_map_lookup(map, key.data,
198664562Sgshapiro						 (char **)NULL, &status);
198738032Speter			if (old.data != NULL)
198838032Speter			{
198938032Speter				old.size = strlen(old.data);
199064562Sgshapiro				if (data.size + old.size + 2 > (size_t)bufsiz)
199138032Speter				{
199238032Speter					if (buf != NULL)
199377349Sgshapiro						sm_free(buf);
199438032Speter					bufsiz = data.size + old.size + 2;
199538032Speter					buf = xalloc(bufsiz);
199638032Speter				}
199738032Speter				snprintf(buf, bufsiz, "%s,%s",
199838032Speter					(char *) data.data, (char *) old.data);
199938032Speter				data.size = data.size + old.size + 1;
200038032Speter				data.data = buf;
200138032Speter				if (tTd(38, 9))
200264562Sgshapiro					dprintf("db_map_store append=%s\n",
200364562Sgshapiro						(char *) data.data);
200438032Speter			}
200538032Speter		}
200664562Sgshapiro# if DB_VERSION_MAJOR < 2
200764562Sgshapiro		status = db->put(db, &key, &data, 0);
200864562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
200964562Sgshapiro		status = errno = db->put(db, NULL, &key, &data, 0);
201064562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
201138032Speter	}
201264562Sgshapiro	if (status != 0)
201338032Speter		syserr("readaliases: db put (%s)", lhs);
201438032Speter}
201538032Speter
201638032Speter
201738032Speter/*
201838032Speter**  DB_MAP_CLOSE -- add distinguished entries and close the database
201938032Speter*/
202038032Speter
202138032Spetervoid
202238032Speterdb_map_close(map)
202338032Speter	MAP *map;
202438032Speter{
202538032Speter	register DB *db = map->map_db2;
202638032Speter
202738032Speter	if (tTd(38, 9))
202864562Sgshapiro		dprintf("db_map_close(%s, %s, %lx)\n",
202938032Speter			map->map_mname, map->map_file, map->map_mflags);
203038032Speter
203138032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
203238032Speter	{
203338032Speter		/* write out the distinguished alias */
203438032Speter		db_map_store(map, "@", "@");
203538032Speter	}
203638032Speter
203738032Speter	(void) db->sync(db, 0);
203838032Speter
203964562Sgshapiro# if !LOCK_ON_OPEN
204038032Speter	if (map->map_lockfd >= 0)
204138032Speter		(void) close(map->map_lockfd);
204264562Sgshapiro# endif /* !LOCK_ON_OPEN */
204338032Speter
204464562Sgshapiro# if DB_VERSION_MAJOR < 2
204538032Speter	if (db->close(db) != 0)
204664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
204742575Speter	/*
204842575Speter	**  Berkeley DB can use internal shared memory
204942575Speter	**  locking for its memory pool.  Closing a map
205042575Speter	**  opened by another process will interfere
205142575Speter	**  with the shared memory and locks of the parent
205242575Speter	**  process leaving things in a bad state.
205343730Speter	*/
205443730Speter
205543730Speter	/*
205642575Speter	**  If this map was not opened by the current
205743730Speter	**  process, do not close the map but recover
205842575Speter	**  the file descriptor.
205942575Speter	*/
206042575Speter	if (map->map_pid != getpid())
206142575Speter	{
206242575Speter		int fd = -1;
206342575Speter
206442575Speter		errno = db->fd(db, &fd);
206542575Speter		if (fd >= 0)
206642575Speter			(void) close(fd);
206742575Speter		return;
206842575Speter	}
206942575Speter
207038032Speter	if ((errno = db->close(db, 0)) != 0)
207164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
207242575Speter		syserr("db_map_close(%s, %s, %lx): db close failure",
207342575Speter			map->map_mname, map->map_file, map->map_mflags);
207438032Speter}
207564562Sgshapiro#endif /* NEWDB */
207638032Speter/*
207738032Speter**  NIS Modules
207838032Speter*/
207938032Speter
208064562Sgshapiro#ifdef NIS
208138032Speter
208238032Speter# ifndef YPERR_BUSY
208338032Speter#  define YPERR_BUSY	16
208464562Sgshapiro# endif /* ! YPERR_BUSY */
208538032Speter
208638032Speter/*
208738032Speter**  NIS_MAP_OPEN -- open DBM map
208838032Speter*/
208938032Speter
209038032Speterbool
209138032Speternis_map_open(map, mode)
209238032Speter	MAP *map;
209338032Speter	int mode;
209438032Speter{
209538032Speter	int yperr;
209638032Speter	register char *p;
209738032Speter	auto char *vp;
209838032Speter	auto int vsize;
209938032Speter
210038032Speter	if (tTd(38, 2))
210164562Sgshapiro		dprintf("nis_map_open(%s, %s, %d)\n",
210238032Speter			map->map_mname, map->map_file, mode);
210338032Speter
210438032Speter	mode &= O_ACCMODE;
210538032Speter	if (mode != O_RDONLY)
210638032Speter	{
210738032Speter		/* issue a pseudo-error message */
210864562Sgshapiro# ifdef ENOSYS
210938032Speter		errno = ENOSYS;
211064562Sgshapiro# else /* ENOSYS */
211164562Sgshapiro#  ifdef EFTYPE
211238032Speter		errno = EFTYPE;
211364562Sgshapiro#  else /* EFTYPE */
211438032Speter		errno = ENXIO;
211564562Sgshapiro#  endif /* EFTYPE */
211664562Sgshapiro# endif /* ENOSYS */
211738032Speter		return FALSE;
211838032Speter	}
211938032Speter
212038032Speter	p = strchr(map->map_file, '@');
212138032Speter	if (p != NULL)
212238032Speter	{
212338032Speter		*p++ = '\0';
212438032Speter		if (*p != '\0')
212538032Speter			map->map_domain = p;
212638032Speter	}
212738032Speter
212838032Speter	if (*map->map_file == '\0')
212938032Speter		map->map_file = "mail.aliases";
213038032Speter
213138032Speter	if (map->map_domain == NULL)
213238032Speter	{
213338032Speter		yperr = yp_get_default_domain(&map->map_domain);
213438032Speter		if (yperr != 0)
213538032Speter		{
213638032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
213764562Sgshapiro				syserr("421 4.3.5 NIS map %s specified, but NIS not running",
213864562Sgshapiro				       map->map_file);
213938032Speter			return FALSE;
214038032Speter		}
214138032Speter	}
214238032Speter
214338032Speter	/* check to see if this map actually exists */
214464562Sgshapiro	vp = NULL;
214538032Speter	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
214638032Speter			&vp, &vsize);
214738032Speter	if (tTd(38, 10))
214864562Sgshapiro		dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n",
214938032Speter			map->map_domain, map->map_file, yperr_string(yperr));
215064562Sgshapiro	if (vp != NULL)
215177349Sgshapiro		sm_free(vp);
215264562Sgshapiro
215338032Speter	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
215438032Speter	{
215538032Speter		/*
215638032Speter		**  We ought to be calling aliaswait() here if this is an
215738032Speter		**  alias file, but powerful HP-UX NIS servers  apparently
215838032Speter		**  don't insert the @:@ token into the alias map when it
215938032Speter		**  is rebuilt, so aliaswait() just hangs.  I hate HP-UX.
216038032Speter		*/
216138032Speter
216264562Sgshapiro# if 0
216338032Speter		if (!bitset(MF_ALIAS, map->map_mflags) ||
216438032Speter		    aliaswait(map, NULL, TRUE))
216564562Sgshapiro# endif /* 0 */
216638032Speter			return TRUE;
216738032Speter	}
216838032Speter
216938032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
217038032Speter	{
217164562Sgshapiro		syserr("421 4.0.0 Cannot bind to map %s in domain %s: %s",
217238032Speter			map->map_file, map->map_domain, yperr_string(yperr));
217338032Speter	}
217438032Speter
217538032Speter	return FALSE;
217638032Speter}
217738032Speter
217838032Speter
217938032Speter/*
218038032Speter**  NIS_MAP_LOOKUP -- look up a datum in a NIS map
218138032Speter*/
218238032Speter
218338032Speter/* ARGSUSED3 */
218438032Speterchar *
218538032Speternis_map_lookup(map, name, av, statp)
218638032Speter	MAP *map;
218738032Speter	char *name;
218838032Speter	char **av;
218938032Speter	int *statp;
219038032Speter{
219138032Speter	char *vp;
219238032Speter	auto int vsize;
219338032Speter	int buflen;
219438032Speter	int yperr;
219538032Speter	char keybuf[MAXNAME + 1];
219638032Speter
219738032Speter	if (tTd(38, 20))
219864562Sgshapiro		dprintf("nis_map_lookup(%s, %s)\n",
219938032Speter			map->map_mname, name);
220038032Speter
220138032Speter	buflen = strlen(name);
220238032Speter	if (buflen > sizeof keybuf - 1)
220338032Speter		buflen = sizeof keybuf - 1;
220464562Sgshapiro	memmove(keybuf, name, buflen);
220538032Speter	keybuf[buflen] = '\0';
220638032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
220738032Speter		makelower(keybuf);
220838032Speter	yperr = YPERR_KEY;
220964562Sgshapiro	vp = NULL;
221038032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
221138032Speter	{
221238032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
221338032Speter			     &vp, &vsize);
221438032Speter		if (yperr == 0)
221538032Speter			map->map_mflags &= ~MF_TRY1NULL;
221638032Speter	}
221738032Speter	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
221838032Speter	{
221964562Sgshapiro		if (vp != NULL)
222064562Sgshapiro		{
222177349Sgshapiro			sm_free(vp);
222264562Sgshapiro			vp = NULL;
222364562Sgshapiro		}
222438032Speter		buflen++;
222538032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
222638032Speter			     &vp, &vsize);
222738032Speter		if (yperr == 0)
222838032Speter			map->map_mflags &= ~MF_TRY0NULL;
222938032Speter	}
223038032Speter	if (yperr != 0)
223138032Speter	{
223238032Speter		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
223338032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
223464562Sgshapiro		if (vp != NULL)
223577349Sgshapiro			sm_free(vp);
223638032Speter		return NULL;
223738032Speter	}
223838032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
223938032Speter		return map_rewrite(map, name, strlen(name), NULL);
224038032Speter	else
224164562Sgshapiro	{
224264562Sgshapiro		char *ret;
224364562Sgshapiro
224464562Sgshapiro		ret = map_rewrite(map, vp, vsize, av);
224564562Sgshapiro		if (vp != NULL)
224677349Sgshapiro			sm_free(vp);
224764562Sgshapiro		return ret;
224864562Sgshapiro	}
224938032Speter}
225038032Speter
225138032Speter
225238032Speter/*
225338032Speter**  NIS_GETCANONNAME -- look up canonical name in NIS
225438032Speter*/
225538032Speter
225664562Sgshapirostatic bool
225738032Speternis_getcanonname(name, hbsize, statp)
225838032Speter	char *name;
225938032Speter	int hbsize;
226038032Speter	int *statp;
226138032Speter{
226238032Speter	char *vp;
226338032Speter	auto int vsize;
226438032Speter	int keylen;
226538032Speter	int yperr;
226638032Speter	static bool try0null = TRUE;
226738032Speter	static bool try1null = TRUE;
226838032Speter	static char *yp_domain = NULL;
226938032Speter	char host_record[MAXLINE];
227038032Speter	char cbuf[MAXNAME];
227138032Speter	char nbuf[MAXNAME + 1];
227238032Speter
227338032Speter	if (tTd(38, 20))
227464562Sgshapiro		dprintf("nis_getcanonname(%s)\n", name);
227538032Speter
227664562Sgshapiro	if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
227738032Speter	{
227838032Speter		*statp = EX_UNAVAILABLE;
227938032Speter		return FALSE;
228038032Speter	}
228173188Sgshapiro	(void) shorten_hostname(nbuf);
228238032Speter	keylen = strlen(nbuf);
228338032Speter
228438032Speter	if (yp_domain == NULL)
228564562Sgshapiro		(void) yp_get_default_domain(&yp_domain);
228638032Speter	makelower(nbuf);
228738032Speter	yperr = YPERR_KEY;
228864562Sgshapiro	vp = NULL;
228938032Speter	if (try0null)
229038032Speter	{
229138032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
229238032Speter			     &vp, &vsize);
229338032Speter		if (yperr == 0)
229438032Speter			try1null = FALSE;
229538032Speter	}
229638032Speter	if (yperr == YPERR_KEY && try1null)
229738032Speter	{
229864562Sgshapiro		if (vp != NULL)
229964562Sgshapiro		{
230077349Sgshapiro			sm_free(vp);
230164562Sgshapiro			vp = NULL;
230264562Sgshapiro		}
230338032Speter		keylen++;
230438032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
230538032Speter			     &vp, &vsize);
230638032Speter		if (yperr == 0)
230738032Speter			try0null = FALSE;
230838032Speter	}
230938032Speter	if (yperr != 0)
231038032Speter	{
231138032Speter		if (yperr == YPERR_KEY)
231238032Speter			*statp = EX_NOHOST;
231338032Speter		else if (yperr == YPERR_BUSY)
231438032Speter			*statp = EX_TEMPFAIL;
231538032Speter		else
231638032Speter			*statp = EX_UNAVAILABLE;
231764562Sgshapiro		if (vp != NULL)
231877349Sgshapiro			sm_free(vp);
231938032Speter		return FALSE;
232038032Speter	}
232164562Sgshapiro	(void) strlcpy(host_record, vp, sizeof host_record);
232277349Sgshapiro	sm_free(vp);
232338032Speter	if (tTd(38, 44))
232464562Sgshapiro		dprintf("got record `%s'\n", host_record);
232573188Sgshapiro	if (!extract_canonname(nbuf, NULL, host_record, cbuf, sizeof cbuf))
232638032Speter	{
232738032Speter		/* this should not happen, but.... */
232838032Speter		*statp = EX_NOHOST;
232938032Speter		return FALSE;
233038032Speter	}
233173188Sgshapiro	if (hbsize <= strlen(cbuf))
233238032Speter	{
233338032Speter		*statp = EX_UNAVAILABLE;
233438032Speter		return FALSE;
233538032Speter	}
233664562Sgshapiro	(void) strlcpy(name, cbuf, hbsize);
233738032Speter	*statp = EX_OK;
233838032Speter	return TRUE;
233938032Speter}
234038032Speter
234164562Sgshapiro#endif /* NIS */
234238032Speter/*
234338032Speter**  NISPLUS Modules
234438032Speter**
234538032Speter**	This code donated by Sun Microsystems.
234638032Speter*/
234738032Speter
234838032Speter#ifdef NISPLUS
234938032Speter
235064562Sgshapiro# undef NIS		/* symbol conflict in nis.h */
235164562Sgshapiro# undef T_UNSPEC	/* symbol conflict in nis.h -> ... -> sys/tiuser.h */
235264562Sgshapiro# include <rpcsvc/nis.h>
235364562Sgshapiro# include <rpcsvc/nislib.h>
235438032Speter
235564562Sgshapiro# define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
235664562Sgshapiro# define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
235764562Sgshapiro# define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
235864562Sgshapiro# define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
235938032Speter
236038032Speter/*
236138032Speter**  NISPLUS_MAP_OPEN -- open nisplus table
236238032Speter*/
236338032Speter
236438032Speterbool
236538032Speternisplus_map_open(map, mode)
236638032Speter	MAP *map;
236738032Speter	int mode;
236838032Speter{
236938032Speter	nis_result *res = NULL;
237038032Speter	int retry_cnt, max_col, i;
237138032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
237238032Speter
237338032Speter	if (tTd(38, 2))
237464562Sgshapiro		dprintf("nisplus_map_open(%s, %s, %d)\n",
237538032Speter			map->map_mname, map->map_file, mode);
237638032Speter
237738032Speter	mode &= O_ACCMODE;
237838032Speter	if (mode != O_RDONLY)
237938032Speter	{
238038032Speter		errno = EPERM;
238138032Speter		return FALSE;
238238032Speter	}
238338032Speter
238438032Speter	if (*map->map_file == '\0')
238538032Speter		map->map_file = "mail_aliases.org_dir";
238638032Speter
238738032Speter	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
238838032Speter	{
238938032Speter		/* set default NISPLUS Domain to $m */
239038032Speter		map->map_domain = newstr(nisplus_default_domain());
239138032Speter		if (tTd(38, 2))
239264562Sgshapiro			dprintf("nisplus_map_open(%s): using domain %s\n",
239364562Sgshapiro				map->map_file, map->map_domain);
239438032Speter	}
239538032Speter	if (!PARTIAL_NAME(map->map_file))
239638032Speter	{
239738032Speter		map->map_domain = newstr("");
239838032Speter		snprintf(qbuf, sizeof qbuf, "%s", map->map_file);
239938032Speter	}
240038032Speter	else
240138032Speter	{
240238032Speter		/* check to see if this map actually exists */
240338032Speter		snprintf(qbuf, sizeof qbuf, "%s.%s",
240438032Speter			map->map_file, map->map_domain);
240538032Speter	}
240638032Speter
240738032Speter	retry_cnt = 0;
240838032Speter	while (res == NULL || res->status != NIS_SUCCESS)
240938032Speter	{
241038032Speter		res = nis_lookup(qbuf, FOLLOW_LINKS);
241138032Speter		switch (res->status)
241238032Speter		{
241338032Speter		  case NIS_SUCCESS:
241438032Speter			break;
241538032Speter
241638032Speter		  case NIS_TRYAGAIN:
241738032Speter		  case NIS_RPCERROR:
241838032Speter		  case NIS_NAMEUNREACHABLE:
241938032Speter			if (retry_cnt++ > 4)
242038032Speter			{
242138032Speter				errno = EAGAIN;
242238032Speter				return FALSE;
242338032Speter			}
242438032Speter			/* try not to overwhelm hosed server */
242538032Speter			sleep(2);
242638032Speter			break;
242738032Speter
242838032Speter		  default:		/* all other nisplus errors */
242964562Sgshapiro# if 0
243038032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
243164562Sgshapiro				syserr("421 4.0.0 Cannot find table %s.%s: %s",
243238032Speter					map->map_file, map->map_domain,
243338032Speter					nis_sperrno(res->status));
243464562Sgshapiro# endif /* 0 */
243538032Speter			errno = EAGAIN;
243638032Speter			return FALSE;
243738032Speter		}
243838032Speter	}
243938032Speter
244038032Speter	if (NIS_RES_NUMOBJ(res) != 1 ||
244138032Speter	    (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
244238032Speter	{
244338032Speter		if (tTd(38, 10))
244464562Sgshapiro			dprintf("nisplus_map_open: %s is not a table\n", qbuf);
244564562Sgshapiro# if 0
244638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
244764562Sgshapiro			syserr("421 4.0.0 %s.%s: %s is not a table",
244838032Speter				map->map_file, map->map_domain,
244938032Speter				nis_sperrno(res->status));
245064562Sgshapiro# endif /* 0 */
245138032Speter		errno = EBADF;
245238032Speter		return FALSE;
245338032Speter	}
245438032Speter	/* default key column is column 0 */
245538032Speter	if (map->map_keycolnm == NULL)
245638032Speter		map->map_keycolnm = newstr(COL_NAME(res,0));
245738032Speter
245838032Speter	max_col = COL_MAX(res);
245938032Speter
246038032Speter	/* verify the key column exist */
246164562Sgshapiro	for (i = 0; i< max_col; i++)
246238032Speter	{
246364562Sgshapiro		if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0)
246438032Speter			break;
246538032Speter	}
246638032Speter	if (i == max_col)
246738032Speter	{
246838032Speter		if (tTd(38, 2))
246964562Sgshapiro			dprintf("nisplus_map_open(%s): can not find key column %s\n",
247038032Speter				map->map_file, map->map_keycolnm);
247138032Speter		errno = ENOENT;
247238032Speter		return FALSE;
247338032Speter	}
247438032Speter
247538032Speter	/* default value column is the last column */
247638032Speter	if (map->map_valcolnm == NULL)
247738032Speter	{
247838032Speter		map->map_valcolno = max_col - 1;
247938032Speter		return TRUE;
248038032Speter	}
248138032Speter
248264562Sgshapiro	for (i = 0; i< max_col; i++)
248338032Speter	{
248438032Speter		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
248538032Speter		{
248638032Speter			map->map_valcolno = i;
248738032Speter			return TRUE;
248838032Speter		}
248938032Speter	}
249038032Speter
249138032Speter	if (tTd(38, 2))
249264562Sgshapiro		dprintf("nisplus_map_open(%s): can not find column %s\n",
249364562Sgshapiro			map->map_file, map->map_keycolnm);
249438032Speter	errno = ENOENT;
249538032Speter	return FALSE;
249638032Speter}
249738032Speter
249838032Speter
249938032Speter/*
250038032Speter**  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
250138032Speter*/
250238032Speter
250338032Speterchar *
250438032Speternisplus_map_lookup(map, name, av, statp)
250538032Speter	MAP *map;
250638032Speter	char *name;
250738032Speter	char **av;
250838032Speter	int *statp;
250938032Speter{
251038032Speter	char *p;
251138032Speter	auto int vsize;
251238032Speter	char *skp;
251338032Speter	int skleft;
251438032Speter	char search_key[MAXNAME + 4];
251538032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
251638032Speter	nis_result *result;
251738032Speter
251838032Speter	if (tTd(38, 20))
251964562Sgshapiro		dprintf("nisplus_map_lookup(%s, %s)\n",
252038032Speter			map->map_mname, name);
252138032Speter
252238032Speter	if (!bitset(MF_OPEN, map->map_mflags))
252338032Speter	{
252438032Speter		if (nisplus_map_open(map, O_RDONLY))
252542575Speter		{
252638032Speter			map->map_mflags |= MF_OPEN;
252742575Speter			map->map_pid = getpid();
252842575Speter		}
252938032Speter		else
253038032Speter		{
253138032Speter			*statp = EX_UNAVAILABLE;
253238032Speter			return NULL;
253338032Speter		}
253438032Speter	}
253538032Speter
253638032Speter	/*
253738032Speter	**  Copy the name to the key buffer, escaping double quote characters
253838032Speter	**  by doubling them and quoting "]" and "," to avoid having the
253938032Speter	**  NIS+ parser choke on them.
254038032Speter	*/
254138032Speter
254238032Speter	skleft = sizeof search_key - 4;
254338032Speter	skp = search_key;
254438032Speter	for (p = name; *p != '\0' && skleft > 0; p++)
254538032Speter	{
254638032Speter		switch (*p)
254738032Speter		{
254838032Speter		  case ']':
254938032Speter		  case ',':
255038032Speter			/* quote the character */
255138032Speter			*skp++ = '"';
255238032Speter			*skp++ = *p;
255338032Speter			*skp++ = '"';
255438032Speter			skleft -= 3;
255538032Speter			break;
255638032Speter
255738032Speter		  case '"':
255838032Speter			/* double the quote */
255938032Speter			*skp++ = '"';
256038032Speter			skleft--;
256164562Sgshapiro			/* FALLTHROUGH */
256238032Speter
256338032Speter		  default:
256438032Speter			*skp++ = *p;
256538032Speter			skleft--;
256638032Speter			break;
256738032Speter		}
256838032Speter	}
256938032Speter	*skp = '\0';
257038032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
257138032Speter		makelower(search_key);
257238032Speter
257338032Speter	/* construct the query */
257438032Speter	if (PARTIAL_NAME(map->map_file))
257538032Speter		snprintf(qbuf, sizeof qbuf, "[%s=%s],%s.%s",
257638032Speter			map->map_keycolnm, search_key, map->map_file,
257738032Speter			map->map_domain);
257838032Speter	else
257938032Speter		snprintf(qbuf, sizeof qbuf, "[%s=%s],%s",
258038032Speter			map->map_keycolnm, search_key, map->map_file);
258138032Speter
258238032Speter	if (tTd(38, 20))
258364562Sgshapiro		dprintf("qbuf=%s\n", qbuf);
258438032Speter	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
258538032Speter	if (result->status == NIS_SUCCESS)
258638032Speter	{
258738032Speter		int count;
258838032Speter		char *str;
258938032Speter
259038032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
259138032Speter		{
259238032Speter			if (LogLevel > 10)
259338032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
259464562Sgshapiro					  "%s: lookup error, expected 1 entry, got %d",
259564562Sgshapiro					  map->map_file, count);
259638032Speter
259738032Speter			/* ignore second entry */
259838032Speter			if (tTd(38, 20))
259964562Sgshapiro				dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
260038032Speter					name, count);
260138032Speter		}
260238032Speter
260338032Speter		p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
260438032Speter		/* set the length of the result */
260538032Speter		if (p == NULL)
260638032Speter			p = "";
260738032Speter		vsize = strlen(p);
260838032Speter		if (tTd(38, 20))
260964562Sgshapiro			dprintf("nisplus_map_lookup(%s), found %s\n",
261038032Speter				name, p);
261138032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
261238032Speter			str = map_rewrite(map, name, strlen(name), NULL);
261338032Speter		else
261438032Speter			str = map_rewrite(map, p, vsize, av);
261538032Speter		nis_freeresult(result);
261638032Speter		*statp = EX_OK;
261738032Speter		return str;
261838032Speter	}
261938032Speter	else
262038032Speter	{
262138032Speter		if (result->status == NIS_NOTFOUND)
262238032Speter			*statp = EX_NOTFOUND;
262338032Speter		else if (result->status == NIS_TRYAGAIN)
262438032Speter			*statp = EX_TEMPFAIL;
262538032Speter		else
262638032Speter		{
262738032Speter			*statp = EX_UNAVAILABLE;
262838032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
262938032Speter		}
263038032Speter	}
263138032Speter	if (tTd(38, 20))
263264562Sgshapiro		dprintf("nisplus_map_lookup(%s), failed\n", name);
263338032Speter	nis_freeresult(result);
263438032Speter	return NULL;
263538032Speter}
263638032Speter
263738032Speter
263838032Speter
263938032Speter/*
264038032Speter**  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
264138032Speter*/
264238032Speter
264364562Sgshapirostatic bool
264438032Speternisplus_getcanonname(name, hbsize, statp)
264538032Speter	char *name;
264638032Speter	int hbsize;
264738032Speter	int *statp;
264838032Speter{
264938032Speter	char *vp;
265038032Speter	auto int vsize;
265138032Speter	nis_result *result;
265238032Speter	char *p;
265338032Speter	char nbuf[MAXNAME + 1];
265438032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
265538032Speter
265638032Speter	if (strlen(name) >= sizeof nbuf)
265738032Speter	{
265838032Speter		*statp = EX_UNAVAILABLE;
265938032Speter		return FALSE;
266038032Speter	}
266164562Sgshapiro	(void) strlcpy(nbuf, name, sizeof nbuf);
266273188Sgshapiro	(void) shorten_hostname(nbuf);
266338032Speter
266438032Speter	p = strchr(nbuf, '.');
266538032Speter	if (p == NULL)
266638032Speter	{
266738032Speter		/* single token */
266838032Speter		snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir", nbuf);
266938032Speter	}
267038032Speter	else if (p[1] != '\0')
267138032Speter	{
267238032Speter		/* multi token -- take only first token in nbuf */
267338032Speter		*p = '\0';
267438032Speter		snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir.%s",
267538032Speter			nbuf, &p[1]);
267638032Speter	}
267738032Speter	else
267838032Speter	{
267938032Speter		*statp = EX_NOHOST;
268038032Speter		return FALSE;
268138032Speter	}
268238032Speter
268338032Speter	if (tTd(38, 20))
268464562Sgshapiro		dprintf("\nnisplus_getcanoname(%s), qbuf=%s\n",
268564562Sgshapiro			name, qbuf);
268638032Speter
268738032Speter	result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
268838032Speter		NULL, NULL);
268938032Speter
269038032Speter	if (result->status == NIS_SUCCESS)
269138032Speter	{
269238032Speter		int count;
269338032Speter		char *domain;
269438032Speter
269538032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
269638032Speter		{
269738032Speter			if (LogLevel > 10)
269838032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
269964562Sgshapiro					  "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
270064562Sgshapiro					  count);
270138032Speter
270238032Speter			/* ignore second entry */
270338032Speter			if (tTd(38, 20))
270464562Sgshapiro				dprintf("nisplus_getcanoname(%s), got %d entries, all but first ignored\n",
270538032Speter					name, count);
270638032Speter		}
270738032Speter
270838032Speter		if (tTd(38, 20))
270964562Sgshapiro			dprintf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
271064562Sgshapiro				name, (NIS_RES_OBJECT(result))->zo_domain);
271138032Speter
271238032Speter
271338032Speter		vp = ((NIS_RES_OBJECT(result))->EN_col(0));
271438032Speter		vsize = strlen(vp);
271538032Speter		if (tTd(38, 20))
271664562Sgshapiro			dprintf("nisplus_getcanonname(%s), found %s\n",
271738032Speter				name, vp);
271838032Speter		if (strchr(vp, '.') != NULL)
271938032Speter		{
272038032Speter			domain = "";
272138032Speter		}
272238032Speter		else
272338032Speter		{
272438032Speter			domain = macvalue('m', CurEnv);
272538032Speter			if (domain == NULL)
272638032Speter				domain = "";
272738032Speter		}
272838032Speter		if (hbsize > vsize + (int) strlen(domain) + 1)
272938032Speter		{
273038032Speter			if (domain[0] == '\0')
273164562Sgshapiro				(void) strlcpy(name, vp, hbsize);
273238032Speter			else
273338032Speter				snprintf(name, hbsize, "%s.%s", vp, domain);
273438032Speter			*statp = EX_OK;
273538032Speter		}
273638032Speter		else
273738032Speter			*statp = EX_NOHOST;
273838032Speter		nis_freeresult(result);
273938032Speter		return TRUE;
274038032Speter	}
274138032Speter	else
274238032Speter	{
274338032Speter		if (result->status == NIS_NOTFOUND)
274438032Speter			*statp = EX_NOHOST;
274538032Speter		else if (result->status == NIS_TRYAGAIN)
274638032Speter			*statp = EX_TEMPFAIL;
274738032Speter		else
274838032Speter			*statp = EX_UNAVAILABLE;
274938032Speter	}
275038032Speter	if (tTd(38, 20))
275164562Sgshapiro		dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
275238032Speter			name, result->status, *statp);
275338032Speter	nis_freeresult(result);
275438032Speter	return FALSE;
275538032Speter}
275638032Speter
275738032Speterchar *
275838032Speternisplus_default_domain()
275938032Speter{
276038032Speter	static char default_domain[MAXNAME + 1] = "";
276138032Speter	char *p;
276238032Speter
276338032Speter	if (default_domain[0] != '\0')
276464562Sgshapiro		return default_domain;
276538032Speter
276638032Speter	p = nis_local_directory();
276738032Speter	snprintf(default_domain, sizeof default_domain, "%s", p);
276838032Speter	return default_domain;
276938032Speter}
277038032Speter
277138032Speter#endif /* NISPLUS */
277238032Speter/*
277338032Speter**  LDAP Modules
277438032Speter*/
277538032Speter
277664562Sgshapiro/*
277764562Sgshapiro**  LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs
277864562Sgshapiro*/
277964562Sgshapiro
278064562Sgshapiro#if defined(LDAPMAP) || defined(PH_MAP)
278164562Sgshapiro
278264562Sgshapiro# ifdef PH_MAP
278364562Sgshapiro#  define ph_map_dequote ldapmap_dequote
278464562Sgshapiro# endif /* PH_MAP */
278564562Sgshapiro
278664562Sgshapirochar *
278764562Sgshapiroldapmap_dequote(str)
278864562Sgshapiro	char *str;
278964562Sgshapiro{
279064562Sgshapiro	char *p;
279164562Sgshapiro	char *start;
279264562Sgshapiro
279364562Sgshapiro	if (str == NULL)
279464562Sgshapiro		return NULL;
279564562Sgshapiro
279664562Sgshapiro	p = str;
279764562Sgshapiro	if (*p == '"')
279864562Sgshapiro	{
279964562Sgshapiro		/* Should probably swallow initial whitespace here */
280064562Sgshapiro		start = ++p;
280164562Sgshapiro	}
280264562Sgshapiro	else
280364562Sgshapiro		return str;
280464562Sgshapiro	while (*p != '"' && *p != '\0')
280564562Sgshapiro		p++;
280664562Sgshapiro	if (*p != '\0')
280764562Sgshapiro		*p = '\0';
280864562Sgshapiro	return start;
280964562Sgshapiro}
281064562Sgshapiro#endif /* defined(LDAPMAP) || defined(PH_MAP) */
281164562Sgshapiro
281238032Speter#ifdef LDAPMAP
281338032Speter
281464562SgshapiroLDAPMAP_STRUCT *LDAPDefaults = NULL;
281538032Speter
281638032Speter/*
281764562Sgshapiro**  LDAPMAP_OPEN -- open LDAP map
281838032Speter**
281964562Sgshapiro**	Connect to the LDAP server.  Re-use existing connections since a
282064562Sgshapiro**	single server connection to a host (with the same host, port,
282164562Sgshapiro**	bind DN, and secret) can answer queries for multiple maps.
282238032Speter*/
282338032Speter
282438032Speterbool
282564562Sgshapiroldapmap_open(map, mode)
282638032Speter	MAP *map;
282738032Speter	int mode;
282838032Speter{
282964562Sgshapiro	LDAPMAP_STRUCT *lmap;
283064562Sgshapiro	STAB *s;
283164562Sgshapiro
283238032Speter	if (tTd(38, 2))
283366494Sgshapiro		dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode);
283438032Speter
283538032Speter	mode &= O_ACCMODE;
283664562Sgshapiro
283764562Sgshapiro	/* sendmail doesn't have the ability to write to LDAP (yet) */
283838032Speter	if (mode != O_RDONLY)
283938032Speter	{
284038032Speter		/* issue a pseudo-error message */
284164562Sgshapiro# ifdef ENOSYS
284238032Speter		errno = ENOSYS;
284364562Sgshapiro# else /* ENOSYS */
284464562Sgshapiro#  ifdef EFTYPE
284538032Speter		errno = EFTYPE;
284664562Sgshapiro#  else /* EFTYPE */
284738032Speter		errno = ENXIO;
284864562Sgshapiro#  endif /* EFTYPE */
284964562Sgshapiro# endif /* ENOSYS */
285038032Speter		return FALSE;
285138032Speter	}
285264562Sgshapiro
285364562Sgshapiro	/* Comma separate if used as an alias file */
285464562Sgshapiro	if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
285564562Sgshapiro		map->map_coldelim = ',';
285664562Sgshapiro
285764562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
285864562Sgshapiro
285964562Sgshapiro	s = ldapmap_findconn(lmap);
286077349Sgshapiro	if (s->s_lmap != NULL)
286164562Sgshapiro	{
286264562Sgshapiro		/* Already have a connection open to this LDAP server */
286377349Sgshapiro		lmap->ldap_ld = ((LDAPMAP_STRUCT *)s->s_lmap->map_db1)->ldap_ld;
286477349Sgshapiro
286577349Sgshapiro		/* Add this map as head of linked list */
286677349Sgshapiro		lmap->ldap_next = s->s_lmap;
286777349Sgshapiro		s->s_lmap = map;
286877349Sgshapiro
286966494Sgshapiro		if (tTd(38, 2))
287066494Sgshapiro			dprintf("using cached connection\n");
287164562Sgshapiro		return TRUE;
287264562Sgshapiro	}
287364562Sgshapiro
287466494Sgshapiro	if (tTd(38, 2))
287566494Sgshapiro		dprintf("opening new connection\n");
287666494Sgshapiro
287764562Sgshapiro	/* No connection yet, connect */
287864562Sgshapiro	if (!ldapmap_start(map))
287964562Sgshapiro		return FALSE;
288064562Sgshapiro
288164562Sgshapiro	/* Save connection for reuse */
288277349Sgshapiro	s->s_lmap = map;
288338032Speter	return TRUE;
288438032Speter}
288538032Speter
288638032Speter/*
288764562Sgshapiro**  LDAPMAP_START -- actually connect to an LDAP server
288838032Speter**
288964562Sgshapiro**	Parameters:
289064562Sgshapiro**		map -- the map being opened.
289164562Sgshapiro**
289264562Sgshapiro**	Returns:
289364562Sgshapiro**		TRUE if connection is successful, FALSE otherwise.
289464562Sgshapiro**
289564562Sgshapiro**	Side Effects:
289664562Sgshapiro**		Populates lmap->ldap_ld.
289738032Speter*/
289838032Speter
289938032Speterstatic jmp_buf	LDAPTimeout;
290038032Speter
290164562Sgshapirostatic bool
290264562Sgshapiroldapmap_start(map)
290338032Speter	MAP *map;
290438032Speter{
290564562Sgshapiro	register int bind_result;
290664562Sgshapiro	int save_errno;
290764562Sgshapiro	register EVENT *ev = NULL;
290864562Sgshapiro	LDAPMAP_STRUCT *lmap;
290938032Speter	LDAP *ld;
291038032Speter
291138032Speter	if (tTd(38, 2))
291264562Sgshapiro		dprintf("ldapmap_start(%s)\n", map->map_mname);
291338032Speter
291464562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
291538032Speter
291638032Speter	if (tTd(38,9))
291764562Sgshapiro		dprintf("ldapmap_start(%s, %d)\n",
291864562Sgshapiro			lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host,
291964562Sgshapiro			lmap->ldap_port);
292038032Speter
292164562Sgshapiro# if USE_LDAP_INIT
292264562Sgshapiro	ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
292371345Sgshapiro	save_errno = errno;
292464562Sgshapiro# else /* USE_LDAP_INIT */
292564562Sgshapiro	/*
292664562Sgshapiro	**  If using ldap_open(), the actual connection to the server
292764562Sgshapiro	**  happens now so we need the timeout here.  For ldap_init(),
292864562Sgshapiro	**  the connection happens at bind time.
292964562Sgshapiro	*/
293038032Speter
293138032Speter	/* set the timeout */
293264562Sgshapiro	if (lmap->ldap_timeout.tv_sec != 0)
293338032Speter	{
293438032Speter		if (setjmp(LDAPTimeout) != 0)
293538032Speter		{
293638032Speter			if (LogLevel > 1)
293738032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
293864562Sgshapiro					  "timeout conning to LDAP server %.100s",
293964562Sgshapiro					  lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host);
294064562Sgshapiro			return FALSE;
294138032Speter		}
294264562Sgshapiro		ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
294338032Speter	}
294438032Speter
294564562Sgshapiro	ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
294664562Sgshapiro	save_errno = errno;
294742575Speter
294864562Sgshapiro	/* clear the event if it has not sprung */
294964562Sgshapiro	if (ev != NULL)
295042575Speter		clrevent(ev);
295164562Sgshapiro# endif /* USE_LDAP_INIT */
295242575Speter
295364562Sgshapiro	errno = save_errno;
295442575Speter	if (ld == NULL)
295538032Speter	{
295638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
295738032Speter		{
295864562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
295964562Sgshapiro				syserr("%s failed to %s in map %s",
296064562Sgshapiro# if USE_LDAP_INIT
296164562Sgshapiro				       "ldap_init",
296264562Sgshapiro# else /* USE_LDAP_INIT */
296364562Sgshapiro				       "ldap_open",
296464562Sgshapiro# endif /* USE_LDAP_INIT */
296564562Sgshapiro				       lmap->ldap_host == NULL ? "localhost"
296664562Sgshapiro							       : lmap->ldap_host,
296764562Sgshapiro				       map->map_mname);
296864562Sgshapiro			else
296964562Sgshapiro				syserr("421 4.0.0 %s failed to %s in map %s",
297064562Sgshapiro# if USE_LDAP_INIT
297164562Sgshapiro				       "ldap_init",
297264562Sgshapiro# else /* USE_LDAP_INIT */
297364562Sgshapiro				       "ldap_open",
297464562Sgshapiro# endif /* USE_LDAP_INIT */
297564562Sgshapiro				       lmap->ldap_host == NULL ? "localhost"
297664562Sgshapiro							       : lmap->ldap_host,
297764562Sgshapiro				       map->map_mname);
297838032Speter		}
297938032Speter		return FALSE;
298038032Speter	}
298138032Speter
298264562Sgshapiro	ldapmap_setopts(ld, lmap);
298338032Speter
298464562Sgshapiro# if USE_LDAP_INIT
298564562Sgshapiro	/*
298664562Sgshapiro	**  If using ldap_init(), the actual connection to the server
298764562Sgshapiro	**  happens at ldap_bind_s() so we need the timeout here.
298864562Sgshapiro	*/
298964562Sgshapiro
299064562Sgshapiro	/* set the timeout */
299164562Sgshapiro	if (lmap->ldap_timeout.tv_sec != 0)
299238032Speter	{
299364562Sgshapiro		if (setjmp(LDAPTimeout) != 0)
299438032Speter		{
299564562Sgshapiro			if (LogLevel > 1)
299664562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
299764562Sgshapiro					  "timeout conning to LDAP server %.100s",
299864562Sgshapiro					  lmap->ldap_host == NULL ? "localhost"
299964562Sgshapiro								  : lmap->ldap_host);
300064562Sgshapiro			return FALSE;
300138032Speter		}
300264562Sgshapiro		ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
300338032Speter	}
300464562Sgshapiro# endif /* USE_LDAP_INIT */
300564562Sgshapiro
300664562Sgshapiro# ifdef LDAP_AUTH_KRBV4
300764562Sgshapiro	if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
300864562Sgshapiro	    lmap->ldap_secret != NULL)
300938032Speter	{
301064562Sgshapiro		/*
301164562Sgshapiro		**  Need to put ticket in environment here instead of
301264562Sgshapiro		**  during parseargs as there may be different tickets
301364562Sgshapiro		**  for different LDAP connections.
301464562Sgshapiro		*/
301564562Sgshapiro
301664562Sgshapiro		(void) putenv(lmap->ldap_secret);
301738032Speter	}
301864562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
301938032Speter
302064562Sgshapiro	bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
302164562Sgshapiro				  lmap->ldap_secret, lmap->ldap_method);
302264562Sgshapiro
302364562Sgshapiro# if USE_LDAP_INIT
302464562Sgshapiro	/* clear the event if it has not sprung */
302564562Sgshapiro	if (ev != NULL)
302664562Sgshapiro		clrevent(ev);
302764562Sgshapiro# endif /* USE_LDAP_INIT */
302864562Sgshapiro
302964562Sgshapiro	if (bind_result != LDAP_SUCCESS)
303064562Sgshapiro	{
303164562Sgshapiro		errno = bind_result + E_LDAPBASE;
303264562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
303364562Sgshapiro		{
303464562Sgshapiro			syserr("421 4.0.0 Cannot bind to map %s in ldap server %s",
303564562Sgshapiro			       map->map_mname,
303664562Sgshapiro			       lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host);
303764562Sgshapiro		}
303864562Sgshapiro		return FALSE;
303964562Sgshapiro	}
304064562Sgshapiro
304164562Sgshapiro	/* We need to cast ld into the map structure */
304264562Sgshapiro	lmap->ldap_ld = ld;
304364562Sgshapiro	return TRUE;
304438032Speter}
304538032Speter
304664562Sgshapiro/* ARGSUSED */
304764562Sgshapirostatic void
304864562Sgshapiroldaptimeout(sig_no)
304964562Sgshapiro	int sig_no;
305064562Sgshapiro{
305177349Sgshapiro	/*
305277349Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
305377349Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
305477349Sgshapiro	**	DOING.
305577349Sgshapiro	*/
305677349Sgshapiro
305777349Sgshapiro	errno = ETIMEDOUT;
305864562Sgshapiro	longjmp(LDAPTimeout, 1);
305964562Sgshapiro}
306038032Speter
306138032Speter/*
306264562Sgshapiro**  LDAPMAP_CLOSE -- close ldap map
306338032Speter*/
306438032Speter
306538032Spetervoid
306664562Sgshapiroldapmap_close(map)
306738032Speter	MAP *map;
306838032Speter{
306964562Sgshapiro	LDAPMAP_STRUCT *lmap;
307064562Sgshapiro	STAB *s;
307143730Speter
307264562Sgshapiro	if (tTd(38, 2))
307364562Sgshapiro		dprintf("ldapmap_close(%s)\n", map->map_mname);
307464562Sgshapiro
307564562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
307664562Sgshapiro
307764562Sgshapiro	/* Check if already closed */
307864562Sgshapiro	if (lmap->ldap_ld == NULL)
307964562Sgshapiro		return;
308064562Sgshapiro
308177349Sgshapiro	/* Close the LDAP connection */
308277349Sgshapiro	ldap_unbind(lmap->ldap_ld);
308377349Sgshapiro
308477349Sgshapiro	/* Mark all the maps that share the connection as closed */
308564562Sgshapiro	s = ldapmap_findconn(lmap);
308664562Sgshapiro
308777349Sgshapiro	while (s->s_lmap != NULL)
308877349Sgshapiro	{
308977349Sgshapiro		MAP *smap = s->s_lmap;
309064562Sgshapiro
309177349Sgshapiro		if (tTd(38, 2) && smap != map)
309277349Sgshapiro			dprintf("ldapmap_close(%s): closed %s (shared LDAP connection)\n",
309377349Sgshapiro				map->map_mname, smap->map_mname);
309464562Sgshapiro
309577349Sgshapiro		smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
309677349Sgshapiro		lmap = (LDAPMAP_STRUCT *) smap->map_db1;
309764562Sgshapiro		lmap->ldap_ld = NULL;
309877349Sgshapiro		s->s_lmap = lmap->ldap_next;
309977349Sgshapiro		lmap->ldap_next = NULL;
310043730Speter	}
310138032Speter}
310238032Speter
310364562Sgshapiro# ifdef SUNET_ID
310443730Speter/*
310542575Speter**  SUNET_ID_HASH -- Convert a string to it's Sunet_id canonical form
310642575Speter**  This only makes sense at Stanford University.
310738032Speter*/
310838032Speter
310938032Speterchar *
311038032Spetersunet_id_hash(str)
311138032Speter	char *str;
311238032Speter{
311338032Speter	char *p, *p_last;
311438032Speter
311538032Speter	p = str;
311638032Speter	p_last = p;
311738032Speter	while (*p != '\0')
311838032Speter	{
311938032Speter		if (islower(*p) || isdigit(*p))
312038032Speter		{
312138032Speter			*p_last = *p;
312238032Speter			p_last++;
312338032Speter		}
312438032Speter		else if (isupper(*p))
312538032Speter		{
312638032Speter			*p_last = tolower(*p);
312738032Speter			p_last++;
312838032Speter		}
312938032Speter		++p;
313038032Speter	}
313138032Speter	if (*p_last != '\0')
313238032Speter		*p_last = '\0';
313364562Sgshapiro	return str;
313438032Speter}
313564562Sgshapiro# endif /* SUNET_ID */
313638032Speter
313738032Speter/*
313864562Sgshapiro**  LDAPMAP_LOOKUP -- look up a datum in a LDAP map
313938032Speter*/
314038032Speter
314138032Speterchar *
314264562Sgshapiroldapmap_lookup(map, name, av, statp)
314338032Speter	MAP *map;
314438032Speter	char *name;
314538032Speter	char **av;
314638032Speter	int *statp;
314738032Speter{
314864562Sgshapiro	int i;
314964562Sgshapiro	int entries = 0;
315064562Sgshapiro	int msgid;
315164562Sgshapiro	int ret;
315264562Sgshapiro	int vsize;
315364562Sgshapiro	char *fp, *vp;
315464562Sgshapiro	char *p, *q;
315564562Sgshapiro	char *result = NULL;
315664562Sgshapiro	LDAPMAP_STRUCT *lmap = NULL;
315738032Speter	char keybuf[MAXNAME + 1];
315864562Sgshapiro	char filter[LDAPMAP_MAX_FILTER + 1];
315938032Speter
316038032Speter	if (tTd(38, 20))
316164562Sgshapiro		dprintf("ldapmap_lookup(%s, %s)\n", map->map_mname, name);
316238032Speter
316338032Speter	/* Get ldap struct pointer from map */
316464562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
316564562Sgshapiro	ldapmap_setopts(lmap->ldap_ld, lmap);
316638032Speter
316764562Sgshapiro	(void) strlcpy(keybuf, name, sizeof keybuf);
316838032Speter
316938032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
317064562Sgshapiro	{
317164562Sgshapiro# ifdef SUNET_ID
317238032Speter		sunet_id_hash(keybuf);
317364562Sgshapiro# else /* SUNET_ID */
317438032Speter		makelower(keybuf);
317564562Sgshapiro# endif /* SUNET_ID */
317664562Sgshapiro	}
317738032Speter
317842575Speter	/* substitute keybuf into filter, perhaps multiple times */
317964562Sgshapiro	memset(filter, '\0', sizeof filter);
318042575Speter	fp = filter;
318164562Sgshapiro	p = lmap->ldap_filter;
318242575Speter	while ((q = strchr(p, '%')) != NULL)
318342575Speter	{
318442575Speter		if (q[1] == 's')
318542575Speter		{
318642575Speter			snprintf(fp, SPACELEFT(filter, fp), "%.*s%s",
318766494Sgshapiro				 (int) (q - p), p, keybuf);
318864562Sgshapiro			fp += strlen(fp);
318942575Speter			p = q + 2;
319042575Speter		}
319164562Sgshapiro		else if (q[1] == '0')
319264562Sgshapiro		{
319364562Sgshapiro			char *k = keybuf;
319464562Sgshapiro
319564562Sgshapiro			snprintf(fp, SPACELEFT(filter, fp), "%.*s",
319666494Sgshapiro				 (int) (q - p), p);
319764562Sgshapiro			fp += strlen(fp);
319864562Sgshapiro			p = q + 2;
319964562Sgshapiro
320064562Sgshapiro			/* Properly escape LDAP special characters */
320164562Sgshapiro			while (SPACELEFT(filter, fp) > 0 &&
320264562Sgshapiro			       *k != '\0')
320364562Sgshapiro			{
320464562Sgshapiro				if (*k == '*' || *k == '(' ||
320564562Sgshapiro				    *k == ')' || *k == '\\')
320664562Sgshapiro				{
320764562Sgshapiro					(void) strlcat(fp,
320864562Sgshapiro						       (*k == '*' ? "\\2A" :
320964562Sgshapiro							(*k == '(' ? "\\28" :
321064562Sgshapiro							 (*k == ')' ? "\\29" :
321164562Sgshapiro							  (*k == '\\' ? "\\5C" :
321264562Sgshapiro							   "\00")))),
321364562Sgshapiro						SPACELEFT(filter, fp));
321464562Sgshapiro					fp += strlen(fp);
321564562Sgshapiro					k++;
321664562Sgshapiro				}
321764562Sgshapiro				else
321864562Sgshapiro					*fp++ = *k++;
321964562Sgshapiro			}
322064562Sgshapiro		}
322142575Speter		else
322242575Speter		{
322342575Speter			snprintf(fp, SPACELEFT(filter, fp), "%.*s",
322466494Sgshapiro				 (int) (q - p + 1), p);
322542575Speter			p = q + (q[1] == '%' ? 2 : 1);
322664562Sgshapiro			fp += strlen(fp);
322742575Speter		}
322842575Speter	}
322942575Speter	snprintf(fp, SPACELEFT(filter, fp), "%s", p);
323042575Speter	if (tTd(38, 20))
323164562Sgshapiro		dprintf("ldap search filter=%s\n", filter);
323238032Speter
323364562Sgshapiro	lmap->ldap_res = NULL;
323464562Sgshapiro	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope,
323564562Sgshapiro			    filter,
323664562Sgshapiro			    (lmap->ldap_attr[0] == NULL ? NULL :
323764562Sgshapiro			     lmap->ldap_attr),
323864562Sgshapiro			    lmap->ldap_attrsonly);
323964562Sgshapiro	if (msgid == -1)
324038032Speter	{
324177349Sgshapiro		int save_errno;
324277349Sgshapiro
324364562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
324477349Sgshapiro		save_errno = errno;
324564562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
324638032Speter		{
324764562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
324866494Sgshapiro				syserr("Error in ldap_search using %s in map %s",
324964562Sgshapiro				       filter, map->map_mname);
325064562Sgshapiro			else
325166494Sgshapiro				syserr("421 4.0.0 Error in ldap_search using %s in map %s",
325264562Sgshapiro				       filter, map->map_mname);
325338032Speter		}
325464562Sgshapiro		*statp = EX_TEMPFAIL;
325566494Sgshapiro#ifdef LDAP_SERVER_DOWN
325677349Sgshapiro		errno = save_errno;
325777349Sgshapiro		if (errno == LDAP_SERVER_DOWN + E_LDAPBASE)
325866494Sgshapiro		{
325966494Sgshapiro			/* server disappeared, try reopen on next search */
326077349Sgshapiro			ldapmap_close(map);
326166494Sgshapiro		}
326266494Sgshapiro#endif /* LDAP_SERVER_DOWN */
326377349Sgshapiro		errno = save_errno;
326464562Sgshapiro		return NULL;
326564562Sgshapiro	}
326664562Sgshapiro
326764562Sgshapiro	*statp = EX_NOTFOUND;
326864562Sgshapiro	vp = NULL;
326964562Sgshapiro
327064562Sgshapiro	/* Get results (all if MF_NOREWRITE, otherwise one by one) */
327164562Sgshapiro	while ((ret = ldap_result(lmap->ldap_ld, msgid,
327264562Sgshapiro				  bitset(MF_NOREWRITE, map->map_mflags),
327364562Sgshapiro				  (lmap->ldap_timeout.tv_sec == 0 ? NULL :
327464562Sgshapiro				   &(lmap->ldap_timeout)),
327564562Sgshapiro				  &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
327664562Sgshapiro	{
327764562Sgshapiro		LDAPMessage *entry;
327864562Sgshapiro
327964562Sgshapiro		if (bitset(MF_SINGLEMATCH, map->map_mflags))
328038032Speter		{
328164562Sgshapiro			entries += ldap_count_entries(lmap->ldap_ld,
328264562Sgshapiro						      lmap->ldap_res);
328364562Sgshapiro			if (entries > 1)
328464562Sgshapiro			{
328564562Sgshapiro				*statp = EX_NOTFOUND;
328664562Sgshapiro				if (lmap->ldap_res != NULL)
328764562Sgshapiro				{
328864562Sgshapiro					ldap_msgfree(lmap->ldap_res);
328964562Sgshapiro					lmap->ldap_res = NULL;
329064562Sgshapiro				}
329164562Sgshapiro				(void) ldap_abandon(lmap->ldap_ld, msgid);
329264562Sgshapiro				if (vp != NULL)
329377349Sgshapiro					sm_free(vp);
329464562Sgshapiro				if (tTd(38, 25))
329564562Sgshapiro					dprintf("ldap search found multiple on a single match query\n");
329664562Sgshapiro				return NULL;
329764562Sgshapiro			}
329864562Sgshapiro		}
329964562Sgshapiro
330064562Sgshapiro		/* If we don't want multiple values and we have one, break */
330164562Sgshapiro		if (map->map_coldelim == '\0' && vp != NULL)
330264562Sgshapiro			break;
330364562Sgshapiro
330464562Sgshapiro		/* Cycle through all entries */
330564562Sgshapiro		for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
330664562Sgshapiro		     entry != NULL;
330764562Sgshapiro		     entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
330864562Sgshapiro		{
330964562Sgshapiro			BerElement *ber;
331064562Sgshapiro			char *attr;
331164562Sgshapiro			char **vals = NULL;
331264562Sgshapiro
331364562Sgshapiro			/*
331464562Sgshapiro			**  If matching only and found an entry,
331564562Sgshapiro			**  no need to spin through attributes
331664562Sgshapiro			*/
331764562Sgshapiro
331864562Sgshapiro			if (*statp == EX_OK &&
331964562Sgshapiro			    bitset(MF_MATCHONLY, map->map_mflags))
332064562Sgshapiro				continue;
332164562Sgshapiro
332264562Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
332364562Sgshapiro			/*
332464562Sgshapiro			**  Reset value to prevent lingering
332564562Sgshapiro			**  LDAP_DECODING_ERROR due to
332664562Sgshapiro			**  OpenLDAP 1.X's hack (see below)
332764562Sgshapiro			*/
332864562Sgshapiro
332964562Sgshapiro			lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
333064562Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
333164562Sgshapiro
333264562Sgshapiro			for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
333364562Sgshapiro							 &ber);
333464562Sgshapiro			     attr != NULL;
333564562Sgshapiro			     attr = ldap_next_attribute(lmap->ldap_ld, entry,
333664562Sgshapiro							ber))
333764562Sgshapiro			{
333864562Sgshapiro				char *tmp, *vp_tmp;
333964562Sgshapiro
334064562Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
334164562Sgshapiro				{
334264562Sgshapiro					vals = ldap_get_values(lmap->ldap_ld,
334364562Sgshapiro							       entry,
334464562Sgshapiro							       attr);
334564562Sgshapiro					if (vals == NULL)
334664562Sgshapiro					{
334764562Sgshapiro						errno = ldapmap_geterrno(lmap->ldap_ld);
334864562Sgshapiro						if (errno == LDAP_SUCCESS)
334964562Sgshapiro							continue;
335064562Sgshapiro
335164562Sgshapiro						/* Must be an error */
335264562Sgshapiro						errno += E_LDAPBASE;
335364562Sgshapiro						if (!bitset(MF_OPTIONAL,
335464562Sgshapiro							    map->map_mflags))
335564562Sgshapiro						{
335664562Sgshapiro							if (bitset(MF_NODEFER,
335764562Sgshapiro								   map->map_mflags))
335864562Sgshapiro								syserr("Error getting LDAP values in map %s",
335964562Sgshapiro								       map->map_mname);
336064562Sgshapiro							else
336164562Sgshapiro								syserr("421 4.0.0 Error getting LDAP values in map %s",
336264562Sgshapiro								       map->map_mname);
336364562Sgshapiro						}
336464562Sgshapiro						*statp = EX_TEMPFAIL;
336564562Sgshapiro# if USING_NETSCAPE_LDAP
336666494Sgshapiro						ldap_memfree(attr);
336764562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
336864562Sgshapiro						if (lmap->ldap_res != NULL)
336964562Sgshapiro						{
337064562Sgshapiro							ldap_msgfree(lmap->ldap_res);
337164562Sgshapiro							lmap->ldap_res = NULL;
337264562Sgshapiro						}
337364562Sgshapiro						(void) ldap_abandon(lmap->ldap_ld,
337464562Sgshapiro								    msgid);
337564562Sgshapiro						if (vp != NULL)
337677349Sgshapiro							sm_free(vp);
337764562Sgshapiro						return NULL;
337864562Sgshapiro					}
337964562Sgshapiro				}
338064562Sgshapiro
338164562Sgshapiro				*statp = EX_OK;
338264562Sgshapiro
338364562Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
338464562Sgshapiro				/*
338564562Sgshapiro				**  Reset value to prevent lingering
338664562Sgshapiro				**  LDAP_DECODING_ERROR due to
338764562Sgshapiro				**  OpenLDAP 1.X's hack (see below)
338864562Sgshapiro				*/
338964562Sgshapiro
339064562Sgshapiro				lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
339164562Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
339264562Sgshapiro
339364562Sgshapiro				/*
339464562Sgshapiro				**  If matching only,
339564562Sgshapiro				**  no need to spin through entries
339664562Sgshapiro				*/
339764562Sgshapiro
339864562Sgshapiro				if (bitset(MF_MATCHONLY, map->map_mflags))
339964562Sgshapiro					continue;
340064562Sgshapiro
340164562Sgshapiro				/*
340264562Sgshapiro				**  If we don't want multiple values,
340364562Sgshapiro				**  return first found.
340464562Sgshapiro				*/
340564562Sgshapiro
340664562Sgshapiro				if (map->map_coldelim == '\0')
340764562Sgshapiro				{
340864562Sgshapiro					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
340964562Sgshapiro					{
341064562Sgshapiro						vp = newstr(attr);
341164562Sgshapiro# if USING_NETSCAPE_LDAP
341266494Sgshapiro						ldap_memfree(attr);
341364562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
341464562Sgshapiro						break;
341564562Sgshapiro					}
341664562Sgshapiro
341764562Sgshapiro					if (vals[0] == NULL)
341864562Sgshapiro					{
341964562Sgshapiro						ldap_value_free(vals);
342064562Sgshapiro# if USING_NETSCAPE_LDAP
342166494Sgshapiro						ldap_memfree(attr);
342264562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
342364562Sgshapiro						continue;
342464562Sgshapiro					}
342564562Sgshapiro
342664562Sgshapiro					vp = newstr(vals[0]);
342764562Sgshapiro					ldap_value_free(vals);
342864562Sgshapiro# if USING_NETSCAPE_LDAP
342966494Sgshapiro					ldap_memfree(attr);
343064562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
343164562Sgshapiro					break;
343264562Sgshapiro				}
343364562Sgshapiro
343464562Sgshapiro				/* attributes only */
343564562Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
343664562Sgshapiro				{
343764562Sgshapiro					if (vp == NULL)
343864562Sgshapiro						vp = newstr(attr);
343964562Sgshapiro					else
344064562Sgshapiro					{
344164562Sgshapiro						vsize = strlen(vp) +
344264562Sgshapiro							strlen(attr) + 2;
344364562Sgshapiro						tmp = xalloc(vsize);
344464562Sgshapiro						snprintf(tmp, vsize, "%s%c%s",
344564562Sgshapiro							 vp, map->map_coldelim,
344664562Sgshapiro							 attr);
344777349Sgshapiro						sm_free(vp);
344864562Sgshapiro						vp = tmp;
344964562Sgshapiro					}
345064562Sgshapiro# if USING_NETSCAPE_LDAP
345166494Sgshapiro					ldap_memfree(attr);
345264562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
345364562Sgshapiro					continue;
345464562Sgshapiro				}
345564562Sgshapiro
345664562Sgshapiro				/*
345764562Sgshapiro				**  If there is more than one,
345864562Sgshapiro				**  munge then into a map_coldelim
345964562Sgshapiro				**  separated string
346064562Sgshapiro				*/
346164562Sgshapiro
346264562Sgshapiro				vsize = 0;
346364562Sgshapiro				for (i = 0; vals[i] != NULL; i++)
346464562Sgshapiro					vsize += strlen(vals[i]) + 1;
346564562Sgshapiro				vp_tmp = xalloc(vsize);
346664562Sgshapiro				*vp_tmp = '\0';
346764562Sgshapiro
346864562Sgshapiro				p = vp_tmp;
346964562Sgshapiro				for (i = 0; vals[i] != NULL; i++)
347064562Sgshapiro				{
347164562Sgshapiro					p += strlcpy(p, vals[i],
347264562Sgshapiro						     vsize - (p - vp_tmp));
347364562Sgshapiro					if (p >= vp_tmp + vsize)
347464562Sgshapiro						syserr("ldapmap_lookup: Internal error: buffer too small for LDAP values");
347564562Sgshapiro					if (vals[i + 1] != NULL)
347664562Sgshapiro						*p++ = map->map_coldelim;
347764562Sgshapiro				}
347864562Sgshapiro
347964562Sgshapiro				ldap_value_free(vals);
348064562Sgshapiro# if USING_NETSCAPE_LDAP
348166494Sgshapiro				ldap_memfree(attr);
348264562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
348364562Sgshapiro				if (vp == NULL)
348464562Sgshapiro				{
348564562Sgshapiro					vp = vp_tmp;
348664562Sgshapiro					continue;
348764562Sgshapiro				}
348864562Sgshapiro				vsize = strlen(vp) + strlen(vp_tmp) + 2;
348964562Sgshapiro				tmp = xalloc(vsize);
349064562Sgshapiro				snprintf(tmp, vsize, "%s%c%s",
349164562Sgshapiro					 vp, map->map_coldelim, vp_tmp);
349264562Sgshapiro
349377349Sgshapiro				sm_free(vp);
349477349Sgshapiro				sm_free(vp_tmp);
349564562Sgshapiro				vp = tmp;
349664562Sgshapiro			}
349764562Sgshapiro			errno = ldapmap_geterrno(lmap->ldap_ld);
349864562Sgshapiro
349964562Sgshapiro			/*
350064562Sgshapiro			**  We check errno != LDAP_DECODING_ERROR since
350164562Sgshapiro			**  OpenLDAP 1.X has a very ugly *undocumented*
350264562Sgshapiro			**  hack of returning this error code from
350364562Sgshapiro			**  ldap_next_attribute() if the library freed the
350464562Sgshapiro			**  ber attribute.  See:
350564562Sgshapiro			**  http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
350664562Sgshapiro			*/
350764562Sgshapiro
350864562Sgshapiro			if (errno != LDAP_SUCCESS &&
350964562Sgshapiro			    errno != LDAP_DECODING_ERROR)
351064562Sgshapiro			{
351164562Sgshapiro				/* Must be an error */
351264562Sgshapiro				errno += E_LDAPBASE;
351364562Sgshapiro				if (!bitset(MF_OPTIONAL, map->map_mflags))
351464562Sgshapiro				{
351564562Sgshapiro					if (bitset(MF_NODEFER, map->map_mflags))
351664562Sgshapiro						syserr("Error getting LDAP attributes in map %s",
351764562Sgshapiro						       map->map_mname);
351864562Sgshapiro					else
351964562Sgshapiro						syserr("421 4.0.0 Error getting LDAP attributes in map %s",
352064562Sgshapiro						       map->map_mname);
352164562Sgshapiro				}
352264562Sgshapiro				*statp = EX_TEMPFAIL;
352364562Sgshapiro				if (lmap->ldap_res != NULL)
352464562Sgshapiro				{
352564562Sgshapiro					ldap_msgfree(lmap->ldap_res);
352664562Sgshapiro					lmap->ldap_res = NULL;
352764562Sgshapiro				}
352864562Sgshapiro				(void) ldap_abandon(lmap->ldap_ld, msgid);
352964562Sgshapiro				if (vp != NULL)
353077349Sgshapiro					sm_free(vp);
353164562Sgshapiro				return NULL;
353264562Sgshapiro			}
353364562Sgshapiro
353464562Sgshapiro			/* We don't want multiple values and we have one */
353564562Sgshapiro			if (map->map_coldelim == '\0' && vp != NULL)
353664562Sgshapiro				break;
353764562Sgshapiro		}
353864562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld);
353964562Sgshapiro		if (errno != LDAP_SUCCESS && errno != LDAP_DECODING_ERROR)
354064562Sgshapiro		{
354164562Sgshapiro			/* Must be an error */
354264562Sgshapiro			errno += E_LDAPBASE;
354338032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
354438032Speter			{
354564562Sgshapiro				if (bitset(MF_NODEFER, map->map_mflags))
354664562Sgshapiro					syserr("Error getting LDAP entries in map %s",
354764562Sgshapiro					       map->map_mname);
354864562Sgshapiro				else
354964562Sgshapiro					syserr("421 4.0.0 Error getting LDAP entries in map %s",
355064562Sgshapiro					       map->map_mname);
355138032Speter			}
355238032Speter			*statp = EX_TEMPFAIL;
355364562Sgshapiro			if (lmap->ldap_res != NULL)
355464562Sgshapiro			{
355564562Sgshapiro				ldap_msgfree(lmap->ldap_res);
355664562Sgshapiro				lmap->ldap_res = NULL;
355764562Sgshapiro			}
355864562Sgshapiro			(void) ldap_abandon(lmap->ldap_ld, msgid);
355964562Sgshapiro			if (vp != NULL)
356077349Sgshapiro				sm_free(vp);
356164562Sgshapiro			return NULL;
356238032Speter		}
356364562Sgshapiro		ldap_msgfree(lmap->ldap_res);
356464562Sgshapiro		lmap->ldap_res = NULL;
356538032Speter	}
356638032Speter
356764562Sgshapiro	/*
356864562Sgshapiro	**  If grabbing all results at once for MF_NOREWRITE and
356964562Sgshapiro	**  only want a single match, make sure that's all we have
357064562Sgshapiro	*/
357164562Sgshapiro
357264562Sgshapiro	if (ret == LDAP_RES_SEARCH_RESULT &&
357364562Sgshapiro	    bitset(MF_NOREWRITE|MF_SINGLEMATCH, map->map_mflags))
357438032Speter	{
357564562Sgshapiro		entries += ldap_count_entries(lmap->ldap_ld, lmap->ldap_res);
357664562Sgshapiro		if (entries > 1)
357764562Sgshapiro		{
357864562Sgshapiro			*statp = EX_NOTFOUND;
357964562Sgshapiro			if (lmap->ldap_res != NULL)
358064562Sgshapiro			{
358164562Sgshapiro				ldap_msgfree(lmap->ldap_res);
358264562Sgshapiro				lmap->ldap_res = NULL;
358364562Sgshapiro			}
358464562Sgshapiro			if (vp != NULL)
358577349Sgshapiro				sm_free(vp);
358664562Sgshapiro			return NULL;
358764562Sgshapiro		}
358864562Sgshapiro		*statp = EX_OK;
358938032Speter	}
359038032Speter
359164562Sgshapiro	if (ret == 0)
359264562Sgshapiro		errno = ETIMEDOUT;
359364562Sgshapiro	else
359464562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld);
359564562Sgshapiro	if (errno != LDAP_SUCCESS)
359638032Speter	{
359777349Sgshapiro		int save_errno;
359877349Sgshapiro
359964562Sgshapiro		/* Must be an error */
360064562Sgshapiro		if (ret != 0)
360164562Sgshapiro			errno += E_LDAPBASE;
360277349Sgshapiro		save_errno = errno;
360377349Sgshapiro
360464562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
360564562Sgshapiro		{
360664562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
360764562Sgshapiro				syserr("Error getting LDAP results in map %s",
360864562Sgshapiro				       map->map_mname);
360964562Sgshapiro			else
361064562Sgshapiro				syserr("421 4.0.0 Error getting LDAP results in map %s",
361164562Sgshapiro				       map->map_mname);
361264562Sgshapiro		}
361364562Sgshapiro		*statp = EX_TEMPFAIL;
361464562Sgshapiro		if (vp != NULL)
361577349Sgshapiro			sm_free(vp);
361677349Sgshapiro#ifdef LDAP_SERVER_DOWN
361777349Sgshapiro		errno = save_errno;
361877349Sgshapiro		if (errno == LDAP_SERVER_DOWN + E_LDAPBASE)
361977349Sgshapiro		{
362077349Sgshapiro			/* server disappeared, try reopen on next search */
362177349Sgshapiro			ldapmap_close(map);
362277349Sgshapiro		}
362377349Sgshapiro#endif /* LDAP_SERVER_DOWN */
362477349Sgshapiro		errno = save_errno;
362564562Sgshapiro		return NULL;
362638032Speter	}
362738032Speter
362864562Sgshapiro	/* Did we match anything? */
362971345Sgshapiro	if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags))
363064562Sgshapiro		return NULL;
363138032Speter
363264562Sgshapiro	/*
363364562Sgshapiro	**  If MF_NOREWRITE, we are special map which doesn't
363464562Sgshapiro	**  actually return a map value.  Instead, we don't free
363564562Sgshapiro	**  ldap_res and let the calling function process the LDAP
363664562Sgshapiro	**  results.  The caller should ldap_msgfree(lmap->ldap_res).
363764562Sgshapiro	*/
363838032Speter
363964562Sgshapiro	if (bitset(MF_NOREWRITE, map->map_mflags))
364064562Sgshapiro	{
364171345Sgshapiro		if (vp != NULL)
364277349Sgshapiro			sm_free(vp);
364364562Sgshapiro		return "";
364464562Sgshapiro	}
364538032Speter
364664562Sgshapiro	if (*statp == EX_OK)
364764562Sgshapiro	{
364864562Sgshapiro		if (LogLevel > 9)
364964562Sgshapiro			sm_syslog(LOG_INFO, CurEnv->e_id,
365071345Sgshapiro				  "ldap %.100s => %s", name,
365171345Sgshapiro				  vp == NULL ? "<NULL>" : vp);
365264562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
365364562Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
365464562Sgshapiro		else
365571345Sgshapiro		{
365671345Sgshapiro			/* vp != NULL according to test above */
365764562Sgshapiro			result = map_rewrite(map, vp, strlen(vp), av);
365871345Sgshapiro		}
365971345Sgshapiro		if (vp != NULL)
366077349Sgshapiro			sm_free(vp);
366164562Sgshapiro	}
366264562Sgshapiro	return result;
366338032Speter}
366438032Speter
366538032Speter/*
366664562Sgshapiro**  LDAPMAP_FINDCONN -- find an LDAP connection to the server
366764562Sgshapiro**
366864562Sgshapiro**	Cache LDAP connections based on the host, port, bind DN,
366966494Sgshapiro**	secret, and PID so we don't have multiple connections open to
367066494Sgshapiro**	the same server for different maps.  Need a separate connection
367166494Sgshapiro**	per PID since a parent process may close the map before the
367266494Sgshapiro**	child is done with it.
367364562Sgshapiro**
367464562Sgshapiro**	Parameters:
367564562Sgshapiro**		lmap -- LDAP map information
367664562Sgshapiro**
367764562Sgshapiro**	Returns:
367864562Sgshapiro**		Symbol table entry for the LDAP connection.
367964562Sgshapiro**
368038032Speter*/
368138032Speter
368264562Sgshapirostatic STAB *
368364562Sgshapiroldapmap_findconn(lmap)
368464562Sgshapiro	LDAPMAP_STRUCT *lmap;
368538032Speter{
368664562Sgshapiro	int len;
368764562Sgshapiro	char *nbuf;
368864562Sgshapiro	STAB *s;
368938032Speter
369064562Sgshapiro	len = (lmap->ldap_host == NULL ? strlen("localhost") :
369164562Sgshapiro					 strlen(lmap->ldap_host)) + 1 + 8 + 1 +
369264562Sgshapiro		(lmap->ldap_binddn == NULL ? 0 : strlen(lmap->ldap_binddn)) +
369364562Sgshapiro		1 +
369464562Sgshapiro		(lmap->ldap_secret == NULL ? 0 : strlen(lmap->ldap_secret)) +
369566494Sgshapiro		8 + 1;
369664562Sgshapiro	nbuf = xalloc(len);
369766494Sgshapiro	snprintf(nbuf, len, "%s%c%d%c%s%c%s%d",
369864562Sgshapiro		 (lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host),
369964562Sgshapiro		 CONDELSE,
370064562Sgshapiro		 lmap->ldap_port,
370164562Sgshapiro		 CONDELSE,
370264562Sgshapiro		 (lmap->ldap_binddn == NULL ? "" : lmap->ldap_binddn),
370364562Sgshapiro		 CONDELSE,
370466494Sgshapiro		 (lmap->ldap_secret == NULL ? "" : lmap->ldap_secret),
370577349Sgshapiro		 (int) getpid());
370677349Sgshapiro	s = stab(nbuf, ST_LMAP, ST_ENTER);
370777349Sgshapiro	sm_free(nbuf);
370864562Sgshapiro	return s;
370964562Sgshapiro}
371064562Sgshapiro/*
371164562Sgshapiro**  LDAPMAP_SETOPTS -- set LDAP options
371264562Sgshapiro**
371364562Sgshapiro**	Parameters:
371464562Sgshapiro**		ld -- LDAP session handle
371564562Sgshapiro**		lmap -- LDAP map information
371664562Sgshapiro**
371764562Sgshapiro**	Returns:
371864562Sgshapiro**		None.
371964562Sgshapiro**
372064562Sgshapiro*/
372164562Sgshapiro
372264562Sgshapirostatic void
372364562Sgshapiroldapmap_setopts(ld, lmap)
372464562Sgshapiro	LDAP *ld;
372564562Sgshapiro	LDAPMAP_STRUCT *lmap;
372664562Sgshapiro{
372764562Sgshapiro# if USE_LDAP_SET_OPTION
372864562Sgshapiro	ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
372964562Sgshapiro	if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
373064562Sgshapiro		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
373138032Speter	else
373264562Sgshapiro		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
373364562Sgshapiro	ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
373464562Sgshapiro	ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
373564562Sgshapiro# else /* USE_LDAP_SET_OPTION */
373664562Sgshapiro	/* From here on in we can use ldap internal timelimits */
373764562Sgshapiro	ld->ld_deref = lmap->ldap_deref;
373864562Sgshapiro	ld->ld_options = lmap->ldap_options;
373964562Sgshapiro	ld->ld_sizelimit = lmap->ldap_sizelimit;
374064562Sgshapiro	ld->ld_timelimit = lmap->ldap_timelimit;
374164562Sgshapiro# endif /* USE_LDAP_SET_OPTION */
374238032Speter}
374364562Sgshapiro/*
374464562Sgshapiro**  LDAPMAP_GETERRNO -- get ldap errno value
374564562Sgshapiro**
374664562Sgshapiro**	Parameters:
374764562Sgshapiro**		ld -- LDAP session handle
374864562Sgshapiro**
374964562Sgshapiro**	Returns:
375064562Sgshapiro**		LDAP errno.
375164562Sgshapiro**
375264562Sgshapiro*/
375338032Speter
375464562Sgshapirostatic int
375564562Sgshapiroldapmap_geterrno(ld)
375664562Sgshapiro	LDAP *ld;
375764562Sgshapiro{
375864562Sgshapiro	int err = LDAP_SUCCESS;
375964562Sgshapiro
376064562Sgshapiro# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
376164562Sgshapiro	(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
376264562Sgshapiro# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
376364562Sgshapiro#  ifdef LDAP_OPT_SIZELIMIT
376464562Sgshapiro	err = ldap_get_lderrno(ld, NULL, NULL);
376564562Sgshapiro#  else /* LDAP_OPT_SIZELIMIT */
376664562Sgshapiro	err = ld->ld_errno;
376764562Sgshapiro
376864562Sgshapiro	/*
376964562Sgshapiro	**  Reset value to prevent lingering LDAP_DECODING_ERROR due to
377064562Sgshapiro	**  OpenLDAP 1.X's hack (see above)
377164562Sgshapiro	*/
377264562Sgshapiro
377364562Sgshapiro	ld->ld_errno = LDAP_SUCCESS;
377464562Sgshapiro#  endif /* LDAP_OPT_SIZELIMIT */
377564562Sgshapiro# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
377664562Sgshapiro	return err;
377764562Sgshapiro}
377864562Sgshapiro
377938032Speter/*
378064562Sgshapiro**  LDAPX_MAP_PARSEARGS -- print warning about use of ldapx map.
378138032Speter*/
378238032Speter
378338032Speterbool
378464562Sgshapiroldapx_map_parseargs(map, args)
378538032Speter	MAP *map;
378638032Speter	char *args;
378738032Speter{
378864562Sgshapiro	printf("Warning: The \"ldapx\" map class is deprecated and will be removed in a future\n");
378964562Sgshapiro	printf("         version.  Use the \"ldap\" map class instead for map \"%s\".\n",
379064562Sgshapiro	       map->map_mname);
379164562Sgshapiro	return ldapmap_parseargs(map, args);
379264562Sgshapiro}
379338032Speter
379464562Sgshapiro/*
379564562Sgshapiro**  LDAPMAP_PARSEARGS -- parse ldap map definition args.
379664562Sgshapiro*/
379738032Speter
379864562Sgshapirostruct lamvalues LDAPAuthMethods[] =
379964562Sgshapiro{
380064562Sgshapiro	{	"none",		LDAP_AUTH_NONE		},
380164562Sgshapiro	{	"simple",	LDAP_AUTH_SIMPLE	},
380264562Sgshapiro# ifdef LDAP_AUTH_KRBV4
380364562Sgshapiro	{	"krbv4",	LDAP_AUTH_KRBV4		},
380464562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
380564562Sgshapiro	{	NULL,		0			}
380664562Sgshapiro};
380738032Speter
380864562Sgshapirostruct ladvalues LDAPAliasDereference[] =
380964562Sgshapiro{
381064562Sgshapiro	{	"never",	LDAP_DEREF_NEVER	},
381164562Sgshapiro	{	"always",	LDAP_DEREF_ALWAYS	},
381264562Sgshapiro	{	"search",	LDAP_DEREF_SEARCHING	},
381364562Sgshapiro	{	"find",		LDAP_DEREF_FINDING	},
381464562Sgshapiro	{	NULL,		0			}
381564562Sgshapiro};
381638032Speter
381764562Sgshapirostruct lssvalues LDAPSearchScope[] =
381864562Sgshapiro{
381964562Sgshapiro	{	"base",		LDAP_SCOPE_BASE		},
382064562Sgshapiro	{	"one",		LDAP_SCOPE_ONELEVEL	},
382164562Sgshapiro	{	"sub",		LDAP_SCOPE_SUBTREE	},
382264562Sgshapiro	{	NULL,		0			}
382364562Sgshapiro};
382438032Speter
382564562Sgshapirobool
382664562Sgshapiroldapmap_parseargs(map, args)
382764562Sgshapiro	MAP *map;
382864562Sgshapiro	char *args;
382964562Sgshapiro{
383064562Sgshapiro	bool secretread = TRUE;
383164562Sgshapiro	int i;
383264562Sgshapiro	register char *p = args;
383364562Sgshapiro	LDAPMAP_STRUCT *lmap;
383464562Sgshapiro	struct lamvalues *lam;
383564562Sgshapiro	struct ladvalues *lad;
383664562Sgshapiro	struct lssvalues *lss;
383764562Sgshapiro	char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
383864562Sgshapiro
383964562Sgshapiro	/* Get ldap struct pointer from map */
384064562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
384164562Sgshapiro
384264562Sgshapiro	/* Check if setting the initial LDAP defaults */
384364562Sgshapiro	if (lmap == NULL || lmap != LDAPDefaults)
384464562Sgshapiro	{
384564562Sgshapiro		/* We need to alloc an LDAPMAP_STRUCT struct */
384664562Sgshapiro		lmap = (LDAPMAP_STRUCT *) xalloc(sizeof *lmap);
384764562Sgshapiro		if (LDAPDefaults == NULL)
384864562Sgshapiro			ldapmap_clear(lmap);
384964562Sgshapiro		else
385064562Sgshapiro			STRUCTCOPY(*LDAPDefaults, *lmap);
385164562Sgshapiro	}
385264562Sgshapiro
385364562Sgshapiro	/* there is no check whether there is really an argument */
385464562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
385564562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
385638032Speter	for (;;)
385738032Speter	{
385838032Speter		while (isascii(*p) && isspace(*p))
385938032Speter			p++;
386038032Speter		if (*p != '-')
386138032Speter			break;
386238032Speter		switch (*++p)
386338032Speter		{
386438032Speter		  case 'N':
386538032Speter			map->map_mflags |= MF_INCLNULL;
386638032Speter			map->map_mflags &= ~MF_TRY0NULL;
386738032Speter			break;
386838032Speter
386938032Speter		  case 'O':
387038032Speter			map->map_mflags &= ~MF_TRY1NULL;
387138032Speter			break;
387238032Speter
387338032Speter		  case 'o':
387438032Speter			map->map_mflags |= MF_OPTIONAL;
387538032Speter			break;
387638032Speter
387738032Speter		  case 'f':
387838032Speter			map->map_mflags |= MF_NOFOLDCASE;
387938032Speter			break;
388038032Speter
388138032Speter		  case 'm':
388238032Speter			map->map_mflags |= MF_MATCHONLY;
388338032Speter			break;
388438032Speter
388538032Speter		  case 'A':
388638032Speter			map->map_mflags |= MF_APPEND;
388738032Speter			break;
388838032Speter
388938032Speter		  case 'q':
389038032Speter			map->map_mflags |= MF_KEEPQUOTES;
389138032Speter			break;
389238032Speter
389338032Speter		  case 'a':
389438032Speter			map->map_app = ++p;
389538032Speter			break;
389638032Speter
389738032Speter		  case 'T':
389838032Speter			map->map_tapp = ++p;
389938032Speter			break;
390038032Speter
390164562Sgshapiro		  case 't':
390264562Sgshapiro			map->map_mflags |= MF_NODEFER;
390364562Sgshapiro			break;
390464562Sgshapiro
390564562Sgshapiro		  case 'S':
390664562Sgshapiro			map->map_spacesub = *++p;
390764562Sgshapiro			break;
390864562Sgshapiro
390964562Sgshapiro		  case 'D':
391064562Sgshapiro			map->map_mflags |= MF_DEFER;
391164562Sgshapiro			break;
391264562Sgshapiro
391364562Sgshapiro		  case 'z':
391464562Sgshapiro			if (*++p != '\\')
391564562Sgshapiro				map->map_coldelim = *p;
391664562Sgshapiro			else
391764562Sgshapiro			{
391864562Sgshapiro				switch (*++p)
391964562Sgshapiro				{
392064562Sgshapiro				  case 'n':
392164562Sgshapiro					map->map_coldelim = '\n';
392264562Sgshapiro					break;
392364562Sgshapiro
392464562Sgshapiro				  case 't':
392564562Sgshapiro					map->map_coldelim = '\t';
392664562Sgshapiro					break;
392764562Sgshapiro
392864562Sgshapiro				  default:
392964562Sgshapiro					map->map_coldelim = '\\';
393064562Sgshapiro				}
393164562Sgshapiro			}
393264562Sgshapiro			break;
393364562Sgshapiro
393464562Sgshapiro			/* Start of ldapmap specific args */
393538032Speter		  case 'k':		/* search field */
393638032Speter			while (isascii(*++p) && isspace(*p))
393738032Speter				continue;
393864562Sgshapiro			lmap->ldap_filter = p;
393938032Speter			break;
394038032Speter
394138032Speter		  case 'v':		/* attr to return */
394238032Speter			while (isascii(*++p) && isspace(*p))
394338032Speter				continue;
394464562Sgshapiro			lmap->ldap_attr[0] = p;
394564562Sgshapiro			lmap->ldap_attr[1] = NULL;
394638032Speter			break;
394738032Speter
394864562Sgshapiro		  case '1':
394964562Sgshapiro			map->map_mflags |= MF_SINGLEMATCH;
395064562Sgshapiro			break;
395164562Sgshapiro
395238032Speter			/* args stolen from ldapsearch.c */
395338032Speter		  case 'R':		/* don't auto chase referrals */
395464562Sgshapiro# ifdef LDAP_REFERRALS
395538032Speter			lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
395664562Sgshapiro# else /* LDAP_REFERRALS */
395738032Speter			syserr("compile with -DLDAP_REFERRALS for referral support\n");
395864562Sgshapiro# endif /* LDAP_REFERRALS */
395938032Speter			break;
396038032Speter
396164562Sgshapiro		  case 'n':		/* retrieve attribute names only */
396264562Sgshapiro			lmap->ldap_attrsonly = LDAPMAP_TRUE;
396338032Speter			break;
396438032Speter
396564562Sgshapiro		  case 'r':		/* alias dereferencing */
396664562Sgshapiro			while (isascii(*++p) && isspace(*p))
396764562Sgshapiro				continue;
396864562Sgshapiro
396964562Sgshapiro			if (strncasecmp(p, "LDAP_DEREF_", 11) == 0)
397064562Sgshapiro				p += 11;
397164562Sgshapiro
397264562Sgshapiro			for (lad = LDAPAliasDereference;
397364562Sgshapiro			     lad != NULL && lad->lad_name != NULL; lad++)
397438032Speter			{
397564562Sgshapiro				if (strncasecmp(p, lad->lad_name,
397664562Sgshapiro						strlen(lad->lad_name)) == 0)
397764562Sgshapiro					break;
397838032Speter			}
397964562Sgshapiro			if (lad->lad_name != NULL)
398064562Sgshapiro				lmap->ldap_deref = lad->lad_code;
398164562Sgshapiro			else
398238032Speter			{
398364562Sgshapiro				/* bad config line */
398464562Sgshapiro				if (!bitset(MCF_OPTFILE,
398564562Sgshapiro					    map->map_class->map_cflags))
398664562Sgshapiro				{
398764562Sgshapiro					char *ptr;
398864562Sgshapiro
398964562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
399064562Sgshapiro						*ptr = '\0';
399173188Sgshapiro					syserr("Deref must be [never|always|search|find] (not %s) in map %s",
399264562Sgshapiro						p, map->map_mname);
399364562Sgshapiro					if (ptr != NULL)
399464562Sgshapiro						*ptr = ' ';
399564562Sgshapiro					return FALSE;
399664562Sgshapiro				}
399738032Speter			}
399864562Sgshapiro			break;
399964562Sgshapiro
400064562Sgshapiro		  case 's':		/* search scope */
400164562Sgshapiro			while (isascii(*++p) && isspace(*p))
400264562Sgshapiro				continue;
400364562Sgshapiro
400464562Sgshapiro			if (strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
400564562Sgshapiro				p += 11;
400664562Sgshapiro
400764562Sgshapiro			for (lss = LDAPSearchScope;
400864562Sgshapiro			     lss != NULL && lss->lss_name != NULL; lss++)
400938032Speter			{
401064562Sgshapiro				if (strncasecmp(p, lss->lss_name,
401164562Sgshapiro						strlen(lss->lss_name)) == 0)
401264562Sgshapiro					break;
401338032Speter			}
401464562Sgshapiro			if (lss->lss_name != NULL)
401564562Sgshapiro				lmap->ldap_scope = lss->lss_code;
401638032Speter			else
401764562Sgshapiro			{
401864562Sgshapiro				/* bad config line */
401964562Sgshapiro				if (!bitset(MCF_OPTFILE,
402064562Sgshapiro					    map->map_class->map_cflags))
402138032Speter				{
402238032Speter					char *ptr;
402338032Speter
402438032Speter					if ((ptr = strchr(p, ' ')) != NULL)
402538032Speter						*ptr = '\0';
402673188Sgshapiro					syserr("Scope must be [base|one|sub] (not %s) in map %s",
402738032Speter						p, map->map_mname);
402838032Speter					if (ptr != NULL)
402938032Speter						*ptr = ' ';
403038032Speter					return FALSE;
403138032Speter				}
403238032Speter			}
403338032Speter			break;
403438032Speter
403538032Speter		  case 'h':		/* ldap host */
403638032Speter			while (isascii(*++p) && isspace(*p))
403738032Speter				continue;
403864562Sgshapiro			lmap->ldap_host = p;
403938032Speter			break;
404038032Speter
404138032Speter		  case 'b':		/* search base */
404238032Speter			while (isascii(*++p) && isspace(*p))
404338032Speter				continue;
404464562Sgshapiro			lmap->ldap_base = p;
404538032Speter			break;
404638032Speter
404738032Speter		  case 'p':		/* ldap port */
404838032Speter			while (isascii(*++p) && isspace(*p))
404938032Speter				continue;
405064562Sgshapiro			lmap->ldap_port = atoi(p);
405138032Speter			break;
405238032Speter
405338032Speter		  case 'l':		/* time limit */
405438032Speter			while (isascii(*++p) && isspace(*p))
405538032Speter				continue;
405664562Sgshapiro			lmap->ldap_timelimit = atoi(p);
405764562Sgshapiro			lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit;
405838032Speter			break;
405938032Speter
406064562Sgshapiro		  case 'Z':
406164562Sgshapiro			while (isascii(*++p) && isspace(*p))
406264562Sgshapiro				continue;
406364562Sgshapiro			lmap->ldap_sizelimit = atoi(p);
406464562Sgshapiro			break;
406564562Sgshapiro
406664562Sgshapiro		  case 'd':		/* Dn to bind to server as */
406764562Sgshapiro			while (isascii(*++p) && isspace(*p))
406864562Sgshapiro				continue;
406964562Sgshapiro			lmap->ldap_binddn = p;
407064562Sgshapiro			break;
407164562Sgshapiro
407264562Sgshapiro		  case 'M':		/* Method for binding */
407364562Sgshapiro			while (isascii(*++p) && isspace(*p))
407464562Sgshapiro				continue;
407564562Sgshapiro
407664562Sgshapiro			if (strncasecmp(p, "LDAP_AUTH_", 10) == 0)
407764562Sgshapiro				p += 10;
407864562Sgshapiro
407964562Sgshapiro			for (lam = LDAPAuthMethods;
408064562Sgshapiro			     lam != NULL && lam->lam_name != NULL; lam++)
408164562Sgshapiro			{
408264562Sgshapiro				if (strncasecmp(p, lam->lam_name,
408364562Sgshapiro						strlen(lam->lam_name)) == 0)
408464562Sgshapiro					break;
408564562Sgshapiro			}
408664562Sgshapiro			if (lam->lam_name != NULL)
408764562Sgshapiro				lmap->ldap_method = lam->lam_code;
408864562Sgshapiro			else
408964562Sgshapiro			{
409064562Sgshapiro				/* bad config line */
409164562Sgshapiro				if (!bitset(MCF_OPTFILE,
409264562Sgshapiro					    map->map_class->map_cflags))
409364562Sgshapiro				{
409464562Sgshapiro					char *ptr;
409564562Sgshapiro
409664562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
409764562Sgshapiro						*ptr = '\0';
409873188Sgshapiro					syserr("Method for binding must be [none|simple|krbv4] (not %s) in map %s",
409964562Sgshapiro						p, map->map_mname);
410064562Sgshapiro					if (ptr != NULL)
410164562Sgshapiro						*ptr = ' ';
410264562Sgshapiro					return FALSE;
410364562Sgshapiro				}
410464562Sgshapiro			}
410564562Sgshapiro
410664562Sgshapiro			break;
410764562Sgshapiro
410864562Sgshapiro			/*
410964562Sgshapiro			**  This is a string that is dependent on the
411064562Sgshapiro			**  method used defined above.
411164562Sgshapiro			*/
411264562Sgshapiro
411364562Sgshapiro		  case 'P':		/* Secret password for binding */
411464562Sgshapiro			 while (isascii(*++p) && isspace(*p))
411564562Sgshapiro				continue;
411664562Sgshapiro			lmap->ldap_secret = p;
411764562Sgshapiro			secretread = FALSE;
411864562Sgshapiro			break;
411964562Sgshapiro
412064562Sgshapiro		  default:
412164562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
412264562Sgshapiro			break;
412338032Speter		}
412438032Speter
412564562Sgshapiro		/* need to account for quoted strings here */
412664562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
412738032Speter		{
412838032Speter			if (*p == '"')
412938032Speter			{
413038032Speter				while (*++p != '"' && *p != '\0')
413138032Speter					continue;
413238032Speter				if (*p != '\0')
413338032Speter					p++;
413438032Speter			}
413538032Speter			else
413638032Speter				p++;
413738032Speter		}
413838032Speter
413938032Speter		if (*p != '\0')
414038032Speter			*p++ = '\0';
414138032Speter	}
414238032Speter
414338032Speter	if (map->map_app != NULL)
414464562Sgshapiro		map->map_app = newstr(ldapmap_dequote(map->map_app));
414538032Speter	if (map->map_tapp != NULL)
414664562Sgshapiro		map->map_tapp = newstr(ldapmap_dequote(map->map_tapp));
414738032Speter
414838032Speter	/*
414942575Speter	**  We need to swallow up all the stuff into a struct
415042575Speter	**  and dump it into map->map_dbptr1
415138032Speter	*/
415238032Speter
415364562Sgshapiro	if (lmap->ldap_host != NULL &&
415464562Sgshapiro	    (LDAPDefaults == NULL ||
415564562Sgshapiro	     LDAPDefaults == lmap ||
415664562Sgshapiro	     LDAPDefaults->ldap_host != lmap->ldap_host))
415764562Sgshapiro		lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host));
415864562Sgshapiro	map->map_domain = lmap->ldap_host;
415964562Sgshapiro
416064562Sgshapiro	if (lmap->ldap_binddn != NULL &&
416164562Sgshapiro	    (LDAPDefaults == NULL ||
416264562Sgshapiro	     LDAPDefaults == lmap ||
416364562Sgshapiro	     LDAPDefaults->ldap_binddn != lmap->ldap_binddn))
416464562Sgshapiro		lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn));
416564562Sgshapiro
416664562Sgshapiro	if (lmap->ldap_secret != NULL &&
416764562Sgshapiro	    (LDAPDefaults == NULL ||
416864562Sgshapiro	     LDAPDefaults == lmap ||
416964562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
417038032Speter	{
417164562Sgshapiro		FILE *sfd;
417264562Sgshapiro		long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
417338032Speter
417464562Sgshapiro		if (DontLockReadFiles)
417564562Sgshapiro			sff |= SFF_NOLOCK;
417638032Speter
417764562Sgshapiro		/* need to use method to map secret to passwd string */
417864562Sgshapiro		switch (lmap->ldap_method)
417964562Sgshapiro		{
418064562Sgshapiro		  case LDAP_AUTH_NONE:
418164562Sgshapiro			/* Do nothing */
418264562Sgshapiro			break;
418338032Speter
418464562Sgshapiro		  case LDAP_AUTH_SIMPLE:
418538032Speter
418664562Sgshapiro			/*
418764562Sgshapiro			**  Secret is the name of a file with
418864562Sgshapiro			**  the first line as the password.
418964562Sgshapiro			*/
419064562Sgshapiro
419164562Sgshapiro			/* Already read in the secret? */
419264562Sgshapiro			if (secretread)
419364562Sgshapiro				break;
419464562Sgshapiro
419564562Sgshapiro			sfd = safefopen(ldapmap_dequote(lmap->ldap_secret),
419664562Sgshapiro					O_RDONLY, 0, sff);
419764562Sgshapiro			if (sfd == NULL)
419864562Sgshapiro			{
419964562Sgshapiro				syserr("LDAP map: cannot open secret %s",
420064562Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
420164562Sgshapiro				return FALSE;
420264562Sgshapiro			}
420364562Sgshapiro			lmap->ldap_secret = sfgets(m_tmp, LDAPMAP_MAX_PASSWD,
420466494Sgshapiro						   sfd, TimeOuts.to_fileopen,
420566494Sgshapiro						   "ldapmap_parseargs");
420664562Sgshapiro			(void) fclose(sfd);
420764562Sgshapiro			if (lmap->ldap_secret != NULL &&
420864562Sgshapiro			    strlen(m_tmp) > 0)
420964562Sgshapiro			{
421064562Sgshapiro				/* chomp newline */
421164562Sgshapiro				if (m_tmp[strlen(m_tmp) - 1] == '\n')
421264562Sgshapiro					m_tmp[strlen(m_tmp) - 1] = '\0';
421364562Sgshapiro
421464562Sgshapiro				lmap->ldap_secret = m_tmp;
421564562Sgshapiro			}
421664562Sgshapiro			break;
421764562Sgshapiro
421864562Sgshapiro# ifdef LDAP_AUTH_KRBV4
421964562Sgshapiro		  case LDAP_AUTH_KRBV4:
422064562Sgshapiro
422164562Sgshapiro			/*
422264562Sgshapiro			**  Secret is where the ticket file is
422364562Sgshapiro			**  stashed
422464562Sgshapiro			*/
422564562Sgshapiro
422664562Sgshapiro			snprintf(m_tmp, MAXPATHLEN + LDAPMAP_MAX_PASSWD,
422764562Sgshapiro				 "KRBTKFILE=%s",
422864562Sgshapiro				 ldapmap_dequote(lmap->ldap_secret));
422964562Sgshapiro			lmap->ldap_secret = m_tmp;
423064562Sgshapiro			break;
423164562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
423264562Sgshapiro
423364562Sgshapiro		  default:	       /* Should NEVER get here */
423464562Sgshapiro			syserr("LDAP map: Illegal value in lmap method");
423564562Sgshapiro			return FALSE;
423664562Sgshapiro			break;
423764562Sgshapiro		}
423838032Speter	}
423938032Speter
424064562Sgshapiro	if (lmap->ldap_secret != NULL &&
424164562Sgshapiro	    (LDAPDefaults == NULL ||
424264562Sgshapiro	     LDAPDefaults == lmap ||
424364562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
424464562Sgshapiro		lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret));
424538032Speter
424664562Sgshapiro	if (lmap->ldap_base != NULL &&
424764562Sgshapiro	    (LDAPDefaults == NULL ||
424864562Sgshapiro	     LDAPDefaults == lmap ||
424964562Sgshapiro	     LDAPDefaults->ldap_base != lmap->ldap_base))
425064562Sgshapiro		lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base));
425164562Sgshapiro
425264562Sgshapiro	/*
425364562Sgshapiro	**  Save the server from extra work.  If request is for a single
425464562Sgshapiro	**  match, tell the server to only return enough records to
425564562Sgshapiro	**  determine if there is a single match or not.  This can not
425664562Sgshapiro	**  be one since the server would only return one and we wouldn't
425764562Sgshapiro	**  know if there were others available.
425864562Sgshapiro	*/
425964562Sgshapiro
426064562Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
426164562Sgshapiro		lmap->ldap_sizelimit = 2;
426264562Sgshapiro
426364562Sgshapiro	/* If setting defaults, don't process ldap_filter and ldap_attr */
426464562Sgshapiro	if (lmap == LDAPDefaults)
426564562Sgshapiro		return TRUE;
426664562Sgshapiro
426764562Sgshapiro	if (lmap->ldap_filter != NULL)
426864562Sgshapiro		lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
426938032Speter	else
427038032Speter	{
427138032Speter		if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
427238032Speter		{
427338032Speter			syserr("No filter given in map %s", map->map_mname);
427438032Speter			return FALSE;
427538032Speter		}
427638032Speter	}
427764562Sgshapiro
427864562Sgshapiro	if (lmap->ldap_attr[0] != NULL)
427938032Speter	{
428064562Sgshapiro		i = 0;
428164562Sgshapiro		p = ldapmap_dequote(lmap->ldap_attr[0]);
428264562Sgshapiro		lmap->ldap_attr[0] = NULL;
428364562Sgshapiro
428464562Sgshapiro		while (p != NULL)
428538032Speter		{
428664562Sgshapiro			char *v;
428764562Sgshapiro
428864562Sgshapiro			while (isascii(*p) && isspace(*p))
428964562Sgshapiro				p++;
429064562Sgshapiro			if (*p == '\0')
429164562Sgshapiro				break;
429264562Sgshapiro			v = p;
429364562Sgshapiro			p = strchr(v, ',');
429464562Sgshapiro			if (p != NULL)
429564562Sgshapiro				*p++ = '\0';
429664562Sgshapiro
429771345Sgshapiro			if (i >= LDAPMAP_MAX_ATTR)
429864562Sgshapiro			{
429964562Sgshapiro				syserr("Too many return attributes in %s (max %d)",
430064562Sgshapiro				       map->map_mname, LDAPMAP_MAX_ATTR);
430164562Sgshapiro				return FALSE;
430264562Sgshapiro			}
430364562Sgshapiro			if (*v != '\0')
430464562Sgshapiro				lmap->ldap_attr[i++] = newstr(v);
430538032Speter		}
430664562Sgshapiro		lmap->ldap_attr[i] = NULL;
430738032Speter	}
430838032Speter
430938032Speter	map->map_db1 = (ARBPTR_T) lmap;
431038032Speter	return TRUE;
431138032Speter}
431238032Speter
431364562Sgshapiro/*
431464562Sgshapiro**  LDAPMAP_CLEAR -- set default values for LDAPMAP_STRUCT
431564562Sgshapiro**
431664562Sgshapiro**	Parameters:
431764562Sgshapiro**		lmap -- pointer to LDAPMAP_STRUCT to clear
431864562Sgshapiro**
431964562Sgshapiro**	Returns:
432064562Sgshapiro**		None.
432164562Sgshapiro**
432264562Sgshapiro*/
432364562Sgshapiro
432464562Sgshapirostatic void
432564562Sgshapiroldapmap_clear(lmap)
432664562Sgshapiro	LDAPMAP_STRUCT *lmap;
432764562Sgshapiro{
432864562Sgshapiro	lmap->ldap_host = NULL;
432964562Sgshapiro	lmap->ldap_port = LDAP_PORT;
433064562Sgshapiro	lmap->ldap_deref = LDAP_DEREF_NEVER;
433164562Sgshapiro	lmap->ldap_timelimit = LDAP_NO_LIMIT;
433264562Sgshapiro	lmap->ldap_sizelimit = LDAP_NO_LIMIT;
433364562Sgshapiro# ifdef LDAP_REFERRALS
433464562Sgshapiro	lmap->ldap_options = LDAP_OPT_REFERRALS;
433564562Sgshapiro# else /* LDAP_REFERRALS */
433664562Sgshapiro	lmap->ldap_options = 0;
433764562Sgshapiro# endif /* LDAP_REFERRALS */
433864562Sgshapiro	lmap->ldap_binddn = NULL;
433964562Sgshapiro	lmap->ldap_secret = NULL;
434064562Sgshapiro	lmap->ldap_method = LDAP_AUTH_SIMPLE;
434164562Sgshapiro	lmap->ldap_base = NULL;
434264562Sgshapiro	lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
434364562Sgshapiro	lmap->ldap_attrsonly = LDAPMAP_FALSE;
434464562Sgshapiro	lmap->ldap_timeout.tv_sec = 0;
434564562Sgshapiro	lmap->ldap_timeout.tv_usec = 0;
434664562Sgshapiro	lmap->ldap_ld = NULL;
434764562Sgshapiro	lmap->ldap_filter = NULL;
434864562Sgshapiro	lmap->ldap_attr[0] = NULL;
434964562Sgshapiro	lmap->ldap_res = NULL;
435077349Sgshapiro	lmap->ldap_next = NULL;
435164562Sgshapiro}
435238032Speter/*
435364562Sgshapiro**  LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
435464562Sgshapiro**
435564562Sgshapiro**	Parameters:
435664562Sgshapiro**		spec -- map argument string from LDAPDefaults option
435764562Sgshapiro**
435864562Sgshapiro**	Returns:
435964562Sgshapiro**		None.
436064562Sgshapiro**
436164562Sgshapiro*/
436264562Sgshapiro
436364562Sgshapirovoid
436464562Sgshapiroldapmap_set_defaults(spec)
436564562Sgshapiro	char *spec;
436664562Sgshapiro{
436773188Sgshapiro	STAB *class;
436864562Sgshapiro	MAP map;
436964562Sgshapiro
437064562Sgshapiro	/* Allocate and set the default values */
437164562Sgshapiro	if (LDAPDefaults == NULL)
437264562Sgshapiro		LDAPDefaults = (LDAPMAP_STRUCT *) xalloc(sizeof *LDAPDefaults);
437364562Sgshapiro	ldapmap_clear(LDAPDefaults);
437464562Sgshapiro
437564562Sgshapiro	memset(&map, '\0', sizeof map);
437673188Sgshapiro
437773188Sgshapiro	/* look up the class */
437873188Sgshapiro	class = stab("ldap", ST_MAPCLASS, ST_FIND);
437973188Sgshapiro	if (class == NULL)
438073188Sgshapiro	{
438173188Sgshapiro		syserr("readcf: LDAPDefaultSpec: class ldap not available");
438273188Sgshapiro		return;
438373188Sgshapiro	}
438473188Sgshapiro	map.map_class = &class->s_mapclass;
438564562Sgshapiro	map.map_db1 = (ARBPTR_T) LDAPDefaults;
438673188Sgshapiro	map.map_mname = "O LDAPDefaultSpec";
438764562Sgshapiro
438864562Sgshapiro	(void) ldapmap_parseargs(&map, spec);
438964562Sgshapiro
439064562Sgshapiro	/* These should never be set in LDAPDefaults */
439164562Sgshapiro	if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) ||
439264562Sgshapiro	    map.map_spacesub != SpaceSub ||
439364562Sgshapiro	    map.map_app != NULL ||
439464562Sgshapiro	    map.map_tapp != NULL)
439564562Sgshapiro	{
439664562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
439764562Sgshapiro		if (map.map_app != NULL)
439864562Sgshapiro		{
439977349Sgshapiro			sm_free(map.map_app);
440064562Sgshapiro			map.map_app = NULL;
440164562Sgshapiro		}
440264562Sgshapiro		if (map.map_tapp != NULL)
440364562Sgshapiro		{
440477349Sgshapiro			sm_free(map.map_tapp);
440564562Sgshapiro			map.map_tapp = NULL;
440664562Sgshapiro		}
440764562Sgshapiro	}
440864562Sgshapiro
440964562Sgshapiro	if (LDAPDefaults->ldap_filter != NULL)
441064562Sgshapiro	{
441164562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
441264562Sgshapiro		/* don't free, it isn't malloc'ed in parseargs */
441364562Sgshapiro		LDAPDefaults->ldap_filter = NULL;
441464562Sgshapiro	}
441564562Sgshapiro
441664562Sgshapiro	if (LDAPDefaults->ldap_attr[0] != NULL)
441764562Sgshapiro	{
441864562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes");
441964562Sgshapiro		/* don't free, they aren't malloc'ed in parseargs */
442064562Sgshapiro		LDAPDefaults->ldap_attr[0] = NULL;
442164562Sgshapiro	}
442264562Sgshapiro}
442364562Sgshapiro#endif /* LDAPMAP */
442464562Sgshapiro/*
442564562Sgshapiro**  PH map
442664562Sgshapiro*/
442764562Sgshapiro
442864562Sgshapiro#ifdef PH_MAP
442964562Sgshapiro
443064562Sgshapiro/*
443164562Sgshapiro**  Support for the CCSO Nameserver (ph/qi).
443264562Sgshapiro**  This code is intended to replace the so-called "ph mailer".
443364562Sgshapiro**  Contributed by Mark D. Roth <roth@uiuc.edu>.  Contact him for support.
443464562Sgshapiro*/
443564562Sgshapiro
443664562Sgshapiro# include <qiapi.h>
443764562Sgshapiro# include <qicode.h>
443864562Sgshapiro
443964562Sgshapiro/*
444064562Sgshapiro**  PH_MAP_PARSEARGS -- parse ph map definition args.
444164562Sgshapiro*/
444264562Sgshapiro
444364562Sgshapirobool
444464562Sgshapiroph_map_parseargs(map, args)
444564562Sgshapiro	MAP *map;
444664562Sgshapiro	char *args;
444764562Sgshapiro{
444864562Sgshapiro	int i;
444964562Sgshapiro	register int done;
445064562Sgshapiro	PH_MAP_STRUCT *pmap = NULL;
445164562Sgshapiro	register char *p = args;
445264562Sgshapiro
445364562Sgshapiro	pmap = (PH_MAP_STRUCT *) xalloc(sizeof *pmap);
445464562Sgshapiro
445564562Sgshapiro	/* defaults */
445664562Sgshapiro	pmap->ph_servers = NULL;
445764562Sgshapiro	pmap->ph_field_list = NULL;
445864562Sgshapiro	pmap->ph_to_server = NULL;
445964562Sgshapiro	pmap->ph_from_server = NULL;
446064562Sgshapiro	pmap->ph_sockfd = -1;
446164562Sgshapiro	pmap->ph_timeout = 0;
446264562Sgshapiro
446364562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
446464562Sgshapiro	for (;;)
446564562Sgshapiro	{
446664562Sgshapiro		while (isascii(*p) && isspace(*p))
446764562Sgshapiro			p++;
446864562Sgshapiro		if (*p != '-')
446964562Sgshapiro			break;
447064562Sgshapiro		switch (*++p)
447164562Sgshapiro		{
447264562Sgshapiro		  case 'N':
447364562Sgshapiro			map->map_mflags |= MF_INCLNULL;
447464562Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
447564562Sgshapiro			break;
447664562Sgshapiro
447764562Sgshapiro		  case 'O':
447864562Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
447964562Sgshapiro			break;
448064562Sgshapiro
448164562Sgshapiro		  case 'o':
448264562Sgshapiro			map->map_mflags |= MF_OPTIONAL;
448364562Sgshapiro			break;
448464562Sgshapiro
448564562Sgshapiro		  case 'f':
448664562Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
448764562Sgshapiro			break;
448864562Sgshapiro
448964562Sgshapiro		  case 'm':
449064562Sgshapiro			map->map_mflags |= MF_MATCHONLY;
449164562Sgshapiro			break;
449264562Sgshapiro
449364562Sgshapiro		  case 'A':
449464562Sgshapiro			map->map_mflags |= MF_APPEND;
449564562Sgshapiro			break;
449664562Sgshapiro
449764562Sgshapiro		  case 'q':
449864562Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
449964562Sgshapiro			break;
450064562Sgshapiro
450164562Sgshapiro		  case 't':
450264562Sgshapiro			map->map_mflags |= MF_NODEFER;
450364562Sgshapiro			break;
450464562Sgshapiro
450564562Sgshapiro		  case 'a':
450664562Sgshapiro			map->map_app = ++p;
450764562Sgshapiro			break;
450864562Sgshapiro
450964562Sgshapiro		  case 'T':
451064562Sgshapiro			map->map_tapp = ++p;
451164562Sgshapiro			break;
451264562Sgshapiro
451364562Sgshapiro#if _FFR_PHMAP_TIMEOUT
451464562Sgshapiro		  case 'l':
451564562Sgshapiro			while (isascii(*++p) && isspace(*p))
451664562Sgshapiro				continue;
451764562Sgshapiro			pmap->ph_timeout = atoi(p);
451864562Sgshapiro			break;
451964562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
452064562Sgshapiro
452164562Sgshapiro		  case 'S':
452264562Sgshapiro			map->map_spacesub = *++p;
452364562Sgshapiro			break;
452464562Sgshapiro
452564562Sgshapiro		  case 'D':
452664562Sgshapiro			map->map_mflags |= MF_DEFER;
452764562Sgshapiro			break;
452864562Sgshapiro
452964562Sgshapiro		  case 'h':		/* PH server list */
453064562Sgshapiro			while (isascii(*++p) && isspace(*p))
453164562Sgshapiro				continue;
453264562Sgshapiro			pmap->ph_servers = p;
453364562Sgshapiro			break;
453464562Sgshapiro
453564562Sgshapiro		  case 'v':		/* fields to search for */
453664562Sgshapiro			while (isascii(*++p) && isspace(*p))
453764562Sgshapiro				continue;
453864562Sgshapiro			pmap->ph_field_list = p;
453964562Sgshapiro			break;
454064562Sgshapiro
454164562Sgshapiro		  default:
454264562Sgshapiro			syserr("ph_map_parseargs: unknown option -%c\n", *p);
454364562Sgshapiro		}
454464562Sgshapiro
454564562Sgshapiro		/* try to account for quoted strings */
454664562Sgshapiro		done = isascii(*p) && isspace(*p);
454764562Sgshapiro		while (*p != '\0' && !done)
454864562Sgshapiro		{
454964562Sgshapiro			if (*p == '"')
455064562Sgshapiro			{
455164562Sgshapiro				while (*++p != '"' && *p != '\0')
455264562Sgshapiro					continue;
455364562Sgshapiro				if (*p != '\0')
455464562Sgshapiro					p++;
455564562Sgshapiro			}
455664562Sgshapiro			else
455764562Sgshapiro				p++;
455864562Sgshapiro			done = isascii(*p) && isspace(*p);
455964562Sgshapiro		}
456064562Sgshapiro
456164562Sgshapiro		if (*p != '\0')
456264562Sgshapiro			*p++ = '\0';
456364562Sgshapiro	}
456464562Sgshapiro
456564562Sgshapiro	if (map->map_app != NULL)
456664562Sgshapiro		map->map_app = newstr(ph_map_dequote(map->map_app));
456764562Sgshapiro	if (map->map_tapp != NULL)
456864562Sgshapiro		map->map_tapp = newstr(ph_map_dequote(map->map_tapp));
456964562Sgshapiro
457064562Sgshapiro	if (pmap->ph_field_list != NULL)
457164562Sgshapiro		pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
457264562Sgshapiro	else
457364562Sgshapiro		pmap->ph_field_list = DEFAULT_PH_MAP_FIELDS;
457464562Sgshapiro
457564562Sgshapiro	if (pmap->ph_servers != NULL)
457664562Sgshapiro		pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
457764562Sgshapiro	else
457864562Sgshapiro	{
457964562Sgshapiro		syserr("ph_map_parseargs: -h flag is required");
458064562Sgshapiro		return FALSE;
458164562Sgshapiro	}
458264562Sgshapiro
458364562Sgshapiro	map->map_db1 = (ARBPTR_T) pmap;
458464562Sgshapiro	return TRUE;
458564562Sgshapiro}
458664562Sgshapiro
458764562Sgshapiro#if _FFR_PHMAP_TIMEOUT
458864562Sgshapiro/*
458964562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
459064562Sgshapiro*/
459164562Sgshapiro
459264562Sgshapirostatic void
459364562Sgshapiroph_map_safeclose(map)
459464562Sgshapiro	MAP *map;
459564562Sgshapiro{
459664562Sgshapiro	int save_errno = errno;
459764562Sgshapiro	PH_MAP_STRUCT *pmap;
459864562Sgshapiro
459964562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
460064562Sgshapiro
460164562Sgshapiro	if (pmap->ph_sockfd != -1)
460264562Sgshapiro	{
460364562Sgshapiro		(void) close(pmap->ph_sockfd);
460464562Sgshapiro		pmap->ph_sockfd = -1;
460564562Sgshapiro	}
460664562Sgshapiro	if (pmap->ph_from_server != NULL)
460764562Sgshapiro	{
460864562Sgshapiro		(void) fclose(pmap->ph_from_server);
460964562Sgshapiro		pmap->ph_from_server = NULL;
461064562Sgshapiro	}
461164562Sgshapiro	if (pmap->ph_to_server != NULL)
461264562Sgshapiro	{
461364562Sgshapiro		(void) fclose(pmap->ph_to_server);
461464562Sgshapiro		pmap->ph_to_server = NULL;
461564562Sgshapiro	}
461664562Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
461764562Sgshapiro	errno = save_errno;
461864562Sgshapiro}
461964562Sgshapiro
462064562Sgshapirovoid
462164562Sgshapiroph_map_close(map)
462264562Sgshapiro	MAP *map;
462364562Sgshapiro{
462464562Sgshapiro	PH_MAP_STRUCT *pmap;
462564562Sgshapiro
462664562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
462764562Sgshapiro	(void) fprintf(pmap->ph_to_server, "quit\n");
462864562Sgshapiro	(void) fflush(pmap->ph_to_server);
462964562Sgshapiro	ph_map_safeclose(map);
463064562Sgshapiro}
463164562Sgshapiro
463264562Sgshapirostatic jmp_buf  PHTimeout;
463364562Sgshapiro
463464562Sgshapiro/* ARGSUSED */
463564562Sgshapirostatic void
463677349Sgshapiroph_timeout(sig)
463777349Sgshapiro	int sig;
463864562Sgshapiro{
463977349Sgshapiro	/*
464077349Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
464177349Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
464277349Sgshapiro	**	DOING.
464377349Sgshapiro	*/
464477349Sgshapiro
464577349Sgshapiro	errno = ETIMEDOUT;
464664562Sgshapiro	longjmp(PHTimeout, 1);
464764562Sgshapiro}
464864562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
464964562Sgshapiro/*
465064562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
465164562Sgshapiro*/
465264562Sgshapiro
465364562Sgshapirovoid
465464562Sgshapiroph_map_close(map)
465564562Sgshapiro	MAP *map;
465664562Sgshapiro{
465764562Sgshapiro	PH_MAP_STRUCT *pmap;
465864562Sgshapiro
465964562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
466064562Sgshapiro	CloseQi(pmap->ph_to_server, pmap->ph_from_server);
466164562Sgshapiro	pmap->ph_to_server = NULL;
466264562Sgshapiro	pmap->ph_from_server = NULL;
466364562Sgshapiro}
466464562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
466564562Sgshapiro
466664562Sgshapiro/*
466764562Sgshapiro**  PH_MAP_OPEN -- sub for opening PH map
466864562Sgshapiro*/
466964562Sgshapirobool
467064562Sgshapiroph_map_open(map, mode)
467164562Sgshapiro	MAP *map;
467264562Sgshapiro	int mode;
467364562Sgshapiro{
467464562Sgshapiro#if !_FFR_PHMAP_TIMEOUT
467564562Sgshapiro	int save_errno = 0;
467664562Sgshapiro#endif /* !_FFR_PHMAP_TIMEOUT */
467764562Sgshapiro	int j;
467864562Sgshapiro	char *hostlist, *tmp;
467964562Sgshapiro	QIR *server_data = NULL;
468064562Sgshapiro	PH_MAP_STRUCT *pmap;
468164562Sgshapiro#if _FFR_PHMAP_TIMEOUT
468264562Sgshapiro	register EVENT *ev = NULL;
468364562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
468464562Sgshapiro
468564562Sgshapiro	if (tTd(38, 2))
468664562Sgshapiro		dprintf("ph_map_open(%s)\n", map->map_mname);
468764562Sgshapiro
468864562Sgshapiro	mode &= O_ACCMODE;
468964562Sgshapiro	if (mode != O_RDONLY)
469064562Sgshapiro	{
469164562Sgshapiro		/* issue a pseudo-error message */
469264562Sgshapiro# ifdef ENOSYS
469364562Sgshapiro		errno = ENOSYS;
469464562Sgshapiro# else /* ENOSYS */
469564562Sgshapiro#  ifdef EFTYPE
469664562Sgshapiro		errno = EFTYPE;
469764562Sgshapiro#  else /* EFTYPE */
469864562Sgshapiro		errno = ENXIO;
469964562Sgshapiro#  endif /* EFTYPE */
470064562Sgshapiro# endif /* ENOSYS */
470164562Sgshapiro		return FALSE;
470264562Sgshapiro	}
470364562Sgshapiro
470466494Sgshapiro	if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER &&
470566494Sgshapiro	    bitset(MF_DEFER, map->map_mflags))
470666494Sgshapiro	{
470766494Sgshapiro		if (tTd(9, 1))
470866494Sgshapiro			dprintf("ph_map_open(%s) => DEFERRED\n",
470971345Sgshapiro				map->map_mname);
471066494Sgshapiro
471166494Sgshapiro		/*
471266494Sgshapiro		** Unset MF_DEFER here so that map_lookup() returns
471366494Sgshapiro		** a temporary failure using the bogus map and
471466494Sgshapiro		** map->map_tapp instead of the default permanent error.
471566494Sgshapiro		*/
471666494Sgshapiro
471766494Sgshapiro		map->map_mflags &= ~MF_DEFER;
471866494Sgshapiro		return FALSE;
471966494Sgshapiro	}
472066494Sgshapiro
472164562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
472264562Sgshapiro
472364562Sgshapiro	hostlist = newstr(pmap->ph_servers);
472464562Sgshapiro	tmp = strtok(hostlist, " ");
472564562Sgshapiro	do
472664562Sgshapiro	{
472764562Sgshapiro#if _FFR_PHMAP_TIMEOUT
472864562Sgshapiro		if (pmap->ph_timeout != 0)
472964562Sgshapiro		{
473064562Sgshapiro			if (setjmp(PHTimeout) != 0)
473164562Sgshapiro			{
473264562Sgshapiro				ev = NULL;
473364562Sgshapiro				if (LogLevel > 1)
473464562Sgshapiro					sm_syslog(LOG_NOTICE, CurEnv->e_id,
473564562Sgshapiro						  "timeout connecting to PH server %.100s",
473664562Sgshapiro						  tmp);
473764562Sgshapiro# ifdef ETIMEDOUT
473864562Sgshapiro				errno = ETIMEDOUT;
473964562Sgshapiro# else /* ETIMEDOUT */
474066494Sgshapiro				errno = EAGAIN;
474164562Sgshapiro# endif /* ETIMEDOUT */
474264562Sgshapiro				goto ph_map_open_abort;
474364562Sgshapiro			}
474477349Sgshapiro			ev = setevent(pmap->ph_timeout, ph_timeout, 0);
474564562Sgshapiro		}
474664562Sgshapiro		if (!OpenQiSock(tmp, &(pmap->ph_sockfd)) &&
474764562Sgshapiro		    !Sock2FILEs(pmap->ph_sockfd, &(pmap->ph_to_server),
474864562Sgshapiro				&(pmap->ph_from_server)) &&
474964562Sgshapiro		    fprintf(pmap->ph_to_server, "id sendmail+phmap\n") >= 0 &&
475064562Sgshapiro		    fflush(pmap->ph_to_server) == 0 &&
475164562Sgshapiro		    (server_data = ReadQi(pmap->ph_from_server, &j)) != NULL &&
475264562Sgshapiro		    server_data->code == 200)
475364562Sgshapiro		{
475464562Sgshapiro			if (ev != NULL)
475564562Sgshapiro				clrevent(ev);
475664562Sgshapiro			FreeQIR(server_data);
475764562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
475864562Sgshapiro		if (OpenQi(tmp, &(pmap->ph_to_server),
475964562Sgshapiro			   &(pmap->ph_from_server)) >= 0)
476064562Sgshapiro		{
476164562Sgshapiro			if (fprintf(pmap->ph_to_server,
476264562Sgshapiro				    "id sendmail+phmap\n") < 0 ||
476377349Sgshapiro			    fflush(pmap->ph_to_server) != 0 ||
476464562Sgshapiro			    (server_data = ReadQi(pmap->ph_from_server,
476564562Sgshapiro						  &j)) == NULL ||
476664562Sgshapiro			    server_data->code != 200)
476764562Sgshapiro			{
476864562Sgshapiro				save_errno = errno;
476964562Sgshapiro				CloseQi(pmap->ph_to_server,
477064562Sgshapiro					pmap->ph_from_server);
477164562Sgshapiro				continue;
477264562Sgshapiro			}
477364562Sgshapiro			if (server_data != NULL)
477464562Sgshapiro				FreeQIR(server_data);
477564562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
477677349Sgshapiro			sm_free(hostlist);
477764562Sgshapiro			return TRUE;
477864562Sgshapiro		}
477964562Sgshapiro#if _FFR_PHMAP_TIMEOUT
478064562Sgshapiro  ph_map_open_abort:
478164562Sgshapiro		if (ev != NULL)
478264562Sgshapiro			clrevent(ev);
478364562Sgshapiro		ph_map_safeclose(map);
478464562Sgshapiro		if (server_data != NULL)
478564562Sgshapiro		{
478664562Sgshapiro			FreeQIR(server_data);
478764562Sgshapiro			server_data = NULL;
478864562Sgshapiro		}
478964562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
479064562Sgshapiro		save_errno = errno;
479164562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
479264562Sgshapiro	} while (tmp = strtok(NULL, " "));
479364562Sgshapiro
479464562Sgshapiro#if !_FFR_PHMAP_TIMEOUT
479564562Sgshapiro	errno = save_errno;
479664562Sgshapiro#endif /* !_FFR_PHMAP_TIMEOUT */
479766494Sgshapiro	if (bitset(MF_NODEFER, map->map_mflags))
479864562Sgshapiro	{
479966494Sgshapiro		if (errno == 0)
480064562Sgshapiro			errno = EAGAIN;
480166494Sgshapiro		syserr("ph_map_open: %s: cannot connect to PH server",
480266494Sgshapiro		       map->map_mname);
480364562Sgshapiro	}
480466494Sgshapiro	else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1)
480564562Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
480666494Sgshapiro			  "ph_map_open: %s: cannot connect to PH server",
480766494Sgshapiro			  map->map_mname);
480877349Sgshapiro	sm_free(hostlist);
480964562Sgshapiro	return FALSE;
481064562Sgshapiro}
481164562Sgshapiro
481264562Sgshapiro/*
481364562Sgshapiro**  PH_MAP_LOOKUP -- look up key from ph server
481464562Sgshapiro*/
481564562Sgshapiro
481664562Sgshapiro#if _FFR_PHMAP_TIMEOUT
481764562Sgshapiro# define MAX_PH_FIELDS	20
481864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
481964562Sgshapiro
482064562Sgshapirochar *
482164562Sgshapiroph_map_lookup(map, key, args, pstat)
482264562Sgshapiro	MAP *map;
482364562Sgshapiro	char *key;
482464562Sgshapiro	char **args;
482564562Sgshapiro	int *pstat;
482664562Sgshapiro{
482764562Sgshapiro	int j;
482864562Sgshapiro	size_t sz;
482964562Sgshapiro	char *tmp, *tmp2;
483064562Sgshapiro	char *message = NULL, *field = NULL, *fmtkey;
483164562Sgshapiro	QIR *server_data = NULL;
483264562Sgshapiro	QIR *qirp;
483364562Sgshapiro	char keybuf[MAXKEY + 1], fieldbuf[101];
483464562Sgshapiro#if _FFR_PHMAP_TIMEOUT
483564562Sgshapiro	QIR *hold_data[MAX_PH_FIELDS];
483664562Sgshapiro	int hold_data_idx = 0;
483764562Sgshapiro	register EVENT *ev = NULL;
483864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
483964562Sgshapiro	PH_MAP_STRUCT *pmap;
484064562Sgshapiro
484164562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
484264562Sgshapiro
484364562Sgshapiro	*pstat = EX_OK;
484464562Sgshapiro
484564562Sgshapiro#if _FFR_PHMAP_TIMEOUT
484664562Sgshapiro	if (pmap->ph_timeout != 0)
484764562Sgshapiro	{
484864562Sgshapiro		if (setjmp(PHTimeout) != 0)
484964562Sgshapiro		{
485064562Sgshapiro			ev = NULL;
485164562Sgshapiro			if (LogLevel > 1)
485264562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
485364562Sgshapiro					  "timeout during PH lookup of %.100s",
485464562Sgshapiro					  key);
485564562Sgshapiro# ifdef ETIMEDOUT
485664562Sgshapiro			errno = ETIMEDOUT;
485764562Sgshapiro# else /* ETIMEDOUT */
485864562Sgshapiro			errno = 0;
485964562Sgshapiro# endif /* ETIMEDOUT */
486064562Sgshapiro			*pstat = EX_TEMPFAIL;
486164562Sgshapiro			goto ph_map_lookup_abort;
486264562Sgshapiro		}
486377349Sgshapiro		ev = setevent(pmap->ph_timeout, ph_timeout, 0);
486464562Sgshapiro	}
486564562Sgshapiro
486664562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
486764562Sgshapiro	/* check all relevant fields */
486864562Sgshapiro	tmp = pmap->ph_field_list;
486964562Sgshapiro	do
487064562Sgshapiro	{
487164562Sgshapiro#if _FFR_PHMAP_TIMEOUT
487264562Sgshapiro		server_data = NULL;
487364562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
487464562Sgshapiro		while (isascii(*tmp) && isspace(*tmp))
487564562Sgshapiro			tmp++;
487664562Sgshapiro		if (*tmp == '\0')
487764562Sgshapiro			break;
487864562Sgshapiro		sz = strcspn(tmp, " ") + 1;
487964562Sgshapiro		if (sz > sizeof fieldbuf)
488064562Sgshapiro			sz = sizeof fieldbuf;
488164562Sgshapiro		(void) strlcpy(fieldbuf, tmp, sz);
488264562Sgshapiro		field = fieldbuf;
488364562Sgshapiro		tmp += sz;
488464562Sgshapiro
488564562Sgshapiro		(void) strlcpy(keybuf, key, sizeof keybuf);
488664562Sgshapiro		fmtkey = keybuf;
488764562Sgshapiro		if (strcmp(field, "alias") == 0)
488864562Sgshapiro		{
488964562Sgshapiro			/*
489064562Sgshapiro			**  for alias lookups, replace any punctuation
489164562Sgshapiro			**  characters with '-'
489264562Sgshapiro			*/
489364562Sgshapiro
489464562Sgshapiro			for (tmp2 = fmtkey; *tmp2 !=  '\0'; tmp2++)
489564562Sgshapiro			{
489664562Sgshapiro				if (isascii(*tmp2) && ispunct(*tmp2))
489764562Sgshapiro					*tmp2 = '-';
489864562Sgshapiro			}
489964562Sgshapiro			tmp2 = field;
490064562Sgshapiro		}
490164562Sgshapiro		else if (strcmp(field,"spacedname") == 0)
490264562Sgshapiro		{
490364562Sgshapiro			/*
490464562Sgshapiro			**  for "spaced" name lookups, replace any
490564562Sgshapiro			**  punctuation characters with a space
490664562Sgshapiro			*/
490764562Sgshapiro
490864562Sgshapiro			for (tmp2 = fmtkey; *tmp2 != '\0'; tmp2++)
490964562Sgshapiro			{
491064562Sgshapiro				if (isascii(*tmp2) && ispunct(*tmp2) &&
491164562Sgshapiro				    *tmp2 != '*')
491264562Sgshapiro					*tmp2 = ' ';
491364562Sgshapiro			}
491464562Sgshapiro			tmp2 = &(field[6]);
491564562Sgshapiro		}
491664562Sgshapiro		else
491764562Sgshapiro			tmp2 = field;
491864562Sgshapiro
491964562Sgshapiro		if (LogLevel > 9)
492064562Sgshapiro			sm_syslog(LOG_NOTICE, CurEnv->e_id,
492164562Sgshapiro				  "ph_map_lookup: query %s=\"%s\" return email",
492264562Sgshapiro				  tmp2, fmtkey);
492364562Sgshapiro		if (tTd(38, 20))
492464562Sgshapiro			dprintf("ph_map_lookup: query %s=\"%s\" return email\n",
492564562Sgshapiro				tmp2, fmtkey);
492664562Sgshapiro
492764562Sgshapiro		j = 0;
492864562Sgshapiro
492964562Sgshapiro		if (fprintf(pmap->ph_to_server, "query %s=%s return email\n",
493064562Sgshapiro			    tmp2, fmtkey) < 0)
493164562Sgshapiro			message = "qi query command failed";
493277349Sgshapiro		else if (fflush(pmap->ph_to_server) != 0)
493364562Sgshapiro			message = "qi fflush failed";
493464562Sgshapiro		else if ((server_data = ReadQi(pmap->ph_from_server,
493564562Sgshapiro					       &j)) == NULL)
493664562Sgshapiro			message = "ReadQi() returned NULL";
493764562Sgshapiro
493864562Sgshapiro#if _FFR_PHMAP_TIMEOUT
493964562Sgshapiro		if ((hold_data[hold_data_idx] = server_data) != NULL)
494064562Sgshapiro		{
494164562Sgshapiro			/* save pointer for later free() */
494264562Sgshapiro			hold_data_idx++;
494364562Sgshapiro		}
494464562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
494564562Sgshapiro
494664562Sgshapiro		if (server_data == NULL ||
494764562Sgshapiro		    (server_data->code >= 400 &&
494864562Sgshapiro		     server_data->code < 500))
494964562Sgshapiro		{
495064562Sgshapiro			/* temporary failure */
495164562Sgshapiro			*pstat = EX_TEMPFAIL;
495264562Sgshapiro#if _FFR_PHMAP_TIMEOUT
495364562Sgshapiro			break;
495464562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
495564562Sgshapiro			if (server_data != NULL)
495664562Sgshapiro			{
495764562Sgshapiro				FreeQIR(server_data);
495864562Sgshapiro				server_data = NULL;
495964562Sgshapiro			}
496064562Sgshapiro			return NULL;
496164562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
496264562Sgshapiro		}
496364562Sgshapiro
496464562Sgshapiro		/*
496564562Sgshapiro		**  if we found a single match, break out.
496664562Sgshapiro		**  otherwise, try the next field.
496764562Sgshapiro		*/
496864562Sgshapiro
496964562Sgshapiro		if (j == 1)
497064562Sgshapiro			break;
497164562Sgshapiro
497264562Sgshapiro		/*
497364562Sgshapiro		**  check for a single response which is an error:
497464562Sgshapiro		**  ReadQi() doesn't set j on error responses,
497564562Sgshapiro		**  but we should stop here instead of moving on if
497664562Sgshapiro		**  it happens (e.g., alias found but email field empty)
497764562Sgshapiro		*/
497864562Sgshapiro
497964562Sgshapiro		for (qirp = server_data;
498064562Sgshapiro		     qirp != NULL && qirp->code < 0;
498164562Sgshapiro		     qirp++)
498264562Sgshapiro		{
498364562Sgshapiro			if (tTd(38, 20))
498464562Sgshapiro				dprintf("ph_map_lookup: QIR: %d:%d:%d:%s\n",
498564562Sgshapiro					qirp->code, qirp->subcode, qirp->field,
498664562Sgshapiro					(qirp->message ? qirp->message
498764562Sgshapiro					 : "[NULL]"));
498864562Sgshapiro			if (qirp->code <= -500)
498964562Sgshapiro			{
499064562Sgshapiro				j = 0;
499164562Sgshapiro				goto ph_map_lookup_abort;
499264562Sgshapiro			}
499364562Sgshapiro		}
499464562Sgshapiro
499564562Sgshapiro#if _FFR_PHMAP_TIMEOUT
499664562Sgshapiro	} while (*tmp != '\0' && hold_data_idx < MAX_PH_FIELDS);
499764562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
499864562Sgshapiro	} while (*tmp != '\0');
499964562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
500064562Sgshapiro
500164562Sgshapiro  ph_map_lookup_abort:
500264562Sgshapiro#if _FFR_PHMAP_TIMEOUT
500364562Sgshapiro	if (ev != NULL)
500464562Sgshapiro		clrevent(ev);
500564562Sgshapiro
500664562Sgshapiro	/*
500764562Sgshapiro	**  Return EX_TEMPFAIL if the timer popped
500864562Sgshapiro	**  or we got a temporary PH error
500964562Sgshapiro	*/
501064562Sgshapiro
501164562Sgshapiro	if (*pstat == EX_TEMPFAIL)
501264562Sgshapiro		ph_map_safeclose(map);
501364562Sgshapiro
501464562Sgshapiro	/* if we didn't find a single match, bail out */
501564562Sgshapiro	if (*pstat == EX_OK && j != 1)
501664562Sgshapiro		*pstat = EX_UNAVAILABLE;
501764562Sgshapiro
501864562Sgshapiro	if (*pstat == EX_OK)
501964562Sgshapiro	{
502064562Sgshapiro		/*
502164562Sgshapiro		** skip leading whitespace and chop at first address
502264562Sgshapiro		*/
502364562Sgshapiro
502464562Sgshapiro		for (tmp = server_data->message;
502564562Sgshapiro		     isascii(*tmp) && isspace(*tmp);
502664562Sgshapiro		     tmp++)
502764562Sgshapiro			continue;
502864562Sgshapiro
502964562Sgshapiro		for (tmp2 = tmp; *tmp2 != '\0'; tmp2++)
503064562Sgshapiro		{
503164562Sgshapiro			if (isascii(*tmp2) && isspace(*tmp2))
503264562Sgshapiro			{
503364562Sgshapiro				*tmp2 = '\0';
503464562Sgshapiro				break;
503564562Sgshapiro			}
503664562Sgshapiro		}
503764562Sgshapiro
503864562Sgshapiro		if (tTd(38,20))
503964562Sgshapiro			dprintf("ph_map_lookup: %s => %s\n", key, tmp);
504064562Sgshapiro
504164562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
504264562Sgshapiro			message = map_rewrite(map, key, strlen(key), NULL);
504364562Sgshapiro		else
504464562Sgshapiro			message = map_rewrite(map, tmp, strlen(tmp), args);
504564562Sgshapiro	}
504664562Sgshapiro
504764562Sgshapiro	/*
504864562Sgshapiro	**  Deferred free() of returned server_data values
504964562Sgshapiro	**  the deferral is to avoid the risk of a free() being
505064562Sgshapiro	**  interrupted by the event timer.  By now the timeout event
505164562Sgshapiro	**  has been cleared and none of the data is still in use.
505264562Sgshapiro	*/
505364562Sgshapiro
505464562Sgshapiro	while (--hold_data_idx >= 0)
505564562Sgshapiro	{
505664562Sgshapiro		if (hold_data[hold_data_idx] != NULL)
505764562Sgshapiro			FreeQIR(hold_data[hold_data_idx]);
505864562Sgshapiro	}
505964562Sgshapiro
506064562Sgshapiro	if (*pstat == EX_OK)
506164562Sgshapiro		return message;
506264562Sgshapiro
506364562Sgshapiro	return NULL;
506464562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
506564562Sgshapiro	/* if we didn't find a single match, bail out */
506664562Sgshapiro	if (j != 1)
506764562Sgshapiro	{
506864562Sgshapiro		*pstat = EX_UNAVAILABLE;
506964562Sgshapiro		if (server_data != NULL)
507064562Sgshapiro		{
507164562Sgshapiro			FreeQIR(server_data);
507264562Sgshapiro			server_data = NULL;
507364562Sgshapiro		}
507464562Sgshapiro		return NULL;
507564562Sgshapiro	}
507664562Sgshapiro
507764562Sgshapiro	/*
507864562Sgshapiro	** skip leading whitespace and chop at first address
507964562Sgshapiro	*/
508064562Sgshapiro
508164562Sgshapiro	for (tmp = server_data->message;
508264562Sgshapiro	     isascii(*tmp) && isspace(*tmp);
508364562Sgshapiro	     tmp++)
508464562Sgshapiro		continue;
508564562Sgshapiro
508664562Sgshapiro	for (tmp2 = tmp; *tmp2 != '\0'; tmp2++)
508764562Sgshapiro	{
508864562Sgshapiro		if (isascii(*tmp2) && isspace(*tmp2))
508964562Sgshapiro		{
509064562Sgshapiro			*tmp2 = '\0';
509164562Sgshapiro			break;
509264562Sgshapiro		}
509364562Sgshapiro	}
509464562Sgshapiro
509564562Sgshapiro	if (tTd(38,20))
509664562Sgshapiro		dprintf("ph_map_lookup: %s => %s\n", key, tmp);
509764562Sgshapiro
509864562Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
509964562Sgshapiro		message = map_rewrite(map, key, strlen(key), NULL);
510064562Sgshapiro	else
510164562Sgshapiro		message = map_rewrite(map, tmp, strlen(tmp), args);
510264562Sgshapiro	if (server_data != NULL)
510364562Sgshapiro	{
510464562Sgshapiro		FreeQIR(server_data);
510564562Sgshapiro		server_data = NULL;
510664562Sgshapiro	}
510764562Sgshapiro	return message;
510864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
510964562Sgshapiro}
511064562Sgshapiro#endif /* PH_MAP */
511164562Sgshapiro/*
511242575Speter**  syslog map
511338032Speter*/
511438032Speter
511538032Speter#define map_prio	map_lockfd	/* overload field */
511638032Speter
511738032Speter/*
511842575Speter**  SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
511938032Speter*/
512038032Speter
512138032Speterbool
512238032Spetersyslog_map_parseargs(map, args)
512338032Speter	MAP *map;
512438032Speter	char *args;
512538032Speter{
512638032Speter	char *p = args;
512738032Speter	char *priority = NULL;
512838032Speter
512964562Sgshapiro	/* there is no check whether there is really an argument */
513064562Sgshapiro	while (*p != '\0')
513138032Speter	{
513238032Speter		while (isascii(*p) && isspace(*p))
513338032Speter			p++;
513438032Speter		if (*p != '-')
513538032Speter			break;
513664562Sgshapiro		++p;
513764562Sgshapiro		if (*p == 'D')
513864562Sgshapiro		{
513964562Sgshapiro			map->map_mflags |= MF_DEFER;
514064562Sgshapiro			++p;
514164562Sgshapiro		}
514264562Sgshapiro		else if (*p == 'S')
514364562Sgshapiro		{
514464562Sgshapiro			map->map_spacesub = *++p;
514564562Sgshapiro			if (*p != '\0')
514664562Sgshapiro				p++;
514764562Sgshapiro		}
514864562Sgshapiro		else if (*p == 'L')
514964562Sgshapiro		{
515064562Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p))
515164562Sgshapiro				continue;
515264562Sgshapiro			if (*p == '\0')
515364562Sgshapiro				break;
515464562Sgshapiro			priority = p;
515564562Sgshapiro			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
515664562Sgshapiro				p++;
515764562Sgshapiro			if (*p != '\0')
515864562Sgshapiro				*p++ = '\0';
515964562Sgshapiro		}
516064562Sgshapiro		else
516164562Sgshapiro		{
516264562Sgshapiro			syserr("Illegal option %c map syslog", *p);
516364562Sgshapiro			++p;
516464562Sgshapiro		}
516538032Speter	}
516638032Speter
516738032Speter	if (priority == NULL)
516838032Speter		map->map_prio = LOG_INFO;
516938032Speter	else
517038032Speter	{
517138032Speter		if (strncasecmp("LOG_", priority, 4) == 0)
517238032Speter			priority += 4;
517338032Speter
517438032Speter#ifdef LOG_EMERG
517538032Speter		if (strcasecmp("EMERG", priority) == 0)
517638032Speter			map->map_prio = LOG_EMERG;
517738032Speter		else
517864562Sgshapiro#endif /* LOG_EMERG */
517938032Speter#ifdef LOG_ALERT
518038032Speter		if (strcasecmp("ALERT", priority) == 0)
518138032Speter			map->map_prio = LOG_ALERT;
518238032Speter		else
518364562Sgshapiro#endif /* LOG_ALERT */
518438032Speter#ifdef LOG_CRIT
518538032Speter		if (strcasecmp("CRIT", priority) == 0)
518638032Speter			map->map_prio = LOG_CRIT;
518738032Speter		else
518864562Sgshapiro#endif /* LOG_CRIT */
518938032Speter#ifdef LOG_ERR
519038032Speter		if (strcasecmp("ERR", priority) == 0)
519138032Speter			map->map_prio = LOG_ERR;
519238032Speter		else
519364562Sgshapiro#endif /* LOG_ERR */
519438032Speter#ifdef LOG_WARNING
519538032Speter		if (strcasecmp("WARNING", priority) == 0)
519638032Speter			map->map_prio = LOG_WARNING;
519738032Speter		else
519864562Sgshapiro#endif /* LOG_WARNING */
519938032Speter#ifdef LOG_NOTICE
520038032Speter		if (strcasecmp("NOTICE", priority) == 0)
520138032Speter			map->map_prio = LOG_NOTICE;
520238032Speter		else
520364562Sgshapiro#endif /* LOG_NOTICE */
520438032Speter#ifdef LOG_INFO
520538032Speter		if (strcasecmp("INFO", priority) == 0)
520638032Speter			map->map_prio = LOG_INFO;
520738032Speter		else
520864562Sgshapiro#endif /* LOG_INFO */
520938032Speter#ifdef LOG_DEBUG
521038032Speter		if (strcasecmp("DEBUG", priority) == 0)
521138032Speter			map->map_prio = LOG_DEBUG;
521238032Speter		else
521364562Sgshapiro#endif /* LOG_DEBUG */
521438032Speter		{
521538032Speter			syserr("syslog_map_parseargs: Unknown priority %s\n",
521638032Speter			       priority);
521738032Speter			return FALSE;
521838032Speter		}
521938032Speter	}
522038032Speter	return TRUE;
522138032Speter}
522238032Speter
522338032Speter/*
522442575Speter**  SYSLOG_MAP_LOOKUP -- rewrite and syslog message.  Always return empty string
522538032Speter*/
522638032Speter
522738032Speterchar *
522838032Spetersyslog_map_lookup(map, string, args, statp)
522938032Speter	MAP *map;
523038032Speter	char *string;
523138032Speter	char **args;
523238032Speter	int *statp;
523338032Speter{
523438032Speter	char *ptr = map_rewrite(map, string, strlen(string), args);
523538032Speter
523638032Speter	if (ptr != NULL)
523738032Speter	{
523838032Speter		if (tTd(38, 20))
523964562Sgshapiro			dprintf("syslog_map_lookup(%s (priority %d): %s\n",
524064562Sgshapiro				map->map_mname, map->map_prio, ptr);
524138032Speter
524238032Speter		sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
524338032Speter	}
524438032Speter
524538032Speter	*statp = EX_OK;
524638032Speter	return "";
524738032Speter}
524838032Speter
524938032Speter/*
525038032Speter**  HESIOD Modules
525138032Speter*/
525238032Speter
525338032Speter#ifdef HESIOD
525438032Speter
525538032Speterbool
525638032Speterhes_map_open(map, mode)
525738032Speter	MAP *map;
525838032Speter	int mode;
525938032Speter{
526038032Speter	if (tTd(38, 2))
526164562Sgshapiro		dprintf("hes_map_open(%s, %s, %d)\n",
526238032Speter			map->map_mname, map->map_file, mode);
526338032Speter
526438032Speter	if (mode != O_RDONLY)
526538032Speter	{
526638032Speter		/* issue a pseudo-error message */
526764562Sgshapiro# ifdef ENOSYS
526838032Speter		errno = ENOSYS;
526964562Sgshapiro# else /* ENOSYS */
527064562Sgshapiro#  ifdef EFTYPE
527138032Speter		errno = EFTYPE;
527264562Sgshapiro#  else /* EFTYPE */
527338032Speter		errno = ENXIO;
527464562Sgshapiro#  endif /* EFTYPE */
527564562Sgshapiro# endif /* ENOSYS */
527638032Speter		return FALSE;
527738032Speter	}
527838032Speter
527964562Sgshapiro# ifdef HESIOD_INIT
528038032Speter	if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
528138032Speter		return TRUE;
528238032Speter
528338032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
528464562Sgshapiro		syserr("421 4.0.0 cannot initialize Hesiod map (%s)",
528538032Speter			errstring(errno));
528638032Speter	return FALSE;
528764562Sgshapiro# else /* HESIOD_INIT */
528838032Speter	if (hes_error() == HES_ER_UNINIT)
528938032Speter		hes_init();
529038032Speter	switch (hes_error())
529138032Speter	{
529238032Speter	  case HES_ER_OK:
529338032Speter	  case HES_ER_NOTFOUND:
529438032Speter		return TRUE;
529538032Speter	}
529638032Speter
529738032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
529864562Sgshapiro		syserr("421 4.0.0 cannot initialize Hesiod map (%d)", hes_error());
529938032Speter
530038032Speter	return FALSE;
530164562Sgshapiro# endif /* HESIOD_INIT */
530238032Speter}
530338032Speter
530438032Speterchar *
530538032Speterhes_map_lookup(map, name, av, statp)
530638032Speter	MAP *map;
530738032Speter	char *name;
530838032Speter	char **av;
530938032Speter	int *statp;
531038032Speter{
531138032Speter	char **hp;
531238032Speter
531338032Speter	if (tTd(38, 20))
531464562Sgshapiro		dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
531538032Speter
531638032Speter	if (name[0] == '\\')
531738032Speter	{
531838032Speter		char *np;
531938032Speter		int nl;
532077349Sgshapiro		int save_errno;
532138032Speter		char nbuf[MAXNAME];
532238032Speter
532338032Speter		nl = strlen(name);
532438032Speter		if (nl < sizeof nbuf - 1)
532538032Speter			np = nbuf;
532638032Speter		else
532738032Speter			np = xalloc(strlen(name) + 2);
532838032Speter		np[0] = '\\';
532964562Sgshapiro		(void) strlcpy(&np[1], name, (sizeof nbuf) - 1);
533064562Sgshapiro# ifdef HESIOD_INIT
533138032Speter		hp = hesiod_resolve(HesiodContext, np, map->map_file);
533264562Sgshapiro# else /* HESIOD_INIT */
533338032Speter		hp = hes_resolve(np, map->map_file);
533464562Sgshapiro# endif /* HESIOD_INIT */
533577349Sgshapiro		save_errno = errno;
533638032Speter		if (np != nbuf)
533777349Sgshapiro			sm_free(np);
533877349Sgshapiro		errno = save_errno;
533938032Speter	}
534038032Speter	else
534138032Speter	{
534264562Sgshapiro# ifdef HESIOD_INIT
534338032Speter		hp = hesiod_resolve(HesiodContext, name, map->map_file);
534464562Sgshapiro# else /* HESIOD_INIT */
534538032Speter		hp = hes_resolve(name, map->map_file);
534664562Sgshapiro# endif /* HESIOD_INIT */
534738032Speter	}
534864562Sgshapiro# ifdef HESIOD_INIT
534977349Sgshapiro	if (hp == NULL || *hp == NULL)
535038032Speter	{
535138032Speter		switch (errno)
535238032Speter		{
535338032Speter		  case ENOENT:
535438032Speter			  *statp = EX_NOTFOUND;
535538032Speter			  break;
535638032Speter		  case ECONNREFUSED:
535738032Speter		  case EMSGSIZE:
535838032Speter			  *statp = EX_TEMPFAIL;
535938032Speter			  break;
536038032Speter		  case ENOMEM:
536138032Speter		  default:
536238032Speter			  *statp = EX_UNAVAILABLE;
536338032Speter			  break;
536438032Speter		}
536577349Sgshapiro		hesiod_free_list(HesiodContext, hp);
536638032Speter		return NULL;
536738032Speter	}
536864562Sgshapiro# else /* HESIOD_INIT */
536938032Speter	if (hp == NULL || hp[0] == NULL)
537038032Speter	{
537138032Speter		switch (hes_error())
537238032Speter		{
537338032Speter		  case HES_ER_OK:
537438032Speter			*statp = EX_OK;
537538032Speter			break;
537638032Speter
537738032Speter		  case HES_ER_NOTFOUND:
537838032Speter			*statp = EX_NOTFOUND;
537938032Speter			break;
538038032Speter
538138032Speter		  case HES_ER_CONFIG:
538238032Speter			*statp = EX_UNAVAILABLE;
538338032Speter			break;
538438032Speter
538538032Speter		  case HES_ER_NET:
538638032Speter			*statp = EX_TEMPFAIL;
538738032Speter			break;
538838032Speter		}
538938032Speter		return NULL;
539038032Speter	}
539164562Sgshapiro# endif /* HESIOD_INIT */
539238032Speter
539338032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
539438032Speter		return map_rewrite(map, name, strlen(name), NULL);
539538032Speter	else
539638032Speter		return map_rewrite(map, hp[0], strlen(hp[0]), av);
539738032Speter}
539838032Speter
539964562Sgshapiro#endif /* HESIOD */
540038032Speter/*
540138032Speter**  NeXT NETINFO Modules
540238032Speter*/
540338032Speter
540438032Speter#if NETINFO
540538032Speter
540638032Speter# define NETINFO_DEFAULT_DIR		"/aliases"
540738032Speter# define NETINFO_DEFAULT_PROPERTY	"members"
540838032Speter
540938032Speter/*
541038032Speter**  NI_MAP_OPEN -- open NetInfo Aliases
541138032Speter*/
541238032Speter
541338032Speterbool
541438032Speterni_map_open(map, mode)
541538032Speter	MAP *map;
541638032Speter	int mode;
541738032Speter{
541838032Speter	if (tTd(38, 2))
541964562Sgshapiro		dprintf("ni_map_open(%s, %s, %d)\n",
542038032Speter			map->map_mname, map->map_file, mode);
542138032Speter	mode &= O_ACCMODE;
542238032Speter
542338032Speter	if (*map->map_file == '\0')
542438032Speter		map->map_file = NETINFO_DEFAULT_DIR;
542538032Speter
542638032Speter	if (map->map_valcolnm == NULL)
542738032Speter		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
542838032Speter
542938032Speter	if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
543038032Speter		map->map_coldelim = ',';
543138032Speter
543238032Speter	return TRUE;
543338032Speter}
543438032Speter
543538032Speter
543638032Speter/*
543738032Speter**  NI_MAP_LOOKUP -- look up a datum in NetInfo
543838032Speter*/
543938032Speter
544038032Speterchar *
544138032Speterni_map_lookup(map, name, av, statp)
544238032Speter	MAP *map;
544338032Speter	char *name;
544438032Speter	char **av;
544538032Speter	int *statp;
544638032Speter{
544738032Speter	char *res;
544838032Speter	char *propval;
544938032Speter
545038032Speter	if (tTd(38, 20))
545164562Sgshapiro		dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
545238032Speter
545338032Speter	propval = ni_propval(map->map_file, map->map_keycolnm, name,
545438032Speter			     map->map_valcolnm, map->map_coldelim);
545538032Speter
545638032Speter	if (propval == NULL)
545738032Speter		return NULL;
545838032Speter
545938032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
546038032Speter		res = map_rewrite(map, name, strlen(name), NULL);
546138032Speter	else
546238032Speter		res = map_rewrite(map, propval, strlen(propval), av);
546377349Sgshapiro	sm_free(propval);
546438032Speter	return res;
546538032Speter}
546638032Speter
546738032Speter
546864562Sgshapirostatic bool
546938032Speterni_getcanonname(name, hbsize, statp)
547038032Speter	char *name;
547138032Speter	int hbsize;
547238032Speter	int *statp;
547338032Speter{
547438032Speter	char *vptr;
547538032Speter	char *ptr;
547638032Speter	char nbuf[MAXNAME + 1];
547738032Speter
547838032Speter	if (tTd(38, 20))
547964562Sgshapiro		dprintf("ni_getcanonname(%s)\n", name);
548038032Speter
548164562Sgshapiro	if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
548238032Speter	{
548338032Speter		*statp = EX_UNAVAILABLE;
548438032Speter		return FALSE;
548538032Speter	}
548673188Sgshapiro	(void) shorten_hostname(nbuf);
548738032Speter
548838032Speter	/* we only accept single token search key */
548938032Speter	if (strchr(nbuf, '.'))
549038032Speter	{
549138032Speter		*statp = EX_NOHOST;
549238032Speter		return FALSE;
549338032Speter	}
549438032Speter
549538032Speter	/* Do the search */
549638032Speter	vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
549738032Speter
549838032Speter	if (vptr == NULL)
549938032Speter	{
550038032Speter		*statp = EX_NOHOST;
550138032Speter		return FALSE;
550238032Speter	}
550338032Speter
550438032Speter	/* Only want the first machine name */
550538032Speter	if ((ptr = strchr(vptr, '\n')) != NULL)
550638032Speter		*ptr = '\0';
550738032Speter
550838032Speter	if (hbsize >= strlen(vptr))
550938032Speter	{
551064562Sgshapiro		(void) strlcpy(name, vptr, hbsize);
551177349Sgshapiro		sm_free(vptr);
551238032Speter		*statp = EX_OK;
551338032Speter		return TRUE;
551438032Speter	}
551538032Speter	*statp = EX_UNAVAILABLE;
551677349Sgshapiro	sm_free(vptr);
551738032Speter	return FALSE;
551838032Speter}
551938032Speter
552038032Speter
552138032Speter/*
552238032Speter**  NI_PROPVAL -- NetInfo property value lookup routine
552338032Speter**
552438032Speter**	Parameters:
552538032Speter**		keydir -- the NetInfo directory name in which to search
552638032Speter**			for the key.
552738032Speter**		keyprop -- the name of the property in which to find the
552838032Speter**			property we are interested.  Defaults to "name".
552938032Speter**		keyval -- the value for which we are really searching.
553038032Speter**		valprop -- the property name for the value in which we
553138032Speter**			are interested.
553238032Speter**		sepchar -- if non-nil, this can be multiple-valued, and
553338032Speter**			we should return a string separated by this
553438032Speter**			character.
553538032Speter**
553638032Speter**	Returns:
553738032Speter**		NULL -- if:
553838032Speter**			1. the directory is not found
553938032Speter**			2. the property name is not found
554038032Speter**			3. the property contains multiple values
554164562Sgshapiro**			4. some error occurred
554238032Speter**		else -- the value of the lookup.
554338032Speter**
554438032Speter**	Example:
554538032Speter**		To search for an alias value, use:
554638032Speter**		  ni_propval("/aliases", "name", aliasname, "members", ',')
554738032Speter**
554838032Speter**	Notes:
554964562Sgshapiro**		Caller should free the return value of ni_proval
555038032Speter*/
555138032Speter
555238032Speter# include <netinfo/ni.h>
555338032Speter
555464562Sgshapiro# define LOCAL_NETINFO_DOMAIN	"."
555564562Sgshapiro# define PARENT_NETINFO_DOMAIN	".."
555664562Sgshapiro# define MAX_NI_LEVELS		256
555738032Speter
555838032Speterchar *
555938032Speterni_propval(keydir, keyprop, keyval, valprop, sepchar)
556038032Speter	char *keydir;
556138032Speter	char *keyprop;
556238032Speter	char *keyval;
556338032Speter	char *valprop;
556438032Speter	int sepchar;
556538032Speter{
556638032Speter	char *propval = NULL;
556738032Speter	int i;
556864562Sgshapiro	int j, alen, l;
556938032Speter	void *ni = NULL;
557038032Speter	void *lastni = NULL;
557138032Speter	ni_status nis;
557238032Speter	ni_id nid;
557338032Speter	ni_namelist ninl;
557438032Speter	register char *p;
557538032Speter	char keybuf[1024];
557638032Speter
557738032Speter	/*
557838032Speter	**  Create the full key from the two parts.
557938032Speter	**
558038032Speter	**	Note that directory can end with, e.g., "name=" to specify
558138032Speter	**	an alternate search property.
558238032Speter	*/
558338032Speter
558438032Speter	i = strlen(keydir) + strlen(keyval) + 2;
558538032Speter	if (keyprop != NULL)
558638032Speter		i += strlen(keyprop) + 1;
558764562Sgshapiro	if (i >= sizeof keybuf)
558838032Speter		return NULL;
558964562Sgshapiro	(void) strlcpy(keybuf, keydir, sizeof keybuf);
559064562Sgshapiro	(void) strlcat(keybuf, "/", sizeof keybuf);
559138032Speter	if (keyprop != NULL)
559238032Speter	{
559364562Sgshapiro		(void) strlcat(keybuf, keyprop, sizeof keybuf);
559464562Sgshapiro		(void) strlcat(keybuf, "=", sizeof keybuf);
559538032Speter	}
559664562Sgshapiro	(void) strlcat(keybuf, keyval, sizeof keybuf);
559738032Speter
559838032Speter	if (tTd(38, 21))
559964562Sgshapiro		dprintf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n",
560038032Speter			keydir, keyprop, keyval, valprop, sepchar, keybuf);
560138032Speter	/*
560238032Speter	**  If the passed directory and property name are found
560338032Speter	**  in one of netinfo domains we need to search (starting
560438032Speter	**  from the local domain moving all the way back to the
560538032Speter	**  root domain) set propval to the property's value
560638032Speter	**  and return it.
560738032Speter	*/
560838032Speter
560938032Speter	for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
561038032Speter	{
561138032Speter		if (i == 0)
561238032Speter		{
561338032Speter			nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
561438032Speter			if (tTd(38, 20))
561564562Sgshapiro				dprintf("ni_open(LOCAL) = %d\n", nis);
561638032Speter		}
561738032Speter		else
561838032Speter		{
561938032Speter			if (lastni != NULL)
562038032Speter				ni_free(lastni);
562138032Speter			lastni = ni;
562238032Speter			nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
562338032Speter			if (tTd(38, 20))
562464562Sgshapiro				dprintf("ni_open(PARENT) = %d\n", nis);
562538032Speter		}
562638032Speter
562738032Speter		/*
562838032Speter		**  Don't bother if we didn't get a handle on a
562938032Speter		**  proper domain.  This is not necessarily an error.
563038032Speter		**  We would get a positive ni_status if, for instance
563138032Speter		**  we never found the directory or property and tried
563238032Speter		**  to open the parent of the root domain!
563338032Speter		*/
563438032Speter
563538032Speter		if (nis != 0)
563638032Speter			break;
563738032Speter
563838032Speter		/*
563938032Speter		**  Find the path to the server information.
564038032Speter		*/
564138032Speter
564238032Speter		if (ni_pathsearch(ni, &nid, keybuf) != 0)
564338032Speter			continue;
564438032Speter
564538032Speter		/*
564638032Speter		**  Find associated value information.
564738032Speter		*/
564838032Speter
564938032Speter		if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
565038032Speter			continue;
565138032Speter
565238032Speter		if (tTd(38, 20))
565364562Sgshapiro			dprintf("ni_lookupprop: len=%d\n",
565464562Sgshapiro				ninl.ni_namelist_len);
565564562Sgshapiro
565638032Speter		/*
565738032Speter		**  See if we have an acceptable number of values.
565838032Speter		*/
565938032Speter
566038032Speter		if (ninl.ni_namelist_len <= 0)
566138032Speter			continue;
566238032Speter
566338032Speter		if (sepchar == '\0' && ninl.ni_namelist_len > 1)
566438032Speter		{
566538032Speter			ni_namelist_free(&ninl);
566638032Speter			continue;
566738032Speter		}
566838032Speter
566938032Speter		/*
567038032Speter		**  Calculate number of bytes needed and build result
567138032Speter		*/
567238032Speter
567338032Speter		alen = 1;
567438032Speter		for (j = 0; j < ninl.ni_namelist_len; j++)
567538032Speter			alen += strlen(ninl.ni_namelist_val[j]) + 1;
567638032Speter		propval = p = xalloc(alen);
567738032Speter		for (j = 0; j < ninl.ni_namelist_len; j++)
567838032Speter		{
567964562Sgshapiro			(void) strlcpy(p, ninl.ni_namelist_val[j], alen);
568064562Sgshapiro			l = strlen(p);
568164562Sgshapiro			p += l;
568238032Speter			*p++ = sepchar;
568364562Sgshapiro			alen -= l + 1;
568438032Speter		}
568538032Speter		*--p = '\0';
568638032Speter
568738032Speter		ni_namelist_free(&ninl);
568838032Speter	}
568938032Speter
569038032Speter	/*
569138032Speter	**  Clean up.
569238032Speter	*/
569338032Speter
569438032Speter	if (ni != NULL)
569538032Speter		ni_free(ni);
569638032Speter	if (lastni != NULL && ni != lastni)
569738032Speter		ni_free(lastni);
569838032Speter	if (tTd(38, 20))
569964562Sgshapiro		dprintf("ni_propval returns: '%s'\n", propval);
570038032Speter
570138032Speter	return propval;
570238032Speter}
570338032Speter
570442575Speter#endif /* NETINFO */
570538032Speter/*
570638032Speter**  TEXT (unindexed text file) Modules
570738032Speter**
570838032Speter**	This code donated by Sun Microsystems.
570938032Speter*/
571038032Speter
571138032Speter#define map_sff		map_lockfd	/* overload field */
571238032Speter
571338032Speter
571438032Speter/*
571538032Speter**  TEXT_MAP_OPEN -- open text table
571638032Speter*/
571738032Speter
571838032Speterbool
571938032Spetertext_map_open(map, mode)
572038032Speter	MAP *map;
572138032Speter	int mode;
572238032Speter{
572364562Sgshapiro	long sff;
572438032Speter	int i;
572538032Speter
572638032Speter	if (tTd(38, 2))
572764562Sgshapiro		dprintf("text_map_open(%s, %s, %d)\n",
572838032Speter			map->map_mname, map->map_file, mode);
572938032Speter
573038032Speter	mode &= O_ACCMODE;
573138032Speter	if (mode != O_RDONLY)
573238032Speter	{
573338032Speter		errno = EPERM;
573438032Speter		return FALSE;
573538032Speter	}
573638032Speter
573738032Speter	if (*map->map_file == '\0')
573838032Speter	{
573938032Speter		syserr("text map \"%s\": file name required",
574038032Speter			map->map_mname);
574138032Speter		return FALSE;
574238032Speter	}
574338032Speter
574438032Speter	if (map->map_file[0] != '/')
574538032Speter	{
574638032Speter		syserr("text map \"%s\": file name must be fully qualified",
574738032Speter			map->map_mname);
574838032Speter		return FALSE;
574938032Speter	}
575038032Speter
575138032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
575264562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
575338032Speter		sff |= SFF_NOWLINK;
575464562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
575538032Speter		sff |= SFF_SAFEDIRPATH;
575638032Speter	if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
575738032Speter			  sff, S_IRUSR, NULL)) != 0)
575838032Speter	{
575964562Sgshapiro		int save_errno = errno;
576064562Sgshapiro
576138032Speter		/* cannot open this map */
576238032Speter		if (tTd(38, 2))
576364562Sgshapiro			dprintf("\tunsafe map file: %d\n", i);
576464562Sgshapiro		errno = save_errno;
576538032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
576638032Speter			syserr("text map \"%s\": unsafe map file %s",
576738032Speter				map->map_mname, map->map_file);
576838032Speter		return FALSE;
576938032Speter	}
577038032Speter
577138032Speter	if (map->map_keycolnm == NULL)
577238032Speter		map->map_keycolno = 0;
577338032Speter	else
577438032Speter	{
577538032Speter		if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
577638032Speter		{
577738032Speter			syserr("text map \"%s\", file %s: -k should specify a number, not %s",
577838032Speter				map->map_mname, map->map_file,
577938032Speter				map->map_keycolnm);
578038032Speter			return FALSE;
578138032Speter		}
578238032Speter		map->map_keycolno = atoi(map->map_keycolnm);
578338032Speter	}
578438032Speter
578538032Speter	if (map->map_valcolnm == NULL)
578638032Speter		map->map_valcolno = 0;
578738032Speter	else
578838032Speter	{
578938032Speter		if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
579038032Speter		{
579138032Speter			syserr("text map \"%s\", file %s: -v should specify a number, not %s",
579238032Speter					map->map_mname, map->map_file,
579338032Speter					map->map_valcolnm);
579438032Speter			return FALSE;
579538032Speter		}
579638032Speter		map->map_valcolno = atoi(map->map_valcolnm);
579738032Speter	}
579838032Speter
579938032Speter	if (tTd(38, 2))
580038032Speter	{
580164562Sgshapiro		dprintf("text_map_open(%s, %s): delimiter = ",
580238032Speter			map->map_mname, map->map_file);
580338032Speter		if (map->map_coldelim == '\0')
580464562Sgshapiro			dprintf("(white space)\n");
580538032Speter		else
580664562Sgshapiro			dprintf("%c\n", map->map_coldelim);
580738032Speter	}
580838032Speter
580938032Speter	map->map_sff = sff;
581038032Speter	return TRUE;
581138032Speter}
581238032Speter
581338032Speter
581438032Speter/*
581538032Speter**  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
581638032Speter*/
581738032Speter
581838032Speterchar *
581938032Spetertext_map_lookup(map, name, av, statp)
582038032Speter	MAP *map;
582138032Speter	char *name;
582238032Speter	char **av;
582338032Speter	int *statp;
582438032Speter{
582538032Speter	char *vp;
582638032Speter	auto int vsize;
582738032Speter	int buflen;
582838032Speter	FILE *f;
582938032Speter	char delim;
583038032Speter	int key_idx;
583138032Speter	bool found_it;
583264562Sgshapiro	long sff = map->map_sff;
583338032Speter	char search_key[MAXNAME + 1];
583438032Speter	char linebuf[MAXLINE];
583538032Speter	char buf[MAXNAME + 1];
583638032Speter
583738032Speter	found_it = FALSE;
583838032Speter	if (tTd(38, 20))
583964562Sgshapiro		dprintf("text_map_lookup(%s, %s)\n", map->map_mname,  name);
584038032Speter
584138032Speter	buflen = strlen(name);
584238032Speter	if (buflen > sizeof search_key - 1)
584338032Speter		buflen = sizeof search_key - 1;
584464562Sgshapiro	memmove(search_key, name, buflen);
584538032Speter	search_key[buflen] = '\0';
584638032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
584738032Speter		makelower(search_key);
584838032Speter
584938032Speter	f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
585038032Speter	if (f == NULL)
585138032Speter	{
585238032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
585338032Speter		*statp = EX_UNAVAILABLE;
585438032Speter		return NULL;
585538032Speter	}
585638032Speter	key_idx = map->map_keycolno;
585738032Speter	delim = map->map_coldelim;
585838032Speter	while (fgets(linebuf, MAXLINE, f) != NULL)
585938032Speter	{
586038032Speter		char *p;
586138032Speter
586238032Speter		/* skip comment line */
586338032Speter		if (linebuf[0] == '#')
586438032Speter			continue;
586538032Speter		p = strchr(linebuf, '\n');
586638032Speter		if (p != NULL)
586738032Speter			*p = '\0';
586838032Speter		p = get_column(linebuf, key_idx, delim, buf, sizeof buf);
586938032Speter		if (p != NULL && strcasecmp(search_key, p) == 0)
587038032Speter		{
587138032Speter			found_it = TRUE;
587238032Speter			break;
587338032Speter		}
587438032Speter	}
587564562Sgshapiro	(void) fclose(f);
587638032Speter	if (!found_it)
587738032Speter	{
587838032Speter		*statp = EX_NOTFOUND;
587938032Speter		return NULL;
588038032Speter	}
588138032Speter	vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof buf);
588242575Speter	if (vp == NULL)
588342575Speter	{
588442575Speter		*statp = EX_NOTFOUND;
588542575Speter		return NULL;
588642575Speter	}
588738032Speter	vsize = strlen(vp);
588838032Speter	*statp = EX_OK;
588938032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
589038032Speter		return map_rewrite(map, name, strlen(name), NULL);
589138032Speter	else
589238032Speter		return map_rewrite(map, vp, vsize, av);
589338032Speter}
589438032Speter
589538032Speter/*
589638032Speter**  TEXT_GETCANONNAME -- look up canonical name in hosts file
589738032Speter*/
589838032Speter
589964562Sgshapirostatic bool
590038032Spetertext_getcanonname(name, hbsize, statp)
590138032Speter	char *name;
590238032Speter	int hbsize;
590338032Speter	int *statp;
590438032Speter{
590538032Speter	bool found;
590673188Sgshapiro	char *dot;
590738032Speter	FILE *f;
590838032Speter	char linebuf[MAXLINE];
590938032Speter	char cbuf[MAXNAME + 1];
591038032Speter	char nbuf[MAXNAME + 1];
591138032Speter
591238032Speter	if (tTd(38, 20))
591364562Sgshapiro		dprintf("text_getcanonname(%s)\n", name);
591438032Speter
591538032Speter	if (strlen(name) >= (SIZE_T) sizeof nbuf)
591638032Speter	{
591738032Speter		*statp = EX_UNAVAILABLE;
591838032Speter		return FALSE;
591938032Speter	}
592064562Sgshapiro	(void) strlcpy(nbuf, name, sizeof nbuf);
592173188Sgshapiro	dot = shorten_hostname(nbuf);
592238032Speter
592338032Speter	f = fopen(HostsFile, "r");
592438032Speter	if (f == NULL)
592538032Speter	{
592638032Speter		*statp = EX_UNAVAILABLE;
592738032Speter		return FALSE;
592838032Speter	}
592938032Speter	found = FALSE;
593038032Speter	while (!found && fgets(linebuf, MAXLINE, f) != NULL)
593138032Speter	{
593238032Speter		char *p = strpbrk(linebuf, "#\n");
593338032Speter
593438032Speter		if (p != NULL)
593538032Speter			*p = '\0';
593638032Speter		if (linebuf[0] != '\0')
593773188Sgshapiro			found = extract_canonname(nbuf, dot, linebuf,
593873188Sgshapiro						  cbuf, sizeof cbuf);
593938032Speter	}
594064562Sgshapiro	(void) fclose(f);
594138032Speter	if (!found)
594238032Speter	{
594338032Speter		*statp = EX_NOHOST;
594438032Speter		return FALSE;
594538032Speter	}
594638032Speter
594738032Speter	if ((SIZE_T) hbsize >= strlen(cbuf))
594838032Speter	{
594964562Sgshapiro		(void) strlcpy(name, cbuf, hbsize);
595038032Speter		*statp = EX_OK;
595138032Speter		return TRUE;
595238032Speter	}
595338032Speter	*statp = EX_UNAVAILABLE;
595438032Speter	return FALSE;
595538032Speter}
595638032Speter/*
595738032Speter**  STAB (Symbol Table) Modules
595838032Speter*/
595938032Speter
596038032Speter
596138032Speter/*
596238032Speter**  STAB_MAP_LOOKUP -- look up alias in symbol table
596338032Speter*/
596438032Speter
596538032Speter/* ARGSUSED2 */
596638032Speterchar *
596738032Speterstab_map_lookup(map, name, av, pstat)
596838032Speter	register MAP *map;
596938032Speter	char *name;
597038032Speter	char **av;
597138032Speter	int *pstat;
597238032Speter{
597338032Speter	register STAB *s;
597438032Speter
597538032Speter	if (tTd(38, 20))
597664562Sgshapiro		dprintf("stab_lookup(%s, %s)\n",
597738032Speter			map->map_mname, name);
597838032Speter
597938032Speter	s = stab(name, ST_ALIAS, ST_FIND);
598038032Speter	if (s != NULL)
598164562Sgshapiro		return s->s_alias;
598264562Sgshapiro	return NULL;
598338032Speter}
598438032Speter
598538032Speter
598638032Speter/*
598738032Speter**  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
598838032Speter*/
598938032Speter
599038032Spetervoid
599138032Speterstab_map_store(map, lhs, rhs)
599238032Speter	register MAP *map;
599338032Speter	char *lhs;
599438032Speter	char *rhs;
599538032Speter{
599638032Speter	register STAB *s;
599738032Speter
599838032Speter	s = stab(lhs, ST_ALIAS, ST_ENTER);
599938032Speter	s->s_alias = newstr(rhs);
600038032Speter}
600138032Speter
600238032Speter
600338032Speter/*
600438032Speter**  STAB_MAP_OPEN -- initialize (reads data file)
600538032Speter**
600638032Speter**	This is a wierd case -- it is only intended as a fallback for
600738032Speter**	aliases.  For this reason, opens for write (only during a
600838032Speter**	"newaliases") always fails, and opens for read open the
600938032Speter**	actual underlying text file instead of the database.
601038032Speter*/
601138032Speter
601238032Speterbool
601338032Speterstab_map_open(map, mode)
601438032Speter	register MAP *map;
601538032Speter	int mode;
601638032Speter{
601738032Speter	FILE *af;
601864562Sgshapiro	long sff;
601938032Speter	struct stat st;
602038032Speter
602138032Speter	if (tTd(38, 2))
602264562Sgshapiro		dprintf("stab_map_open(%s, %s, %d)\n",
602338032Speter			map->map_mname, map->map_file, mode);
602438032Speter
602538032Speter	mode &= O_ACCMODE;
602638032Speter	if (mode != O_RDONLY)
602738032Speter	{
602838032Speter		errno = EPERM;
602938032Speter		return FALSE;
603038032Speter	}
603138032Speter
603238032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
603364562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
603438032Speter		sff |= SFF_NOWLINK;
603564562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
603638032Speter		sff |= SFF_SAFEDIRPATH;
603738032Speter	af = safefopen(map->map_file, O_RDONLY, 0444, sff);
603838032Speter	if (af == NULL)
603938032Speter		return FALSE;
604038032Speter	readaliases(map, af, FALSE, FALSE);
604138032Speter
604238032Speter	if (fstat(fileno(af), &st) >= 0)
604338032Speter		map->map_mtime = st.st_mtime;
604464562Sgshapiro	(void) fclose(af);
604538032Speter
604638032Speter	return TRUE;
604738032Speter}
604838032Speter/*
604938032Speter**  Implicit Modules
605038032Speter**
605138032Speter**	Tries several types.  For back compatibility of aliases.
605238032Speter*/
605338032Speter
605438032Speter
605538032Speter/*
605638032Speter**  IMPL_MAP_LOOKUP -- lookup in best open database
605738032Speter*/
605838032Speter
605938032Speterchar *
606038032Speterimpl_map_lookup(map, name, av, pstat)
606138032Speter	MAP *map;
606238032Speter	char *name;
606338032Speter	char **av;
606438032Speter	int *pstat;
606538032Speter{
606638032Speter	if (tTd(38, 20))
606764562Sgshapiro		dprintf("impl_map_lookup(%s, %s)\n",
606838032Speter			map->map_mname, name);
606938032Speter
607038032Speter#ifdef NEWDB
607138032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
607238032Speter		return db_map_lookup(map, name, av, pstat);
607364562Sgshapiro#endif /* NEWDB */
607438032Speter#ifdef NDBM
607538032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
607638032Speter		return ndbm_map_lookup(map, name, av, pstat);
607764562Sgshapiro#endif /* NDBM */
607838032Speter	return stab_map_lookup(map, name, av, pstat);
607938032Speter}
608038032Speter
608138032Speter/*
608238032Speter**  IMPL_MAP_STORE -- store in open databases
608338032Speter*/
608438032Speter
608538032Spetervoid
608638032Speterimpl_map_store(map, lhs, rhs)
608738032Speter	MAP *map;
608838032Speter	char *lhs;
608938032Speter	char *rhs;
609038032Speter{
609138032Speter	if (tTd(38, 12))
609264562Sgshapiro		dprintf("impl_map_store(%s, %s, %s)\n",
609338032Speter			map->map_mname, lhs, rhs);
609438032Speter#ifdef NEWDB
609538032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
609638032Speter		db_map_store(map, lhs, rhs);
609764562Sgshapiro#endif /* NEWDB */
609838032Speter#ifdef NDBM
609938032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
610038032Speter		ndbm_map_store(map, lhs, rhs);
610164562Sgshapiro#endif /* NDBM */
610238032Speter	stab_map_store(map, lhs, rhs);
610338032Speter}
610438032Speter
610538032Speter/*
610638032Speter**  IMPL_MAP_OPEN -- implicit database open
610738032Speter*/
610838032Speter
610938032Speterbool
611038032Speterimpl_map_open(map, mode)
611138032Speter	MAP *map;
611238032Speter	int mode;
611338032Speter{
611438032Speter	if (tTd(38, 2))
611564562Sgshapiro		dprintf("impl_map_open(%s, %s, %d)\n",
611638032Speter			map->map_mname, map->map_file, mode);
611738032Speter
611838032Speter	mode &= O_ACCMODE;
611938032Speter#ifdef NEWDB
612038032Speter	map->map_mflags |= MF_IMPL_HASH;
612138032Speter	if (hash_map_open(map, mode))
612238032Speter	{
612338032Speter# ifdef NDBM_YP_COMPAT
612438032Speter		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
612564562Sgshapiro# endif /* NDBM_YP_COMPAT */
612638032Speter			return TRUE;
612738032Speter	}
612838032Speter	else
612938032Speter		map->map_mflags &= ~MF_IMPL_HASH;
613064562Sgshapiro#endif /* NEWDB */
613138032Speter#ifdef NDBM
613238032Speter	map->map_mflags |= MF_IMPL_NDBM;
613338032Speter	if (ndbm_map_open(map, mode))
613438032Speter	{
613538032Speter		return TRUE;
613638032Speter	}
613738032Speter	else
613838032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
613964562Sgshapiro#endif /* NDBM */
614038032Speter
614138032Speter#if defined(NEWDB) || defined(NDBM)
614238032Speter	if (Verbose)
614338032Speter		message("WARNING: cannot open alias database %s%s",
614438032Speter			map->map_file,
614538032Speter			mode == O_RDONLY ? "; reading text version" : "");
614664562Sgshapiro#else /* defined(NEWDB) || defined(NDBM) */
614738032Speter	if (mode != O_RDONLY)
614838032Speter		usrerr("Cannot rebuild aliases: no database format defined");
614964562Sgshapiro#endif /* defined(NEWDB) || defined(NDBM) */
615038032Speter
615138032Speter	if (mode == O_RDONLY)
615238032Speter		return stab_map_open(map, mode);
615338032Speter	else
615438032Speter		return FALSE;
615538032Speter}
615638032Speter
615738032Speter
615838032Speter/*
615938032Speter**  IMPL_MAP_CLOSE -- close any open database(s)
616038032Speter*/
616138032Speter
616238032Spetervoid
616338032Speterimpl_map_close(map)
616438032Speter	MAP *map;
616538032Speter{
616638032Speter	if (tTd(38, 9))
616764562Sgshapiro		dprintf("impl_map_close(%s, %s, %lx)\n",
616838032Speter			map->map_mname, map->map_file, map->map_mflags);
616938032Speter#ifdef NEWDB
617038032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
617138032Speter	{
617238032Speter		db_map_close(map);
617338032Speter		map->map_mflags &= ~MF_IMPL_HASH;
617438032Speter	}
617564562Sgshapiro#endif /* NEWDB */
617638032Speter
617738032Speter#ifdef NDBM
617838032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
617938032Speter	{
618038032Speter		ndbm_map_close(map);
618138032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
618238032Speter	}
618364562Sgshapiro#endif /* NDBM */
618438032Speter}
618538032Speter/*
618638032Speter**  User map class.
618738032Speter**
618838032Speter**	Provides access to the system password file.
618938032Speter*/
619038032Speter
619138032Speter/*
619238032Speter**  USER_MAP_OPEN -- open user map
619338032Speter**
619438032Speter**	Really just binds field names to field numbers.
619538032Speter*/
619638032Speter
619738032Speterbool
619838032Speteruser_map_open(map, mode)
619938032Speter	MAP *map;
620038032Speter	int mode;
620138032Speter{
620238032Speter	if (tTd(38, 2))
620364562Sgshapiro		dprintf("user_map_open(%s, %d)\n",
620438032Speter			map->map_mname, mode);
620538032Speter
620638032Speter	mode &= O_ACCMODE;
620738032Speter	if (mode != O_RDONLY)
620838032Speter	{
620938032Speter		/* issue a pseudo-error message */
621038032Speter#ifdef ENOSYS
621138032Speter		errno = ENOSYS;
621264562Sgshapiro#else /* ENOSYS */
621338032Speter# ifdef EFTYPE
621438032Speter		errno = EFTYPE;
621564562Sgshapiro# else /* EFTYPE */
621638032Speter		errno = ENXIO;
621764562Sgshapiro# endif /* EFTYPE */
621864562Sgshapiro#endif /* ENOSYS */
621938032Speter		return FALSE;
622038032Speter	}
622138032Speter	if (map->map_valcolnm == NULL)
622264562Sgshapiro		/* EMPTY */
622338032Speter		/* nothing */ ;
622438032Speter	else if (strcasecmp(map->map_valcolnm, "name") == 0)
622538032Speter		map->map_valcolno = 1;
622638032Speter	else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
622738032Speter		map->map_valcolno = 2;
622838032Speter	else if (strcasecmp(map->map_valcolnm, "uid") == 0)
622938032Speter		map->map_valcolno = 3;
623038032Speter	else if (strcasecmp(map->map_valcolnm, "gid") == 0)
623138032Speter		map->map_valcolno = 4;
623238032Speter	else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
623338032Speter		map->map_valcolno = 5;
623438032Speter	else if (strcasecmp(map->map_valcolnm, "dir") == 0)
623538032Speter		map->map_valcolno = 6;
623638032Speter	else if (strcasecmp(map->map_valcolnm, "shell") == 0)
623738032Speter		map->map_valcolno = 7;
623838032Speter	else
623938032Speter	{
624038032Speter		syserr("User map %s: unknown column name %s",
624138032Speter			map->map_mname, map->map_valcolnm);
624238032Speter		return FALSE;
624338032Speter	}
624438032Speter	return TRUE;
624538032Speter}
624638032Speter
624738032Speter
624838032Speter/*
624938032Speter**  USER_MAP_LOOKUP -- look up a user in the passwd file.
625038032Speter*/
625138032Speter
625238032Speter/* ARGSUSED3 */
625338032Speterchar *
625438032Speteruser_map_lookup(map, key, av, statp)
625538032Speter	MAP *map;
625638032Speter	char *key;
625738032Speter	char **av;
625838032Speter	int *statp;
625938032Speter{
626038032Speter	struct passwd *pw;
626138032Speter	auto bool fuzzy;
626238032Speter
626338032Speter	if (tTd(38, 20))
626464562Sgshapiro		dprintf("user_map_lookup(%s, %s)\n",
626538032Speter			map->map_mname, key);
626638032Speter
626738032Speter	pw = finduser(key, &fuzzy);
626838032Speter	if (pw == NULL)
626938032Speter		return NULL;
627038032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
627138032Speter		return map_rewrite(map, key, strlen(key), NULL);
627238032Speter	else
627338032Speter	{
627438032Speter		char *rwval = NULL;
627538032Speter		char buf[30];
627638032Speter
627738032Speter		switch (map->map_valcolno)
627838032Speter		{
627938032Speter		  case 0:
628038032Speter		  case 1:
628138032Speter			rwval = pw->pw_name;
628238032Speter			break;
628338032Speter
628438032Speter		  case 2:
628538032Speter			rwval = pw->pw_passwd;
628638032Speter			break;
628738032Speter
628838032Speter		  case 3:
628964562Sgshapiro			snprintf(buf, sizeof buf, "%d", (int) pw->pw_uid);
629038032Speter			rwval = buf;
629138032Speter			break;
629238032Speter
629338032Speter		  case 4:
629464562Sgshapiro			snprintf(buf, sizeof buf, "%d", (int) pw->pw_gid);
629538032Speter			rwval = buf;
629638032Speter			break;
629738032Speter
629838032Speter		  case 5:
629938032Speter			rwval = pw->pw_gecos;
630038032Speter			break;
630138032Speter
630238032Speter		  case 6:
630338032Speter			rwval = pw->pw_dir;
630438032Speter			break;
630538032Speter
630638032Speter		  case 7:
630738032Speter			rwval = pw->pw_shell;
630838032Speter			break;
630938032Speter		}
631038032Speter		return map_rewrite(map, rwval, strlen(rwval), av);
631138032Speter	}
631238032Speter}
631338032Speter/*
631438032Speter**  Program map type.
631538032Speter**
631638032Speter**	This provides access to arbitrary programs.  It should be used
631738032Speter**	only very sparingly, since there is no way to bound the cost
631838032Speter**	of invoking an arbitrary program.
631938032Speter*/
632038032Speter
632138032Speterchar *
632238032Speterprog_map_lookup(map, name, av, statp)
632338032Speter	MAP *map;
632438032Speter	char *name;
632538032Speter	char **av;
632638032Speter	int *statp;
632738032Speter{
632838032Speter	int i;
632964562Sgshapiro	int save_errno;
633038032Speter	int fd;
633164562Sgshapiro	int status;
633238032Speter	auto pid_t pid;
633364562Sgshapiro	register char *p;
633438032Speter	char *rval;
633538032Speter	char *argv[MAXPV + 1];
633638032Speter	char buf[MAXLINE];
633738032Speter
633838032Speter	if (tTd(38, 20))
633964562Sgshapiro		dprintf("prog_map_lookup(%s, %s) %s\n",
634038032Speter			map->map_mname, name, map->map_file);
634138032Speter
634238032Speter	i = 0;
634338032Speter	argv[i++] = map->map_file;
634438032Speter	if (map->map_rebuild != NULL)
634538032Speter	{
634638032Speter		snprintf(buf, sizeof buf, "%s", map->map_rebuild);
634738032Speter		for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
634838032Speter		{
634938032Speter			if (i >= MAXPV - 1)
635038032Speter				break;
635138032Speter			argv[i++] = p;
635238032Speter		}
635338032Speter	}
635438032Speter	argv[i++] = name;
635538032Speter	argv[i] = NULL;
635638032Speter	if (tTd(38, 21))
635738032Speter	{
635864562Sgshapiro		dprintf("prog_open:");
635938032Speter		for (i = 0; argv[i] != NULL; i++)
636064562Sgshapiro			dprintf(" %s", argv[i]);
636164562Sgshapiro		dprintf("\n");
636238032Speter	}
636338032Speter	(void) blocksignal(SIGCHLD);
636438032Speter	pid = prog_open(argv, &fd, CurEnv);
636538032Speter	if (pid < 0)
636638032Speter	{
636738032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
636838032Speter			syserr("prog_map_lookup(%s) failed (%s) -- closing",
636938032Speter				map->map_mname, errstring(errno));
637038032Speter		else if (tTd(38, 9))
637164562Sgshapiro			dprintf("prog_map_lookup(%s) failed (%s) -- closing",
637238032Speter				map->map_mname, errstring(errno));
637338032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
637438032Speter		*statp = EX_OSFILE;
637538032Speter		return NULL;
637638032Speter	}
637738032Speter	i = read(fd, buf, sizeof buf - 1);
637838032Speter	if (i < 0)
637938032Speter	{
638038032Speter		syserr("prog_map_lookup(%s): read error %s\n",
638138032Speter			map->map_mname, errstring(errno));
638238032Speter		rval = NULL;
638338032Speter	}
638438032Speter	else if (i == 0)
638538032Speter	{
638638032Speter		if (tTd(38, 20))
638764562Sgshapiro			dprintf("prog_map_lookup(%s): empty answer\n",
638838032Speter				map->map_mname);
638938032Speter		rval = NULL;
639038032Speter	}
639138032Speter	else
639238032Speter	{
639338032Speter		buf[i] = '\0';
639438032Speter		p = strchr(buf, '\n');
639538032Speter		if (p != NULL)
639638032Speter			*p = '\0';
639738032Speter
639838032Speter		/* collect the return value */
639938032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
640038032Speter			rval = map_rewrite(map, name, strlen(name), NULL);
640138032Speter		else
640277349Sgshapiro			rval = map_rewrite(map, buf, strlen(buf), av);
640338032Speter
640438032Speter		/* now flush any additional output */
640538032Speter		while ((i = read(fd, buf, sizeof buf)) > 0)
640638032Speter			continue;
640738032Speter	}
640838032Speter
640938032Speter	/* wait for the process to terminate */
641064562Sgshapiro	(void) close(fd);
641164562Sgshapiro	status = waitfor(pid);
641264562Sgshapiro	save_errno = errno;
641338032Speter	(void) releasesignal(SIGCHLD);
641464562Sgshapiro	errno = save_errno;
641538032Speter
641664562Sgshapiro	if (status == -1)
641738032Speter	{
641838032Speter		syserr("prog_map_lookup(%s): wait error %s\n",
641938032Speter			map->map_mname, errstring(errno));
642038032Speter		*statp = EX_SOFTWARE;
642138032Speter		rval = NULL;
642238032Speter	}
642364562Sgshapiro	else if (WIFEXITED(status))
642438032Speter	{
642564562Sgshapiro		if ((*statp = WEXITSTATUS(status)) != EX_OK)
642638032Speter			rval = NULL;
642738032Speter	}
642838032Speter	else
642938032Speter	{
643038032Speter		syserr("prog_map_lookup(%s): child died on signal %d",
643164562Sgshapiro			map->map_mname, status);
643238032Speter		*statp = EX_UNAVAILABLE;
643338032Speter		rval = NULL;
643438032Speter	}
643538032Speter	return rval;
643638032Speter}
643738032Speter/*
643838032Speter**  Sequenced map type.
643938032Speter**
644038032Speter**	Tries each map in order until something matches, much like
644138032Speter**	implicit.  Stores go to the first map in the list that can
644238032Speter**	support storing.
644338032Speter**
644438032Speter**	This is slightly unusual in that there are two interfaces.
644538032Speter**	The "sequence" interface lets you stack maps arbitrarily.
644638032Speter**	The "switch" interface builds a sequence map by looking
644738032Speter**	at a system-dependent configuration file such as
644838032Speter**	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
644938032Speter**
645038032Speter**	We don't need an explicit open, since all maps are
645138032Speter**	opened during startup, including underlying maps.
645238032Speter*/
645338032Speter
645438032Speter/*
645538032Speter**  SEQ_MAP_PARSE -- Sequenced map parsing
645638032Speter*/
645738032Speter
645838032Speterbool
645938032Speterseq_map_parse(map, ap)
646038032Speter	MAP *map;
646138032Speter	char *ap;
646238032Speter{
646338032Speter	int maxmap;
646438032Speter
646538032Speter	if (tTd(38, 2))
646664562Sgshapiro		dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
646738032Speter	maxmap = 0;
646838032Speter	while (*ap != '\0')
646938032Speter	{
647038032Speter		register char *p;
647138032Speter		STAB *s;
647238032Speter
647338032Speter		/* find beginning of map name */
647438032Speter		while (isascii(*ap) && isspace(*ap))
647538032Speter			ap++;
647664562Sgshapiro		for (p = ap;
647764562Sgshapiro		     (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.';
647864562Sgshapiro		     p++)
647938032Speter			continue;
648038032Speter		if (*p != '\0')
648138032Speter			*p++ = '\0';
648238032Speter		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
648338032Speter			p++;
648438032Speter		if (*ap == '\0')
648538032Speter		{
648638032Speter			ap = p;
648738032Speter			continue;
648838032Speter		}
648938032Speter		s = stab(ap, ST_MAP, ST_FIND);
649038032Speter		if (s == NULL)
649138032Speter		{
649238032Speter			syserr("Sequence map %s: unknown member map %s",
649338032Speter				map->map_mname, ap);
649438032Speter		}
649538032Speter		else if (maxmap == MAXMAPSTACK)
649638032Speter		{
649738032Speter			syserr("Sequence map %s: too many member maps (%d max)",
649838032Speter				map->map_mname, MAXMAPSTACK);
649938032Speter			maxmap++;
650038032Speter		}
650138032Speter		else if (maxmap < MAXMAPSTACK)
650238032Speter		{
650338032Speter			map->map_stack[maxmap++] = &s->s_map;
650438032Speter		}
650538032Speter		ap = p;
650638032Speter	}
650738032Speter	return TRUE;
650838032Speter}
650938032Speter
651038032Speter
651138032Speter/*
651238032Speter**  SWITCH_MAP_OPEN -- open a switched map
651338032Speter**
651438032Speter**	This looks at the system-dependent configuration and builds
651538032Speter**	a sequence map that does the same thing.
651638032Speter**
651738032Speter**	Every system must define a switch_map_find routine in conf.c
651838032Speter**	that will return the list of service types associated with a
651938032Speter**	given service class.
652038032Speter*/
652138032Speter
652238032Speterbool
652338032Speterswitch_map_open(map, mode)
652438032Speter	MAP *map;
652538032Speter	int mode;
652638032Speter{
652738032Speter	int mapno;
652838032Speter	int nmaps;
652938032Speter	char *maptype[MAXMAPSTACK];
653038032Speter
653138032Speter	if (tTd(38, 2))
653264562Sgshapiro		dprintf("switch_map_open(%s, %s, %d)\n",
653338032Speter			map->map_mname, map->map_file, mode);
653438032Speter
653538032Speter	mode &= O_ACCMODE;
653638032Speter	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
653738032Speter	if (tTd(38, 19))
653838032Speter	{
653964562Sgshapiro		dprintf("\tswitch_map_find => %d\n", nmaps);
654038032Speter		for (mapno = 0; mapno < nmaps; mapno++)
654164562Sgshapiro			dprintf("\t\t%s\n", maptype[mapno]);
654238032Speter	}
654338032Speter	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
654438032Speter		return FALSE;
654538032Speter
654638032Speter	for (mapno = 0; mapno < nmaps; mapno++)
654738032Speter	{
654838032Speter		register STAB *s;
654938032Speter		char nbuf[MAXNAME + 1];
655038032Speter
655138032Speter		if (maptype[mapno] == NULL)
655238032Speter			continue;
655338032Speter		(void) snprintf(nbuf, sizeof nbuf, "%s.%s",
655438032Speter			map->map_mname, maptype[mapno]);
655538032Speter		s = stab(nbuf, ST_MAP, ST_FIND);
655638032Speter		if (s == NULL)
655738032Speter		{
655838032Speter			syserr("Switch map %s: unknown member map %s",
655938032Speter				map->map_mname, nbuf);
656038032Speter		}
656138032Speter		else
656238032Speter		{
656338032Speter			map->map_stack[mapno] = &s->s_map;
656438032Speter			if (tTd(38, 4))
656564562Sgshapiro				dprintf("\tmap_stack[%d] = %s:%s\n",
656638032Speter					mapno, s->s_map.map_class->map_cname,
656738032Speter					nbuf);
656838032Speter		}
656938032Speter	}
657038032Speter	return TRUE;
657138032Speter}
657238032Speter
657338032Speter
657438032Speter/*
657538032Speter**  SEQ_MAP_CLOSE -- close all underlying maps
657638032Speter*/
657738032Speter
657838032Spetervoid
657938032Speterseq_map_close(map)
658038032Speter	MAP *map;
658138032Speter{
658238032Speter	int mapno;
658338032Speter
658438032Speter	if (tTd(38, 9))
658564562Sgshapiro		dprintf("seq_map_close(%s)\n", map->map_mname);
658638032Speter
658738032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
658838032Speter	{
658938032Speter		MAP *mm = map->map_stack[mapno];
659038032Speter
659138032Speter		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
659238032Speter			continue;
659377349Sgshapiro		mm->map_mflags |= MF_CLOSING;
659438032Speter		mm->map_class->map_close(mm);
659577349Sgshapiro		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
659638032Speter	}
659738032Speter}
659838032Speter
659938032Speter
660038032Speter/*
660138032Speter**  SEQ_MAP_LOOKUP -- sequenced map lookup
660238032Speter*/
660338032Speter
660438032Speterchar *
660538032Speterseq_map_lookup(map, key, args, pstat)
660638032Speter	MAP *map;
660738032Speter	char *key;
660838032Speter	char **args;
660938032Speter	int *pstat;
661038032Speter{
661138032Speter	int mapno;
661238032Speter	int mapbit = 0x01;
661338032Speter	bool tempfail = FALSE;
661438032Speter
661538032Speter	if (tTd(38, 20))
661664562Sgshapiro		dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
661738032Speter
661838032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
661938032Speter	{
662038032Speter		MAP *mm = map->map_stack[mapno];
662138032Speter		char *rv;
662238032Speter
662338032Speter		if (mm == NULL)
662438032Speter			continue;
662564562Sgshapiro		if (!bitset(MF_OPEN, mm->map_mflags) &&
662664562Sgshapiro		    !openmap(mm))
662738032Speter		{
662838032Speter			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
662938032Speter			{
663038032Speter				*pstat = EX_UNAVAILABLE;
663138032Speter				return NULL;
663238032Speter			}
663338032Speter			continue;
663438032Speter		}
663538032Speter		*pstat = EX_OK;
663638032Speter		rv = mm->map_class->map_lookup(mm, key, args, pstat);
663738032Speter		if (rv != NULL)
663838032Speter			return rv;
663938032Speter		if (*pstat == EX_TEMPFAIL)
664038032Speter		{
664138032Speter			if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
664238032Speter				return NULL;
664338032Speter			tempfail = TRUE;
664438032Speter		}
664538032Speter		else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
664638032Speter			break;
664738032Speter	}
664838032Speter	if (tempfail)
664938032Speter		*pstat = EX_TEMPFAIL;
665038032Speter	else if (*pstat == EX_OK)
665138032Speter		*pstat = EX_NOTFOUND;
665238032Speter	return NULL;
665338032Speter}
665438032Speter
665538032Speter
665638032Speter/*
665738032Speter**  SEQ_MAP_STORE -- sequenced map store
665838032Speter*/
665938032Speter
666038032Spetervoid
666138032Speterseq_map_store(map, key, val)
666238032Speter	MAP *map;
666338032Speter	char *key;
666438032Speter	char *val;
666538032Speter{
666638032Speter	int mapno;
666738032Speter
666838032Speter	if (tTd(38, 12))
666964562Sgshapiro		dprintf("seq_map_store(%s, %s, %s)\n",
667038032Speter			map->map_mname, key, val);
667138032Speter
667238032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
667338032Speter	{
667438032Speter		MAP *mm = map->map_stack[mapno];
667538032Speter
667638032Speter		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
667738032Speter			continue;
667838032Speter
667938032Speter		mm->map_class->map_store(mm, key, val);
668038032Speter		return;
668138032Speter	}
668238032Speter	syserr("seq_map_store(%s, %s, %s): no writable map",
668338032Speter		map->map_mname, key, val);
668438032Speter}
668538032Speter/*
668638032Speter**  NULL stubs
668738032Speter*/
668838032Speter
668938032Speter/* ARGSUSED */
669038032Speterbool
669138032Speternull_map_open(map, mode)
669238032Speter	MAP *map;
669338032Speter	int mode;
669438032Speter{
669538032Speter	return TRUE;
669638032Speter}
669738032Speter
669838032Speter/* ARGSUSED */
669938032Spetervoid
670038032Speternull_map_close(map)
670138032Speter	MAP *map;
670238032Speter{
670338032Speter	return;
670438032Speter}
670538032Speter
670638032Speterchar *
670738032Speternull_map_lookup(map, key, args, pstat)
670838032Speter	MAP *map;
670938032Speter	char *key;
671038032Speter	char **args;
671138032Speter	int *pstat;
671238032Speter{
671338032Speter	*pstat = EX_NOTFOUND;
671438032Speter	return NULL;
671538032Speter}
671638032Speter
671738032Speter/* ARGSUSED */
671838032Spetervoid
671938032Speternull_map_store(map, key, val)
672038032Speter	MAP *map;
672138032Speter	char *key;
672238032Speter	char *val;
672338032Speter{
672438032Speter	return;
672538032Speter}
672638032Speter
672738032Speter
672838032Speter/*
672938032Speter**  BOGUS stubs
673038032Speter*/
673138032Speter
673238032Speterchar *
673338032Speterbogus_map_lookup(map, key, args, pstat)
673438032Speter	MAP *map;
673538032Speter	char *key;
673638032Speter	char **args;
673738032Speter	int *pstat;
673838032Speter{
673938032Speter	*pstat = EX_TEMPFAIL;
674038032Speter	return NULL;
674138032Speter}
674238032Speter
674338032SpeterMAPCLASS	BogusMapClass =
674438032Speter{
674538032Speter	"bogus-map",		NULL,		0,
674638032Speter	NULL,		bogus_map_lookup,	null_map_store,
674738032Speter	null_map_open,	null_map_close,
674838032Speter};
674938032Speter/*
675064562Sgshapiro**  MACRO modules
675164562Sgshapiro*/
675264562Sgshapiro
675364562Sgshapirochar *
675464562Sgshapiromacro_map_lookup(map, name, av, statp)
675564562Sgshapiro	MAP *map;
675664562Sgshapiro	char *name;
675764562Sgshapiro	char **av;
675864562Sgshapiro	int *statp;
675964562Sgshapiro{
676064562Sgshapiro	int mid;
676164562Sgshapiro
676264562Sgshapiro	if (tTd(38, 20))
676364562Sgshapiro		dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
676464562Sgshapiro			name == NULL ? "NULL" : name);
676564562Sgshapiro
676664562Sgshapiro	if (name == NULL ||
676764562Sgshapiro	    *name == '\0' ||
676864562Sgshapiro	    (mid = macid(name, NULL)) == '\0')
676964562Sgshapiro	{
677064562Sgshapiro		*statp = EX_CONFIG;
677164562Sgshapiro		return NULL;
677264562Sgshapiro	}
677364562Sgshapiro
677464562Sgshapiro	if (av[1] == NULL)
677564562Sgshapiro		define(mid, NULL, CurEnv);
677664562Sgshapiro	else
677764562Sgshapiro		define(mid, newstr(av[1]), CurEnv);
677864562Sgshapiro
677964562Sgshapiro	*statp = EX_OK;
678064562Sgshapiro	return "";
678164562Sgshapiro}
678264562Sgshapiro/*
678338032Speter**  REGEX modules
678438032Speter*/
678538032Speter
678638032Speter#ifdef MAP_REGEX
678738032Speter
678838032Speter# include <regex.h>
678938032Speter
679038032Speter# define DEFAULT_DELIM	CONDELSE
679138032Speter
679238032Speter# define END_OF_FIELDS	-1
679338032Speter
679438032Speter# define ERRBUF_SIZE	80
679538032Speter# define MAX_MATCH	32
679638032Speter
679764562Sgshapiro# define xnalloc(s)	memset(xalloc(s), '\0', s);
679838032Speter
679938032Speterstruct regex_map
680038032Speter{
680171345Sgshapiro	regex_t	*regex_pattern_buf;	/* xalloc it */
680238032Speter	int	*regex_subfields;	/* move to type MAP */
680364562Sgshapiro	char	*regex_delim;		/* move to type MAP */
680438032Speter};
680538032Speter
680638032Speterstatic int
680738032Speterparse_fields(s, ibuf, blen, nr_substrings)
680838032Speter	char *s;
680938032Speter	int *ibuf;		/* array */
681038032Speter	int blen;		/* number of elements in ibuf */
681138032Speter	int nr_substrings;	/* number of substrings in the pattern */
681238032Speter{
681338032Speter	register char *cp;
681438032Speter	int i = 0;
681538032Speter	bool lastone = FALSE;
681638032Speter
681738032Speter	blen--;		/* for terminating END_OF_FIELDS */
681838032Speter	cp = s;
681938032Speter	do
682038032Speter	{
682138032Speter		for (;; cp++)
682238032Speter		{
682338032Speter			if (*cp == ',')
682438032Speter			{
682538032Speter				*cp = '\0';
682638032Speter				break;
682738032Speter			}
682838032Speter			if (*cp == '\0')
682938032Speter			{
683038032Speter				lastone = TRUE;
683138032Speter				break;
683238032Speter			}
683338032Speter		}
683438032Speter		if (i < blen)
683538032Speter		{
683638032Speter			int val = atoi(s);
683738032Speter
683838032Speter			if (val < 0 || val >= nr_substrings)
683938032Speter			{
684038032Speter				syserr("field (%d) out of range, only %d substrings in pattern",
684138032Speter				       val, nr_substrings);
684238032Speter				return -1;
684338032Speter			}
684438032Speter			ibuf[i++] = val;
684538032Speter		}
684638032Speter		else
684738032Speter		{
684838032Speter			syserr("too many fields, %d max\n", blen);
684938032Speter			return -1;
685038032Speter		}
685138032Speter		s = ++cp;
685238032Speter	} while (!lastone);
685338032Speter	ibuf[i] = END_OF_FIELDS;
685438032Speter	return i;
685538032Speter}
685638032Speter
685738032Speterbool
685838032Speterregex_map_init(map, ap)
685938032Speter	MAP *map;
686038032Speter	char *ap;
686138032Speter{
686238032Speter	int regerr;
686338032Speter	struct regex_map *map_p;
686438032Speter	register char *p;
686538032Speter	char *sub_param = NULL;
686638032Speter	int pflags;
686738032Speter	static char defdstr[] = { (char)DEFAULT_DELIM, '\0' };
686838032Speter
686938032Speter	if (tTd(38, 2))
687064562Sgshapiro		dprintf("regex_map_init: mapname '%s', args '%s'\n",
687164562Sgshapiro			map->map_mname, ap);
687238032Speter
687338032Speter	pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
687438032Speter
687538032Speter	p = ap;
687638032Speter
687764562Sgshapiro	map_p = (struct regex_map *) xnalloc(sizeof *map_p);
687871345Sgshapiro	map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t));
687938032Speter
688038032Speter	for (;;)
688164562Sgshapiro	{
688238032Speter		while (isascii(*p) && isspace(*p))
688338032Speter			p++;
688438032Speter		if (*p != '-')
688538032Speter			break;
688638032Speter		switch (*++p)
688738032Speter		{
688838032Speter		  case 'n':	/* not */
688938032Speter			map->map_mflags |= MF_REGEX_NOT;
689038032Speter			break;
689138032Speter
689238032Speter		  case 'f':	/* case sensitive */
689338032Speter			map->map_mflags |= MF_NOFOLDCASE;
689438032Speter			pflags &= ~REG_ICASE;
689538032Speter			break;
689638032Speter
689738032Speter		  case 'b':	/* basic regular expressions */
689838032Speter			pflags &= ~REG_EXTENDED;
689938032Speter			break;
690038032Speter
690138032Speter		  case 's':	/* substring match () syntax */
690238032Speter			sub_param = ++p;
690338032Speter			pflags &= ~REG_NOSUB;
690438032Speter			break;
690538032Speter
690638032Speter		  case 'd':	/* delimiter */
690764562Sgshapiro			map_p->regex_delim = ++p;
690838032Speter			break;
690938032Speter
691038032Speter		  case 'a':	/* map append */
691138032Speter			map->map_app = ++p;
691238032Speter			break;
691338032Speter
691438032Speter		  case 'm':	/* matchonly */
691538032Speter			map->map_mflags |= MF_MATCHONLY;
691638032Speter			break;
691738032Speter
691864562Sgshapiro		  case 'S':
691964562Sgshapiro			map->map_spacesub = *++p;
692064562Sgshapiro			break;
692164562Sgshapiro
692264562Sgshapiro		  case 'D':
692364562Sgshapiro			map->map_mflags |= MF_DEFER;
692464562Sgshapiro			break;
692564562Sgshapiro
692638032Speter		}
692764562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
692864562Sgshapiro			p++;
692964562Sgshapiro		if (*p != '\0')
693064562Sgshapiro			*p++ = '\0';
693138032Speter	}
693238032Speter	if (tTd(38, 3))
693364562Sgshapiro		dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
693438032Speter
693571345Sgshapiro	if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0)
693638032Speter	{
693738032Speter		/* Errorhandling */
693838032Speter		char errbuf[ERRBUF_SIZE];
693938032Speter
694071345Sgshapiro		(void) regerror(regerr, map_p->regex_pattern_buf,
694164562Sgshapiro			 errbuf, ERRBUF_SIZE);
694238032Speter		syserr("pattern-compile-error: %s\n", errbuf);
694377349Sgshapiro		sm_free(map_p->regex_pattern_buf);
694477349Sgshapiro		sm_free(map_p);
694538032Speter		return FALSE;
694638032Speter	}
694738032Speter
694838032Speter	if (map->map_app != NULL)
694938032Speter		map->map_app = newstr(map->map_app);
695064562Sgshapiro	if (map_p->regex_delim != NULL)
695164562Sgshapiro		map_p->regex_delim = newstr(map_p->regex_delim);
695238032Speter	else
695364562Sgshapiro		map_p->regex_delim = defdstr;
695438032Speter
695538032Speter	if (!bitset(REG_NOSUB, pflags))
695638032Speter	{
695738032Speter		/* substring matching */
695838032Speter		int substrings;
695964562Sgshapiro		int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1));
696038032Speter
696171345Sgshapiro		substrings = map_p->regex_pattern_buf->re_nsub + 1;
696238032Speter
696338032Speter		if (tTd(38, 3))
696464562Sgshapiro			dprintf("regex_map_init: nr of substrings %d\n",
696564562Sgshapiro				substrings);
696638032Speter
696738032Speter		if (substrings >= MAX_MATCH)
696838032Speter		{
696938032Speter			syserr("too many substrings, %d max\n", MAX_MATCH);
697077349Sgshapiro			sm_free(map_p->regex_pattern_buf);
697177349Sgshapiro			sm_free(map_p);
697238032Speter			return FALSE;
697338032Speter		}
697438032Speter		if (sub_param != NULL && sub_param[0] != '\0')
697538032Speter		{
697638032Speter			/* optional parameter -sfields */
697738032Speter			if (parse_fields(sub_param, fields,
697838032Speter					 MAX_MATCH + 1, substrings) == -1)
697938032Speter				return FALSE;
698038032Speter		}
698138032Speter		else
698238032Speter		{
698364562Sgshapiro			/* set default fields */
698438032Speter			int i;
698538032Speter
698638032Speter			for (i = 0; i < substrings; i++)
698738032Speter				fields[i] = i;
698838032Speter			fields[i] = END_OF_FIELDS;
698938032Speter		}
699038032Speter		map_p->regex_subfields = fields;
699138032Speter		if (tTd(38, 3))
699238032Speter		{
699338032Speter			int *ip;
699438032Speter
699564562Sgshapiro			dprintf("regex_map_init: subfields");
699638032Speter			for (ip = fields; *ip != END_OF_FIELDS; ip++)
699764562Sgshapiro				dprintf(" %d", *ip);
699864562Sgshapiro			dprintf("\n");
699938032Speter		}
700038032Speter	}
700138032Speter	map->map_db1 = (ARBPTR_T)map_p;	/* dirty hack */
700238032Speter
700338032Speter	return TRUE;
700438032Speter}
700538032Speter
700638032Speterstatic char *
700738032Speterregex_map_rewrite(map, s, slen, av)
700838032Speter	MAP *map;
700938032Speter	const char *s;
701038032Speter	size_t slen;
701138032Speter	char **av;
701238032Speter{
701338032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
701438032Speter		return map_rewrite(map, av[0], strlen(av[0]), NULL);
701538032Speter	else
701677349Sgshapiro		return map_rewrite(map, s, slen, av);
701738032Speter}
701838032Speter
701938032Speterchar *
702038032Speterregex_map_lookup(map, name, av, statp)
702138032Speter	MAP *map;
702238032Speter	char *name;
702338032Speter	char **av;
702438032Speter	int *statp;
702538032Speter{
702638032Speter	int reg_res;
702738032Speter	struct regex_map *map_p;
702838032Speter	regmatch_t pmatch[MAX_MATCH];
702938032Speter
703038032Speter	if (tTd(38, 20))
703138032Speter	{
703238032Speter		char **cpp;
703338032Speter
703464562Sgshapiro		dprintf("regex_map_lookup: key '%s'\n", name);
703564562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
703664562Sgshapiro			dprintf("regex_map_lookup: arg '%s'\n", *cpp);
703738032Speter	}
703838032Speter
703938032Speter	map_p = (struct regex_map *)(map->map_db1);
704071345Sgshapiro	reg_res = regexec(map_p->regex_pattern_buf,
704164562Sgshapiro			  name, MAX_MATCH, pmatch, 0);
704238032Speter
704338032Speter	if (bitset(MF_REGEX_NOT, map->map_mflags))
704438032Speter	{
704538032Speter		/* option -n */
704638032Speter		if (reg_res == REG_NOMATCH)
704738032Speter			return regex_map_rewrite(map, "", (size_t)0, av);
704838032Speter		else
704938032Speter			return NULL;
705038032Speter	}
705138032Speter	if (reg_res == REG_NOMATCH)
705238032Speter		return NULL;
705338032Speter
705438032Speter	if (map_p->regex_subfields != NULL)
705538032Speter	{
705638032Speter		/* option -s */
705738032Speter		static char retbuf[MAXNAME];
705838032Speter		int fields[MAX_MATCH + 1];
705938032Speter		bool first = TRUE;
706038032Speter		int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
706138032Speter		bool quotemode = FALSE, bslashmode = FALSE;
706238032Speter		register char *dp, *sp;
706338032Speter		char *endp, *ldp;
706438032Speter		int *ip;
706538032Speter
706638032Speter		dp = retbuf;
706738032Speter		ldp = retbuf + sizeof(retbuf) - 1;
706838032Speter
706938032Speter		if (av[1] != NULL)
707038032Speter		{
707138032Speter			if (parse_fields(av[1], fields, MAX_MATCH + 1,
707271345Sgshapiro					 (int) map_p->regex_pattern_buf->re_nsub + 1) == -1)
707338032Speter			{
707438032Speter				*statp = EX_CONFIG;
707538032Speter				return NULL;
707638032Speter			}
707738032Speter			ip = fields;
707838032Speter		}
707938032Speter		else
708038032Speter			ip = map_p->regex_subfields;
708138032Speter
708238032Speter		for ( ; *ip != END_OF_FIELDS; ip++)
708338032Speter		{
708438032Speter			if (!first)
708538032Speter			{
708664562Sgshapiro				for (sp = map_p->regex_delim; *sp; sp++)
708738032Speter				{
708838032Speter					if (dp < ldp)
708938032Speter						*dp++ = *sp;
709038032Speter				}
709138032Speter			}
709238032Speter			else
709338032Speter				first = FALSE;
709438032Speter
709538032Speter
709671345Sgshapiro			if (*ip >= MAX_MATCH ||
709771345Sgshapiro			    pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
709838032Speter				continue;
709938032Speter
710038032Speter			sp = name + pmatch[*ip].rm_so;
710138032Speter			endp = name + pmatch[*ip].rm_eo;
710238032Speter			for (; endp > sp; sp++)
710338032Speter			{
710438032Speter				if (dp < ldp)
710538032Speter				{
710664562Sgshapiro					if (bslashmode)
710764562Sgshapiro					{
710838032Speter						*dp++ = *sp;
710938032Speter						bslashmode = FALSE;
711038032Speter					}
711164562Sgshapiro					else if (quotemode && *sp != '"' &&
711238032Speter						*sp != '\\')
711338032Speter					{
711438032Speter						*dp++ = *sp;
711538032Speter					}
711638032Speter					else switch(*dp++ = *sp)
711738032Speter					{
711838032Speter						case '\\':
711938032Speter						bslashmode = TRUE;
712038032Speter						break;
712138032Speter
712238032Speter						case '(':
712338032Speter						cmntcnt++;
712438032Speter						break;
712538032Speter
712638032Speter						case ')':
712738032Speter						cmntcnt--;
712838032Speter						break;
712938032Speter
713038032Speter						case '<':
713138032Speter						anglecnt++;
713238032Speter						break;
713338032Speter
713438032Speter						case '>':
713538032Speter						anglecnt--;
713638032Speter						break;
713738032Speter
713838032Speter						case ' ':
713938032Speter						spacecnt++;
714038032Speter						break;
714138032Speter
714238032Speter						case '"':
714338032Speter						quotemode = !quotemode;
714438032Speter						break;
714538032Speter					}
714638032Speter				}
714738032Speter			}
714838032Speter		}
714938032Speter		if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
715038032Speter		    bslashmode || spacecnt != 0)
715138032Speter		{
715264562Sgshapiro			sm_syslog(LOG_WARNING, NOQID,
715364562Sgshapiro				  "Warning: regex may cause prescan() failure map=%s lookup=%s",
715464562Sgshapiro				  map->map_mname, name);
715538032Speter			return NULL;
715638032Speter		}
715738032Speter
715838032Speter		*dp = '\0';
715938032Speter
716038032Speter		return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
716138032Speter	}
716238032Speter	return regex_map_rewrite(map, "", (size_t)0, av);
716338032Speter}
716438032Speter#endif /* MAP_REGEX */
716564562Sgshapiro/*
716664562Sgshapiro**  NSD modules
716764562Sgshapiro*/
716864562Sgshapiro#ifdef MAP_NSD
716964562Sgshapiro
717064562Sgshapiro# include <ndbm.h>
717164562Sgshapiro# define _DATUM_DEFINED
717264562Sgshapiro# include <ns_api.h>
717364562Sgshapiro
717464562Sgshapirotypedef struct ns_map_list
717564562Sgshapiro{
717664562Sgshapiro	ns_map_t *map;
717764562Sgshapiro	char *mapname;
717864562Sgshapiro	struct ns_map_list *next;
717964562Sgshapiro} ns_map_list_t;
718064562Sgshapiro
718164562Sgshapirostatic ns_map_t *
718264562Sgshapirons_map_t_find(mapname)
718364562Sgshapiro	char *mapname;
718464562Sgshapiro{
718564562Sgshapiro	static ns_map_list_t *ns_maps = NULL;
718664562Sgshapiro	ns_map_list_t *ns_map;
718764562Sgshapiro
718864562Sgshapiro	/* walk the list of maps looking for the correctly named map */
718964562Sgshapiro	for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next)
719064562Sgshapiro	{
719164562Sgshapiro		if (strcmp(ns_map->mapname, mapname) == 0)
719264562Sgshapiro			break;
719364562Sgshapiro	}
719464562Sgshapiro
719564562Sgshapiro	/* if we are looking at a NULL ns_map_list_t, then create a new one */
719664562Sgshapiro	if (ns_map == NULL)
719764562Sgshapiro	{
719864562Sgshapiro		ns_map = (ns_map_list_t *) xalloc(sizeof *ns_map);
719964562Sgshapiro		ns_map->mapname = newstr(mapname);
720064562Sgshapiro		ns_map->map = (ns_map_t *) xalloc(sizeof *ns_map->map);
720164562Sgshapiro		ns_map->next = ns_maps;
720264562Sgshapiro		ns_maps = ns_map;
720364562Sgshapiro	}
720464562Sgshapiro	return ns_map->map;
720564562Sgshapiro}
720664562Sgshapiro
720764562Sgshapirochar *
720864562Sgshapironsd_map_lookup(map, name, av, statp)
720964562Sgshapiro	MAP *map;
721064562Sgshapiro	char *name;
721164562Sgshapiro	char **av;
721264562Sgshapiro	int *statp;
721364562Sgshapiro{
721471345Sgshapiro	int buflen, r;
721564562Sgshapiro	char *p;
721664562Sgshapiro	ns_map_t *ns_map;
721764562Sgshapiro	char keybuf[MAXNAME + 1];
721864562Sgshapiro	char buf[MAXLINE];
721964562Sgshapiro
722064562Sgshapiro	if (tTd(38, 20))
722164562Sgshapiro		dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
722264562Sgshapiro
722364562Sgshapiro	buflen = strlen(name);
722464562Sgshapiro	if (buflen > sizeof keybuf - 1)
722564562Sgshapiro		buflen = sizeof keybuf - 1;
722664562Sgshapiro	memmove(keybuf, name, buflen);
722764562Sgshapiro	keybuf[buflen] = '\0';
722864562Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
722964562Sgshapiro		makelower(keybuf);
723064562Sgshapiro
723164562Sgshapiro	ns_map = ns_map_t_find(map->map_file);
723264562Sgshapiro	if (ns_map == NULL)
723364562Sgshapiro	{
723464562Sgshapiro		if (tTd(38, 20))
723564562Sgshapiro			dprintf("nsd_map_t_find failed\n");
723671345Sgshapiro		*statp = EX_UNAVAILABLE;
723764562Sgshapiro		return NULL;
723864562Sgshapiro	}
723971345Sgshapiro	r = ns_lookup(ns_map, NULL, map->map_file, keybuf, NULL, buf, MAXLINE);
724071345Sgshapiro	if (r == NS_UNAVAIL || r == NS_TRYAGAIN)
724171345Sgshapiro	{
724271345Sgshapiro		*statp = EX_TEMPFAIL;
724364562Sgshapiro		return NULL;
724471345Sgshapiro	}
724577349Sgshapiro	if (r == NS_BADREQ
724677349Sgshapiro# ifdef NS_NOPERM
724777349Sgshapiro	    || r == NS_NOPERM
724877349Sgshapiro# endif /* NS_NOPERM */
724977349Sgshapiro	    )
725071345Sgshapiro	{
725171345Sgshapiro		*statp = EX_CONFIG;
725271345Sgshapiro		return NULL;
725371345Sgshapiro	}
725471345Sgshapiro	if (r != NS_SUCCESS)
725571345Sgshapiro	{
725671345Sgshapiro		*statp = EX_NOTFOUND;
725771345Sgshapiro		return NULL;
725871345Sgshapiro	}
725964562Sgshapiro
726071345Sgshapiro	*statp = EX_OK;
726171345Sgshapiro
726264562Sgshapiro	/* Null out trailing \n */
726364562Sgshapiro	if ((p = strchr(buf, '\n')) != NULL)
726464562Sgshapiro		*p = '\0';
726564562Sgshapiro
726664562Sgshapiro	return map_rewrite(map, buf, strlen(buf), av);
726764562Sgshapiro}
726864562Sgshapiro#endif /* MAP_NSD */
726964562Sgshapiro
727064562Sgshapirochar *
727164562Sgshapiroarith_map_lookup(map, name, av, statp)
727264562Sgshapiro	MAP *map;
727364562Sgshapiro	char *name;
727464562Sgshapiro	char **av;
727564562Sgshapiro	int *statp;
727664562Sgshapiro{
727764562Sgshapiro	long r;
727864562Sgshapiro	long v[2];
727964562Sgshapiro	bool res = FALSE;
728064562Sgshapiro	bool boolres;
728164562Sgshapiro	static char result[16];
728264562Sgshapiro	char **cpp;
728364562Sgshapiro
728464562Sgshapiro	if (tTd(38, 2))
728564562Sgshapiro	{
728664562Sgshapiro		dprintf("arith_map_lookup: key '%s'\n", name);
728764562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
728864562Sgshapiro			dprintf("arith_map_lookup: arg '%s'\n", *cpp);
728964562Sgshapiro	}
729064562Sgshapiro	r = 0;
729164562Sgshapiro	boolres = FALSE;
729264562Sgshapiro	cpp = av;
729364562Sgshapiro	*statp = EX_OK;
729464562Sgshapiro
729564562Sgshapiro	/*
729664562Sgshapiro	**  read arguments for arith map
729764562Sgshapiro	**  - no check is made whether they are really numbers
729864562Sgshapiro	**  - just ignores args after the second
729964562Sgshapiro	*/
730064562Sgshapiro	for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
730164562Sgshapiro		v[r++] = strtol(*cpp, NULL, 0);
730264562Sgshapiro
730364562Sgshapiro	/* operator and (at least) two operands given? */
730464562Sgshapiro	if (name != NULL && r == 2)
730564562Sgshapiro	{
730664562Sgshapiro		switch(*name)
730764562Sgshapiro		{
730864562Sgshapiro#if _FFR_ARITH
730964562Sgshapiro		  case '|':
731064562Sgshapiro			r = v[0] | v[1];
731164562Sgshapiro			break;
731264562Sgshapiro
731364562Sgshapiro		  case '&':
731464562Sgshapiro			r = v[0] & v[1];
731564562Sgshapiro			break;
731664562Sgshapiro
731764562Sgshapiro		  case '%':
731864562Sgshapiro			if (v[1] == 0)
731964562Sgshapiro				return NULL;
732064562Sgshapiro			r = v[0] % v[1];
732164562Sgshapiro			break;
732264562Sgshapiro#endif /* _FFR_ARITH */
732364562Sgshapiro
732464562Sgshapiro		  case '+':
732564562Sgshapiro			r = v[0] + v[1];
732664562Sgshapiro			break;
732764562Sgshapiro
732864562Sgshapiro		  case '-':
732964562Sgshapiro			r = v[0] - v[1];
733064562Sgshapiro			break;
733164562Sgshapiro
733264562Sgshapiro		  case '*':
733364562Sgshapiro			r = v[0] * v[1];
733464562Sgshapiro			break;
733564562Sgshapiro
733664562Sgshapiro		  case '/':
733764562Sgshapiro			if (v[1] == 0)
733864562Sgshapiro				return NULL;
733964562Sgshapiro			r = v[0] / v[1];
734064562Sgshapiro			break;
734164562Sgshapiro
734264562Sgshapiro		  case 'l':
734364562Sgshapiro			res = v[0] < v[1];
734464562Sgshapiro			boolres = TRUE;
734564562Sgshapiro			break;
734664562Sgshapiro
734764562Sgshapiro		  case '=':
734864562Sgshapiro			res = v[0] == v[1];
734964562Sgshapiro			boolres = TRUE;
735064562Sgshapiro			break;
735164562Sgshapiro
735264562Sgshapiro		  default:
735364562Sgshapiro			/* XXX */
735464562Sgshapiro			*statp = EX_CONFIG;
735564562Sgshapiro			if (LogLevel > 10)
735664562Sgshapiro				sm_syslog(LOG_WARNING, NOQID,
735764562Sgshapiro					  "arith_map: unknown operator %c",
735864562Sgshapiro					  isprint(*name) ? *name : '?');
735964562Sgshapiro			return NULL;
736064562Sgshapiro		}
736164562Sgshapiro		if (boolres)
736264562Sgshapiro			snprintf(result, sizeof result, res ? "TRUE" : "FALSE");
736364562Sgshapiro		else
736464562Sgshapiro			snprintf(result, sizeof result, "%ld", r);
736564562Sgshapiro		return result;
736664562Sgshapiro	}
736764562Sgshapiro	*statp = EX_CONFIG;
736864562Sgshapiro	return NULL;
736964562Sgshapiro}
7370