map.c revision 66494
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
1566494Sgshapirostatic char id[] = "@(#)$Id: map.c,v 8.414.4.24 2000/09/27 04:11:29 gshapiro Exp $";
1664562Sgshapiro#endif /* ! lint */
1738032Speter
1864562Sgshapiro#include <sendmail.h>
1938032Speter
2064562Sgshapiro
2138032Speter#ifdef NDBM
2238032Speter# include <ndbm.h>
2338032Speter# ifdef R_FIRST
2438032Speter  ERROR README:	You are running the Berkeley DB version of ndbm.h.  See
2538032Speter  ERROR README:	the README file about tweaking Berkeley DB so it can
2638032Speter  ERROR README:	coexist with NDBM, or delete -DNDBM from the Makefile
2738032Speter  ERROR README: and use -DNEWDB instead.
2864562Sgshapiro# endif /* R_FIRST */
2964562Sgshapiro#endif /* NDBM */
3038032Speter#ifdef NEWDB
3138032Speter# include <db.h>
3238032Speter# ifndef DB_VERSION_MAJOR
3338032Speter#  define DB_VERSION_MAJOR 1
3464562Sgshapiro# endif /* ! DB_VERSION_MAJOR */
3564562Sgshapiro#endif /* NEWDB */
3638032Speter#ifdef NIS
3738032Speter  struct dom_binding;	/* forward reference needed on IRIX */
3838032Speter# include <rpcsvc/ypclnt.h>
3938032Speter# ifdef NDBM
4038032Speter#  define NDBM_YP_COMPAT	/* create YP-compatible NDBM files */
4164562Sgshapiro# endif /* NDBM */
4264562Sgshapiro#endif /* NIS */
4338032Speter
4464562Sgshapiro#ifdef NEWDB
4564562Sgshapiro# if DB_VERSION_MAJOR < 2
4664562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
4764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
4864562Sgshapiro# if DB_VERSION_MAJOR == 2
4964562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
5064562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
5164562Sgshapiro# if DB_VERSION_MAJOR > 2
5264562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, void **));
5364562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
5464562Sgshapiro#endif /* NEWDB */
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();
57166494Sgshapiro			MapOpenErr = TRUE;
57238032Speter		}
57364562Sgshapiro		else
57464562Sgshapiro		{
57564562Sgshapiro			/* don't try again */
57664562Sgshapiro			map->map_mflags &= ~MF_VALID;
57764562Sgshapiro		}
57838032Speter	}
57964562Sgshapiro
58064562Sgshapiro	if (restore)
58164562Sgshapiro	{
58264562Sgshapiro		Errors = saveerrors;
58364562Sgshapiro		HoldErrs = savehold;
58464562Sgshapiro		QuickAbort = savequick;
58564562Sgshapiro	}
58664562Sgshapiro
58764562Sgshapiro	return bitset(MF_OPEN, map->map_mflags);
58838032Speter}
58938032Speter/*
59042575Speter**  CLOSEMAPS -- close all open maps opened by the current pid.
59142575Speter**
59242575Speter**	Parameters:
59342575Speter**		none
59442575Speter**
59542575Speter**	Returns:
59642575Speter**		none.
59742575Speter*/
59842575Speter
59942575Spetervoid
60042575Speterclosemaps()
60142575Speter{
60242575Speter	stabapply(map_close, 0);
60342575Speter}
60464562Sgshapiro/*
60564562Sgshapiro**  MAP_CLOSE -- close a map opened by the current pid.
60664562Sgshapiro**
60764562Sgshapiro**	Parameters:
60864562Sgshapiro**		s -- STAB entry: if map: try to open
60964562Sgshapiro**		second parameter is unused (required by stabapply())
61064562Sgshapiro**
61164562Sgshapiro**	Returns:
61264562Sgshapiro**		none.
61364562Sgshapiro*/
61442575Speter
61542575Speter/* ARGSUSED1 */
61664562Sgshapirostatic void
61742575Spetermap_close(s, unused)
61842575Speter	register STAB *s;
61942575Speter	int unused;
62042575Speter{
62142575Speter	MAP *map;
62242575Speter
62342575Speter	if (s->s_type != ST_MAP)
62442575Speter		return;
62564562Sgshapiro
62642575Speter	map = &s->s_map;
62742575Speter
62842575Speter	if (!bitset(MF_VALID, map->map_mflags) ||
62942575Speter	    !bitset(MF_OPEN, 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))
281366494Sgshapiro		dprintf("ldapmap_open(%s, %d): ", 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;
284466494Sgshapiro		if (tTd(38, 2))
284566494Sgshapiro			dprintf("using cached connection\n");
284664562Sgshapiro		return TRUE;
284764562Sgshapiro	}
284864562Sgshapiro
284966494Sgshapiro	if (tTd(38, 2))
285066494Sgshapiro		dprintf("opening new connection\n");
285166494Sgshapiro
285264562Sgshapiro	/* No connection yet, connect */
285364562Sgshapiro	if (!ldapmap_start(map))
285464562Sgshapiro		return FALSE;
285564562Sgshapiro
285664562Sgshapiro	/* Save connection for reuse */
285764562Sgshapiro	s->s_ldap = lmap->ldap_ld;
285838032Speter	return TRUE;
285938032Speter}
286038032Speter
286138032Speter/*
286264562Sgshapiro**  LDAPMAP_START -- actually connect to an LDAP server
286338032Speter**
286464562Sgshapiro**	Parameters:
286564562Sgshapiro**		map -- the map being opened.
286664562Sgshapiro**
286764562Sgshapiro**	Returns:
286864562Sgshapiro**		TRUE if connection is successful, FALSE otherwise.
286964562Sgshapiro**
287064562Sgshapiro**	Side Effects:
287164562Sgshapiro**		Populates lmap->ldap_ld.
287238032Speter*/
287338032Speter
287438032Speterstatic jmp_buf	LDAPTimeout;
287538032Speter
287664562Sgshapirostatic bool
287764562Sgshapiroldapmap_start(map)
287838032Speter	MAP *map;
287938032Speter{
288064562Sgshapiro	register int bind_result;
288164562Sgshapiro	int save_errno;
288264562Sgshapiro	register EVENT *ev = NULL;
288364562Sgshapiro	LDAPMAP_STRUCT *lmap;
288438032Speter	LDAP *ld;
288538032Speter
288638032Speter	if (tTd(38, 2))
288764562Sgshapiro		dprintf("ldapmap_start(%s)\n", map->map_mname);
288838032Speter
288964562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
289038032Speter
289138032Speter	if (tTd(38,9))
289264562Sgshapiro		dprintf("ldapmap_start(%s, %d)\n",
289364562Sgshapiro			lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host,
289464562Sgshapiro			lmap->ldap_port);
289538032Speter
289664562Sgshapiro# if USE_LDAP_INIT
289764562Sgshapiro	ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
289864562Sgshapiro# else /* USE_LDAP_INIT */
289964562Sgshapiro	/*
290064562Sgshapiro	**  If using ldap_open(), the actual connection to the server
290164562Sgshapiro	**  happens now so we need the timeout here.  For ldap_init(),
290264562Sgshapiro	**  the connection happens at bind time.
290364562Sgshapiro	*/
290438032Speter
290538032Speter	/* set the timeout */
290664562Sgshapiro	if (lmap->ldap_timeout.tv_sec != 0)
290738032Speter	{
290838032Speter		if (setjmp(LDAPTimeout) != 0)
290938032Speter		{
291038032Speter			if (LogLevel > 1)
291138032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
291264562Sgshapiro					  "timeout conning to LDAP server %.100s",
291364562Sgshapiro					  lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host);
291464562Sgshapiro			return FALSE;
291538032Speter		}
291664562Sgshapiro		ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
291738032Speter	}
291838032Speter
291964562Sgshapiro	ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
292064562Sgshapiro	save_errno = errno;
292142575Speter
292264562Sgshapiro	/* clear the event if it has not sprung */
292364562Sgshapiro	if (ev != NULL)
292442575Speter		clrevent(ev);
292564562Sgshapiro# endif /* USE_LDAP_INIT */
292642575Speter
292764562Sgshapiro	errno = save_errno;
292842575Speter	if (ld == NULL)
292938032Speter	{
293038032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
293138032Speter		{
293264562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
293364562Sgshapiro				syserr("%s failed to %s in map %s",
293464562Sgshapiro# if USE_LDAP_INIT
293564562Sgshapiro				       "ldap_init",
293664562Sgshapiro# else /* USE_LDAP_INIT */
293764562Sgshapiro				       "ldap_open",
293864562Sgshapiro# endif /* USE_LDAP_INIT */
293964562Sgshapiro				       lmap->ldap_host == NULL ? "localhost"
294064562Sgshapiro							       : lmap->ldap_host,
294164562Sgshapiro				       map->map_mname);
294264562Sgshapiro			else
294364562Sgshapiro				syserr("421 4.0.0 %s failed to %s in map %s",
294464562Sgshapiro# if USE_LDAP_INIT
294564562Sgshapiro				       "ldap_init",
294664562Sgshapiro# else /* USE_LDAP_INIT */
294764562Sgshapiro				       "ldap_open",
294864562Sgshapiro# endif /* USE_LDAP_INIT */
294964562Sgshapiro				       lmap->ldap_host == NULL ? "localhost"
295064562Sgshapiro							       : lmap->ldap_host,
295164562Sgshapiro				       map->map_mname);
295238032Speter		}
295338032Speter		return FALSE;
295438032Speter	}
295538032Speter
295664562Sgshapiro	ldapmap_setopts(ld, lmap);
295738032Speter
295864562Sgshapiro# if USE_LDAP_INIT
295964562Sgshapiro	/*
296064562Sgshapiro	**  If using ldap_init(), the actual connection to the server
296164562Sgshapiro	**  happens at ldap_bind_s() so we need the timeout here.
296264562Sgshapiro	*/
296364562Sgshapiro
296464562Sgshapiro	/* set the timeout */
296564562Sgshapiro	if (lmap->ldap_timeout.tv_sec != 0)
296638032Speter	{
296764562Sgshapiro		if (setjmp(LDAPTimeout) != 0)
296838032Speter		{
296964562Sgshapiro			if (LogLevel > 1)
297064562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
297164562Sgshapiro					  "timeout conning to LDAP server %.100s",
297264562Sgshapiro					  lmap->ldap_host == NULL ? "localhost"
297364562Sgshapiro								  : lmap->ldap_host);
297464562Sgshapiro			return FALSE;
297538032Speter		}
297664562Sgshapiro		ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
297738032Speter	}
297864562Sgshapiro# endif /* USE_LDAP_INIT */
297964562Sgshapiro
298064562Sgshapiro# ifdef LDAP_AUTH_KRBV4
298164562Sgshapiro	if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
298264562Sgshapiro	    lmap->ldap_secret != NULL)
298338032Speter	{
298464562Sgshapiro		/*
298564562Sgshapiro		**  Need to put ticket in environment here instead of
298664562Sgshapiro		**  during parseargs as there may be different tickets
298764562Sgshapiro		**  for different LDAP connections.
298864562Sgshapiro		*/
298964562Sgshapiro
299064562Sgshapiro		(void) putenv(lmap->ldap_secret);
299138032Speter	}
299264562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
299338032Speter
299464562Sgshapiro	bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
299564562Sgshapiro				  lmap->ldap_secret, lmap->ldap_method);
299664562Sgshapiro
299764562Sgshapiro# if USE_LDAP_INIT
299864562Sgshapiro	/* clear the event if it has not sprung */
299964562Sgshapiro	if (ev != NULL)
300064562Sgshapiro		clrevent(ev);
300164562Sgshapiro# endif /* USE_LDAP_INIT */
300264562Sgshapiro
300364562Sgshapiro	if (bind_result != LDAP_SUCCESS)
300464562Sgshapiro	{
300564562Sgshapiro		errno = bind_result + E_LDAPBASE;
300664562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
300764562Sgshapiro		{
300864562Sgshapiro			syserr("421 4.0.0 Cannot bind to map %s in ldap server %s",
300964562Sgshapiro			       map->map_mname,
301064562Sgshapiro			       lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host);
301164562Sgshapiro		}
301264562Sgshapiro		return FALSE;
301364562Sgshapiro	}
301464562Sgshapiro
301564562Sgshapiro	/* We need to cast ld into the map structure */
301664562Sgshapiro	lmap->ldap_ld = ld;
301764562Sgshapiro	return TRUE;
301838032Speter}
301938032Speter
302064562Sgshapiro/* ARGSUSED */
302164562Sgshapirostatic void
302264562Sgshapiroldaptimeout(sig_no)
302364562Sgshapiro	int sig_no;
302464562Sgshapiro{
302564562Sgshapiro	longjmp(LDAPTimeout, 1);
302664562Sgshapiro}
302738032Speter
302838032Speter/*
302964562Sgshapiro**  LDAPMAP_CLOSE -- close ldap map
303038032Speter*/
303138032Speter
303238032Spetervoid
303364562Sgshapiroldapmap_close(map)
303438032Speter	MAP *map;
303538032Speter{
303664562Sgshapiro	LDAPMAP_STRUCT *lmap;
303764562Sgshapiro	STAB *s;
303843730Speter
303964562Sgshapiro	if (tTd(38, 2))
304064562Sgshapiro		dprintf("ldapmap_close(%s)\n", map->map_mname);
304164562Sgshapiro
304264562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
304364562Sgshapiro
304464562Sgshapiro	/* Check if already closed */
304564562Sgshapiro	if (lmap->ldap_ld == NULL)
304664562Sgshapiro		return;
304764562Sgshapiro
304864562Sgshapiro	s = ldapmap_findconn(lmap);
304964562Sgshapiro
305064562Sgshapiro	/* Check if already closed */
305164562Sgshapiro	if (s->s_ldap == NULL)
305264562Sgshapiro		return;
305364562Sgshapiro
305464562Sgshapiro	/* If same as saved connection, stored connection is going away */
305564562Sgshapiro	if (s->s_ldap == lmap->ldap_ld)
305664562Sgshapiro		s->s_ldap = NULL;
305764562Sgshapiro
305864562Sgshapiro	if (lmap->ldap_ld != NULL)
305943730Speter	{
306064562Sgshapiro		ldap_unbind(lmap->ldap_ld);
306164562Sgshapiro		lmap->ldap_ld = NULL;
306243730Speter	}
306338032Speter}
306438032Speter
306564562Sgshapiro# ifdef SUNET_ID
306643730Speter/*
306742575Speter**  SUNET_ID_HASH -- Convert a string to it's Sunet_id canonical form
306842575Speter**  This only makes sense at Stanford University.
306938032Speter*/
307038032Speter
307138032Speterchar *
307238032Spetersunet_id_hash(str)
307338032Speter	char *str;
307438032Speter{
307538032Speter	char *p, *p_last;
307638032Speter
307738032Speter	p = str;
307838032Speter	p_last = p;
307938032Speter	while (*p != '\0')
308038032Speter	{
308138032Speter		if (islower(*p) || isdigit(*p))
308238032Speter		{
308338032Speter			*p_last = *p;
308438032Speter			p_last++;
308538032Speter		}
308638032Speter		else if (isupper(*p))
308738032Speter		{
308838032Speter			*p_last = tolower(*p);
308938032Speter			p_last++;
309038032Speter		}
309138032Speter		++p;
309238032Speter	}
309338032Speter	if (*p_last != '\0')
309438032Speter		*p_last = '\0';
309564562Sgshapiro	return str;
309638032Speter}
309764562Sgshapiro# endif /* SUNET_ID */
309838032Speter
309938032Speter/*
310064562Sgshapiro**  LDAPMAP_LOOKUP -- look up a datum in a LDAP map
310138032Speter*/
310238032Speter
310338032Speterchar *
310464562Sgshapiroldapmap_lookup(map, name, av, statp)
310538032Speter	MAP *map;
310638032Speter	char *name;
310738032Speter	char **av;
310838032Speter	int *statp;
310938032Speter{
311064562Sgshapiro	int i;
311164562Sgshapiro	int entries = 0;
311264562Sgshapiro	int msgid;
311364562Sgshapiro	int ret;
311464562Sgshapiro	int vsize;
311564562Sgshapiro	char *fp, *vp;
311664562Sgshapiro	char *p, *q;
311764562Sgshapiro	char *result = NULL;
311864562Sgshapiro	LDAPMAP_STRUCT *lmap = NULL;
311938032Speter	char keybuf[MAXNAME + 1];
312064562Sgshapiro	char filter[LDAPMAP_MAX_FILTER + 1];
312138032Speter
312238032Speter	if (tTd(38, 20))
312364562Sgshapiro		dprintf("ldapmap_lookup(%s, %s)\n", map->map_mname, name);
312438032Speter
312538032Speter	/* Get ldap struct pointer from map */
312664562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
312764562Sgshapiro	ldapmap_setopts(lmap->ldap_ld, lmap);
312838032Speter
312964562Sgshapiro	(void) strlcpy(keybuf, name, sizeof keybuf);
313038032Speter
313138032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
313264562Sgshapiro	{
313364562Sgshapiro# ifdef SUNET_ID
313438032Speter		sunet_id_hash(keybuf);
313564562Sgshapiro# else /* SUNET_ID */
313638032Speter		makelower(keybuf);
313764562Sgshapiro# endif /* SUNET_ID */
313864562Sgshapiro	}
313938032Speter
314042575Speter	/* substitute keybuf into filter, perhaps multiple times */
314164562Sgshapiro	memset(filter, '\0', sizeof filter);
314242575Speter	fp = filter;
314364562Sgshapiro	p = lmap->ldap_filter;
314442575Speter	while ((q = strchr(p, '%')) != NULL)
314542575Speter	{
314642575Speter		if (q[1] == 's')
314742575Speter		{
314842575Speter			snprintf(fp, SPACELEFT(filter, fp), "%.*s%s",
314966494Sgshapiro				 (int) (q - p), p, keybuf);
315064562Sgshapiro			fp += strlen(fp);
315142575Speter			p = q + 2;
315242575Speter		}
315364562Sgshapiro		else if (q[1] == '0')
315464562Sgshapiro		{
315564562Sgshapiro			char *k = keybuf;
315664562Sgshapiro
315764562Sgshapiro			snprintf(fp, SPACELEFT(filter, fp), "%.*s",
315866494Sgshapiro				 (int) (q - p), p);
315964562Sgshapiro			fp += strlen(fp);
316064562Sgshapiro			p = q + 2;
316164562Sgshapiro
316264562Sgshapiro			/* Properly escape LDAP special characters */
316364562Sgshapiro			while (SPACELEFT(filter, fp) > 0 &&
316464562Sgshapiro			       *k != '\0')
316564562Sgshapiro			{
316664562Sgshapiro				if (*k == '*' || *k == '(' ||
316764562Sgshapiro				    *k == ')' || *k == '\\')
316864562Sgshapiro				{
316964562Sgshapiro					(void) strlcat(fp,
317064562Sgshapiro						       (*k == '*' ? "\\2A" :
317164562Sgshapiro							(*k == '(' ? "\\28" :
317264562Sgshapiro							 (*k == ')' ? "\\29" :
317364562Sgshapiro							  (*k == '\\' ? "\\5C" :
317464562Sgshapiro							   "\00")))),
317564562Sgshapiro						SPACELEFT(filter, fp));
317664562Sgshapiro					fp += strlen(fp);
317764562Sgshapiro					k++;
317864562Sgshapiro				}
317964562Sgshapiro				else
318064562Sgshapiro					*fp++ = *k++;
318164562Sgshapiro			}
318264562Sgshapiro		}
318342575Speter		else
318442575Speter		{
318542575Speter			snprintf(fp, SPACELEFT(filter, fp), "%.*s",
318666494Sgshapiro				 (int) (q - p + 1), p);
318742575Speter			p = q + (q[1] == '%' ? 2 : 1);
318864562Sgshapiro			fp += strlen(fp);
318942575Speter		}
319042575Speter	}
319142575Speter	snprintf(fp, SPACELEFT(filter, fp), "%s", p);
319242575Speter	if (tTd(38, 20))
319364562Sgshapiro		dprintf("ldap search filter=%s\n", filter);
319438032Speter
319564562Sgshapiro	lmap->ldap_res = NULL;
319664562Sgshapiro	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope,
319764562Sgshapiro			    filter,
319864562Sgshapiro			    (lmap->ldap_attr[0] == NULL ? NULL :
319964562Sgshapiro			     lmap->ldap_attr),
320064562Sgshapiro			    lmap->ldap_attrsonly);
320164562Sgshapiro	if (msgid == -1)
320238032Speter	{
320364562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
320464562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
320538032Speter		{
320664562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
320766494Sgshapiro				syserr("Error in ldap_search using %s in map %s",
320864562Sgshapiro				       filter, map->map_mname);
320964562Sgshapiro			else
321066494Sgshapiro				syserr("421 4.0.0 Error in ldap_search using %s in map %s",
321164562Sgshapiro				       filter, map->map_mname);
321238032Speter		}
321364562Sgshapiro		*statp = EX_TEMPFAIL;
321466494Sgshapiro#ifdef LDAP_SERVER_DOWN
321566494Sgshapiro		if (errno == LDAP_SERVER_DOWN)
321666494Sgshapiro		{
321766494Sgshapiro			int save_errno = errno;
321866494Sgshapiro
321966494Sgshapiro			/* server disappeared, try reopen on next search */
322066494Sgshapiro			map->map_class->map_close(map);
322166494Sgshapiro			map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
322266494Sgshapiro			errno = save_errno;
322366494Sgshapiro		}
322466494Sgshapiro#endif /* LDAP_SERVER_DOWN */
322564562Sgshapiro		return NULL;
322664562Sgshapiro	}
322764562Sgshapiro
322864562Sgshapiro	*statp = EX_NOTFOUND;
322964562Sgshapiro	vp = NULL;
323064562Sgshapiro
323164562Sgshapiro	/* Get results (all if MF_NOREWRITE, otherwise one by one) */
323264562Sgshapiro	while ((ret = ldap_result(lmap->ldap_ld, msgid,
323364562Sgshapiro				  bitset(MF_NOREWRITE, map->map_mflags),
323464562Sgshapiro				  (lmap->ldap_timeout.tv_sec == 0 ? NULL :
323564562Sgshapiro				   &(lmap->ldap_timeout)),
323664562Sgshapiro				  &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
323764562Sgshapiro	{
323864562Sgshapiro		LDAPMessage *entry;
323964562Sgshapiro
324064562Sgshapiro		if (bitset(MF_SINGLEMATCH, map->map_mflags))
324138032Speter		{
324264562Sgshapiro			entries += ldap_count_entries(lmap->ldap_ld,
324364562Sgshapiro						      lmap->ldap_res);
324464562Sgshapiro			if (entries > 1)
324564562Sgshapiro			{
324664562Sgshapiro				*statp = EX_NOTFOUND;
324764562Sgshapiro				if (lmap->ldap_res != NULL)
324864562Sgshapiro				{
324964562Sgshapiro					ldap_msgfree(lmap->ldap_res);
325064562Sgshapiro					lmap->ldap_res = NULL;
325164562Sgshapiro				}
325264562Sgshapiro				(void) ldap_abandon(lmap->ldap_ld, msgid);
325364562Sgshapiro				if (vp != NULL)
325464562Sgshapiro					free(vp);
325564562Sgshapiro				if (tTd(38, 25))
325664562Sgshapiro					dprintf("ldap search found multiple on a single match query\n");
325764562Sgshapiro				return NULL;
325864562Sgshapiro			}
325964562Sgshapiro		}
326064562Sgshapiro
326164562Sgshapiro		/* If we don't want multiple values and we have one, break */
326264562Sgshapiro		if (map->map_coldelim == '\0' && vp != NULL)
326364562Sgshapiro			break;
326464562Sgshapiro
326564562Sgshapiro		/* Cycle through all entries */
326664562Sgshapiro		for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
326764562Sgshapiro		     entry != NULL;
326864562Sgshapiro		     entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
326964562Sgshapiro		{
327064562Sgshapiro			BerElement *ber;
327164562Sgshapiro			char *attr;
327264562Sgshapiro			char **vals = NULL;
327364562Sgshapiro
327464562Sgshapiro			/*
327564562Sgshapiro			**  If matching only and found an entry,
327664562Sgshapiro			**  no need to spin through attributes
327764562Sgshapiro			*/
327864562Sgshapiro
327964562Sgshapiro			if (*statp == EX_OK &&
328064562Sgshapiro			    bitset(MF_MATCHONLY, map->map_mflags))
328164562Sgshapiro				continue;
328264562Sgshapiro
328364562Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
328464562Sgshapiro			/*
328564562Sgshapiro			**  Reset value to prevent lingering
328664562Sgshapiro			**  LDAP_DECODING_ERROR due to
328764562Sgshapiro			**  OpenLDAP 1.X's hack (see below)
328864562Sgshapiro			*/
328964562Sgshapiro
329064562Sgshapiro			lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
329164562Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
329264562Sgshapiro
329364562Sgshapiro			for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
329464562Sgshapiro							 &ber);
329564562Sgshapiro			     attr != NULL;
329664562Sgshapiro			     attr = ldap_next_attribute(lmap->ldap_ld, entry,
329764562Sgshapiro							ber))
329864562Sgshapiro			{
329964562Sgshapiro				char *tmp, *vp_tmp;
330064562Sgshapiro
330164562Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
330264562Sgshapiro				{
330364562Sgshapiro					vals = ldap_get_values(lmap->ldap_ld,
330464562Sgshapiro							       entry,
330564562Sgshapiro							       attr);
330664562Sgshapiro					if (vals == NULL)
330764562Sgshapiro					{
330864562Sgshapiro						errno = ldapmap_geterrno(lmap->ldap_ld);
330964562Sgshapiro						if (errno == LDAP_SUCCESS)
331064562Sgshapiro							continue;
331164562Sgshapiro
331264562Sgshapiro						/* Must be an error */
331364562Sgshapiro						errno += E_LDAPBASE;
331464562Sgshapiro						if (!bitset(MF_OPTIONAL,
331564562Sgshapiro							    map->map_mflags))
331664562Sgshapiro						{
331764562Sgshapiro							if (bitset(MF_NODEFER,
331864562Sgshapiro								   map->map_mflags))
331964562Sgshapiro								syserr("Error getting LDAP values in map %s",
332064562Sgshapiro								       map->map_mname);
332164562Sgshapiro							else
332264562Sgshapiro								syserr("421 4.0.0 Error getting LDAP values in map %s",
332364562Sgshapiro								       map->map_mname);
332464562Sgshapiro						}
332564562Sgshapiro						*statp = EX_TEMPFAIL;
332664562Sgshapiro# if USING_NETSCAPE_LDAP
332766494Sgshapiro						ldap_memfree(attr);
332864562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
332964562Sgshapiro						if (lmap->ldap_res != NULL)
333064562Sgshapiro						{
333164562Sgshapiro							ldap_msgfree(lmap->ldap_res);
333264562Sgshapiro							lmap->ldap_res = NULL;
333364562Sgshapiro						}
333464562Sgshapiro						(void) ldap_abandon(lmap->ldap_ld,
333564562Sgshapiro								    msgid);
333664562Sgshapiro						if (vp != NULL)
333764562Sgshapiro							free(vp);
333864562Sgshapiro						return NULL;
333964562Sgshapiro					}
334064562Sgshapiro				}
334164562Sgshapiro
334264562Sgshapiro				*statp = EX_OK;
334364562Sgshapiro
334464562Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
334564562Sgshapiro				/*
334664562Sgshapiro				**  Reset value to prevent lingering
334764562Sgshapiro				**  LDAP_DECODING_ERROR due to
334864562Sgshapiro				**  OpenLDAP 1.X's hack (see below)
334964562Sgshapiro				*/
335064562Sgshapiro
335164562Sgshapiro				lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
335264562Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
335364562Sgshapiro
335464562Sgshapiro				/*
335564562Sgshapiro				**  If matching only,
335664562Sgshapiro				**  no need to spin through entries
335764562Sgshapiro				*/
335864562Sgshapiro
335964562Sgshapiro				if (bitset(MF_MATCHONLY, map->map_mflags))
336064562Sgshapiro					continue;
336164562Sgshapiro
336264562Sgshapiro				/*
336364562Sgshapiro				**  If we don't want multiple values,
336464562Sgshapiro				**  return first found.
336564562Sgshapiro				*/
336664562Sgshapiro
336764562Sgshapiro				if (map->map_coldelim == '\0')
336864562Sgshapiro				{
336964562Sgshapiro					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
337064562Sgshapiro					{
337164562Sgshapiro						vp = newstr(attr);
337264562Sgshapiro# if USING_NETSCAPE_LDAP
337366494Sgshapiro						ldap_memfree(attr);
337464562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
337564562Sgshapiro						break;
337664562Sgshapiro					}
337764562Sgshapiro
337864562Sgshapiro					if (vals[0] == NULL)
337964562Sgshapiro					{
338064562Sgshapiro						ldap_value_free(vals);
338164562Sgshapiro# if USING_NETSCAPE_LDAP
338266494Sgshapiro						ldap_memfree(attr);
338364562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
338464562Sgshapiro						continue;
338564562Sgshapiro					}
338664562Sgshapiro
338764562Sgshapiro					vp = newstr(vals[0]);
338864562Sgshapiro					ldap_value_free(vals);
338964562Sgshapiro# if USING_NETSCAPE_LDAP
339066494Sgshapiro					ldap_memfree(attr);
339164562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
339264562Sgshapiro					break;
339364562Sgshapiro				}
339464562Sgshapiro
339564562Sgshapiro				/* attributes only */
339664562Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
339764562Sgshapiro				{
339864562Sgshapiro					if (vp == NULL)
339964562Sgshapiro						vp = newstr(attr);
340064562Sgshapiro					else
340164562Sgshapiro					{
340264562Sgshapiro						vsize = strlen(vp) +
340364562Sgshapiro							strlen(attr) + 2;
340464562Sgshapiro						tmp = xalloc(vsize);
340564562Sgshapiro						snprintf(tmp, vsize, "%s%c%s",
340664562Sgshapiro							 vp, map->map_coldelim,
340764562Sgshapiro							 attr);
340864562Sgshapiro						free(vp);
340964562Sgshapiro						vp = tmp;
341064562Sgshapiro					}
341164562Sgshapiro# if USING_NETSCAPE_LDAP
341266494Sgshapiro					ldap_memfree(attr);
341364562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
341464562Sgshapiro					continue;
341564562Sgshapiro				}
341664562Sgshapiro
341764562Sgshapiro				/*
341864562Sgshapiro				**  If there is more than one,
341964562Sgshapiro				**  munge then into a map_coldelim
342064562Sgshapiro				**  separated string
342164562Sgshapiro				*/
342264562Sgshapiro
342364562Sgshapiro				vsize = 0;
342464562Sgshapiro				for (i = 0; vals[i] != NULL; i++)
342564562Sgshapiro					vsize += strlen(vals[i]) + 1;
342664562Sgshapiro				vp_tmp = xalloc(vsize);
342764562Sgshapiro				*vp_tmp = '\0';
342864562Sgshapiro
342964562Sgshapiro				p = vp_tmp;
343064562Sgshapiro				for (i = 0; vals[i] != NULL; i++)
343164562Sgshapiro				{
343264562Sgshapiro					p += strlcpy(p, vals[i],
343364562Sgshapiro						     vsize - (p - vp_tmp));
343464562Sgshapiro					if (p >= vp_tmp + vsize)
343564562Sgshapiro						syserr("ldapmap_lookup: Internal error: buffer too small for LDAP values");
343664562Sgshapiro					if (vals[i + 1] != NULL)
343764562Sgshapiro						*p++ = map->map_coldelim;
343864562Sgshapiro				}
343964562Sgshapiro
344064562Sgshapiro				ldap_value_free(vals);
344164562Sgshapiro# if USING_NETSCAPE_LDAP
344266494Sgshapiro				ldap_memfree(attr);
344364562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
344464562Sgshapiro				if (vp == NULL)
344564562Sgshapiro				{
344664562Sgshapiro					vp = vp_tmp;
344764562Sgshapiro					continue;
344864562Sgshapiro				}
344964562Sgshapiro				vsize = strlen(vp) + strlen(vp_tmp) + 2;
345064562Sgshapiro				tmp = xalloc(vsize);
345164562Sgshapiro				snprintf(tmp, vsize, "%s%c%s",
345264562Sgshapiro					 vp, map->map_coldelim, vp_tmp);
345364562Sgshapiro
345464562Sgshapiro				free(vp);
345564562Sgshapiro				free(vp_tmp);
345664562Sgshapiro				vp = tmp;
345764562Sgshapiro			}
345864562Sgshapiro			errno = ldapmap_geterrno(lmap->ldap_ld);
345964562Sgshapiro
346064562Sgshapiro			/*
346164562Sgshapiro			**  We check errno != LDAP_DECODING_ERROR since
346264562Sgshapiro			**  OpenLDAP 1.X has a very ugly *undocumented*
346364562Sgshapiro			**  hack of returning this error code from
346464562Sgshapiro			**  ldap_next_attribute() if the library freed the
346564562Sgshapiro			**  ber attribute.  See:
346664562Sgshapiro			**  http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
346764562Sgshapiro			*/
346864562Sgshapiro
346964562Sgshapiro			if (errno != LDAP_SUCCESS &&
347064562Sgshapiro			    errno != LDAP_DECODING_ERROR)
347164562Sgshapiro			{
347264562Sgshapiro				/* Must be an error */
347364562Sgshapiro				errno += E_LDAPBASE;
347464562Sgshapiro				if (!bitset(MF_OPTIONAL, map->map_mflags))
347564562Sgshapiro				{
347664562Sgshapiro					if (bitset(MF_NODEFER, map->map_mflags))
347764562Sgshapiro						syserr("Error getting LDAP attributes in map %s",
347864562Sgshapiro						       map->map_mname);
347964562Sgshapiro					else
348064562Sgshapiro						syserr("421 4.0.0 Error getting LDAP attributes in map %s",
348164562Sgshapiro						       map->map_mname);
348264562Sgshapiro				}
348364562Sgshapiro				*statp = EX_TEMPFAIL;
348464562Sgshapiro				if (lmap->ldap_res != NULL)
348564562Sgshapiro				{
348664562Sgshapiro					ldap_msgfree(lmap->ldap_res);
348764562Sgshapiro					lmap->ldap_res = NULL;
348864562Sgshapiro				}
348964562Sgshapiro				(void) ldap_abandon(lmap->ldap_ld, msgid);
349064562Sgshapiro				if (vp != NULL)
349164562Sgshapiro					free(vp);
349264562Sgshapiro				return NULL;
349364562Sgshapiro			}
349464562Sgshapiro
349564562Sgshapiro			/* We don't want multiple values and we have one */
349664562Sgshapiro			if (map->map_coldelim == '\0' && vp != NULL)
349764562Sgshapiro				break;
349864562Sgshapiro		}
349964562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld);
350064562Sgshapiro		if (errno != LDAP_SUCCESS && errno != LDAP_DECODING_ERROR)
350164562Sgshapiro		{
350264562Sgshapiro			/* Must be an error */
350364562Sgshapiro			errno += E_LDAPBASE;
350438032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
350538032Speter			{
350664562Sgshapiro				if (bitset(MF_NODEFER, map->map_mflags))
350764562Sgshapiro					syserr("Error getting LDAP entries in map %s",
350864562Sgshapiro					       map->map_mname);
350964562Sgshapiro				else
351064562Sgshapiro					syserr("421 4.0.0 Error getting LDAP entries in map %s",
351164562Sgshapiro					       map->map_mname);
351238032Speter			}
351338032Speter			*statp = EX_TEMPFAIL;
351464562Sgshapiro			if (lmap->ldap_res != NULL)
351564562Sgshapiro			{
351664562Sgshapiro				ldap_msgfree(lmap->ldap_res);
351764562Sgshapiro				lmap->ldap_res = NULL;
351864562Sgshapiro			}
351964562Sgshapiro			(void) ldap_abandon(lmap->ldap_ld, msgid);
352064562Sgshapiro			if (vp != NULL)
352164562Sgshapiro				free(vp);
352264562Sgshapiro			return NULL;
352338032Speter		}
352464562Sgshapiro		ldap_msgfree(lmap->ldap_res);
352564562Sgshapiro		lmap->ldap_res = NULL;
352638032Speter	}
352738032Speter
352864562Sgshapiro	/*
352964562Sgshapiro	**  If grabbing all results at once for MF_NOREWRITE and
353064562Sgshapiro	**  only want a single match, make sure that's all we have
353164562Sgshapiro	*/
353264562Sgshapiro
353364562Sgshapiro	if (ret == LDAP_RES_SEARCH_RESULT &&
353464562Sgshapiro	    bitset(MF_NOREWRITE|MF_SINGLEMATCH, map->map_mflags))
353538032Speter	{
353664562Sgshapiro		entries += ldap_count_entries(lmap->ldap_ld, lmap->ldap_res);
353764562Sgshapiro		if (entries > 1)
353864562Sgshapiro		{
353964562Sgshapiro			*statp = EX_NOTFOUND;
354064562Sgshapiro			if (lmap->ldap_res != NULL)
354164562Sgshapiro			{
354264562Sgshapiro				ldap_msgfree(lmap->ldap_res);
354364562Sgshapiro				lmap->ldap_res = NULL;
354464562Sgshapiro			}
354564562Sgshapiro			if (vp != NULL)
354664562Sgshapiro				free(vp);
354764562Sgshapiro			return NULL;
354864562Sgshapiro		}
354964562Sgshapiro		*statp = EX_OK;
355038032Speter	}
355138032Speter
355264562Sgshapiro	if (ret == 0)
355364562Sgshapiro		errno = ETIMEDOUT;
355464562Sgshapiro	else
355564562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld);
355664562Sgshapiro	if (errno != LDAP_SUCCESS)
355738032Speter	{
355864562Sgshapiro		/* Must be an error */
355964562Sgshapiro		if (ret != 0)
356064562Sgshapiro			errno += E_LDAPBASE;
356164562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
356264562Sgshapiro		{
356364562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
356464562Sgshapiro				syserr("Error getting LDAP results in map %s",
356564562Sgshapiro				       map->map_mname);
356664562Sgshapiro			else
356764562Sgshapiro				syserr("421 4.0.0 Error getting LDAP results in map %s",
356864562Sgshapiro				       map->map_mname);
356964562Sgshapiro		}
357064562Sgshapiro		*statp = EX_TEMPFAIL;
357164562Sgshapiro		if (vp != NULL)
357264562Sgshapiro			free(vp);
357364562Sgshapiro		return NULL;
357438032Speter	}
357538032Speter
357664562Sgshapiro	/* Did we match anything? */
357764562Sgshapiro	if (vp == NULL)
357864562Sgshapiro		return NULL;
357938032Speter
358064562Sgshapiro	/*
358164562Sgshapiro	**  If MF_NOREWRITE, we are special map which doesn't
358264562Sgshapiro	**  actually return a map value.  Instead, we don't free
358364562Sgshapiro	**  ldap_res and let the calling function process the LDAP
358464562Sgshapiro	**  results.  The caller should ldap_msgfree(lmap->ldap_res).
358564562Sgshapiro	*/
358638032Speter
358764562Sgshapiro	if (bitset(MF_NOREWRITE, map->map_mflags))
358864562Sgshapiro	{
358964562Sgshapiro		/* vp != NULL due to test above */
359064562Sgshapiro		free(vp);
359164562Sgshapiro		return "";
359264562Sgshapiro	}
359338032Speter
359464562Sgshapiro	if (*statp == EX_OK)
359564562Sgshapiro	{
359664562Sgshapiro		/* vp != NULL due to test above */
359764562Sgshapiro		if (LogLevel > 9)
359864562Sgshapiro			sm_syslog(LOG_INFO, CurEnv->e_id,
359964562Sgshapiro				  "ldap %.100s => %s", name, vp);
360064562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
360164562Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
360264562Sgshapiro		else
360364562Sgshapiro			result = map_rewrite(map, vp, strlen(vp), av);
360464562Sgshapiro		free(vp);
360564562Sgshapiro	}
360664562Sgshapiro	return result;
360738032Speter}
360838032Speter
360938032Speter/*
361064562Sgshapiro**  LDAPMAP_FINDCONN -- find an LDAP connection to the server
361164562Sgshapiro**
361264562Sgshapiro**	Cache LDAP connections based on the host, port, bind DN,
361366494Sgshapiro**	secret, and PID so we don't have multiple connections open to
361466494Sgshapiro**	the same server for different maps.  Need a separate connection
361566494Sgshapiro**	per PID since a parent process may close the map before the
361666494Sgshapiro**	child is done with it.
361764562Sgshapiro**
361864562Sgshapiro**	Parameters:
361964562Sgshapiro**		lmap -- LDAP map information
362064562Sgshapiro**
362164562Sgshapiro**	Returns:
362264562Sgshapiro**		Symbol table entry for the LDAP connection.
362364562Sgshapiro**
362438032Speter*/
362538032Speter
362664562Sgshapirostatic STAB *
362764562Sgshapiroldapmap_findconn(lmap)
362864562Sgshapiro	LDAPMAP_STRUCT *lmap;
362938032Speter{
363064562Sgshapiro	int len;
363164562Sgshapiro	char *nbuf;
363264562Sgshapiro	STAB *s;
363338032Speter
363464562Sgshapiro	len = (lmap->ldap_host == NULL ? strlen("localhost") :
363564562Sgshapiro					 strlen(lmap->ldap_host)) + 1 + 8 + 1 +
363664562Sgshapiro		(lmap->ldap_binddn == NULL ? 0 : strlen(lmap->ldap_binddn)) +
363764562Sgshapiro		1 +
363864562Sgshapiro		(lmap->ldap_secret == NULL ? 0 : strlen(lmap->ldap_secret)) +
363966494Sgshapiro		8 + 1;
364064562Sgshapiro	nbuf = xalloc(len);
364166494Sgshapiro	snprintf(nbuf, len, "%s%c%d%c%s%c%s%d",
364264562Sgshapiro		 (lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host),
364364562Sgshapiro		 CONDELSE,
364464562Sgshapiro		 lmap->ldap_port,
364564562Sgshapiro		 CONDELSE,
364664562Sgshapiro		 (lmap->ldap_binddn == NULL ? "" : lmap->ldap_binddn),
364764562Sgshapiro		 CONDELSE,
364866494Sgshapiro		 (lmap->ldap_secret == NULL ? "" : lmap->ldap_secret),
364966494Sgshapiro		 getpid());
365064562Sgshapiro	s = stab(nbuf, ST_LDAP, ST_ENTER);
365164562Sgshapiro	free(nbuf);
365264562Sgshapiro	return s;
365364562Sgshapiro}
365464562Sgshapiro/*
365564562Sgshapiro**  LDAPMAP_SETOPTS -- set LDAP options
365664562Sgshapiro**
365764562Sgshapiro**	Parameters:
365864562Sgshapiro**		ld -- LDAP session handle
365964562Sgshapiro**		lmap -- LDAP map information
366064562Sgshapiro**
366164562Sgshapiro**	Returns:
366264562Sgshapiro**		None.
366364562Sgshapiro**
366464562Sgshapiro*/
366564562Sgshapiro
366664562Sgshapirostatic void
366764562Sgshapiroldapmap_setopts(ld, lmap)
366864562Sgshapiro	LDAP *ld;
366964562Sgshapiro	LDAPMAP_STRUCT *lmap;
367064562Sgshapiro{
367164562Sgshapiro# if USE_LDAP_SET_OPTION
367264562Sgshapiro	ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
367364562Sgshapiro	if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
367464562Sgshapiro		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
367538032Speter	else
367664562Sgshapiro		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
367764562Sgshapiro	ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
367864562Sgshapiro	ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
367964562Sgshapiro# else /* USE_LDAP_SET_OPTION */
368064562Sgshapiro	/* From here on in we can use ldap internal timelimits */
368164562Sgshapiro	ld->ld_deref = lmap->ldap_deref;
368264562Sgshapiro	ld->ld_options = lmap->ldap_options;
368364562Sgshapiro	ld->ld_sizelimit = lmap->ldap_sizelimit;
368464562Sgshapiro	ld->ld_timelimit = lmap->ldap_timelimit;
368564562Sgshapiro# endif /* USE_LDAP_SET_OPTION */
368638032Speter}
368764562Sgshapiro/*
368864562Sgshapiro**  LDAPMAP_GETERRNO -- get ldap errno value
368964562Sgshapiro**
369064562Sgshapiro**	Parameters:
369164562Sgshapiro**		ld -- LDAP session handle
369264562Sgshapiro**
369364562Sgshapiro**	Returns:
369464562Sgshapiro**		LDAP errno.
369564562Sgshapiro**
369664562Sgshapiro*/
369738032Speter
369864562Sgshapirostatic int
369964562Sgshapiroldapmap_geterrno(ld)
370064562Sgshapiro	LDAP *ld;
370164562Sgshapiro{
370264562Sgshapiro	int err = LDAP_SUCCESS;
370364562Sgshapiro
370464562Sgshapiro# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
370564562Sgshapiro	(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
370664562Sgshapiro# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
370764562Sgshapiro#  ifdef LDAP_OPT_SIZELIMIT
370864562Sgshapiro	err = ldap_get_lderrno(ld, NULL, NULL);
370964562Sgshapiro#  else /* LDAP_OPT_SIZELIMIT */
371064562Sgshapiro	err = ld->ld_errno;
371164562Sgshapiro
371264562Sgshapiro	/*
371364562Sgshapiro	**  Reset value to prevent lingering LDAP_DECODING_ERROR due to
371464562Sgshapiro	**  OpenLDAP 1.X's hack (see above)
371564562Sgshapiro	*/
371664562Sgshapiro
371764562Sgshapiro	ld->ld_errno = LDAP_SUCCESS;
371864562Sgshapiro#  endif /* LDAP_OPT_SIZELIMIT */
371964562Sgshapiro# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
372064562Sgshapiro	return err;
372164562Sgshapiro}
372264562Sgshapiro
372338032Speter/*
372464562Sgshapiro**  LDAPX_MAP_PARSEARGS -- print warning about use of ldapx map.
372538032Speter*/
372638032Speter
372738032Speterbool
372864562Sgshapiroldapx_map_parseargs(map, args)
372938032Speter	MAP *map;
373038032Speter	char *args;
373138032Speter{
373264562Sgshapiro	printf("Warning: The \"ldapx\" map class is deprecated and will be removed in a future\n");
373364562Sgshapiro	printf("         version.  Use the \"ldap\" map class instead for map \"%s\".\n",
373464562Sgshapiro	       map->map_mname);
373564562Sgshapiro	return ldapmap_parseargs(map, args);
373664562Sgshapiro}
373738032Speter
373864562Sgshapiro/*
373964562Sgshapiro**  LDAPMAP_PARSEARGS -- parse ldap map definition args.
374064562Sgshapiro*/
374138032Speter
374264562Sgshapirostruct lamvalues LDAPAuthMethods[] =
374364562Sgshapiro{
374464562Sgshapiro	{	"none",		LDAP_AUTH_NONE		},
374564562Sgshapiro	{	"simple",	LDAP_AUTH_SIMPLE	},
374664562Sgshapiro# ifdef LDAP_AUTH_KRBV4
374764562Sgshapiro	{	"krbv4",	LDAP_AUTH_KRBV4		},
374864562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
374964562Sgshapiro	{	NULL,		0			}
375064562Sgshapiro};
375138032Speter
375264562Sgshapirostruct ladvalues LDAPAliasDereference[] =
375364562Sgshapiro{
375464562Sgshapiro	{	"never",	LDAP_DEREF_NEVER	},
375564562Sgshapiro	{	"always",	LDAP_DEREF_ALWAYS	},
375664562Sgshapiro	{	"search",	LDAP_DEREF_SEARCHING	},
375764562Sgshapiro	{	"find",		LDAP_DEREF_FINDING	},
375864562Sgshapiro	{	NULL,		0			}
375964562Sgshapiro};
376038032Speter
376164562Sgshapirostruct lssvalues LDAPSearchScope[] =
376264562Sgshapiro{
376364562Sgshapiro	{	"base",		LDAP_SCOPE_BASE		},
376464562Sgshapiro	{	"one",		LDAP_SCOPE_ONELEVEL	},
376564562Sgshapiro	{	"sub",		LDAP_SCOPE_SUBTREE	},
376664562Sgshapiro	{	NULL,		0			}
376764562Sgshapiro};
376838032Speter
376964562Sgshapirobool
377064562Sgshapiroldapmap_parseargs(map, args)
377164562Sgshapiro	MAP *map;
377264562Sgshapiro	char *args;
377364562Sgshapiro{
377464562Sgshapiro	bool secretread = TRUE;
377564562Sgshapiro	int i;
377664562Sgshapiro	register char *p = args;
377764562Sgshapiro	LDAPMAP_STRUCT *lmap;
377864562Sgshapiro	struct lamvalues *lam;
377964562Sgshapiro	struct ladvalues *lad;
378064562Sgshapiro	struct lssvalues *lss;
378164562Sgshapiro	char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
378264562Sgshapiro
378364562Sgshapiro	/* Get ldap struct pointer from map */
378464562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
378564562Sgshapiro
378664562Sgshapiro	/* Check if setting the initial LDAP defaults */
378764562Sgshapiro	if (lmap == NULL || lmap != LDAPDefaults)
378864562Sgshapiro	{
378964562Sgshapiro		/* We need to alloc an LDAPMAP_STRUCT struct */
379064562Sgshapiro		lmap = (LDAPMAP_STRUCT *) xalloc(sizeof *lmap);
379164562Sgshapiro		if (LDAPDefaults == NULL)
379264562Sgshapiro			ldapmap_clear(lmap);
379364562Sgshapiro		else
379464562Sgshapiro			STRUCTCOPY(*LDAPDefaults, *lmap);
379564562Sgshapiro	}
379664562Sgshapiro
379764562Sgshapiro	/* there is no check whether there is really an argument */
379864562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
379964562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
380038032Speter	for (;;)
380138032Speter	{
380238032Speter		while (isascii(*p) && isspace(*p))
380338032Speter			p++;
380438032Speter		if (*p != '-')
380538032Speter			break;
380638032Speter		switch (*++p)
380738032Speter		{
380838032Speter		  case 'N':
380938032Speter			map->map_mflags |= MF_INCLNULL;
381038032Speter			map->map_mflags &= ~MF_TRY0NULL;
381138032Speter			break;
381238032Speter
381338032Speter		  case 'O':
381438032Speter			map->map_mflags &= ~MF_TRY1NULL;
381538032Speter			break;
381638032Speter
381738032Speter		  case 'o':
381838032Speter			map->map_mflags |= MF_OPTIONAL;
381938032Speter			break;
382038032Speter
382138032Speter		  case 'f':
382238032Speter			map->map_mflags |= MF_NOFOLDCASE;
382338032Speter			break;
382438032Speter
382538032Speter		  case 'm':
382638032Speter			map->map_mflags |= MF_MATCHONLY;
382738032Speter			break;
382838032Speter
382938032Speter		  case 'A':
383038032Speter			map->map_mflags |= MF_APPEND;
383138032Speter			break;
383238032Speter
383338032Speter		  case 'q':
383438032Speter			map->map_mflags |= MF_KEEPQUOTES;
383538032Speter			break;
383638032Speter
383738032Speter		  case 'a':
383838032Speter			map->map_app = ++p;
383938032Speter			break;
384038032Speter
384138032Speter		  case 'T':
384238032Speter			map->map_tapp = ++p;
384338032Speter			break;
384438032Speter
384564562Sgshapiro		  case 't':
384664562Sgshapiro			map->map_mflags |= MF_NODEFER;
384764562Sgshapiro			break;
384864562Sgshapiro
384964562Sgshapiro		  case 'S':
385064562Sgshapiro			map->map_spacesub = *++p;
385164562Sgshapiro			break;
385264562Sgshapiro
385364562Sgshapiro		  case 'D':
385464562Sgshapiro			map->map_mflags |= MF_DEFER;
385564562Sgshapiro			break;
385664562Sgshapiro
385764562Sgshapiro		  case 'z':
385864562Sgshapiro			if (*++p != '\\')
385964562Sgshapiro				map->map_coldelim = *p;
386064562Sgshapiro			else
386164562Sgshapiro			{
386264562Sgshapiro				switch (*++p)
386364562Sgshapiro				{
386464562Sgshapiro				  case 'n':
386564562Sgshapiro					map->map_coldelim = '\n';
386664562Sgshapiro					break;
386764562Sgshapiro
386864562Sgshapiro				  case 't':
386964562Sgshapiro					map->map_coldelim = '\t';
387064562Sgshapiro					break;
387164562Sgshapiro
387264562Sgshapiro				  default:
387364562Sgshapiro					map->map_coldelim = '\\';
387464562Sgshapiro				}
387564562Sgshapiro			}
387664562Sgshapiro			break;
387764562Sgshapiro
387864562Sgshapiro			/* Start of ldapmap specific args */
387938032Speter		  case 'k':		/* search field */
388038032Speter			while (isascii(*++p) && isspace(*p))
388138032Speter				continue;
388264562Sgshapiro			lmap->ldap_filter = p;
388338032Speter			break;
388438032Speter
388538032Speter		  case 'v':		/* attr to return */
388638032Speter			while (isascii(*++p) && isspace(*p))
388738032Speter				continue;
388864562Sgshapiro			lmap->ldap_attr[0] = p;
388964562Sgshapiro			lmap->ldap_attr[1] = NULL;
389038032Speter			break;
389138032Speter
389264562Sgshapiro		  case '1':
389364562Sgshapiro			map->map_mflags |= MF_SINGLEMATCH;
389464562Sgshapiro			break;
389564562Sgshapiro
389638032Speter			/* args stolen from ldapsearch.c */
389738032Speter		  case 'R':		/* don't auto chase referrals */
389864562Sgshapiro# ifdef LDAP_REFERRALS
389938032Speter			lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
390064562Sgshapiro# else /* LDAP_REFERRALS */
390138032Speter			syserr("compile with -DLDAP_REFERRALS for referral support\n");
390264562Sgshapiro# endif /* LDAP_REFERRALS */
390338032Speter			break;
390438032Speter
390564562Sgshapiro		  case 'n':		/* retrieve attribute names only */
390664562Sgshapiro			lmap->ldap_attrsonly = LDAPMAP_TRUE;
390738032Speter			break;
390838032Speter
390964562Sgshapiro		  case 'r':		/* alias dereferencing */
391064562Sgshapiro			while (isascii(*++p) && isspace(*p))
391164562Sgshapiro				continue;
391264562Sgshapiro
391364562Sgshapiro			if (strncasecmp(p, "LDAP_DEREF_", 11) == 0)
391464562Sgshapiro				p += 11;
391564562Sgshapiro
391664562Sgshapiro			for (lad = LDAPAliasDereference;
391764562Sgshapiro			     lad != NULL && lad->lad_name != NULL; lad++)
391838032Speter			{
391964562Sgshapiro				if (strncasecmp(p, lad->lad_name,
392064562Sgshapiro						strlen(lad->lad_name)) == 0)
392164562Sgshapiro					break;
392238032Speter			}
392364562Sgshapiro			if (lad->lad_name != NULL)
392464562Sgshapiro				lmap->ldap_deref = lad->lad_code;
392564562Sgshapiro			else
392638032Speter			{
392764562Sgshapiro				/* bad config line */
392864562Sgshapiro				if (!bitset(MCF_OPTFILE,
392964562Sgshapiro					    map->map_class->map_cflags))
393064562Sgshapiro				{
393164562Sgshapiro					char *ptr;
393264562Sgshapiro
393364562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
393464562Sgshapiro						*ptr = '\0';
393564562Sgshapiro					syserr("Deref must be [never|always|search|find] not %s in map %s",
393664562Sgshapiro						p, map->map_mname);
393764562Sgshapiro					if (ptr != NULL)
393864562Sgshapiro						*ptr = ' ';
393964562Sgshapiro					return FALSE;
394064562Sgshapiro				}
394138032Speter			}
394264562Sgshapiro			break;
394364562Sgshapiro
394464562Sgshapiro		  case 's':		/* search scope */
394564562Sgshapiro			while (isascii(*++p) && isspace(*p))
394664562Sgshapiro				continue;
394764562Sgshapiro
394864562Sgshapiro			if (strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
394964562Sgshapiro				p += 11;
395064562Sgshapiro
395164562Sgshapiro			for (lss = LDAPSearchScope;
395264562Sgshapiro			     lss != NULL && lss->lss_name != NULL; lss++)
395338032Speter			{
395464562Sgshapiro				if (strncasecmp(p, lss->lss_name,
395564562Sgshapiro						strlen(lss->lss_name)) == 0)
395664562Sgshapiro					break;
395738032Speter			}
395864562Sgshapiro			if (lss->lss_name != NULL)
395964562Sgshapiro				lmap->ldap_scope = lss->lss_code;
396038032Speter			else
396164562Sgshapiro			{
396264562Sgshapiro				/* bad config line */
396364562Sgshapiro				if (!bitset(MCF_OPTFILE,
396464562Sgshapiro					    map->map_class->map_cflags))
396538032Speter				{
396638032Speter					char *ptr;
396738032Speter
396838032Speter					if ((ptr = strchr(p, ' ')) != NULL)
396938032Speter						*ptr = '\0';
397038032Speter					syserr("Scope must be [base|one|sub] not %s in map %s",
397138032Speter						p, map->map_mname);
397238032Speter					if (ptr != NULL)
397338032Speter						*ptr = ' ';
397438032Speter					return FALSE;
397538032Speter				}
397638032Speter			}
397738032Speter			break;
397838032Speter
397938032Speter		  case 'h':		/* ldap host */
398038032Speter			while (isascii(*++p) && isspace(*p))
398138032Speter				continue;
398264562Sgshapiro			lmap->ldap_host = p;
398338032Speter			break;
398438032Speter
398538032Speter		  case 'b':		/* search base */
398638032Speter			while (isascii(*++p) && isspace(*p))
398738032Speter				continue;
398864562Sgshapiro			lmap->ldap_base = p;
398938032Speter			break;
399038032Speter
399138032Speter		  case 'p':		/* ldap port */
399238032Speter			while (isascii(*++p) && isspace(*p))
399338032Speter				continue;
399464562Sgshapiro			lmap->ldap_port = atoi(p);
399538032Speter			break;
399638032Speter
399738032Speter		  case 'l':		/* time limit */
399838032Speter			while (isascii(*++p) && isspace(*p))
399938032Speter				continue;
400064562Sgshapiro			lmap->ldap_timelimit = atoi(p);
400164562Sgshapiro			lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit;
400238032Speter			break;
400338032Speter
400464562Sgshapiro		  case 'Z':
400564562Sgshapiro			while (isascii(*++p) && isspace(*p))
400664562Sgshapiro				continue;
400764562Sgshapiro			lmap->ldap_sizelimit = atoi(p);
400864562Sgshapiro			break;
400964562Sgshapiro
401064562Sgshapiro		  case 'd':		/* Dn to bind to server as */
401164562Sgshapiro			while (isascii(*++p) && isspace(*p))
401264562Sgshapiro				continue;
401364562Sgshapiro			lmap->ldap_binddn = p;
401464562Sgshapiro			break;
401564562Sgshapiro
401664562Sgshapiro		  case 'M':		/* Method for binding */
401764562Sgshapiro			while (isascii(*++p) && isspace(*p))
401864562Sgshapiro				continue;
401964562Sgshapiro
402064562Sgshapiro			if (strncasecmp(p, "LDAP_AUTH_", 10) == 0)
402164562Sgshapiro				p += 10;
402264562Sgshapiro
402364562Sgshapiro			for (lam = LDAPAuthMethods;
402464562Sgshapiro			     lam != NULL && lam->lam_name != NULL; lam++)
402564562Sgshapiro			{
402664562Sgshapiro				if (strncasecmp(p, lam->lam_name,
402764562Sgshapiro						strlen(lam->lam_name)) == 0)
402864562Sgshapiro					break;
402964562Sgshapiro			}
403064562Sgshapiro			if (lam->lam_name != NULL)
403164562Sgshapiro				lmap->ldap_method = lam->lam_code;
403264562Sgshapiro			else
403364562Sgshapiro			{
403464562Sgshapiro				/* bad config line */
403564562Sgshapiro				if (!bitset(MCF_OPTFILE,
403664562Sgshapiro					    map->map_class->map_cflags))
403764562Sgshapiro				{
403864562Sgshapiro					char *ptr;
403964562Sgshapiro
404064562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
404164562Sgshapiro						*ptr = '\0';
404264562Sgshapiro					syserr("Method for binding must be [none|simple|krbv4] not %s in map %s",
404364562Sgshapiro						p, map->map_mname);
404464562Sgshapiro					if (ptr != NULL)
404564562Sgshapiro						*ptr = ' ';
404664562Sgshapiro					return FALSE;
404764562Sgshapiro				}
404864562Sgshapiro			}
404964562Sgshapiro
405064562Sgshapiro			break;
405164562Sgshapiro
405264562Sgshapiro			/*
405364562Sgshapiro			**  This is a string that is dependent on the
405464562Sgshapiro			**  method used defined above.
405564562Sgshapiro			*/
405664562Sgshapiro
405764562Sgshapiro		  case 'P':		/* Secret password for binding */
405864562Sgshapiro			 while (isascii(*++p) && isspace(*p))
405964562Sgshapiro				continue;
406064562Sgshapiro			lmap->ldap_secret = p;
406164562Sgshapiro			secretread = FALSE;
406264562Sgshapiro			break;
406364562Sgshapiro
406464562Sgshapiro		  default:
406564562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
406664562Sgshapiro			break;
406738032Speter		}
406838032Speter
406964562Sgshapiro		/* need to account for quoted strings here */
407064562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
407138032Speter		{
407238032Speter			if (*p == '"')
407338032Speter			{
407438032Speter				while (*++p != '"' && *p != '\0')
407538032Speter					continue;
407638032Speter				if (*p != '\0')
407738032Speter					p++;
407838032Speter			}
407938032Speter			else
408038032Speter				p++;
408138032Speter		}
408238032Speter
408338032Speter		if (*p != '\0')
408438032Speter			*p++ = '\0';
408538032Speter	}
408638032Speter
408738032Speter	if (map->map_app != NULL)
408864562Sgshapiro		map->map_app = newstr(ldapmap_dequote(map->map_app));
408938032Speter	if (map->map_tapp != NULL)
409064562Sgshapiro		map->map_tapp = newstr(ldapmap_dequote(map->map_tapp));
409138032Speter
409238032Speter	/*
409342575Speter	**  We need to swallow up all the stuff into a struct
409442575Speter	**  and dump it into map->map_dbptr1
409538032Speter	*/
409638032Speter
409764562Sgshapiro	if (lmap->ldap_host != NULL &&
409864562Sgshapiro	    (LDAPDefaults == NULL ||
409964562Sgshapiro	     LDAPDefaults == lmap ||
410064562Sgshapiro	     LDAPDefaults->ldap_host != lmap->ldap_host))
410164562Sgshapiro		lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host));
410264562Sgshapiro	map->map_domain = lmap->ldap_host;
410364562Sgshapiro
410464562Sgshapiro	if (lmap->ldap_binddn != NULL &&
410564562Sgshapiro	    (LDAPDefaults == NULL ||
410664562Sgshapiro	     LDAPDefaults == lmap ||
410764562Sgshapiro	     LDAPDefaults->ldap_binddn != lmap->ldap_binddn))
410864562Sgshapiro		lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn));
410964562Sgshapiro
411064562Sgshapiro	if (lmap->ldap_secret != NULL &&
411164562Sgshapiro	    (LDAPDefaults == NULL ||
411264562Sgshapiro	     LDAPDefaults == lmap ||
411364562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
411438032Speter	{
411564562Sgshapiro		FILE *sfd;
411664562Sgshapiro		long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
411738032Speter
411864562Sgshapiro		if (DontLockReadFiles)
411964562Sgshapiro			sff |= SFF_NOLOCK;
412038032Speter
412164562Sgshapiro		/* need to use method to map secret to passwd string */
412264562Sgshapiro		switch (lmap->ldap_method)
412364562Sgshapiro		{
412464562Sgshapiro		  case LDAP_AUTH_NONE:
412564562Sgshapiro			/* Do nothing */
412664562Sgshapiro			break;
412738032Speter
412864562Sgshapiro		  case LDAP_AUTH_SIMPLE:
412938032Speter
413064562Sgshapiro			/*
413164562Sgshapiro			**  Secret is the name of a file with
413264562Sgshapiro			**  the first line as the password.
413364562Sgshapiro			*/
413464562Sgshapiro
413564562Sgshapiro			/* Already read in the secret? */
413664562Sgshapiro			if (secretread)
413764562Sgshapiro				break;
413864562Sgshapiro
413964562Sgshapiro			sfd = safefopen(ldapmap_dequote(lmap->ldap_secret),
414064562Sgshapiro					O_RDONLY, 0, sff);
414164562Sgshapiro			if (sfd == NULL)
414264562Sgshapiro			{
414364562Sgshapiro				syserr("LDAP map: cannot open secret %s",
414464562Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
414564562Sgshapiro				return FALSE;
414664562Sgshapiro			}
414764562Sgshapiro			lmap->ldap_secret = sfgets(m_tmp, LDAPMAP_MAX_PASSWD,
414866494Sgshapiro						   sfd, TimeOuts.to_fileopen,
414966494Sgshapiro						   "ldapmap_parseargs");
415064562Sgshapiro			(void) fclose(sfd);
415164562Sgshapiro			if (lmap->ldap_secret != NULL &&
415264562Sgshapiro			    strlen(m_tmp) > 0)
415364562Sgshapiro			{
415464562Sgshapiro				/* chomp newline */
415564562Sgshapiro				if (m_tmp[strlen(m_tmp) - 1] == '\n')
415664562Sgshapiro					m_tmp[strlen(m_tmp) - 1] = '\0';
415764562Sgshapiro
415864562Sgshapiro				lmap->ldap_secret = m_tmp;
415964562Sgshapiro			}
416064562Sgshapiro			break;
416164562Sgshapiro
416264562Sgshapiro# ifdef LDAP_AUTH_KRBV4
416364562Sgshapiro		  case LDAP_AUTH_KRBV4:
416464562Sgshapiro
416564562Sgshapiro			/*
416664562Sgshapiro			**  Secret is where the ticket file is
416764562Sgshapiro			**  stashed
416864562Sgshapiro			*/
416964562Sgshapiro
417064562Sgshapiro			snprintf(m_tmp, MAXPATHLEN + LDAPMAP_MAX_PASSWD,
417164562Sgshapiro				 "KRBTKFILE=%s",
417264562Sgshapiro				 ldapmap_dequote(lmap->ldap_secret));
417364562Sgshapiro			lmap->ldap_secret = m_tmp;
417464562Sgshapiro			break;
417564562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
417664562Sgshapiro
417764562Sgshapiro		  default:	       /* Should NEVER get here */
417864562Sgshapiro			syserr("LDAP map: Illegal value in lmap method");
417964562Sgshapiro			return FALSE;
418064562Sgshapiro			break;
418164562Sgshapiro		}
418238032Speter	}
418338032Speter
418464562Sgshapiro	if (lmap->ldap_secret != NULL &&
418564562Sgshapiro	    (LDAPDefaults == NULL ||
418664562Sgshapiro	     LDAPDefaults == lmap ||
418764562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
418864562Sgshapiro		lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret));
418938032Speter
419064562Sgshapiro	if (lmap->ldap_base != NULL &&
419164562Sgshapiro	    (LDAPDefaults == NULL ||
419264562Sgshapiro	     LDAPDefaults == lmap ||
419364562Sgshapiro	     LDAPDefaults->ldap_base != lmap->ldap_base))
419464562Sgshapiro		lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base));
419564562Sgshapiro
419664562Sgshapiro	/*
419764562Sgshapiro	**  Save the server from extra work.  If request is for a single
419864562Sgshapiro	**  match, tell the server to only return enough records to
419964562Sgshapiro	**  determine if there is a single match or not.  This can not
420064562Sgshapiro	**  be one since the server would only return one and we wouldn't
420164562Sgshapiro	**  know if there were others available.
420264562Sgshapiro	*/
420364562Sgshapiro
420464562Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
420564562Sgshapiro		lmap->ldap_sizelimit = 2;
420664562Sgshapiro
420764562Sgshapiro	/* If setting defaults, don't process ldap_filter and ldap_attr */
420864562Sgshapiro	if (lmap == LDAPDefaults)
420964562Sgshapiro		return TRUE;
421064562Sgshapiro
421164562Sgshapiro	if (lmap->ldap_filter != NULL)
421264562Sgshapiro		lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
421338032Speter	else
421438032Speter	{
421538032Speter		if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
421638032Speter		{
421738032Speter			syserr("No filter given in map %s", map->map_mname);
421838032Speter			return FALSE;
421938032Speter		}
422038032Speter	}
422164562Sgshapiro
422264562Sgshapiro	if (lmap->ldap_attr[0] != NULL)
422338032Speter	{
422464562Sgshapiro		i = 0;
422564562Sgshapiro		p = ldapmap_dequote(lmap->ldap_attr[0]);
422664562Sgshapiro		lmap->ldap_attr[0] = NULL;
422764562Sgshapiro
422864562Sgshapiro		while (p != NULL)
422938032Speter		{
423064562Sgshapiro			char *v;
423164562Sgshapiro
423264562Sgshapiro			while (isascii(*p) && isspace(*p))
423364562Sgshapiro				p++;
423464562Sgshapiro			if (*p == '\0')
423564562Sgshapiro				break;
423664562Sgshapiro			v = p;
423764562Sgshapiro			p = strchr(v, ',');
423864562Sgshapiro			if (p != NULL)
423964562Sgshapiro				*p++ = '\0';
424064562Sgshapiro
424164562Sgshapiro			if (i == LDAPMAP_MAX_ATTR)
424264562Sgshapiro			{
424364562Sgshapiro				syserr("Too many return attributes in %s (max %d)",
424464562Sgshapiro				       map->map_mname, LDAPMAP_MAX_ATTR);
424564562Sgshapiro				return FALSE;
424664562Sgshapiro			}
424764562Sgshapiro			if (*v != '\0')
424864562Sgshapiro				lmap->ldap_attr[i++] = newstr(v);
424938032Speter		}
425064562Sgshapiro		lmap->ldap_attr[i] = NULL;
425138032Speter	}
425238032Speter
425338032Speter	map->map_db1 = (ARBPTR_T) lmap;
425438032Speter	return TRUE;
425538032Speter}
425638032Speter
425764562Sgshapiro/*
425864562Sgshapiro**  LDAPMAP_CLEAR -- set default values for LDAPMAP_STRUCT
425964562Sgshapiro**
426064562Sgshapiro**	Parameters:
426164562Sgshapiro**		lmap -- pointer to LDAPMAP_STRUCT to clear
426264562Sgshapiro**
426364562Sgshapiro**	Returns:
426464562Sgshapiro**		None.
426564562Sgshapiro**
426664562Sgshapiro*/
426764562Sgshapiro
426864562Sgshapirostatic void
426964562Sgshapiroldapmap_clear(lmap)
427064562Sgshapiro	LDAPMAP_STRUCT *lmap;
427164562Sgshapiro{
427264562Sgshapiro	lmap->ldap_host = NULL;
427364562Sgshapiro	lmap->ldap_port = LDAP_PORT;
427464562Sgshapiro	lmap->ldap_deref = LDAP_DEREF_NEVER;
427564562Sgshapiro	lmap->ldap_timelimit = LDAP_NO_LIMIT;
427664562Sgshapiro	lmap->ldap_sizelimit = LDAP_NO_LIMIT;
427764562Sgshapiro# ifdef LDAP_REFERRALS
427864562Sgshapiro	lmap->ldap_options = LDAP_OPT_REFERRALS;
427964562Sgshapiro# else /* LDAP_REFERRALS */
428064562Sgshapiro	lmap->ldap_options = 0;
428164562Sgshapiro# endif /* LDAP_REFERRALS */
428264562Sgshapiro	lmap->ldap_binddn = NULL;
428364562Sgshapiro	lmap->ldap_secret = NULL;
428464562Sgshapiro	lmap->ldap_method = LDAP_AUTH_SIMPLE;
428564562Sgshapiro	lmap->ldap_base = NULL;
428664562Sgshapiro	lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
428764562Sgshapiro	lmap->ldap_attrsonly = LDAPMAP_FALSE;
428864562Sgshapiro	lmap->ldap_timeout.tv_sec = 0;
428964562Sgshapiro	lmap->ldap_timeout.tv_usec = 0;
429064562Sgshapiro	lmap->ldap_ld = NULL;
429164562Sgshapiro	lmap->ldap_filter = NULL;
429264562Sgshapiro	lmap->ldap_attr[0] = NULL;
429364562Sgshapiro	lmap->ldap_res = NULL;
429464562Sgshapiro}
429538032Speter/*
429664562Sgshapiro**  LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
429764562Sgshapiro**
429864562Sgshapiro**	Parameters:
429964562Sgshapiro**		spec -- map argument string from LDAPDefaults option
430064562Sgshapiro**
430164562Sgshapiro**	Returns:
430264562Sgshapiro**		None.
430364562Sgshapiro**
430464562Sgshapiro*/
430564562Sgshapiro
430664562Sgshapirovoid
430764562Sgshapiroldapmap_set_defaults(spec)
430864562Sgshapiro	char *spec;
430964562Sgshapiro{
431064562Sgshapiro	MAP map;
431164562Sgshapiro
431264562Sgshapiro	/* Allocate and set the default values */
431364562Sgshapiro	if (LDAPDefaults == NULL)
431464562Sgshapiro		LDAPDefaults = (LDAPMAP_STRUCT *) xalloc(sizeof *LDAPDefaults);
431564562Sgshapiro	ldapmap_clear(LDAPDefaults);
431664562Sgshapiro
431764562Sgshapiro	memset(&map, '\0', sizeof map);
431864562Sgshapiro	map.map_db1 = (ARBPTR_T) LDAPDefaults;
431964562Sgshapiro
432064562Sgshapiro	(void) ldapmap_parseargs(&map, spec);
432164562Sgshapiro
432264562Sgshapiro	/* These should never be set in LDAPDefaults */
432364562Sgshapiro	if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) ||
432464562Sgshapiro	    map.map_spacesub != SpaceSub ||
432564562Sgshapiro	    map.map_app != NULL ||
432664562Sgshapiro	    map.map_tapp != NULL)
432764562Sgshapiro	{
432864562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
432964562Sgshapiro		if (map.map_app != NULL)
433064562Sgshapiro		{
433164562Sgshapiro			free(map.map_app);
433264562Sgshapiro			map.map_app = NULL;
433364562Sgshapiro		}
433464562Sgshapiro		if (map.map_tapp != NULL)
433564562Sgshapiro		{
433664562Sgshapiro			free(map.map_tapp);
433764562Sgshapiro			map.map_tapp = NULL;
433864562Sgshapiro		}
433964562Sgshapiro	}
434064562Sgshapiro
434164562Sgshapiro	if (LDAPDefaults->ldap_filter != NULL)
434264562Sgshapiro	{
434364562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
434464562Sgshapiro		/* don't free, it isn't malloc'ed in parseargs */
434564562Sgshapiro		LDAPDefaults->ldap_filter = NULL;
434664562Sgshapiro	}
434764562Sgshapiro
434864562Sgshapiro	if (LDAPDefaults->ldap_attr[0] != NULL)
434964562Sgshapiro	{
435064562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes");
435164562Sgshapiro		/* don't free, they aren't malloc'ed in parseargs */
435264562Sgshapiro		LDAPDefaults->ldap_attr[0] = NULL;
435364562Sgshapiro	}
435464562Sgshapiro}
435564562Sgshapiro#endif /* LDAPMAP */
435664562Sgshapiro/*
435764562Sgshapiro**  PH map
435864562Sgshapiro*/
435964562Sgshapiro
436064562Sgshapiro#ifdef PH_MAP
436164562Sgshapiro
436264562Sgshapiro/*
436364562Sgshapiro**  Support for the CCSO Nameserver (ph/qi).
436464562Sgshapiro**  This code is intended to replace the so-called "ph mailer".
436564562Sgshapiro**  Contributed by Mark D. Roth <roth@uiuc.edu>.  Contact him for support.
436664562Sgshapiro*/
436764562Sgshapiro
436864562Sgshapiro# include <qiapi.h>
436964562Sgshapiro# include <qicode.h>
437064562Sgshapiro
437164562Sgshapiro/*
437264562Sgshapiro**  PH_MAP_PARSEARGS -- parse ph map definition args.
437364562Sgshapiro*/
437464562Sgshapiro
437564562Sgshapirobool
437664562Sgshapiroph_map_parseargs(map, args)
437764562Sgshapiro	MAP *map;
437864562Sgshapiro	char *args;
437964562Sgshapiro{
438064562Sgshapiro	int i;
438164562Sgshapiro	register int done;
438264562Sgshapiro	PH_MAP_STRUCT *pmap = NULL;
438364562Sgshapiro	register char *p = args;
438464562Sgshapiro
438564562Sgshapiro	pmap = (PH_MAP_STRUCT *) xalloc(sizeof *pmap);
438664562Sgshapiro
438764562Sgshapiro	/* defaults */
438864562Sgshapiro	pmap->ph_servers = NULL;
438964562Sgshapiro	pmap->ph_field_list = NULL;
439064562Sgshapiro	pmap->ph_to_server = NULL;
439164562Sgshapiro	pmap->ph_from_server = NULL;
439264562Sgshapiro	pmap->ph_sockfd = -1;
439364562Sgshapiro	pmap->ph_timeout = 0;
439464562Sgshapiro
439564562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
439664562Sgshapiro	for (;;)
439764562Sgshapiro	{
439864562Sgshapiro		while (isascii(*p) && isspace(*p))
439964562Sgshapiro			p++;
440064562Sgshapiro		if (*p != '-')
440164562Sgshapiro			break;
440264562Sgshapiro		switch (*++p)
440364562Sgshapiro		{
440464562Sgshapiro		  case 'N':
440564562Sgshapiro			map->map_mflags |= MF_INCLNULL;
440664562Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
440764562Sgshapiro			break;
440864562Sgshapiro
440964562Sgshapiro		  case 'O':
441064562Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
441164562Sgshapiro			break;
441264562Sgshapiro
441364562Sgshapiro		  case 'o':
441464562Sgshapiro			map->map_mflags |= MF_OPTIONAL;
441564562Sgshapiro			break;
441664562Sgshapiro
441764562Sgshapiro		  case 'f':
441864562Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
441964562Sgshapiro			break;
442064562Sgshapiro
442164562Sgshapiro		  case 'm':
442264562Sgshapiro			map->map_mflags |= MF_MATCHONLY;
442364562Sgshapiro			break;
442464562Sgshapiro
442564562Sgshapiro		  case 'A':
442664562Sgshapiro			map->map_mflags |= MF_APPEND;
442764562Sgshapiro			break;
442864562Sgshapiro
442964562Sgshapiro		  case 'q':
443064562Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
443164562Sgshapiro			break;
443264562Sgshapiro
443364562Sgshapiro		  case 't':
443464562Sgshapiro			map->map_mflags |= MF_NODEFER;
443564562Sgshapiro			break;
443664562Sgshapiro
443764562Sgshapiro		  case 'a':
443864562Sgshapiro			map->map_app = ++p;
443964562Sgshapiro			break;
444064562Sgshapiro
444164562Sgshapiro		  case 'T':
444264562Sgshapiro			map->map_tapp = ++p;
444364562Sgshapiro			break;
444464562Sgshapiro
444564562Sgshapiro#if _FFR_PHMAP_TIMEOUT
444664562Sgshapiro		  case 'l':
444764562Sgshapiro			while (isascii(*++p) && isspace(*p))
444864562Sgshapiro				continue;
444964562Sgshapiro			pmap->ph_timeout = atoi(p);
445064562Sgshapiro			break;
445164562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
445264562Sgshapiro
445364562Sgshapiro		  case 'S':
445464562Sgshapiro			map->map_spacesub = *++p;
445564562Sgshapiro			break;
445664562Sgshapiro
445764562Sgshapiro		  case 'D':
445864562Sgshapiro			map->map_mflags |= MF_DEFER;
445964562Sgshapiro			break;
446064562Sgshapiro
446164562Sgshapiro		  case 'h':		/* PH server list */
446264562Sgshapiro			while (isascii(*++p) && isspace(*p))
446364562Sgshapiro				continue;
446464562Sgshapiro			pmap->ph_servers = p;
446564562Sgshapiro			break;
446664562Sgshapiro
446764562Sgshapiro		  case 'v':		/* fields to search for */
446864562Sgshapiro			while (isascii(*++p) && isspace(*p))
446964562Sgshapiro				continue;
447064562Sgshapiro			pmap->ph_field_list = p;
447164562Sgshapiro			break;
447264562Sgshapiro
447364562Sgshapiro		  default:
447464562Sgshapiro			syserr("ph_map_parseargs: unknown option -%c\n", *p);
447564562Sgshapiro		}
447664562Sgshapiro
447764562Sgshapiro		/* try to account for quoted strings */
447864562Sgshapiro		done = isascii(*p) && isspace(*p);
447964562Sgshapiro		while (*p != '\0' && !done)
448064562Sgshapiro		{
448164562Sgshapiro			if (*p == '"')
448264562Sgshapiro			{
448364562Sgshapiro				while (*++p != '"' && *p != '\0')
448464562Sgshapiro					continue;
448564562Sgshapiro				if (*p != '\0')
448664562Sgshapiro					p++;
448764562Sgshapiro			}
448864562Sgshapiro			else
448964562Sgshapiro				p++;
449064562Sgshapiro			done = isascii(*p) && isspace(*p);
449164562Sgshapiro		}
449264562Sgshapiro
449364562Sgshapiro		if (*p != '\0')
449464562Sgshapiro			*p++ = '\0';
449564562Sgshapiro	}
449664562Sgshapiro
449764562Sgshapiro	if (map->map_app != NULL)
449864562Sgshapiro		map->map_app = newstr(ph_map_dequote(map->map_app));
449964562Sgshapiro	if (map->map_tapp != NULL)
450064562Sgshapiro		map->map_tapp = newstr(ph_map_dequote(map->map_tapp));
450164562Sgshapiro
450264562Sgshapiro	if (pmap->ph_field_list != NULL)
450364562Sgshapiro		pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
450464562Sgshapiro	else
450564562Sgshapiro		pmap->ph_field_list = DEFAULT_PH_MAP_FIELDS;
450664562Sgshapiro
450764562Sgshapiro	if (pmap->ph_servers != NULL)
450864562Sgshapiro		pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
450964562Sgshapiro	else
451064562Sgshapiro	{
451164562Sgshapiro		syserr("ph_map_parseargs: -h flag is required");
451264562Sgshapiro		return FALSE;
451364562Sgshapiro	}
451464562Sgshapiro
451564562Sgshapiro	map->map_db1 = (ARBPTR_T) pmap;
451664562Sgshapiro	return TRUE;
451764562Sgshapiro}
451864562Sgshapiro
451964562Sgshapiro#if _FFR_PHMAP_TIMEOUT
452064562Sgshapiro/*
452164562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
452264562Sgshapiro*/
452364562Sgshapiro
452464562Sgshapirostatic void
452564562Sgshapiroph_map_safeclose(map)
452664562Sgshapiro	MAP *map;
452764562Sgshapiro{
452864562Sgshapiro	int save_errno = errno;
452964562Sgshapiro	PH_MAP_STRUCT *pmap;
453064562Sgshapiro
453164562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
453264562Sgshapiro
453364562Sgshapiro	if (pmap->ph_sockfd != -1)
453464562Sgshapiro	{
453564562Sgshapiro		(void) close(pmap->ph_sockfd);
453664562Sgshapiro		pmap->ph_sockfd = -1;
453764562Sgshapiro	}
453864562Sgshapiro	if (pmap->ph_from_server != NULL)
453964562Sgshapiro	{
454064562Sgshapiro		(void) fclose(pmap->ph_from_server);
454164562Sgshapiro		pmap->ph_from_server = NULL;
454264562Sgshapiro	}
454364562Sgshapiro	if (pmap->ph_to_server != NULL)
454464562Sgshapiro	{
454564562Sgshapiro		(void) fclose(pmap->ph_to_server);
454664562Sgshapiro		pmap->ph_to_server = NULL;
454764562Sgshapiro	}
454864562Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
454964562Sgshapiro	errno = save_errno;
455064562Sgshapiro}
455164562Sgshapiro
455264562Sgshapirovoid
455364562Sgshapiroph_map_close(map)
455464562Sgshapiro	MAP *map;
455564562Sgshapiro{
455664562Sgshapiro	PH_MAP_STRUCT *pmap;
455764562Sgshapiro
455864562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
455964562Sgshapiro	(void) fprintf(pmap->ph_to_server, "quit\n");
456064562Sgshapiro	(void) fflush(pmap->ph_to_server);
456164562Sgshapiro	ph_map_safeclose(map);
456264562Sgshapiro}
456364562Sgshapiro
456464562Sgshapirostatic jmp_buf  PHTimeout;
456564562Sgshapiro
456664562Sgshapiro/* ARGSUSED */
456764562Sgshapirostatic void
456864562Sgshapiroph_timeout_func(sig_no)
456964562Sgshapiro	int sig_no;
457064562Sgshapiro{
457164562Sgshapiro	longjmp(PHTimeout, 1);
457264562Sgshapiro}
457364562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
457464562Sgshapiro/*
457564562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
457664562Sgshapiro*/
457764562Sgshapiro
457864562Sgshapirovoid
457964562Sgshapiroph_map_close(map)
458064562Sgshapiro	MAP *map;
458164562Sgshapiro{
458264562Sgshapiro	PH_MAP_STRUCT *pmap;
458364562Sgshapiro
458464562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
458564562Sgshapiro	CloseQi(pmap->ph_to_server, pmap->ph_from_server);
458664562Sgshapiro	pmap->ph_to_server = NULL;
458764562Sgshapiro	pmap->ph_from_server = NULL;
458864562Sgshapiro}
458964562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
459064562Sgshapiro
459164562Sgshapiro/*
459264562Sgshapiro**  PH_MAP_OPEN -- sub for opening PH map
459364562Sgshapiro*/
459464562Sgshapirobool
459564562Sgshapiroph_map_open(map, mode)
459664562Sgshapiro	MAP *map;
459764562Sgshapiro	int mode;
459864562Sgshapiro{
459964562Sgshapiro#if !_FFR_PHMAP_TIMEOUT
460064562Sgshapiro	int save_errno = 0;
460164562Sgshapiro#endif /* !_FFR_PHMAP_TIMEOUT */
460264562Sgshapiro	int j;
460364562Sgshapiro	char *hostlist, *tmp;
460464562Sgshapiro	QIR *server_data = NULL;
460564562Sgshapiro	PH_MAP_STRUCT *pmap;
460664562Sgshapiro#if _FFR_PHMAP_TIMEOUT
460764562Sgshapiro	register EVENT *ev = NULL;
460864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
460964562Sgshapiro
461064562Sgshapiro	if (tTd(38, 2))
461164562Sgshapiro		dprintf("ph_map_open(%s)\n", map->map_mname);
461264562Sgshapiro
461364562Sgshapiro	mode &= O_ACCMODE;
461464562Sgshapiro	if (mode != O_RDONLY)
461564562Sgshapiro	{
461664562Sgshapiro		/* issue a pseudo-error message */
461764562Sgshapiro# ifdef ENOSYS
461864562Sgshapiro		errno = ENOSYS;
461964562Sgshapiro# else /* ENOSYS */
462064562Sgshapiro#  ifdef EFTYPE
462164562Sgshapiro		errno = EFTYPE;
462264562Sgshapiro#  else /* EFTYPE */
462364562Sgshapiro		errno = ENXIO;
462464562Sgshapiro#  endif /* EFTYPE */
462564562Sgshapiro# endif /* ENOSYS */
462664562Sgshapiro		return FALSE;
462764562Sgshapiro	}
462864562Sgshapiro
462966494Sgshapiro	if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER &&
463066494Sgshapiro	    bitset(MF_DEFER, map->map_mflags))
463166494Sgshapiro	{
463266494Sgshapiro		if (tTd(9, 1))
463366494Sgshapiro			dprintf("ph_map_open(%s) => DEFERRED\n",
463466494Sgshapiro			        map->map_mname);
463566494Sgshapiro
463666494Sgshapiro		/*
463766494Sgshapiro		** Unset MF_DEFER here so that map_lookup() returns
463866494Sgshapiro		** a temporary failure using the bogus map and
463966494Sgshapiro		** map->map_tapp instead of the default permanent error.
464066494Sgshapiro		*/
464166494Sgshapiro
464266494Sgshapiro		map->map_mflags &= ~MF_DEFER;
464366494Sgshapiro		return FALSE;
464466494Sgshapiro	}
464566494Sgshapiro
464664562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
464764562Sgshapiro
464864562Sgshapiro	hostlist = newstr(pmap->ph_servers);
464964562Sgshapiro	tmp = strtok(hostlist, " ");
465064562Sgshapiro	do
465164562Sgshapiro	{
465264562Sgshapiro#if _FFR_PHMAP_TIMEOUT
465364562Sgshapiro		if (pmap->ph_timeout != 0)
465464562Sgshapiro		{
465564562Sgshapiro			if (setjmp(PHTimeout) != 0)
465664562Sgshapiro			{
465764562Sgshapiro				ev = NULL;
465864562Sgshapiro				if (LogLevel > 1)
465964562Sgshapiro					sm_syslog(LOG_NOTICE, CurEnv->e_id,
466064562Sgshapiro						  "timeout connecting to PH server %.100s",
466164562Sgshapiro						  tmp);
466264562Sgshapiro# ifdef ETIMEDOUT
466364562Sgshapiro				errno = ETIMEDOUT;
466464562Sgshapiro# else /* ETIMEDOUT */
466566494Sgshapiro				errno = EAGAIN;
466664562Sgshapiro# endif /* ETIMEDOUT */
466764562Sgshapiro				goto ph_map_open_abort;
466864562Sgshapiro			}
466964562Sgshapiro			ev = setevent(pmap->ph_timeout, ph_timeout_func, 0);
467064562Sgshapiro		}
467164562Sgshapiro		if (!OpenQiSock(tmp, &(pmap->ph_sockfd)) &&
467264562Sgshapiro		    !Sock2FILEs(pmap->ph_sockfd, &(pmap->ph_to_server),
467364562Sgshapiro				&(pmap->ph_from_server)) &&
467464562Sgshapiro		    fprintf(pmap->ph_to_server, "id sendmail+phmap\n") >= 0 &&
467564562Sgshapiro		    fflush(pmap->ph_to_server) == 0 &&
467664562Sgshapiro		    (server_data = ReadQi(pmap->ph_from_server, &j)) != NULL &&
467764562Sgshapiro		    server_data->code == 200)
467864562Sgshapiro		{
467964562Sgshapiro			if (ev != NULL)
468064562Sgshapiro				clrevent(ev);
468164562Sgshapiro			FreeQIR(server_data);
468264562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
468364562Sgshapiro		if (OpenQi(tmp, &(pmap->ph_to_server),
468464562Sgshapiro			   &(pmap->ph_from_server)) >= 0)
468564562Sgshapiro		{
468664562Sgshapiro			if (fprintf(pmap->ph_to_server,
468764562Sgshapiro				    "id sendmail+phmap\n") < 0 ||
468864562Sgshapiro			    fflush(pmap->ph_to_server) < 0 ||
468964562Sgshapiro			    (server_data = ReadQi(pmap->ph_from_server,
469064562Sgshapiro						  &j)) == NULL ||
469164562Sgshapiro			    server_data->code != 200)
469264562Sgshapiro			{
469364562Sgshapiro				save_errno = errno;
469464562Sgshapiro				CloseQi(pmap->ph_to_server,
469564562Sgshapiro					pmap->ph_from_server);
469664562Sgshapiro				continue;
469764562Sgshapiro			}
469864562Sgshapiro			if (server_data != NULL)
469964562Sgshapiro				FreeQIR(server_data);
470064562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
470164562Sgshapiro			free(hostlist);
470264562Sgshapiro			return TRUE;
470364562Sgshapiro		}
470464562Sgshapiro#if _FFR_PHMAP_TIMEOUT
470564562Sgshapiro  ph_map_open_abort:
470664562Sgshapiro		if (ev != NULL)
470764562Sgshapiro			clrevent(ev);
470864562Sgshapiro		ph_map_safeclose(map);
470964562Sgshapiro		if (server_data != NULL)
471064562Sgshapiro		{
471164562Sgshapiro			FreeQIR(server_data);
471264562Sgshapiro			server_data = NULL;
471364562Sgshapiro		}
471464562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
471564562Sgshapiro		save_errno = errno;
471664562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
471764562Sgshapiro	} while (tmp = strtok(NULL, " "));
471864562Sgshapiro
471964562Sgshapiro#if !_FFR_PHMAP_TIMEOUT
472064562Sgshapiro	errno = save_errno;
472164562Sgshapiro#endif /* !_FFR_PHMAP_TIMEOUT */
472266494Sgshapiro	if (bitset(MF_NODEFER, map->map_mflags))
472364562Sgshapiro	{
472466494Sgshapiro		if (errno == 0)
472564562Sgshapiro			errno = EAGAIN;
472666494Sgshapiro		syserr("ph_map_open: %s: cannot connect to PH server",
472766494Sgshapiro		       map->map_mname);
472864562Sgshapiro	}
472966494Sgshapiro	else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1)
473064562Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
473166494Sgshapiro			  "ph_map_open: %s: cannot connect to PH server",
473266494Sgshapiro			  map->map_mname);
473364562Sgshapiro	free(hostlist);
473464562Sgshapiro	return FALSE;
473564562Sgshapiro}
473664562Sgshapiro
473764562Sgshapiro/*
473864562Sgshapiro**  PH_MAP_LOOKUP -- look up key from ph server
473964562Sgshapiro*/
474064562Sgshapiro
474164562Sgshapiro#if _FFR_PHMAP_TIMEOUT
474264562Sgshapiro# define MAX_PH_FIELDS	20
474364562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
474464562Sgshapiro
474564562Sgshapirochar *
474664562Sgshapiroph_map_lookup(map, key, args, pstat)
474764562Sgshapiro	MAP *map;
474864562Sgshapiro	char *key;
474964562Sgshapiro	char **args;
475064562Sgshapiro	int *pstat;
475164562Sgshapiro{
475264562Sgshapiro	int j;
475364562Sgshapiro	size_t sz;
475464562Sgshapiro	char *tmp, *tmp2;
475564562Sgshapiro	char *message = NULL, *field = NULL, *fmtkey;
475664562Sgshapiro	QIR *server_data = NULL;
475764562Sgshapiro	QIR *qirp;
475864562Sgshapiro	char keybuf[MAXKEY + 1], fieldbuf[101];
475964562Sgshapiro#if _FFR_PHMAP_TIMEOUT
476064562Sgshapiro	QIR *hold_data[MAX_PH_FIELDS];
476164562Sgshapiro	int hold_data_idx = 0;
476264562Sgshapiro	register EVENT *ev = NULL;
476364562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
476464562Sgshapiro	PH_MAP_STRUCT *pmap;
476564562Sgshapiro
476664562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
476764562Sgshapiro
476864562Sgshapiro	*pstat = EX_OK;
476964562Sgshapiro
477064562Sgshapiro#if _FFR_PHMAP_TIMEOUT
477164562Sgshapiro	if (pmap->ph_timeout != 0)
477264562Sgshapiro	{
477364562Sgshapiro		if (setjmp(PHTimeout) != 0)
477464562Sgshapiro		{
477564562Sgshapiro			ev = NULL;
477664562Sgshapiro			if (LogLevel > 1)
477764562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
477864562Sgshapiro					  "timeout during PH lookup of %.100s",
477964562Sgshapiro					  key);
478064562Sgshapiro# ifdef ETIMEDOUT
478164562Sgshapiro			errno = ETIMEDOUT;
478264562Sgshapiro# else /* ETIMEDOUT */
478364562Sgshapiro			errno = 0;
478464562Sgshapiro# endif /* ETIMEDOUT */
478564562Sgshapiro			*pstat = EX_TEMPFAIL;
478664562Sgshapiro			goto ph_map_lookup_abort;
478764562Sgshapiro		}
478864562Sgshapiro		ev = setevent(pmap->ph_timeout, ph_timeout_func, 0);
478964562Sgshapiro	}
479064562Sgshapiro
479164562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
479264562Sgshapiro	/* check all relevant fields */
479364562Sgshapiro	tmp = pmap->ph_field_list;
479464562Sgshapiro	do
479564562Sgshapiro	{
479664562Sgshapiro#if _FFR_PHMAP_TIMEOUT
479764562Sgshapiro		server_data = NULL;
479864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
479964562Sgshapiro		while (isascii(*tmp) && isspace(*tmp))
480064562Sgshapiro			tmp++;
480164562Sgshapiro		if (*tmp == '\0')
480264562Sgshapiro			break;
480364562Sgshapiro		sz = strcspn(tmp, " ") + 1;
480464562Sgshapiro		if (sz > sizeof fieldbuf)
480564562Sgshapiro			sz = sizeof fieldbuf;
480664562Sgshapiro		(void) strlcpy(fieldbuf, tmp, sz);
480764562Sgshapiro		field = fieldbuf;
480864562Sgshapiro		tmp += sz;
480964562Sgshapiro
481064562Sgshapiro		(void) strlcpy(keybuf, key, sizeof keybuf);
481164562Sgshapiro		fmtkey = keybuf;
481264562Sgshapiro		if (strcmp(field, "alias") == 0)
481364562Sgshapiro		{
481464562Sgshapiro			/*
481564562Sgshapiro			**  for alias lookups, replace any punctuation
481664562Sgshapiro			**  characters with '-'
481764562Sgshapiro			*/
481864562Sgshapiro
481964562Sgshapiro			for (tmp2 = fmtkey; *tmp2 !=  '\0'; tmp2++)
482064562Sgshapiro			{
482164562Sgshapiro				if (isascii(*tmp2) && ispunct(*tmp2))
482264562Sgshapiro					*tmp2 = '-';
482364562Sgshapiro			}
482464562Sgshapiro			tmp2 = field;
482564562Sgshapiro		}
482664562Sgshapiro		else if (strcmp(field,"spacedname") == 0)
482764562Sgshapiro		{
482864562Sgshapiro			/*
482964562Sgshapiro			**  for "spaced" name lookups, replace any
483064562Sgshapiro			**  punctuation characters with a space
483164562Sgshapiro			*/
483264562Sgshapiro
483364562Sgshapiro			for (tmp2 = fmtkey; *tmp2 != '\0'; tmp2++)
483464562Sgshapiro			{
483564562Sgshapiro				if (isascii(*tmp2) && ispunct(*tmp2) &&
483664562Sgshapiro				    *tmp2 != '*')
483764562Sgshapiro					*tmp2 = ' ';
483864562Sgshapiro			}
483964562Sgshapiro			tmp2 = &(field[6]);
484064562Sgshapiro		}
484164562Sgshapiro		else
484264562Sgshapiro			tmp2 = field;
484364562Sgshapiro
484464562Sgshapiro		if (LogLevel > 9)
484564562Sgshapiro			sm_syslog(LOG_NOTICE, CurEnv->e_id,
484664562Sgshapiro				  "ph_map_lookup: query %s=\"%s\" return email",
484764562Sgshapiro				  tmp2, fmtkey);
484864562Sgshapiro		if (tTd(38, 20))
484964562Sgshapiro			dprintf("ph_map_lookup: query %s=\"%s\" return email\n",
485064562Sgshapiro				tmp2, fmtkey);
485164562Sgshapiro
485264562Sgshapiro		j = 0;
485364562Sgshapiro
485464562Sgshapiro		if (fprintf(pmap->ph_to_server, "query %s=%s return email\n",
485564562Sgshapiro			    tmp2, fmtkey) < 0)
485664562Sgshapiro			message = "qi query command failed";
485764562Sgshapiro		else if (fflush(pmap->ph_to_server) < 0)
485864562Sgshapiro			message = "qi fflush failed";
485964562Sgshapiro		else if ((server_data = ReadQi(pmap->ph_from_server,
486064562Sgshapiro					       &j)) == NULL)
486164562Sgshapiro			message = "ReadQi() returned NULL";
486264562Sgshapiro
486364562Sgshapiro#if _FFR_PHMAP_TIMEOUT
486464562Sgshapiro		if ((hold_data[hold_data_idx] = server_data) != NULL)
486564562Sgshapiro		{
486664562Sgshapiro			/* save pointer for later free() */
486764562Sgshapiro			hold_data_idx++;
486864562Sgshapiro		}
486964562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
487064562Sgshapiro
487164562Sgshapiro		if (server_data == NULL ||
487264562Sgshapiro		    (server_data->code >= 400 &&
487364562Sgshapiro		     server_data->code < 500))
487464562Sgshapiro		{
487564562Sgshapiro			/* temporary failure */
487664562Sgshapiro			*pstat = EX_TEMPFAIL;
487764562Sgshapiro#if _FFR_PHMAP_TIMEOUT
487864562Sgshapiro			break;
487964562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
488064562Sgshapiro			if (server_data != NULL)
488164562Sgshapiro			{
488264562Sgshapiro				FreeQIR(server_data);
488364562Sgshapiro				server_data = NULL;
488464562Sgshapiro			}
488564562Sgshapiro			return NULL;
488664562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
488764562Sgshapiro		}
488864562Sgshapiro
488964562Sgshapiro		/*
489064562Sgshapiro		**  if we found a single match, break out.
489164562Sgshapiro		**  otherwise, try the next field.
489264562Sgshapiro		*/
489364562Sgshapiro
489464562Sgshapiro		if (j == 1)
489564562Sgshapiro			break;
489664562Sgshapiro
489764562Sgshapiro		/*
489864562Sgshapiro		**  check for a single response which is an error:
489964562Sgshapiro		**  ReadQi() doesn't set j on error responses,
490064562Sgshapiro		**  but we should stop here instead of moving on if
490164562Sgshapiro		**  it happens (e.g., alias found but email field empty)
490264562Sgshapiro		*/
490364562Sgshapiro
490464562Sgshapiro		for (qirp = server_data;
490564562Sgshapiro		     qirp != NULL && qirp->code < 0;
490664562Sgshapiro		     qirp++)
490764562Sgshapiro		{
490864562Sgshapiro			if (tTd(38, 20))
490964562Sgshapiro				dprintf("ph_map_lookup: QIR: %d:%d:%d:%s\n",
491064562Sgshapiro					qirp->code, qirp->subcode, qirp->field,
491164562Sgshapiro					(qirp->message ? qirp->message
491264562Sgshapiro					 : "[NULL]"));
491364562Sgshapiro			if (qirp->code <= -500)
491464562Sgshapiro			{
491564562Sgshapiro				j = 0;
491664562Sgshapiro				goto ph_map_lookup_abort;
491764562Sgshapiro			}
491864562Sgshapiro		}
491964562Sgshapiro
492064562Sgshapiro#if _FFR_PHMAP_TIMEOUT
492164562Sgshapiro	} while (*tmp != '\0' && hold_data_idx < MAX_PH_FIELDS);
492264562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
492364562Sgshapiro	} while (*tmp != '\0');
492464562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
492564562Sgshapiro
492664562Sgshapiro  ph_map_lookup_abort:
492764562Sgshapiro#if _FFR_PHMAP_TIMEOUT
492864562Sgshapiro	if (ev != NULL)
492964562Sgshapiro		clrevent(ev);
493064562Sgshapiro
493164562Sgshapiro	/*
493264562Sgshapiro	**  Return EX_TEMPFAIL if the timer popped
493364562Sgshapiro	**  or we got a temporary PH error
493464562Sgshapiro	*/
493564562Sgshapiro
493664562Sgshapiro	if (*pstat == EX_TEMPFAIL)
493764562Sgshapiro		ph_map_safeclose(map);
493864562Sgshapiro
493964562Sgshapiro	/* if we didn't find a single match, bail out */
494064562Sgshapiro	if (*pstat == EX_OK && j != 1)
494164562Sgshapiro		*pstat = EX_UNAVAILABLE;
494264562Sgshapiro
494364562Sgshapiro	if (*pstat == EX_OK)
494464562Sgshapiro	{
494564562Sgshapiro		/*
494664562Sgshapiro		** skip leading whitespace and chop at first address
494764562Sgshapiro		*/
494864562Sgshapiro
494964562Sgshapiro		for (tmp = server_data->message;
495064562Sgshapiro		     isascii(*tmp) && isspace(*tmp);
495164562Sgshapiro		     tmp++)
495264562Sgshapiro			continue;
495364562Sgshapiro
495464562Sgshapiro		for (tmp2 = tmp; *tmp2 != '\0'; tmp2++)
495564562Sgshapiro		{
495664562Sgshapiro			if (isascii(*tmp2) && isspace(*tmp2))
495764562Sgshapiro			{
495864562Sgshapiro				*tmp2 = '\0';
495964562Sgshapiro				break;
496064562Sgshapiro			}
496164562Sgshapiro		}
496264562Sgshapiro
496364562Sgshapiro		if (tTd(38,20))
496464562Sgshapiro			dprintf("ph_map_lookup: %s => %s\n", key, tmp);
496564562Sgshapiro
496664562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
496764562Sgshapiro			message = map_rewrite(map, key, strlen(key), NULL);
496864562Sgshapiro		else
496964562Sgshapiro			message = map_rewrite(map, tmp, strlen(tmp), args);
497064562Sgshapiro	}
497164562Sgshapiro
497264562Sgshapiro	/*
497364562Sgshapiro	**  Deferred free() of returned server_data values
497464562Sgshapiro	**  the deferral is to avoid the risk of a free() being
497564562Sgshapiro	**  interrupted by the event timer.  By now the timeout event
497664562Sgshapiro	**  has been cleared and none of the data is still in use.
497764562Sgshapiro	*/
497864562Sgshapiro
497964562Sgshapiro	while (--hold_data_idx >= 0)
498064562Sgshapiro	{
498164562Sgshapiro		if (hold_data[hold_data_idx] != NULL)
498264562Sgshapiro			FreeQIR(hold_data[hold_data_idx]);
498364562Sgshapiro	}
498464562Sgshapiro
498564562Sgshapiro	if (*pstat == EX_OK)
498664562Sgshapiro		return message;
498764562Sgshapiro
498864562Sgshapiro	return NULL;
498964562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
499064562Sgshapiro	/* if we didn't find a single match, bail out */
499164562Sgshapiro	if (j != 1)
499264562Sgshapiro	{
499364562Sgshapiro		*pstat = EX_UNAVAILABLE;
499464562Sgshapiro		if (server_data != NULL)
499564562Sgshapiro		{
499664562Sgshapiro			FreeQIR(server_data);
499764562Sgshapiro			server_data = NULL;
499864562Sgshapiro		}
499964562Sgshapiro		return NULL;
500064562Sgshapiro	}
500164562Sgshapiro
500264562Sgshapiro	/*
500364562Sgshapiro	** skip leading whitespace and chop at first address
500464562Sgshapiro	*/
500564562Sgshapiro
500664562Sgshapiro	for (tmp = server_data->message;
500764562Sgshapiro	     isascii(*tmp) && isspace(*tmp);
500864562Sgshapiro	     tmp++)
500964562Sgshapiro		continue;
501064562Sgshapiro
501164562Sgshapiro	for (tmp2 = tmp; *tmp2 != '\0'; tmp2++)
501264562Sgshapiro	{
501364562Sgshapiro		if (isascii(*tmp2) && isspace(*tmp2))
501464562Sgshapiro		{
501564562Sgshapiro			*tmp2 = '\0';
501664562Sgshapiro			break;
501764562Sgshapiro		}
501864562Sgshapiro	}
501964562Sgshapiro
502064562Sgshapiro	if (tTd(38,20))
502164562Sgshapiro		dprintf("ph_map_lookup: %s => %s\n", key, tmp);
502264562Sgshapiro
502364562Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
502464562Sgshapiro		message = map_rewrite(map, key, strlen(key), NULL);
502564562Sgshapiro	else
502664562Sgshapiro		message = map_rewrite(map, tmp, strlen(tmp), args);
502764562Sgshapiro	if (server_data != NULL)
502864562Sgshapiro	{
502964562Sgshapiro		FreeQIR(server_data);
503064562Sgshapiro		server_data = NULL;
503164562Sgshapiro	}
503264562Sgshapiro	return message;
503364562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
503464562Sgshapiro}
503564562Sgshapiro#endif /* PH_MAP */
503664562Sgshapiro/*
503742575Speter**  syslog map
503838032Speter*/
503938032Speter
504038032Speter#define map_prio	map_lockfd	/* overload field */
504138032Speter
504238032Speter/*
504342575Speter**  SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
504438032Speter*/
504538032Speter
504638032Speterbool
504738032Spetersyslog_map_parseargs(map, args)
504838032Speter	MAP *map;
504938032Speter	char *args;
505038032Speter{
505138032Speter	char *p = args;
505238032Speter	char *priority = NULL;
505338032Speter
505464562Sgshapiro	/* there is no check whether there is really an argument */
505564562Sgshapiro	while (*p != '\0')
505638032Speter	{
505738032Speter		while (isascii(*p) && isspace(*p))
505838032Speter			p++;
505938032Speter		if (*p != '-')
506038032Speter			break;
506164562Sgshapiro		++p;
506264562Sgshapiro		if (*p == 'D')
506364562Sgshapiro		{
506464562Sgshapiro			map->map_mflags |= MF_DEFER;
506564562Sgshapiro			++p;
506664562Sgshapiro		}
506764562Sgshapiro		else if (*p == 'S')
506864562Sgshapiro		{
506964562Sgshapiro			map->map_spacesub = *++p;
507064562Sgshapiro			if (*p != '\0')
507164562Sgshapiro				p++;
507264562Sgshapiro		}
507364562Sgshapiro		else if (*p == 'L')
507464562Sgshapiro		{
507564562Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p))
507664562Sgshapiro				continue;
507764562Sgshapiro			if (*p == '\0')
507864562Sgshapiro				break;
507964562Sgshapiro			priority = p;
508064562Sgshapiro			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
508164562Sgshapiro				p++;
508264562Sgshapiro			if (*p != '\0')
508364562Sgshapiro				*p++ = '\0';
508464562Sgshapiro		}
508564562Sgshapiro		else
508664562Sgshapiro		{
508764562Sgshapiro			syserr("Illegal option %c map syslog", *p);
508864562Sgshapiro			++p;
508964562Sgshapiro		}
509038032Speter	}
509138032Speter
509238032Speter	if (priority == NULL)
509338032Speter		map->map_prio = LOG_INFO;
509438032Speter	else
509538032Speter	{
509638032Speter		if (strncasecmp("LOG_", priority, 4) == 0)
509738032Speter			priority += 4;
509838032Speter
509938032Speter#ifdef LOG_EMERG
510038032Speter		if (strcasecmp("EMERG", priority) == 0)
510138032Speter			map->map_prio = LOG_EMERG;
510238032Speter		else
510364562Sgshapiro#endif /* LOG_EMERG */
510438032Speter#ifdef LOG_ALERT
510538032Speter		if (strcasecmp("ALERT", priority) == 0)
510638032Speter			map->map_prio = LOG_ALERT;
510738032Speter		else
510864562Sgshapiro#endif /* LOG_ALERT */
510938032Speter#ifdef LOG_CRIT
511038032Speter		if (strcasecmp("CRIT", priority) == 0)
511138032Speter			map->map_prio = LOG_CRIT;
511238032Speter		else
511364562Sgshapiro#endif /* LOG_CRIT */
511438032Speter#ifdef LOG_ERR
511538032Speter		if (strcasecmp("ERR", priority) == 0)
511638032Speter			map->map_prio = LOG_ERR;
511738032Speter		else
511864562Sgshapiro#endif /* LOG_ERR */
511938032Speter#ifdef LOG_WARNING
512038032Speter		if (strcasecmp("WARNING", priority) == 0)
512138032Speter			map->map_prio = LOG_WARNING;
512238032Speter		else
512364562Sgshapiro#endif /* LOG_WARNING */
512438032Speter#ifdef LOG_NOTICE
512538032Speter		if (strcasecmp("NOTICE", priority) == 0)
512638032Speter			map->map_prio = LOG_NOTICE;
512738032Speter		else
512864562Sgshapiro#endif /* LOG_NOTICE */
512938032Speter#ifdef LOG_INFO
513038032Speter		if (strcasecmp("INFO", priority) == 0)
513138032Speter			map->map_prio = LOG_INFO;
513238032Speter		else
513364562Sgshapiro#endif /* LOG_INFO */
513438032Speter#ifdef LOG_DEBUG
513538032Speter		if (strcasecmp("DEBUG", priority) == 0)
513638032Speter			map->map_prio = LOG_DEBUG;
513738032Speter		else
513864562Sgshapiro#endif /* LOG_DEBUG */
513938032Speter		{
514038032Speter			syserr("syslog_map_parseargs: Unknown priority %s\n",
514138032Speter			       priority);
514238032Speter			return FALSE;
514338032Speter		}
514438032Speter	}
514538032Speter	return TRUE;
514638032Speter}
514738032Speter
514838032Speter/*
514942575Speter**  SYSLOG_MAP_LOOKUP -- rewrite and syslog message.  Always return empty string
515038032Speter*/
515138032Speter
515238032Speterchar *
515338032Spetersyslog_map_lookup(map, string, args, statp)
515438032Speter	MAP *map;
515538032Speter	char *string;
515638032Speter	char **args;
515738032Speter	int *statp;
515838032Speter{
515938032Speter	char *ptr = map_rewrite(map, string, strlen(string), args);
516038032Speter
516138032Speter	if (ptr != NULL)
516238032Speter	{
516338032Speter		if (tTd(38, 20))
516464562Sgshapiro			dprintf("syslog_map_lookup(%s (priority %d): %s\n",
516564562Sgshapiro				map->map_mname, map->map_prio, ptr);
516638032Speter
516738032Speter		sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
516838032Speter	}
516938032Speter
517038032Speter	*statp = EX_OK;
517138032Speter	return "";
517238032Speter}
517338032Speter
517438032Speter/*
517538032Speter**  HESIOD Modules
517638032Speter*/
517738032Speter
517838032Speter#ifdef HESIOD
517938032Speter
518038032Speterbool
518138032Speterhes_map_open(map, mode)
518238032Speter	MAP *map;
518338032Speter	int mode;
518438032Speter{
518538032Speter	if (tTd(38, 2))
518664562Sgshapiro		dprintf("hes_map_open(%s, %s, %d)\n",
518738032Speter			map->map_mname, map->map_file, mode);
518838032Speter
518938032Speter	if (mode != O_RDONLY)
519038032Speter	{
519138032Speter		/* issue a pseudo-error message */
519264562Sgshapiro# ifdef ENOSYS
519338032Speter		errno = ENOSYS;
519464562Sgshapiro# else /* ENOSYS */
519564562Sgshapiro#  ifdef EFTYPE
519638032Speter		errno = EFTYPE;
519764562Sgshapiro#  else /* EFTYPE */
519838032Speter		errno = ENXIO;
519964562Sgshapiro#  endif /* EFTYPE */
520064562Sgshapiro# endif /* ENOSYS */
520138032Speter		return FALSE;
520238032Speter	}
520338032Speter
520464562Sgshapiro# ifdef HESIOD_INIT
520538032Speter	if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
520638032Speter		return TRUE;
520738032Speter
520838032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
520964562Sgshapiro		syserr("421 4.0.0 cannot initialize Hesiod map (%s)",
521038032Speter			errstring(errno));
521138032Speter	return FALSE;
521264562Sgshapiro# else /* HESIOD_INIT */
521338032Speter	if (hes_error() == HES_ER_UNINIT)
521438032Speter		hes_init();
521538032Speter	switch (hes_error())
521638032Speter	{
521738032Speter	  case HES_ER_OK:
521838032Speter	  case HES_ER_NOTFOUND:
521938032Speter		return TRUE;
522038032Speter	}
522138032Speter
522238032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
522364562Sgshapiro		syserr("421 4.0.0 cannot initialize Hesiod map (%d)", hes_error());
522438032Speter
522538032Speter	return FALSE;
522664562Sgshapiro# endif /* HESIOD_INIT */
522738032Speter}
522838032Speter
522938032Speterchar *
523038032Speterhes_map_lookup(map, name, av, statp)
523138032Speter	MAP *map;
523238032Speter	char *name;
523338032Speter	char **av;
523438032Speter	int *statp;
523538032Speter{
523638032Speter	char **hp;
523738032Speter
523838032Speter	if (tTd(38, 20))
523964562Sgshapiro		dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
524038032Speter
524138032Speter	if (name[0] == '\\')
524238032Speter	{
524338032Speter		char *np;
524438032Speter		int nl;
524538032Speter		char nbuf[MAXNAME];
524638032Speter
524738032Speter		nl = strlen(name);
524838032Speter		if (nl < sizeof nbuf - 1)
524938032Speter			np = nbuf;
525038032Speter		else
525138032Speter			np = xalloc(strlen(name) + 2);
525238032Speter		np[0] = '\\';
525364562Sgshapiro		(void) strlcpy(&np[1], name, (sizeof nbuf) - 1);
525464562Sgshapiro# ifdef HESIOD_INIT
525538032Speter		hp = hesiod_resolve(HesiodContext, np, map->map_file);
525664562Sgshapiro# else /* HESIOD_INIT */
525738032Speter		hp = hes_resolve(np, map->map_file);
525864562Sgshapiro# endif /* HESIOD_INIT */
525938032Speter		if (np != nbuf)
526038032Speter			free(np);
526138032Speter	}
526238032Speter	else
526338032Speter	{
526464562Sgshapiro# ifdef HESIOD_INIT
526538032Speter		hp = hesiod_resolve(HesiodContext, name, map->map_file);
526664562Sgshapiro# else /* HESIOD_INIT */
526738032Speter		hp = hes_resolve(name, map->map_file);
526864562Sgshapiro# endif /* HESIOD_INIT */
526938032Speter	}
527064562Sgshapiro# ifdef HESIOD_INIT
527138032Speter	if (hp == NULL)
527238032Speter		return NULL;
527338032Speter	if (*hp == NULL)
527438032Speter	{
527538032Speter		hesiod_free_list(HesiodContext, hp);
527638032Speter		switch (errno)
527738032Speter		{
527838032Speter		  case ENOENT:
527938032Speter			  *statp = EX_NOTFOUND;
528038032Speter			  break;
528138032Speter		  case ECONNREFUSED:
528238032Speter		  case EMSGSIZE:
528338032Speter			  *statp = EX_TEMPFAIL;
528438032Speter			  break;
528538032Speter		  case ENOMEM:
528638032Speter		  default:
528738032Speter			  *statp = EX_UNAVAILABLE;
528838032Speter			  break;
528938032Speter		}
529038032Speter		return NULL;
529138032Speter	}
529264562Sgshapiro# else /* HESIOD_INIT */
529338032Speter	if (hp == NULL || hp[0] == NULL)
529438032Speter	{
529538032Speter		switch (hes_error())
529638032Speter		{
529738032Speter		  case HES_ER_OK:
529838032Speter			*statp = EX_OK;
529938032Speter			break;
530038032Speter
530138032Speter		  case HES_ER_NOTFOUND:
530238032Speter			*statp = EX_NOTFOUND;
530338032Speter			break;
530438032Speter
530538032Speter		  case HES_ER_CONFIG:
530638032Speter			*statp = EX_UNAVAILABLE;
530738032Speter			break;
530838032Speter
530938032Speter		  case HES_ER_NET:
531038032Speter			*statp = EX_TEMPFAIL;
531138032Speter			break;
531238032Speter		}
531338032Speter		return NULL;
531438032Speter	}
531564562Sgshapiro# endif /* HESIOD_INIT */
531638032Speter
531738032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
531838032Speter		return map_rewrite(map, name, strlen(name), NULL);
531938032Speter	else
532038032Speter		return map_rewrite(map, hp[0], strlen(hp[0]), av);
532138032Speter}
532238032Speter
532364562Sgshapiro#endif /* HESIOD */
532438032Speter/*
532538032Speter**  NeXT NETINFO Modules
532638032Speter*/
532738032Speter
532838032Speter#if NETINFO
532938032Speter
533038032Speter# define NETINFO_DEFAULT_DIR		"/aliases"
533138032Speter# define NETINFO_DEFAULT_PROPERTY	"members"
533238032Speter
533338032Speter/*
533438032Speter**  NI_MAP_OPEN -- open NetInfo Aliases
533538032Speter*/
533638032Speter
533738032Speterbool
533838032Speterni_map_open(map, mode)
533938032Speter	MAP *map;
534038032Speter	int mode;
534138032Speter{
534238032Speter	if (tTd(38, 2))
534364562Sgshapiro		dprintf("ni_map_open(%s, %s, %d)\n",
534438032Speter			map->map_mname, map->map_file, mode);
534538032Speter	mode &= O_ACCMODE;
534638032Speter
534738032Speter	if (*map->map_file == '\0')
534838032Speter		map->map_file = NETINFO_DEFAULT_DIR;
534938032Speter
535038032Speter	if (map->map_valcolnm == NULL)
535138032Speter		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
535238032Speter
535338032Speter	if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
535438032Speter		map->map_coldelim = ',';
535538032Speter
535638032Speter	return TRUE;
535738032Speter}
535838032Speter
535938032Speter
536038032Speter/*
536138032Speter**  NI_MAP_LOOKUP -- look up a datum in NetInfo
536238032Speter*/
536338032Speter
536438032Speterchar *
536538032Speterni_map_lookup(map, name, av, statp)
536638032Speter	MAP *map;
536738032Speter	char *name;
536838032Speter	char **av;
536938032Speter	int *statp;
537038032Speter{
537138032Speter	char *res;
537238032Speter	char *propval;
537338032Speter
537438032Speter	if (tTd(38, 20))
537564562Sgshapiro		dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
537638032Speter
537738032Speter	propval = ni_propval(map->map_file, map->map_keycolnm, name,
537838032Speter			     map->map_valcolnm, map->map_coldelim);
537938032Speter
538038032Speter	if (propval == NULL)
538138032Speter		return NULL;
538238032Speter
538338032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
538438032Speter		res = map_rewrite(map, name, strlen(name), NULL);
538538032Speter	else
538638032Speter		res = map_rewrite(map, propval, strlen(propval), av);
538738032Speter	free(propval);
538838032Speter	return res;
538938032Speter}
539038032Speter
539138032Speter
539264562Sgshapirostatic bool
539338032Speterni_getcanonname(name, hbsize, statp)
539438032Speter	char *name;
539538032Speter	int hbsize;
539638032Speter	int *statp;
539738032Speter{
539838032Speter	char *vptr;
539938032Speter	char *ptr;
540038032Speter	char nbuf[MAXNAME + 1];
540138032Speter
540238032Speter	if (tTd(38, 20))
540364562Sgshapiro		dprintf("ni_getcanonname(%s)\n", name);
540438032Speter
540564562Sgshapiro	if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
540638032Speter	{
540738032Speter		*statp = EX_UNAVAILABLE;
540838032Speter		return FALSE;
540938032Speter	}
541038032Speter	shorten_hostname(nbuf);
541138032Speter
541238032Speter	/* we only accept single token search key */
541338032Speter	if (strchr(nbuf, '.'))
541438032Speter	{
541538032Speter		*statp = EX_NOHOST;
541638032Speter		return FALSE;
541738032Speter	}
541838032Speter
541938032Speter	/* Do the search */
542038032Speter	vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
542138032Speter
542238032Speter	if (vptr == NULL)
542338032Speter	{
542438032Speter		*statp = EX_NOHOST;
542538032Speter		return FALSE;
542638032Speter	}
542738032Speter
542838032Speter	/* Only want the first machine name */
542938032Speter	if ((ptr = strchr(vptr, '\n')) != NULL)
543038032Speter		*ptr = '\0';
543138032Speter
543238032Speter	if (hbsize >= strlen(vptr))
543338032Speter	{
543464562Sgshapiro		(void) strlcpy(name, vptr, hbsize);
543564562Sgshapiro		free(vptr);
543638032Speter		*statp = EX_OK;
543738032Speter		return TRUE;
543838032Speter	}
543938032Speter	*statp = EX_UNAVAILABLE;
544038032Speter	free(vptr);
544138032Speter	return FALSE;
544238032Speter}
544338032Speter
544438032Speter
544538032Speter/*
544638032Speter**  NI_PROPVAL -- NetInfo property value lookup routine
544738032Speter**
544838032Speter**	Parameters:
544938032Speter**		keydir -- the NetInfo directory name in which to search
545038032Speter**			for the key.
545138032Speter**		keyprop -- the name of the property in which to find the
545238032Speter**			property we are interested.  Defaults to "name".
545338032Speter**		keyval -- the value for which we are really searching.
545438032Speter**		valprop -- the property name for the value in which we
545538032Speter**			are interested.
545638032Speter**		sepchar -- if non-nil, this can be multiple-valued, and
545738032Speter**			we should return a string separated by this
545838032Speter**			character.
545938032Speter**
546038032Speter**	Returns:
546138032Speter**		NULL -- if:
546238032Speter**			1. the directory is not found
546338032Speter**			2. the property name is not found
546438032Speter**			3. the property contains multiple values
546564562Sgshapiro**			4. some error occurred
546638032Speter**		else -- the value of the lookup.
546738032Speter**
546838032Speter**	Example:
546938032Speter**		To search for an alias value, use:
547038032Speter**		  ni_propval("/aliases", "name", aliasname, "members", ',')
547138032Speter**
547238032Speter**	Notes:
547364562Sgshapiro**		Caller should free the return value of ni_proval
547438032Speter*/
547538032Speter
547638032Speter# include <netinfo/ni.h>
547738032Speter
547864562Sgshapiro# define LOCAL_NETINFO_DOMAIN	"."
547964562Sgshapiro# define PARENT_NETINFO_DOMAIN	".."
548064562Sgshapiro# define MAX_NI_LEVELS		256
548138032Speter
548238032Speterchar *
548338032Speterni_propval(keydir, keyprop, keyval, valprop, sepchar)
548438032Speter	char *keydir;
548538032Speter	char *keyprop;
548638032Speter	char *keyval;
548738032Speter	char *valprop;
548838032Speter	int sepchar;
548938032Speter{
549038032Speter	char *propval = NULL;
549138032Speter	int i;
549264562Sgshapiro	int j, alen, l;
549338032Speter	void *ni = NULL;
549438032Speter	void *lastni = NULL;
549538032Speter	ni_status nis;
549638032Speter	ni_id nid;
549738032Speter	ni_namelist ninl;
549838032Speter	register char *p;
549938032Speter	char keybuf[1024];
550038032Speter
550138032Speter	/*
550238032Speter	**  Create the full key from the two parts.
550338032Speter	**
550438032Speter	**	Note that directory can end with, e.g., "name=" to specify
550538032Speter	**	an alternate search property.
550638032Speter	*/
550738032Speter
550838032Speter	i = strlen(keydir) + strlen(keyval) + 2;
550938032Speter	if (keyprop != NULL)
551038032Speter		i += strlen(keyprop) + 1;
551164562Sgshapiro	if (i >= sizeof keybuf)
551238032Speter		return NULL;
551364562Sgshapiro	(void) strlcpy(keybuf, keydir, sizeof keybuf);
551464562Sgshapiro	(void) strlcat(keybuf, "/", sizeof keybuf);
551538032Speter	if (keyprop != NULL)
551638032Speter	{
551764562Sgshapiro		(void) strlcat(keybuf, keyprop, sizeof keybuf);
551864562Sgshapiro		(void) strlcat(keybuf, "=", sizeof keybuf);
551938032Speter	}
552064562Sgshapiro	(void) strlcat(keybuf, keyval, sizeof keybuf);
552138032Speter
552238032Speter	if (tTd(38, 21))
552364562Sgshapiro		dprintf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n",
552438032Speter			keydir, keyprop, keyval, valprop, sepchar, keybuf);
552538032Speter	/*
552638032Speter	**  If the passed directory and property name are found
552738032Speter	**  in one of netinfo domains we need to search (starting
552838032Speter	**  from the local domain moving all the way back to the
552938032Speter	**  root domain) set propval to the property's value
553038032Speter	**  and return it.
553138032Speter	*/
553238032Speter
553338032Speter	for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
553438032Speter	{
553538032Speter		if (i == 0)
553638032Speter		{
553738032Speter			nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
553838032Speter			if (tTd(38, 20))
553964562Sgshapiro				dprintf("ni_open(LOCAL) = %d\n", nis);
554038032Speter		}
554138032Speter		else
554238032Speter		{
554338032Speter			if (lastni != NULL)
554438032Speter				ni_free(lastni);
554538032Speter			lastni = ni;
554638032Speter			nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
554738032Speter			if (tTd(38, 20))
554864562Sgshapiro				dprintf("ni_open(PARENT) = %d\n", nis);
554938032Speter		}
555038032Speter
555138032Speter		/*
555238032Speter		**  Don't bother if we didn't get a handle on a
555338032Speter		**  proper domain.  This is not necessarily an error.
555438032Speter		**  We would get a positive ni_status if, for instance
555538032Speter		**  we never found the directory or property and tried
555638032Speter		**  to open the parent of the root domain!
555738032Speter		*/
555838032Speter
555938032Speter		if (nis != 0)
556038032Speter			break;
556138032Speter
556238032Speter		/*
556338032Speter		**  Find the path to the server information.
556438032Speter		*/
556538032Speter
556638032Speter		if (ni_pathsearch(ni, &nid, keybuf) != 0)
556738032Speter			continue;
556838032Speter
556938032Speter		/*
557038032Speter		**  Find associated value information.
557138032Speter		*/
557238032Speter
557338032Speter		if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
557438032Speter			continue;
557538032Speter
557638032Speter		if (tTd(38, 20))
557764562Sgshapiro			dprintf("ni_lookupprop: len=%d\n",
557864562Sgshapiro				ninl.ni_namelist_len);
557964562Sgshapiro
558038032Speter		/*
558138032Speter		**  See if we have an acceptable number of values.
558238032Speter		*/
558338032Speter
558438032Speter		if (ninl.ni_namelist_len <= 0)
558538032Speter			continue;
558638032Speter
558738032Speter		if (sepchar == '\0' && ninl.ni_namelist_len > 1)
558838032Speter		{
558938032Speter			ni_namelist_free(&ninl);
559038032Speter			continue;
559138032Speter		}
559238032Speter
559338032Speter		/*
559438032Speter		**  Calculate number of bytes needed and build result
559538032Speter		*/
559638032Speter
559738032Speter		alen = 1;
559838032Speter		for (j = 0; j < ninl.ni_namelist_len; j++)
559938032Speter			alen += strlen(ninl.ni_namelist_val[j]) + 1;
560038032Speter		propval = p = xalloc(alen);
560138032Speter		for (j = 0; j < ninl.ni_namelist_len; j++)
560238032Speter		{
560364562Sgshapiro			(void) strlcpy(p, ninl.ni_namelist_val[j], alen);
560464562Sgshapiro			l = strlen(p);
560564562Sgshapiro			p += l;
560638032Speter			*p++ = sepchar;
560764562Sgshapiro			alen -= l + 1;
560838032Speter		}
560938032Speter		*--p = '\0';
561038032Speter
561138032Speter		ni_namelist_free(&ninl);
561238032Speter	}
561338032Speter
561438032Speter	/*
561538032Speter	**  Clean up.
561638032Speter	*/
561738032Speter
561838032Speter	if (ni != NULL)
561938032Speter		ni_free(ni);
562038032Speter	if (lastni != NULL && ni != lastni)
562138032Speter		ni_free(lastni);
562238032Speter	if (tTd(38, 20))
562364562Sgshapiro		dprintf("ni_propval returns: '%s'\n", propval);
562438032Speter
562538032Speter	return propval;
562638032Speter}
562738032Speter
562842575Speter#endif /* NETINFO */
562938032Speter/*
563038032Speter**  TEXT (unindexed text file) Modules
563138032Speter**
563238032Speter**	This code donated by Sun Microsystems.
563338032Speter*/
563438032Speter
563538032Speter#define map_sff		map_lockfd	/* overload field */
563638032Speter
563738032Speter
563838032Speter/*
563938032Speter**  TEXT_MAP_OPEN -- open text table
564038032Speter*/
564138032Speter
564238032Speterbool
564338032Spetertext_map_open(map, mode)
564438032Speter	MAP *map;
564538032Speter	int mode;
564638032Speter{
564764562Sgshapiro	long sff;
564838032Speter	int i;
564938032Speter
565038032Speter	if (tTd(38, 2))
565164562Sgshapiro		dprintf("text_map_open(%s, %s, %d)\n",
565238032Speter			map->map_mname, map->map_file, mode);
565338032Speter
565438032Speter	mode &= O_ACCMODE;
565538032Speter	if (mode != O_RDONLY)
565638032Speter	{
565738032Speter		errno = EPERM;
565838032Speter		return FALSE;
565938032Speter	}
566038032Speter
566138032Speter	if (*map->map_file == '\0')
566238032Speter	{
566338032Speter		syserr("text map \"%s\": file name required",
566438032Speter			map->map_mname);
566538032Speter		return FALSE;
566638032Speter	}
566738032Speter
566838032Speter	if (map->map_file[0] != '/')
566938032Speter	{
567038032Speter		syserr("text map \"%s\": file name must be fully qualified",
567138032Speter			map->map_mname);
567238032Speter		return FALSE;
567338032Speter	}
567438032Speter
567538032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
567664562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
567738032Speter		sff |= SFF_NOWLINK;
567864562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
567938032Speter		sff |= SFF_SAFEDIRPATH;
568038032Speter	if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
568138032Speter			  sff, S_IRUSR, NULL)) != 0)
568238032Speter	{
568364562Sgshapiro		int save_errno = errno;
568464562Sgshapiro
568538032Speter		/* cannot open this map */
568638032Speter		if (tTd(38, 2))
568764562Sgshapiro			dprintf("\tunsafe map file: %d\n", i);
568864562Sgshapiro		errno = save_errno;
568938032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
569038032Speter			syserr("text map \"%s\": unsafe map file %s",
569138032Speter				map->map_mname, map->map_file);
569238032Speter		return FALSE;
569338032Speter	}
569438032Speter
569538032Speter	if (map->map_keycolnm == NULL)
569638032Speter		map->map_keycolno = 0;
569738032Speter	else
569838032Speter	{
569938032Speter		if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
570038032Speter		{
570138032Speter			syserr("text map \"%s\", file %s: -k should specify a number, not %s",
570238032Speter				map->map_mname, map->map_file,
570338032Speter				map->map_keycolnm);
570438032Speter			return FALSE;
570538032Speter		}
570638032Speter		map->map_keycolno = atoi(map->map_keycolnm);
570738032Speter	}
570838032Speter
570938032Speter	if (map->map_valcolnm == NULL)
571038032Speter		map->map_valcolno = 0;
571138032Speter	else
571238032Speter	{
571338032Speter		if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
571438032Speter		{
571538032Speter			syserr("text map \"%s\", file %s: -v should specify a number, not %s",
571638032Speter					map->map_mname, map->map_file,
571738032Speter					map->map_valcolnm);
571838032Speter			return FALSE;
571938032Speter		}
572038032Speter		map->map_valcolno = atoi(map->map_valcolnm);
572138032Speter	}
572238032Speter
572338032Speter	if (tTd(38, 2))
572438032Speter	{
572564562Sgshapiro		dprintf("text_map_open(%s, %s): delimiter = ",
572638032Speter			map->map_mname, map->map_file);
572738032Speter		if (map->map_coldelim == '\0')
572864562Sgshapiro			dprintf("(white space)\n");
572938032Speter		else
573064562Sgshapiro			dprintf("%c\n", map->map_coldelim);
573138032Speter	}
573238032Speter
573338032Speter	map->map_sff = sff;
573438032Speter	return TRUE;
573538032Speter}
573638032Speter
573738032Speter
573838032Speter/*
573938032Speter**  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
574038032Speter*/
574138032Speter
574238032Speterchar *
574338032Spetertext_map_lookup(map, name, av, statp)
574438032Speter	MAP *map;
574538032Speter	char *name;
574638032Speter	char **av;
574738032Speter	int *statp;
574838032Speter{
574938032Speter	char *vp;
575038032Speter	auto int vsize;
575138032Speter	int buflen;
575238032Speter	FILE *f;
575338032Speter	char delim;
575438032Speter	int key_idx;
575538032Speter	bool found_it;
575664562Sgshapiro	long sff = map->map_sff;
575738032Speter	char search_key[MAXNAME + 1];
575838032Speter	char linebuf[MAXLINE];
575938032Speter	char buf[MAXNAME + 1];
576038032Speter
576138032Speter	found_it = FALSE;
576238032Speter	if (tTd(38, 20))
576364562Sgshapiro		dprintf("text_map_lookup(%s, %s)\n", map->map_mname,  name);
576438032Speter
576538032Speter	buflen = strlen(name);
576638032Speter	if (buflen > sizeof search_key - 1)
576738032Speter		buflen = sizeof search_key - 1;
576864562Sgshapiro	memmove(search_key, name, buflen);
576938032Speter	search_key[buflen] = '\0';
577038032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
577138032Speter		makelower(search_key);
577238032Speter
577338032Speter	f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
577438032Speter	if (f == NULL)
577538032Speter	{
577638032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
577738032Speter		*statp = EX_UNAVAILABLE;
577838032Speter		return NULL;
577938032Speter	}
578038032Speter	key_idx = map->map_keycolno;
578138032Speter	delim = map->map_coldelim;
578238032Speter	while (fgets(linebuf, MAXLINE, f) != NULL)
578338032Speter	{
578438032Speter		char *p;
578538032Speter
578638032Speter		/* skip comment line */
578738032Speter		if (linebuf[0] == '#')
578838032Speter			continue;
578938032Speter		p = strchr(linebuf, '\n');
579038032Speter		if (p != NULL)
579138032Speter			*p = '\0';
579238032Speter		p = get_column(linebuf, key_idx, delim, buf, sizeof buf);
579338032Speter		if (p != NULL && strcasecmp(search_key, p) == 0)
579438032Speter		{
579538032Speter			found_it = TRUE;
579638032Speter			break;
579738032Speter		}
579838032Speter	}
579964562Sgshapiro	(void) fclose(f);
580038032Speter	if (!found_it)
580138032Speter	{
580238032Speter		*statp = EX_NOTFOUND;
580338032Speter		return NULL;
580438032Speter	}
580538032Speter	vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof buf);
580642575Speter	if (vp == NULL)
580742575Speter	{
580842575Speter		*statp = EX_NOTFOUND;
580942575Speter		return NULL;
581042575Speter	}
581138032Speter	vsize = strlen(vp);
581238032Speter	*statp = EX_OK;
581338032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
581438032Speter		return map_rewrite(map, name, strlen(name), NULL);
581538032Speter	else
581638032Speter		return map_rewrite(map, vp, vsize, av);
581738032Speter}
581838032Speter
581938032Speter/*
582038032Speter**  TEXT_GETCANONNAME -- look up canonical name in hosts file
582138032Speter*/
582238032Speter
582364562Sgshapirostatic bool
582438032Spetertext_getcanonname(name, hbsize, statp)
582538032Speter	char *name;
582638032Speter	int hbsize;
582738032Speter	int *statp;
582838032Speter{
582938032Speter	bool found;
583038032Speter	FILE *f;
583138032Speter	char linebuf[MAXLINE];
583238032Speter	char cbuf[MAXNAME + 1];
583338032Speter	char nbuf[MAXNAME + 1];
583438032Speter
583538032Speter	if (tTd(38, 20))
583664562Sgshapiro		dprintf("text_getcanonname(%s)\n", name);
583738032Speter
583838032Speter	if (strlen(name) >= (SIZE_T) sizeof nbuf)
583938032Speter	{
584038032Speter		*statp = EX_UNAVAILABLE;
584138032Speter		return FALSE;
584238032Speter	}
584364562Sgshapiro	(void) strlcpy(nbuf, name, sizeof nbuf);
584438032Speter	shorten_hostname(nbuf);
584538032Speter
584638032Speter	f = fopen(HostsFile, "r");
584738032Speter	if (f == NULL)
584838032Speter	{
584938032Speter		*statp = EX_UNAVAILABLE;
585038032Speter		return FALSE;
585138032Speter	}
585238032Speter	found = FALSE;
585338032Speter	while (!found && fgets(linebuf, MAXLINE, f) != NULL)
585438032Speter	{
585538032Speter		char *p = strpbrk(linebuf, "#\n");
585638032Speter
585738032Speter		if (p != NULL)
585838032Speter			*p = '\0';
585938032Speter		if (linebuf[0] != '\0')
586038032Speter			found = extract_canonname(nbuf, linebuf, cbuf, sizeof cbuf);
586138032Speter	}
586264562Sgshapiro	(void) fclose(f);
586338032Speter	if (!found)
586438032Speter	{
586538032Speter		*statp = EX_NOHOST;
586638032Speter		return FALSE;
586738032Speter	}
586838032Speter
586938032Speter	if ((SIZE_T) hbsize >= strlen(cbuf))
587038032Speter	{
587164562Sgshapiro		(void) strlcpy(name, cbuf, hbsize);
587238032Speter		*statp = EX_OK;
587338032Speter		return TRUE;
587438032Speter	}
587538032Speter	*statp = EX_UNAVAILABLE;
587638032Speter	return FALSE;
587738032Speter}
587838032Speter/*
587938032Speter**  STAB (Symbol Table) Modules
588038032Speter*/
588138032Speter
588238032Speter
588338032Speter/*
588438032Speter**  STAB_MAP_LOOKUP -- look up alias in symbol table
588538032Speter*/
588638032Speter
588738032Speter/* ARGSUSED2 */
588838032Speterchar *
588938032Speterstab_map_lookup(map, name, av, pstat)
589038032Speter	register MAP *map;
589138032Speter	char *name;
589238032Speter	char **av;
589338032Speter	int *pstat;
589438032Speter{
589538032Speter	register STAB *s;
589638032Speter
589738032Speter	if (tTd(38, 20))
589864562Sgshapiro		dprintf("stab_lookup(%s, %s)\n",
589938032Speter			map->map_mname, name);
590038032Speter
590138032Speter	s = stab(name, ST_ALIAS, ST_FIND);
590238032Speter	if (s != NULL)
590364562Sgshapiro		return s->s_alias;
590464562Sgshapiro	return NULL;
590538032Speter}
590638032Speter
590738032Speter
590838032Speter/*
590938032Speter**  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
591038032Speter*/
591138032Speter
591238032Spetervoid
591338032Speterstab_map_store(map, lhs, rhs)
591438032Speter	register MAP *map;
591538032Speter	char *lhs;
591638032Speter	char *rhs;
591738032Speter{
591838032Speter	register STAB *s;
591938032Speter
592038032Speter	s = stab(lhs, ST_ALIAS, ST_ENTER);
592138032Speter	s->s_alias = newstr(rhs);
592238032Speter}
592338032Speter
592438032Speter
592538032Speter/*
592638032Speter**  STAB_MAP_OPEN -- initialize (reads data file)
592738032Speter**
592838032Speter**	This is a wierd case -- it is only intended as a fallback for
592938032Speter**	aliases.  For this reason, opens for write (only during a
593038032Speter**	"newaliases") always fails, and opens for read open the
593138032Speter**	actual underlying text file instead of the database.
593238032Speter*/
593338032Speter
593438032Speterbool
593538032Speterstab_map_open(map, mode)
593638032Speter	register MAP *map;
593738032Speter	int mode;
593838032Speter{
593938032Speter	FILE *af;
594064562Sgshapiro	long sff;
594138032Speter	struct stat st;
594238032Speter
594338032Speter	if (tTd(38, 2))
594464562Sgshapiro		dprintf("stab_map_open(%s, %s, %d)\n",
594538032Speter			map->map_mname, map->map_file, mode);
594638032Speter
594738032Speter	mode &= O_ACCMODE;
594838032Speter	if (mode != O_RDONLY)
594938032Speter	{
595038032Speter		errno = EPERM;
595138032Speter		return FALSE;
595238032Speter	}
595338032Speter
595438032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
595564562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
595638032Speter		sff |= SFF_NOWLINK;
595764562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
595838032Speter		sff |= SFF_SAFEDIRPATH;
595938032Speter	af = safefopen(map->map_file, O_RDONLY, 0444, sff);
596038032Speter	if (af == NULL)
596138032Speter		return FALSE;
596238032Speter	readaliases(map, af, FALSE, FALSE);
596338032Speter
596438032Speter	if (fstat(fileno(af), &st) >= 0)
596538032Speter		map->map_mtime = st.st_mtime;
596664562Sgshapiro	(void) fclose(af);
596738032Speter
596838032Speter	return TRUE;
596938032Speter}
597038032Speter/*
597138032Speter**  Implicit Modules
597238032Speter**
597338032Speter**	Tries several types.  For back compatibility of aliases.
597438032Speter*/
597538032Speter
597638032Speter
597738032Speter/*
597838032Speter**  IMPL_MAP_LOOKUP -- lookup in best open database
597938032Speter*/
598038032Speter
598138032Speterchar *
598238032Speterimpl_map_lookup(map, name, av, pstat)
598338032Speter	MAP *map;
598438032Speter	char *name;
598538032Speter	char **av;
598638032Speter	int *pstat;
598738032Speter{
598838032Speter	if (tTd(38, 20))
598964562Sgshapiro		dprintf("impl_map_lookup(%s, %s)\n",
599038032Speter			map->map_mname, name);
599138032Speter
599238032Speter#ifdef NEWDB
599338032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
599438032Speter		return db_map_lookup(map, name, av, pstat);
599564562Sgshapiro#endif /* NEWDB */
599638032Speter#ifdef NDBM
599738032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
599838032Speter		return ndbm_map_lookup(map, name, av, pstat);
599964562Sgshapiro#endif /* NDBM */
600038032Speter	return stab_map_lookup(map, name, av, pstat);
600138032Speter}
600238032Speter
600338032Speter/*
600438032Speter**  IMPL_MAP_STORE -- store in open databases
600538032Speter*/
600638032Speter
600738032Spetervoid
600838032Speterimpl_map_store(map, lhs, rhs)
600938032Speter	MAP *map;
601038032Speter	char *lhs;
601138032Speter	char *rhs;
601238032Speter{
601338032Speter	if (tTd(38, 12))
601464562Sgshapiro		dprintf("impl_map_store(%s, %s, %s)\n",
601538032Speter			map->map_mname, lhs, rhs);
601638032Speter#ifdef NEWDB
601738032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
601838032Speter		db_map_store(map, lhs, rhs);
601964562Sgshapiro#endif /* NEWDB */
602038032Speter#ifdef NDBM
602138032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
602238032Speter		ndbm_map_store(map, lhs, rhs);
602364562Sgshapiro#endif /* NDBM */
602438032Speter	stab_map_store(map, lhs, rhs);
602538032Speter}
602638032Speter
602738032Speter/*
602838032Speter**  IMPL_MAP_OPEN -- implicit database open
602938032Speter*/
603038032Speter
603138032Speterbool
603238032Speterimpl_map_open(map, mode)
603338032Speter	MAP *map;
603438032Speter	int mode;
603538032Speter{
603638032Speter	if (tTd(38, 2))
603764562Sgshapiro		dprintf("impl_map_open(%s, %s, %d)\n",
603838032Speter			map->map_mname, map->map_file, mode);
603938032Speter
604038032Speter	mode &= O_ACCMODE;
604138032Speter#ifdef NEWDB
604238032Speter	map->map_mflags |= MF_IMPL_HASH;
604338032Speter	if (hash_map_open(map, mode))
604438032Speter	{
604538032Speter# ifdef NDBM_YP_COMPAT
604638032Speter		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
604764562Sgshapiro# endif /* NDBM_YP_COMPAT */
604838032Speter			return TRUE;
604938032Speter	}
605038032Speter	else
605138032Speter		map->map_mflags &= ~MF_IMPL_HASH;
605264562Sgshapiro#endif /* NEWDB */
605338032Speter#ifdef NDBM
605438032Speter	map->map_mflags |= MF_IMPL_NDBM;
605538032Speter	if (ndbm_map_open(map, mode))
605638032Speter	{
605738032Speter		return TRUE;
605838032Speter	}
605938032Speter	else
606038032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
606164562Sgshapiro#endif /* NDBM */
606238032Speter
606338032Speter#if defined(NEWDB) || defined(NDBM)
606438032Speter	if (Verbose)
606538032Speter		message("WARNING: cannot open alias database %s%s",
606638032Speter			map->map_file,
606738032Speter			mode == O_RDONLY ? "; reading text version" : "");
606864562Sgshapiro#else /* defined(NEWDB) || defined(NDBM) */
606938032Speter	if (mode != O_RDONLY)
607038032Speter		usrerr("Cannot rebuild aliases: no database format defined");
607164562Sgshapiro#endif /* defined(NEWDB) || defined(NDBM) */
607238032Speter
607338032Speter	if (mode == O_RDONLY)
607438032Speter		return stab_map_open(map, mode);
607538032Speter	else
607638032Speter		return FALSE;
607738032Speter}
607838032Speter
607938032Speter
608038032Speter/*
608138032Speter**  IMPL_MAP_CLOSE -- close any open database(s)
608238032Speter*/
608338032Speter
608438032Spetervoid
608538032Speterimpl_map_close(map)
608638032Speter	MAP *map;
608738032Speter{
608838032Speter	if (tTd(38, 9))
608964562Sgshapiro		dprintf("impl_map_close(%s, %s, %lx)\n",
609038032Speter			map->map_mname, map->map_file, map->map_mflags);
609138032Speter#ifdef NEWDB
609238032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
609338032Speter	{
609438032Speter		db_map_close(map);
609538032Speter		map->map_mflags &= ~MF_IMPL_HASH;
609638032Speter	}
609764562Sgshapiro#endif /* NEWDB */
609838032Speter
609938032Speter#ifdef NDBM
610038032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
610138032Speter	{
610238032Speter		ndbm_map_close(map);
610338032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
610438032Speter	}
610564562Sgshapiro#endif /* NDBM */
610638032Speter}
610738032Speter/*
610838032Speter**  User map class.
610938032Speter**
611038032Speter**	Provides access to the system password file.
611138032Speter*/
611238032Speter
611338032Speter/*
611438032Speter**  USER_MAP_OPEN -- open user map
611538032Speter**
611638032Speter**	Really just binds field names to field numbers.
611738032Speter*/
611838032Speter
611938032Speterbool
612038032Speteruser_map_open(map, mode)
612138032Speter	MAP *map;
612238032Speter	int mode;
612338032Speter{
612438032Speter	if (tTd(38, 2))
612564562Sgshapiro		dprintf("user_map_open(%s, %d)\n",
612638032Speter			map->map_mname, mode);
612738032Speter
612838032Speter	mode &= O_ACCMODE;
612938032Speter	if (mode != O_RDONLY)
613038032Speter	{
613138032Speter		/* issue a pseudo-error message */
613238032Speter#ifdef ENOSYS
613338032Speter		errno = ENOSYS;
613464562Sgshapiro#else /* ENOSYS */
613538032Speter# ifdef EFTYPE
613638032Speter		errno = EFTYPE;
613764562Sgshapiro# else /* EFTYPE */
613838032Speter		errno = ENXIO;
613964562Sgshapiro# endif /* EFTYPE */
614064562Sgshapiro#endif /* ENOSYS */
614138032Speter		return FALSE;
614238032Speter	}
614338032Speter	if (map->map_valcolnm == NULL)
614464562Sgshapiro		/* EMPTY */
614538032Speter		/* nothing */ ;
614638032Speter	else if (strcasecmp(map->map_valcolnm, "name") == 0)
614738032Speter		map->map_valcolno = 1;
614838032Speter	else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
614938032Speter		map->map_valcolno = 2;
615038032Speter	else if (strcasecmp(map->map_valcolnm, "uid") == 0)
615138032Speter		map->map_valcolno = 3;
615238032Speter	else if (strcasecmp(map->map_valcolnm, "gid") == 0)
615338032Speter		map->map_valcolno = 4;
615438032Speter	else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
615538032Speter		map->map_valcolno = 5;
615638032Speter	else if (strcasecmp(map->map_valcolnm, "dir") == 0)
615738032Speter		map->map_valcolno = 6;
615838032Speter	else if (strcasecmp(map->map_valcolnm, "shell") == 0)
615938032Speter		map->map_valcolno = 7;
616038032Speter	else
616138032Speter	{
616238032Speter		syserr("User map %s: unknown column name %s",
616338032Speter			map->map_mname, map->map_valcolnm);
616438032Speter		return FALSE;
616538032Speter	}
616638032Speter	return TRUE;
616738032Speter}
616838032Speter
616938032Speter
617038032Speter/*
617138032Speter**  USER_MAP_LOOKUP -- look up a user in the passwd file.
617238032Speter*/
617338032Speter
617438032Speter/* ARGSUSED3 */
617538032Speterchar *
617638032Speteruser_map_lookup(map, key, av, statp)
617738032Speter	MAP *map;
617838032Speter	char *key;
617938032Speter	char **av;
618038032Speter	int *statp;
618138032Speter{
618238032Speter	struct passwd *pw;
618338032Speter	auto bool fuzzy;
618438032Speter
618538032Speter	if (tTd(38, 20))
618664562Sgshapiro		dprintf("user_map_lookup(%s, %s)\n",
618738032Speter			map->map_mname, key);
618838032Speter
618938032Speter	pw = finduser(key, &fuzzy);
619038032Speter	if (pw == NULL)
619138032Speter		return NULL;
619238032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
619338032Speter		return map_rewrite(map, key, strlen(key), NULL);
619438032Speter	else
619538032Speter	{
619638032Speter		char *rwval = NULL;
619738032Speter		char buf[30];
619838032Speter
619938032Speter		switch (map->map_valcolno)
620038032Speter		{
620138032Speter		  case 0:
620238032Speter		  case 1:
620338032Speter			rwval = pw->pw_name;
620438032Speter			break;
620538032Speter
620638032Speter		  case 2:
620738032Speter			rwval = pw->pw_passwd;
620838032Speter			break;
620938032Speter
621038032Speter		  case 3:
621164562Sgshapiro			snprintf(buf, sizeof buf, "%d", (int) pw->pw_uid);
621238032Speter			rwval = buf;
621338032Speter			break;
621438032Speter
621538032Speter		  case 4:
621664562Sgshapiro			snprintf(buf, sizeof buf, "%d", (int) pw->pw_gid);
621738032Speter			rwval = buf;
621838032Speter			break;
621938032Speter
622038032Speter		  case 5:
622138032Speter			rwval = pw->pw_gecos;
622238032Speter			break;
622338032Speter
622438032Speter		  case 6:
622538032Speter			rwval = pw->pw_dir;
622638032Speter			break;
622738032Speter
622838032Speter		  case 7:
622938032Speter			rwval = pw->pw_shell;
623038032Speter			break;
623138032Speter		}
623238032Speter		return map_rewrite(map, rwval, strlen(rwval), av);
623338032Speter	}
623438032Speter}
623538032Speter/*
623638032Speter**  Program map type.
623738032Speter**
623838032Speter**	This provides access to arbitrary programs.  It should be used
623938032Speter**	only very sparingly, since there is no way to bound the cost
624038032Speter**	of invoking an arbitrary program.
624138032Speter*/
624238032Speter
624338032Speterchar *
624438032Speterprog_map_lookup(map, name, av, statp)
624538032Speter	MAP *map;
624638032Speter	char *name;
624738032Speter	char **av;
624838032Speter	int *statp;
624938032Speter{
625038032Speter	int i;
625164562Sgshapiro	int save_errno;
625238032Speter	int fd;
625364562Sgshapiro	int status;
625438032Speter	auto pid_t pid;
625564562Sgshapiro	register char *p;
625638032Speter	char *rval;
625738032Speter	char *argv[MAXPV + 1];
625838032Speter	char buf[MAXLINE];
625938032Speter
626038032Speter	if (tTd(38, 20))
626164562Sgshapiro		dprintf("prog_map_lookup(%s, %s) %s\n",
626238032Speter			map->map_mname, name, map->map_file);
626338032Speter
626438032Speter	i = 0;
626538032Speter	argv[i++] = map->map_file;
626638032Speter	if (map->map_rebuild != NULL)
626738032Speter	{
626838032Speter		snprintf(buf, sizeof buf, "%s", map->map_rebuild);
626938032Speter		for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
627038032Speter		{
627138032Speter			if (i >= MAXPV - 1)
627238032Speter				break;
627338032Speter			argv[i++] = p;
627438032Speter		}
627538032Speter	}
627638032Speter	argv[i++] = name;
627738032Speter	argv[i] = NULL;
627838032Speter	if (tTd(38, 21))
627938032Speter	{
628064562Sgshapiro		dprintf("prog_open:");
628138032Speter		for (i = 0; argv[i] != NULL; i++)
628264562Sgshapiro			dprintf(" %s", argv[i]);
628364562Sgshapiro		dprintf("\n");
628438032Speter	}
628538032Speter	(void) blocksignal(SIGCHLD);
628638032Speter	pid = prog_open(argv, &fd, CurEnv);
628738032Speter	if (pid < 0)
628838032Speter	{
628938032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
629038032Speter			syserr("prog_map_lookup(%s) failed (%s) -- closing",
629138032Speter				map->map_mname, errstring(errno));
629238032Speter		else if (tTd(38, 9))
629364562Sgshapiro			dprintf("prog_map_lookup(%s) failed (%s) -- closing",
629438032Speter				map->map_mname, errstring(errno));
629538032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
629638032Speter		*statp = EX_OSFILE;
629738032Speter		return NULL;
629838032Speter	}
629938032Speter	i = read(fd, buf, sizeof buf - 1);
630038032Speter	if (i < 0)
630138032Speter	{
630238032Speter		syserr("prog_map_lookup(%s): read error %s\n",
630338032Speter			map->map_mname, errstring(errno));
630438032Speter		rval = NULL;
630538032Speter	}
630638032Speter	else if (i == 0)
630738032Speter	{
630838032Speter		if (tTd(38, 20))
630964562Sgshapiro			dprintf("prog_map_lookup(%s): empty answer\n",
631038032Speter				map->map_mname);
631138032Speter		rval = NULL;
631238032Speter	}
631338032Speter	else
631438032Speter	{
631538032Speter		buf[i] = '\0';
631638032Speter		p = strchr(buf, '\n');
631738032Speter		if (p != NULL)
631838032Speter			*p = '\0';
631938032Speter
632038032Speter		/* collect the return value */
632138032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
632238032Speter			rval = map_rewrite(map, name, strlen(name), NULL);
632338032Speter		else
632438032Speter			rval = map_rewrite(map, buf, strlen(buf), NULL);
632538032Speter
632638032Speter		/* now flush any additional output */
632738032Speter		while ((i = read(fd, buf, sizeof buf)) > 0)
632838032Speter			continue;
632938032Speter	}
633038032Speter
633138032Speter	/* wait for the process to terminate */
633264562Sgshapiro	(void) close(fd);
633364562Sgshapiro	status = waitfor(pid);
633464562Sgshapiro	save_errno = errno;
633538032Speter	(void) releasesignal(SIGCHLD);
633664562Sgshapiro	errno = save_errno;
633738032Speter
633864562Sgshapiro	if (status == -1)
633938032Speter	{
634038032Speter		syserr("prog_map_lookup(%s): wait error %s\n",
634138032Speter			map->map_mname, errstring(errno));
634238032Speter		*statp = EX_SOFTWARE;
634338032Speter		rval = NULL;
634438032Speter	}
634564562Sgshapiro	else if (WIFEXITED(status))
634638032Speter	{
634764562Sgshapiro		if ((*statp = WEXITSTATUS(status)) != EX_OK)
634838032Speter			rval = NULL;
634938032Speter	}
635038032Speter	else
635138032Speter	{
635238032Speter		syserr("prog_map_lookup(%s): child died on signal %d",
635364562Sgshapiro			map->map_mname, status);
635438032Speter		*statp = EX_UNAVAILABLE;
635538032Speter		rval = NULL;
635638032Speter	}
635738032Speter	return rval;
635838032Speter}
635938032Speter/*
636038032Speter**  Sequenced map type.
636138032Speter**
636238032Speter**	Tries each map in order until something matches, much like
636338032Speter**	implicit.  Stores go to the first map in the list that can
636438032Speter**	support storing.
636538032Speter**
636638032Speter**	This is slightly unusual in that there are two interfaces.
636738032Speter**	The "sequence" interface lets you stack maps arbitrarily.
636838032Speter**	The "switch" interface builds a sequence map by looking
636938032Speter**	at a system-dependent configuration file such as
637038032Speter**	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
637138032Speter**
637238032Speter**	We don't need an explicit open, since all maps are
637338032Speter**	opened during startup, including underlying maps.
637438032Speter*/
637538032Speter
637638032Speter/*
637738032Speter**  SEQ_MAP_PARSE -- Sequenced map parsing
637838032Speter*/
637938032Speter
638038032Speterbool
638138032Speterseq_map_parse(map, ap)
638238032Speter	MAP *map;
638338032Speter	char *ap;
638438032Speter{
638538032Speter	int maxmap;
638638032Speter
638738032Speter	if (tTd(38, 2))
638864562Sgshapiro		dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
638938032Speter	maxmap = 0;
639038032Speter	while (*ap != '\0')
639138032Speter	{
639238032Speter		register char *p;
639338032Speter		STAB *s;
639438032Speter
639538032Speter		/* find beginning of map name */
639638032Speter		while (isascii(*ap) && isspace(*ap))
639738032Speter			ap++;
639864562Sgshapiro		for (p = ap;
639964562Sgshapiro		     (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.';
640064562Sgshapiro		     p++)
640138032Speter			continue;
640238032Speter		if (*p != '\0')
640338032Speter			*p++ = '\0';
640438032Speter		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
640538032Speter			p++;
640638032Speter		if (*ap == '\0')
640738032Speter		{
640838032Speter			ap = p;
640938032Speter			continue;
641038032Speter		}
641138032Speter		s = stab(ap, ST_MAP, ST_FIND);
641238032Speter		if (s == NULL)
641338032Speter		{
641438032Speter			syserr("Sequence map %s: unknown member map %s",
641538032Speter				map->map_mname, ap);
641638032Speter		}
641738032Speter		else if (maxmap == MAXMAPSTACK)
641838032Speter		{
641938032Speter			syserr("Sequence map %s: too many member maps (%d max)",
642038032Speter				map->map_mname, MAXMAPSTACK);
642138032Speter			maxmap++;
642238032Speter		}
642338032Speter		else if (maxmap < MAXMAPSTACK)
642438032Speter		{
642538032Speter			map->map_stack[maxmap++] = &s->s_map;
642638032Speter		}
642738032Speter		ap = p;
642838032Speter	}
642938032Speter	return TRUE;
643038032Speter}
643138032Speter
643238032Speter
643338032Speter/*
643438032Speter**  SWITCH_MAP_OPEN -- open a switched map
643538032Speter**
643638032Speter**	This looks at the system-dependent configuration and builds
643738032Speter**	a sequence map that does the same thing.
643838032Speter**
643938032Speter**	Every system must define a switch_map_find routine in conf.c
644038032Speter**	that will return the list of service types associated with a
644138032Speter**	given service class.
644238032Speter*/
644338032Speter
644438032Speterbool
644538032Speterswitch_map_open(map, mode)
644638032Speter	MAP *map;
644738032Speter	int mode;
644838032Speter{
644938032Speter	int mapno;
645038032Speter	int nmaps;
645138032Speter	char *maptype[MAXMAPSTACK];
645238032Speter
645338032Speter	if (tTd(38, 2))
645464562Sgshapiro		dprintf("switch_map_open(%s, %s, %d)\n",
645538032Speter			map->map_mname, map->map_file, mode);
645638032Speter
645738032Speter	mode &= O_ACCMODE;
645838032Speter	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
645938032Speter	if (tTd(38, 19))
646038032Speter	{
646164562Sgshapiro		dprintf("\tswitch_map_find => %d\n", nmaps);
646238032Speter		for (mapno = 0; mapno < nmaps; mapno++)
646364562Sgshapiro			dprintf("\t\t%s\n", maptype[mapno]);
646438032Speter	}
646538032Speter	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
646638032Speter		return FALSE;
646738032Speter
646838032Speter	for (mapno = 0; mapno < nmaps; mapno++)
646938032Speter	{
647038032Speter		register STAB *s;
647138032Speter		char nbuf[MAXNAME + 1];
647238032Speter
647338032Speter		if (maptype[mapno] == NULL)
647438032Speter			continue;
647538032Speter		(void) snprintf(nbuf, sizeof nbuf, "%s.%s",
647638032Speter			map->map_mname, maptype[mapno]);
647738032Speter		s = stab(nbuf, ST_MAP, ST_FIND);
647838032Speter		if (s == NULL)
647938032Speter		{
648038032Speter			syserr("Switch map %s: unknown member map %s",
648138032Speter				map->map_mname, nbuf);
648238032Speter		}
648338032Speter		else
648438032Speter		{
648538032Speter			map->map_stack[mapno] = &s->s_map;
648638032Speter			if (tTd(38, 4))
648764562Sgshapiro				dprintf("\tmap_stack[%d] = %s:%s\n",
648838032Speter					mapno, s->s_map.map_class->map_cname,
648938032Speter					nbuf);
649038032Speter		}
649138032Speter	}
649238032Speter	return TRUE;
649338032Speter}
649438032Speter
649538032Speter
649638032Speter/*
649738032Speter**  SEQ_MAP_CLOSE -- close all underlying maps
649838032Speter*/
649938032Speter
650038032Spetervoid
650138032Speterseq_map_close(map)
650238032Speter	MAP *map;
650338032Speter{
650438032Speter	int mapno;
650538032Speter
650638032Speter	if (tTd(38, 9))
650764562Sgshapiro		dprintf("seq_map_close(%s)\n", map->map_mname);
650838032Speter
650938032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
651038032Speter	{
651138032Speter		MAP *mm = map->map_stack[mapno];
651238032Speter
651338032Speter		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
651438032Speter			continue;
651538032Speter		mm->map_class->map_close(mm);
651638032Speter		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
651738032Speter	}
651838032Speter}
651938032Speter
652038032Speter
652138032Speter/*
652238032Speter**  SEQ_MAP_LOOKUP -- sequenced map lookup
652338032Speter*/
652438032Speter
652538032Speterchar *
652638032Speterseq_map_lookup(map, key, args, pstat)
652738032Speter	MAP *map;
652838032Speter	char *key;
652938032Speter	char **args;
653038032Speter	int *pstat;
653138032Speter{
653238032Speter	int mapno;
653338032Speter	int mapbit = 0x01;
653438032Speter	bool tempfail = FALSE;
653538032Speter
653638032Speter	if (tTd(38, 20))
653764562Sgshapiro		dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
653838032Speter
653938032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
654038032Speter	{
654138032Speter		MAP *mm = map->map_stack[mapno];
654238032Speter		char *rv;
654338032Speter
654438032Speter		if (mm == NULL)
654538032Speter			continue;
654664562Sgshapiro		if (!bitset(MF_OPEN, mm->map_mflags) &&
654764562Sgshapiro		    !openmap(mm))
654838032Speter		{
654938032Speter			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
655038032Speter			{
655138032Speter				*pstat = EX_UNAVAILABLE;
655238032Speter				return NULL;
655338032Speter			}
655438032Speter			continue;
655538032Speter		}
655638032Speter		*pstat = EX_OK;
655738032Speter		rv = mm->map_class->map_lookup(mm, key, args, pstat);
655838032Speter		if (rv != NULL)
655938032Speter			return rv;
656038032Speter		if (*pstat == EX_TEMPFAIL)
656138032Speter		{
656238032Speter			if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
656338032Speter				return NULL;
656438032Speter			tempfail = TRUE;
656538032Speter		}
656638032Speter		else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
656738032Speter			break;
656838032Speter	}
656938032Speter	if (tempfail)
657038032Speter		*pstat = EX_TEMPFAIL;
657138032Speter	else if (*pstat == EX_OK)
657238032Speter		*pstat = EX_NOTFOUND;
657338032Speter	return NULL;
657438032Speter}
657538032Speter
657638032Speter
657738032Speter/*
657838032Speter**  SEQ_MAP_STORE -- sequenced map store
657938032Speter*/
658038032Speter
658138032Spetervoid
658238032Speterseq_map_store(map, key, val)
658338032Speter	MAP *map;
658438032Speter	char *key;
658538032Speter	char *val;
658638032Speter{
658738032Speter	int mapno;
658838032Speter
658938032Speter	if (tTd(38, 12))
659064562Sgshapiro		dprintf("seq_map_store(%s, %s, %s)\n",
659138032Speter			map->map_mname, key, val);
659238032Speter
659338032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
659438032Speter	{
659538032Speter		MAP *mm = map->map_stack[mapno];
659638032Speter
659738032Speter		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
659838032Speter			continue;
659938032Speter
660038032Speter		mm->map_class->map_store(mm, key, val);
660138032Speter		return;
660238032Speter	}
660338032Speter	syserr("seq_map_store(%s, %s, %s): no writable map",
660438032Speter		map->map_mname, key, val);
660538032Speter}
660638032Speter/*
660738032Speter**  NULL stubs
660838032Speter*/
660938032Speter
661038032Speter/* ARGSUSED */
661138032Speterbool
661238032Speternull_map_open(map, mode)
661338032Speter	MAP *map;
661438032Speter	int mode;
661538032Speter{
661638032Speter	return TRUE;
661738032Speter}
661838032Speter
661938032Speter/* ARGSUSED */
662038032Spetervoid
662138032Speternull_map_close(map)
662238032Speter	MAP *map;
662338032Speter{
662438032Speter	return;
662538032Speter}
662638032Speter
662738032Speterchar *
662838032Speternull_map_lookup(map, key, args, pstat)
662938032Speter	MAP *map;
663038032Speter	char *key;
663138032Speter	char **args;
663238032Speter	int *pstat;
663338032Speter{
663438032Speter	*pstat = EX_NOTFOUND;
663538032Speter	return NULL;
663638032Speter}
663738032Speter
663838032Speter/* ARGSUSED */
663938032Spetervoid
664038032Speternull_map_store(map, key, val)
664138032Speter	MAP *map;
664238032Speter	char *key;
664338032Speter	char *val;
664438032Speter{
664538032Speter	return;
664638032Speter}
664738032Speter
664838032Speter
664938032Speter/*
665038032Speter**  BOGUS stubs
665138032Speter*/
665238032Speter
665338032Speterchar *
665438032Speterbogus_map_lookup(map, key, args, pstat)
665538032Speter	MAP *map;
665638032Speter	char *key;
665738032Speter	char **args;
665838032Speter	int *pstat;
665938032Speter{
666038032Speter	*pstat = EX_TEMPFAIL;
666138032Speter	return NULL;
666238032Speter}
666338032Speter
666438032SpeterMAPCLASS	BogusMapClass =
666538032Speter{
666638032Speter	"bogus-map",		NULL,		0,
666738032Speter	NULL,		bogus_map_lookup,	null_map_store,
666838032Speter	null_map_open,	null_map_close,
666938032Speter};
667038032Speter/*
667164562Sgshapiro**  MACRO modules
667264562Sgshapiro*/
667364562Sgshapiro
667464562Sgshapirochar *
667564562Sgshapiromacro_map_lookup(map, name, av, statp)
667664562Sgshapiro	MAP *map;
667764562Sgshapiro	char *name;
667864562Sgshapiro	char **av;
667964562Sgshapiro	int *statp;
668064562Sgshapiro{
668164562Sgshapiro	int mid;
668264562Sgshapiro
668364562Sgshapiro	if (tTd(38, 20))
668464562Sgshapiro		dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
668564562Sgshapiro			name == NULL ? "NULL" : name);
668664562Sgshapiro
668764562Sgshapiro	if (name == NULL ||
668864562Sgshapiro	    *name == '\0' ||
668964562Sgshapiro	    (mid = macid(name, NULL)) == '\0')
669064562Sgshapiro	{
669164562Sgshapiro		*statp = EX_CONFIG;
669264562Sgshapiro		return NULL;
669364562Sgshapiro	}
669464562Sgshapiro
669564562Sgshapiro	if (av[1] == NULL)
669664562Sgshapiro		define(mid, NULL, CurEnv);
669764562Sgshapiro	else
669864562Sgshapiro		define(mid, newstr(av[1]), CurEnv);
669964562Sgshapiro
670064562Sgshapiro	*statp = EX_OK;
670164562Sgshapiro	return "";
670264562Sgshapiro}
670364562Sgshapiro/*
670438032Speter**  REGEX modules
670538032Speter*/
670638032Speter
670738032Speter#ifdef MAP_REGEX
670838032Speter
670938032Speter# include <regex.h>
671038032Speter
671138032Speter# define DEFAULT_DELIM	CONDELSE
671238032Speter
671338032Speter# define END_OF_FIELDS	-1
671438032Speter
671538032Speter# define ERRBUF_SIZE	80
671638032Speter# define MAX_MATCH	32
671738032Speter
671864562Sgshapiro# define xnalloc(s)	memset(xalloc(s), '\0', s);
671938032Speter
672038032Speterstruct regex_map
672138032Speter{
672264562Sgshapiro	regex_t	regex_pattern_buf;	/* xalloc it */
672338032Speter	int	*regex_subfields;	/* move to type MAP */
672464562Sgshapiro	char	*regex_delim;		/* move to type MAP */
672538032Speter};
672638032Speter
672738032Speterstatic int
672838032Speterparse_fields(s, ibuf, blen, nr_substrings)
672938032Speter	char *s;
673038032Speter	int *ibuf;		/* array */
673138032Speter	int blen;		/* number of elements in ibuf */
673238032Speter	int nr_substrings;	/* number of substrings in the pattern */
673338032Speter{
673438032Speter	register char *cp;
673538032Speter	int i = 0;
673638032Speter	bool lastone = FALSE;
673738032Speter
673838032Speter	blen--;		/* for terminating END_OF_FIELDS */
673938032Speter	cp = s;
674038032Speter	do
674138032Speter	{
674238032Speter		for (;; cp++)
674338032Speter		{
674438032Speter			if (*cp == ',')
674538032Speter			{
674638032Speter				*cp = '\0';
674738032Speter				break;
674838032Speter			}
674938032Speter			if (*cp == '\0')
675038032Speter			{
675138032Speter				lastone = TRUE;
675238032Speter				break;
675338032Speter			}
675438032Speter		}
675538032Speter		if (i < blen)
675638032Speter		{
675738032Speter			int val = atoi(s);
675838032Speter
675938032Speter			if (val < 0 || val >= nr_substrings)
676038032Speter			{
676138032Speter				syserr("field (%d) out of range, only %d substrings in pattern",
676238032Speter				       val, nr_substrings);
676338032Speter				return -1;
676438032Speter			}
676538032Speter			ibuf[i++] = val;
676638032Speter		}
676738032Speter		else
676838032Speter		{
676938032Speter			syserr("too many fields, %d max\n", blen);
677038032Speter			return -1;
677138032Speter		}
677238032Speter		s = ++cp;
677338032Speter	} while (!lastone);
677438032Speter	ibuf[i] = END_OF_FIELDS;
677538032Speter	return i;
677638032Speter}
677738032Speter
677838032Speterbool
677938032Speterregex_map_init(map, ap)
678038032Speter	MAP *map;
678138032Speter	char *ap;
678238032Speter{
678338032Speter	int regerr;
678438032Speter	struct regex_map *map_p;
678538032Speter	register char *p;
678638032Speter	char *sub_param = NULL;
678738032Speter	int pflags;
678838032Speter	static char defdstr[] = { (char)DEFAULT_DELIM, '\0' };
678938032Speter
679038032Speter	if (tTd(38, 2))
679164562Sgshapiro		dprintf("regex_map_init: mapname '%s', args '%s'\n",
679264562Sgshapiro			map->map_mname, ap);
679338032Speter
679438032Speter	pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
679538032Speter
679638032Speter	p = ap;
679738032Speter
679864562Sgshapiro	map_p = (struct regex_map *) xnalloc(sizeof *map_p);
679938032Speter
680038032Speter	for (;;)
680164562Sgshapiro	{
680238032Speter		while (isascii(*p) && isspace(*p))
680338032Speter			p++;
680438032Speter		if (*p != '-')
680538032Speter			break;
680638032Speter		switch (*++p)
680738032Speter		{
680838032Speter		  case 'n':	/* not */
680938032Speter			map->map_mflags |= MF_REGEX_NOT;
681038032Speter			break;
681138032Speter
681238032Speter		  case 'f':	/* case sensitive */
681338032Speter			map->map_mflags |= MF_NOFOLDCASE;
681438032Speter			pflags &= ~REG_ICASE;
681538032Speter			break;
681638032Speter
681738032Speter		  case 'b':	/* basic regular expressions */
681838032Speter			pflags &= ~REG_EXTENDED;
681938032Speter			break;
682038032Speter
682138032Speter		  case 's':	/* substring match () syntax */
682238032Speter			sub_param = ++p;
682338032Speter			pflags &= ~REG_NOSUB;
682438032Speter			break;
682538032Speter
682638032Speter		  case 'd':	/* delimiter */
682764562Sgshapiro			map_p->regex_delim = ++p;
682838032Speter			break;
682938032Speter
683038032Speter		  case 'a':	/* map append */
683138032Speter			map->map_app = ++p;
683238032Speter			break;
683338032Speter
683438032Speter		  case 'm':	/* matchonly */
683538032Speter			map->map_mflags |= MF_MATCHONLY;
683638032Speter			break;
683738032Speter
683864562Sgshapiro		  case 'S':
683964562Sgshapiro			map->map_spacesub = *++p;
684064562Sgshapiro			break;
684164562Sgshapiro
684264562Sgshapiro		  case 'D':
684364562Sgshapiro			map->map_mflags |= MF_DEFER;
684464562Sgshapiro			break;
684564562Sgshapiro
684638032Speter		}
684764562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
684864562Sgshapiro			p++;
684964562Sgshapiro		if (*p != '\0')
685064562Sgshapiro			*p++ = '\0';
685138032Speter	}
685238032Speter	if (tTd(38, 3))
685364562Sgshapiro		dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
685438032Speter
685564562Sgshapiro	if ((regerr = regcomp(&(map_p->regex_pattern_buf), p, pflags)) != 0)
685638032Speter	{
685738032Speter		/* Errorhandling */
685838032Speter		char errbuf[ERRBUF_SIZE];
685938032Speter
686064562Sgshapiro		(void) regerror(regerr, &(map_p->regex_pattern_buf),
686164562Sgshapiro			 errbuf, ERRBUF_SIZE);
686238032Speter		syserr("pattern-compile-error: %s\n", errbuf);
686338032Speter		free(map_p);
686438032Speter		return FALSE;
686538032Speter	}
686638032Speter
686738032Speter	if (map->map_app != NULL)
686838032Speter		map->map_app = newstr(map->map_app);
686964562Sgshapiro	if (map_p->regex_delim != NULL)
687064562Sgshapiro		map_p->regex_delim = newstr(map_p->regex_delim);
687138032Speter	else
687264562Sgshapiro		map_p->regex_delim = defdstr;
687338032Speter
687438032Speter	if (!bitset(REG_NOSUB, pflags))
687538032Speter	{
687638032Speter		/* substring matching */
687738032Speter		int substrings;
687864562Sgshapiro		int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1));
687938032Speter
688064562Sgshapiro		substrings = map_p->regex_pattern_buf.re_nsub + 1;
688138032Speter
688238032Speter		if (tTd(38, 3))
688364562Sgshapiro			dprintf("regex_map_init: nr of substrings %d\n",
688464562Sgshapiro				substrings);
688538032Speter
688638032Speter		if (substrings >= MAX_MATCH)
688738032Speter		{
688838032Speter			syserr("too many substrings, %d max\n", MAX_MATCH);
688938032Speter			free(map_p);
689038032Speter			return FALSE;
689138032Speter		}
689238032Speter		if (sub_param != NULL && sub_param[0] != '\0')
689338032Speter		{
689438032Speter			/* optional parameter -sfields */
689538032Speter			if (parse_fields(sub_param, fields,
689638032Speter					 MAX_MATCH + 1, substrings) == -1)
689738032Speter				return FALSE;
689838032Speter		}
689938032Speter		else
690038032Speter		{
690164562Sgshapiro			/* set default fields */
690238032Speter			int i;
690338032Speter
690438032Speter			for (i = 0; i < substrings; i++)
690538032Speter				fields[i] = i;
690638032Speter			fields[i] = END_OF_FIELDS;
690738032Speter		}
690838032Speter		map_p->regex_subfields = fields;
690938032Speter		if (tTd(38, 3))
691038032Speter		{
691138032Speter			int *ip;
691238032Speter
691364562Sgshapiro			dprintf("regex_map_init: subfields");
691438032Speter			for (ip = fields; *ip != END_OF_FIELDS; ip++)
691564562Sgshapiro				dprintf(" %d", *ip);
691664562Sgshapiro			dprintf("\n");
691738032Speter		}
691838032Speter	}
691938032Speter	map->map_db1 = (ARBPTR_T)map_p;	/* dirty hack */
692038032Speter
692138032Speter	return TRUE;
692238032Speter}
692338032Speter
692438032Speterstatic char *
692538032Speterregex_map_rewrite(map, s, slen, av)
692638032Speter	MAP *map;
692738032Speter	const char *s;
692838032Speter	size_t slen;
692938032Speter	char **av;
693038032Speter{
693138032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
693238032Speter		return map_rewrite(map, av[0], strlen(av[0]), NULL);
693338032Speter	else
693438032Speter		return map_rewrite(map, s, slen, NULL);
693538032Speter}
693638032Speter
693738032Speterchar *
693838032Speterregex_map_lookup(map, name, av, statp)
693938032Speter	MAP *map;
694038032Speter	char *name;
694138032Speter	char **av;
694238032Speter	int *statp;
694338032Speter{
694438032Speter	int reg_res;
694538032Speter	struct regex_map *map_p;
694638032Speter	regmatch_t pmatch[MAX_MATCH];
694738032Speter
694838032Speter	if (tTd(38, 20))
694938032Speter	{
695038032Speter		char **cpp;
695138032Speter
695264562Sgshapiro		dprintf("regex_map_lookup: key '%s'\n", name);
695364562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
695464562Sgshapiro			dprintf("regex_map_lookup: arg '%s'\n", *cpp);
695538032Speter	}
695638032Speter
695738032Speter	map_p = (struct regex_map *)(map->map_db1);
695864562Sgshapiro	reg_res = regexec(&(map_p->regex_pattern_buf),
695964562Sgshapiro			  name, MAX_MATCH, pmatch, 0);
696038032Speter
696138032Speter	if (bitset(MF_REGEX_NOT, map->map_mflags))
696238032Speter	{
696338032Speter		/* option -n */
696438032Speter		if (reg_res == REG_NOMATCH)
696538032Speter			return regex_map_rewrite(map, "", (size_t)0, av);
696638032Speter		else
696738032Speter			return NULL;
696838032Speter	}
696938032Speter	if (reg_res == REG_NOMATCH)
697038032Speter		return NULL;
697138032Speter
697238032Speter	if (map_p->regex_subfields != NULL)
697338032Speter	{
697438032Speter		/* option -s */
697538032Speter		static char retbuf[MAXNAME];
697638032Speter		int fields[MAX_MATCH + 1];
697738032Speter		bool first = TRUE;
697838032Speter		int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
697938032Speter		bool quotemode = FALSE, bslashmode = FALSE;
698038032Speter		register char *dp, *sp;
698138032Speter		char *endp, *ldp;
698238032Speter		int *ip;
698338032Speter
698438032Speter		dp = retbuf;
698538032Speter		ldp = retbuf + sizeof(retbuf) - 1;
698638032Speter
698738032Speter		if (av[1] != NULL)
698838032Speter		{
698938032Speter			if (parse_fields(av[1], fields, MAX_MATCH + 1,
699064562Sgshapiro					 (int) map_p->regex_pattern_buf.re_nsub + 1) == -1)
699138032Speter			{
699238032Speter				*statp = EX_CONFIG;
699338032Speter				return NULL;
699438032Speter			}
699538032Speter			ip = fields;
699638032Speter		}
699738032Speter		else
699838032Speter			ip = map_p->regex_subfields;
699938032Speter
700038032Speter		for ( ; *ip != END_OF_FIELDS; ip++)
700138032Speter		{
700238032Speter			if (!first)
700338032Speter			{
700464562Sgshapiro				for (sp = map_p->regex_delim; *sp; sp++)
700538032Speter				{
700638032Speter					if (dp < ldp)
700738032Speter						*dp++ = *sp;
700838032Speter				}
700938032Speter			}
701038032Speter			else
701138032Speter				first = FALSE;
701238032Speter
701338032Speter
701438032Speter			if (pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
701538032Speter				continue;
701638032Speter
701738032Speter			sp = name + pmatch[*ip].rm_so;
701838032Speter			endp = name + pmatch[*ip].rm_eo;
701938032Speter			for (; endp > sp; sp++)
702038032Speter			{
702138032Speter				if (dp < ldp)
702238032Speter				{
702364562Sgshapiro					if (bslashmode)
702464562Sgshapiro					{
702538032Speter						*dp++ = *sp;
702638032Speter						bslashmode = FALSE;
702738032Speter					}
702864562Sgshapiro					else if (quotemode && *sp != '"' &&
702938032Speter						*sp != '\\')
703038032Speter					{
703138032Speter						*dp++ = *sp;
703238032Speter					}
703338032Speter					else switch(*dp++ = *sp)
703438032Speter					{
703538032Speter						case '\\':
703638032Speter						bslashmode = TRUE;
703738032Speter						break;
703838032Speter
703938032Speter						case '(':
704038032Speter						cmntcnt++;
704138032Speter						break;
704238032Speter
704338032Speter						case ')':
704438032Speter						cmntcnt--;
704538032Speter						break;
704638032Speter
704738032Speter						case '<':
704838032Speter						anglecnt++;
704938032Speter						break;
705038032Speter
705138032Speter						case '>':
705238032Speter						anglecnt--;
705338032Speter						break;
705438032Speter
705538032Speter						case ' ':
705638032Speter						spacecnt++;
705738032Speter						break;
705838032Speter
705938032Speter						case '"':
706038032Speter						quotemode = !quotemode;
706138032Speter						break;
706238032Speter					}
706338032Speter				}
706438032Speter			}
706538032Speter		}
706638032Speter		if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
706738032Speter		    bslashmode || spacecnt != 0)
706838032Speter		{
706964562Sgshapiro			sm_syslog(LOG_WARNING, NOQID,
707064562Sgshapiro				  "Warning: regex may cause prescan() failure map=%s lookup=%s",
707164562Sgshapiro				  map->map_mname, name);
707238032Speter			return NULL;
707338032Speter		}
707438032Speter
707538032Speter		*dp = '\0';
707638032Speter
707738032Speter		return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
707838032Speter	}
707938032Speter	return regex_map_rewrite(map, "", (size_t)0, av);
708038032Speter}
708138032Speter#endif /* MAP_REGEX */
708264562Sgshapiro/*
708364562Sgshapiro**  NSD modules
708464562Sgshapiro*/
708564562Sgshapiro#ifdef MAP_NSD
708664562Sgshapiro
708764562Sgshapiro# include <ndbm.h>
708864562Sgshapiro# define _DATUM_DEFINED
708964562Sgshapiro# include <ns_api.h>
709064562Sgshapiro
709164562Sgshapirotypedef struct ns_map_list
709264562Sgshapiro{
709364562Sgshapiro	ns_map_t *map;
709464562Sgshapiro	char *mapname;
709564562Sgshapiro	struct ns_map_list *next;
709664562Sgshapiro} ns_map_list_t;
709764562Sgshapiro
709864562Sgshapirostatic ns_map_t *
709964562Sgshapirons_map_t_find(mapname)
710064562Sgshapiro	char *mapname;
710164562Sgshapiro{
710264562Sgshapiro	static ns_map_list_t *ns_maps = NULL;
710364562Sgshapiro	ns_map_list_t *ns_map;
710464562Sgshapiro
710564562Sgshapiro	/* walk the list of maps looking for the correctly named map */
710664562Sgshapiro	for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next)
710764562Sgshapiro	{
710864562Sgshapiro		if (strcmp(ns_map->mapname, mapname) == 0)
710964562Sgshapiro			break;
711064562Sgshapiro	}
711164562Sgshapiro
711264562Sgshapiro	/* if we are looking at a NULL ns_map_list_t, then create a new one */
711364562Sgshapiro	if (ns_map == NULL)
711464562Sgshapiro	{
711564562Sgshapiro		ns_map = (ns_map_list_t *) xalloc(sizeof *ns_map);
711664562Sgshapiro		ns_map->mapname = newstr(mapname);
711764562Sgshapiro		ns_map->map = (ns_map_t *) xalloc(sizeof *ns_map->map);
711864562Sgshapiro		ns_map->next = ns_maps;
711964562Sgshapiro		ns_maps = ns_map;
712064562Sgshapiro	}
712164562Sgshapiro	return ns_map->map;
712264562Sgshapiro}
712364562Sgshapiro
712464562Sgshapirochar *
712564562Sgshapironsd_map_lookup(map, name, av, statp)
712664562Sgshapiro	MAP *map;
712764562Sgshapiro	char *name;
712864562Sgshapiro	char **av;
712964562Sgshapiro	int *statp;
713064562Sgshapiro{
713164562Sgshapiro	int buflen;
713264562Sgshapiro	char *p;
713364562Sgshapiro	ns_map_t *ns_map;
713464562Sgshapiro	char keybuf[MAXNAME + 1];
713564562Sgshapiro	char buf[MAXLINE];
713664562Sgshapiro
713764562Sgshapiro	if (tTd(38, 20))
713864562Sgshapiro		dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
713964562Sgshapiro
714064562Sgshapiro	buflen = strlen(name);
714164562Sgshapiro	if (buflen > sizeof keybuf - 1)
714264562Sgshapiro		buflen = sizeof keybuf - 1;
714364562Sgshapiro	memmove(keybuf, name, buflen);
714464562Sgshapiro	keybuf[buflen] = '\0';
714564562Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
714664562Sgshapiro		makelower(keybuf);
714764562Sgshapiro
714864562Sgshapiro	ns_map = ns_map_t_find(map->map_file);
714964562Sgshapiro	if (ns_map == NULL)
715064562Sgshapiro	{
715164562Sgshapiro		if (tTd(38, 20))
715264562Sgshapiro			dprintf("nsd_map_t_find failed\n");
715364562Sgshapiro		return NULL;
715464562Sgshapiro	}
715564562Sgshapiro
715664562Sgshapiro	if (ns_lookup(ns_map, NULL, map->map_file,
715764562Sgshapiro		      keybuf, NULL, buf, MAXLINE) == NULL)
715864562Sgshapiro		return NULL;
715964562Sgshapiro
716064562Sgshapiro	/* Null out trailing \n */
716164562Sgshapiro	if ((p = strchr(buf, '\n')) != NULL)
716264562Sgshapiro		*p = '\0';
716364562Sgshapiro
716464562Sgshapiro	return map_rewrite(map, buf, strlen(buf), av);
716564562Sgshapiro}
716664562Sgshapiro#endif /* MAP_NSD */
716764562Sgshapiro
716864562Sgshapirochar *
716964562Sgshapiroarith_map_lookup(map, name, av, statp)
717064562Sgshapiro	MAP *map;
717164562Sgshapiro	char *name;
717264562Sgshapiro	char **av;
717364562Sgshapiro	int *statp;
717464562Sgshapiro{
717564562Sgshapiro	long r;
717664562Sgshapiro	long v[2];
717764562Sgshapiro	bool res = FALSE;
717864562Sgshapiro	bool boolres;
717964562Sgshapiro	static char result[16];
718064562Sgshapiro	char **cpp;
718164562Sgshapiro
718264562Sgshapiro	if (tTd(38, 2))
718364562Sgshapiro	{
718464562Sgshapiro		dprintf("arith_map_lookup: key '%s'\n", name);
718564562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
718664562Sgshapiro			dprintf("arith_map_lookup: arg '%s'\n", *cpp);
718764562Sgshapiro	}
718864562Sgshapiro	r = 0;
718964562Sgshapiro	boolres = FALSE;
719064562Sgshapiro	cpp = av;
719164562Sgshapiro	*statp = EX_OK;
719264562Sgshapiro
719364562Sgshapiro	/*
719464562Sgshapiro	**  read arguments for arith map
719564562Sgshapiro	**  - no check is made whether they are really numbers
719664562Sgshapiro	**  - just ignores args after the second
719764562Sgshapiro	*/
719864562Sgshapiro	for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
719964562Sgshapiro		v[r++] = strtol(*cpp, NULL, 0);
720064562Sgshapiro
720164562Sgshapiro	/* operator and (at least) two operands given? */
720264562Sgshapiro	if (name != NULL && r == 2)
720364562Sgshapiro	{
720464562Sgshapiro		switch(*name)
720564562Sgshapiro		{
720664562Sgshapiro#if _FFR_ARITH
720764562Sgshapiro		  case '|':
720864562Sgshapiro			r = v[0] | v[1];
720964562Sgshapiro			break;
721064562Sgshapiro
721164562Sgshapiro		  case '&':
721264562Sgshapiro			r = v[0] & v[1];
721364562Sgshapiro			break;
721464562Sgshapiro
721564562Sgshapiro		  case '%':
721664562Sgshapiro			if (v[1] == 0)
721764562Sgshapiro				return NULL;
721864562Sgshapiro			r = v[0] % v[1];
721964562Sgshapiro			break;
722064562Sgshapiro#endif /* _FFR_ARITH */
722164562Sgshapiro
722264562Sgshapiro		  case '+':
722364562Sgshapiro			r = v[0] + v[1];
722464562Sgshapiro			break;
722564562Sgshapiro
722664562Sgshapiro		  case '-':
722764562Sgshapiro			r = v[0] - v[1];
722864562Sgshapiro			break;
722964562Sgshapiro
723064562Sgshapiro		  case '*':
723164562Sgshapiro			r = v[0] * v[1];
723264562Sgshapiro			break;
723364562Sgshapiro
723464562Sgshapiro		  case '/':
723564562Sgshapiro			if (v[1] == 0)
723664562Sgshapiro				return NULL;
723764562Sgshapiro			r = v[0] / v[1];
723864562Sgshapiro			break;
723964562Sgshapiro
724064562Sgshapiro		  case 'l':
724164562Sgshapiro			res = v[0] < v[1];
724264562Sgshapiro			boolres = TRUE;
724364562Sgshapiro			break;
724464562Sgshapiro
724564562Sgshapiro		  case '=':
724664562Sgshapiro			res = v[0] == v[1];
724764562Sgshapiro			boolres = TRUE;
724864562Sgshapiro			break;
724964562Sgshapiro
725064562Sgshapiro		  default:
725164562Sgshapiro			/* XXX */
725264562Sgshapiro			*statp = EX_CONFIG;
725364562Sgshapiro			if (LogLevel > 10)
725464562Sgshapiro				sm_syslog(LOG_WARNING, NOQID,
725564562Sgshapiro					  "arith_map: unknown operator %c",
725664562Sgshapiro					  isprint(*name) ? *name : '?');
725764562Sgshapiro			return NULL;
725864562Sgshapiro		}
725964562Sgshapiro		if (boolres)
726064562Sgshapiro			snprintf(result, sizeof result, res ? "TRUE" : "FALSE");
726164562Sgshapiro		else
726264562Sgshapiro			snprintf(result, sizeof result, "%ld", r);
726364562Sgshapiro		return result;
726464562Sgshapiro	}
726564562Sgshapiro	*statp = EX_CONFIG;
726664562Sgshapiro	return NULL;
726764562Sgshapiro}
7268