map.c revision 64562
138032Speter/*
264562Sgshapiro * Copyright (c) 1998-2000 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
1564562Sgshapirostatic char id[] = "@(#)$Id: map.c,v 8.414.4.13 2000/07/14 16:48:21 ca 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 */
5564562Sgshapirostatic bool	extract_canonname __P((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)
37338032Speter			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	{
49538032Speter		map->map_class->map_close(map);
49638032Speter		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
49738032Speter	}
49838032Speter
49964562Sgshapiro	(void) rebuildaliases(map, FALSE);
50064562Sgshapiro	return;
50164562Sgshapiro}
50264562Sgshapiro/*
50364562Sgshapiro**  OPENMAP -- open a map
50464562Sgshapiro**
50564562Sgshapiro**	Parameters:
50664562Sgshapiro**		map -- map to open (it must not be open).
50764562Sgshapiro**
50864562Sgshapiro**	Returns:
50964562Sgshapiro**		whether open succeeded.
51064562Sgshapiro**
51164562Sgshapiro*/
51264562Sgshapiro
51364562Sgshapirobool
51464562Sgshapiroopenmap(map)
51564562Sgshapiro	MAP *map;
51664562Sgshapiro{
51764562Sgshapiro	bool restore = FALSE;
51864562Sgshapiro	bool savehold = HoldErrs;
51964562Sgshapiro	bool savequick = QuickAbort;
52064562Sgshapiro	int saveerrors = Errors;
52164562Sgshapiro
52264562Sgshapiro	if (!bitset(MF_VALID, map->map_mflags))
52364562Sgshapiro		return FALSE;
52464562Sgshapiro
52564562Sgshapiro	/* better safe than sorry... */
52664562Sgshapiro	if (bitset(MF_OPEN, map->map_mflags))
52764562Sgshapiro		return TRUE;
52864562Sgshapiro
52964562Sgshapiro	/* Don't send a map open error out via SMTP */
53064562Sgshapiro	if ((OnlyOneError || QuickAbort) &&
53164562Sgshapiro	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))
53238032Speter	{
53364562Sgshapiro		restore = TRUE;
53464562Sgshapiro		HoldErrs = TRUE;
53564562Sgshapiro		QuickAbort = FALSE;
53638032Speter	}
53738032Speter
53864562Sgshapiro	errno = 0;
53938032Speter	if (map->map_class->map_open(map, O_RDONLY))
54038032Speter	{
54138032Speter		if (tTd(38, 4))
54264562Sgshapiro			dprintf("openmap()\t%s:%s %s: valid\n",
54338032Speter				map->map_class->map_cname == NULL ? "NULL" :
54438032Speter					map->map_class->map_cname,
54538032Speter				map->map_mname == NULL ? "NULL" :
54638032Speter					map->map_mname,
54738032Speter				map->map_file == NULL ? "NULL" :
54838032Speter					map->map_file);
54938032Speter		map->map_mflags |= MF_OPEN;
55042575Speter		map->map_pid = getpid();
55138032Speter	}
55238032Speter	else
55338032Speter	{
55438032Speter		if (tTd(38, 4))
55564562Sgshapiro			dprintf("openmap()\t%s:%s %s: invalid%s%s\n",
55638032Speter				map->map_class->map_cname == NULL ? "NULL" :
55738032Speter					map->map_class->map_cname,
55838032Speter				map->map_mname == NULL ? "NULL" :
55938032Speter					map->map_mname,
56038032Speter				map->map_file == NULL ? "NULL" :
56138032Speter					map->map_file,
56264562Sgshapiro				errno == 0 ? "" : ": ",
56364562Sgshapiro				errno == 0 ? "" : errstring(errno));
56438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
56538032Speter		{
56638032Speter			extern MAPCLASS BogusMapClass;
56738032Speter
56838032Speter			map->map_class = &BogusMapClass;
56938032Speter			map->map_mflags |= MF_OPEN;
57042575Speter			map->map_pid = getpid();
57138032Speter		}
57264562Sgshapiro		else
57364562Sgshapiro		{
57464562Sgshapiro			/* don't try again */
57564562Sgshapiro			map->map_mflags &= ~MF_VALID;
57664562Sgshapiro		}
57738032Speter	}
57864562Sgshapiro
57964562Sgshapiro	if (restore)
58064562Sgshapiro	{
58164562Sgshapiro		Errors = saveerrors;
58264562Sgshapiro		HoldErrs = savehold;
58364562Sgshapiro		QuickAbort = savequick;
58464562Sgshapiro	}
58564562Sgshapiro
58664562Sgshapiro	return bitset(MF_OPEN, map->map_mflags);
58738032Speter}
58838032Speter/*
58942575Speter**  CLOSEMAPS -- close all open maps opened by the current pid.
59042575Speter**
59142575Speter**	Parameters:
59242575Speter**		none
59342575Speter**
59442575Speter**	Returns:
59542575Speter**		none.
59642575Speter*/
59742575Speter
59842575Spetervoid
59942575Speterclosemaps()
60042575Speter{
60142575Speter	stabapply(map_close, 0);
60242575Speter}
60364562Sgshapiro/*
60464562Sgshapiro**  MAP_CLOSE -- close a map opened by the current pid.
60564562Sgshapiro**
60664562Sgshapiro**	Parameters:
60764562Sgshapiro**		s -- STAB entry: if map: try to open
60864562Sgshapiro**		second parameter is unused (required by stabapply())
60964562Sgshapiro**
61064562Sgshapiro**	Returns:
61164562Sgshapiro**		none.
61264562Sgshapiro*/
61342575Speter
61442575Speter/* ARGSUSED1 */
61564562Sgshapirostatic void
61642575Spetermap_close(s, unused)
61742575Speter	register STAB *s;
61842575Speter	int unused;
61942575Speter{
62042575Speter	MAP *map;
62142575Speter
62242575Speter	if (s->s_type != ST_MAP)
62342575Speter		return;
62464562Sgshapiro
62542575Speter	map = &s->s_map;
62642575Speter
62742575Speter	if (!bitset(MF_VALID, map->map_mflags) ||
62842575Speter	    !bitset(MF_OPEN, map->map_mflags) ||
62964562Sgshapiro	    bitset(MF_SHARED, map->map_mflags) ||
63042575Speter	    map->map_pid != getpid())
63142575Speter		return;
63264562Sgshapiro
63342575Speter	if (tTd(38, 5))
63464562Sgshapiro		dprintf("closemaps: closing %s (%s)\n",
63564562Sgshapiro			map->map_mname == NULL ? "NULL" : map->map_mname,
63664562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
63764562Sgshapiro
63842575Speter	map->map_class->map_close(map);
63942575Speter	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
64042575Speter}
64142575Speter/*
64238032Speter**  GETCANONNAME -- look up name using service switch
64338032Speter**
64438032Speter**	Parameters:
64538032Speter**		host -- the host name to look up.
64638032Speter**		hbsize -- the size of the host buffer.
64738032Speter**		trymx -- if set, try MX records.
64838032Speter**
64938032Speter**	Returns:
65038032Speter**		TRUE -- if the host was found.
65138032Speter**		FALSE -- otherwise.
65238032Speter*/
65338032Speter
65438032Speterbool
65538032Spetergetcanonname(host, hbsize, trymx)
65638032Speter	char *host;
65738032Speter	int hbsize;
65838032Speter	bool trymx;
65938032Speter{
66038032Speter	int nmaps;
66138032Speter	int mapno;
66238032Speter	bool found = FALSE;
66338032Speter	bool got_tempfail = FALSE;
66464562Sgshapiro	auto int status;
66538032Speter	char *maptype[MAXMAPSTACK];
66638032Speter	short mapreturn[MAXMAPACTIONS];
66738032Speter
66838032Speter	nmaps = switch_map_find("hosts", maptype, mapreturn);
66938032Speter	for (mapno = 0; mapno < nmaps; mapno++)
67038032Speter	{
67138032Speter		int i;
67238032Speter
67338032Speter		if (tTd(38, 20))
67464562Sgshapiro			dprintf("getcanonname(%s), trying %s\n",
67538032Speter				host, maptype[mapno]);
67638032Speter		if (strcmp("files", maptype[mapno]) == 0)
67738032Speter		{
67864562Sgshapiro			found = text_getcanonname(host, hbsize, &status);
67938032Speter		}
68038032Speter#ifdef NIS
68138032Speter		else if (strcmp("nis", maptype[mapno]) == 0)
68238032Speter		{
68364562Sgshapiro			found = nis_getcanonname(host, hbsize, &status);
68438032Speter		}
68564562Sgshapiro#endif /* NIS */
68638032Speter#ifdef NISPLUS
68738032Speter		else if (strcmp("nisplus", maptype[mapno]) == 0)
68838032Speter		{
68964562Sgshapiro			found = nisplus_getcanonname(host, hbsize, &status);
69038032Speter		}
69164562Sgshapiro#endif /* NISPLUS */
69238032Speter#if NAMED_BIND
69338032Speter		else if (strcmp("dns", maptype[mapno]) == 0)
69438032Speter		{
69564562Sgshapiro			found = dns_getcanonname(host, hbsize, trymx, &status);
69638032Speter		}
69764562Sgshapiro#endif /* NAMED_BIND */
69838032Speter#if NETINFO
69938032Speter		else if (strcmp("netinfo", maptype[mapno]) == 0)
70038032Speter		{
70164562Sgshapiro			found = ni_getcanonname(host, hbsize, &status);
70238032Speter		}
70364562Sgshapiro#endif /* NETINFO */
70438032Speter		else
70538032Speter		{
70638032Speter			found = FALSE;
70764562Sgshapiro			status = EX_UNAVAILABLE;
70838032Speter		}
70938032Speter
71038032Speter		/*
71138032Speter		**  Heuristic: if $m is not set, we are running during system
71238032Speter		**  startup.  In this case, when a name is apparently found
71338032Speter		**  but has no dot, treat is as not found.  This avoids
71438032Speter		**  problems if /etc/hosts has no FQDN but is listed first
71538032Speter		**  in the service switch.
71638032Speter		*/
71738032Speter
71838032Speter		if (found &&
71938032Speter		    (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
72038032Speter			break;
72138032Speter
72238032Speter		/* see if we should continue */
72364562Sgshapiro		if (status == EX_TEMPFAIL)
72438032Speter		{
72538032Speter			i = MA_TRYAGAIN;
72638032Speter			got_tempfail = TRUE;
72738032Speter		}
72864562Sgshapiro		else if (status == EX_NOTFOUND)
72938032Speter			i = MA_NOTFOUND;
73038032Speter		else
73138032Speter			i = MA_UNAVAIL;
73238032Speter		if (bitset(1 << mapno, mapreturn[i]))
73338032Speter			break;
73438032Speter	}
73538032Speter
73638032Speter	if (found)
73738032Speter	{
73838032Speter		char *d;
73938032Speter
74038032Speter		if (tTd(38, 20))
74164562Sgshapiro			dprintf("getcanonname(%s), found\n", host);
74238032Speter
74338032Speter		/*
74438032Speter		**  If returned name is still single token, compensate
74538032Speter		**  by tagging on $m.  This is because some sites set
74638032Speter		**  up their DNS or NIS databases wrong.
74738032Speter		*/
74838032Speter
74938032Speter		if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
75038032Speter		{
75138032Speter			d = macvalue('m', CurEnv);
75238032Speter			if (d != NULL &&
75338032Speter			    hbsize > (int) (strlen(host) + strlen(d) + 1))
75438032Speter			{
75538032Speter				if (host[strlen(host) - 1] != '.')
75664562Sgshapiro					(void) strlcat(host, ".", hbsize);
75764562Sgshapiro				(void) strlcat(host, d, hbsize);
75838032Speter			}
75938032Speter			else
76038032Speter				return FALSE;
76138032Speter		}
76238032Speter		return TRUE;
76338032Speter	}
76438032Speter
76538032Speter	if (tTd(38, 20))
76664562Sgshapiro		dprintf("getcanonname(%s), failed, status=%d\n", host, status);
76738032Speter
76838032Speter#if NAMED_BIND
76938032Speter	if (got_tempfail)
77038032Speter		h_errno = TRY_AGAIN;
77138032Speter	else
77238032Speter		h_errno = HOST_NOT_FOUND;
77364562Sgshapiro#endif /* NAMED_BIND */
77438032Speter
77538032Speter	return FALSE;
77638032Speter}
77738032Speter/*
77838032Speter**  EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
77938032Speter**
78038032Speter**	Parameters:
78138032Speter**		name -- the name against which to match.
78238032Speter**		line -- the /etc/hosts line.
78338032Speter**		cbuf -- the location to store the result.
78438032Speter**		cbuflen -- the size of cbuf.
78538032Speter**
78638032Speter**	Returns:
78738032Speter**		TRUE -- if the line matched the desired name.
78838032Speter**		FALSE -- otherwise.
78938032Speter*/
79038032Speter
79164562Sgshapirostatic bool
79238032Speterextract_canonname(name, line, cbuf, cbuflen)
79338032Speter	char *name;
79438032Speter	char *line;
79538032Speter	char cbuf[];
79638032Speter	int cbuflen;
79738032Speter{
79838032Speter	int i;
79938032Speter	char *p;
80038032Speter	bool found = FALSE;
80138032Speter
80238032Speter	cbuf[0] = '\0';
80338032Speter	if (line[0] == '#')
80438032Speter		return FALSE;
80538032Speter
80638032Speter	for (i = 1; ; i++)
80738032Speter	{
80838032Speter		char nbuf[MAXNAME + 1];
80938032Speter
81038032Speter		p = get_column(line, i, '\0', nbuf, sizeof nbuf);
81138032Speter		if (p == NULL)
81238032Speter			break;
81338032Speter		if (*p == '\0')
81438032Speter			continue;
81538032Speter		if (cbuf[0] == '\0' ||
81638032Speter		    (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
81738032Speter		{
81838032Speter			snprintf(cbuf, cbuflen, "%s", p);
81938032Speter		}
82038032Speter		if (strcasecmp(name, p) == 0)
82138032Speter			found = TRUE;
82238032Speter	}
82338032Speter	if (found && strchr(cbuf, '.') == NULL)
82438032Speter	{
82538032Speter		/* try to add a domain on the end of the name */
82638032Speter		char *domain = macvalue('m', CurEnv);
82738032Speter
82838032Speter		if (domain != NULL &&
82964562Sgshapiro		    strlen(domain) + (i = strlen(cbuf)) + 1 < (size_t) cbuflen)
83038032Speter		{
83164562Sgshapiro			p = &cbuf[i];
83238032Speter			*p++ = '.';
83364562Sgshapiro			(void) strlcpy(p, domain, cbuflen - i - 1);
83438032Speter		}
83538032Speter	}
83638032Speter	return found;
83738032Speter}
83838032Speter/*
83938032Speter**  NDBM modules
84038032Speter*/
84138032Speter
84238032Speter#ifdef NDBM
84338032Speter
84438032Speter/*
84538032Speter**  NDBM_MAP_OPEN -- DBM-style map open
84638032Speter*/
84738032Speter
84838032Speterbool
84938032Speterndbm_map_open(map, mode)
85038032Speter	MAP *map;
85138032Speter	int mode;
85238032Speter{
85338032Speter	register DBM *dbm;
85464562Sgshapiro	int save_errno;
85538032Speter	int dfd;
85638032Speter	int pfd;
85764562Sgshapiro	long sff;
85838032Speter	int ret;
85938032Speter	int smode = S_IREAD;
86038032Speter	char dirfile[MAXNAME + 1];
86138032Speter	char pagfile[MAXNAME + 1];
86264562Sgshapiro	struct stat st;
86338032Speter	struct stat std, stp;
86438032Speter
86538032Speter	if (tTd(38, 2))
86664562Sgshapiro		dprintf("ndbm_map_open(%s, %s, %d)\n",
86738032Speter			map->map_mname, map->map_file, mode);
86838032Speter	map->map_lockfd = -1;
86938032Speter	mode &= O_ACCMODE;
87038032Speter
87138032Speter	/* do initial file and directory checks */
87238032Speter	snprintf(dirfile, sizeof dirfile, "%s.dir", map->map_file);
87338032Speter	snprintf(pagfile, sizeof pagfile, "%s.pag", map->map_file);
87438032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
87538032Speter	if (mode == O_RDWR)
87638032Speter	{
87738032Speter		sff |= SFF_CREAT;
87864562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
87938032Speter			sff |= SFF_NOSLINK;
88064562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
88138032Speter			sff |= SFF_NOHLINK;
88238032Speter		smode = S_IWRITE;
88338032Speter	}
88438032Speter	else
88538032Speter	{
88664562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
88738032Speter			sff |= SFF_NOWLINK;
88838032Speter	}
88964562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
89038032Speter		sff |= SFF_SAFEDIRPATH;
89138032Speter	ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
89238032Speter			    sff, smode, &std);
89338032Speter	if (ret == 0)
89438032Speter		ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
89538032Speter			       sff, smode, &stp);
89664562Sgshapiro
89764562Sgshapiro# if !_FFR_REMOVE_AUTOREBUILD
89838032Speter	if (ret == ENOENT && AutoRebuild &&
89938032Speter	    bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
90038032Speter	    (bitset(MF_IMPL_NDBM, map->map_mflags) ||
90138032Speter	     bitset(MF_ALIAS, map->map_mflags)) &&
90238032Speter	    mode == O_RDONLY)
90338032Speter	{
90438032Speter		bool impl = bitset(MF_IMPL_NDBM, map->map_mflags);
90538032Speter
90638032Speter		/* may be able to rebuild */
90738032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
90838032Speter		if (!rebuildaliases(map, TRUE))
90938032Speter			return FALSE;
91038032Speter		if (impl)
91138032Speter			return impl_map_open(map, O_RDONLY);
91238032Speter		else
91338032Speter			return ndbm_map_open(map, O_RDONLY);
91438032Speter	}
91564562Sgshapiro# endif /* !_FFR_REMOVE_AUTOREBUILD */
91664562Sgshapiro
91738032Speter	if (ret != 0)
91838032Speter	{
91938032Speter		char *prob = "unsafe";
92038032Speter
92138032Speter		/* cannot open this map */
92238032Speter		if (ret == ENOENT)
92338032Speter			prob = "missing";
92438032Speter		if (tTd(38, 2))
92564562Sgshapiro			dprintf("\t%s map file: %d\n", prob, ret);
92638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
92738032Speter			syserr("dbm map \"%s\": %s map file %s",
92838032Speter				map->map_mname, prob, map->map_file);
92938032Speter		return FALSE;
93038032Speter	}
93138032Speter	if (std.st_mode == ST_MODE_NOFILE)
93238032Speter		mode |= O_CREAT|O_EXCL;
93338032Speter
93464562Sgshapiro# if LOCK_ON_OPEN
93538032Speter	if (mode == O_RDONLY)
93638032Speter		mode |= O_SHLOCK;
93738032Speter	else
93838032Speter		mode |= O_TRUNC|O_EXLOCK;
93964562Sgshapiro# else /* LOCK_ON_OPEN */
94038032Speter	if ((mode & O_ACCMODE) == O_RDWR)
94138032Speter	{
94264562Sgshapiro#  if NOFTRUNCATE
94338032Speter		/*
94438032Speter		**  Warning: race condition.  Try to lock the file as
94538032Speter		**  quickly as possible after opening it.
94638032Speter		**	This may also have security problems on some systems,
94738032Speter		**	but there isn't anything we can do about it.
94838032Speter		*/
94938032Speter
95038032Speter		mode |= O_TRUNC;
95164562Sgshapiro#  else /* NOFTRUNCATE */
95238032Speter		/*
95338032Speter		**  This ugly code opens the map without truncating it,
95438032Speter		**  locks the file, then truncates it.  Necessary to
95538032Speter		**  avoid race conditions.
95638032Speter		*/
95738032Speter
95838032Speter		int dirfd;
95938032Speter		int pagfd;
96064562Sgshapiro		long sff = SFF_CREAT|SFF_OPENASROOT;
96138032Speter
96264562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
96338032Speter			sff |= SFF_NOSLINK;
96464562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
96538032Speter			sff |= SFF_NOHLINK;
96638032Speter
96738032Speter		dirfd = safeopen(dirfile, mode, DBMMODE, sff);
96838032Speter		pagfd = safeopen(pagfile, mode, DBMMODE, sff);
96938032Speter
97038032Speter		if (dirfd < 0 || pagfd < 0)
97138032Speter		{
97264562Sgshapiro			save_errno = errno;
97338032Speter			if (dirfd >= 0)
97438032Speter				(void) close(dirfd);
97538032Speter			if (pagfd >= 0)
97638032Speter				(void) close(pagfd);
97738032Speter			errno = save_errno;
97838032Speter			syserr("ndbm_map_open: cannot create database %s",
97938032Speter				map->map_file);
98038032Speter			return FALSE;
98138032Speter		}
98238032Speter		if (ftruncate(dirfd, (off_t) 0) < 0 ||
98338032Speter		    ftruncate(pagfd, (off_t) 0) < 0)
98438032Speter		{
98564562Sgshapiro			save_errno = errno;
98638032Speter			(void) close(dirfd);
98738032Speter			(void) close(pagfd);
98838032Speter			errno = save_errno;
98938032Speter			syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
99038032Speter				map->map_file);
99138032Speter			return FALSE;
99238032Speter		}
99338032Speter
99438032Speter		/* if new file, get "before" bits for later filechanged check */
99538032Speter		if (std.st_mode == ST_MODE_NOFILE &&
99638032Speter		    (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
99738032Speter		{
99864562Sgshapiro			save_errno = errno;
99938032Speter			(void) close(dirfd);
100038032Speter			(void) close(pagfd);
100138032Speter			errno = save_errno;
100238032Speter			syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
100338032Speter				map->map_file);
100438032Speter			return FALSE;
100538032Speter		}
100638032Speter
100738032Speter		/* have to save the lock for the duration (bletch) */
100838032Speter		map->map_lockfd = dirfd;
100964562Sgshapiro		(void) close(pagfd);
101038032Speter
101138032Speter		/* twiddle bits for dbm_open */
101238032Speter		mode &= ~(O_CREAT|O_EXCL);
101364562Sgshapiro#  endif /* NOFTRUNCATE */
101438032Speter	}
101564562Sgshapiro# endif /* LOCK_ON_OPEN */
101638032Speter
101738032Speter	/* open the database */
101838032Speter	dbm = dbm_open(map->map_file, mode, DBMMODE);
101938032Speter	if (dbm == NULL)
102038032Speter	{
102164562Sgshapiro		save_errno = errno;
102238032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
102338032Speter		    aliaswait(map, ".pag", FALSE))
102438032Speter			return TRUE;
102564562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
102638032Speter		if (map->map_lockfd >= 0)
102764562Sgshapiro			(void) close(map->map_lockfd);
102864562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
102938032Speter		errno = save_errno;
103038032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
103138032Speter			syserr("Cannot open DBM database %s", map->map_file);
103238032Speter		return FALSE;
103338032Speter	}
103438032Speter	dfd = dbm_dirfno(dbm);
103538032Speter	pfd = dbm_pagfno(dbm);
103638032Speter	if (dfd == pfd)
103738032Speter	{
103838032Speter		/* heuristic: if files are linked, this is actually gdbm */
103938032Speter		dbm_close(dbm);
104064562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
104138032Speter		if (map->map_lockfd >= 0)
104264562Sgshapiro			(void) close(map->map_lockfd);
104364562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
104438032Speter		errno = 0;
104538032Speter		syserr("dbm map \"%s\": cannot support GDBM",
104638032Speter			map->map_mname);
104738032Speter		return FALSE;
104838032Speter	}
104938032Speter
105038032Speter	if (filechanged(dirfile, dfd, &std) ||
105138032Speter	    filechanged(pagfile, pfd, &stp))
105238032Speter	{
105364562Sgshapiro		save_errno = errno;
105438032Speter		dbm_close(dbm);
105564562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
105638032Speter		if (map->map_lockfd >= 0)
105764562Sgshapiro			(void) close(map->map_lockfd);
105864562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
105938032Speter		errno = save_errno;
106038032Speter		syserr("ndbm_map_open(%s): file changed after open",
106138032Speter			map->map_file);
106238032Speter		return FALSE;
106338032Speter	}
106438032Speter
106538032Speter	map->map_db1 = (ARBPTR_T) dbm;
106664562Sgshapiro
106764562Sgshapiro	/*
106864562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
106964562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
107064562Sgshapiro	**  map_mtime to be set
107164562Sgshapiro	*/
107264562Sgshapiro
107364562Sgshapiro	if (fstat(dfd, &st) >= 0)
107464562Sgshapiro		map->map_mtime = st.st_mtime;
107564562Sgshapiro
107638032Speter	if (mode == O_RDONLY)
107738032Speter	{
107864562Sgshapiro# if LOCK_ON_OPEN
107938032Speter		if (dfd >= 0)
108038032Speter			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
108138032Speter		if (pfd >= 0)
108238032Speter			(void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
108364562Sgshapiro# endif /* LOCK_ON_OPEN */
108438032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
108538032Speter		    !aliaswait(map, ".pag", TRUE))
108638032Speter			return FALSE;
108738032Speter	}
108838032Speter	else
108938032Speter	{
109038032Speter		map->map_mflags |= MF_LOCKED;
109142575Speter		if (geteuid() == 0 && TrustedUid != 0)
109238032Speter		{
109364562Sgshapiro#  if HASFCHOWN
109442575Speter			if (fchown(dfd, TrustedUid, -1) < 0 ||
109542575Speter			    fchown(pfd, TrustedUid, -1) < 0)
109638032Speter			{
109738032Speter				int err = errno;
109838032Speter
109938032Speter				sm_syslog(LOG_ALERT, NOQID,
110038032Speter					  "ownership change on %s failed: %s",
110138032Speter					  map->map_file, errstring(err));
110238032Speter				message("050 ownership change on %s failed: %s",
110338032Speter					map->map_file, errstring(err));
110438032Speter			}
110564562Sgshapiro#  endif /* HASFCHOWN */
110638032Speter		}
110738032Speter	}
110838032Speter	return TRUE;
110938032Speter}
111038032Speter
111138032Speter
111238032Speter/*
111338032Speter**  NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
111438032Speter*/
111538032Speter
111638032Speterchar *
111738032Speterndbm_map_lookup(map, name, av, statp)
111838032Speter	MAP *map;
111938032Speter	char *name;
112038032Speter	char **av;
112138032Speter	int *statp;
112238032Speter{
112338032Speter	datum key, val;
112438032Speter	int fd;
112538032Speter	char keybuf[MAXNAME + 1];
112638032Speter	struct stat stbuf;
112738032Speter
112838032Speter	if (tTd(38, 20))
112964562Sgshapiro		dprintf("ndbm_map_lookup(%s, %s)\n",
113038032Speter			map->map_mname, name);
113138032Speter
113238032Speter	key.dptr = name;
113338032Speter	key.dsize = strlen(name);
113438032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
113538032Speter	{
113638032Speter		if (key.dsize > sizeof keybuf - 1)
113738032Speter			key.dsize = sizeof keybuf - 1;
113864562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
113938032Speter		keybuf[key.dsize] = '\0';
114038032Speter		makelower(keybuf);
114138032Speter		key.dptr = keybuf;
114238032Speter	}
114338032Speterlockdbm:
114438032Speter	fd = dbm_dirfno((DBM *) map->map_db1);
114538032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
114638032Speter		(void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
114738032Speter	if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
114838032Speter	{
114938032Speter		/* Reopen the database to sync the cache */
115038032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
115138032Speter								 : O_RDONLY;
115238032Speter
115364562Sgshapiro		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
115464562Sgshapiro			(void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
115538032Speter		map->map_class->map_close(map);
115638032Speter		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
115738032Speter		if (map->map_class->map_open(map, omode))
115838032Speter		{
115938032Speter			map->map_mflags |= MF_OPEN;
116042575Speter			map->map_pid = getpid();
116138032Speter			if ((omode && O_ACCMODE) == O_RDWR)
116238032Speter				map->map_mflags |= MF_WRITABLE;
116338032Speter			goto lockdbm;
116438032Speter		}
116538032Speter		else
116638032Speter		{
116738032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
116838032Speter			{
116938032Speter				extern MAPCLASS BogusMapClass;
117038032Speter
117138032Speter				*statp = EX_TEMPFAIL;
117238032Speter				map->map_class = &BogusMapClass;
117338032Speter				map->map_mflags |= MF_OPEN;
117442575Speter				map->map_pid = getpid();
117538032Speter				syserr("Cannot reopen NDBM database %s",
117638032Speter					map->map_file);
117738032Speter			}
117838032Speter			return NULL;
117938032Speter		}
118038032Speter	}
118138032Speter	val.dptr = NULL;
118238032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
118338032Speter	{
118438032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
118538032Speter		if (val.dptr != NULL)
118638032Speter			map->map_mflags &= ~MF_TRY1NULL;
118738032Speter	}
118838032Speter	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
118938032Speter	{
119038032Speter		key.dsize++;
119138032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
119238032Speter		if (val.dptr != NULL)
119338032Speter			map->map_mflags &= ~MF_TRY0NULL;
119438032Speter	}
119538032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
119638032Speter		(void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
119738032Speter	if (val.dptr == NULL)
119838032Speter		return NULL;
119938032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
120038032Speter		return map_rewrite(map, name, strlen(name), NULL);
120138032Speter	else
120238032Speter		return map_rewrite(map, val.dptr, val.dsize, av);
120338032Speter}
120438032Speter
120538032Speter
120638032Speter/*
120738032Speter**  NDBM_MAP_STORE -- store a datum in the database
120838032Speter*/
120938032Speter
121038032Spetervoid
121138032Speterndbm_map_store(map, lhs, rhs)
121238032Speter	register MAP *map;
121338032Speter	char *lhs;
121438032Speter	char *rhs;
121538032Speter{
121638032Speter	datum key;
121738032Speter	datum data;
121864562Sgshapiro	int status;
121938032Speter	char keybuf[MAXNAME + 1];
122038032Speter
122138032Speter	if (tTd(38, 12))
122264562Sgshapiro		dprintf("ndbm_map_store(%s, %s, %s)\n",
122338032Speter			map->map_mname, lhs, rhs);
122438032Speter
122538032Speter	key.dsize = strlen(lhs);
122638032Speter	key.dptr = lhs;
122738032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
122838032Speter	{
122938032Speter		if (key.dsize > sizeof keybuf - 1)
123038032Speter			key.dsize = sizeof keybuf - 1;
123164562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
123238032Speter		keybuf[key.dsize] = '\0';
123338032Speter		makelower(keybuf);
123438032Speter		key.dptr = keybuf;
123538032Speter	}
123638032Speter
123738032Speter	data.dsize = strlen(rhs);
123838032Speter	data.dptr = rhs;
123938032Speter
124038032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
124138032Speter	{
124238032Speter		key.dsize++;
124338032Speter		data.dsize++;
124438032Speter	}
124538032Speter
124664562Sgshapiro	status = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
124764562Sgshapiro	if (status > 0)
124838032Speter	{
124938032Speter		if (!bitset(MF_APPEND, map->map_mflags))
125038032Speter			message("050 Warning: duplicate alias name %s", lhs);
125138032Speter		else
125238032Speter		{
125338032Speter			static char *buf = NULL;
125438032Speter			static int bufsiz = 0;
125538032Speter			auto int xstat;
125638032Speter			datum old;
125738032Speter
125838032Speter			old.dptr = ndbm_map_lookup(map, key.dptr,
125938032Speter						   (char **)NULL, &xstat);
126038032Speter			if (old.dptr != NULL && *(char *) old.dptr != '\0')
126138032Speter			{
126238032Speter				old.dsize = strlen(old.dptr);
126338032Speter				if (data.dsize + old.dsize + 2 > bufsiz)
126438032Speter				{
126538032Speter					if (buf != NULL)
126638032Speter						(void) free(buf);
126738032Speter					bufsiz = data.dsize + old.dsize + 2;
126838032Speter					buf = xalloc(bufsiz);
126938032Speter				}
127038032Speter				snprintf(buf, bufsiz, "%s,%s",
127138032Speter					data.dptr, old.dptr);
127238032Speter				data.dsize = data.dsize + old.dsize + 1;
127338032Speter				data.dptr = buf;
127438032Speter				if (tTd(38, 9))
127564562Sgshapiro					dprintf("ndbm_map_store append=%s\n",
127664562Sgshapiro						data.dptr);
127738032Speter			}
127838032Speter		}
127964562Sgshapiro		status = dbm_store((DBM *) map->map_db1,
128064562Sgshapiro				   key, data, DBM_REPLACE);
128138032Speter	}
128264562Sgshapiro	if (status != 0)
128364562Sgshapiro		syserr("readaliases: dbm put (%s): %d", lhs, status);
128438032Speter}
128538032Speter
128638032Speter
128738032Speter/*
128838032Speter**  NDBM_MAP_CLOSE -- close the database
128938032Speter*/
129038032Speter
129138032Spetervoid
129238032Speterndbm_map_close(map)
129338032Speter	register MAP  *map;
129438032Speter{
129538032Speter	if (tTd(38, 9))
129664562Sgshapiro		dprintf("ndbm_map_close(%s, %s, %lx)\n",
129738032Speter			map->map_mname, map->map_file, map->map_mflags);
129838032Speter
129938032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
130038032Speter	{
130164562Sgshapiro# ifdef NDBM_YP_COMPAT
130238032Speter		bool inclnull;
130342575Speter		char buf[MAXHOSTNAMELEN];
130438032Speter
130538032Speter		inclnull = bitset(MF_INCLNULL, map->map_mflags);
130638032Speter		map->map_mflags &= ~MF_INCLNULL;
130738032Speter
130838032Speter		if (strstr(map->map_file, "/yp/") != NULL)
130938032Speter		{
131038032Speter			long save_mflags = map->map_mflags;
131138032Speter
131238032Speter			map->map_mflags |= MF_NOFOLDCASE;
131338032Speter
131438032Speter			(void) snprintf(buf, sizeof buf, "%010ld", curtime());
131538032Speter			ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
131638032Speter
131738032Speter			(void) gethostname(buf, sizeof buf);
131838032Speter			ndbm_map_store(map, "YP_MASTER_NAME", buf);
131938032Speter
132038032Speter			map->map_mflags = save_mflags;
132138032Speter		}
132238032Speter
132338032Speter		if (inclnull)
132438032Speter			map->map_mflags |= MF_INCLNULL;
132564562Sgshapiro# endif /* NDBM_YP_COMPAT */
132638032Speter
132738032Speter		/* write out the distinguished alias */
132838032Speter		ndbm_map_store(map, "@", "@");
132938032Speter	}
133038032Speter	dbm_close((DBM *) map->map_db1);
133138032Speter
133238032Speter	/* release lock (if needed) */
133364562Sgshapiro# if !LOCK_ON_OPEN
133438032Speter	if (map->map_lockfd >= 0)
133538032Speter		(void) close(map->map_lockfd);
133664562Sgshapiro# endif /* !LOCK_ON_OPEN */
133738032Speter}
133838032Speter
133964562Sgshapiro#endif /* NDBM */
134038032Speter/*
134138032Speter**  NEWDB (Hash and BTree) Modules
134238032Speter*/
134338032Speter
134438032Speter#ifdef NEWDB
134538032Speter
134638032Speter/*
134738032Speter**  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
134838032Speter**
134938032Speter**	These do rather bizarre locking.  If you can lock on open,
135038032Speter**	do that to avoid the condition of opening a database that
135138032Speter**	is being rebuilt.  If you don't, we'll try to fake it, but
135238032Speter**	there will be a race condition.  If opening for read-only,
135338032Speter**	we immediately release the lock to avoid freezing things up.
135438032Speter**	We really ought to hold the lock, but guarantee that we won't
135538032Speter**	be pokey about it.  That's hard to do.
135638032Speter*/
135738032Speter
135838032Speter/* these should be K line arguments */
135964562Sgshapiro# if DB_VERSION_MAJOR < 2
136064562Sgshapiro#  define db_cachesize	cachesize
136164562Sgshapiro#  define h_nelem	nelem
136264562Sgshapiro#  ifndef DB_CACHE_SIZE
136364562Sgshapiro#   define DB_CACHE_SIZE	(1024 * 1024)	/* database memory cache size */
136464562Sgshapiro#  endif /* ! DB_CACHE_SIZE */
136564562Sgshapiro#  ifndef DB_HASH_NELEM
136664562Sgshapiro#   define DB_HASH_NELEM	4096		/* (starting) size of hash table */
136764562Sgshapiro#  endif /* ! DB_HASH_NELEM */
136864562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
136938032Speter
137038032Speterbool
137138032Speterbt_map_open(map, mode)
137238032Speter	MAP *map;
137338032Speter	int mode;
137438032Speter{
137564562Sgshapiro# if DB_VERSION_MAJOR < 2
137638032Speter	BTREEINFO btinfo;
137764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
137864562Sgshapiro# if DB_VERSION_MAJOR == 2
137938032Speter	DB_INFO btinfo;
138064562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
138164562Sgshapiro# if DB_VERSION_MAJOR > 2
138264562Sgshapiro	void *btinfo = NULL;
138364562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
138438032Speter
138538032Speter	if (tTd(38, 2))
138664562Sgshapiro		dprintf("bt_map_open(%s, %s, %d)\n",
138738032Speter			map->map_mname, map->map_file, mode);
138838032Speter
138964562Sgshapiro# if DB_VERSION_MAJOR < 3
139064562Sgshapiro	memset(&btinfo, '\0', sizeof btinfo);
139164562Sgshapiro#  ifdef DB_CACHE_SIZE
139238032Speter	btinfo.db_cachesize = DB_CACHE_SIZE;
139364562Sgshapiro#  endif /* DB_CACHE_SIZE */
139464562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
139564562Sgshapiro
139638032Speter	return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
139738032Speter}
139838032Speter
139938032Speterbool
140038032Speterhash_map_open(map, mode)
140138032Speter	MAP *map;
140238032Speter	int mode;
140338032Speter{
140464562Sgshapiro# if DB_VERSION_MAJOR < 2
140538032Speter	HASHINFO hinfo;
140664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
140764562Sgshapiro# if DB_VERSION_MAJOR == 2
140838032Speter	DB_INFO hinfo;
140964562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
141064562Sgshapiro# if DB_VERSION_MAJOR > 2
141164562Sgshapiro	void *hinfo = NULL;
141264562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
141338032Speter
141438032Speter	if (tTd(38, 2))
141564562Sgshapiro		dprintf("hash_map_open(%s, %s, %d)\n",
141638032Speter			map->map_mname, map->map_file, mode);
141738032Speter
141864562Sgshapiro# if DB_VERSION_MAJOR < 3
141964562Sgshapiro	memset(&hinfo, '\0', sizeof hinfo);
142064562Sgshapiro#  ifdef DB_HASH_NELEM
142138032Speter	hinfo.h_nelem = DB_HASH_NELEM;
142264562Sgshapiro#  endif /* DB_HASH_NELEM */
142364562Sgshapiro#  ifdef DB_CACHE_SIZE
142438032Speter	hinfo.db_cachesize = DB_CACHE_SIZE;
142564562Sgshapiro#  endif /* DB_CACHE_SIZE */
142664562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
142764562Sgshapiro
142838032Speter	return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
142938032Speter}
143038032Speter
143164562Sgshapirostatic bool
143238032Speterdb_map_open(map, mode, mapclassname, dbtype, openinfo)
143338032Speter	MAP *map;
143438032Speter	int mode;
143538032Speter	char *mapclassname;
143638032Speter	DBTYPE dbtype;
143764562Sgshapiro# if DB_VERSION_MAJOR < 2
143838032Speter	const void *openinfo;
143964562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
144064562Sgshapiro# if DB_VERSION_MAJOR == 2
144138032Speter	DB_INFO *openinfo;
144264562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
144364562Sgshapiro# if DB_VERSION_MAJOR > 2
144464562Sgshapiro	void **openinfo;
144564562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
144638032Speter{
144738032Speter	DB *db = NULL;
144838032Speter	int i;
144938032Speter	int omode;
145038032Speter	int smode = S_IREAD;
145138032Speter	int fd;
145264562Sgshapiro	long sff;
145364562Sgshapiro	int save_errno;
145438032Speter	struct stat st;
145538032Speter	char buf[MAXNAME + 1];
145638032Speter
145738032Speter	/* do initial file and directory checks */
145864562Sgshapiro	(void) strlcpy(buf, map->map_file, sizeof buf - 3);
145938032Speter	i = strlen(buf);
146038032Speter	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
146164562Sgshapiro		(void) strlcat(buf, ".db", sizeof buf);
146238032Speter
146338032Speter	mode &= O_ACCMODE;
146438032Speter	omode = mode;
146538032Speter
146638032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
146738032Speter	if (mode == O_RDWR)
146838032Speter	{
146938032Speter		sff |= SFF_CREAT;
147064562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
147138032Speter			sff |= SFF_NOSLINK;
147264562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
147338032Speter			sff |= SFF_NOHLINK;
147438032Speter		smode = S_IWRITE;
147538032Speter	}
147638032Speter	else
147738032Speter	{
147864562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
147938032Speter			sff |= SFF_NOWLINK;
148038032Speter	}
148164562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
148238032Speter		sff |= SFF_SAFEDIRPATH;
148338032Speter	i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
148464562Sgshapiro
148564562Sgshapiro# if !_FFR_REMOVE_AUTOREBUILD
148638032Speter	if (i == ENOENT && AutoRebuild &&
148738032Speter	    bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
148838032Speter	    (bitset(MF_IMPL_HASH, map->map_mflags) ||
148938032Speter	     bitset(MF_ALIAS, map->map_mflags)) &&
149038032Speter	    mode == O_RDONLY)
149138032Speter	{
149238032Speter		bool impl = bitset(MF_IMPL_HASH, map->map_mflags);
149338032Speter
149438032Speter		/* may be able to rebuild */
149538032Speter		map->map_mflags &= ~MF_IMPL_HASH;
149638032Speter		if (!rebuildaliases(map, TRUE))
149738032Speter			return FALSE;
149838032Speter		if (impl)
149938032Speter			return impl_map_open(map, O_RDONLY);
150038032Speter		else
150138032Speter			return db_map_open(map, O_RDONLY, mapclassname,
150238032Speter					   dbtype, openinfo);
150338032Speter	}
150464562Sgshapiro# endif /* !_FFR_REMOVE_AUTOREBUILD */
150538032Speter
150638032Speter	if (i != 0)
150738032Speter	{
150838032Speter		char *prob = "unsafe";
150938032Speter
151038032Speter		/* cannot open this map */
151138032Speter		if (i == ENOENT)
151238032Speter			prob = "missing";
151338032Speter		if (tTd(38, 2))
151464562Sgshapiro			dprintf("\t%s map file: %s\n", prob, errstring(i));
151538032Speter		errno = i;
151638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
151738032Speter			syserr("%s map \"%s\": %s map file %s",
151838032Speter				mapclassname, map->map_mname, prob, buf);
151938032Speter		return FALSE;
152038032Speter	}
152138032Speter	if (st.st_mode == ST_MODE_NOFILE)
152238032Speter		omode |= O_CREAT|O_EXCL;
152338032Speter
152438032Speter	map->map_lockfd = -1;
152538032Speter
152664562Sgshapiro# if LOCK_ON_OPEN
152738032Speter	if (mode == O_RDWR)
152838032Speter		omode |= O_TRUNC|O_EXLOCK;
152938032Speter	else
153038032Speter		omode |= O_SHLOCK;
153164562Sgshapiro# else /* LOCK_ON_OPEN */
153238032Speter	/*
153338032Speter	**  Pre-lock the file to avoid race conditions.  In particular,
153438032Speter	**  since dbopen returns NULL if the file is zero length, we
153538032Speter	**  must have a locked instance around the dbopen.
153638032Speter	*/
153738032Speter
153838032Speter	fd = open(buf, omode, DBMMODE);
153938032Speter	if (fd < 0)
154038032Speter	{
154138032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
154238032Speter			syserr("db_map_open: cannot pre-open database %s", buf);
154338032Speter		return FALSE;
154438032Speter	}
154538032Speter
154638032Speter	/* make sure no baddies slipped in just before the open... */
154738032Speter	if (filechanged(buf, fd, &st))
154838032Speter	{
154964562Sgshapiro		save_errno = errno;
155038032Speter		(void) close(fd);
155138032Speter		errno = save_errno;
155238032Speter		syserr("db_map_open(%s): file changed after pre-open", buf);
155338032Speter		return FALSE;
155438032Speter	}
155538032Speter
155638032Speter	/* if new file, get the "before" bits for later filechanged check */
155738032Speter	if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
155838032Speter	{
155964562Sgshapiro		save_errno = errno;
156038032Speter		(void) close(fd);
156138032Speter		errno = save_errno;
156238032Speter		syserr("db_map_open(%s): cannot fstat pre-opened file",
156338032Speter			buf);
156438032Speter		return FALSE;
156538032Speter	}
156638032Speter
156738032Speter	/* actually lock the pre-opened file */
156838032Speter	if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
156938032Speter		syserr("db_map_open: cannot lock %s", buf);
157038032Speter
157138032Speter	/* set up mode bits for dbopen */
157238032Speter	if (mode == O_RDWR)
157338032Speter		omode |= O_TRUNC;
157438032Speter	omode &= ~(O_EXCL|O_CREAT);
157564562Sgshapiro# endif /* LOCK_ON_OPEN */
157638032Speter
157764562Sgshapiro# if DB_VERSION_MAJOR < 2
157838032Speter	db = dbopen(buf, omode, DBMMODE, dbtype, openinfo);
157964562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
158038032Speter	{
158138032Speter		int flags = 0;
158264562Sgshapiro#  if DB_VERSION_MAJOR > 2
158364562Sgshapiro		int ret;
158464562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
158538032Speter
158638032Speter		if (mode == O_RDONLY)
158738032Speter			flags |= DB_RDONLY;
158838032Speter		if (bitset(O_CREAT, omode))
158938032Speter			flags |= DB_CREATE;
159038032Speter		if (bitset(O_TRUNC, omode))
159138032Speter			flags |= DB_TRUNCATE;
159238032Speter
159364562Sgshapiro#  if !HASFLOCK && defined(DB_FCNTL_LOCKING)
159464562Sgshapiro		flags |= DB_FCNTL_LOCKING;
159564562Sgshapiro#  endif /* !HASFLOCK && defined(DB_FCNTL_LOCKING) */
159664562Sgshapiro
159764562Sgshapiro#  if DB_VERSION_MAJOR > 2
159864562Sgshapiro		ret = db_create(&db, NULL, 0);
159964562Sgshapiro#  ifdef DB_CACHE_SIZE
160064562Sgshapiro		if (ret == 0 && db != NULL)
160164562Sgshapiro		{
160264562Sgshapiro			ret = db->set_cachesize(db, 0, DB_CACHE_SIZE, 0);
160364562Sgshapiro			if (ret != 0)
160464562Sgshapiro			{
160564562Sgshapiro				(void) db->close(db, 0);
160664562Sgshapiro				db = NULL;
160764562Sgshapiro			}
160864562Sgshapiro		}
160964562Sgshapiro#  endif /* DB_CACHE_SIZE */
161064562Sgshapiro#  ifdef DB_HASH_NELEM
161164562Sgshapiro		if (dbtype == DB_HASH && ret == 0 && db != NULL)
161264562Sgshapiro		{
161364562Sgshapiro			ret = db->set_h_nelem(db, DB_HASH_NELEM);
161464562Sgshapiro			if (ret != 0)
161564562Sgshapiro			{
161664562Sgshapiro				(void) db->close(db, 0);
161764562Sgshapiro				db = NULL;
161864562Sgshapiro			}
161964562Sgshapiro		}
162064562Sgshapiro#  endif /* DB_HASH_NELEM */
162164562Sgshapiro		if (ret == 0 && db != NULL)
162264562Sgshapiro		{
162364562Sgshapiro			ret = db->open(db, buf, NULL, dbtype, flags, DBMMODE);
162464562Sgshapiro			if (ret != 0)
162564562Sgshapiro			{
162664562Sgshapiro				(void) db->close(db, 0);
162764562Sgshapiro				db = NULL;
162864562Sgshapiro			}
162964562Sgshapiro		}
163064562Sgshapiro		errno = ret;
163164562Sgshapiro#  else /* DB_VERSION_MAJOR > 2 */
163238032Speter		errno = db_open(buf, dbtype, flags, DBMMODE,
163338032Speter				NULL, openinfo, &db);
163464562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
163538032Speter	}
163664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
163764562Sgshapiro	save_errno = errno;
163838032Speter
163964562Sgshapiro# if !LOCK_ON_OPEN
164038032Speter	if (mode == O_RDWR)
164138032Speter		map->map_lockfd = fd;
164238032Speter	else
164338032Speter		(void) close(fd);
164464562Sgshapiro# endif /* !LOCK_ON_OPEN */
164538032Speter
164638032Speter	if (db == NULL)
164738032Speter	{
164838032Speter		if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
164938032Speter		    aliaswait(map, ".db", FALSE))
165038032Speter			return TRUE;
165164562Sgshapiro# if !LOCK_ON_OPEN
165238032Speter		if (map->map_lockfd >= 0)
165338032Speter			(void) close(map->map_lockfd);
165464562Sgshapiro# endif /* !LOCK_ON_OPEN */
165564562Sgshapiro		errno = save_errno;
165638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
165738032Speter			syserr("Cannot open %s database %s",
165838032Speter				mapclassname, buf);
165938032Speter		return FALSE;
166038032Speter	}
166138032Speter
166264562Sgshapiro# if DB_VERSION_MAJOR < 2
166338032Speter	fd = db->fd(db);
166464562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
166538032Speter	fd = -1;
166638032Speter	errno = db->fd(db, &fd);
166764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
166838032Speter	if (filechanged(buf, fd, &st))
166938032Speter	{
167064562Sgshapiro		save_errno = errno;
167164562Sgshapiro# if DB_VERSION_MAJOR < 2
167264562Sgshapiro		(void) db->close(db);
167364562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
167438032Speter		errno = db->close(db, 0);
167564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
167664562Sgshapiro# if !LOCK_ON_OPEN
167738032Speter		if (map->map_lockfd >= 0)
167864562Sgshapiro			(void) close(map->map_lockfd);
167964562Sgshapiro# endif /* !LOCK_ON_OPEN */
168038032Speter		errno = save_errno;
168138032Speter		syserr("db_map_open(%s): file changed after open", buf);
168238032Speter		return FALSE;
168338032Speter	}
168438032Speter
168538032Speter	if (mode == O_RDWR)
168638032Speter		map->map_mflags |= MF_LOCKED;
168764562Sgshapiro# if LOCK_ON_OPEN
168838032Speter	if (fd >= 0 && mode == O_RDONLY)
168938032Speter	{
169038032Speter		(void) lockfile(fd, buf, NULL, LOCK_UN);
169138032Speter	}
169264562Sgshapiro# endif /* LOCK_ON_OPEN */
169338032Speter
169438032Speter	/* try to make sure that at least the database header is on disk */
169538032Speter	if (mode == O_RDWR)
169638032Speter	{
169738032Speter		(void) db->sync(db, 0);
169842575Speter		if (geteuid() == 0 && TrustedUid != 0)
169938032Speter		{
170064562Sgshapiro#  if HASFCHOWN
170142575Speter			if (fchown(fd, TrustedUid, -1) < 0)
170238032Speter			{
170338032Speter				int err = errno;
170438032Speter
170538032Speter				sm_syslog(LOG_ALERT, NOQID,
170638032Speter					  "ownership change on %s failed: %s",
170738032Speter					  buf, errstring(err));
170838032Speter				message("050 ownership change on %s failed: %s",
170938032Speter					buf, errstring(err));
171038032Speter			}
171164562Sgshapiro#  endif /* HASFCHOWN */
171238032Speter		}
171338032Speter	}
171438032Speter
171564562Sgshapiro	map->map_db2 = (ARBPTR_T) db;
171664562Sgshapiro
171764562Sgshapiro	/*
171864562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
171964562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
172064562Sgshapiro	**  map_mtime to be set
172164562Sgshapiro	*/
172264562Sgshapiro
172338032Speter	if (fd >= 0 && fstat(fd, &st) >= 0)
172438032Speter		map->map_mtime = st.st_mtime;
172538032Speter
172638032Speter	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
172738032Speter	    !aliaswait(map, ".db", TRUE))
172838032Speter		return FALSE;
172938032Speter	return TRUE;
173038032Speter}
173138032Speter
173238032Speter
173338032Speter/*
173438032Speter**  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
173538032Speter*/
173638032Speter
173738032Speterchar *
173838032Speterdb_map_lookup(map, name, av, statp)
173938032Speter	MAP *map;
174038032Speter	char *name;
174138032Speter	char **av;
174238032Speter	int *statp;
174338032Speter{
174438032Speter	DBT key, val;
174538032Speter	register DB *db = (DB *) map->map_db2;
174638032Speter	int i;
174738032Speter	int st;
174864562Sgshapiro	int save_errno;
174938032Speter	int fd;
175038032Speter	struct stat stbuf;
175138032Speter	char keybuf[MAXNAME + 1];
175238032Speter	char buf[MAXNAME + 1];
175338032Speter
175464562Sgshapiro	memset(&key, '\0', sizeof key);
175564562Sgshapiro	memset(&val, '\0', sizeof val);
175638032Speter
175738032Speter	if (tTd(38, 20))
175864562Sgshapiro		dprintf("db_map_lookup(%s, %s)\n",
175938032Speter			map->map_mname, name);
176038032Speter
176138032Speter	i = strlen(map->map_file);
176238032Speter	if (i > MAXNAME)
176338032Speter		i = MAXNAME;
176464562Sgshapiro	(void) strlcpy(buf, map->map_file, i + 1);
176538032Speter	if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
176638032Speter		buf[i - 3] = '\0';
176738032Speter
176838032Speter	key.size = strlen(name);
176938032Speter	if (key.size > sizeof keybuf - 1)
177038032Speter		key.size = sizeof keybuf - 1;
177138032Speter	key.data = keybuf;
177264562Sgshapiro	memmove(keybuf, name, key.size);
177338032Speter	keybuf[key.size] = '\0';
177438032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
177538032Speter		makelower(keybuf);
177638032Speter  lockdb:
177764562Sgshapiro# if DB_VERSION_MAJOR < 2
177838032Speter	fd = db->fd(db);
177964562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
178038032Speter	fd = -1;
178138032Speter	errno = db->fd(db, &fd);
178264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
178338032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
178438032Speter		(void) lockfile(fd, buf, ".db", LOCK_SH);
178538032Speter	if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
178638032Speter	{
178738032Speter		/* Reopen the database to sync the cache */
178838032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
178938032Speter								 : O_RDONLY;
179038032Speter
179164562Sgshapiro		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
179264562Sgshapiro			(void) lockfile(fd, buf, ".db", LOCK_UN);
179338032Speter		map->map_class->map_close(map);
179438032Speter		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
179538032Speter		if (map->map_class->map_open(map, omode))
179638032Speter		{
179738032Speter			map->map_mflags |= MF_OPEN;
179842575Speter			map->map_pid = getpid();
179938032Speter			if ((omode && O_ACCMODE) == O_RDWR)
180038032Speter				map->map_mflags |= MF_WRITABLE;
180138032Speter			db = (DB *) map->map_db2;
180238032Speter			goto lockdb;
180338032Speter		}
180438032Speter		else
180538032Speter		{
180638032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
180738032Speter			{
180838032Speter				extern MAPCLASS BogusMapClass;
180938032Speter
181038032Speter				*statp = EX_TEMPFAIL;
181138032Speter				map->map_class = &BogusMapClass;
181238032Speter				map->map_mflags |= MF_OPEN;
181342575Speter				map->map_pid = getpid();
181438032Speter				syserr("Cannot reopen DB database %s",
181538032Speter					map->map_file);
181638032Speter			}
181738032Speter			return NULL;
181838032Speter		}
181938032Speter	}
182038032Speter
182138032Speter	st = 1;
182238032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
182338032Speter	{
182464562Sgshapiro# if DB_VERSION_MAJOR < 2
182538032Speter		st = db->get(db, &key, &val, 0);
182664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
182738032Speter		errno = db->get(db, NULL, &key, &val, 0);
182838032Speter		switch (errno)
182938032Speter		{
183038032Speter		  case DB_NOTFOUND:
183138032Speter		  case DB_KEYEMPTY:
183238032Speter			st = 1;
183338032Speter			break;
183438032Speter
183538032Speter		  case 0:
183638032Speter			st = 0;
183738032Speter			break;
183838032Speter
183938032Speter		  default:
184038032Speter			st = -1;
184138032Speter			break;
184238032Speter		}
184364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
184438032Speter		if (st == 0)
184538032Speter			map->map_mflags &= ~MF_TRY1NULL;
184638032Speter	}
184738032Speter	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
184838032Speter	{
184938032Speter		key.size++;
185064562Sgshapiro# if DB_VERSION_MAJOR < 2
185138032Speter		st = db->get(db, &key, &val, 0);
185264562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
185338032Speter		errno = db->get(db, NULL, &key, &val, 0);
185438032Speter		switch (errno)
185538032Speter		{
185638032Speter		  case DB_NOTFOUND:
185738032Speter		  case DB_KEYEMPTY:
185838032Speter			st = 1;
185938032Speter			break;
186038032Speter
186138032Speter		  case 0:
186238032Speter			st = 0;
186338032Speter			break;
186438032Speter
186538032Speter		  default:
186638032Speter			st = -1;
186738032Speter			break;
186838032Speter		}
186964562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
187038032Speter		if (st == 0)
187138032Speter			map->map_mflags &= ~MF_TRY0NULL;
187238032Speter	}
187364562Sgshapiro	save_errno = errno;
187438032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
187538032Speter		(void) lockfile(fd, buf, ".db", LOCK_UN);
187638032Speter	if (st != 0)
187738032Speter	{
187864562Sgshapiro		errno = save_errno;
187938032Speter		if (st < 0)
188038032Speter			syserr("db_map_lookup: get (%s)", name);
188138032Speter		return NULL;
188238032Speter	}
188338032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
188438032Speter		return map_rewrite(map, name, strlen(name), NULL);
188538032Speter	else
188638032Speter		return map_rewrite(map, val.data, val.size, av);
188738032Speter}
188838032Speter
188938032Speter
189038032Speter/*
189138032Speter**  DB_MAP_STORE -- store a datum in the NEWDB database
189238032Speter*/
189338032Speter
189438032Spetervoid
189538032Speterdb_map_store(map, lhs, rhs)
189638032Speter	register MAP *map;
189738032Speter	char *lhs;
189838032Speter	char *rhs;
189938032Speter{
190064562Sgshapiro	int status;
190138032Speter	DBT key;
190238032Speter	DBT data;
190338032Speter	register DB *db = map->map_db2;
190438032Speter	char keybuf[MAXNAME + 1];
190538032Speter
190664562Sgshapiro	memset(&key, '\0', sizeof key);
190764562Sgshapiro	memset(&data, '\0', sizeof data);
190838032Speter
190938032Speter	if (tTd(38, 12))
191064562Sgshapiro		dprintf("db_map_store(%s, %s, %s)\n",
191138032Speter			map->map_mname, lhs, rhs);
191238032Speter
191338032Speter	key.size = strlen(lhs);
191438032Speter	key.data = lhs;
191538032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
191638032Speter	{
191738032Speter		if (key.size > sizeof keybuf - 1)
191838032Speter			key.size = sizeof keybuf - 1;
191964562Sgshapiro		memmove(keybuf, key.data, key.size);
192038032Speter		keybuf[key.size] = '\0';
192138032Speter		makelower(keybuf);
192238032Speter		key.data = keybuf;
192338032Speter	}
192438032Speter
192538032Speter	data.size = strlen(rhs);
192638032Speter	data.data = rhs;
192738032Speter
192838032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
192938032Speter	{
193038032Speter		key.size++;
193138032Speter		data.size++;
193238032Speter	}
193338032Speter
193464562Sgshapiro# if DB_VERSION_MAJOR < 2
193564562Sgshapiro	status = db->put(db, &key, &data, R_NOOVERWRITE);
193664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
193738032Speter	errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE);
193838032Speter	switch (errno)
193938032Speter	{
194038032Speter	  case DB_KEYEXIST:
194164562Sgshapiro		status = 1;
194238032Speter		break;
194338032Speter
194438032Speter	  case 0:
194564562Sgshapiro		status = 0;
194638032Speter		break;
194738032Speter
194838032Speter	  default:
194964562Sgshapiro		status = -1;
195038032Speter		break;
195138032Speter	}
195264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
195364562Sgshapiro	if (status > 0)
195438032Speter	{
195538032Speter		if (!bitset(MF_APPEND, map->map_mflags))
195638032Speter			message("050 Warning: duplicate alias name %s", lhs);
195738032Speter		else
195838032Speter		{
195938032Speter			static char *buf = NULL;
196038032Speter			static int bufsiz = 0;
196138032Speter			DBT old;
196238032Speter
196364562Sgshapiro			memset(&old, '\0', sizeof old);
196438032Speter
196564562Sgshapiro			old.data = db_map_lookup(map, key.data,
196664562Sgshapiro						 (char **)NULL, &status);
196738032Speter			if (old.data != NULL)
196838032Speter			{
196938032Speter				old.size = strlen(old.data);
197064562Sgshapiro				if (data.size + old.size + 2 > (size_t)bufsiz)
197138032Speter				{
197238032Speter					if (buf != NULL)
197338032Speter						(void) free(buf);
197438032Speter					bufsiz = data.size + old.size + 2;
197538032Speter					buf = xalloc(bufsiz);
197638032Speter				}
197738032Speter				snprintf(buf, bufsiz, "%s,%s",
197838032Speter					(char *) data.data, (char *) old.data);
197938032Speter				data.size = data.size + old.size + 1;
198038032Speter				data.data = buf;
198138032Speter				if (tTd(38, 9))
198264562Sgshapiro					dprintf("db_map_store append=%s\n",
198364562Sgshapiro						(char *) data.data);
198438032Speter			}
198538032Speter		}
198664562Sgshapiro# if DB_VERSION_MAJOR < 2
198764562Sgshapiro		status = db->put(db, &key, &data, 0);
198864562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
198964562Sgshapiro		status = errno = db->put(db, NULL, &key, &data, 0);
199064562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
199138032Speter	}
199264562Sgshapiro	if (status != 0)
199338032Speter		syserr("readaliases: db put (%s)", lhs);
199438032Speter}
199538032Speter
199638032Speter
199738032Speter/*
199838032Speter**  DB_MAP_CLOSE -- add distinguished entries and close the database
199938032Speter*/
200038032Speter
200138032Spetervoid
200238032Speterdb_map_close(map)
200338032Speter	MAP *map;
200438032Speter{
200538032Speter	register DB *db = map->map_db2;
200638032Speter
200738032Speter	if (tTd(38, 9))
200864562Sgshapiro		dprintf("db_map_close(%s, %s, %lx)\n",
200938032Speter			map->map_mname, map->map_file, map->map_mflags);
201038032Speter
201138032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
201238032Speter	{
201338032Speter		/* write out the distinguished alias */
201438032Speter		db_map_store(map, "@", "@");
201538032Speter	}
201638032Speter
201738032Speter	(void) db->sync(db, 0);
201838032Speter
201964562Sgshapiro# if !LOCK_ON_OPEN
202038032Speter	if (map->map_lockfd >= 0)
202138032Speter		(void) close(map->map_lockfd);
202264562Sgshapiro# endif /* !LOCK_ON_OPEN */
202338032Speter
202464562Sgshapiro# if DB_VERSION_MAJOR < 2
202538032Speter	if (db->close(db) != 0)
202664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
202742575Speter	/*
202842575Speter	**  Berkeley DB can use internal shared memory
202942575Speter	**  locking for its memory pool.  Closing a map
203042575Speter	**  opened by another process will interfere
203142575Speter	**  with the shared memory and locks of the parent
203242575Speter	**  process leaving things in a bad state.
203343730Speter	*/
203443730Speter
203543730Speter	/*
203642575Speter	**  If this map was not opened by the current
203743730Speter	**  process, do not close the map but recover
203842575Speter	**  the file descriptor.
203942575Speter	*/
204042575Speter	if (map->map_pid != getpid())
204142575Speter	{
204242575Speter		int fd = -1;
204342575Speter
204442575Speter		errno = db->fd(db, &fd);
204542575Speter		if (fd >= 0)
204642575Speter			(void) close(fd);
204742575Speter		return;
204842575Speter	}
204942575Speter
205038032Speter	if ((errno = db->close(db, 0)) != 0)
205164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
205242575Speter		syserr("db_map_close(%s, %s, %lx): db close failure",
205342575Speter			map->map_mname, map->map_file, map->map_mflags);
205438032Speter}
205564562Sgshapiro#endif /* NEWDB */
205638032Speter/*
205738032Speter**  NIS Modules
205838032Speter*/
205938032Speter
206064562Sgshapiro#ifdef NIS
206138032Speter
206238032Speter# ifndef YPERR_BUSY
206338032Speter#  define YPERR_BUSY	16
206464562Sgshapiro# endif /* ! YPERR_BUSY */
206538032Speter
206638032Speter/*
206738032Speter**  NIS_MAP_OPEN -- open DBM map
206838032Speter*/
206938032Speter
207038032Speterbool
207138032Speternis_map_open(map, mode)
207238032Speter	MAP *map;
207338032Speter	int mode;
207438032Speter{
207538032Speter	int yperr;
207638032Speter	register char *p;
207738032Speter	auto char *vp;
207838032Speter	auto int vsize;
207938032Speter
208038032Speter	if (tTd(38, 2))
208164562Sgshapiro		dprintf("nis_map_open(%s, %s, %d)\n",
208238032Speter			map->map_mname, map->map_file, mode);
208338032Speter
208438032Speter	mode &= O_ACCMODE;
208538032Speter	if (mode != O_RDONLY)
208638032Speter	{
208738032Speter		/* issue a pseudo-error message */
208864562Sgshapiro# ifdef ENOSYS
208938032Speter		errno = ENOSYS;
209064562Sgshapiro# else /* ENOSYS */
209164562Sgshapiro#  ifdef EFTYPE
209238032Speter		errno = EFTYPE;
209364562Sgshapiro#  else /* EFTYPE */
209438032Speter		errno = ENXIO;
209564562Sgshapiro#  endif /* EFTYPE */
209664562Sgshapiro# endif /* ENOSYS */
209738032Speter		return FALSE;
209838032Speter	}
209938032Speter
210038032Speter	p = strchr(map->map_file, '@');
210138032Speter	if (p != NULL)
210238032Speter	{
210338032Speter		*p++ = '\0';
210438032Speter		if (*p != '\0')
210538032Speter			map->map_domain = p;
210638032Speter	}
210738032Speter
210838032Speter	if (*map->map_file == '\0')
210938032Speter		map->map_file = "mail.aliases";
211038032Speter
211138032Speter	if (map->map_domain == NULL)
211238032Speter	{
211338032Speter		yperr = yp_get_default_domain(&map->map_domain);
211438032Speter		if (yperr != 0)
211538032Speter		{
211638032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
211764562Sgshapiro				syserr("421 4.3.5 NIS map %s specified, but NIS not running",
211864562Sgshapiro				       map->map_file);
211938032Speter			return FALSE;
212038032Speter		}
212138032Speter	}
212238032Speter
212338032Speter	/* check to see if this map actually exists */
212464562Sgshapiro	vp = NULL;
212538032Speter	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
212638032Speter			&vp, &vsize);
212738032Speter	if (tTd(38, 10))
212864562Sgshapiro		dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n",
212938032Speter			map->map_domain, map->map_file, yperr_string(yperr));
213064562Sgshapiro	if (vp != NULL)
213164562Sgshapiro		free(vp);
213264562Sgshapiro
213338032Speter	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
213438032Speter	{
213538032Speter		/*
213638032Speter		**  We ought to be calling aliaswait() here if this is an
213738032Speter		**  alias file, but powerful HP-UX NIS servers  apparently
213838032Speter		**  don't insert the @:@ token into the alias map when it
213938032Speter		**  is rebuilt, so aliaswait() just hangs.  I hate HP-UX.
214038032Speter		*/
214138032Speter
214264562Sgshapiro# if 0
214338032Speter		if (!bitset(MF_ALIAS, map->map_mflags) ||
214438032Speter		    aliaswait(map, NULL, TRUE))
214564562Sgshapiro# endif /* 0 */
214638032Speter			return TRUE;
214738032Speter	}
214838032Speter
214938032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
215038032Speter	{
215164562Sgshapiro		syserr("421 4.0.0 Cannot bind to map %s in domain %s: %s",
215238032Speter			map->map_file, map->map_domain, yperr_string(yperr));
215338032Speter	}
215438032Speter
215538032Speter	return FALSE;
215638032Speter}
215738032Speter
215838032Speter
215938032Speter/*
216038032Speter**  NIS_MAP_LOOKUP -- look up a datum in a NIS map
216138032Speter*/
216238032Speter
216338032Speter/* ARGSUSED3 */
216438032Speterchar *
216538032Speternis_map_lookup(map, name, av, statp)
216638032Speter	MAP *map;
216738032Speter	char *name;
216838032Speter	char **av;
216938032Speter	int *statp;
217038032Speter{
217138032Speter	char *vp;
217238032Speter	auto int vsize;
217338032Speter	int buflen;
217438032Speter	int yperr;
217538032Speter	char keybuf[MAXNAME + 1];
217638032Speter
217738032Speter	if (tTd(38, 20))
217864562Sgshapiro		dprintf("nis_map_lookup(%s, %s)\n",
217938032Speter			map->map_mname, name);
218038032Speter
218138032Speter	buflen = strlen(name);
218238032Speter	if (buflen > sizeof keybuf - 1)
218338032Speter		buflen = sizeof keybuf - 1;
218464562Sgshapiro	memmove(keybuf, name, buflen);
218538032Speter	keybuf[buflen] = '\0';
218638032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
218738032Speter		makelower(keybuf);
218838032Speter	yperr = YPERR_KEY;
218964562Sgshapiro	vp = NULL;
219038032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
219138032Speter	{
219238032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
219338032Speter			     &vp, &vsize);
219438032Speter		if (yperr == 0)
219538032Speter			map->map_mflags &= ~MF_TRY1NULL;
219638032Speter	}
219738032Speter	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
219838032Speter	{
219964562Sgshapiro		if (vp != NULL)
220064562Sgshapiro		{
220164562Sgshapiro			free(vp);
220264562Sgshapiro			vp = NULL;
220364562Sgshapiro		}
220438032Speter		buflen++;
220538032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
220638032Speter			     &vp, &vsize);
220738032Speter		if (yperr == 0)
220838032Speter			map->map_mflags &= ~MF_TRY0NULL;
220938032Speter	}
221038032Speter	if (yperr != 0)
221138032Speter	{
221238032Speter		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
221338032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
221464562Sgshapiro		if (vp != NULL)
221564562Sgshapiro			free(vp);
221638032Speter		return NULL;
221738032Speter	}
221838032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
221938032Speter		return map_rewrite(map, name, strlen(name), NULL);
222038032Speter	else
222164562Sgshapiro	{
222264562Sgshapiro		char *ret;
222364562Sgshapiro
222464562Sgshapiro		ret = map_rewrite(map, vp, vsize, av);
222564562Sgshapiro		if (vp != NULL)
222664562Sgshapiro			free(vp);
222764562Sgshapiro		return ret;
222864562Sgshapiro	}
222938032Speter}
223038032Speter
223138032Speter
223238032Speter/*
223338032Speter**  NIS_GETCANONNAME -- look up canonical name in NIS
223438032Speter*/
223538032Speter
223664562Sgshapirostatic bool
223738032Speternis_getcanonname(name, hbsize, statp)
223838032Speter	char *name;
223938032Speter	int hbsize;
224038032Speter	int *statp;
224138032Speter{
224238032Speter	char *vp;
224338032Speter	auto int vsize;
224438032Speter	int keylen;
224538032Speter	int yperr;
224638032Speter	static bool try0null = TRUE;
224738032Speter	static bool try1null = TRUE;
224838032Speter	static char *yp_domain = NULL;
224938032Speter	char host_record[MAXLINE];
225038032Speter	char cbuf[MAXNAME];
225138032Speter	char nbuf[MAXNAME + 1];
225238032Speter
225338032Speter	if (tTd(38, 20))
225464562Sgshapiro		dprintf("nis_getcanonname(%s)\n", name);
225538032Speter
225664562Sgshapiro	if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
225738032Speter	{
225838032Speter		*statp = EX_UNAVAILABLE;
225938032Speter		return FALSE;
226038032Speter	}
226138032Speter	shorten_hostname(nbuf);
226238032Speter	keylen = strlen(nbuf);
226338032Speter
226438032Speter	if (yp_domain == NULL)
226564562Sgshapiro		(void) yp_get_default_domain(&yp_domain);
226638032Speter	makelower(nbuf);
226738032Speter	yperr = YPERR_KEY;
226864562Sgshapiro	vp = NULL;
226938032Speter	if (try0null)
227038032Speter	{
227138032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
227238032Speter			     &vp, &vsize);
227338032Speter		if (yperr == 0)
227438032Speter			try1null = FALSE;
227538032Speter	}
227638032Speter	if (yperr == YPERR_KEY && try1null)
227738032Speter	{
227864562Sgshapiro		if (vp != NULL)
227964562Sgshapiro		{
228064562Sgshapiro			free(vp);
228164562Sgshapiro			vp = NULL;
228264562Sgshapiro		}
228338032Speter		keylen++;
228438032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
228538032Speter			     &vp, &vsize);
228638032Speter		if (yperr == 0)
228738032Speter			try0null = FALSE;
228838032Speter	}
228938032Speter	if (yperr != 0)
229038032Speter	{
229138032Speter		if (yperr == YPERR_KEY)
229238032Speter			*statp = EX_NOHOST;
229338032Speter		else if (yperr == YPERR_BUSY)
229438032Speter			*statp = EX_TEMPFAIL;
229538032Speter		else
229638032Speter			*statp = EX_UNAVAILABLE;
229764562Sgshapiro		if (vp != NULL)
229864562Sgshapiro			free(vp);
229938032Speter		return FALSE;
230038032Speter	}
230164562Sgshapiro	(void) strlcpy(host_record, vp, sizeof host_record);
230264562Sgshapiro	free(vp);
230338032Speter	if (tTd(38, 44))
230464562Sgshapiro		dprintf("got record `%s'\n", host_record);
230538032Speter	if (!extract_canonname(nbuf, host_record, cbuf, sizeof cbuf))
230638032Speter	{
230738032Speter		/* this should not happen, but.... */
230838032Speter		*statp = EX_NOHOST;
230938032Speter		return FALSE;
231038032Speter	}
231138032Speter	if (hbsize < strlen(cbuf))
231238032Speter	{
231338032Speter		*statp = EX_UNAVAILABLE;
231438032Speter		return FALSE;
231538032Speter	}
231664562Sgshapiro	(void) strlcpy(name, cbuf, hbsize);
231738032Speter	*statp = EX_OK;
231838032Speter	return TRUE;
231938032Speter}
232038032Speter
232164562Sgshapiro#endif /* NIS */
232238032Speter/*
232338032Speter**  NISPLUS Modules
232438032Speter**
232538032Speter**	This code donated by Sun Microsystems.
232638032Speter*/
232738032Speter
232838032Speter#ifdef NISPLUS
232938032Speter
233064562Sgshapiro# undef NIS		/* symbol conflict in nis.h */
233164562Sgshapiro# undef T_UNSPEC	/* symbol conflict in nis.h -> ... -> sys/tiuser.h */
233264562Sgshapiro# include <rpcsvc/nis.h>
233364562Sgshapiro# include <rpcsvc/nislib.h>
233438032Speter
233564562Sgshapiro# define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
233664562Sgshapiro# define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
233764562Sgshapiro# define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
233864562Sgshapiro# define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
233938032Speter
234038032Speter/*
234138032Speter**  NISPLUS_MAP_OPEN -- open nisplus table
234238032Speter*/
234338032Speter
234438032Speterbool
234538032Speternisplus_map_open(map, mode)
234638032Speter	MAP *map;
234738032Speter	int mode;
234838032Speter{
234938032Speter	nis_result *res = NULL;
235038032Speter	int retry_cnt, max_col, i;
235138032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
235238032Speter
235338032Speter	if (tTd(38, 2))
235464562Sgshapiro		dprintf("nisplus_map_open(%s, %s, %d)\n",
235538032Speter			map->map_mname, map->map_file, mode);
235638032Speter
235738032Speter	mode &= O_ACCMODE;
235838032Speter	if (mode != O_RDONLY)
235938032Speter	{
236038032Speter		errno = EPERM;
236138032Speter		return FALSE;
236238032Speter	}
236338032Speter
236438032Speter	if (*map->map_file == '\0')
236538032Speter		map->map_file = "mail_aliases.org_dir";
236638032Speter
236738032Speter	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
236838032Speter	{
236938032Speter		/* set default NISPLUS Domain to $m */
237038032Speter		map->map_domain = newstr(nisplus_default_domain());
237138032Speter		if (tTd(38, 2))
237264562Sgshapiro			dprintf("nisplus_map_open(%s): using domain %s\n",
237364562Sgshapiro				map->map_file, map->map_domain);
237438032Speter	}
237538032Speter	if (!PARTIAL_NAME(map->map_file))
237638032Speter	{
237738032Speter		map->map_domain = newstr("");
237838032Speter		snprintf(qbuf, sizeof qbuf, "%s", map->map_file);
237938032Speter	}
238038032Speter	else
238138032Speter	{
238238032Speter		/* check to see if this map actually exists */
238338032Speter		snprintf(qbuf, sizeof qbuf, "%s.%s",
238438032Speter			map->map_file, map->map_domain);
238538032Speter	}
238638032Speter
238738032Speter	retry_cnt = 0;
238838032Speter	while (res == NULL || res->status != NIS_SUCCESS)
238938032Speter	{
239038032Speter		res = nis_lookup(qbuf, FOLLOW_LINKS);
239138032Speter		switch (res->status)
239238032Speter		{
239338032Speter		  case NIS_SUCCESS:
239438032Speter			break;
239538032Speter
239638032Speter		  case NIS_TRYAGAIN:
239738032Speter		  case NIS_RPCERROR:
239838032Speter		  case NIS_NAMEUNREACHABLE:
239938032Speter			if (retry_cnt++ > 4)
240038032Speter			{
240138032Speter				errno = EAGAIN;
240238032Speter				return FALSE;
240338032Speter			}
240438032Speter			/* try not to overwhelm hosed server */
240538032Speter			sleep(2);
240638032Speter			break;
240738032Speter
240838032Speter		  default:		/* all other nisplus errors */
240964562Sgshapiro# if 0
241038032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
241164562Sgshapiro				syserr("421 4.0.0 Cannot find table %s.%s: %s",
241238032Speter					map->map_file, map->map_domain,
241338032Speter					nis_sperrno(res->status));
241464562Sgshapiro# endif /* 0 */
241538032Speter			errno = EAGAIN;
241638032Speter			return FALSE;
241738032Speter		}
241838032Speter	}
241938032Speter
242038032Speter	if (NIS_RES_NUMOBJ(res) != 1 ||
242138032Speter	    (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
242238032Speter	{
242338032Speter		if (tTd(38, 10))
242464562Sgshapiro			dprintf("nisplus_map_open: %s is not a table\n", qbuf);
242564562Sgshapiro# if 0
242638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
242764562Sgshapiro			syserr("421 4.0.0 %s.%s: %s is not a table",
242838032Speter				map->map_file, map->map_domain,
242938032Speter				nis_sperrno(res->status));
243064562Sgshapiro# endif /* 0 */
243138032Speter		errno = EBADF;
243238032Speter		return FALSE;
243338032Speter	}
243438032Speter	/* default key column is column 0 */
243538032Speter	if (map->map_keycolnm == NULL)
243638032Speter		map->map_keycolnm = newstr(COL_NAME(res,0));
243738032Speter
243838032Speter	max_col = COL_MAX(res);
243938032Speter
244038032Speter	/* verify the key column exist */
244164562Sgshapiro	for (i = 0; i< max_col; i++)
244238032Speter	{
244364562Sgshapiro		if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0)
244438032Speter			break;
244538032Speter	}
244638032Speter	if (i == max_col)
244738032Speter	{
244838032Speter		if (tTd(38, 2))
244964562Sgshapiro			dprintf("nisplus_map_open(%s): can not find key column %s\n",
245038032Speter				map->map_file, map->map_keycolnm);
245138032Speter		errno = ENOENT;
245238032Speter		return FALSE;
245338032Speter	}
245438032Speter
245538032Speter	/* default value column is the last column */
245638032Speter	if (map->map_valcolnm == NULL)
245738032Speter	{
245838032Speter		map->map_valcolno = max_col - 1;
245938032Speter		return TRUE;
246038032Speter	}
246138032Speter
246264562Sgshapiro	for (i = 0; i< max_col; i++)
246338032Speter	{
246438032Speter		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
246538032Speter		{
246638032Speter			map->map_valcolno = i;
246738032Speter			return TRUE;
246838032Speter		}
246938032Speter	}
247038032Speter
247138032Speter	if (tTd(38, 2))
247264562Sgshapiro		dprintf("nisplus_map_open(%s): can not find column %s\n",
247364562Sgshapiro			map->map_file, map->map_keycolnm);
247438032Speter	errno = ENOENT;
247538032Speter	return FALSE;
247638032Speter}
247738032Speter
247838032Speter
247938032Speter/*
248038032Speter**  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
248138032Speter*/
248238032Speter
248338032Speterchar *
248438032Speternisplus_map_lookup(map, name, av, statp)
248538032Speter	MAP *map;
248638032Speter	char *name;
248738032Speter	char **av;
248838032Speter	int *statp;
248938032Speter{
249038032Speter	char *p;
249138032Speter	auto int vsize;
249238032Speter	char *skp;
249338032Speter	int skleft;
249438032Speter	char search_key[MAXNAME + 4];
249538032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
249638032Speter	nis_result *result;
249738032Speter
249838032Speter	if (tTd(38, 20))
249964562Sgshapiro		dprintf("nisplus_map_lookup(%s, %s)\n",
250038032Speter			map->map_mname, name);
250138032Speter
250238032Speter	if (!bitset(MF_OPEN, map->map_mflags))
250338032Speter	{
250438032Speter		if (nisplus_map_open(map, O_RDONLY))
250542575Speter		{
250638032Speter			map->map_mflags |= MF_OPEN;
250742575Speter			map->map_pid = getpid();
250842575Speter		}
250938032Speter		else
251038032Speter		{
251138032Speter			*statp = EX_UNAVAILABLE;
251238032Speter			return NULL;
251338032Speter		}
251438032Speter	}
251538032Speter
251638032Speter	/*
251738032Speter	**  Copy the name to the key buffer, escaping double quote characters
251838032Speter	**  by doubling them and quoting "]" and "," to avoid having the
251938032Speter	**  NIS+ parser choke on them.
252038032Speter	*/
252138032Speter
252238032Speter	skleft = sizeof search_key - 4;
252338032Speter	skp = search_key;
252438032Speter	for (p = name; *p != '\0' && skleft > 0; p++)
252538032Speter	{
252638032Speter		switch (*p)
252738032Speter		{
252838032Speter		  case ']':
252938032Speter		  case ',':
253038032Speter			/* quote the character */
253138032Speter			*skp++ = '"';
253238032Speter			*skp++ = *p;
253338032Speter			*skp++ = '"';
253438032Speter			skleft -= 3;
253538032Speter			break;
253638032Speter
253738032Speter		  case '"':
253838032Speter			/* double the quote */
253938032Speter			*skp++ = '"';
254038032Speter			skleft--;
254164562Sgshapiro			/* FALLTHROUGH */
254238032Speter
254338032Speter		  default:
254438032Speter			*skp++ = *p;
254538032Speter			skleft--;
254638032Speter			break;
254738032Speter		}
254838032Speter	}
254938032Speter	*skp = '\0';
255038032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
255138032Speter		makelower(search_key);
255238032Speter
255338032Speter	/* construct the query */
255438032Speter	if (PARTIAL_NAME(map->map_file))
255538032Speter		snprintf(qbuf, sizeof qbuf, "[%s=%s],%s.%s",
255638032Speter			map->map_keycolnm, search_key, map->map_file,
255738032Speter			map->map_domain);
255838032Speter	else
255938032Speter		snprintf(qbuf, sizeof qbuf, "[%s=%s],%s",
256038032Speter			map->map_keycolnm, search_key, map->map_file);
256138032Speter
256238032Speter	if (tTd(38, 20))
256364562Sgshapiro		dprintf("qbuf=%s\n", qbuf);
256438032Speter	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
256538032Speter	if (result->status == NIS_SUCCESS)
256638032Speter	{
256738032Speter		int count;
256838032Speter		char *str;
256938032Speter
257038032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
257138032Speter		{
257238032Speter			if (LogLevel > 10)
257338032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
257464562Sgshapiro					  "%s: lookup error, expected 1 entry, got %d",
257564562Sgshapiro					  map->map_file, count);
257638032Speter
257738032Speter			/* ignore second entry */
257838032Speter			if (tTd(38, 20))
257964562Sgshapiro				dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
258038032Speter					name, count);
258138032Speter		}
258238032Speter
258338032Speter		p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
258438032Speter		/* set the length of the result */
258538032Speter		if (p == NULL)
258638032Speter			p = "";
258738032Speter		vsize = strlen(p);
258838032Speter		if (tTd(38, 20))
258964562Sgshapiro			dprintf("nisplus_map_lookup(%s), found %s\n",
259038032Speter				name, p);
259138032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
259238032Speter			str = map_rewrite(map, name, strlen(name), NULL);
259338032Speter		else
259438032Speter			str = map_rewrite(map, p, vsize, av);
259538032Speter		nis_freeresult(result);
259638032Speter		*statp = EX_OK;
259738032Speter		return str;
259838032Speter	}
259938032Speter	else
260038032Speter	{
260138032Speter		if (result->status == NIS_NOTFOUND)
260238032Speter			*statp = EX_NOTFOUND;
260338032Speter		else if (result->status == NIS_TRYAGAIN)
260438032Speter			*statp = EX_TEMPFAIL;
260538032Speter		else
260638032Speter		{
260738032Speter			*statp = EX_UNAVAILABLE;
260838032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
260938032Speter		}
261038032Speter	}
261138032Speter	if (tTd(38, 20))
261264562Sgshapiro		dprintf("nisplus_map_lookup(%s), failed\n", name);
261338032Speter	nis_freeresult(result);
261438032Speter	return NULL;
261538032Speter}
261638032Speter
261738032Speter
261838032Speter
261938032Speter/*
262038032Speter**  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
262138032Speter*/
262238032Speter
262364562Sgshapirostatic bool
262438032Speternisplus_getcanonname(name, hbsize, statp)
262538032Speter	char *name;
262638032Speter	int hbsize;
262738032Speter	int *statp;
262838032Speter{
262938032Speter	char *vp;
263038032Speter	auto int vsize;
263138032Speter	nis_result *result;
263238032Speter	char *p;
263338032Speter	char nbuf[MAXNAME + 1];
263438032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
263538032Speter
263638032Speter	if (strlen(name) >= sizeof nbuf)
263738032Speter	{
263838032Speter		*statp = EX_UNAVAILABLE;
263938032Speter		return FALSE;
264038032Speter	}
264164562Sgshapiro	(void) strlcpy(nbuf, name, sizeof nbuf);
264238032Speter	shorten_hostname(nbuf);
264338032Speter
264438032Speter	p = strchr(nbuf, '.');
264538032Speter	if (p == NULL)
264638032Speter	{
264738032Speter		/* single token */
264838032Speter		snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir", nbuf);
264938032Speter	}
265038032Speter	else if (p[1] != '\0')
265138032Speter	{
265238032Speter		/* multi token -- take only first token in nbuf */
265338032Speter		*p = '\0';
265438032Speter		snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir.%s",
265538032Speter			nbuf, &p[1]);
265638032Speter	}
265738032Speter	else
265838032Speter	{
265938032Speter		*statp = EX_NOHOST;
266038032Speter		return FALSE;
266138032Speter	}
266238032Speter
266338032Speter	if (tTd(38, 20))
266464562Sgshapiro		dprintf("\nnisplus_getcanoname(%s), qbuf=%s\n",
266564562Sgshapiro			name, qbuf);
266638032Speter
266738032Speter	result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
266838032Speter		NULL, NULL);
266938032Speter
267038032Speter	if (result->status == NIS_SUCCESS)
267138032Speter	{
267238032Speter		int count;
267338032Speter		char *domain;
267438032Speter
267538032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
267638032Speter		{
267738032Speter			if (LogLevel > 10)
267838032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
267964562Sgshapiro					  "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
268064562Sgshapiro					  count);
268138032Speter
268238032Speter			/* ignore second entry */
268338032Speter			if (tTd(38, 20))
268464562Sgshapiro				dprintf("nisplus_getcanoname(%s), got %d entries, all but first ignored\n",
268538032Speter					name, count);
268638032Speter		}
268738032Speter
268838032Speter		if (tTd(38, 20))
268964562Sgshapiro			dprintf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
269064562Sgshapiro				name, (NIS_RES_OBJECT(result))->zo_domain);
269138032Speter
269238032Speter
269338032Speter		vp = ((NIS_RES_OBJECT(result))->EN_col(0));
269438032Speter		vsize = strlen(vp);
269538032Speter		if (tTd(38, 20))
269664562Sgshapiro			dprintf("nisplus_getcanonname(%s), found %s\n",
269738032Speter				name, vp);
269838032Speter		if (strchr(vp, '.') != NULL)
269938032Speter		{
270038032Speter			domain = "";
270138032Speter		}
270238032Speter		else
270338032Speter		{
270438032Speter			domain = macvalue('m', CurEnv);
270538032Speter			if (domain == NULL)
270638032Speter				domain = "";
270738032Speter		}
270838032Speter		if (hbsize > vsize + (int) strlen(domain) + 1)
270938032Speter		{
271038032Speter			if (domain[0] == '\0')
271164562Sgshapiro				(void) strlcpy(name, vp, hbsize);
271238032Speter			else
271338032Speter				snprintf(name, hbsize, "%s.%s", vp, domain);
271438032Speter			*statp = EX_OK;
271538032Speter		}
271638032Speter		else
271738032Speter			*statp = EX_NOHOST;
271838032Speter		nis_freeresult(result);
271938032Speter		return TRUE;
272038032Speter	}
272138032Speter	else
272238032Speter	{
272338032Speter		if (result->status == NIS_NOTFOUND)
272438032Speter			*statp = EX_NOHOST;
272538032Speter		else if (result->status == NIS_TRYAGAIN)
272638032Speter			*statp = EX_TEMPFAIL;
272738032Speter		else
272838032Speter			*statp = EX_UNAVAILABLE;
272938032Speter	}
273038032Speter	if (tTd(38, 20))
273164562Sgshapiro		dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
273238032Speter			name, result->status, *statp);
273338032Speter	nis_freeresult(result);
273438032Speter	return FALSE;
273538032Speter}
273638032Speter
273738032Speterchar *
273838032Speternisplus_default_domain()
273938032Speter{
274038032Speter	static char default_domain[MAXNAME + 1] = "";
274138032Speter	char *p;
274238032Speter
274338032Speter	if (default_domain[0] != '\0')
274464562Sgshapiro		return default_domain;
274538032Speter
274638032Speter	p = nis_local_directory();
274738032Speter	snprintf(default_domain, sizeof default_domain, "%s", p);
274838032Speter	return default_domain;
274938032Speter}
275038032Speter
275138032Speter#endif /* NISPLUS */
275238032Speter/*
275338032Speter**  LDAP Modules
275438032Speter*/
275538032Speter
275664562Sgshapiro/*
275764562Sgshapiro**  LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs
275864562Sgshapiro*/
275964562Sgshapiro
276064562Sgshapiro#if defined(LDAPMAP) || defined(PH_MAP)
276164562Sgshapiro
276264562Sgshapiro# ifdef PH_MAP
276364562Sgshapiro#  define ph_map_dequote ldapmap_dequote
276464562Sgshapiro# endif /* PH_MAP */
276564562Sgshapiro
276664562Sgshapirochar *
276764562Sgshapiroldapmap_dequote(str)
276864562Sgshapiro	char *str;
276964562Sgshapiro{
277064562Sgshapiro	char *p;
277164562Sgshapiro	char *start;
277264562Sgshapiro
277364562Sgshapiro	if (str == NULL)
277464562Sgshapiro		return NULL;
277564562Sgshapiro
277664562Sgshapiro	p = str;
277764562Sgshapiro	if (*p == '"')
277864562Sgshapiro	{
277964562Sgshapiro		/* Should probably swallow initial whitespace here */
278064562Sgshapiro		start = ++p;
278164562Sgshapiro	}
278264562Sgshapiro	else
278364562Sgshapiro		return str;
278464562Sgshapiro	while (*p != '"' && *p != '\0')
278564562Sgshapiro		p++;
278664562Sgshapiro	if (*p != '\0')
278764562Sgshapiro		*p = '\0';
278864562Sgshapiro	return start;
278964562Sgshapiro}
279064562Sgshapiro#endif /* defined(LDAPMAP) || defined(PH_MAP) */
279164562Sgshapiro
279238032Speter#ifdef LDAPMAP
279338032Speter
279464562SgshapiroLDAPMAP_STRUCT *LDAPDefaults = NULL;
279538032Speter
279638032Speter/*
279764562Sgshapiro**  LDAPMAP_OPEN -- open LDAP map
279838032Speter**
279964562Sgshapiro**	Connect to the LDAP server.  Re-use existing connections since a
280064562Sgshapiro**	single server connection to a host (with the same host, port,
280164562Sgshapiro**	bind DN, and secret) can answer queries for multiple maps.
280238032Speter*/
280338032Speter
280438032Speterbool
280564562Sgshapiroldapmap_open(map, mode)
280638032Speter	MAP *map;
280738032Speter	int mode;
280838032Speter{
280964562Sgshapiro	LDAPMAP_STRUCT *lmap;
281064562Sgshapiro	STAB *s;
281164562Sgshapiro
281238032Speter	if (tTd(38, 2))
281364562Sgshapiro		dprintf("ldapmap_open(%s, %d)\n", map->map_mname, mode);
281438032Speter
281538032Speter	mode &= O_ACCMODE;
281664562Sgshapiro
281764562Sgshapiro	/* sendmail doesn't have the ability to write to LDAP (yet) */
281838032Speter	if (mode != O_RDONLY)
281938032Speter	{
282038032Speter		/* issue a pseudo-error message */
282164562Sgshapiro# ifdef ENOSYS
282238032Speter		errno = ENOSYS;
282364562Sgshapiro# else /* ENOSYS */
282464562Sgshapiro#  ifdef EFTYPE
282538032Speter		errno = EFTYPE;
282664562Sgshapiro#  else /* EFTYPE */
282738032Speter		errno = ENXIO;
282864562Sgshapiro#  endif /* EFTYPE */
282964562Sgshapiro# endif /* ENOSYS */
283038032Speter		return FALSE;
283138032Speter	}
283264562Sgshapiro
283364562Sgshapiro	/* Comma separate if used as an alias file */
283464562Sgshapiro	if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
283564562Sgshapiro		map->map_coldelim = ',';
283664562Sgshapiro
283764562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
283864562Sgshapiro
283964562Sgshapiro	s = ldapmap_findconn(lmap);
284064562Sgshapiro	if (s->s_ldap != NULL)
284164562Sgshapiro	{
284264562Sgshapiro		/* Already have a connection open to this LDAP server */
284364562Sgshapiro		lmap->ldap_ld = s->s_ldap;
284464562Sgshapiro		map->map_mflags |= MF_SHARED;
284564562Sgshapiro		return TRUE;
284664562Sgshapiro	}
284764562Sgshapiro
284864562Sgshapiro	/* No connection yet, connect */
284964562Sgshapiro	if (!ldapmap_start(map))
285064562Sgshapiro		return FALSE;
285164562Sgshapiro
285264562Sgshapiro	/* Save connection for reuse */
285364562Sgshapiro	s->s_ldap = lmap->ldap_ld;
285438032Speter	return TRUE;
285538032Speter}
285638032Speter
285738032Speter/*
285864562Sgshapiro**  LDAPMAP_START -- actually connect to an LDAP server
285938032Speter**
286064562Sgshapiro**	Parameters:
286164562Sgshapiro**		map -- the map being opened.
286264562Sgshapiro**
286364562Sgshapiro**	Returns:
286464562Sgshapiro**		TRUE if connection is successful, FALSE otherwise.
286564562Sgshapiro**
286664562Sgshapiro**	Side Effects:
286764562Sgshapiro**		Populates lmap->ldap_ld.
286838032Speter*/
286938032Speter
287038032Speterstatic jmp_buf	LDAPTimeout;
287138032Speter
287264562Sgshapirostatic bool
287364562Sgshapiroldapmap_start(map)
287438032Speter	MAP *map;
287538032Speter{
287664562Sgshapiro	register int bind_result;
287764562Sgshapiro	int save_errno;
287864562Sgshapiro	register EVENT *ev = NULL;
287964562Sgshapiro	LDAPMAP_STRUCT *lmap;
288038032Speter	LDAP *ld;
288138032Speter
288238032Speter	if (tTd(38, 2))
288364562Sgshapiro		dprintf("ldapmap_start(%s)\n", map->map_mname);
288438032Speter
288564562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
288638032Speter
288738032Speter	if (tTd(38,9))
288864562Sgshapiro		dprintf("ldapmap_start(%s, %d)\n",
288964562Sgshapiro			lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host,
289064562Sgshapiro			lmap->ldap_port);
289138032Speter
289264562Sgshapiro# if USE_LDAP_INIT
289364562Sgshapiro	ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
289464562Sgshapiro# else /* USE_LDAP_INIT */
289564562Sgshapiro	/*
289664562Sgshapiro	**  If using ldap_open(), the actual connection to the server
289764562Sgshapiro	**  happens now so we need the timeout here.  For ldap_init(),
289864562Sgshapiro	**  the connection happens at bind time.
289964562Sgshapiro	*/
290038032Speter
290138032Speter	/* set the timeout */
290264562Sgshapiro	if (lmap->ldap_timeout.tv_sec != 0)
290338032Speter	{
290438032Speter		if (setjmp(LDAPTimeout) != 0)
290538032Speter		{
290638032Speter			if (LogLevel > 1)
290738032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
290864562Sgshapiro					  "timeout conning to LDAP server %.100s",
290964562Sgshapiro					  lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host);
291064562Sgshapiro			return FALSE;
291138032Speter		}
291264562Sgshapiro		ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
291338032Speter	}
291438032Speter
291564562Sgshapiro	ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
291664562Sgshapiro	save_errno = errno;
291742575Speter
291864562Sgshapiro	/* clear the event if it has not sprung */
291964562Sgshapiro	if (ev != NULL)
292042575Speter		clrevent(ev);
292164562Sgshapiro# endif /* USE_LDAP_INIT */
292242575Speter
292364562Sgshapiro	errno = save_errno;
292442575Speter	if (ld == NULL)
292538032Speter	{
292638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
292738032Speter		{
292864562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
292964562Sgshapiro				syserr("%s failed to %s in map %s",
293064562Sgshapiro# if USE_LDAP_INIT
293164562Sgshapiro				       "ldap_init",
293264562Sgshapiro# else /* USE_LDAP_INIT */
293364562Sgshapiro				       "ldap_open",
293464562Sgshapiro# endif /* USE_LDAP_INIT */
293564562Sgshapiro				       lmap->ldap_host == NULL ? "localhost"
293664562Sgshapiro							       : lmap->ldap_host,
293764562Sgshapiro				       map->map_mname);
293864562Sgshapiro			else
293964562Sgshapiro				syserr("421 4.0.0 %s failed to %s in map %s",
294064562Sgshapiro# if USE_LDAP_INIT
294164562Sgshapiro				       "ldap_init",
294264562Sgshapiro# else /* USE_LDAP_INIT */
294364562Sgshapiro				       "ldap_open",
294464562Sgshapiro# endif /* USE_LDAP_INIT */
294564562Sgshapiro				       lmap->ldap_host == NULL ? "localhost"
294664562Sgshapiro							       : lmap->ldap_host,
294764562Sgshapiro				       map->map_mname);
294838032Speter		}
294938032Speter		return FALSE;
295038032Speter	}
295138032Speter
295264562Sgshapiro	ldapmap_setopts(ld, lmap);
295338032Speter
295464562Sgshapiro# if USE_LDAP_INIT
295564562Sgshapiro	/*
295664562Sgshapiro	**  If using ldap_init(), the actual connection to the server
295764562Sgshapiro	**  happens at ldap_bind_s() so we need the timeout here.
295864562Sgshapiro	*/
295964562Sgshapiro
296064562Sgshapiro	/* set the timeout */
296164562Sgshapiro	if (lmap->ldap_timeout.tv_sec != 0)
296238032Speter	{
296364562Sgshapiro		if (setjmp(LDAPTimeout) != 0)
296438032Speter		{
296564562Sgshapiro			if (LogLevel > 1)
296664562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
296764562Sgshapiro					  "timeout conning to LDAP server %.100s",
296864562Sgshapiro					  lmap->ldap_host == NULL ? "localhost"
296964562Sgshapiro								  : lmap->ldap_host);
297064562Sgshapiro			return FALSE;
297138032Speter		}
297264562Sgshapiro		ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
297338032Speter	}
297464562Sgshapiro# endif /* USE_LDAP_INIT */
297564562Sgshapiro
297664562Sgshapiro# ifdef LDAP_AUTH_KRBV4
297764562Sgshapiro	if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
297864562Sgshapiro	    lmap->ldap_secret != NULL)
297938032Speter	{
298064562Sgshapiro		/*
298164562Sgshapiro		**  Need to put ticket in environment here instead of
298264562Sgshapiro		**  during parseargs as there may be different tickets
298364562Sgshapiro		**  for different LDAP connections.
298464562Sgshapiro		*/
298564562Sgshapiro
298664562Sgshapiro		(void) putenv(lmap->ldap_secret);
298738032Speter	}
298864562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
298938032Speter
299064562Sgshapiro	bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
299164562Sgshapiro				  lmap->ldap_secret, lmap->ldap_method);
299264562Sgshapiro
299364562Sgshapiro# if USE_LDAP_INIT
299464562Sgshapiro	/* clear the event if it has not sprung */
299564562Sgshapiro	if (ev != NULL)
299664562Sgshapiro		clrevent(ev);
299764562Sgshapiro# endif /* USE_LDAP_INIT */
299864562Sgshapiro
299964562Sgshapiro	if (bind_result != LDAP_SUCCESS)
300064562Sgshapiro	{
300164562Sgshapiro		errno = bind_result + E_LDAPBASE;
300264562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
300364562Sgshapiro		{
300464562Sgshapiro			syserr("421 4.0.0 Cannot bind to map %s in ldap server %s",
300564562Sgshapiro			       map->map_mname,
300664562Sgshapiro			       lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host);
300764562Sgshapiro		}
300864562Sgshapiro		return FALSE;
300964562Sgshapiro	}
301064562Sgshapiro
301164562Sgshapiro	/* We need to cast ld into the map structure */
301264562Sgshapiro	lmap->ldap_ld = ld;
301364562Sgshapiro	return TRUE;
301438032Speter}
301538032Speter
301664562Sgshapiro/* ARGSUSED */
301764562Sgshapirostatic void
301864562Sgshapiroldaptimeout(sig_no)
301964562Sgshapiro	int sig_no;
302064562Sgshapiro{
302164562Sgshapiro	longjmp(LDAPTimeout, 1);
302264562Sgshapiro}
302338032Speter
302438032Speter/*
302564562Sgshapiro**  LDAPMAP_CLOSE -- close ldap map
302638032Speter*/
302738032Speter
302838032Spetervoid
302964562Sgshapiroldapmap_close(map)
303038032Speter	MAP *map;
303138032Speter{
303264562Sgshapiro	LDAPMAP_STRUCT *lmap;
303364562Sgshapiro	STAB *s;
303443730Speter
303564562Sgshapiro	if (tTd(38, 2))
303664562Sgshapiro		dprintf("ldapmap_close(%s)\n", map->map_mname);
303764562Sgshapiro
303864562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
303964562Sgshapiro
304064562Sgshapiro	/* Check if already closed */
304164562Sgshapiro	if (lmap->ldap_ld == NULL)
304264562Sgshapiro		return;
304364562Sgshapiro
304464562Sgshapiro	s = ldapmap_findconn(lmap);
304564562Sgshapiro
304664562Sgshapiro	/* Check if already closed */
304764562Sgshapiro	if (s->s_ldap == NULL)
304864562Sgshapiro		return;
304964562Sgshapiro
305064562Sgshapiro	/* If same as saved connection, stored connection is going away */
305164562Sgshapiro	if (s->s_ldap == lmap->ldap_ld)
305264562Sgshapiro		s->s_ldap = NULL;
305364562Sgshapiro
305464562Sgshapiro	if (lmap->ldap_ld != NULL)
305543730Speter	{
305664562Sgshapiro		ldap_unbind(lmap->ldap_ld);
305764562Sgshapiro		lmap->ldap_ld = NULL;
305843730Speter	}
305938032Speter}
306038032Speter
306164562Sgshapiro# ifdef SUNET_ID
306243730Speter/*
306342575Speter**  SUNET_ID_HASH -- Convert a string to it's Sunet_id canonical form
306442575Speter**  This only makes sense at Stanford University.
306538032Speter*/
306638032Speter
306738032Speterchar *
306838032Spetersunet_id_hash(str)
306938032Speter	char *str;
307038032Speter{
307138032Speter	char *p, *p_last;
307238032Speter
307338032Speter	p = str;
307438032Speter	p_last = p;
307538032Speter	while (*p != '\0')
307638032Speter	{
307738032Speter		if (islower(*p) || isdigit(*p))
307838032Speter		{
307938032Speter			*p_last = *p;
308038032Speter			p_last++;
308138032Speter		}
308238032Speter		else if (isupper(*p))
308338032Speter		{
308438032Speter			*p_last = tolower(*p);
308538032Speter			p_last++;
308638032Speter		}
308738032Speter		++p;
308838032Speter	}
308938032Speter	if (*p_last != '\0')
309038032Speter		*p_last = '\0';
309164562Sgshapiro	return str;
309238032Speter}
309364562Sgshapiro# endif /* SUNET_ID */
309438032Speter
309538032Speter/*
309664562Sgshapiro**  LDAPMAP_LOOKUP -- look up a datum in a LDAP map
309738032Speter*/
309838032Speter
309938032Speterchar *
310064562Sgshapiroldapmap_lookup(map, name, av, statp)
310138032Speter	MAP *map;
310238032Speter	char *name;
310338032Speter	char **av;
310438032Speter	int *statp;
310538032Speter{
310664562Sgshapiro	int i;
310764562Sgshapiro	int entries = 0;
310864562Sgshapiro	int msgid;
310964562Sgshapiro	int ret;
311064562Sgshapiro	int vsize;
311164562Sgshapiro	char *fp, *vp;
311264562Sgshapiro	char *p, *q;
311364562Sgshapiro	char *result = NULL;
311464562Sgshapiro	LDAPMAP_STRUCT *lmap = NULL;
311538032Speter	char keybuf[MAXNAME + 1];
311664562Sgshapiro	char filter[LDAPMAP_MAX_FILTER + 1];
311738032Speter
311838032Speter	if (tTd(38, 20))
311964562Sgshapiro		dprintf("ldapmap_lookup(%s, %s)\n", map->map_mname, name);
312038032Speter
312138032Speter	/* Get ldap struct pointer from map */
312264562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
312364562Sgshapiro	ldapmap_setopts(lmap->ldap_ld, lmap);
312438032Speter
312564562Sgshapiro	(void) strlcpy(keybuf, name, sizeof keybuf);
312638032Speter
312738032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
312864562Sgshapiro	{
312964562Sgshapiro# ifdef SUNET_ID
313038032Speter		sunet_id_hash(keybuf);
313164562Sgshapiro# else /* SUNET_ID */
313238032Speter		makelower(keybuf);
313364562Sgshapiro# endif /* SUNET_ID */
313464562Sgshapiro	}
313538032Speter
313642575Speter	/* substitute keybuf into filter, perhaps multiple times */
313764562Sgshapiro	memset(filter, '\0', sizeof filter);
313842575Speter	fp = filter;
313964562Sgshapiro	p = lmap->ldap_filter;
314042575Speter	while ((q = strchr(p, '%')) != NULL)
314142575Speter	{
314242575Speter		if (q[1] == 's')
314342575Speter		{
314442575Speter			snprintf(fp, SPACELEFT(filter, fp), "%.*s%s",
314542575Speter				 q - p, p, keybuf);
314664562Sgshapiro			fp += strlen(fp);
314742575Speter			p = q + 2;
314842575Speter		}
314964562Sgshapiro		else if (q[1] == '0')
315064562Sgshapiro		{
315164562Sgshapiro			char *k = keybuf;
315264562Sgshapiro
315364562Sgshapiro			snprintf(fp, SPACELEFT(filter, fp), "%.*s",
315464562Sgshapiro				 q - p, p);
315564562Sgshapiro			fp += strlen(fp);
315664562Sgshapiro			p = q + 2;
315764562Sgshapiro
315864562Sgshapiro			/* Properly escape LDAP special characters */
315964562Sgshapiro			while (SPACELEFT(filter, fp) > 0 &&
316064562Sgshapiro			       *k != '\0')
316164562Sgshapiro			{
316264562Sgshapiro				if (*k == '*' || *k == '(' ||
316364562Sgshapiro				    *k == ')' || *k == '\\')
316464562Sgshapiro				{
316564562Sgshapiro					(void) strlcat(fp,
316664562Sgshapiro						       (*k == '*' ? "\\2A" :
316764562Sgshapiro							(*k == '(' ? "\\28" :
316864562Sgshapiro							 (*k == ')' ? "\\29" :
316964562Sgshapiro							  (*k == '\\' ? "\\5C" :
317064562Sgshapiro							   "\00")))),
317164562Sgshapiro						SPACELEFT(filter, fp));
317264562Sgshapiro					fp += strlen(fp);
317364562Sgshapiro					k++;
317464562Sgshapiro				}
317564562Sgshapiro				else
317664562Sgshapiro					*fp++ = *k++;
317764562Sgshapiro			}
317864562Sgshapiro		}
317942575Speter		else
318042575Speter		{
318142575Speter			snprintf(fp, SPACELEFT(filter, fp), "%.*s",
318242575Speter				 q - p + 1, p);
318342575Speter			p = q + (q[1] == '%' ? 2 : 1);
318464562Sgshapiro			fp += strlen(fp);
318542575Speter		}
318642575Speter	}
318742575Speter	snprintf(fp, SPACELEFT(filter, fp), "%s", p);
318842575Speter	if (tTd(38, 20))
318964562Sgshapiro		dprintf("ldap search filter=%s\n", filter);
319038032Speter
319164562Sgshapiro	lmap->ldap_res = NULL;
319264562Sgshapiro	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope,
319364562Sgshapiro			    filter,
319464562Sgshapiro			    (lmap->ldap_attr[0] == NULL ? NULL :
319564562Sgshapiro			     lmap->ldap_attr),
319664562Sgshapiro			    lmap->ldap_attrsonly);
319764562Sgshapiro	if (msgid == -1)
319838032Speter	{
319964562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
320064562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
320138032Speter		{
320264562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
320364562Sgshapiro				syserr("Error in ldap_search_st using %s in map %s",
320464562Sgshapiro				       filter, map->map_mname);
320564562Sgshapiro			else
320664562Sgshapiro				syserr("421 4.0.0 Error in ldap_search_st using %s in map %s",
320764562Sgshapiro				       filter, map->map_mname);
320838032Speter		}
320964562Sgshapiro		*statp = EX_TEMPFAIL;
321064562Sgshapiro		return NULL;
321164562Sgshapiro	}
321264562Sgshapiro
321364562Sgshapiro	*statp = EX_NOTFOUND;
321464562Sgshapiro	vp = NULL;
321564562Sgshapiro
321664562Sgshapiro	/* Get results (all if MF_NOREWRITE, otherwise one by one) */
321764562Sgshapiro	while ((ret = ldap_result(lmap->ldap_ld, msgid,
321864562Sgshapiro				  bitset(MF_NOREWRITE, map->map_mflags),
321964562Sgshapiro				  (lmap->ldap_timeout.tv_sec == 0 ? NULL :
322064562Sgshapiro				   &(lmap->ldap_timeout)),
322164562Sgshapiro				  &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
322264562Sgshapiro	{
322364562Sgshapiro		LDAPMessage *entry;
322464562Sgshapiro
322564562Sgshapiro		if (bitset(MF_SINGLEMATCH, map->map_mflags))
322638032Speter		{
322764562Sgshapiro			entries += ldap_count_entries(lmap->ldap_ld,
322864562Sgshapiro						      lmap->ldap_res);
322964562Sgshapiro			if (entries > 1)
323064562Sgshapiro			{
323164562Sgshapiro				*statp = EX_NOTFOUND;
323264562Sgshapiro				if (lmap->ldap_res != NULL)
323364562Sgshapiro				{
323464562Sgshapiro					ldap_msgfree(lmap->ldap_res);
323564562Sgshapiro					lmap->ldap_res = NULL;
323664562Sgshapiro				}
323764562Sgshapiro				(void) ldap_abandon(lmap->ldap_ld, msgid);
323864562Sgshapiro				if (vp != NULL)
323964562Sgshapiro					free(vp);
324064562Sgshapiro				if (tTd(38, 25))
324164562Sgshapiro					dprintf("ldap search found multiple on a single match query\n");
324264562Sgshapiro				return NULL;
324364562Sgshapiro			}
324464562Sgshapiro		}
324564562Sgshapiro
324664562Sgshapiro		/* If we don't want multiple values and we have one, break */
324764562Sgshapiro		if (map->map_coldelim == '\0' && vp != NULL)
324864562Sgshapiro			break;
324964562Sgshapiro
325064562Sgshapiro		/* Cycle through all entries */
325164562Sgshapiro		for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
325264562Sgshapiro		     entry != NULL;
325364562Sgshapiro		     entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
325464562Sgshapiro		{
325564562Sgshapiro			BerElement *ber;
325664562Sgshapiro			char *attr;
325764562Sgshapiro			char **vals = NULL;
325864562Sgshapiro
325964562Sgshapiro			/*
326064562Sgshapiro			**  If matching only and found an entry,
326164562Sgshapiro			**  no need to spin through attributes
326264562Sgshapiro			*/
326364562Sgshapiro
326464562Sgshapiro			if (*statp == EX_OK &&
326564562Sgshapiro			    bitset(MF_MATCHONLY, map->map_mflags))
326664562Sgshapiro				continue;
326764562Sgshapiro
326864562Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
326964562Sgshapiro			/*
327064562Sgshapiro			**  Reset value to prevent lingering
327164562Sgshapiro			**  LDAP_DECODING_ERROR due to
327264562Sgshapiro			**  OpenLDAP 1.X's hack (see below)
327364562Sgshapiro			*/
327464562Sgshapiro
327564562Sgshapiro			lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
327664562Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
327764562Sgshapiro
327864562Sgshapiro			for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
327964562Sgshapiro							 &ber);
328064562Sgshapiro			     attr != NULL;
328164562Sgshapiro			     attr = ldap_next_attribute(lmap->ldap_ld, entry,
328264562Sgshapiro							ber))
328364562Sgshapiro			{
328464562Sgshapiro				char *tmp, *vp_tmp;
328564562Sgshapiro
328664562Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
328764562Sgshapiro				{
328864562Sgshapiro					vals = ldap_get_values(lmap->ldap_ld,
328964562Sgshapiro							       entry,
329064562Sgshapiro							       attr);
329164562Sgshapiro					if (vals == NULL)
329264562Sgshapiro					{
329364562Sgshapiro						errno = ldapmap_geterrno(lmap->ldap_ld);
329464562Sgshapiro						if (errno == LDAP_SUCCESS)
329564562Sgshapiro							continue;
329664562Sgshapiro
329764562Sgshapiro						/* Must be an error */
329864562Sgshapiro						errno += E_LDAPBASE;
329964562Sgshapiro						if (!bitset(MF_OPTIONAL,
330064562Sgshapiro							    map->map_mflags))
330164562Sgshapiro						{
330264562Sgshapiro							if (bitset(MF_NODEFER,
330364562Sgshapiro								   map->map_mflags))
330464562Sgshapiro								syserr("Error getting LDAP values in map %s",
330564562Sgshapiro								       map->map_mname);
330664562Sgshapiro							else
330764562Sgshapiro								syserr("421 4.0.0 Error getting LDAP values in map %s",
330864562Sgshapiro								       map->map_mname);
330964562Sgshapiro						}
331064562Sgshapiro						*statp = EX_TEMPFAIL;
331164562Sgshapiro# if USING_NETSCAPE_LDAP
331264562Sgshapiro						ldap_mem_free(attr);
331364562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
331464562Sgshapiro						if (lmap->ldap_res != NULL)
331564562Sgshapiro						{
331664562Sgshapiro							ldap_msgfree(lmap->ldap_res);
331764562Sgshapiro							lmap->ldap_res = NULL;
331864562Sgshapiro						}
331964562Sgshapiro						(void) ldap_abandon(lmap->ldap_ld,
332064562Sgshapiro								    msgid);
332164562Sgshapiro						if (vp != NULL)
332264562Sgshapiro							free(vp);
332364562Sgshapiro						return NULL;
332464562Sgshapiro					}
332564562Sgshapiro				}
332664562Sgshapiro
332764562Sgshapiro				*statp = EX_OK;
332864562Sgshapiro
332964562Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
333064562Sgshapiro				/*
333164562Sgshapiro				**  Reset value to prevent lingering
333264562Sgshapiro				**  LDAP_DECODING_ERROR due to
333364562Sgshapiro				**  OpenLDAP 1.X's hack (see below)
333464562Sgshapiro				*/
333564562Sgshapiro
333664562Sgshapiro				lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
333764562Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
333864562Sgshapiro
333964562Sgshapiro				/*
334064562Sgshapiro				**  If matching only,
334164562Sgshapiro				**  no need to spin through entries
334264562Sgshapiro				*/
334364562Sgshapiro
334464562Sgshapiro				if (bitset(MF_MATCHONLY, map->map_mflags))
334564562Sgshapiro					continue;
334664562Sgshapiro
334764562Sgshapiro				/*
334864562Sgshapiro				**  If we don't want multiple values,
334964562Sgshapiro				**  return first found.
335064562Sgshapiro				*/
335164562Sgshapiro
335264562Sgshapiro				if (map->map_coldelim == '\0')
335364562Sgshapiro				{
335464562Sgshapiro					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
335564562Sgshapiro					{
335664562Sgshapiro						vp = newstr(attr);
335764562Sgshapiro# if USING_NETSCAPE_LDAP
335864562Sgshapiro						ldap_mem_free(attr);
335964562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
336064562Sgshapiro						break;
336164562Sgshapiro					}
336264562Sgshapiro
336364562Sgshapiro					if (vals[0] == NULL)
336464562Sgshapiro					{
336564562Sgshapiro						ldap_value_free(vals);
336664562Sgshapiro# if USING_NETSCAPE_LDAP
336764562Sgshapiro						ldap_mem_free(attr);
336864562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
336964562Sgshapiro						continue;
337064562Sgshapiro					}
337164562Sgshapiro
337264562Sgshapiro					vp = newstr(vals[0]);
337364562Sgshapiro					ldap_value_free(vals);
337464562Sgshapiro# if USING_NETSCAPE_LDAP
337564562Sgshapiro					ldap_mem_free(attr);
337664562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
337764562Sgshapiro					break;
337864562Sgshapiro				}
337964562Sgshapiro
338064562Sgshapiro				/* attributes only */
338164562Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
338264562Sgshapiro				{
338364562Sgshapiro					if (vp == NULL)
338464562Sgshapiro						vp = newstr(attr);
338564562Sgshapiro					else
338664562Sgshapiro					{
338764562Sgshapiro						vsize = strlen(vp) +
338864562Sgshapiro							strlen(attr) + 2;
338964562Sgshapiro						tmp = xalloc(vsize);
339064562Sgshapiro						snprintf(tmp, vsize, "%s%c%s",
339164562Sgshapiro							 vp, map->map_coldelim,
339264562Sgshapiro							 attr);
339364562Sgshapiro						free(vp);
339464562Sgshapiro						vp = tmp;
339564562Sgshapiro					}
339664562Sgshapiro# if USING_NETSCAPE_LDAP
339764562Sgshapiro					ldap_mem_free(attr);
339864562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
339964562Sgshapiro					continue;
340064562Sgshapiro				}
340164562Sgshapiro
340264562Sgshapiro				/*
340364562Sgshapiro				**  If there is more than one,
340464562Sgshapiro				**  munge then into a map_coldelim
340564562Sgshapiro				**  separated string
340664562Sgshapiro				*/
340764562Sgshapiro
340864562Sgshapiro				vsize = 0;
340964562Sgshapiro				for (i = 0; vals[i] != NULL; i++)
341064562Sgshapiro					vsize += strlen(vals[i]) + 1;
341164562Sgshapiro				vp_tmp = xalloc(vsize);
341264562Sgshapiro				*vp_tmp = '\0';
341364562Sgshapiro
341464562Sgshapiro				p = vp_tmp;
341564562Sgshapiro				for (i = 0; vals[i] != NULL; i++)
341664562Sgshapiro				{
341764562Sgshapiro					p += strlcpy(p, vals[i],
341864562Sgshapiro						     vsize - (p - vp_tmp));
341964562Sgshapiro					if (p >= vp_tmp + vsize)
342064562Sgshapiro						syserr("ldapmap_lookup: Internal error: buffer too small for LDAP values");
342164562Sgshapiro					if (vals[i + 1] != NULL)
342264562Sgshapiro						*p++ = map->map_coldelim;
342364562Sgshapiro				}
342464562Sgshapiro
342564562Sgshapiro				ldap_value_free(vals);
342664562Sgshapiro# if USING_NETSCAPE_LDAP
342764562Sgshapiro				ldap_mem_free(attr);
342864562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
342964562Sgshapiro				if (vp == NULL)
343064562Sgshapiro				{
343164562Sgshapiro					vp = vp_tmp;
343264562Sgshapiro					continue;
343364562Sgshapiro				}
343464562Sgshapiro				vsize = strlen(vp) + strlen(vp_tmp) + 2;
343564562Sgshapiro				tmp = xalloc(vsize);
343664562Sgshapiro				snprintf(tmp, vsize, "%s%c%s",
343764562Sgshapiro					 vp, map->map_coldelim, vp_tmp);
343864562Sgshapiro
343964562Sgshapiro				free(vp);
344064562Sgshapiro				free(vp_tmp);
344164562Sgshapiro				vp = tmp;
344264562Sgshapiro			}
344364562Sgshapiro			errno = ldapmap_geterrno(lmap->ldap_ld);
344464562Sgshapiro
344564562Sgshapiro			/*
344664562Sgshapiro			**  We check errno != LDAP_DECODING_ERROR since
344764562Sgshapiro			**  OpenLDAP 1.X has a very ugly *undocumented*
344864562Sgshapiro			**  hack of returning this error code from
344964562Sgshapiro			**  ldap_next_attribute() if the library freed the
345064562Sgshapiro			**  ber attribute.  See:
345164562Sgshapiro			**  http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
345264562Sgshapiro			*/
345364562Sgshapiro
345464562Sgshapiro			if (errno != LDAP_SUCCESS &&
345564562Sgshapiro			    errno != LDAP_DECODING_ERROR)
345664562Sgshapiro			{
345764562Sgshapiro				/* Must be an error */
345864562Sgshapiro				errno += E_LDAPBASE;
345964562Sgshapiro				if (!bitset(MF_OPTIONAL, map->map_mflags))
346064562Sgshapiro				{
346164562Sgshapiro					if (bitset(MF_NODEFER, map->map_mflags))
346264562Sgshapiro						syserr("Error getting LDAP attributes in map %s",
346364562Sgshapiro						       map->map_mname);
346464562Sgshapiro					else
346564562Sgshapiro						syserr("421 4.0.0 Error getting LDAP attributes in map %s",
346664562Sgshapiro						       map->map_mname);
346764562Sgshapiro				}
346864562Sgshapiro				*statp = EX_TEMPFAIL;
346964562Sgshapiro				if (lmap->ldap_res != NULL)
347064562Sgshapiro				{
347164562Sgshapiro					ldap_msgfree(lmap->ldap_res);
347264562Sgshapiro					lmap->ldap_res = NULL;
347364562Sgshapiro				}
347464562Sgshapiro				(void) ldap_abandon(lmap->ldap_ld, msgid);
347564562Sgshapiro				if (vp != NULL)
347664562Sgshapiro					free(vp);
347764562Sgshapiro				return NULL;
347864562Sgshapiro			}
347964562Sgshapiro
348064562Sgshapiro			/* We don't want multiple values and we have one */
348164562Sgshapiro			if (map->map_coldelim == '\0' && vp != NULL)
348264562Sgshapiro				break;
348364562Sgshapiro		}
348464562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld);
348564562Sgshapiro		if (errno != LDAP_SUCCESS && errno != LDAP_DECODING_ERROR)
348664562Sgshapiro		{
348764562Sgshapiro			/* Must be an error */
348864562Sgshapiro			errno += E_LDAPBASE;
348938032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
349038032Speter			{
349164562Sgshapiro				if (bitset(MF_NODEFER, map->map_mflags))
349264562Sgshapiro					syserr("Error getting LDAP entries in map %s",
349364562Sgshapiro					       map->map_mname);
349464562Sgshapiro				else
349564562Sgshapiro					syserr("421 4.0.0 Error getting LDAP entries in map %s",
349664562Sgshapiro					       map->map_mname);
349738032Speter			}
349838032Speter			*statp = EX_TEMPFAIL;
349964562Sgshapiro			if (lmap->ldap_res != NULL)
350064562Sgshapiro			{
350164562Sgshapiro				ldap_msgfree(lmap->ldap_res);
350264562Sgshapiro				lmap->ldap_res = NULL;
350364562Sgshapiro			}
350464562Sgshapiro			(void) ldap_abandon(lmap->ldap_ld, msgid);
350564562Sgshapiro			if (vp != NULL)
350664562Sgshapiro				free(vp);
350764562Sgshapiro			return NULL;
350838032Speter		}
350964562Sgshapiro		ldap_msgfree(lmap->ldap_res);
351064562Sgshapiro		lmap->ldap_res = NULL;
351138032Speter	}
351238032Speter
351364562Sgshapiro	/*
351464562Sgshapiro	**  If grabbing all results at once for MF_NOREWRITE and
351564562Sgshapiro	**  only want a single match, make sure that's all we have
351664562Sgshapiro	*/
351764562Sgshapiro
351864562Sgshapiro	if (ret == LDAP_RES_SEARCH_RESULT &&
351964562Sgshapiro	    bitset(MF_NOREWRITE|MF_SINGLEMATCH, map->map_mflags))
352038032Speter	{
352164562Sgshapiro		entries += ldap_count_entries(lmap->ldap_ld, lmap->ldap_res);
352264562Sgshapiro		if (entries > 1)
352364562Sgshapiro		{
352464562Sgshapiro			*statp = EX_NOTFOUND;
352564562Sgshapiro			if (lmap->ldap_res != NULL)
352664562Sgshapiro			{
352764562Sgshapiro				ldap_msgfree(lmap->ldap_res);
352864562Sgshapiro				lmap->ldap_res = NULL;
352964562Sgshapiro			}
353064562Sgshapiro			if (vp != NULL)
353164562Sgshapiro				free(vp);
353264562Sgshapiro			return NULL;
353364562Sgshapiro		}
353464562Sgshapiro		*statp = EX_OK;
353538032Speter	}
353638032Speter
353764562Sgshapiro	if (ret == 0)
353864562Sgshapiro		errno = ETIMEDOUT;
353964562Sgshapiro	else
354064562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld);
354164562Sgshapiro	if (errno != LDAP_SUCCESS)
354238032Speter	{
354364562Sgshapiro		/* Must be an error */
354464562Sgshapiro		if (ret != 0)
354564562Sgshapiro			errno += E_LDAPBASE;
354664562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
354764562Sgshapiro		{
354864562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
354964562Sgshapiro				syserr("Error getting LDAP results in map %s",
355064562Sgshapiro				       map->map_mname);
355164562Sgshapiro			else
355264562Sgshapiro				syserr("421 4.0.0 Error getting LDAP results in map %s",
355364562Sgshapiro				       map->map_mname);
355464562Sgshapiro		}
355564562Sgshapiro		*statp = EX_TEMPFAIL;
355664562Sgshapiro		if (vp != NULL)
355764562Sgshapiro			free(vp);
355864562Sgshapiro		return NULL;
355938032Speter	}
356038032Speter
356164562Sgshapiro	/* Did we match anything? */
356264562Sgshapiro	if (vp == NULL)
356364562Sgshapiro		return NULL;
356438032Speter
356564562Sgshapiro	/*
356664562Sgshapiro	**  If MF_NOREWRITE, we are special map which doesn't
356764562Sgshapiro	**  actually return a map value.  Instead, we don't free
356864562Sgshapiro	**  ldap_res and let the calling function process the LDAP
356964562Sgshapiro	**  results.  The caller should ldap_msgfree(lmap->ldap_res).
357064562Sgshapiro	*/
357138032Speter
357264562Sgshapiro	if (bitset(MF_NOREWRITE, map->map_mflags))
357364562Sgshapiro	{
357464562Sgshapiro		/* vp != NULL due to test above */
357564562Sgshapiro		free(vp);
357664562Sgshapiro		return "";
357764562Sgshapiro	}
357838032Speter
357964562Sgshapiro	if (*statp == EX_OK)
358064562Sgshapiro	{
358164562Sgshapiro		/* vp != NULL due to test above */
358264562Sgshapiro		if (LogLevel > 9)
358364562Sgshapiro			sm_syslog(LOG_INFO, CurEnv->e_id,
358464562Sgshapiro				  "ldap %.100s => %s", name, vp);
358564562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
358664562Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
358764562Sgshapiro		else
358864562Sgshapiro			result = map_rewrite(map, vp, strlen(vp), av);
358964562Sgshapiro		free(vp);
359064562Sgshapiro	}
359164562Sgshapiro	return result;
359238032Speter}
359338032Speter
359438032Speter/*
359564562Sgshapiro**  LDAPMAP_FINDCONN -- find an LDAP connection to the server
359664562Sgshapiro**
359764562Sgshapiro**	Cache LDAP connections based on the host, port, bind DN,
359864562Sgshapiro**	and secret so we don't have multiple connections open to
359964562Sgshapiro**	the same server for different maps.
360064562Sgshapiro**
360164562Sgshapiro**	Parameters:
360264562Sgshapiro**		lmap -- LDAP map information
360364562Sgshapiro**
360464562Sgshapiro**	Returns:
360564562Sgshapiro**		Symbol table entry for the LDAP connection.
360664562Sgshapiro**
360738032Speter*/
360838032Speter
360964562Sgshapirostatic STAB *
361064562Sgshapiroldapmap_findconn(lmap)
361164562Sgshapiro	LDAPMAP_STRUCT *lmap;
361238032Speter{
361364562Sgshapiro	int len;
361464562Sgshapiro	char *nbuf;
361564562Sgshapiro	STAB *s;
361638032Speter
361764562Sgshapiro	len = (lmap->ldap_host == NULL ? strlen("localhost") :
361864562Sgshapiro					 strlen(lmap->ldap_host)) + 1 + 8 + 1 +
361964562Sgshapiro		(lmap->ldap_binddn == NULL ? 0 : strlen(lmap->ldap_binddn)) +
362064562Sgshapiro		1 +
362164562Sgshapiro		(lmap->ldap_secret == NULL ? 0 : strlen(lmap->ldap_secret)) +
362264562Sgshapiro		1;
362364562Sgshapiro	nbuf = xalloc(len);
362464562Sgshapiro	snprintf(nbuf, len, "%s%c%d%c%s%c%s",
362564562Sgshapiro		 (lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host),
362664562Sgshapiro		 CONDELSE,
362764562Sgshapiro		 lmap->ldap_port,
362864562Sgshapiro		 CONDELSE,
362964562Sgshapiro		 (lmap->ldap_binddn == NULL ? "" : lmap->ldap_binddn),
363064562Sgshapiro		 CONDELSE,
363164562Sgshapiro		 (lmap->ldap_secret == NULL ? "" : lmap->ldap_secret));
363264562Sgshapiro	s = stab(nbuf, ST_LDAP, ST_ENTER);
363364562Sgshapiro	free(nbuf);
363464562Sgshapiro	return s;
363564562Sgshapiro}
363664562Sgshapiro/*
363764562Sgshapiro**  LDAPMAP_SETOPTS -- set LDAP options
363864562Sgshapiro**
363964562Sgshapiro**	Parameters:
364064562Sgshapiro**		ld -- LDAP session handle
364164562Sgshapiro**		lmap -- LDAP map information
364264562Sgshapiro**
364364562Sgshapiro**	Returns:
364464562Sgshapiro**		None.
364564562Sgshapiro**
364664562Sgshapiro*/
364764562Sgshapiro
364864562Sgshapirostatic void
364964562Sgshapiroldapmap_setopts(ld, lmap)
365064562Sgshapiro	LDAP *ld;
365164562Sgshapiro	LDAPMAP_STRUCT *lmap;
365264562Sgshapiro{
365364562Sgshapiro# if USE_LDAP_SET_OPTION
365464562Sgshapiro	ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
365564562Sgshapiro	if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
365664562Sgshapiro		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
365738032Speter	else
365864562Sgshapiro		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
365964562Sgshapiro	ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
366064562Sgshapiro	ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
366164562Sgshapiro# else /* USE_LDAP_SET_OPTION */
366264562Sgshapiro	/* From here on in we can use ldap internal timelimits */
366364562Sgshapiro	ld->ld_deref = lmap->ldap_deref;
366464562Sgshapiro	ld->ld_options = lmap->ldap_options;
366564562Sgshapiro	ld->ld_sizelimit = lmap->ldap_sizelimit;
366664562Sgshapiro	ld->ld_timelimit = lmap->ldap_timelimit;
366764562Sgshapiro# endif /* USE_LDAP_SET_OPTION */
366838032Speter}
366964562Sgshapiro/*
367064562Sgshapiro**  LDAPMAP_GETERRNO -- get ldap errno value
367164562Sgshapiro**
367264562Sgshapiro**	Parameters:
367364562Sgshapiro**		ld -- LDAP session handle
367464562Sgshapiro**
367564562Sgshapiro**	Returns:
367664562Sgshapiro**		LDAP errno.
367764562Sgshapiro**
367864562Sgshapiro*/
367938032Speter
368064562Sgshapirostatic int
368164562Sgshapiroldapmap_geterrno(ld)
368264562Sgshapiro	LDAP *ld;
368364562Sgshapiro{
368464562Sgshapiro	int err = LDAP_SUCCESS;
368564562Sgshapiro
368664562Sgshapiro# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
368764562Sgshapiro	(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
368864562Sgshapiro# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
368964562Sgshapiro#  ifdef LDAP_OPT_SIZELIMIT
369064562Sgshapiro	err = ldap_get_lderrno(ld, NULL, NULL);
369164562Sgshapiro#  else /* LDAP_OPT_SIZELIMIT */
369264562Sgshapiro	err = ld->ld_errno;
369364562Sgshapiro
369464562Sgshapiro	/*
369564562Sgshapiro	**  Reset value to prevent lingering LDAP_DECODING_ERROR due to
369664562Sgshapiro	**  OpenLDAP 1.X's hack (see above)
369764562Sgshapiro	*/
369864562Sgshapiro
369964562Sgshapiro	ld->ld_errno = LDAP_SUCCESS;
370064562Sgshapiro#  endif /* LDAP_OPT_SIZELIMIT */
370164562Sgshapiro# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
370264562Sgshapiro	return err;
370364562Sgshapiro}
370464562Sgshapiro
370538032Speter/*
370664562Sgshapiro**  LDAPX_MAP_PARSEARGS -- print warning about use of ldapx map.
370738032Speter*/
370838032Speter
370938032Speterbool
371064562Sgshapiroldapx_map_parseargs(map, args)
371138032Speter	MAP *map;
371238032Speter	char *args;
371338032Speter{
371464562Sgshapiro	printf("Warning: The \"ldapx\" map class is deprecated and will be removed in a future\n");
371564562Sgshapiro	printf("         version.  Use the \"ldap\" map class instead for map \"%s\".\n",
371664562Sgshapiro	       map->map_mname);
371764562Sgshapiro	return ldapmap_parseargs(map, args);
371864562Sgshapiro}
371938032Speter
372064562Sgshapiro/*
372164562Sgshapiro**  LDAPMAP_PARSEARGS -- parse ldap map definition args.
372264562Sgshapiro*/
372338032Speter
372464562Sgshapirostruct lamvalues LDAPAuthMethods[] =
372564562Sgshapiro{
372664562Sgshapiro	{	"none",		LDAP_AUTH_NONE		},
372764562Sgshapiro	{	"simple",	LDAP_AUTH_SIMPLE	},
372864562Sgshapiro# ifdef LDAP_AUTH_KRBV4
372964562Sgshapiro	{	"krbv4",	LDAP_AUTH_KRBV4		},
373064562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
373164562Sgshapiro	{	NULL,		0			}
373264562Sgshapiro};
373338032Speter
373464562Sgshapirostruct ladvalues LDAPAliasDereference[] =
373564562Sgshapiro{
373664562Sgshapiro	{	"never",	LDAP_DEREF_NEVER	},
373764562Sgshapiro	{	"always",	LDAP_DEREF_ALWAYS	},
373864562Sgshapiro	{	"search",	LDAP_DEREF_SEARCHING	},
373964562Sgshapiro	{	"find",		LDAP_DEREF_FINDING	},
374064562Sgshapiro	{	NULL,		0			}
374164562Sgshapiro};
374238032Speter
374364562Sgshapirostruct lssvalues LDAPSearchScope[] =
374464562Sgshapiro{
374564562Sgshapiro	{	"base",		LDAP_SCOPE_BASE		},
374664562Sgshapiro	{	"one",		LDAP_SCOPE_ONELEVEL	},
374764562Sgshapiro	{	"sub",		LDAP_SCOPE_SUBTREE	},
374864562Sgshapiro	{	NULL,		0			}
374964562Sgshapiro};
375038032Speter
375164562Sgshapirobool
375264562Sgshapiroldapmap_parseargs(map, args)
375364562Sgshapiro	MAP *map;
375464562Sgshapiro	char *args;
375564562Sgshapiro{
375664562Sgshapiro	bool secretread = TRUE;
375764562Sgshapiro	int i;
375864562Sgshapiro	register char *p = args;
375964562Sgshapiro	LDAPMAP_STRUCT *lmap;
376064562Sgshapiro	struct lamvalues *lam;
376164562Sgshapiro	struct ladvalues *lad;
376264562Sgshapiro	struct lssvalues *lss;
376364562Sgshapiro	char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
376464562Sgshapiro
376564562Sgshapiro	/* Get ldap struct pointer from map */
376664562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
376764562Sgshapiro
376864562Sgshapiro	/* Check if setting the initial LDAP defaults */
376964562Sgshapiro	if (lmap == NULL || lmap != LDAPDefaults)
377064562Sgshapiro	{
377164562Sgshapiro		/* We need to alloc an LDAPMAP_STRUCT struct */
377264562Sgshapiro		lmap = (LDAPMAP_STRUCT *) xalloc(sizeof *lmap);
377364562Sgshapiro		if (LDAPDefaults == NULL)
377464562Sgshapiro			ldapmap_clear(lmap);
377564562Sgshapiro		else
377664562Sgshapiro			STRUCTCOPY(*LDAPDefaults, *lmap);
377764562Sgshapiro	}
377864562Sgshapiro
377964562Sgshapiro	/* there is no check whether there is really an argument */
378064562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
378164562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
378238032Speter	for (;;)
378338032Speter	{
378438032Speter		while (isascii(*p) && isspace(*p))
378538032Speter			p++;
378638032Speter		if (*p != '-')
378738032Speter			break;
378838032Speter		switch (*++p)
378938032Speter		{
379038032Speter		  case 'N':
379138032Speter			map->map_mflags |= MF_INCLNULL;
379238032Speter			map->map_mflags &= ~MF_TRY0NULL;
379338032Speter			break;
379438032Speter
379538032Speter		  case 'O':
379638032Speter			map->map_mflags &= ~MF_TRY1NULL;
379738032Speter			break;
379838032Speter
379938032Speter		  case 'o':
380038032Speter			map->map_mflags |= MF_OPTIONAL;
380138032Speter			break;
380238032Speter
380338032Speter		  case 'f':
380438032Speter			map->map_mflags |= MF_NOFOLDCASE;
380538032Speter			break;
380638032Speter
380738032Speter		  case 'm':
380838032Speter			map->map_mflags |= MF_MATCHONLY;
380938032Speter			break;
381038032Speter
381138032Speter		  case 'A':
381238032Speter			map->map_mflags |= MF_APPEND;
381338032Speter			break;
381438032Speter
381538032Speter		  case 'q':
381638032Speter			map->map_mflags |= MF_KEEPQUOTES;
381738032Speter			break;
381838032Speter
381938032Speter		  case 'a':
382038032Speter			map->map_app = ++p;
382138032Speter			break;
382238032Speter
382338032Speter		  case 'T':
382438032Speter			map->map_tapp = ++p;
382538032Speter			break;
382638032Speter
382764562Sgshapiro		  case 't':
382864562Sgshapiro			map->map_mflags |= MF_NODEFER;
382964562Sgshapiro			break;
383064562Sgshapiro
383164562Sgshapiro		  case 'S':
383264562Sgshapiro			map->map_spacesub = *++p;
383364562Sgshapiro			break;
383464562Sgshapiro
383564562Sgshapiro		  case 'D':
383664562Sgshapiro			map->map_mflags |= MF_DEFER;
383764562Sgshapiro			break;
383864562Sgshapiro
383964562Sgshapiro		  case 'z':
384064562Sgshapiro			if (*++p != '\\')
384164562Sgshapiro				map->map_coldelim = *p;
384264562Sgshapiro			else
384364562Sgshapiro			{
384464562Sgshapiro				switch (*++p)
384564562Sgshapiro				{
384664562Sgshapiro				  case 'n':
384764562Sgshapiro					map->map_coldelim = '\n';
384864562Sgshapiro					break;
384964562Sgshapiro
385064562Sgshapiro				  case 't':
385164562Sgshapiro					map->map_coldelim = '\t';
385264562Sgshapiro					break;
385364562Sgshapiro
385464562Sgshapiro				  default:
385564562Sgshapiro					map->map_coldelim = '\\';
385664562Sgshapiro				}
385764562Sgshapiro			}
385864562Sgshapiro			break;
385964562Sgshapiro
386064562Sgshapiro			/* Start of ldapmap specific args */
386138032Speter		  case 'k':		/* search field */
386238032Speter			while (isascii(*++p) && isspace(*p))
386338032Speter				continue;
386464562Sgshapiro			lmap->ldap_filter = p;
386538032Speter			break;
386638032Speter
386738032Speter		  case 'v':		/* attr to return */
386838032Speter			while (isascii(*++p) && isspace(*p))
386938032Speter				continue;
387064562Sgshapiro			lmap->ldap_attr[0] = p;
387164562Sgshapiro			lmap->ldap_attr[1] = NULL;
387238032Speter			break;
387338032Speter
387464562Sgshapiro		  case '1':
387564562Sgshapiro			map->map_mflags |= MF_SINGLEMATCH;
387664562Sgshapiro			break;
387764562Sgshapiro
387838032Speter			/* args stolen from ldapsearch.c */
387938032Speter		  case 'R':		/* don't auto chase referrals */
388064562Sgshapiro# ifdef LDAP_REFERRALS
388138032Speter			lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
388264562Sgshapiro# else /* LDAP_REFERRALS */
388338032Speter			syserr("compile with -DLDAP_REFERRALS for referral support\n");
388464562Sgshapiro# endif /* LDAP_REFERRALS */
388538032Speter			break;
388638032Speter
388764562Sgshapiro		  case 'n':		/* retrieve attribute names only */
388864562Sgshapiro			lmap->ldap_attrsonly = LDAPMAP_TRUE;
388938032Speter			break;
389038032Speter
389164562Sgshapiro		  case 'r':		/* alias dereferencing */
389264562Sgshapiro			while (isascii(*++p) && isspace(*p))
389364562Sgshapiro				continue;
389464562Sgshapiro
389564562Sgshapiro			if (strncasecmp(p, "LDAP_DEREF_", 11) == 0)
389664562Sgshapiro				p += 11;
389764562Sgshapiro
389864562Sgshapiro			for (lad = LDAPAliasDereference;
389964562Sgshapiro			     lad != NULL && lad->lad_name != NULL; lad++)
390038032Speter			{
390164562Sgshapiro				if (strncasecmp(p, lad->lad_name,
390264562Sgshapiro						strlen(lad->lad_name)) == 0)
390364562Sgshapiro					break;
390438032Speter			}
390564562Sgshapiro			if (lad->lad_name != NULL)
390664562Sgshapiro				lmap->ldap_deref = lad->lad_code;
390764562Sgshapiro			else
390838032Speter			{
390964562Sgshapiro				/* bad config line */
391064562Sgshapiro				if (!bitset(MCF_OPTFILE,
391164562Sgshapiro					    map->map_class->map_cflags))
391264562Sgshapiro				{
391364562Sgshapiro					char *ptr;
391464562Sgshapiro
391564562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
391664562Sgshapiro						*ptr = '\0';
391764562Sgshapiro					syserr("Deref must be [never|always|search|find] not %s in map %s",
391864562Sgshapiro						p, map->map_mname);
391964562Sgshapiro					if (ptr != NULL)
392064562Sgshapiro						*ptr = ' ';
392164562Sgshapiro					return FALSE;
392264562Sgshapiro				}
392338032Speter			}
392464562Sgshapiro			break;
392564562Sgshapiro
392664562Sgshapiro		  case 's':		/* search scope */
392764562Sgshapiro			while (isascii(*++p) && isspace(*p))
392864562Sgshapiro				continue;
392964562Sgshapiro
393064562Sgshapiro			if (strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
393164562Sgshapiro				p += 11;
393264562Sgshapiro
393364562Sgshapiro			for (lss = LDAPSearchScope;
393464562Sgshapiro			     lss != NULL && lss->lss_name != NULL; lss++)
393538032Speter			{
393664562Sgshapiro				if (strncasecmp(p, lss->lss_name,
393764562Sgshapiro						strlen(lss->lss_name)) == 0)
393864562Sgshapiro					break;
393938032Speter			}
394064562Sgshapiro			if (lss->lss_name != NULL)
394164562Sgshapiro				lmap->ldap_scope = lss->lss_code;
394238032Speter			else
394364562Sgshapiro			{
394464562Sgshapiro				/* bad config line */
394564562Sgshapiro				if (!bitset(MCF_OPTFILE,
394664562Sgshapiro					    map->map_class->map_cflags))
394738032Speter				{
394838032Speter					char *ptr;
394938032Speter
395038032Speter					if ((ptr = strchr(p, ' ')) != NULL)
395138032Speter						*ptr = '\0';
395238032Speter					syserr("Scope must be [base|one|sub] not %s in map %s",
395338032Speter						p, map->map_mname);
395438032Speter					if (ptr != NULL)
395538032Speter						*ptr = ' ';
395638032Speter					return FALSE;
395738032Speter				}
395838032Speter			}
395938032Speter			break;
396038032Speter
396138032Speter		  case 'h':		/* ldap host */
396238032Speter			while (isascii(*++p) && isspace(*p))
396338032Speter				continue;
396464562Sgshapiro			lmap->ldap_host = p;
396538032Speter			break;
396638032Speter
396738032Speter		  case 'b':		/* search base */
396838032Speter			while (isascii(*++p) && isspace(*p))
396938032Speter				continue;
397064562Sgshapiro			lmap->ldap_base = p;
397138032Speter			break;
397238032Speter
397338032Speter		  case 'p':		/* ldap port */
397438032Speter			while (isascii(*++p) && isspace(*p))
397538032Speter				continue;
397664562Sgshapiro			lmap->ldap_port = atoi(p);
397738032Speter			break;
397838032Speter
397938032Speter		  case 'l':		/* time limit */
398038032Speter			while (isascii(*++p) && isspace(*p))
398138032Speter				continue;
398264562Sgshapiro			lmap->ldap_timelimit = atoi(p);
398364562Sgshapiro			lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit;
398438032Speter			break;
398538032Speter
398664562Sgshapiro		  case 'Z':
398764562Sgshapiro			while (isascii(*++p) && isspace(*p))
398864562Sgshapiro				continue;
398964562Sgshapiro			lmap->ldap_sizelimit = atoi(p);
399064562Sgshapiro			break;
399164562Sgshapiro
399264562Sgshapiro		  case 'd':		/* Dn to bind to server as */
399364562Sgshapiro			while (isascii(*++p) && isspace(*p))
399464562Sgshapiro				continue;
399564562Sgshapiro			lmap->ldap_binddn = p;
399664562Sgshapiro			break;
399764562Sgshapiro
399864562Sgshapiro		  case 'M':		/* Method for binding */
399964562Sgshapiro			while (isascii(*++p) && isspace(*p))
400064562Sgshapiro				continue;
400164562Sgshapiro
400264562Sgshapiro			if (strncasecmp(p, "LDAP_AUTH_", 10) == 0)
400364562Sgshapiro				p += 10;
400464562Sgshapiro
400564562Sgshapiro			for (lam = LDAPAuthMethods;
400664562Sgshapiro			     lam != NULL && lam->lam_name != NULL; lam++)
400764562Sgshapiro			{
400864562Sgshapiro				if (strncasecmp(p, lam->lam_name,
400964562Sgshapiro						strlen(lam->lam_name)) == 0)
401064562Sgshapiro					break;
401164562Sgshapiro			}
401264562Sgshapiro			if (lam->lam_name != NULL)
401364562Sgshapiro				lmap->ldap_method = lam->lam_code;
401464562Sgshapiro			else
401564562Sgshapiro			{
401664562Sgshapiro				/* bad config line */
401764562Sgshapiro				if (!bitset(MCF_OPTFILE,
401864562Sgshapiro					    map->map_class->map_cflags))
401964562Sgshapiro				{
402064562Sgshapiro					char *ptr;
402164562Sgshapiro
402264562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
402364562Sgshapiro						*ptr = '\0';
402464562Sgshapiro					syserr("Method for binding must be [none|simple|krbv4] not %s in map %s",
402564562Sgshapiro						p, map->map_mname);
402664562Sgshapiro					if (ptr != NULL)
402764562Sgshapiro						*ptr = ' ';
402864562Sgshapiro					return FALSE;
402964562Sgshapiro				}
403064562Sgshapiro			}
403164562Sgshapiro
403264562Sgshapiro			break;
403364562Sgshapiro
403464562Sgshapiro			/*
403564562Sgshapiro			**  This is a string that is dependent on the
403664562Sgshapiro			**  method used defined above.
403764562Sgshapiro			*/
403864562Sgshapiro
403964562Sgshapiro		  case 'P':		/* Secret password for binding */
404064562Sgshapiro			 while (isascii(*++p) && isspace(*p))
404164562Sgshapiro				continue;
404264562Sgshapiro			lmap->ldap_secret = p;
404364562Sgshapiro			secretread = FALSE;
404464562Sgshapiro			break;
404564562Sgshapiro
404664562Sgshapiro		  default:
404764562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
404864562Sgshapiro			break;
404938032Speter		}
405038032Speter
405164562Sgshapiro		/* need to account for quoted strings here */
405264562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
405338032Speter		{
405438032Speter			if (*p == '"')
405538032Speter			{
405638032Speter				while (*++p != '"' && *p != '\0')
405738032Speter					continue;
405838032Speter				if (*p != '\0')
405938032Speter					p++;
406038032Speter			}
406138032Speter			else
406238032Speter				p++;
406338032Speter		}
406438032Speter
406538032Speter		if (*p != '\0')
406638032Speter			*p++ = '\0';
406738032Speter	}
406838032Speter
406938032Speter	if (map->map_app != NULL)
407064562Sgshapiro		map->map_app = newstr(ldapmap_dequote(map->map_app));
407138032Speter	if (map->map_tapp != NULL)
407264562Sgshapiro		map->map_tapp = newstr(ldapmap_dequote(map->map_tapp));
407338032Speter
407438032Speter	/*
407542575Speter	**  We need to swallow up all the stuff into a struct
407642575Speter	**  and dump it into map->map_dbptr1
407738032Speter	*/
407838032Speter
407964562Sgshapiro	if (lmap->ldap_host != NULL &&
408064562Sgshapiro	    (LDAPDefaults == NULL ||
408164562Sgshapiro	     LDAPDefaults == lmap ||
408264562Sgshapiro	     LDAPDefaults->ldap_host != lmap->ldap_host))
408364562Sgshapiro		lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host));
408464562Sgshapiro	map->map_domain = lmap->ldap_host;
408564562Sgshapiro
408664562Sgshapiro	if (lmap->ldap_binddn != NULL &&
408764562Sgshapiro	    (LDAPDefaults == NULL ||
408864562Sgshapiro	     LDAPDefaults == lmap ||
408964562Sgshapiro	     LDAPDefaults->ldap_binddn != lmap->ldap_binddn))
409064562Sgshapiro		lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn));
409164562Sgshapiro
409264562Sgshapiro	if (lmap->ldap_secret != NULL &&
409364562Sgshapiro	    (LDAPDefaults == NULL ||
409464562Sgshapiro	     LDAPDefaults == lmap ||
409564562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
409638032Speter	{
409764562Sgshapiro		FILE *sfd;
409864562Sgshapiro		long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
409938032Speter
410064562Sgshapiro		if (DontLockReadFiles)
410164562Sgshapiro			sff |= SFF_NOLOCK;
410238032Speter
410364562Sgshapiro		/* need to use method to map secret to passwd string */
410464562Sgshapiro		switch (lmap->ldap_method)
410564562Sgshapiro		{
410664562Sgshapiro		  case LDAP_AUTH_NONE:
410764562Sgshapiro			/* Do nothing */
410864562Sgshapiro			break;
410938032Speter
411064562Sgshapiro		  case LDAP_AUTH_SIMPLE:
411138032Speter
411264562Sgshapiro			/*
411364562Sgshapiro			**  Secret is the name of a file with
411464562Sgshapiro			**  the first line as the password.
411564562Sgshapiro			*/
411664562Sgshapiro
411764562Sgshapiro			/* Already read in the secret? */
411864562Sgshapiro			if (secretread)
411964562Sgshapiro				break;
412064562Sgshapiro
412164562Sgshapiro			sfd = safefopen(ldapmap_dequote(lmap->ldap_secret),
412264562Sgshapiro					O_RDONLY, 0, sff);
412364562Sgshapiro			if (sfd == NULL)
412464562Sgshapiro			{
412564562Sgshapiro				syserr("LDAP map: cannot open secret %s",
412664562Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
412764562Sgshapiro				return FALSE;
412864562Sgshapiro			}
412964562Sgshapiro			lmap->ldap_secret = sfgets(m_tmp, LDAPMAP_MAX_PASSWD,
413064562Sgshapiro						   sfd, 0, "ldapmap_parseargs");
413164562Sgshapiro			(void) fclose(sfd);
413264562Sgshapiro			if (lmap->ldap_secret != NULL &&
413364562Sgshapiro			    strlen(m_tmp) > 0)
413464562Sgshapiro			{
413564562Sgshapiro				/* chomp newline */
413664562Sgshapiro				if (m_tmp[strlen(m_tmp) - 1] == '\n')
413764562Sgshapiro					m_tmp[strlen(m_tmp) - 1] = '\0';
413864562Sgshapiro
413964562Sgshapiro				lmap->ldap_secret = m_tmp;
414064562Sgshapiro			}
414164562Sgshapiro			break;
414264562Sgshapiro
414364562Sgshapiro# ifdef LDAP_AUTH_KRBV4
414464562Sgshapiro		  case LDAP_AUTH_KRBV4:
414564562Sgshapiro
414664562Sgshapiro			/*
414764562Sgshapiro			**  Secret is where the ticket file is
414864562Sgshapiro			**  stashed
414964562Sgshapiro			*/
415064562Sgshapiro
415164562Sgshapiro			snprintf(m_tmp, MAXPATHLEN + LDAPMAP_MAX_PASSWD,
415264562Sgshapiro				 "KRBTKFILE=%s",
415364562Sgshapiro				 ldapmap_dequote(lmap->ldap_secret));
415464562Sgshapiro			lmap->ldap_secret = m_tmp;
415564562Sgshapiro			break;
415664562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
415764562Sgshapiro
415864562Sgshapiro		  default:	       /* Should NEVER get here */
415964562Sgshapiro			syserr("LDAP map: Illegal value in lmap method");
416064562Sgshapiro			return FALSE;
416164562Sgshapiro			break;
416264562Sgshapiro		}
416338032Speter	}
416438032Speter
416564562Sgshapiro	if (lmap->ldap_secret != NULL &&
416664562Sgshapiro	    (LDAPDefaults == NULL ||
416764562Sgshapiro	     LDAPDefaults == lmap ||
416864562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
416964562Sgshapiro		lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret));
417038032Speter
417164562Sgshapiro	if (lmap->ldap_base != NULL &&
417264562Sgshapiro	    (LDAPDefaults == NULL ||
417364562Sgshapiro	     LDAPDefaults == lmap ||
417464562Sgshapiro	     LDAPDefaults->ldap_base != lmap->ldap_base))
417564562Sgshapiro		lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base));
417664562Sgshapiro
417764562Sgshapiro	/*
417864562Sgshapiro	**  Save the server from extra work.  If request is for a single
417964562Sgshapiro	**  match, tell the server to only return enough records to
418064562Sgshapiro	**  determine if there is a single match or not.  This can not
418164562Sgshapiro	**  be one since the server would only return one and we wouldn't
418264562Sgshapiro	**  know if there were others available.
418364562Sgshapiro	*/
418464562Sgshapiro
418564562Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
418664562Sgshapiro		lmap->ldap_sizelimit = 2;
418764562Sgshapiro
418864562Sgshapiro	/* If setting defaults, don't process ldap_filter and ldap_attr */
418964562Sgshapiro	if (lmap == LDAPDefaults)
419064562Sgshapiro		return TRUE;
419164562Sgshapiro
419264562Sgshapiro	if (lmap->ldap_filter != NULL)
419364562Sgshapiro		lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
419438032Speter	else
419538032Speter	{
419638032Speter		if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
419738032Speter		{
419838032Speter			syserr("No filter given in map %s", map->map_mname);
419938032Speter			return FALSE;
420038032Speter		}
420138032Speter	}
420264562Sgshapiro
420364562Sgshapiro	if (lmap->ldap_attr[0] != NULL)
420438032Speter	{
420564562Sgshapiro		i = 0;
420664562Sgshapiro		p = ldapmap_dequote(lmap->ldap_attr[0]);
420764562Sgshapiro		lmap->ldap_attr[0] = NULL;
420864562Sgshapiro
420964562Sgshapiro		while (p != NULL)
421038032Speter		{
421164562Sgshapiro			char *v;
421264562Sgshapiro
421364562Sgshapiro			while (isascii(*p) && isspace(*p))
421464562Sgshapiro				p++;
421564562Sgshapiro			if (*p == '\0')
421664562Sgshapiro				break;
421764562Sgshapiro			v = p;
421864562Sgshapiro			p = strchr(v, ',');
421964562Sgshapiro			if (p != NULL)
422064562Sgshapiro				*p++ = '\0';
422164562Sgshapiro
422264562Sgshapiro			if (i == LDAPMAP_MAX_ATTR)
422364562Sgshapiro			{
422464562Sgshapiro				syserr("Too many return attributes in %s (max %d)",
422564562Sgshapiro				       map->map_mname, LDAPMAP_MAX_ATTR);
422664562Sgshapiro				return FALSE;
422764562Sgshapiro			}
422864562Sgshapiro			if (*v != '\0')
422964562Sgshapiro				lmap->ldap_attr[i++] = newstr(v);
423038032Speter		}
423164562Sgshapiro		lmap->ldap_attr[i] = NULL;
423238032Speter	}
423338032Speter
423438032Speter	map->map_db1 = (ARBPTR_T) lmap;
423538032Speter	return TRUE;
423638032Speter}
423738032Speter
423864562Sgshapiro/*
423964562Sgshapiro**  LDAPMAP_CLEAR -- set default values for LDAPMAP_STRUCT
424064562Sgshapiro**
424164562Sgshapiro**	Parameters:
424264562Sgshapiro**		lmap -- pointer to LDAPMAP_STRUCT to clear
424364562Sgshapiro**
424464562Sgshapiro**	Returns:
424564562Sgshapiro**		None.
424664562Sgshapiro**
424764562Sgshapiro*/
424864562Sgshapiro
424964562Sgshapirostatic void
425064562Sgshapiroldapmap_clear(lmap)
425164562Sgshapiro	LDAPMAP_STRUCT *lmap;
425264562Sgshapiro{
425364562Sgshapiro	lmap->ldap_host = NULL;
425464562Sgshapiro	lmap->ldap_port = LDAP_PORT;
425564562Sgshapiro	lmap->ldap_deref = LDAP_DEREF_NEVER;
425664562Sgshapiro	lmap->ldap_timelimit = LDAP_NO_LIMIT;
425764562Sgshapiro	lmap->ldap_sizelimit = LDAP_NO_LIMIT;
425864562Sgshapiro# ifdef LDAP_REFERRALS
425964562Sgshapiro	lmap->ldap_options = LDAP_OPT_REFERRALS;
426064562Sgshapiro# else /* LDAP_REFERRALS */
426164562Sgshapiro	lmap->ldap_options = 0;
426264562Sgshapiro# endif /* LDAP_REFERRALS */
426364562Sgshapiro	lmap->ldap_binddn = NULL;
426464562Sgshapiro	lmap->ldap_secret = NULL;
426564562Sgshapiro	lmap->ldap_method = LDAP_AUTH_SIMPLE;
426664562Sgshapiro	lmap->ldap_base = NULL;
426764562Sgshapiro	lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
426864562Sgshapiro	lmap->ldap_attrsonly = LDAPMAP_FALSE;
426964562Sgshapiro	lmap->ldap_timeout.tv_sec = 0;
427064562Sgshapiro	lmap->ldap_timeout.tv_usec = 0;
427164562Sgshapiro	lmap->ldap_ld = NULL;
427264562Sgshapiro	lmap->ldap_filter = NULL;
427364562Sgshapiro	lmap->ldap_attr[0] = NULL;
427464562Sgshapiro	lmap->ldap_res = NULL;
427564562Sgshapiro}
427638032Speter/*
427764562Sgshapiro**  LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
427864562Sgshapiro**
427964562Sgshapiro**	Parameters:
428064562Sgshapiro**		spec -- map argument string from LDAPDefaults option
428164562Sgshapiro**
428264562Sgshapiro**	Returns:
428364562Sgshapiro**		None.
428464562Sgshapiro**
428564562Sgshapiro*/
428664562Sgshapiro
428764562Sgshapirovoid
428864562Sgshapiroldapmap_set_defaults(spec)
428964562Sgshapiro	char *spec;
429064562Sgshapiro{
429164562Sgshapiro	MAP map;
429264562Sgshapiro
429364562Sgshapiro	/* Allocate and set the default values */
429464562Sgshapiro	if (LDAPDefaults == NULL)
429564562Sgshapiro		LDAPDefaults = (LDAPMAP_STRUCT *) xalloc(sizeof *LDAPDefaults);
429664562Sgshapiro	ldapmap_clear(LDAPDefaults);
429764562Sgshapiro
429864562Sgshapiro	memset(&map, '\0', sizeof map);
429964562Sgshapiro	map.map_db1 = (ARBPTR_T) LDAPDefaults;
430064562Sgshapiro
430164562Sgshapiro	(void) ldapmap_parseargs(&map, spec);
430264562Sgshapiro
430364562Sgshapiro	/* These should never be set in LDAPDefaults */
430464562Sgshapiro	if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) ||
430564562Sgshapiro	    map.map_spacesub != SpaceSub ||
430664562Sgshapiro	    map.map_app != NULL ||
430764562Sgshapiro	    map.map_tapp != NULL)
430864562Sgshapiro	{
430964562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
431064562Sgshapiro		if (map.map_app != NULL)
431164562Sgshapiro		{
431264562Sgshapiro			free(map.map_app);
431364562Sgshapiro			map.map_app = NULL;
431464562Sgshapiro		}
431564562Sgshapiro		if (map.map_tapp != NULL)
431664562Sgshapiro		{
431764562Sgshapiro			free(map.map_tapp);
431864562Sgshapiro			map.map_tapp = NULL;
431964562Sgshapiro		}
432064562Sgshapiro	}
432164562Sgshapiro
432264562Sgshapiro	if (LDAPDefaults->ldap_filter != NULL)
432364562Sgshapiro	{
432464562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
432564562Sgshapiro		/* don't free, it isn't malloc'ed in parseargs */
432664562Sgshapiro		LDAPDefaults->ldap_filter = NULL;
432764562Sgshapiro	}
432864562Sgshapiro
432964562Sgshapiro	if (LDAPDefaults->ldap_attr[0] != NULL)
433064562Sgshapiro	{
433164562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes");
433264562Sgshapiro		/* don't free, they aren't malloc'ed in parseargs */
433364562Sgshapiro		LDAPDefaults->ldap_attr[0] = NULL;
433464562Sgshapiro	}
433564562Sgshapiro}
433664562Sgshapiro#endif /* LDAPMAP */
433764562Sgshapiro/*
433864562Sgshapiro**  PH map
433964562Sgshapiro*/
434064562Sgshapiro
434164562Sgshapiro#ifdef PH_MAP
434264562Sgshapiro
434364562Sgshapiro/*
434464562Sgshapiro**  Support for the CCSO Nameserver (ph/qi).
434564562Sgshapiro**  This code is intended to replace the so-called "ph mailer".
434664562Sgshapiro**  Contributed by Mark D. Roth <roth@uiuc.edu>.  Contact him for support.
434764562Sgshapiro*/
434864562Sgshapiro
434964562Sgshapiro# include <qiapi.h>
435064562Sgshapiro# include <qicode.h>
435164562Sgshapiro
435264562Sgshapiro/*
435364562Sgshapiro**  PH_MAP_PARSEARGS -- parse ph map definition args.
435464562Sgshapiro*/
435564562Sgshapiro
435664562Sgshapirobool
435764562Sgshapiroph_map_parseargs(map, args)
435864562Sgshapiro	MAP *map;
435964562Sgshapiro	char *args;
436064562Sgshapiro{
436164562Sgshapiro	int i;
436264562Sgshapiro	register int done;
436364562Sgshapiro	PH_MAP_STRUCT *pmap = NULL;
436464562Sgshapiro	register char *p = args;
436564562Sgshapiro
436664562Sgshapiro	pmap = (PH_MAP_STRUCT *) xalloc(sizeof *pmap);
436764562Sgshapiro
436864562Sgshapiro	/* defaults */
436964562Sgshapiro	pmap->ph_servers = NULL;
437064562Sgshapiro	pmap->ph_field_list = NULL;
437164562Sgshapiro	pmap->ph_to_server = NULL;
437264562Sgshapiro	pmap->ph_from_server = NULL;
437364562Sgshapiro	pmap->ph_sockfd = -1;
437464562Sgshapiro	pmap->ph_timeout = 0;
437564562Sgshapiro
437664562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
437764562Sgshapiro	for (;;)
437864562Sgshapiro	{
437964562Sgshapiro		while (isascii(*p) && isspace(*p))
438064562Sgshapiro			p++;
438164562Sgshapiro		if (*p != '-')
438264562Sgshapiro			break;
438364562Sgshapiro		switch (*++p)
438464562Sgshapiro		{
438564562Sgshapiro		  case 'N':
438664562Sgshapiro			map->map_mflags |= MF_INCLNULL;
438764562Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
438864562Sgshapiro			break;
438964562Sgshapiro
439064562Sgshapiro		  case 'O':
439164562Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
439264562Sgshapiro			break;
439364562Sgshapiro
439464562Sgshapiro		  case 'o':
439564562Sgshapiro			map->map_mflags |= MF_OPTIONAL;
439664562Sgshapiro			break;
439764562Sgshapiro
439864562Sgshapiro		  case 'f':
439964562Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
440064562Sgshapiro			break;
440164562Sgshapiro
440264562Sgshapiro		  case 'm':
440364562Sgshapiro			map->map_mflags |= MF_MATCHONLY;
440464562Sgshapiro			break;
440564562Sgshapiro
440664562Sgshapiro		  case 'A':
440764562Sgshapiro			map->map_mflags |= MF_APPEND;
440864562Sgshapiro			break;
440964562Sgshapiro
441064562Sgshapiro		  case 'q':
441164562Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
441264562Sgshapiro			break;
441364562Sgshapiro
441464562Sgshapiro		  case 't':
441564562Sgshapiro			map->map_mflags |= MF_NODEFER;
441664562Sgshapiro			break;
441764562Sgshapiro
441864562Sgshapiro		  case 'a':
441964562Sgshapiro			map->map_app = ++p;
442064562Sgshapiro			break;
442164562Sgshapiro
442264562Sgshapiro		  case 'T':
442364562Sgshapiro			map->map_tapp = ++p;
442464562Sgshapiro			break;
442564562Sgshapiro
442664562Sgshapiro#if _FFR_PHMAP_TIMEOUT
442764562Sgshapiro		  case 'l':
442864562Sgshapiro			while (isascii(*++p) && isspace(*p))
442964562Sgshapiro				continue;
443064562Sgshapiro			pmap->ph_timeout = atoi(p);
443164562Sgshapiro			break;
443264562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
443364562Sgshapiro
443464562Sgshapiro		  case 'S':
443564562Sgshapiro			map->map_spacesub = *++p;
443664562Sgshapiro			break;
443764562Sgshapiro
443864562Sgshapiro		  case 'D':
443964562Sgshapiro			map->map_mflags |= MF_DEFER;
444064562Sgshapiro			break;
444164562Sgshapiro
444264562Sgshapiro		  case 'h':		/* PH server list */
444364562Sgshapiro			while (isascii(*++p) && isspace(*p))
444464562Sgshapiro				continue;
444564562Sgshapiro			pmap->ph_servers = p;
444664562Sgshapiro			break;
444764562Sgshapiro
444864562Sgshapiro		  case 'v':		/* fields to search for */
444964562Sgshapiro			while (isascii(*++p) && isspace(*p))
445064562Sgshapiro				continue;
445164562Sgshapiro			pmap->ph_field_list = p;
445264562Sgshapiro			break;
445364562Sgshapiro
445464562Sgshapiro		  default:
445564562Sgshapiro			syserr("ph_map_parseargs: unknown option -%c\n", *p);
445664562Sgshapiro		}
445764562Sgshapiro
445864562Sgshapiro		/* try to account for quoted strings */
445964562Sgshapiro		done = isascii(*p) && isspace(*p);
446064562Sgshapiro		while (*p != '\0' && !done)
446164562Sgshapiro		{
446264562Sgshapiro			if (*p == '"')
446364562Sgshapiro			{
446464562Sgshapiro				while (*++p != '"' && *p != '\0')
446564562Sgshapiro					continue;
446664562Sgshapiro				if (*p != '\0')
446764562Sgshapiro					p++;
446864562Sgshapiro			}
446964562Sgshapiro			else
447064562Sgshapiro				p++;
447164562Sgshapiro			done = isascii(*p) && isspace(*p);
447264562Sgshapiro		}
447364562Sgshapiro
447464562Sgshapiro		if (*p != '\0')
447564562Sgshapiro			*p++ = '\0';
447664562Sgshapiro	}
447764562Sgshapiro
447864562Sgshapiro	if (map->map_app != NULL)
447964562Sgshapiro		map->map_app = newstr(ph_map_dequote(map->map_app));
448064562Sgshapiro	if (map->map_tapp != NULL)
448164562Sgshapiro		map->map_tapp = newstr(ph_map_dequote(map->map_tapp));
448264562Sgshapiro
448364562Sgshapiro	if (pmap->ph_field_list != NULL)
448464562Sgshapiro		pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
448564562Sgshapiro	else
448664562Sgshapiro		pmap->ph_field_list = DEFAULT_PH_MAP_FIELDS;
448764562Sgshapiro
448864562Sgshapiro	if (pmap->ph_servers != NULL)
448964562Sgshapiro		pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
449064562Sgshapiro	else
449164562Sgshapiro	{
449264562Sgshapiro		syserr("ph_map_parseargs: -h flag is required");
449364562Sgshapiro		return FALSE;
449464562Sgshapiro	}
449564562Sgshapiro
449664562Sgshapiro	map->map_db1 = (ARBPTR_T) pmap;
449764562Sgshapiro	return TRUE;
449864562Sgshapiro}
449964562Sgshapiro
450064562Sgshapiro#if _FFR_PHMAP_TIMEOUT
450164562Sgshapiro/*
450264562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
450364562Sgshapiro*/
450464562Sgshapiro
450564562Sgshapirostatic void
450664562Sgshapiroph_map_safeclose(map)
450764562Sgshapiro	MAP *map;
450864562Sgshapiro{
450964562Sgshapiro	int save_errno = errno;
451064562Sgshapiro	PH_MAP_STRUCT *pmap;
451164562Sgshapiro
451264562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
451364562Sgshapiro
451464562Sgshapiro	if (pmap->ph_sockfd != -1)
451564562Sgshapiro	{
451664562Sgshapiro		(void) close(pmap->ph_sockfd);
451764562Sgshapiro		pmap->ph_sockfd = -1;
451864562Sgshapiro	}
451964562Sgshapiro	if (pmap->ph_from_server != NULL)
452064562Sgshapiro	{
452164562Sgshapiro		(void) fclose(pmap->ph_from_server);
452264562Sgshapiro		pmap->ph_from_server = NULL;
452364562Sgshapiro	}
452464562Sgshapiro	if (pmap->ph_to_server != NULL)
452564562Sgshapiro	{
452664562Sgshapiro		(void) fclose(pmap->ph_to_server);
452764562Sgshapiro		pmap->ph_to_server = NULL;
452864562Sgshapiro	}
452964562Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
453064562Sgshapiro	errno = save_errno;
453164562Sgshapiro}
453264562Sgshapiro
453364562Sgshapirovoid
453464562Sgshapiroph_map_close(map)
453564562Sgshapiro	MAP *map;
453664562Sgshapiro{
453764562Sgshapiro	PH_MAP_STRUCT *pmap;
453864562Sgshapiro
453964562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
454064562Sgshapiro	(void) fprintf(pmap->ph_to_server, "quit\n");
454164562Sgshapiro	(void) fflush(pmap->ph_to_server);
454264562Sgshapiro	ph_map_safeclose(map);
454364562Sgshapiro}
454464562Sgshapiro
454564562Sgshapirostatic jmp_buf  PHTimeout;
454664562Sgshapiro
454764562Sgshapiro/* ARGSUSED */
454864562Sgshapirostatic void
454964562Sgshapiroph_timeout_func(sig_no)
455064562Sgshapiro	int sig_no;
455164562Sgshapiro{
455264562Sgshapiro	longjmp(PHTimeout, 1);
455364562Sgshapiro}
455464562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
455564562Sgshapiro/*
455664562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
455764562Sgshapiro*/
455864562Sgshapiro
455964562Sgshapirovoid
456064562Sgshapiroph_map_close(map)
456164562Sgshapiro	MAP *map;
456264562Sgshapiro{
456364562Sgshapiro	PH_MAP_STRUCT *pmap;
456464562Sgshapiro
456564562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
456664562Sgshapiro	CloseQi(pmap->ph_to_server, pmap->ph_from_server);
456764562Sgshapiro	pmap->ph_to_server = NULL;
456864562Sgshapiro	pmap->ph_from_server = NULL;
456964562Sgshapiro}
457064562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
457164562Sgshapiro
457264562Sgshapiro/*
457364562Sgshapiro**  PH_MAP_OPEN -- sub for opening PH map
457464562Sgshapiro*/
457564562Sgshapirobool
457664562Sgshapiroph_map_open(map, mode)
457764562Sgshapiro	MAP *map;
457864562Sgshapiro	int mode;
457964562Sgshapiro{
458064562Sgshapiro#if !_FFR_PHMAP_TIMEOUT
458164562Sgshapiro	int save_errno = 0;
458264562Sgshapiro#endif /* !_FFR_PHMAP_TIMEOUT */
458364562Sgshapiro	int j;
458464562Sgshapiro	char *hostlist, *tmp;
458564562Sgshapiro	QIR *server_data = NULL;
458664562Sgshapiro	PH_MAP_STRUCT *pmap;
458764562Sgshapiro#if _FFR_PHMAP_TIMEOUT
458864562Sgshapiro	register EVENT *ev = NULL;
458964562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
459064562Sgshapiro
459164562Sgshapiro	if (tTd(38, 2))
459264562Sgshapiro		dprintf("ph_map_open(%s)\n", map->map_mname);
459364562Sgshapiro
459464562Sgshapiro	mode &= O_ACCMODE;
459564562Sgshapiro	if (mode != O_RDONLY)
459664562Sgshapiro	{
459764562Sgshapiro		/* issue a pseudo-error message */
459864562Sgshapiro# ifdef ENOSYS
459964562Sgshapiro		errno = ENOSYS;
460064562Sgshapiro# else /* ENOSYS */
460164562Sgshapiro#  ifdef EFTYPE
460264562Sgshapiro		errno = EFTYPE;
460364562Sgshapiro#  else /* EFTYPE */
460464562Sgshapiro		errno = ENXIO;
460564562Sgshapiro#  endif /* EFTYPE */
460664562Sgshapiro# endif /* ENOSYS */
460764562Sgshapiro		return FALSE;
460864562Sgshapiro	}
460964562Sgshapiro
461064562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
461164562Sgshapiro
461264562Sgshapiro	hostlist = newstr(pmap->ph_servers);
461364562Sgshapiro	tmp = strtok(hostlist, " ");
461464562Sgshapiro	do
461564562Sgshapiro	{
461664562Sgshapiro#if _FFR_PHMAP_TIMEOUT
461764562Sgshapiro		if (pmap->ph_timeout != 0)
461864562Sgshapiro		{
461964562Sgshapiro			if (setjmp(PHTimeout) != 0)
462064562Sgshapiro			{
462164562Sgshapiro				ev = NULL;
462264562Sgshapiro				if (LogLevel > 1)
462364562Sgshapiro					sm_syslog(LOG_NOTICE, CurEnv->e_id,
462464562Sgshapiro						  "timeout connecting to PH server %.100s",
462564562Sgshapiro						  tmp);
462664562Sgshapiro# ifdef ETIMEDOUT
462764562Sgshapiro				errno = ETIMEDOUT;
462864562Sgshapiro# else /* ETIMEDOUT */
462964562Sgshapiro				errno = 0;
463064562Sgshapiro# endif /* ETIMEDOUT */
463164562Sgshapiro				goto ph_map_open_abort;
463264562Sgshapiro			}
463364562Sgshapiro			ev = setevent(pmap->ph_timeout, ph_timeout_func, 0);
463464562Sgshapiro		}
463564562Sgshapiro		if (!OpenQiSock(tmp, &(pmap->ph_sockfd)) &&
463664562Sgshapiro		    !Sock2FILEs(pmap->ph_sockfd, &(pmap->ph_to_server),
463764562Sgshapiro				&(pmap->ph_from_server)) &&
463864562Sgshapiro		    fprintf(pmap->ph_to_server, "id sendmail+phmap\n") >= 0 &&
463964562Sgshapiro		    fflush(pmap->ph_to_server) == 0 &&
464064562Sgshapiro		    (server_data = ReadQi(pmap->ph_from_server, &j)) != NULL &&
464164562Sgshapiro		    server_data->code == 200)
464264562Sgshapiro		{
464364562Sgshapiro			if (ev != NULL)
464464562Sgshapiro				clrevent(ev);
464564562Sgshapiro			FreeQIR(server_data);
464664562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
464764562Sgshapiro		if (OpenQi(tmp, &(pmap->ph_to_server),
464864562Sgshapiro			   &(pmap->ph_from_server)) >= 0)
464964562Sgshapiro		{
465064562Sgshapiro			if (fprintf(pmap->ph_to_server,
465164562Sgshapiro				    "id sendmail+phmap\n") < 0 ||
465264562Sgshapiro			    fflush(pmap->ph_to_server) < 0 ||
465364562Sgshapiro			    (server_data = ReadQi(pmap->ph_from_server,
465464562Sgshapiro						  &j)) == NULL ||
465564562Sgshapiro			    server_data->code != 200)
465664562Sgshapiro			{
465764562Sgshapiro				save_errno = errno;
465864562Sgshapiro				CloseQi(pmap->ph_to_server,
465964562Sgshapiro					pmap->ph_from_server);
466064562Sgshapiro				continue;
466164562Sgshapiro			}
466264562Sgshapiro			if (server_data != NULL)
466364562Sgshapiro				FreeQIR(server_data);
466464562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
466564562Sgshapiro			free(hostlist);
466664562Sgshapiro			return TRUE;
466764562Sgshapiro		}
466864562Sgshapiro#if _FFR_PHMAP_TIMEOUT
466964562Sgshapiro  ph_map_open_abort:
467064562Sgshapiro		if (ev != NULL)
467164562Sgshapiro			clrevent(ev);
467264562Sgshapiro		ph_map_safeclose(map);
467364562Sgshapiro		if (server_data != NULL)
467464562Sgshapiro		{
467564562Sgshapiro			FreeQIR(server_data);
467664562Sgshapiro			server_data = NULL;
467764562Sgshapiro		}
467864562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
467964562Sgshapiro		save_errno = errno;
468064562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
468164562Sgshapiro	} while (tmp = strtok(NULL, " "));
468264562Sgshapiro
468364562Sgshapiro#if !_FFR_PHMAP_TIMEOUT
468464562Sgshapiro	errno = save_errno;
468564562Sgshapiro#endif /* !_FFR_PHMAP_TIMEOUT */
468664562Sgshapiro	if (!bitset(MF_OPTIONAL, map->map_mflags))
468764562Sgshapiro	{
468864562Sgshapiro		if (errno == 0 && !bitset(MF_NODEFER,map->map_mflags))
468964562Sgshapiro			errno = EAGAIN;
469064562Sgshapiro		syserr("ph_map_open: cannot connect to PH server");
469164562Sgshapiro	}
469264562Sgshapiro	else if (LogLevel > 1)
469364562Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
469464562Sgshapiro			  "ph_map_open: cannot connect to PH server");
469564562Sgshapiro	free(hostlist);
469664562Sgshapiro	return FALSE;
469764562Sgshapiro}
469864562Sgshapiro
469964562Sgshapiro/*
470064562Sgshapiro**  PH_MAP_LOOKUP -- look up key from ph server
470164562Sgshapiro*/
470264562Sgshapiro
470364562Sgshapiro#if _FFR_PHMAP_TIMEOUT
470464562Sgshapiro# define MAX_PH_FIELDS	20
470564562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
470664562Sgshapiro
470764562Sgshapirochar *
470864562Sgshapiroph_map_lookup(map, key, args, pstat)
470964562Sgshapiro	MAP *map;
471064562Sgshapiro	char *key;
471164562Sgshapiro	char **args;
471264562Sgshapiro	int *pstat;
471364562Sgshapiro{
471464562Sgshapiro	int j;
471564562Sgshapiro	size_t sz;
471664562Sgshapiro	char *tmp, *tmp2;
471764562Sgshapiro	char *message = NULL, *field = NULL, *fmtkey;
471864562Sgshapiro	QIR *server_data = NULL;
471964562Sgshapiro	QIR *qirp;
472064562Sgshapiro	char keybuf[MAXKEY + 1], fieldbuf[101];
472164562Sgshapiro#if _FFR_PHMAP_TIMEOUT
472264562Sgshapiro	QIR *hold_data[MAX_PH_FIELDS];
472364562Sgshapiro	int hold_data_idx = 0;
472464562Sgshapiro	register EVENT *ev = NULL;
472564562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
472664562Sgshapiro	PH_MAP_STRUCT *pmap;
472764562Sgshapiro
472864562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
472964562Sgshapiro
473064562Sgshapiro	*pstat = EX_OK;
473164562Sgshapiro
473264562Sgshapiro#if _FFR_PHMAP_TIMEOUT
473364562Sgshapiro	if (pmap->ph_timeout != 0)
473464562Sgshapiro	{
473564562Sgshapiro		if (setjmp(PHTimeout) != 0)
473664562Sgshapiro		{
473764562Sgshapiro			ev = NULL;
473864562Sgshapiro			if (LogLevel > 1)
473964562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
474064562Sgshapiro					  "timeout during PH lookup of %.100s",
474164562Sgshapiro					  key);
474264562Sgshapiro# ifdef ETIMEDOUT
474364562Sgshapiro			errno = ETIMEDOUT;
474464562Sgshapiro# else /* ETIMEDOUT */
474564562Sgshapiro			errno = 0;
474664562Sgshapiro# endif /* ETIMEDOUT */
474764562Sgshapiro			*pstat = EX_TEMPFAIL;
474864562Sgshapiro			goto ph_map_lookup_abort;
474964562Sgshapiro		}
475064562Sgshapiro		ev = setevent(pmap->ph_timeout, ph_timeout_func, 0);
475164562Sgshapiro	}
475264562Sgshapiro
475364562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
475464562Sgshapiro	/* check all relevant fields */
475564562Sgshapiro	tmp = pmap->ph_field_list;
475664562Sgshapiro	do
475764562Sgshapiro	{
475864562Sgshapiro#if _FFR_PHMAP_TIMEOUT
475964562Sgshapiro		server_data = NULL;
476064562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
476164562Sgshapiro		while (isascii(*tmp) && isspace(*tmp))
476264562Sgshapiro			tmp++;
476364562Sgshapiro		if (*tmp == '\0')
476464562Sgshapiro			break;
476564562Sgshapiro		sz = strcspn(tmp, " ") + 1;
476664562Sgshapiro		if (sz > sizeof fieldbuf)
476764562Sgshapiro			sz = sizeof fieldbuf;
476864562Sgshapiro		(void) strlcpy(fieldbuf, tmp, sz);
476964562Sgshapiro		field = fieldbuf;
477064562Sgshapiro		tmp += sz;
477164562Sgshapiro
477264562Sgshapiro		(void) strlcpy(keybuf, key, sizeof keybuf);
477364562Sgshapiro		fmtkey = keybuf;
477464562Sgshapiro		if (strcmp(field, "alias") == 0)
477564562Sgshapiro		{
477664562Sgshapiro			/*
477764562Sgshapiro			**  for alias lookups, replace any punctuation
477864562Sgshapiro			**  characters with '-'
477964562Sgshapiro			*/
478064562Sgshapiro
478164562Sgshapiro			for (tmp2 = fmtkey; *tmp2 !=  '\0'; tmp2++)
478264562Sgshapiro			{
478364562Sgshapiro				if (isascii(*tmp2) && ispunct(*tmp2))
478464562Sgshapiro					*tmp2 = '-';
478564562Sgshapiro			}
478664562Sgshapiro			tmp2 = field;
478764562Sgshapiro		}
478864562Sgshapiro		else if (strcmp(field,"spacedname") == 0)
478964562Sgshapiro		{
479064562Sgshapiro			/*
479164562Sgshapiro			**  for "spaced" name lookups, replace any
479264562Sgshapiro			**  punctuation characters with a space
479364562Sgshapiro			*/
479464562Sgshapiro
479564562Sgshapiro			for (tmp2 = fmtkey; *tmp2 != '\0'; tmp2++)
479664562Sgshapiro			{
479764562Sgshapiro				if (isascii(*tmp2) && ispunct(*tmp2) &&
479864562Sgshapiro				    *tmp2 != '*')
479964562Sgshapiro					*tmp2 = ' ';
480064562Sgshapiro			}
480164562Sgshapiro			tmp2 = &(field[6]);
480264562Sgshapiro		}
480364562Sgshapiro		else
480464562Sgshapiro			tmp2 = field;
480564562Sgshapiro
480664562Sgshapiro		if (LogLevel > 9)
480764562Sgshapiro			sm_syslog(LOG_NOTICE, CurEnv->e_id,
480864562Sgshapiro				  "ph_map_lookup: query %s=\"%s\" return email",
480964562Sgshapiro				  tmp2, fmtkey);
481064562Sgshapiro		if (tTd(38, 20))
481164562Sgshapiro			dprintf("ph_map_lookup: query %s=\"%s\" return email\n",
481264562Sgshapiro				tmp2, fmtkey);
481364562Sgshapiro
481464562Sgshapiro		j = 0;
481564562Sgshapiro
481664562Sgshapiro		if (fprintf(pmap->ph_to_server, "query %s=%s return email\n",
481764562Sgshapiro			    tmp2, fmtkey) < 0)
481864562Sgshapiro			message = "qi query command failed";
481964562Sgshapiro		else if (fflush(pmap->ph_to_server) < 0)
482064562Sgshapiro			message = "qi fflush failed";
482164562Sgshapiro		else if ((server_data = ReadQi(pmap->ph_from_server,
482264562Sgshapiro					       &j)) == NULL)
482364562Sgshapiro			message = "ReadQi() returned NULL";
482464562Sgshapiro
482564562Sgshapiro#if _FFR_PHMAP_TIMEOUT
482664562Sgshapiro		if ((hold_data[hold_data_idx] = server_data) != NULL)
482764562Sgshapiro		{
482864562Sgshapiro			/* save pointer for later free() */
482964562Sgshapiro			hold_data_idx++;
483064562Sgshapiro		}
483164562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
483264562Sgshapiro
483364562Sgshapiro		if (server_data == NULL ||
483464562Sgshapiro		    (server_data->code >= 400 &&
483564562Sgshapiro		     server_data->code < 500))
483664562Sgshapiro		{
483764562Sgshapiro			/* temporary failure */
483864562Sgshapiro			*pstat = EX_TEMPFAIL;
483964562Sgshapiro#if _FFR_PHMAP_TIMEOUT
484064562Sgshapiro			break;
484164562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
484264562Sgshapiro			if (server_data != NULL)
484364562Sgshapiro			{
484464562Sgshapiro				FreeQIR(server_data);
484564562Sgshapiro				server_data = NULL;
484664562Sgshapiro			}
484764562Sgshapiro			return NULL;
484864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
484964562Sgshapiro		}
485064562Sgshapiro
485164562Sgshapiro		/*
485264562Sgshapiro		**  if we found a single match, break out.
485364562Sgshapiro		**  otherwise, try the next field.
485464562Sgshapiro		*/
485564562Sgshapiro
485664562Sgshapiro		if (j == 1)
485764562Sgshapiro			break;
485864562Sgshapiro
485964562Sgshapiro		/*
486064562Sgshapiro		**  check for a single response which is an error:
486164562Sgshapiro		**  ReadQi() doesn't set j on error responses,
486264562Sgshapiro		**  but we should stop here instead of moving on if
486364562Sgshapiro		**  it happens (e.g., alias found but email field empty)
486464562Sgshapiro		*/
486564562Sgshapiro
486664562Sgshapiro		for (qirp = server_data;
486764562Sgshapiro		     qirp != NULL && qirp->code < 0;
486864562Sgshapiro		     qirp++)
486964562Sgshapiro		{
487064562Sgshapiro			if (tTd(38, 20))
487164562Sgshapiro				dprintf("ph_map_lookup: QIR: %d:%d:%d:%s\n",
487264562Sgshapiro					qirp->code, qirp->subcode, qirp->field,
487364562Sgshapiro					(qirp->message ? qirp->message
487464562Sgshapiro					 : "[NULL]"));
487564562Sgshapiro			if (qirp->code <= -500)
487664562Sgshapiro			{
487764562Sgshapiro				j = 0;
487864562Sgshapiro				goto ph_map_lookup_abort;
487964562Sgshapiro			}
488064562Sgshapiro		}
488164562Sgshapiro
488264562Sgshapiro#if _FFR_PHMAP_TIMEOUT
488364562Sgshapiro	} while (*tmp != '\0' && hold_data_idx < MAX_PH_FIELDS);
488464562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
488564562Sgshapiro	} while (*tmp != '\0');
488664562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
488764562Sgshapiro
488864562Sgshapiro  ph_map_lookup_abort:
488964562Sgshapiro#if _FFR_PHMAP_TIMEOUT
489064562Sgshapiro	if (ev != NULL)
489164562Sgshapiro		clrevent(ev);
489264562Sgshapiro
489364562Sgshapiro	/*
489464562Sgshapiro	**  Return EX_TEMPFAIL if the timer popped
489564562Sgshapiro	**  or we got a temporary PH error
489664562Sgshapiro	*/
489764562Sgshapiro
489864562Sgshapiro	if (*pstat == EX_TEMPFAIL)
489964562Sgshapiro		ph_map_safeclose(map);
490064562Sgshapiro
490164562Sgshapiro	/* if we didn't find a single match, bail out */
490264562Sgshapiro	if (*pstat == EX_OK && j != 1)
490364562Sgshapiro		*pstat = EX_UNAVAILABLE;
490464562Sgshapiro
490564562Sgshapiro	if (*pstat == EX_OK)
490664562Sgshapiro	{
490764562Sgshapiro		/*
490864562Sgshapiro		** skip leading whitespace and chop at first address
490964562Sgshapiro		*/
491064562Sgshapiro
491164562Sgshapiro		for (tmp = server_data->message;
491264562Sgshapiro		     isascii(*tmp) && isspace(*tmp);
491364562Sgshapiro		     tmp++)
491464562Sgshapiro			continue;
491564562Sgshapiro
491664562Sgshapiro		for (tmp2 = tmp; *tmp2 != '\0'; tmp2++)
491764562Sgshapiro		{
491864562Sgshapiro			if (isascii(*tmp2) && isspace(*tmp2))
491964562Sgshapiro			{
492064562Sgshapiro				*tmp2 = '\0';
492164562Sgshapiro				break;
492264562Sgshapiro			}
492364562Sgshapiro		}
492464562Sgshapiro
492564562Sgshapiro		if (tTd(38,20))
492664562Sgshapiro			dprintf("ph_map_lookup: %s => %s\n", key, tmp);
492764562Sgshapiro
492864562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
492964562Sgshapiro			message = map_rewrite(map, key, strlen(key), NULL);
493064562Sgshapiro		else
493164562Sgshapiro			message = map_rewrite(map, tmp, strlen(tmp), args);
493264562Sgshapiro	}
493364562Sgshapiro
493464562Sgshapiro	/*
493564562Sgshapiro	**  Deferred free() of returned server_data values
493664562Sgshapiro	**  the deferral is to avoid the risk of a free() being
493764562Sgshapiro	**  interrupted by the event timer.  By now the timeout event
493864562Sgshapiro	**  has been cleared and none of the data is still in use.
493964562Sgshapiro	*/
494064562Sgshapiro
494164562Sgshapiro	while (--hold_data_idx >= 0)
494264562Sgshapiro	{
494364562Sgshapiro		if (hold_data[hold_data_idx] != NULL)
494464562Sgshapiro			FreeQIR(hold_data[hold_data_idx]);
494564562Sgshapiro	}
494664562Sgshapiro
494764562Sgshapiro	if (*pstat == EX_OK)
494864562Sgshapiro		return message;
494964562Sgshapiro
495064562Sgshapiro	return NULL;
495164562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
495264562Sgshapiro	/* if we didn't find a single match, bail out */
495364562Sgshapiro	if (j != 1)
495464562Sgshapiro	{
495564562Sgshapiro		*pstat = EX_UNAVAILABLE;
495664562Sgshapiro		if (server_data != NULL)
495764562Sgshapiro		{
495864562Sgshapiro			FreeQIR(server_data);
495964562Sgshapiro			server_data = NULL;
496064562Sgshapiro		}
496164562Sgshapiro		return NULL;
496264562Sgshapiro	}
496364562Sgshapiro
496464562Sgshapiro	/*
496564562Sgshapiro	** skip leading whitespace and chop at first address
496664562Sgshapiro	*/
496764562Sgshapiro
496864562Sgshapiro	for (tmp = server_data->message;
496964562Sgshapiro	     isascii(*tmp) && isspace(*tmp);
497064562Sgshapiro	     tmp++)
497164562Sgshapiro		continue;
497264562Sgshapiro
497364562Sgshapiro	for (tmp2 = tmp; *tmp2 != '\0'; tmp2++)
497464562Sgshapiro	{
497564562Sgshapiro		if (isascii(*tmp2) && isspace(*tmp2))
497664562Sgshapiro		{
497764562Sgshapiro			*tmp2 = '\0';
497864562Sgshapiro			break;
497964562Sgshapiro		}
498064562Sgshapiro	}
498164562Sgshapiro
498264562Sgshapiro	if (tTd(38,20))
498364562Sgshapiro		dprintf("ph_map_lookup: %s => %s\n", key, tmp);
498464562Sgshapiro
498564562Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
498664562Sgshapiro		message = map_rewrite(map, key, strlen(key), NULL);
498764562Sgshapiro	else
498864562Sgshapiro		message = map_rewrite(map, tmp, strlen(tmp), args);
498964562Sgshapiro	if (server_data != NULL)
499064562Sgshapiro	{
499164562Sgshapiro		FreeQIR(server_data);
499264562Sgshapiro		server_data = NULL;
499364562Sgshapiro	}
499464562Sgshapiro	return message;
499564562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
499664562Sgshapiro}
499764562Sgshapiro#endif /* PH_MAP */
499864562Sgshapiro/*
499942575Speter**  syslog map
500038032Speter*/
500138032Speter
500238032Speter#define map_prio	map_lockfd	/* overload field */
500338032Speter
500438032Speter/*
500542575Speter**  SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
500638032Speter*/
500738032Speter
500838032Speterbool
500938032Spetersyslog_map_parseargs(map, args)
501038032Speter	MAP *map;
501138032Speter	char *args;
501238032Speter{
501338032Speter	char *p = args;
501438032Speter	char *priority = NULL;
501538032Speter
501664562Sgshapiro	/* there is no check whether there is really an argument */
501764562Sgshapiro	while (*p != '\0')
501838032Speter	{
501938032Speter		while (isascii(*p) && isspace(*p))
502038032Speter			p++;
502138032Speter		if (*p != '-')
502238032Speter			break;
502364562Sgshapiro		++p;
502464562Sgshapiro		if (*p == 'D')
502564562Sgshapiro		{
502664562Sgshapiro			map->map_mflags |= MF_DEFER;
502764562Sgshapiro			++p;
502864562Sgshapiro		}
502964562Sgshapiro		else if (*p == 'S')
503064562Sgshapiro		{
503164562Sgshapiro			map->map_spacesub = *++p;
503264562Sgshapiro			if (*p != '\0')
503364562Sgshapiro				p++;
503464562Sgshapiro		}
503564562Sgshapiro		else if (*p == 'L')
503664562Sgshapiro		{
503764562Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p))
503864562Sgshapiro				continue;
503964562Sgshapiro			if (*p == '\0')
504064562Sgshapiro				break;
504164562Sgshapiro			priority = p;
504264562Sgshapiro			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
504364562Sgshapiro				p++;
504464562Sgshapiro			if (*p != '\0')
504564562Sgshapiro				*p++ = '\0';
504664562Sgshapiro		}
504764562Sgshapiro		else
504864562Sgshapiro		{
504964562Sgshapiro			syserr("Illegal option %c map syslog", *p);
505064562Sgshapiro			++p;
505164562Sgshapiro		}
505238032Speter	}
505338032Speter
505438032Speter	if (priority == NULL)
505538032Speter		map->map_prio = LOG_INFO;
505638032Speter	else
505738032Speter	{
505838032Speter		if (strncasecmp("LOG_", priority, 4) == 0)
505938032Speter			priority += 4;
506038032Speter
506138032Speter#ifdef LOG_EMERG
506238032Speter		if (strcasecmp("EMERG", priority) == 0)
506338032Speter			map->map_prio = LOG_EMERG;
506438032Speter		else
506564562Sgshapiro#endif /* LOG_EMERG */
506638032Speter#ifdef LOG_ALERT
506738032Speter		if (strcasecmp("ALERT", priority) == 0)
506838032Speter			map->map_prio = LOG_ALERT;
506938032Speter		else
507064562Sgshapiro#endif /* LOG_ALERT */
507138032Speter#ifdef LOG_CRIT
507238032Speter		if (strcasecmp("CRIT", priority) == 0)
507338032Speter			map->map_prio = LOG_CRIT;
507438032Speter		else
507564562Sgshapiro#endif /* LOG_CRIT */
507638032Speter#ifdef LOG_ERR
507738032Speter		if (strcasecmp("ERR", priority) == 0)
507838032Speter			map->map_prio = LOG_ERR;
507938032Speter		else
508064562Sgshapiro#endif /* LOG_ERR */
508138032Speter#ifdef LOG_WARNING
508238032Speter		if (strcasecmp("WARNING", priority) == 0)
508338032Speter			map->map_prio = LOG_WARNING;
508438032Speter		else
508564562Sgshapiro#endif /* LOG_WARNING */
508638032Speter#ifdef LOG_NOTICE
508738032Speter		if (strcasecmp("NOTICE", priority) == 0)
508838032Speter			map->map_prio = LOG_NOTICE;
508938032Speter		else
509064562Sgshapiro#endif /* LOG_NOTICE */
509138032Speter#ifdef LOG_INFO
509238032Speter		if (strcasecmp("INFO", priority) == 0)
509338032Speter			map->map_prio = LOG_INFO;
509438032Speter		else
509564562Sgshapiro#endif /* LOG_INFO */
509638032Speter#ifdef LOG_DEBUG
509738032Speter		if (strcasecmp("DEBUG", priority) == 0)
509838032Speter			map->map_prio = LOG_DEBUG;
509938032Speter		else
510064562Sgshapiro#endif /* LOG_DEBUG */
510138032Speter		{
510238032Speter			syserr("syslog_map_parseargs: Unknown priority %s\n",
510338032Speter			       priority);
510438032Speter			return FALSE;
510538032Speter		}
510638032Speter	}
510738032Speter	return TRUE;
510838032Speter}
510938032Speter
511038032Speter/*
511142575Speter**  SYSLOG_MAP_LOOKUP -- rewrite and syslog message.  Always return empty string
511238032Speter*/
511338032Speter
511438032Speterchar *
511538032Spetersyslog_map_lookup(map, string, args, statp)
511638032Speter	MAP *map;
511738032Speter	char *string;
511838032Speter	char **args;
511938032Speter	int *statp;
512038032Speter{
512138032Speter	char *ptr = map_rewrite(map, string, strlen(string), args);
512238032Speter
512338032Speter	if (ptr != NULL)
512438032Speter	{
512538032Speter		if (tTd(38, 20))
512664562Sgshapiro			dprintf("syslog_map_lookup(%s (priority %d): %s\n",
512764562Sgshapiro				map->map_mname, map->map_prio, ptr);
512838032Speter
512938032Speter		sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
513038032Speter	}
513138032Speter
513238032Speter	*statp = EX_OK;
513338032Speter	return "";
513438032Speter}
513538032Speter
513638032Speter/*
513738032Speter**  HESIOD Modules
513838032Speter*/
513938032Speter
514038032Speter#ifdef HESIOD
514138032Speter
514238032Speterbool
514338032Speterhes_map_open(map, mode)
514438032Speter	MAP *map;
514538032Speter	int mode;
514638032Speter{
514738032Speter	if (tTd(38, 2))
514864562Sgshapiro		dprintf("hes_map_open(%s, %s, %d)\n",
514938032Speter			map->map_mname, map->map_file, mode);
515038032Speter
515138032Speter	if (mode != O_RDONLY)
515238032Speter	{
515338032Speter		/* issue a pseudo-error message */
515464562Sgshapiro# ifdef ENOSYS
515538032Speter		errno = ENOSYS;
515664562Sgshapiro# else /* ENOSYS */
515764562Sgshapiro#  ifdef EFTYPE
515838032Speter		errno = EFTYPE;
515964562Sgshapiro#  else /* EFTYPE */
516038032Speter		errno = ENXIO;
516164562Sgshapiro#  endif /* EFTYPE */
516264562Sgshapiro# endif /* ENOSYS */
516338032Speter		return FALSE;
516438032Speter	}
516538032Speter
516664562Sgshapiro# ifdef HESIOD_INIT
516738032Speter	if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
516838032Speter		return TRUE;
516938032Speter
517038032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
517164562Sgshapiro		syserr("421 4.0.0 cannot initialize Hesiod map (%s)",
517238032Speter			errstring(errno));
517338032Speter	return FALSE;
517464562Sgshapiro# else /* HESIOD_INIT */
517538032Speter	if (hes_error() == HES_ER_UNINIT)
517638032Speter		hes_init();
517738032Speter	switch (hes_error())
517838032Speter	{
517938032Speter	  case HES_ER_OK:
518038032Speter	  case HES_ER_NOTFOUND:
518138032Speter		return TRUE;
518238032Speter	}
518338032Speter
518438032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
518564562Sgshapiro		syserr("421 4.0.0 cannot initialize Hesiod map (%d)", hes_error());
518638032Speter
518738032Speter	return FALSE;
518864562Sgshapiro# endif /* HESIOD_INIT */
518938032Speter}
519038032Speter
519138032Speterchar *
519238032Speterhes_map_lookup(map, name, av, statp)
519338032Speter	MAP *map;
519438032Speter	char *name;
519538032Speter	char **av;
519638032Speter	int *statp;
519738032Speter{
519838032Speter	char **hp;
519938032Speter
520038032Speter	if (tTd(38, 20))
520164562Sgshapiro		dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
520238032Speter
520338032Speter	if (name[0] == '\\')
520438032Speter	{
520538032Speter		char *np;
520638032Speter		int nl;
520738032Speter		char nbuf[MAXNAME];
520838032Speter
520938032Speter		nl = strlen(name);
521038032Speter		if (nl < sizeof nbuf - 1)
521138032Speter			np = nbuf;
521238032Speter		else
521338032Speter			np = xalloc(strlen(name) + 2);
521438032Speter		np[0] = '\\';
521564562Sgshapiro		(void) strlcpy(&np[1], name, (sizeof nbuf) - 1);
521664562Sgshapiro# ifdef HESIOD_INIT
521738032Speter		hp = hesiod_resolve(HesiodContext, np, map->map_file);
521864562Sgshapiro# else /* HESIOD_INIT */
521938032Speter		hp = hes_resolve(np, map->map_file);
522064562Sgshapiro# endif /* HESIOD_INIT */
522138032Speter		if (np != nbuf)
522238032Speter			free(np);
522338032Speter	}
522438032Speter	else
522538032Speter	{
522664562Sgshapiro# ifdef HESIOD_INIT
522738032Speter		hp = hesiod_resolve(HesiodContext, name, map->map_file);
522864562Sgshapiro# else /* HESIOD_INIT */
522938032Speter		hp = hes_resolve(name, map->map_file);
523064562Sgshapiro# endif /* HESIOD_INIT */
523138032Speter	}
523264562Sgshapiro# ifdef HESIOD_INIT
523338032Speter	if (hp == NULL)
523438032Speter		return NULL;
523538032Speter	if (*hp == NULL)
523638032Speter	{
523738032Speter		hesiod_free_list(HesiodContext, hp);
523838032Speter		switch (errno)
523938032Speter		{
524038032Speter		  case ENOENT:
524138032Speter			  *statp = EX_NOTFOUND;
524238032Speter			  break;
524338032Speter		  case ECONNREFUSED:
524438032Speter		  case EMSGSIZE:
524538032Speter			  *statp = EX_TEMPFAIL;
524638032Speter			  break;
524738032Speter		  case ENOMEM:
524838032Speter		  default:
524938032Speter			  *statp = EX_UNAVAILABLE;
525038032Speter			  break;
525138032Speter		}
525238032Speter		return NULL;
525338032Speter	}
525464562Sgshapiro# else /* HESIOD_INIT */
525538032Speter	if (hp == NULL || hp[0] == NULL)
525638032Speter	{
525738032Speter		switch (hes_error())
525838032Speter		{
525938032Speter		  case HES_ER_OK:
526038032Speter			*statp = EX_OK;
526138032Speter			break;
526238032Speter
526338032Speter		  case HES_ER_NOTFOUND:
526438032Speter			*statp = EX_NOTFOUND;
526538032Speter			break;
526638032Speter
526738032Speter		  case HES_ER_CONFIG:
526838032Speter			*statp = EX_UNAVAILABLE;
526938032Speter			break;
527038032Speter
527138032Speter		  case HES_ER_NET:
527238032Speter			*statp = EX_TEMPFAIL;
527338032Speter			break;
527438032Speter		}
527538032Speter		return NULL;
527638032Speter	}
527764562Sgshapiro# endif /* HESIOD_INIT */
527838032Speter
527938032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
528038032Speter		return map_rewrite(map, name, strlen(name), NULL);
528138032Speter	else
528238032Speter		return map_rewrite(map, hp[0], strlen(hp[0]), av);
528338032Speter}
528438032Speter
528564562Sgshapiro#endif /* HESIOD */
528638032Speter/*
528738032Speter**  NeXT NETINFO Modules
528838032Speter*/
528938032Speter
529038032Speter#if NETINFO
529138032Speter
529238032Speter# define NETINFO_DEFAULT_DIR		"/aliases"
529338032Speter# define NETINFO_DEFAULT_PROPERTY	"members"
529438032Speter
529538032Speter/*
529638032Speter**  NI_MAP_OPEN -- open NetInfo Aliases
529738032Speter*/
529838032Speter
529938032Speterbool
530038032Speterni_map_open(map, mode)
530138032Speter	MAP *map;
530238032Speter	int mode;
530338032Speter{
530438032Speter	if (tTd(38, 2))
530564562Sgshapiro		dprintf("ni_map_open(%s, %s, %d)\n",
530638032Speter			map->map_mname, map->map_file, mode);
530738032Speter	mode &= O_ACCMODE;
530838032Speter
530938032Speter	if (*map->map_file == '\0')
531038032Speter		map->map_file = NETINFO_DEFAULT_DIR;
531138032Speter
531238032Speter	if (map->map_valcolnm == NULL)
531338032Speter		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
531438032Speter
531538032Speter	if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
531638032Speter		map->map_coldelim = ',';
531738032Speter
531838032Speter	return TRUE;
531938032Speter}
532038032Speter
532138032Speter
532238032Speter/*
532338032Speter**  NI_MAP_LOOKUP -- look up a datum in NetInfo
532438032Speter*/
532538032Speter
532638032Speterchar *
532738032Speterni_map_lookup(map, name, av, statp)
532838032Speter	MAP *map;
532938032Speter	char *name;
533038032Speter	char **av;
533138032Speter	int *statp;
533238032Speter{
533338032Speter	char *res;
533438032Speter	char *propval;
533538032Speter
533638032Speter	if (tTd(38, 20))
533764562Sgshapiro		dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
533838032Speter
533938032Speter	propval = ni_propval(map->map_file, map->map_keycolnm, name,
534038032Speter			     map->map_valcolnm, map->map_coldelim);
534138032Speter
534238032Speter	if (propval == NULL)
534338032Speter		return NULL;
534438032Speter
534538032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
534638032Speter		res = map_rewrite(map, name, strlen(name), NULL);
534738032Speter	else
534838032Speter		res = map_rewrite(map, propval, strlen(propval), av);
534938032Speter	free(propval);
535038032Speter	return res;
535138032Speter}
535238032Speter
535338032Speter
535464562Sgshapirostatic bool
535538032Speterni_getcanonname(name, hbsize, statp)
535638032Speter	char *name;
535738032Speter	int hbsize;
535838032Speter	int *statp;
535938032Speter{
536038032Speter	char *vptr;
536138032Speter	char *ptr;
536238032Speter	char nbuf[MAXNAME + 1];
536338032Speter
536438032Speter	if (tTd(38, 20))
536564562Sgshapiro		dprintf("ni_getcanonname(%s)\n", name);
536638032Speter
536764562Sgshapiro	if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
536838032Speter	{
536938032Speter		*statp = EX_UNAVAILABLE;
537038032Speter		return FALSE;
537138032Speter	}
537238032Speter	shorten_hostname(nbuf);
537338032Speter
537438032Speter	/* we only accept single token search key */
537538032Speter	if (strchr(nbuf, '.'))
537638032Speter	{
537738032Speter		*statp = EX_NOHOST;
537838032Speter		return FALSE;
537938032Speter	}
538038032Speter
538138032Speter	/* Do the search */
538238032Speter	vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
538338032Speter
538438032Speter	if (vptr == NULL)
538538032Speter	{
538638032Speter		*statp = EX_NOHOST;
538738032Speter		return FALSE;
538838032Speter	}
538938032Speter
539038032Speter	/* Only want the first machine name */
539138032Speter	if ((ptr = strchr(vptr, '\n')) != NULL)
539238032Speter		*ptr = '\0';
539338032Speter
539438032Speter	if (hbsize >= strlen(vptr))
539538032Speter	{
539664562Sgshapiro		(void) strlcpy(name, vptr, hbsize);
539764562Sgshapiro		free(vptr);
539838032Speter		*statp = EX_OK;
539938032Speter		return TRUE;
540038032Speter	}
540138032Speter	*statp = EX_UNAVAILABLE;
540238032Speter	free(vptr);
540338032Speter	return FALSE;
540438032Speter}
540538032Speter
540638032Speter
540738032Speter/*
540838032Speter**  NI_PROPVAL -- NetInfo property value lookup routine
540938032Speter**
541038032Speter**	Parameters:
541138032Speter**		keydir -- the NetInfo directory name in which to search
541238032Speter**			for the key.
541338032Speter**		keyprop -- the name of the property in which to find the
541438032Speter**			property we are interested.  Defaults to "name".
541538032Speter**		keyval -- the value for which we are really searching.
541638032Speter**		valprop -- the property name for the value in which we
541738032Speter**			are interested.
541838032Speter**		sepchar -- if non-nil, this can be multiple-valued, and
541938032Speter**			we should return a string separated by this
542038032Speter**			character.
542138032Speter**
542238032Speter**	Returns:
542338032Speter**		NULL -- if:
542438032Speter**			1. the directory is not found
542538032Speter**			2. the property name is not found
542638032Speter**			3. the property contains multiple values
542764562Sgshapiro**			4. some error occurred
542838032Speter**		else -- the value of the lookup.
542938032Speter**
543038032Speter**	Example:
543138032Speter**		To search for an alias value, use:
543238032Speter**		  ni_propval("/aliases", "name", aliasname, "members", ',')
543338032Speter**
543438032Speter**	Notes:
543564562Sgshapiro**		Caller should free the return value of ni_proval
543638032Speter*/
543738032Speter
543838032Speter# include <netinfo/ni.h>
543938032Speter
544064562Sgshapiro# define LOCAL_NETINFO_DOMAIN	"."
544164562Sgshapiro# define PARENT_NETINFO_DOMAIN	".."
544264562Sgshapiro# define MAX_NI_LEVELS		256
544338032Speter
544438032Speterchar *
544538032Speterni_propval(keydir, keyprop, keyval, valprop, sepchar)
544638032Speter	char *keydir;
544738032Speter	char *keyprop;
544838032Speter	char *keyval;
544938032Speter	char *valprop;
545038032Speter	int sepchar;
545138032Speter{
545238032Speter	char *propval = NULL;
545338032Speter	int i;
545464562Sgshapiro	int j, alen, l;
545538032Speter	void *ni = NULL;
545638032Speter	void *lastni = NULL;
545738032Speter	ni_status nis;
545838032Speter	ni_id nid;
545938032Speter	ni_namelist ninl;
546038032Speter	register char *p;
546138032Speter	char keybuf[1024];
546238032Speter
546338032Speter	/*
546438032Speter	**  Create the full key from the two parts.
546538032Speter	**
546638032Speter	**	Note that directory can end with, e.g., "name=" to specify
546738032Speter	**	an alternate search property.
546838032Speter	*/
546938032Speter
547038032Speter	i = strlen(keydir) + strlen(keyval) + 2;
547138032Speter	if (keyprop != NULL)
547238032Speter		i += strlen(keyprop) + 1;
547364562Sgshapiro	if (i >= sizeof keybuf)
547438032Speter		return NULL;
547564562Sgshapiro	(void) strlcpy(keybuf, keydir, sizeof keybuf);
547664562Sgshapiro	(void) strlcat(keybuf, "/", sizeof keybuf);
547738032Speter	if (keyprop != NULL)
547838032Speter	{
547964562Sgshapiro		(void) strlcat(keybuf, keyprop, sizeof keybuf);
548064562Sgshapiro		(void) strlcat(keybuf, "=", sizeof keybuf);
548138032Speter	}
548264562Sgshapiro	(void) strlcat(keybuf, keyval, sizeof keybuf);
548338032Speter
548438032Speter	if (tTd(38, 21))
548564562Sgshapiro		dprintf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n",
548638032Speter			keydir, keyprop, keyval, valprop, sepchar, keybuf);
548738032Speter	/*
548838032Speter	**  If the passed directory and property name are found
548938032Speter	**  in one of netinfo domains we need to search (starting
549038032Speter	**  from the local domain moving all the way back to the
549138032Speter	**  root domain) set propval to the property's value
549238032Speter	**  and return it.
549338032Speter	*/
549438032Speter
549538032Speter	for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
549638032Speter	{
549738032Speter		if (i == 0)
549838032Speter		{
549938032Speter			nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
550038032Speter			if (tTd(38, 20))
550164562Sgshapiro				dprintf("ni_open(LOCAL) = %d\n", nis);
550238032Speter		}
550338032Speter		else
550438032Speter		{
550538032Speter			if (lastni != NULL)
550638032Speter				ni_free(lastni);
550738032Speter			lastni = ni;
550838032Speter			nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
550938032Speter			if (tTd(38, 20))
551064562Sgshapiro				dprintf("ni_open(PARENT) = %d\n", nis);
551138032Speter		}
551238032Speter
551338032Speter		/*
551438032Speter		**  Don't bother if we didn't get a handle on a
551538032Speter		**  proper domain.  This is not necessarily an error.
551638032Speter		**  We would get a positive ni_status if, for instance
551738032Speter		**  we never found the directory or property and tried
551838032Speter		**  to open the parent of the root domain!
551938032Speter		*/
552038032Speter
552138032Speter		if (nis != 0)
552238032Speter			break;
552338032Speter
552438032Speter		/*
552538032Speter		**  Find the path to the server information.
552638032Speter		*/
552738032Speter
552838032Speter		if (ni_pathsearch(ni, &nid, keybuf) != 0)
552938032Speter			continue;
553038032Speter
553138032Speter		/*
553238032Speter		**  Find associated value information.
553338032Speter		*/
553438032Speter
553538032Speter		if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
553638032Speter			continue;
553738032Speter
553838032Speter		if (tTd(38, 20))
553964562Sgshapiro			dprintf("ni_lookupprop: len=%d\n",
554064562Sgshapiro				ninl.ni_namelist_len);
554164562Sgshapiro
554238032Speter		/*
554338032Speter		**  See if we have an acceptable number of values.
554438032Speter		*/
554538032Speter
554638032Speter		if (ninl.ni_namelist_len <= 0)
554738032Speter			continue;
554838032Speter
554938032Speter		if (sepchar == '\0' && ninl.ni_namelist_len > 1)
555038032Speter		{
555138032Speter			ni_namelist_free(&ninl);
555238032Speter			continue;
555338032Speter		}
555438032Speter
555538032Speter		/*
555638032Speter		**  Calculate number of bytes needed and build result
555738032Speter		*/
555838032Speter
555938032Speter		alen = 1;
556038032Speter		for (j = 0; j < ninl.ni_namelist_len; j++)
556138032Speter			alen += strlen(ninl.ni_namelist_val[j]) + 1;
556238032Speter		propval = p = xalloc(alen);
556338032Speter		for (j = 0; j < ninl.ni_namelist_len; j++)
556438032Speter		{
556564562Sgshapiro			(void) strlcpy(p, ninl.ni_namelist_val[j], alen);
556664562Sgshapiro			l = strlen(p);
556764562Sgshapiro			p += l;
556838032Speter			*p++ = sepchar;
556964562Sgshapiro			alen -= l + 1;
557038032Speter		}
557138032Speter		*--p = '\0';
557238032Speter
557338032Speter		ni_namelist_free(&ninl);
557438032Speter	}
557538032Speter
557638032Speter	/*
557738032Speter	**  Clean up.
557838032Speter	*/
557938032Speter
558038032Speter	if (ni != NULL)
558138032Speter		ni_free(ni);
558238032Speter	if (lastni != NULL && ni != lastni)
558338032Speter		ni_free(lastni);
558438032Speter	if (tTd(38, 20))
558564562Sgshapiro		dprintf("ni_propval returns: '%s'\n", propval);
558638032Speter
558738032Speter	return propval;
558838032Speter}
558938032Speter
559042575Speter#endif /* NETINFO */
559138032Speter/*
559238032Speter**  TEXT (unindexed text file) Modules
559338032Speter**
559438032Speter**	This code donated by Sun Microsystems.
559538032Speter*/
559638032Speter
559738032Speter#define map_sff		map_lockfd	/* overload field */
559838032Speter
559938032Speter
560038032Speter/*
560138032Speter**  TEXT_MAP_OPEN -- open text table
560238032Speter*/
560338032Speter
560438032Speterbool
560538032Spetertext_map_open(map, mode)
560638032Speter	MAP *map;
560738032Speter	int mode;
560838032Speter{
560964562Sgshapiro	long sff;
561038032Speter	int i;
561138032Speter
561238032Speter	if (tTd(38, 2))
561364562Sgshapiro		dprintf("text_map_open(%s, %s, %d)\n",
561438032Speter			map->map_mname, map->map_file, mode);
561538032Speter
561638032Speter	mode &= O_ACCMODE;
561738032Speter	if (mode != O_RDONLY)
561838032Speter	{
561938032Speter		errno = EPERM;
562038032Speter		return FALSE;
562138032Speter	}
562238032Speter
562338032Speter	if (*map->map_file == '\0')
562438032Speter	{
562538032Speter		syserr("text map \"%s\": file name required",
562638032Speter			map->map_mname);
562738032Speter		return FALSE;
562838032Speter	}
562938032Speter
563038032Speter	if (map->map_file[0] != '/')
563138032Speter	{
563238032Speter		syserr("text map \"%s\": file name must be fully qualified",
563338032Speter			map->map_mname);
563438032Speter		return FALSE;
563538032Speter	}
563638032Speter
563738032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
563864562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
563938032Speter		sff |= SFF_NOWLINK;
564064562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
564138032Speter		sff |= SFF_SAFEDIRPATH;
564238032Speter	if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
564338032Speter			  sff, S_IRUSR, NULL)) != 0)
564438032Speter	{
564564562Sgshapiro		int save_errno = errno;
564664562Sgshapiro
564738032Speter		/* cannot open this map */
564838032Speter		if (tTd(38, 2))
564964562Sgshapiro			dprintf("\tunsafe map file: %d\n", i);
565064562Sgshapiro		errno = save_errno;
565138032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
565238032Speter			syserr("text map \"%s\": unsafe map file %s",
565338032Speter				map->map_mname, map->map_file);
565438032Speter		return FALSE;
565538032Speter	}
565638032Speter
565738032Speter	if (map->map_keycolnm == NULL)
565838032Speter		map->map_keycolno = 0;
565938032Speter	else
566038032Speter	{
566138032Speter		if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
566238032Speter		{
566338032Speter			syserr("text map \"%s\", file %s: -k should specify a number, not %s",
566438032Speter				map->map_mname, map->map_file,
566538032Speter				map->map_keycolnm);
566638032Speter			return FALSE;
566738032Speter		}
566838032Speter		map->map_keycolno = atoi(map->map_keycolnm);
566938032Speter	}
567038032Speter
567138032Speter	if (map->map_valcolnm == NULL)
567238032Speter		map->map_valcolno = 0;
567338032Speter	else
567438032Speter	{
567538032Speter		if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
567638032Speter		{
567738032Speter			syserr("text map \"%s\", file %s: -v should specify a number, not %s",
567838032Speter					map->map_mname, map->map_file,
567938032Speter					map->map_valcolnm);
568038032Speter			return FALSE;
568138032Speter		}
568238032Speter		map->map_valcolno = atoi(map->map_valcolnm);
568338032Speter	}
568438032Speter
568538032Speter	if (tTd(38, 2))
568638032Speter	{
568764562Sgshapiro		dprintf("text_map_open(%s, %s): delimiter = ",
568838032Speter			map->map_mname, map->map_file);
568938032Speter		if (map->map_coldelim == '\0')
569064562Sgshapiro			dprintf("(white space)\n");
569138032Speter		else
569264562Sgshapiro			dprintf("%c\n", map->map_coldelim);
569338032Speter	}
569438032Speter
569538032Speter	map->map_sff = sff;
569638032Speter	return TRUE;
569738032Speter}
569838032Speter
569938032Speter
570038032Speter/*
570138032Speter**  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
570238032Speter*/
570338032Speter
570438032Speterchar *
570538032Spetertext_map_lookup(map, name, av, statp)
570638032Speter	MAP *map;
570738032Speter	char *name;
570838032Speter	char **av;
570938032Speter	int *statp;
571038032Speter{
571138032Speter	char *vp;
571238032Speter	auto int vsize;
571338032Speter	int buflen;
571438032Speter	FILE *f;
571538032Speter	char delim;
571638032Speter	int key_idx;
571738032Speter	bool found_it;
571864562Sgshapiro	long sff = map->map_sff;
571938032Speter	char search_key[MAXNAME + 1];
572038032Speter	char linebuf[MAXLINE];
572138032Speter	char buf[MAXNAME + 1];
572238032Speter
572338032Speter	found_it = FALSE;
572438032Speter	if (tTd(38, 20))
572564562Sgshapiro		dprintf("text_map_lookup(%s, %s)\n", map->map_mname,  name);
572638032Speter
572738032Speter	buflen = strlen(name);
572838032Speter	if (buflen > sizeof search_key - 1)
572938032Speter		buflen = sizeof search_key - 1;
573064562Sgshapiro	memmove(search_key, name, buflen);
573138032Speter	search_key[buflen] = '\0';
573238032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
573338032Speter		makelower(search_key);
573438032Speter
573538032Speter	f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
573638032Speter	if (f == NULL)
573738032Speter	{
573838032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
573938032Speter		*statp = EX_UNAVAILABLE;
574038032Speter		return NULL;
574138032Speter	}
574238032Speter	key_idx = map->map_keycolno;
574338032Speter	delim = map->map_coldelim;
574438032Speter	while (fgets(linebuf, MAXLINE, f) != NULL)
574538032Speter	{
574638032Speter		char *p;
574738032Speter
574838032Speter		/* skip comment line */
574938032Speter		if (linebuf[0] == '#')
575038032Speter			continue;
575138032Speter		p = strchr(linebuf, '\n');
575238032Speter		if (p != NULL)
575338032Speter			*p = '\0';
575438032Speter		p = get_column(linebuf, key_idx, delim, buf, sizeof buf);
575538032Speter		if (p != NULL && strcasecmp(search_key, p) == 0)
575638032Speter		{
575738032Speter			found_it = TRUE;
575838032Speter			break;
575938032Speter		}
576038032Speter	}
576164562Sgshapiro	(void) fclose(f);
576238032Speter	if (!found_it)
576338032Speter	{
576438032Speter		*statp = EX_NOTFOUND;
576538032Speter		return NULL;
576638032Speter	}
576738032Speter	vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof buf);
576842575Speter	if (vp == NULL)
576942575Speter	{
577042575Speter		*statp = EX_NOTFOUND;
577142575Speter		return NULL;
577242575Speter	}
577338032Speter	vsize = strlen(vp);
577438032Speter	*statp = EX_OK;
577538032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
577638032Speter		return map_rewrite(map, name, strlen(name), NULL);
577738032Speter	else
577838032Speter		return map_rewrite(map, vp, vsize, av);
577938032Speter}
578038032Speter
578138032Speter/*
578238032Speter**  TEXT_GETCANONNAME -- look up canonical name in hosts file
578338032Speter*/
578438032Speter
578564562Sgshapirostatic bool
578638032Spetertext_getcanonname(name, hbsize, statp)
578738032Speter	char *name;
578838032Speter	int hbsize;
578938032Speter	int *statp;
579038032Speter{
579138032Speter	bool found;
579238032Speter	FILE *f;
579338032Speter	char linebuf[MAXLINE];
579438032Speter	char cbuf[MAXNAME + 1];
579538032Speter	char nbuf[MAXNAME + 1];
579638032Speter
579738032Speter	if (tTd(38, 20))
579864562Sgshapiro		dprintf("text_getcanonname(%s)\n", name);
579938032Speter
580038032Speter	if (strlen(name) >= (SIZE_T) sizeof nbuf)
580138032Speter	{
580238032Speter		*statp = EX_UNAVAILABLE;
580338032Speter		return FALSE;
580438032Speter	}
580564562Sgshapiro	(void) strlcpy(nbuf, name, sizeof nbuf);
580638032Speter	shorten_hostname(nbuf);
580738032Speter
580838032Speter	f = fopen(HostsFile, "r");
580938032Speter	if (f == NULL)
581038032Speter	{
581138032Speter		*statp = EX_UNAVAILABLE;
581238032Speter		return FALSE;
581338032Speter	}
581438032Speter	found = FALSE;
581538032Speter	while (!found && fgets(linebuf, MAXLINE, f) != NULL)
581638032Speter	{
581738032Speter		char *p = strpbrk(linebuf, "#\n");
581838032Speter
581938032Speter		if (p != NULL)
582038032Speter			*p = '\0';
582138032Speter		if (linebuf[0] != '\0')
582238032Speter			found = extract_canonname(nbuf, linebuf, cbuf, sizeof cbuf);
582338032Speter	}
582464562Sgshapiro	(void) fclose(f);
582538032Speter	if (!found)
582638032Speter	{
582738032Speter		*statp = EX_NOHOST;
582838032Speter		return FALSE;
582938032Speter	}
583038032Speter
583138032Speter	if ((SIZE_T) hbsize >= strlen(cbuf))
583238032Speter	{
583364562Sgshapiro		(void) strlcpy(name, cbuf, hbsize);
583438032Speter		*statp = EX_OK;
583538032Speter		return TRUE;
583638032Speter	}
583738032Speter	*statp = EX_UNAVAILABLE;
583838032Speter	return FALSE;
583938032Speter}
584038032Speter/*
584138032Speter**  STAB (Symbol Table) Modules
584238032Speter*/
584338032Speter
584438032Speter
584538032Speter/*
584638032Speter**  STAB_MAP_LOOKUP -- look up alias in symbol table
584738032Speter*/
584838032Speter
584938032Speter/* ARGSUSED2 */
585038032Speterchar *
585138032Speterstab_map_lookup(map, name, av, pstat)
585238032Speter	register MAP *map;
585338032Speter	char *name;
585438032Speter	char **av;
585538032Speter	int *pstat;
585638032Speter{
585738032Speter	register STAB *s;
585838032Speter
585938032Speter	if (tTd(38, 20))
586064562Sgshapiro		dprintf("stab_lookup(%s, %s)\n",
586138032Speter			map->map_mname, name);
586238032Speter
586338032Speter	s = stab(name, ST_ALIAS, ST_FIND);
586438032Speter	if (s != NULL)
586564562Sgshapiro		return s->s_alias;
586664562Sgshapiro	return NULL;
586738032Speter}
586838032Speter
586938032Speter
587038032Speter/*
587138032Speter**  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
587238032Speter*/
587338032Speter
587438032Spetervoid
587538032Speterstab_map_store(map, lhs, rhs)
587638032Speter	register MAP *map;
587738032Speter	char *lhs;
587838032Speter	char *rhs;
587938032Speter{
588038032Speter	register STAB *s;
588138032Speter
588238032Speter	s = stab(lhs, ST_ALIAS, ST_ENTER);
588338032Speter	s->s_alias = newstr(rhs);
588438032Speter}
588538032Speter
588638032Speter
588738032Speter/*
588838032Speter**  STAB_MAP_OPEN -- initialize (reads data file)
588938032Speter**
589038032Speter**	This is a wierd case -- it is only intended as a fallback for
589138032Speter**	aliases.  For this reason, opens for write (only during a
589238032Speter**	"newaliases") always fails, and opens for read open the
589338032Speter**	actual underlying text file instead of the database.
589438032Speter*/
589538032Speter
589638032Speterbool
589738032Speterstab_map_open(map, mode)
589838032Speter	register MAP *map;
589938032Speter	int mode;
590038032Speter{
590138032Speter	FILE *af;
590264562Sgshapiro	long sff;
590338032Speter	struct stat st;
590438032Speter
590538032Speter	if (tTd(38, 2))
590664562Sgshapiro		dprintf("stab_map_open(%s, %s, %d)\n",
590738032Speter			map->map_mname, map->map_file, mode);
590838032Speter
590938032Speter	mode &= O_ACCMODE;
591038032Speter	if (mode != O_RDONLY)
591138032Speter	{
591238032Speter		errno = EPERM;
591338032Speter		return FALSE;
591438032Speter	}
591538032Speter
591638032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
591764562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
591838032Speter		sff |= SFF_NOWLINK;
591964562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
592038032Speter		sff |= SFF_SAFEDIRPATH;
592138032Speter	af = safefopen(map->map_file, O_RDONLY, 0444, sff);
592238032Speter	if (af == NULL)
592338032Speter		return FALSE;
592438032Speter	readaliases(map, af, FALSE, FALSE);
592538032Speter
592638032Speter	if (fstat(fileno(af), &st) >= 0)
592738032Speter		map->map_mtime = st.st_mtime;
592864562Sgshapiro	(void) fclose(af);
592938032Speter
593038032Speter	return TRUE;
593138032Speter}
593238032Speter/*
593338032Speter**  Implicit Modules
593438032Speter**
593538032Speter**	Tries several types.  For back compatibility of aliases.
593638032Speter*/
593738032Speter
593838032Speter
593938032Speter/*
594038032Speter**  IMPL_MAP_LOOKUP -- lookup in best open database
594138032Speter*/
594238032Speter
594338032Speterchar *
594438032Speterimpl_map_lookup(map, name, av, pstat)
594538032Speter	MAP *map;
594638032Speter	char *name;
594738032Speter	char **av;
594838032Speter	int *pstat;
594938032Speter{
595038032Speter	if (tTd(38, 20))
595164562Sgshapiro		dprintf("impl_map_lookup(%s, %s)\n",
595238032Speter			map->map_mname, name);
595338032Speter
595438032Speter#ifdef NEWDB
595538032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
595638032Speter		return db_map_lookup(map, name, av, pstat);
595764562Sgshapiro#endif /* NEWDB */
595838032Speter#ifdef NDBM
595938032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
596038032Speter		return ndbm_map_lookup(map, name, av, pstat);
596164562Sgshapiro#endif /* NDBM */
596238032Speter	return stab_map_lookup(map, name, av, pstat);
596338032Speter}
596438032Speter
596538032Speter/*
596638032Speter**  IMPL_MAP_STORE -- store in open databases
596738032Speter*/
596838032Speter
596938032Spetervoid
597038032Speterimpl_map_store(map, lhs, rhs)
597138032Speter	MAP *map;
597238032Speter	char *lhs;
597338032Speter	char *rhs;
597438032Speter{
597538032Speter	if (tTd(38, 12))
597664562Sgshapiro		dprintf("impl_map_store(%s, %s, %s)\n",
597738032Speter			map->map_mname, lhs, rhs);
597838032Speter#ifdef NEWDB
597938032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
598038032Speter		db_map_store(map, lhs, rhs);
598164562Sgshapiro#endif /* NEWDB */
598238032Speter#ifdef NDBM
598338032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
598438032Speter		ndbm_map_store(map, lhs, rhs);
598564562Sgshapiro#endif /* NDBM */
598638032Speter	stab_map_store(map, lhs, rhs);
598738032Speter}
598838032Speter
598938032Speter/*
599038032Speter**  IMPL_MAP_OPEN -- implicit database open
599138032Speter*/
599238032Speter
599338032Speterbool
599438032Speterimpl_map_open(map, mode)
599538032Speter	MAP *map;
599638032Speter	int mode;
599738032Speter{
599838032Speter	if (tTd(38, 2))
599964562Sgshapiro		dprintf("impl_map_open(%s, %s, %d)\n",
600038032Speter			map->map_mname, map->map_file, mode);
600138032Speter
600238032Speter	mode &= O_ACCMODE;
600338032Speter#ifdef NEWDB
600438032Speter	map->map_mflags |= MF_IMPL_HASH;
600538032Speter	if (hash_map_open(map, mode))
600638032Speter	{
600738032Speter# ifdef NDBM_YP_COMPAT
600838032Speter		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
600964562Sgshapiro# endif /* NDBM_YP_COMPAT */
601038032Speter			return TRUE;
601138032Speter	}
601238032Speter	else
601338032Speter		map->map_mflags &= ~MF_IMPL_HASH;
601464562Sgshapiro#endif /* NEWDB */
601538032Speter#ifdef NDBM
601638032Speter	map->map_mflags |= MF_IMPL_NDBM;
601738032Speter	if (ndbm_map_open(map, mode))
601838032Speter	{
601938032Speter		return TRUE;
602038032Speter	}
602138032Speter	else
602238032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
602364562Sgshapiro#endif /* NDBM */
602438032Speter
602538032Speter#if defined(NEWDB) || defined(NDBM)
602638032Speter	if (Verbose)
602738032Speter		message("WARNING: cannot open alias database %s%s",
602838032Speter			map->map_file,
602938032Speter			mode == O_RDONLY ? "; reading text version" : "");
603064562Sgshapiro#else /* defined(NEWDB) || defined(NDBM) */
603138032Speter	if (mode != O_RDONLY)
603238032Speter		usrerr("Cannot rebuild aliases: no database format defined");
603364562Sgshapiro#endif /* defined(NEWDB) || defined(NDBM) */
603438032Speter
603538032Speter	if (mode == O_RDONLY)
603638032Speter		return stab_map_open(map, mode);
603738032Speter	else
603838032Speter		return FALSE;
603938032Speter}
604038032Speter
604138032Speter
604238032Speter/*
604338032Speter**  IMPL_MAP_CLOSE -- close any open database(s)
604438032Speter*/
604538032Speter
604638032Spetervoid
604738032Speterimpl_map_close(map)
604838032Speter	MAP *map;
604938032Speter{
605038032Speter	if (tTd(38, 9))
605164562Sgshapiro		dprintf("impl_map_close(%s, %s, %lx)\n",
605238032Speter			map->map_mname, map->map_file, map->map_mflags);
605338032Speter#ifdef NEWDB
605438032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
605538032Speter	{
605638032Speter		db_map_close(map);
605738032Speter		map->map_mflags &= ~MF_IMPL_HASH;
605838032Speter	}
605964562Sgshapiro#endif /* NEWDB */
606038032Speter
606138032Speter#ifdef NDBM
606238032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
606338032Speter	{
606438032Speter		ndbm_map_close(map);
606538032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
606638032Speter	}
606764562Sgshapiro#endif /* NDBM */
606838032Speter}
606938032Speter/*
607038032Speter**  User map class.
607138032Speter**
607238032Speter**	Provides access to the system password file.
607338032Speter*/
607438032Speter
607538032Speter/*
607638032Speter**  USER_MAP_OPEN -- open user map
607738032Speter**
607838032Speter**	Really just binds field names to field numbers.
607938032Speter*/
608038032Speter
608138032Speterbool
608238032Speteruser_map_open(map, mode)
608338032Speter	MAP *map;
608438032Speter	int mode;
608538032Speter{
608638032Speter	if (tTd(38, 2))
608764562Sgshapiro		dprintf("user_map_open(%s, %d)\n",
608838032Speter			map->map_mname, mode);
608938032Speter
609038032Speter	mode &= O_ACCMODE;
609138032Speter	if (mode != O_RDONLY)
609238032Speter	{
609338032Speter		/* issue a pseudo-error message */
609438032Speter#ifdef ENOSYS
609538032Speter		errno = ENOSYS;
609664562Sgshapiro#else /* ENOSYS */
609738032Speter# ifdef EFTYPE
609838032Speter		errno = EFTYPE;
609964562Sgshapiro# else /* EFTYPE */
610038032Speter		errno = ENXIO;
610164562Sgshapiro# endif /* EFTYPE */
610264562Sgshapiro#endif /* ENOSYS */
610338032Speter		return FALSE;
610438032Speter	}
610538032Speter	if (map->map_valcolnm == NULL)
610664562Sgshapiro		/* EMPTY */
610738032Speter		/* nothing */ ;
610838032Speter	else if (strcasecmp(map->map_valcolnm, "name") == 0)
610938032Speter		map->map_valcolno = 1;
611038032Speter	else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
611138032Speter		map->map_valcolno = 2;
611238032Speter	else if (strcasecmp(map->map_valcolnm, "uid") == 0)
611338032Speter		map->map_valcolno = 3;
611438032Speter	else if (strcasecmp(map->map_valcolnm, "gid") == 0)
611538032Speter		map->map_valcolno = 4;
611638032Speter	else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
611738032Speter		map->map_valcolno = 5;
611838032Speter	else if (strcasecmp(map->map_valcolnm, "dir") == 0)
611938032Speter		map->map_valcolno = 6;
612038032Speter	else if (strcasecmp(map->map_valcolnm, "shell") == 0)
612138032Speter		map->map_valcolno = 7;
612238032Speter	else
612338032Speter	{
612438032Speter		syserr("User map %s: unknown column name %s",
612538032Speter			map->map_mname, map->map_valcolnm);
612638032Speter		return FALSE;
612738032Speter	}
612838032Speter	return TRUE;
612938032Speter}
613038032Speter
613138032Speter
613238032Speter/*
613338032Speter**  USER_MAP_LOOKUP -- look up a user in the passwd file.
613438032Speter*/
613538032Speter
613638032Speter/* ARGSUSED3 */
613738032Speterchar *
613838032Speteruser_map_lookup(map, key, av, statp)
613938032Speter	MAP *map;
614038032Speter	char *key;
614138032Speter	char **av;
614238032Speter	int *statp;
614338032Speter{
614438032Speter	struct passwd *pw;
614538032Speter	auto bool fuzzy;
614638032Speter
614738032Speter	if (tTd(38, 20))
614864562Sgshapiro		dprintf("user_map_lookup(%s, %s)\n",
614938032Speter			map->map_mname, key);
615038032Speter
615138032Speter	pw = finduser(key, &fuzzy);
615238032Speter	if (pw == NULL)
615338032Speter		return NULL;
615438032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
615538032Speter		return map_rewrite(map, key, strlen(key), NULL);
615638032Speter	else
615738032Speter	{
615838032Speter		char *rwval = NULL;
615938032Speter		char buf[30];
616038032Speter
616138032Speter		switch (map->map_valcolno)
616238032Speter		{
616338032Speter		  case 0:
616438032Speter		  case 1:
616538032Speter			rwval = pw->pw_name;
616638032Speter			break;
616738032Speter
616838032Speter		  case 2:
616938032Speter			rwval = pw->pw_passwd;
617038032Speter			break;
617138032Speter
617238032Speter		  case 3:
617364562Sgshapiro			snprintf(buf, sizeof buf, "%d", (int) pw->pw_uid);
617438032Speter			rwval = buf;
617538032Speter			break;
617638032Speter
617738032Speter		  case 4:
617864562Sgshapiro			snprintf(buf, sizeof buf, "%d", (int) pw->pw_gid);
617938032Speter			rwval = buf;
618038032Speter			break;
618138032Speter
618238032Speter		  case 5:
618338032Speter			rwval = pw->pw_gecos;
618438032Speter			break;
618538032Speter
618638032Speter		  case 6:
618738032Speter			rwval = pw->pw_dir;
618838032Speter			break;
618938032Speter
619038032Speter		  case 7:
619138032Speter			rwval = pw->pw_shell;
619238032Speter			break;
619338032Speter		}
619438032Speter		return map_rewrite(map, rwval, strlen(rwval), av);
619538032Speter	}
619638032Speter}
619738032Speter/*
619838032Speter**  Program map type.
619938032Speter**
620038032Speter**	This provides access to arbitrary programs.  It should be used
620138032Speter**	only very sparingly, since there is no way to bound the cost
620238032Speter**	of invoking an arbitrary program.
620338032Speter*/
620438032Speter
620538032Speterchar *
620638032Speterprog_map_lookup(map, name, av, statp)
620738032Speter	MAP *map;
620838032Speter	char *name;
620938032Speter	char **av;
621038032Speter	int *statp;
621138032Speter{
621238032Speter	int i;
621364562Sgshapiro	int save_errno;
621438032Speter	int fd;
621564562Sgshapiro	int status;
621638032Speter	auto pid_t pid;
621764562Sgshapiro	register char *p;
621838032Speter	char *rval;
621938032Speter	char *argv[MAXPV + 1];
622038032Speter	char buf[MAXLINE];
622138032Speter
622238032Speter	if (tTd(38, 20))
622364562Sgshapiro		dprintf("prog_map_lookup(%s, %s) %s\n",
622438032Speter			map->map_mname, name, map->map_file);
622538032Speter
622638032Speter	i = 0;
622738032Speter	argv[i++] = map->map_file;
622838032Speter	if (map->map_rebuild != NULL)
622938032Speter	{
623038032Speter		snprintf(buf, sizeof buf, "%s", map->map_rebuild);
623138032Speter		for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
623238032Speter		{
623338032Speter			if (i >= MAXPV - 1)
623438032Speter				break;
623538032Speter			argv[i++] = p;
623638032Speter		}
623738032Speter	}
623838032Speter	argv[i++] = name;
623938032Speter	argv[i] = NULL;
624038032Speter	if (tTd(38, 21))
624138032Speter	{
624264562Sgshapiro		dprintf("prog_open:");
624338032Speter		for (i = 0; argv[i] != NULL; i++)
624464562Sgshapiro			dprintf(" %s", argv[i]);
624564562Sgshapiro		dprintf("\n");
624638032Speter	}
624738032Speter	(void) blocksignal(SIGCHLD);
624838032Speter	pid = prog_open(argv, &fd, CurEnv);
624938032Speter	if (pid < 0)
625038032Speter	{
625138032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
625238032Speter			syserr("prog_map_lookup(%s) failed (%s) -- closing",
625338032Speter				map->map_mname, errstring(errno));
625438032Speter		else if (tTd(38, 9))
625564562Sgshapiro			dprintf("prog_map_lookup(%s) failed (%s) -- closing",
625638032Speter				map->map_mname, errstring(errno));
625738032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
625838032Speter		*statp = EX_OSFILE;
625938032Speter		return NULL;
626038032Speter	}
626138032Speter	i = read(fd, buf, sizeof buf - 1);
626238032Speter	if (i < 0)
626338032Speter	{
626438032Speter		syserr("prog_map_lookup(%s): read error %s\n",
626538032Speter			map->map_mname, errstring(errno));
626638032Speter		rval = NULL;
626738032Speter	}
626838032Speter	else if (i == 0)
626938032Speter	{
627038032Speter		if (tTd(38, 20))
627164562Sgshapiro			dprintf("prog_map_lookup(%s): empty answer\n",
627238032Speter				map->map_mname);
627338032Speter		rval = NULL;
627438032Speter	}
627538032Speter	else
627638032Speter	{
627738032Speter		buf[i] = '\0';
627838032Speter		p = strchr(buf, '\n');
627938032Speter		if (p != NULL)
628038032Speter			*p = '\0';
628138032Speter
628238032Speter		/* collect the return value */
628338032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
628438032Speter			rval = map_rewrite(map, name, strlen(name), NULL);
628538032Speter		else
628638032Speter			rval = map_rewrite(map, buf, strlen(buf), NULL);
628738032Speter
628838032Speter		/* now flush any additional output */
628938032Speter		while ((i = read(fd, buf, sizeof buf)) > 0)
629038032Speter			continue;
629138032Speter	}
629238032Speter
629338032Speter	/* wait for the process to terminate */
629464562Sgshapiro	(void) close(fd);
629564562Sgshapiro	status = waitfor(pid);
629664562Sgshapiro	save_errno = errno;
629738032Speter	(void) releasesignal(SIGCHLD);
629864562Sgshapiro	errno = save_errno;
629938032Speter
630064562Sgshapiro	if (status == -1)
630138032Speter	{
630238032Speter		syserr("prog_map_lookup(%s): wait error %s\n",
630338032Speter			map->map_mname, errstring(errno));
630438032Speter		*statp = EX_SOFTWARE;
630538032Speter		rval = NULL;
630638032Speter	}
630764562Sgshapiro	else if (WIFEXITED(status))
630838032Speter	{
630964562Sgshapiro		if ((*statp = WEXITSTATUS(status)) != EX_OK)
631038032Speter			rval = NULL;
631138032Speter	}
631238032Speter	else
631338032Speter	{
631438032Speter		syserr("prog_map_lookup(%s): child died on signal %d",
631564562Sgshapiro			map->map_mname, status);
631638032Speter		*statp = EX_UNAVAILABLE;
631738032Speter		rval = NULL;
631838032Speter	}
631938032Speter	return rval;
632038032Speter}
632138032Speter/*
632238032Speter**  Sequenced map type.
632338032Speter**
632438032Speter**	Tries each map in order until something matches, much like
632538032Speter**	implicit.  Stores go to the first map in the list that can
632638032Speter**	support storing.
632738032Speter**
632838032Speter**	This is slightly unusual in that there are two interfaces.
632938032Speter**	The "sequence" interface lets you stack maps arbitrarily.
633038032Speter**	The "switch" interface builds a sequence map by looking
633138032Speter**	at a system-dependent configuration file such as
633238032Speter**	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
633338032Speter**
633438032Speter**	We don't need an explicit open, since all maps are
633538032Speter**	opened during startup, including underlying maps.
633638032Speter*/
633738032Speter
633838032Speter/*
633938032Speter**  SEQ_MAP_PARSE -- Sequenced map parsing
634038032Speter*/
634138032Speter
634238032Speterbool
634338032Speterseq_map_parse(map, ap)
634438032Speter	MAP *map;
634538032Speter	char *ap;
634638032Speter{
634738032Speter	int maxmap;
634838032Speter
634938032Speter	if (tTd(38, 2))
635064562Sgshapiro		dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
635138032Speter	maxmap = 0;
635238032Speter	while (*ap != '\0')
635338032Speter	{
635438032Speter		register char *p;
635538032Speter		STAB *s;
635638032Speter
635738032Speter		/* find beginning of map name */
635838032Speter		while (isascii(*ap) && isspace(*ap))
635938032Speter			ap++;
636064562Sgshapiro		for (p = ap;
636164562Sgshapiro		     (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.';
636264562Sgshapiro		     p++)
636338032Speter			continue;
636438032Speter		if (*p != '\0')
636538032Speter			*p++ = '\0';
636638032Speter		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
636738032Speter			p++;
636838032Speter		if (*ap == '\0')
636938032Speter		{
637038032Speter			ap = p;
637138032Speter			continue;
637238032Speter		}
637338032Speter		s = stab(ap, ST_MAP, ST_FIND);
637438032Speter		if (s == NULL)
637538032Speter		{
637638032Speter			syserr("Sequence map %s: unknown member map %s",
637738032Speter				map->map_mname, ap);
637838032Speter		}
637938032Speter		else if (maxmap == MAXMAPSTACK)
638038032Speter		{
638138032Speter			syserr("Sequence map %s: too many member maps (%d max)",
638238032Speter				map->map_mname, MAXMAPSTACK);
638338032Speter			maxmap++;
638438032Speter		}
638538032Speter		else if (maxmap < MAXMAPSTACK)
638638032Speter		{
638738032Speter			map->map_stack[maxmap++] = &s->s_map;
638838032Speter		}
638938032Speter		ap = p;
639038032Speter	}
639138032Speter	return TRUE;
639238032Speter}
639338032Speter
639438032Speter
639538032Speter/*
639638032Speter**  SWITCH_MAP_OPEN -- open a switched map
639738032Speter**
639838032Speter**	This looks at the system-dependent configuration and builds
639938032Speter**	a sequence map that does the same thing.
640038032Speter**
640138032Speter**	Every system must define a switch_map_find routine in conf.c
640238032Speter**	that will return the list of service types associated with a
640338032Speter**	given service class.
640438032Speter*/
640538032Speter
640638032Speterbool
640738032Speterswitch_map_open(map, mode)
640838032Speter	MAP *map;
640938032Speter	int mode;
641038032Speter{
641138032Speter	int mapno;
641238032Speter	int nmaps;
641338032Speter	char *maptype[MAXMAPSTACK];
641438032Speter
641538032Speter	if (tTd(38, 2))
641664562Sgshapiro		dprintf("switch_map_open(%s, %s, %d)\n",
641738032Speter			map->map_mname, map->map_file, mode);
641838032Speter
641938032Speter	mode &= O_ACCMODE;
642038032Speter	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
642138032Speter	if (tTd(38, 19))
642238032Speter	{
642364562Sgshapiro		dprintf("\tswitch_map_find => %d\n", nmaps);
642438032Speter		for (mapno = 0; mapno < nmaps; mapno++)
642564562Sgshapiro			dprintf("\t\t%s\n", maptype[mapno]);
642638032Speter	}
642738032Speter	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
642838032Speter		return FALSE;
642938032Speter
643038032Speter	for (mapno = 0; mapno < nmaps; mapno++)
643138032Speter	{
643238032Speter		register STAB *s;
643338032Speter		char nbuf[MAXNAME + 1];
643438032Speter
643538032Speter		if (maptype[mapno] == NULL)
643638032Speter			continue;
643738032Speter		(void) snprintf(nbuf, sizeof nbuf, "%s.%s",
643838032Speter			map->map_mname, maptype[mapno]);
643938032Speter		s = stab(nbuf, ST_MAP, ST_FIND);
644038032Speter		if (s == NULL)
644138032Speter		{
644238032Speter			syserr("Switch map %s: unknown member map %s",
644338032Speter				map->map_mname, nbuf);
644438032Speter		}
644538032Speter		else
644638032Speter		{
644738032Speter			map->map_stack[mapno] = &s->s_map;
644838032Speter			if (tTd(38, 4))
644964562Sgshapiro				dprintf("\tmap_stack[%d] = %s:%s\n",
645038032Speter					mapno, s->s_map.map_class->map_cname,
645138032Speter					nbuf);
645238032Speter		}
645338032Speter	}
645438032Speter	return TRUE;
645538032Speter}
645638032Speter
645738032Speter
645838032Speter/*
645938032Speter**  SEQ_MAP_CLOSE -- close all underlying maps
646038032Speter*/
646138032Speter
646238032Spetervoid
646338032Speterseq_map_close(map)
646438032Speter	MAP *map;
646538032Speter{
646638032Speter	int mapno;
646738032Speter
646838032Speter	if (tTd(38, 9))
646964562Sgshapiro		dprintf("seq_map_close(%s)\n", map->map_mname);
647038032Speter
647138032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
647238032Speter	{
647338032Speter		MAP *mm = map->map_stack[mapno];
647438032Speter
647538032Speter		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
647638032Speter			continue;
647738032Speter		mm->map_class->map_close(mm);
647838032Speter		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
647938032Speter	}
648038032Speter}
648138032Speter
648238032Speter
648338032Speter/*
648438032Speter**  SEQ_MAP_LOOKUP -- sequenced map lookup
648538032Speter*/
648638032Speter
648738032Speterchar *
648838032Speterseq_map_lookup(map, key, args, pstat)
648938032Speter	MAP *map;
649038032Speter	char *key;
649138032Speter	char **args;
649238032Speter	int *pstat;
649338032Speter{
649438032Speter	int mapno;
649538032Speter	int mapbit = 0x01;
649638032Speter	bool tempfail = FALSE;
649738032Speter
649838032Speter	if (tTd(38, 20))
649964562Sgshapiro		dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
650038032Speter
650138032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
650238032Speter	{
650338032Speter		MAP *mm = map->map_stack[mapno];
650438032Speter		char *rv;
650538032Speter
650638032Speter		if (mm == NULL)
650738032Speter			continue;
650864562Sgshapiro		if (!bitset(MF_OPEN, mm->map_mflags) &&
650964562Sgshapiro		    !openmap(mm))
651038032Speter		{
651138032Speter			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
651238032Speter			{
651338032Speter				*pstat = EX_UNAVAILABLE;
651438032Speter				return NULL;
651538032Speter			}
651638032Speter			continue;
651738032Speter		}
651838032Speter		*pstat = EX_OK;
651938032Speter		rv = mm->map_class->map_lookup(mm, key, args, pstat);
652038032Speter		if (rv != NULL)
652138032Speter			return rv;
652238032Speter		if (*pstat == EX_TEMPFAIL)
652338032Speter		{
652438032Speter			if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
652538032Speter				return NULL;
652638032Speter			tempfail = TRUE;
652738032Speter		}
652838032Speter		else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
652938032Speter			break;
653038032Speter	}
653138032Speter	if (tempfail)
653238032Speter		*pstat = EX_TEMPFAIL;
653338032Speter	else if (*pstat == EX_OK)
653438032Speter		*pstat = EX_NOTFOUND;
653538032Speter	return NULL;
653638032Speter}
653738032Speter
653838032Speter
653938032Speter/*
654038032Speter**  SEQ_MAP_STORE -- sequenced map store
654138032Speter*/
654238032Speter
654338032Spetervoid
654438032Speterseq_map_store(map, key, val)
654538032Speter	MAP *map;
654638032Speter	char *key;
654738032Speter	char *val;
654838032Speter{
654938032Speter	int mapno;
655038032Speter
655138032Speter	if (tTd(38, 12))
655264562Sgshapiro		dprintf("seq_map_store(%s, %s, %s)\n",
655338032Speter			map->map_mname, key, val);
655438032Speter
655538032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
655638032Speter	{
655738032Speter		MAP *mm = map->map_stack[mapno];
655838032Speter
655938032Speter		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
656038032Speter			continue;
656138032Speter
656238032Speter		mm->map_class->map_store(mm, key, val);
656338032Speter		return;
656438032Speter	}
656538032Speter	syserr("seq_map_store(%s, %s, %s): no writable map",
656638032Speter		map->map_mname, key, val);
656738032Speter}
656838032Speter/*
656938032Speter**  NULL stubs
657038032Speter*/
657138032Speter
657238032Speter/* ARGSUSED */
657338032Speterbool
657438032Speternull_map_open(map, mode)
657538032Speter	MAP *map;
657638032Speter	int mode;
657738032Speter{
657838032Speter	return TRUE;
657938032Speter}
658038032Speter
658138032Speter/* ARGSUSED */
658238032Spetervoid
658338032Speternull_map_close(map)
658438032Speter	MAP *map;
658538032Speter{
658638032Speter	return;
658738032Speter}
658838032Speter
658938032Speterchar *
659038032Speternull_map_lookup(map, key, args, pstat)
659138032Speter	MAP *map;
659238032Speter	char *key;
659338032Speter	char **args;
659438032Speter	int *pstat;
659538032Speter{
659638032Speter	*pstat = EX_NOTFOUND;
659738032Speter	return NULL;
659838032Speter}
659938032Speter
660038032Speter/* ARGSUSED */
660138032Spetervoid
660238032Speternull_map_store(map, key, val)
660338032Speter	MAP *map;
660438032Speter	char *key;
660538032Speter	char *val;
660638032Speter{
660738032Speter	return;
660838032Speter}
660938032Speter
661038032Speter
661138032Speter/*
661238032Speter**  BOGUS stubs
661338032Speter*/
661438032Speter
661538032Speterchar *
661638032Speterbogus_map_lookup(map, key, args, pstat)
661738032Speter	MAP *map;
661838032Speter	char *key;
661938032Speter	char **args;
662038032Speter	int *pstat;
662138032Speter{
662238032Speter	*pstat = EX_TEMPFAIL;
662338032Speter	return NULL;
662438032Speter}
662538032Speter
662638032SpeterMAPCLASS	BogusMapClass =
662738032Speter{
662838032Speter	"bogus-map",		NULL,		0,
662938032Speter	NULL,		bogus_map_lookup,	null_map_store,
663038032Speter	null_map_open,	null_map_close,
663138032Speter};
663238032Speter/*
663364562Sgshapiro**  MACRO modules
663464562Sgshapiro*/
663564562Sgshapiro
663664562Sgshapirochar *
663764562Sgshapiromacro_map_lookup(map, name, av, statp)
663864562Sgshapiro	MAP *map;
663964562Sgshapiro	char *name;
664064562Sgshapiro	char **av;
664164562Sgshapiro	int *statp;
664264562Sgshapiro{
664364562Sgshapiro	int mid;
664464562Sgshapiro
664564562Sgshapiro	if (tTd(38, 20))
664664562Sgshapiro		dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
664764562Sgshapiro			name == NULL ? "NULL" : name);
664864562Sgshapiro
664964562Sgshapiro	if (name == NULL ||
665064562Sgshapiro	    *name == '\0' ||
665164562Sgshapiro	    (mid = macid(name, NULL)) == '\0')
665264562Sgshapiro	{
665364562Sgshapiro		*statp = EX_CONFIG;
665464562Sgshapiro		return NULL;
665564562Sgshapiro	}
665664562Sgshapiro
665764562Sgshapiro	if (av[1] == NULL)
665864562Sgshapiro		define(mid, NULL, CurEnv);
665964562Sgshapiro	else
666064562Sgshapiro		define(mid, newstr(av[1]), CurEnv);
666164562Sgshapiro
666264562Sgshapiro	*statp = EX_OK;
666364562Sgshapiro	return "";
666464562Sgshapiro}
666564562Sgshapiro/*
666638032Speter**  REGEX modules
666738032Speter*/
666838032Speter
666938032Speter#ifdef MAP_REGEX
667038032Speter
667138032Speter# include <regex.h>
667238032Speter
667338032Speter# define DEFAULT_DELIM	CONDELSE
667438032Speter
667538032Speter# define END_OF_FIELDS	-1
667638032Speter
667738032Speter# define ERRBUF_SIZE	80
667838032Speter# define MAX_MATCH	32
667938032Speter
668064562Sgshapiro# define xnalloc(s)	memset(xalloc(s), '\0', s);
668138032Speter
668238032Speterstruct regex_map
668338032Speter{
668464562Sgshapiro	regex_t	regex_pattern_buf;	/* xalloc it */
668538032Speter	int	*regex_subfields;	/* move to type MAP */
668664562Sgshapiro	char	*regex_delim;		/* move to type MAP */
668738032Speter};
668838032Speter
668938032Speterstatic int
669038032Speterparse_fields(s, ibuf, blen, nr_substrings)
669138032Speter	char *s;
669238032Speter	int *ibuf;		/* array */
669338032Speter	int blen;		/* number of elements in ibuf */
669438032Speter	int nr_substrings;	/* number of substrings in the pattern */
669538032Speter{
669638032Speter	register char *cp;
669738032Speter	int i = 0;
669838032Speter	bool lastone = FALSE;
669938032Speter
670038032Speter	blen--;		/* for terminating END_OF_FIELDS */
670138032Speter	cp = s;
670238032Speter	do
670338032Speter	{
670438032Speter		for (;; cp++)
670538032Speter		{
670638032Speter			if (*cp == ',')
670738032Speter			{
670838032Speter				*cp = '\0';
670938032Speter				break;
671038032Speter			}
671138032Speter			if (*cp == '\0')
671238032Speter			{
671338032Speter				lastone = TRUE;
671438032Speter				break;
671538032Speter			}
671638032Speter		}
671738032Speter		if (i < blen)
671838032Speter		{
671938032Speter			int val = atoi(s);
672038032Speter
672138032Speter			if (val < 0 || val >= nr_substrings)
672238032Speter			{
672338032Speter				syserr("field (%d) out of range, only %d substrings in pattern",
672438032Speter				       val, nr_substrings);
672538032Speter				return -1;
672638032Speter			}
672738032Speter			ibuf[i++] = val;
672838032Speter		}
672938032Speter		else
673038032Speter		{
673138032Speter			syserr("too many fields, %d max\n", blen);
673238032Speter			return -1;
673338032Speter		}
673438032Speter		s = ++cp;
673538032Speter	} while (!lastone);
673638032Speter	ibuf[i] = END_OF_FIELDS;
673738032Speter	return i;
673838032Speter}
673938032Speter
674038032Speterbool
674138032Speterregex_map_init(map, ap)
674238032Speter	MAP *map;
674338032Speter	char *ap;
674438032Speter{
674538032Speter	int regerr;
674638032Speter	struct regex_map *map_p;
674738032Speter	register char *p;
674838032Speter	char *sub_param = NULL;
674938032Speter	int pflags;
675038032Speter	static char defdstr[] = { (char)DEFAULT_DELIM, '\0' };
675138032Speter
675238032Speter	if (tTd(38, 2))
675364562Sgshapiro		dprintf("regex_map_init: mapname '%s', args '%s'\n",
675464562Sgshapiro			map->map_mname, ap);
675538032Speter
675638032Speter	pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
675738032Speter
675838032Speter	p = ap;
675938032Speter
676064562Sgshapiro	map_p = (struct regex_map *) xnalloc(sizeof *map_p);
676138032Speter
676238032Speter	for (;;)
676364562Sgshapiro	{
676438032Speter		while (isascii(*p) && isspace(*p))
676538032Speter			p++;
676638032Speter		if (*p != '-')
676738032Speter			break;
676838032Speter		switch (*++p)
676938032Speter		{
677038032Speter		  case 'n':	/* not */
677138032Speter			map->map_mflags |= MF_REGEX_NOT;
677238032Speter			break;
677338032Speter
677438032Speter		  case 'f':	/* case sensitive */
677538032Speter			map->map_mflags |= MF_NOFOLDCASE;
677638032Speter			pflags &= ~REG_ICASE;
677738032Speter			break;
677838032Speter
677938032Speter		  case 'b':	/* basic regular expressions */
678038032Speter			pflags &= ~REG_EXTENDED;
678138032Speter			break;
678238032Speter
678338032Speter		  case 's':	/* substring match () syntax */
678438032Speter			sub_param = ++p;
678538032Speter			pflags &= ~REG_NOSUB;
678638032Speter			break;
678738032Speter
678838032Speter		  case 'd':	/* delimiter */
678964562Sgshapiro			map_p->regex_delim = ++p;
679038032Speter			break;
679138032Speter
679238032Speter		  case 'a':	/* map append */
679338032Speter			map->map_app = ++p;
679438032Speter			break;
679538032Speter
679638032Speter		  case 'm':	/* matchonly */
679738032Speter			map->map_mflags |= MF_MATCHONLY;
679838032Speter			break;
679938032Speter
680064562Sgshapiro		  case 'S':
680164562Sgshapiro			map->map_spacesub = *++p;
680264562Sgshapiro			break;
680364562Sgshapiro
680464562Sgshapiro		  case 'D':
680564562Sgshapiro			map->map_mflags |= MF_DEFER;
680664562Sgshapiro			break;
680764562Sgshapiro
680838032Speter		}
680964562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
681064562Sgshapiro			p++;
681164562Sgshapiro		if (*p != '\0')
681264562Sgshapiro			*p++ = '\0';
681338032Speter	}
681438032Speter	if (tTd(38, 3))
681564562Sgshapiro		dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
681638032Speter
681764562Sgshapiro	if ((regerr = regcomp(&(map_p->regex_pattern_buf), p, pflags)) != 0)
681838032Speter	{
681938032Speter		/* Errorhandling */
682038032Speter		char errbuf[ERRBUF_SIZE];
682138032Speter
682264562Sgshapiro		(void) regerror(regerr, &(map_p->regex_pattern_buf),
682364562Sgshapiro			 errbuf, ERRBUF_SIZE);
682438032Speter		syserr("pattern-compile-error: %s\n", errbuf);
682538032Speter		free(map_p);
682638032Speter		return FALSE;
682738032Speter	}
682838032Speter
682938032Speter	if (map->map_app != NULL)
683038032Speter		map->map_app = newstr(map->map_app);
683164562Sgshapiro	if (map_p->regex_delim != NULL)
683264562Sgshapiro		map_p->regex_delim = newstr(map_p->regex_delim);
683338032Speter	else
683464562Sgshapiro		map_p->regex_delim = defdstr;
683538032Speter
683638032Speter	if (!bitset(REG_NOSUB, pflags))
683738032Speter	{
683838032Speter		/* substring matching */
683938032Speter		int substrings;
684064562Sgshapiro		int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1));
684138032Speter
684264562Sgshapiro		substrings = map_p->regex_pattern_buf.re_nsub + 1;
684338032Speter
684438032Speter		if (tTd(38, 3))
684564562Sgshapiro			dprintf("regex_map_init: nr of substrings %d\n",
684664562Sgshapiro				substrings);
684738032Speter
684838032Speter		if (substrings >= MAX_MATCH)
684938032Speter		{
685038032Speter			syserr("too many substrings, %d max\n", MAX_MATCH);
685138032Speter			free(map_p);
685238032Speter			return FALSE;
685338032Speter		}
685438032Speter		if (sub_param != NULL && sub_param[0] != '\0')
685538032Speter		{
685638032Speter			/* optional parameter -sfields */
685738032Speter			if (parse_fields(sub_param, fields,
685838032Speter					 MAX_MATCH + 1, substrings) == -1)
685938032Speter				return FALSE;
686038032Speter		}
686138032Speter		else
686238032Speter		{
686364562Sgshapiro			/* set default fields */
686438032Speter			int i;
686538032Speter
686638032Speter			for (i = 0; i < substrings; i++)
686738032Speter				fields[i] = i;
686838032Speter			fields[i] = END_OF_FIELDS;
686938032Speter		}
687038032Speter		map_p->regex_subfields = fields;
687138032Speter		if (tTd(38, 3))
687238032Speter		{
687338032Speter			int *ip;
687438032Speter
687564562Sgshapiro			dprintf("regex_map_init: subfields");
687638032Speter			for (ip = fields; *ip != END_OF_FIELDS; ip++)
687764562Sgshapiro				dprintf(" %d", *ip);
687864562Sgshapiro			dprintf("\n");
687938032Speter		}
688038032Speter	}
688138032Speter	map->map_db1 = (ARBPTR_T)map_p;	/* dirty hack */
688238032Speter
688338032Speter	return TRUE;
688438032Speter}
688538032Speter
688638032Speterstatic char *
688738032Speterregex_map_rewrite(map, s, slen, av)
688838032Speter	MAP *map;
688938032Speter	const char *s;
689038032Speter	size_t slen;
689138032Speter	char **av;
689238032Speter{
689338032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
689438032Speter		return map_rewrite(map, av[0], strlen(av[0]), NULL);
689538032Speter	else
689638032Speter		return map_rewrite(map, s, slen, NULL);
689738032Speter}
689838032Speter
689938032Speterchar *
690038032Speterregex_map_lookup(map, name, av, statp)
690138032Speter	MAP *map;
690238032Speter	char *name;
690338032Speter	char **av;
690438032Speter	int *statp;
690538032Speter{
690638032Speter	int reg_res;
690738032Speter	struct regex_map *map_p;
690838032Speter	regmatch_t pmatch[MAX_MATCH];
690938032Speter
691038032Speter	if (tTd(38, 20))
691138032Speter	{
691238032Speter		char **cpp;
691338032Speter
691464562Sgshapiro		dprintf("regex_map_lookup: key '%s'\n", name);
691564562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
691664562Sgshapiro			dprintf("regex_map_lookup: arg '%s'\n", *cpp);
691738032Speter	}
691838032Speter
691938032Speter	map_p = (struct regex_map *)(map->map_db1);
692064562Sgshapiro	reg_res = regexec(&(map_p->regex_pattern_buf),
692164562Sgshapiro			  name, MAX_MATCH, pmatch, 0);
692238032Speter
692338032Speter	if (bitset(MF_REGEX_NOT, map->map_mflags))
692438032Speter	{
692538032Speter		/* option -n */
692638032Speter		if (reg_res == REG_NOMATCH)
692738032Speter			return regex_map_rewrite(map, "", (size_t)0, av);
692838032Speter		else
692938032Speter			return NULL;
693038032Speter	}
693138032Speter	if (reg_res == REG_NOMATCH)
693238032Speter		return NULL;
693338032Speter
693438032Speter	if (map_p->regex_subfields != NULL)
693538032Speter	{
693638032Speter		/* option -s */
693738032Speter		static char retbuf[MAXNAME];
693838032Speter		int fields[MAX_MATCH + 1];
693938032Speter		bool first = TRUE;
694038032Speter		int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
694138032Speter		bool quotemode = FALSE, bslashmode = FALSE;
694238032Speter		register char *dp, *sp;
694338032Speter		char *endp, *ldp;
694438032Speter		int *ip;
694538032Speter
694638032Speter		dp = retbuf;
694738032Speter		ldp = retbuf + sizeof(retbuf) - 1;
694838032Speter
694938032Speter		if (av[1] != NULL)
695038032Speter		{
695138032Speter			if (parse_fields(av[1], fields, MAX_MATCH + 1,
695264562Sgshapiro					 (int) map_p->regex_pattern_buf.re_nsub + 1) == -1)
695338032Speter			{
695438032Speter				*statp = EX_CONFIG;
695538032Speter				return NULL;
695638032Speter			}
695738032Speter			ip = fields;
695838032Speter		}
695938032Speter		else
696038032Speter			ip = map_p->regex_subfields;
696138032Speter
696238032Speter		for ( ; *ip != END_OF_FIELDS; ip++)
696338032Speter		{
696438032Speter			if (!first)
696538032Speter			{
696664562Sgshapiro				for (sp = map_p->regex_delim; *sp; sp++)
696738032Speter				{
696838032Speter					if (dp < ldp)
696938032Speter						*dp++ = *sp;
697038032Speter				}
697138032Speter			}
697238032Speter			else
697338032Speter				first = FALSE;
697438032Speter
697538032Speter
697638032Speter			if (pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
697738032Speter				continue;
697838032Speter
697938032Speter			sp = name + pmatch[*ip].rm_so;
698038032Speter			endp = name + pmatch[*ip].rm_eo;
698138032Speter			for (; endp > sp; sp++)
698238032Speter			{
698338032Speter				if (dp < ldp)
698438032Speter				{
698564562Sgshapiro					if (bslashmode)
698664562Sgshapiro					{
698738032Speter						*dp++ = *sp;
698838032Speter						bslashmode = FALSE;
698938032Speter					}
699064562Sgshapiro					else if (quotemode && *sp != '"' &&
699138032Speter						*sp != '\\')
699238032Speter					{
699338032Speter						*dp++ = *sp;
699438032Speter					}
699538032Speter					else switch(*dp++ = *sp)
699638032Speter					{
699738032Speter						case '\\':
699838032Speter						bslashmode = TRUE;
699938032Speter						break;
700038032Speter
700138032Speter						case '(':
700238032Speter						cmntcnt++;
700338032Speter						break;
700438032Speter
700538032Speter						case ')':
700638032Speter						cmntcnt--;
700738032Speter						break;
700838032Speter
700938032Speter						case '<':
701038032Speter						anglecnt++;
701138032Speter						break;
701238032Speter
701338032Speter						case '>':
701438032Speter						anglecnt--;
701538032Speter						break;
701638032Speter
701738032Speter						case ' ':
701838032Speter						spacecnt++;
701938032Speter						break;
702038032Speter
702138032Speter						case '"':
702238032Speter						quotemode = !quotemode;
702338032Speter						break;
702438032Speter					}
702538032Speter				}
702638032Speter			}
702738032Speter		}
702838032Speter		if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
702938032Speter		    bslashmode || spacecnt != 0)
703038032Speter		{
703164562Sgshapiro			sm_syslog(LOG_WARNING, NOQID,
703264562Sgshapiro				  "Warning: regex may cause prescan() failure map=%s lookup=%s",
703364562Sgshapiro				  map->map_mname, name);
703438032Speter			return NULL;
703538032Speter		}
703638032Speter
703738032Speter		*dp = '\0';
703838032Speter
703938032Speter		return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
704038032Speter	}
704138032Speter	return regex_map_rewrite(map, "", (size_t)0, av);
704238032Speter}
704338032Speter#endif /* MAP_REGEX */
704464562Sgshapiro/*
704564562Sgshapiro**  NSD modules
704664562Sgshapiro*/
704764562Sgshapiro#ifdef MAP_NSD
704864562Sgshapiro
704964562Sgshapiro# include <ndbm.h>
705064562Sgshapiro# define _DATUM_DEFINED
705164562Sgshapiro# include <ns_api.h>
705264562Sgshapiro
705364562Sgshapirotypedef struct ns_map_list
705464562Sgshapiro{
705564562Sgshapiro	ns_map_t *map;
705664562Sgshapiro	char *mapname;
705764562Sgshapiro	struct ns_map_list *next;
705864562Sgshapiro} ns_map_list_t;
705964562Sgshapiro
706064562Sgshapirostatic ns_map_t *
706164562Sgshapirons_map_t_find(mapname)
706264562Sgshapiro	char *mapname;
706364562Sgshapiro{
706464562Sgshapiro	static ns_map_list_t *ns_maps = NULL;
706564562Sgshapiro	ns_map_list_t *ns_map;
706664562Sgshapiro
706764562Sgshapiro	/* walk the list of maps looking for the correctly named map */
706864562Sgshapiro	for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next)
706964562Sgshapiro	{
707064562Sgshapiro		if (strcmp(ns_map->mapname, mapname) == 0)
707164562Sgshapiro			break;
707264562Sgshapiro	}
707364562Sgshapiro
707464562Sgshapiro	/* if we are looking at a NULL ns_map_list_t, then create a new one */
707564562Sgshapiro	if (ns_map == NULL)
707664562Sgshapiro	{
707764562Sgshapiro		ns_map = (ns_map_list_t *) xalloc(sizeof *ns_map);
707864562Sgshapiro		ns_map->mapname = newstr(mapname);
707964562Sgshapiro		ns_map->map = (ns_map_t *) xalloc(sizeof *ns_map->map);
708064562Sgshapiro		ns_map->next = ns_maps;
708164562Sgshapiro		ns_maps = ns_map;
708264562Sgshapiro	}
708364562Sgshapiro	return ns_map->map;
708464562Sgshapiro}
708564562Sgshapiro
708664562Sgshapirochar *
708764562Sgshapironsd_map_lookup(map, name, av, statp)
708864562Sgshapiro	MAP *map;
708964562Sgshapiro	char *name;
709064562Sgshapiro	char **av;
709164562Sgshapiro	int *statp;
709264562Sgshapiro{
709364562Sgshapiro	int buflen;
709464562Sgshapiro	char *p;
709564562Sgshapiro	ns_map_t *ns_map;
709664562Sgshapiro	char keybuf[MAXNAME + 1];
709764562Sgshapiro	char buf[MAXLINE];
709864562Sgshapiro
709964562Sgshapiro	if (tTd(38, 20))
710064562Sgshapiro		dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
710164562Sgshapiro
710264562Sgshapiro	buflen = strlen(name);
710364562Sgshapiro	if (buflen > sizeof keybuf - 1)
710464562Sgshapiro		buflen = sizeof keybuf - 1;
710564562Sgshapiro	memmove(keybuf, name, buflen);
710664562Sgshapiro	keybuf[buflen] = '\0';
710764562Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
710864562Sgshapiro		makelower(keybuf);
710964562Sgshapiro
711064562Sgshapiro	ns_map = ns_map_t_find(map->map_file);
711164562Sgshapiro	if (ns_map == NULL)
711264562Sgshapiro	{
711364562Sgshapiro		if (tTd(38, 20))
711464562Sgshapiro			dprintf("nsd_map_t_find failed\n");
711564562Sgshapiro		return NULL;
711664562Sgshapiro	}
711764562Sgshapiro
711864562Sgshapiro	if (ns_lookup(ns_map, NULL, map->map_file,
711964562Sgshapiro		      keybuf, NULL, buf, MAXLINE) == NULL)
712064562Sgshapiro		return NULL;
712164562Sgshapiro
712264562Sgshapiro	/* Null out trailing \n */
712364562Sgshapiro	if ((p = strchr(buf, '\n')) != NULL)
712464562Sgshapiro		*p = '\0';
712564562Sgshapiro
712664562Sgshapiro	return map_rewrite(map, buf, strlen(buf), av);
712764562Sgshapiro}
712864562Sgshapiro#endif /* MAP_NSD */
712964562Sgshapiro
713064562Sgshapirochar *
713164562Sgshapiroarith_map_lookup(map, name, av, statp)
713264562Sgshapiro	MAP *map;
713364562Sgshapiro	char *name;
713464562Sgshapiro	char **av;
713564562Sgshapiro	int *statp;
713664562Sgshapiro{
713764562Sgshapiro	long r;
713864562Sgshapiro	long v[2];
713964562Sgshapiro	bool res = FALSE;
714064562Sgshapiro	bool boolres;
714164562Sgshapiro	static char result[16];
714264562Sgshapiro	char **cpp;
714364562Sgshapiro
714464562Sgshapiro	if (tTd(38, 2))
714564562Sgshapiro	{
714664562Sgshapiro		dprintf("arith_map_lookup: key '%s'\n", name);
714764562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
714864562Sgshapiro			dprintf("arith_map_lookup: arg '%s'\n", *cpp);
714964562Sgshapiro	}
715064562Sgshapiro	r = 0;
715164562Sgshapiro	boolres = FALSE;
715264562Sgshapiro	cpp = av;
715364562Sgshapiro	*statp = EX_OK;
715464562Sgshapiro
715564562Sgshapiro	/*
715664562Sgshapiro	**  read arguments for arith map
715764562Sgshapiro	**  - no check is made whether they are really numbers
715864562Sgshapiro	**  - just ignores args after the second
715964562Sgshapiro	*/
716064562Sgshapiro	for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
716164562Sgshapiro		v[r++] = strtol(*cpp, NULL, 0);
716264562Sgshapiro
716364562Sgshapiro	/* operator and (at least) two operands given? */
716464562Sgshapiro	if (name != NULL && r == 2)
716564562Sgshapiro	{
716664562Sgshapiro		switch(*name)
716764562Sgshapiro		{
716864562Sgshapiro#if _FFR_ARITH
716964562Sgshapiro		  case '|':
717064562Sgshapiro			r = v[0] | v[1];
717164562Sgshapiro			break;
717264562Sgshapiro
717364562Sgshapiro		  case '&':
717464562Sgshapiro			r = v[0] & v[1];
717564562Sgshapiro			break;
717664562Sgshapiro
717764562Sgshapiro		  case '%':
717864562Sgshapiro			if (v[1] == 0)
717964562Sgshapiro				return NULL;
718064562Sgshapiro			r = v[0] % v[1];
718164562Sgshapiro			break;
718264562Sgshapiro#endif /* _FFR_ARITH */
718364562Sgshapiro
718464562Sgshapiro		  case '+':
718564562Sgshapiro			r = v[0] + v[1];
718664562Sgshapiro			break;
718764562Sgshapiro
718864562Sgshapiro		  case '-':
718964562Sgshapiro			r = v[0] - v[1];
719064562Sgshapiro			break;
719164562Sgshapiro
719264562Sgshapiro		  case '*':
719364562Sgshapiro			r = v[0] * v[1];
719464562Sgshapiro			break;
719564562Sgshapiro
719664562Sgshapiro		  case '/':
719764562Sgshapiro			if (v[1] == 0)
719864562Sgshapiro				return NULL;
719964562Sgshapiro			r = v[0] / v[1];
720064562Sgshapiro			break;
720164562Sgshapiro
720264562Sgshapiro		  case 'l':
720364562Sgshapiro			res = v[0] < v[1];
720464562Sgshapiro			boolres = TRUE;
720564562Sgshapiro			break;
720664562Sgshapiro
720764562Sgshapiro		  case '=':
720864562Sgshapiro			res = v[0] == v[1];
720964562Sgshapiro			boolres = TRUE;
721064562Sgshapiro			break;
721164562Sgshapiro
721264562Sgshapiro		  default:
721364562Sgshapiro			/* XXX */
721464562Sgshapiro			*statp = EX_CONFIG;
721564562Sgshapiro			if (LogLevel > 10)
721664562Sgshapiro				sm_syslog(LOG_WARNING, NOQID,
721764562Sgshapiro					  "arith_map: unknown operator %c",
721864562Sgshapiro					  isprint(*name) ? *name : '?');
721964562Sgshapiro			return NULL;
722064562Sgshapiro		}
722164562Sgshapiro		if (boolres)
722264562Sgshapiro			snprintf(result, sizeof result, res ? "TRUE" : "FALSE");
722364562Sgshapiro		else
722464562Sgshapiro			snprintf(result, sizeof result, "%ld", r);
722564562Sgshapiro		return result;
722664562Sgshapiro	}
722764562Sgshapiro	*statp = EX_CONFIG;
722864562Sgshapiro	return NULL;
722964562Sgshapiro}
7230