map.c revision 71345
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
1571345Sgshapirostatic char id[] = "@(#)$Id: map.c,v 8.414.4.34 2000/12/18 18:00:43 ca Exp $";
1664562Sgshapiro#endif /* ! lint */
1738032Speter
1864562Sgshapiro#include <sendmail.h>
1938032Speter
2064562Sgshapiro
2138032Speter#ifdef NDBM
2238032Speter# include <ndbm.h>
2338032Speter# ifdef R_FIRST
2438032Speter  ERROR README:	You are running the Berkeley DB version of ndbm.h.  See
2538032Speter  ERROR README:	the README file about tweaking Berkeley DB so it can
2638032Speter  ERROR README:	coexist with NDBM, or delete -DNDBM from the Makefile
2738032Speter  ERROR README: and use -DNEWDB instead.
2864562Sgshapiro# endif /* R_FIRST */
2964562Sgshapiro#endif /* NDBM */
3038032Speter#ifdef NEWDB
3138032Speter# include <db.h>
3238032Speter# ifndef DB_VERSION_MAJOR
3338032Speter#  define DB_VERSION_MAJOR 1
3464562Sgshapiro# endif /* ! DB_VERSION_MAJOR */
3564562Sgshapiro#endif /* NEWDB */
3638032Speter#ifdef NIS
3738032Speter  struct dom_binding;	/* forward reference needed on IRIX */
3838032Speter# include <rpcsvc/ypclnt.h>
3938032Speter# ifdef NDBM
4038032Speter#  define NDBM_YP_COMPAT	/* create YP-compatible NDBM files */
4164562Sgshapiro# endif /* NDBM */
4264562Sgshapiro#endif /* NIS */
4338032Speter
4464562Sgshapiro#ifdef NEWDB
4564562Sgshapiro# if DB_VERSION_MAJOR < 2
4664562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
4764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
4864562Sgshapiro# if DB_VERSION_MAJOR == 2
4964562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
5064562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
5164562Sgshapiro# if DB_VERSION_MAJOR > 2
5264562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, void **));
5364562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
5464562Sgshapiro#endif /* NEWDB */
5564562Sgshapirostatic bool	extract_canonname __P((char *, char *, char[], int));
5664562Sgshapiro#ifdef LDAPMAP
5764562Sgshapirostatic void	ldapmap_clear __P((LDAPMAP_STRUCT *));
5864562Sgshapirostatic STAB	*ldapmap_findconn __P((LDAPMAP_STRUCT *));
5964562Sgshapirostatic int	ldapmap_geterrno __P((LDAP *));
6064562Sgshapirostatic void	ldapmap_setopts __P((LDAP *, LDAPMAP_STRUCT *));
6164562Sgshapirostatic bool	ldapmap_start __P((MAP *));
6264562Sgshapirostatic void	ldaptimeout __P((int));
6364562Sgshapiro#endif /* LDAPMAP */
6464562Sgshapirostatic void	map_close __P((STAB *, int));
6564562Sgshapirostatic void	map_init __P((STAB *, int));
6664562Sgshapiro#ifdef NISPLUS
6764562Sgshapirostatic bool	nisplus_getcanonname __P((char *, int, int *));
6864562Sgshapiro#endif /* NISPLUS */
6964562Sgshapiro#ifdef NIS
7064562Sgshapirostatic bool	nis_getcanonname __P((char *, int, int *));
7164562Sgshapiro#endif /* NIS */
7264562Sgshapiro#if NETINFO
7364562Sgshapirostatic bool	ni_getcanonname __P((char *, int, int *));
7464562Sgshapiro#endif /* NETINFO */
7564562Sgshapirostatic bool	text_getcanonname __P((char *, int, int *));
7664562Sgshapiro
7738032Speter/*
7838032Speter**  MAP.C -- implementations for various map classes.
7938032Speter**
8038032Speter**	Each map class implements a series of functions:
8138032Speter**
8238032Speter**	bool map_parse(MAP *map, char *args)
8338032Speter**		Parse the arguments from the config file.  Return TRUE
8438032Speter**		if they were ok, FALSE otherwise.  Fill in map with the
8538032Speter**		values.
8638032Speter**
8738032Speter**	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
8838032Speter**		Look up the key in the given map.  If found, do any
8938032Speter**		rewriting the map wants (including "args" if desired)
9038032Speter**		and return the value.  Set *pstat to the appropriate status
9138032Speter**		on error and return NULL.  Args will be NULL if called
9238032Speter**		from the alias routines, although this should probably
9338032Speter**		not be relied upon.  It is suggested you call map_rewrite
9438032Speter**		to return the results -- it takes care of null termination
9538032Speter**		and uses a dynamically expanded buffer as needed.
9638032Speter**
9738032Speter**	void map_store(MAP *map, char *key, char *value)
9838032Speter**		Store the key:value pair in the map.
9938032Speter**
10038032Speter**	bool map_open(MAP *map, int mode)
10138032Speter**		Open the map for the indicated mode.  Mode should
10238032Speter**		be either O_RDONLY or O_RDWR.  Return TRUE if it
10338032Speter**		was opened successfully, FALSE otherwise.  If the open
10438032Speter**		failed an the MF_OPTIONAL flag is not set, it should
10538032Speter**		also print an error.  If the MF_ALIAS bit is set
10638032Speter**		and this map class understands the @:@ convention, it
10738032Speter**		should call aliaswait() before returning.
10838032Speter**
10938032Speter**	void map_close(MAP *map)
11038032Speter**		Close the map.
11138032Speter**
11238032Speter**	This file also includes the implementation for getcanonname.
11338032Speter**	It is currently implemented in a pretty ad-hoc manner; it ought
11438032Speter**	to be more properly integrated into the map structure.
11538032Speter*/
11638032Speter
11738032Speter#define DBMMODE		0644
11838032Speter
11938032Speter#ifndef EX_NOTFOUND
12038032Speter# define EX_NOTFOUND	EX_NOHOST
12164562Sgshapiro#endif /* ! EX_NOTFOUND */
12238032Speter
12338032Speter#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
12438032Speter# define LOCK_ON_OPEN	1	/* we can open/create a locked file */
12564562Sgshapiro#else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
12638032Speter# define LOCK_ON_OPEN	0	/* no such luck -- bend over backwards */
12764562Sgshapiro#endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
12838032Speter
12938032Speter#ifndef O_ACCMODE
13038032Speter# define O_ACCMODE	(O_RDONLY|O_WRONLY|O_RDWR)
13164562Sgshapiro#endif /* ! O_ACCMODE */
13238032Speter/*
13338032Speter**  MAP_PARSEARGS -- parse config line arguments for database lookup
13438032Speter**
13538032Speter**	This is a generic version of the map_parse method.
13638032Speter**
13738032Speter**	Parameters:
13838032Speter**		map -- the map being initialized.
13938032Speter**		ap -- a pointer to the args on the config line.
14038032Speter**
14138032Speter**	Returns:
14238032Speter**		TRUE -- if everything parsed OK.
14338032Speter**		FALSE -- otherwise.
14438032Speter**
14538032Speter**	Side Effects:
14638032Speter**		null terminates the filename; stores it in map
14738032Speter*/
14838032Speter
14938032Speterbool
15038032Spetermap_parseargs(map, ap)
15138032Speter	MAP *map;
15238032Speter	char *ap;
15338032Speter{
15438032Speter	register char *p = ap;
15538032Speter
15664562Sgshapiro	/*
15764562Sgshapiro	**  there is no check whether there is really an argument,
15864562Sgshapiro	**  but that's not important enough to warrant extra code
15964562Sgshapiro	*/
16038032Speter	map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
16164562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
16238032Speter	for (;;)
16338032Speter	{
16438032Speter		while (isascii(*p) && isspace(*p))
16538032Speter			p++;
16638032Speter		if (*p != '-')
16738032Speter			break;
16838032Speter		switch (*++p)
16938032Speter		{
17038032Speter		  case 'N':
17138032Speter			map->map_mflags |= MF_INCLNULL;
17238032Speter			map->map_mflags &= ~MF_TRY0NULL;
17338032Speter			break;
17438032Speter
17538032Speter		  case 'O':
17638032Speter			map->map_mflags &= ~MF_TRY1NULL;
17738032Speter			break;
17838032Speter
17938032Speter		  case 'o':
18038032Speter			map->map_mflags |= MF_OPTIONAL;
18138032Speter			break;
18238032Speter
18338032Speter		  case 'f':
18438032Speter			map->map_mflags |= MF_NOFOLDCASE;
18538032Speter			break;
18638032Speter
18738032Speter		  case 'm':
18838032Speter			map->map_mflags |= MF_MATCHONLY;
18938032Speter			break;
19038032Speter
19138032Speter		  case 'A':
19238032Speter			map->map_mflags |= MF_APPEND;
19338032Speter			break;
19438032Speter
19538032Speter		  case 'q':
19638032Speter			map->map_mflags |= MF_KEEPQUOTES;
19738032Speter			break;
19838032Speter
19938032Speter		  case 'a':
20038032Speter			map->map_app = ++p;
20138032Speter			break;
20238032Speter
20338032Speter		  case 'T':
20438032Speter			map->map_tapp = ++p;
20538032Speter			break;
20638032Speter
20738032Speter		  case 'k':
20838032Speter			while (isascii(*++p) && isspace(*p))
20938032Speter				continue;
21038032Speter			map->map_keycolnm = p;
21138032Speter			break;
21238032Speter
21338032Speter		  case 'v':
21438032Speter			while (isascii(*++p) && isspace(*p))
21538032Speter				continue;
21638032Speter			map->map_valcolnm = p;
21738032Speter			break;
21838032Speter
21938032Speter		  case 'z':
22038032Speter			if (*++p != '\\')
22138032Speter				map->map_coldelim = *p;
22238032Speter			else
22338032Speter			{
22438032Speter				switch (*++p)
22538032Speter				{
22638032Speter				  case 'n':
22738032Speter					map->map_coldelim = '\n';
22838032Speter					break;
22938032Speter
23038032Speter				  case 't':
23138032Speter					map->map_coldelim = '\t';
23238032Speter					break;
23338032Speter
23438032Speter				  default:
23538032Speter					map->map_coldelim = '\\';
23638032Speter				}
23738032Speter			}
23838032Speter			break;
23938032Speter
24038032Speter		  case 't':
24138032Speter			map->map_mflags |= MF_NODEFER;
24238032Speter			break;
24338032Speter
24464562Sgshapiro
24564562Sgshapiro		  case 'S':
24664562Sgshapiro			map->map_spacesub = *++p;
24738032Speter			break;
24838032Speter
24964562Sgshapiro		  case 'D':
25064562Sgshapiro			map->map_mflags |= MF_DEFER;
25138032Speter			break;
25264562Sgshapiro
25364562Sgshapiro		  default:
25464562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
25564562Sgshapiro			break;
25638032Speter		}
25738032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
25838032Speter			p++;
25938032Speter		if (*p != '\0')
26038032Speter			*p++ = '\0';
26138032Speter	}
26238032Speter	if (map->map_app != NULL)
26338032Speter		map->map_app = newstr(map->map_app);
26438032Speter	if (map->map_tapp != NULL)
26538032Speter		map->map_tapp = newstr(map->map_tapp);
26638032Speter	if (map->map_keycolnm != NULL)
26738032Speter		map->map_keycolnm = newstr(map->map_keycolnm);
26838032Speter	if (map->map_valcolnm != NULL)
26938032Speter		map->map_valcolnm = newstr(map->map_valcolnm);
27038032Speter
27138032Speter	if (*p != '\0')
27238032Speter	{
27338032Speter		map->map_file = p;
27438032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
27538032Speter			p++;
27638032Speter		if (*p != '\0')
27738032Speter			*p++ = '\0';
27838032Speter		map->map_file = newstr(map->map_file);
27938032Speter	}
28038032Speter
28138032Speter	while (*p != '\0' && isascii(*p) && isspace(*p))
28238032Speter		p++;
28338032Speter	if (*p != '\0')
28438032Speter		map->map_rebuild = newstr(p);
28538032Speter
28638032Speter	if (map->map_file == NULL &&
28738032Speter	    !bitset(MCF_OPTFILE, map->map_class->map_cflags))
28838032Speter	{
28938032Speter		syserr("No file name for %s map %s",
29038032Speter			map->map_class->map_cname, map->map_mname);
29138032Speter		return FALSE;
29238032Speter	}
29338032Speter	return TRUE;
29438032Speter}
29538032Speter/*
29638032Speter**  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
29738032Speter**
29838032Speter**	It also adds the map_app string.  It can be used as a utility
29938032Speter**	in the map_lookup method.
30038032Speter**
30138032Speter**	Parameters:
30238032Speter**		map -- the map that causes this.
30338032Speter**		s -- the string to rewrite, NOT necessarily null terminated.
30438032Speter**		slen -- the length of s.
30538032Speter**		av -- arguments to interpolate into buf.
30638032Speter**
30738032Speter**	Returns:
30838032Speter**		Pointer to rewritten result.  This is static data that
30938032Speter**		should be copied if it is to be saved!
31038032Speter**
31138032Speter**	Side Effects:
31238032Speter**		none.
31338032Speter*/
31438032Speter
31538032Speterchar *
31638032Spetermap_rewrite(map, s, slen, av)
31738032Speter	register MAP *map;
31838032Speter	register const char *s;
31938032Speter	size_t slen;
32038032Speter	char **av;
32138032Speter{
32238032Speter	register char *bp;
32338032Speter	register char c;
32438032Speter	char **avp;
32538032Speter	register char *ap;
32638032Speter	size_t l;
32738032Speter	size_t len;
32838032Speter	static size_t buflen = 0;
32938032Speter	static char *buf = NULL;
33038032Speter
33138032Speter	if (tTd(39, 1))
33238032Speter	{
33364562Sgshapiro		dprintf("map_rewrite(%.*s), av =", (int)slen, s);
33438032Speter		if (av == NULL)
33564562Sgshapiro			dprintf(" (nullv)");
33638032Speter		else
33738032Speter		{
33838032Speter			for (avp = av; *avp != NULL; avp++)
33964562Sgshapiro				dprintf("\n\t%s", *avp);
34038032Speter		}
34164562Sgshapiro		dprintf("\n");
34238032Speter	}
34338032Speter
34438032Speter	/* count expected size of output (can safely overestimate) */
34538032Speter	l = len = slen;
34638032Speter	if (av != NULL)
34738032Speter	{
34838032Speter		const char *sp = s;
34938032Speter
35038032Speter		while (l-- > 0 && (c = *sp++) != '\0')
35138032Speter		{
35238032Speter			if (c != '%')
35338032Speter				continue;
35438032Speter			if (l-- <= 0)
35538032Speter				break;
35638032Speter			c = *sp++;
35738032Speter			if (!(isascii(c) && isdigit(c)))
35838032Speter				continue;
35938032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
36038032Speter				continue;
36138032Speter			if (*avp == NULL)
36238032Speter				continue;
36338032Speter			len += strlen(*avp);
36438032Speter		}
36538032Speter	}
36638032Speter	if (map->map_app != NULL)
36738032Speter		len += strlen(map->map_app);
36838032Speter	if (buflen < ++len)
36938032Speter	{
37038032Speter		/* need to malloc additional space */
37138032Speter		buflen = len;
37238032Speter		if (buf != NULL)
37338032Speter			free(buf);
37438032Speter		buf = xalloc(buflen);
37538032Speter	}
37638032Speter
37738032Speter	bp = buf;
37838032Speter	if (av == NULL)
37938032Speter	{
38064562Sgshapiro		memmove(bp, s, slen);
38138032Speter		bp += slen;
38264562Sgshapiro
38364562Sgshapiro		/* assert(len > slen); */
38464562Sgshapiro		len -= slen;
38538032Speter	}
38638032Speter	else
38738032Speter	{
38838032Speter		while (slen-- > 0 && (c = *s++) != '\0')
38938032Speter		{
39038032Speter			if (c != '%')
39138032Speter			{
39238032Speter  pushc:
39364562Sgshapiro				if (--len <= 0)
39464562Sgshapiro					break;
39538032Speter				*bp++ = c;
39638032Speter				continue;
39738032Speter			}
39838032Speter			if (slen-- <= 0 || (c = *s++) == '\0')
39938032Speter				c = '%';
40038032Speter			if (c == '%')
40138032Speter				goto pushc;
40238032Speter			if (!(isascii(c) && isdigit(c)))
40338032Speter			{
40438032Speter				*bp++ = '%';
40564562Sgshapiro				--len;
40638032Speter				goto pushc;
40738032Speter			}
40838032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
40938032Speter				continue;
41038032Speter			if (*avp == NULL)
41138032Speter				continue;
41238032Speter
41338032Speter			/* transliterate argument into output string */
41464562Sgshapiro			for (ap = *avp; (c = *ap++) != '\0' && len > 0; --len)
41538032Speter				*bp++ = c;
41638032Speter		}
41738032Speter	}
41864562Sgshapiro	if (map->map_app != NULL && len > 0)
41964562Sgshapiro		(void) strlcpy(bp, map->map_app, len);
42038032Speter	else
42138032Speter		*bp = '\0';
42238032Speter	if (tTd(39, 1))
42364562Sgshapiro		dprintf("map_rewrite => %s\n", buf);
42438032Speter	return buf;
42538032Speter}
42638032Speter/*
42764562Sgshapiro**  INITMAPS -- rebuild alias maps
42838032Speter**
42938032Speter**	Parameters:
43064562Sgshapiro**		none.
43138032Speter**
43238032Speter**	Returns:
43338032Speter**		none.
43438032Speter*/
43538032Speter
43638032Spetervoid
43764562Sgshapiroinitmaps()
43838032Speter{
43938032Speter#if XDEBUG
44038032Speter	checkfd012("entering initmaps");
44164562Sgshapiro#endif /* XDEBUG */
44238032Speter	stabapply(map_init, 0);
44338032Speter#if XDEBUG
44438032Speter	checkfd012("exiting initmaps");
44564562Sgshapiro#endif /* XDEBUG */
44638032Speter}
44764562Sgshapiro/*
44864562Sgshapiro**  MAP_INIT -- rebuild a map
44964562Sgshapiro**
45064562Sgshapiro**	Parameters:
45164562Sgshapiro**		s -- STAB entry: if map: try to rebuild
45264562Sgshapiro**		unused -- unused variable
45364562Sgshapiro**
45464562Sgshapiro**	Returns:
45564562Sgshapiro**		none.
45664562Sgshapiro**
45764562Sgshapiro**	Side Effects:
45864562Sgshapiro**		will close already open rebuildable map.
45964562Sgshapiro*/
46038032Speter
46164562Sgshapiro/* ARGSUSED1 */
46264562Sgshapirostatic void
46364562Sgshapiromap_init(s, unused)
46438032Speter	register STAB *s;
46564562Sgshapiro	int unused;
46638032Speter{
46738032Speter	register MAP *map;
46838032Speter
46938032Speter	/* has to be a map */
47038032Speter	if (s->s_type != ST_MAP)
47138032Speter		return;
47238032Speter
47338032Speter	map = &s->s_map;
47438032Speter	if (!bitset(MF_VALID, map->map_mflags))
47538032Speter		return;
47638032Speter
47738032Speter	if (tTd(38, 2))
47864562Sgshapiro		dprintf("map_init(%s:%s, %s)\n",
47938032Speter			map->map_class->map_cname == NULL ? "NULL" :
48038032Speter				map->map_class->map_cname,
48138032Speter			map->map_mname == NULL ? "NULL" : map->map_mname,
48264562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
48338032Speter
48464562Sgshapiro	if (!bitset(MF_ALIAS, map->map_mflags) ||
48564562Sgshapiro	    !bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
48638032Speter	{
48738032Speter		if (tTd(38, 3))
48864562Sgshapiro			dprintf("\tnot rebuildable\n");
48938032Speter		return;
49038032Speter	}
49138032Speter
49238032Speter	/* if already open, close it (for nested open) */
49338032Speter	if (bitset(MF_OPEN, map->map_mflags))
49438032Speter	{
49538032Speter		map->map_class->map_close(map);
49638032Speter		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
49738032Speter	}
49838032Speter
49964562Sgshapiro	(void) rebuildaliases(map, FALSE);
50064562Sgshapiro	return;
50164562Sgshapiro}
50264562Sgshapiro/*
50364562Sgshapiro**  OPENMAP -- open a map
50464562Sgshapiro**
50564562Sgshapiro**	Parameters:
50664562Sgshapiro**		map -- map to open (it must not be open).
50764562Sgshapiro**
50864562Sgshapiro**	Returns:
50964562Sgshapiro**		whether open succeeded.
51064562Sgshapiro**
51164562Sgshapiro*/
51264562Sgshapiro
51364562Sgshapirobool
51464562Sgshapiroopenmap(map)
51564562Sgshapiro	MAP *map;
51664562Sgshapiro{
51764562Sgshapiro	bool restore = FALSE;
51864562Sgshapiro	bool savehold = HoldErrs;
51964562Sgshapiro	bool savequick = QuickAbort;
52064562Sgshapiro	int saveerrors = Errors;
52164562Sgshapiro
52264562Sgshapiro	if (!bitset(MF_VALID, map->map_mflags))
52364562Sgshapiro		return FALSE;
52464562Sgshapiro
52564562Sgshapiro	/* better safe than sorry... */
52664562Sgshapiro	if (bitset(MF_OPEN, map->map_mflags))
52764562Sgshapiro		return TRUE;
52864562Sgshapiro
52964562Sgshapiro	/* Don't send a map open error out via SMTP */
53064562Sgshapiro	if ((OnlyOneError || QuickAbort) &&
53164562Sgshapiro	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))
53238032Speter	{
53364562Sgshapiro		restore = TRUE;
53464562Sgshapiro		HoldErrs = TRUE;
53564562Sgshapiro		QuickAbort = FALSE;
53638032Speter	}
53738032Speter
53864562Sgshapiro	errno = 0;
53938032Speter	if (map->map_class->map_open(map, O_RDONLY))
54038032Speter	{
54138032Speter		if (tTd(38, 4))
54264562Sgshapiro			dprintf("openmap()\t%s:%s %s: valid\n",
54338032Speter				map->map_class->map_cname == NULL ? "NULL" :
54438032Speter					map->map_class->map_cname,
54538032Speter				map->map_mname == NULL ? "NULL" :
54638032Speter					map->map_mname,
54738032Speter				map->map_file == NULL ? "NULL" :
54838032Speter					map->map_file);
54938032Speter		map->map_mflags |= MF_OPEN;
55042575Speter		map->map_pid = getpid();
55138032Speter	}
55238032Speter	else
55338032Speter	{
55438032Speter		if (tTd(38, 4))
55564562Sgshapiro			dprintf("openmap()\t%s:%s %s: invalid%s%s\n",
55638032Speter				map->map_class->map_cname == NULL ? "NULL" :
55738032Speter					map->map_class->map_cname,
55838032Speter				map->map_mname == NULL ? "NULL" :
55938032Speter					map->map_mname,
56038032Speter				map->map_file == NULL ? "NULL" :
56138032Speter					map->map_file,
56264562Sgshapiro				errno == 0 ? "" : ": ",
56364562Sgshapiro				errno == 0 ? "" : errstring(errno));
56438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
56538032Speter		{
56638032Speter			extern MAPCLASS BogusMapClass;
56738032Speter
56838032Speter			map->map_class = &BogusMapClass;
56938032Speter			map->map_mflags |= MF_OPEN;
57042575Speter			map->map_pid = getpid();
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);
289871345Sgshapiro	save_errno = errno;
289964562Sgshapiro# else /* USE_LDAP_INIT */
290064562Sgshapiro	/*
290164562Sgshapiro	**  If using ldap_open(), the actual connection to the server
290264562Sgshapiro	**  happens now so we need the timeout here.  For ldap_init(),
290364562Sgshapiro	**  the connection happens at bind time.
290464562Sgshapiro	*/
290538032Speter
290638032Speter	/* set the timeout */
290764562Sgshapiro	if (lmap->ldap_timeout.tv_sec != 0)
290838032Speter	{
290938032Speter		if (setjmp(LDAPTimeout) != 0)
291038032Speter		{
291138032Speter			if (LogLevel > 1)
291238032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
291364562Sgshapiro					  "timeout conning to LDAP server %.100s",
291464562Sgshapiro					  lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host);
291564562Sgshapiro			return FALSE;
291638032Speter		}
291764562Sgshapiro		ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
291838032Speter	}
291938032Speter
292064562Sgshapiro	ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
292164562Sgshapiro	save_errno = errno;
292242575Speter
292364562Sgshapiro	/* clear the event if it has not sprung */
292464562Sgshapiro	if (ev != NULL)
292542575Speter		clrevent(ev);
292664562Sgshapiro# endif /* USE_LDAP_INIT */
292742575Speter
292864562Sgshapiro	errno = save_errno;
292942575Speter	if (ld == NULL)
293038032Speter	{
293138032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
293238032Speter		{
293364562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
293464562Sgshapiro				syserr("%s failed to %s in map %s",
293564562Sgshapiro# if USE_LDAP_INIT
293664562Sgshapiro				       "ldap_init",
293764562Sgshapiro# else /* USE_LDAP_INIT */
293864562Sgshapiro				       "ldap_open",
293964562Sgshapiro# endif /* USE_LDAP_INIT */
294064562Sgshapiro				       lmap->ldap_host == NULL ? "localhost"
294164562Sgshapiro							       : lmap->ldap_host,
294264562Sgshapiro				       map->map_mname);
294364562Sgshapiro			else
294464562Sgshapiro				syserr("421 4.0.0 %s failed to %s in map %s",
294564562Sgshapiro# if USE_LDAP_INIT
294664562Sgshapiro				       "ldap_init",
294764562Sgshapiro# else /* USE_LDAP_INIT */
294864562Sgshapiro				       "ldap_open",
294964562Sgshapiro# endif /* USE_LDAP_INIT */
295064562Sgshapiro				       lmap->ldap_host == NULL ? "localhost"
295164562Sgshapiro							       : lmap->ldap_host,
295264562Sgshapiro				       map->map_mname);
295338032Speter		}
295438032Speter		return FALSE;
295538032Speter	}
295638032Speter
295764562Sgshapiro	ldapmap_setopts(ld, lmap);
295838032Speter
295964562Sgshapiro# if USE_LDAP_INIT
296064562Sgshapiro	/*
296164562Sgshapiro	**  If using ldap_init(), the actual connection to the server
296264562Sgshapiro	**  happens at ldap_bind_s() so we need the timeout here.
296364562Sgshapiro	*/
296464562Sgshapiro
296564562Sgshapiro	/* set the timeout */
296664562Sgshapiro	if (lmap->ldap_timeout.tv_sec != 0)
296738032Speter	{
296864562Sgshapiro		if (setjmp(LDAPTimeout) != 0)
296938032Speter		{
297064562Sgshapiro			if (LogLevel > 1)
297164562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
297264562Sgshapiro					  "timeout conning to LDAP server %.100s",
297364562Sgshapiro					  lmap->ldap_host == NULL ? "localhost"
297464562Sgshapiro								  : lmap->ldap_host);
297564562Sgshapiro			return FALSE;
297638032Speter		}
297764562Sgshapiro		ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
297838032Speter	}
297964562Sgshapiro# endif /* USE_LDAP_INIT */
298064562Sgshapiro
298164562Sgshapiro# ifdef LDAP_AUTH_KRBV4
298264562Sgshapiro	if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
298364562Sgshapiro	    lmap->ldap_secret != NULL)
298438032Speter	{
298564562Sgshapiro		/*
298664562Sgshapiro		**  Need to put ticket in environment here instead of
298764562Sgshapiro		**  during parseargs as there may be different tickets
298864562Sgshapiro		**  for different LDAP connections.
298964562Sgshapiro		*/
299064562Sgshapiro
299164562Sgshapiro		(void) putenv(lmap->ldap_secret);
299238032Speter	}
299364562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
299438032Speter
299564562Sgshapiro	bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
299664562Sgshapiro				  lmap->ldap_secret, lmap->ldap_method);
299764562Sgshapiro
299864562Sgshapiro# if USE_LDAP_INIT
299964562Sgshapiro	/* clear the event if it has not sprung */
300064562Sgshapiro	if (ev != NULL)
300164562Sgshapiro		clrevent(ev);
300264562Sgshapiro# endif /* USE_LDAP_INIT */
300364562Sgshapiro
300464562Sgshapiro	if (bind_result != LDAP_SUCCESS)
300564562Sgshapiro	{
300664562Sgshapiro		errno = bind_result + E_LDAPBASE;
300764562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
300864562Sgshapiro		{
300964562Sgshapiro			syserr("421 4.0.0 Cannot bind to map %s in ldap server %s",
301064562Sgshapiro			       map->map_mname,
301164562Sgshapiro			       lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host);
301264562Sgshapiro		}
301364562Sgshapiro		return FALSE;
301464562Sgshapiro	}
301564562Sgshapiro
301664562Sgshapiro	/* We need to cast ld into the map structure */
301764562Sgshapiro	lmap->ldap_ld = ld;
301864562Sgshapiro	return TRUE;
301938032Speter}
302038032Speter
302164562Sgshapiro/* ARGSUSED */
302264562Sgshapirostatic void
302364562Sgshapiroldaptimeout(sig_no)
302464562Sgshapiro	int sig_no;
302564562Sgshapiro{
302664562Sgshapiro	longjmp(LDAPTimeout, 1);
302764562Sgshapiro}
302838032Speter
302938032Speter/*
303064562Sgshapiro**  LDAPMAP_CLOSE -- close ldap map
303138032Speter*/
303238032Speter
303338032Spetervoid
303464562Sgshapiroldapmap_close(map)
303538032Speter	MAP *map;
303638032Speter{
303764562Sgshapiro	LDAPMAP_STRUCT *lmap;
303864562Sgshapiro	STAB *s;
303943730Speter
304064562Sgshapiro	if (tTd(38, 2))
304164562Sgshapiro		dprintf("ldapmap_close(%s)\n", map->map_mname);
304264562Sgshapiro
304364562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
304464562Sgshapiro
304564562Sgshapiro	/* Check if already closed */
304664562Sgshapiro	if (lmap->ldap_ld == NULL)
304764562Sgshapiro		return;
304864562Sgshapiro
304964562Sgshapiro	s = ldapmap_findconn(lmap);
305064562Sgshapiro
305164562Sgshapiro	/* Check if already closed */
305264562Sgshapiro	if (s->s_ldap == NULL)
305364562Sgshapiro		return;
305464562Sgshapiro
305564562Sgshapiro	/* If same as saved connection, stored connection is going away */
305664562Sgshapiro	if (s->s_ldap == lmap->ldap_ld)
305764562Sgshapiro		s->s_ldap = NULL;
305864562Sgshapiro
305964562Sgshapiro	if (lmap->ldap_ld != NULL)
306043730Speter	{
306164562Sgshapiro		ldap_unbind(lmap->ldap_ld);
306264562Sgshapiro		lmap->ldap_ld = NULL;
306343730Speter	}
306438032Speter}
306538032Speter
306664562Sgshapiro# ifdef SUNET_ID
306743730Speter/*
306842575Speter**  SUNET_ID_HASH -- Convert a string to it's Sunet_id canonical form
306942575Speter**  This only makes sense at Stanford University.
307038032Speter*/
307138032Speter
307238032Speterchar *
307338032Spetersunet_id_hash(str)
307438032Speter	char *str;
307538032Speter{
307638032Speter	char *p, *p_last;
307738032Speter
307838032Speter	p = str;
307938032Speter	p_last = p;
308038032Speter	while (*p != '\0')
308138032Speter	{
308238032Speter		if (islower(*p) || isdigit(*p))
308338032Speter		{
308438032Speter			*p_last = *p;
308538032Speter			p_last++;
308638032Speter		}
308738032Speter		else if (isupper(*p))
308838032Speter		{
308938032Speter			*p_last = tolower(*p);
309038032Speter			p_last++;
309138032Speter		}
309238032Speter		++p;
309338032Speter	}
309438032Speter	if (*p_last != '\0')
309538032Speter		*p_last = '\0';
309664562Sgshapiro	return str;
309738032Speter}
309864562Sgshapiro# endif /* SUNET_ID */
309938032Speter
310038032Speter/*
310164562Sgshapiro**  LDAPMAP_LOOKUP -- look up a datum in a LDAP map
310238032Speter*/
310338032Speter
310438032Speterchar *
310564562Sgshapiroldapmap_lookup(map, name, av, statp)
310638032Speter	MAP *map;
310738032Speter	char *name;
310838032Speter	char **av;
310938032Speter	int *statp;
311038032Speter{
311164562Sgshapiro	int i;
311264562Sgshapiro	int entries = 0;
311364562Sgshapiro	int msgid;
311464562Sgshapiro	int ret;
311564562Sgshapiro	int vsize;
311664562Sgshapiro	char *fp, *vp;
311764562Sgshapiro	char *p, *q;
311864562Sgshapiro	char *result = NULL;
311964562Sgshapiro	LDAPMAP_STRUCT *lmap = NULL;
312038032Speter	char keybuf[MAXNAME + 1];
312164562Sgshapiro	char filter[LDAPMAP_MAX_FILTER + 1];
312238032Speter
312338032Speter	if (tTd(38, 20))
312464562Sgshapiro		dprintf("ldapmap_lookup(%s, %s)\n", map->map_mname, name);
312538032Speter
312638032Speter	/* Get ldap struct pointer from map */
312764562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
312864562Sgshapiro	ldapmap_setopts(lmap->ldap_ld, lmap);
312938032Speter
313064562Sgshapiro	(void) strlcpy(keybuf, name, sizeof keybuf);
313138032Speter
313238032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
313364562Sgshapiro	{
313464562Sgshapiro# ifdef SUNET_ID
313538032Speter		sunet_id_hash(keybuf);
313664562Sgshapiro# else /* SUNET_ID */
313738032Speter		makelower(keybuf);
313864562Sgshapiro# endif /* SUNET_ID */
313964562Sgshapiro	}
314038032Speter
314142575Speter	/* substitute keybuf into filter, perhaps multiple times */
314264562Sgshapiro	memset(filter, '\0', sizeof filter);
314342575Speter	fp = filter;
314464562Sgshapiro	p = lmap->ldap_filter;
314542575Speter	while ((q = strchr(p, '%')) != NULL)
314642575Speter	{
314742575Speter		if (q[1] == 's')
314842575Speter		{
314942575Speter			snprintf(fp, SPACELEFT(filter, fp), "%.*s%s",
315066494Sgshapiro				 (int) (q - p), p, keybuf);
315164562Sgshapiro			fp += strlen(fp);
315242575Speter			p = q + 2;
315342575Speter		}
315464562Sgshapiro		else if (q[1] == '0')
315564562Sgshapiro		{
315664562Sgshapiro			char *k = keybuf;
315764562Sgshapiro
315864562Sgshapiro			snprintf(fp, SPACELEFT(filter, fp), "%.*s",
315966494Sgshapiro				 (int) (q - p), p);
316064562Sgshapiro			fp += strlen(fp);
316164562Sgshapiro			p = q + 2;
316264562Sgshapiro
316364562Sgshapiro			/* Properly escape LDAP special characters */
316464562Sgshapiro			while (SPACELEFT(filter, fp) > 0 &&
316564562Sgshapiro			       *k != '\0')
316664562Sgshapiro			{
316764562Sgshapiro				if (*k == '*' || *k == '(' ||
316864562Sgshapiro				    *k == ')' || *k == '\\')
316964562Sgshapiro				{
317064562Sgshapiro					(void) strlcat(fp,
317164562Sgshapiro						       (*k == '*' ? "\\2A" :
317264562Sgshapiro							(*k == '(' ? "\\28" :
317364562Sgshapiro							 (*k == ')' ? "\\29" :
317464562Sgshapiro							  (*k == '\\' ? "\\5C" :
317564562Sgshapiro							   "\00")))),
317664562Sgshapiro						SPACELEFT(filter, fp));
317764562Sgshapiro					fp += strlen(fp);
317864562Sgshapiro					k++;
317964562Sgshapiro				}
318064562Sgshapiro				else
318164562Sgshapiro					*fp++ = *k++;
318264562Sgshapiro			}
318364562Sgshapiro		}
318442575Speter		else
318542575Speter		{
318642575Speter			snprintf(fp, SPACELEFT(filter, fp), "%.*s",
318766494Sgshapiro				 (int) (q - p + 1), p);
318842575Speter			p = q + (q[1] == '%' ? 2 : 1);
318964562Sgshapiro			fp += strlen(fp);
319042575Speter		}
319142575Speter	}
319242575Speter	snprintf(fp, SPACELEFT(filter, fp), "%s", p);
319342575Speter	if (tTd(38, 20))
319464562Sgshapiro		dprintf("ldap search filter=%s\n", filter);
319538032Speter
319664562Sgshapiro	lmap->ldap_res = NULL;
319764562Sgshapiro	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope,
319864562Sgshapiro			    filter,
319964562Sgshapiro			    (lmap->ldap_attr[0] == NULL ? NULL :
320064562Sgshapiro			     lmap->ldap_attr),
320164562Sgshapiro			    lmap->ldap_attrsonly);
320264562Sgshapiro	if (msgid == -1)
320338032Speter	{
320464562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
320564562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
320638032Speter		{
320764562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
320866494Sgshapiro				syserr("Error in ldap_search using %s in map %s",
320964562Sgshapiro				       filter, map->map_mname);
321064562Sgshapiro			else
321166494Sgshapiro				syserr("421 4.0.0 Error in ldap_search using %s in map %s",
321264562Sgshapiro				       filter, map->map_mname);
321338032Speter		}
321464562Sgshapiro		*statp = EX_TEMPFAIL;
321566494Sgshapiro#ifdef LDAP_SERVER_DOWN
321666494Sgshapiro		if (errno == LDAP_SERVER_DOWN)
321766494Sgshapiro		{
321866494Sgshapiro			int save_errno = errno;
321966494Sgshapiro
322066494Sgshapiro			/* server disappeared, try reopen on next search */
322166494Sgshapiro			map->map_class->map_close(map);
322266494Sgshapiro			map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
322366494Sgshapiro			errno = save_errno;
322466494Sgshapiro		}
322566494Sgshapiro#endif /* LDAP_SERVER_DOWN */
322664562Sgshapiro		return NULL;
322764562Sgshapiro	}
322864562Sgshapiro
322964562Sgshapiro	*statp = EX_NOTFOUND;
323064562Sgshapiro	vp = NULL;
323164562Sgshapiro
323264562Sgshapiro	/* Get results (all if MF_NOREWRITE, otherwise one by one) */
323364562Sgshapiro	while ((ret = ldap_result(lmap->ldap_ld, msgid,
323464562Sgshapiro				  bitset(MF_NOREWRITE, map->map_mflags),
323564562Sgshapiro				  (lmap->ldap_timeout.tv_sec == 0 ? NULL :
323664562Sgshapiro				   &(lmap->ldap_timeout)),
323764562Sgshapiro				  &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
323864562Sgshapiro	{
323964562Sgshapiro		LDAPMessage *entry;
324064562Sgshapiro
324164562Sgshapiro		if (bitset(MF_SINGLEMATCH, map->map_mflags))
324238032Speter		{
324364562Sgshapiro			entries += ldap_count_entries(lmap->ldap_ld,
324464562Sgshapiro						      lmap->ldap_res);
324564562Sgshapiro			if (entries > 1)
324664562Sgshapiro			{
324764562Sgshapiro				*statp = EX_NOTFOUND;
324864562Sgshapiro				if (lmap->ldap_res != NULL)
324964562Sgshapiro				{
325064562Sgshapiro					ldap_msgfree(lmap->ldap_res);
325164562Sgshapiro					lmap->ldap_res = NULL;
325264562Sgshapiro				}
325364562Sgshapiro				(void) ldap_abandon(lmap->ldap_ld, msgid);
325464562Sgshapiro				if (vp != NULL)
325564562Sgshapiro					free(vp);
325664562Sgshapiro				if (tTd(38, 25))
325764562Sgshapiro					dprintf("ldap search found multiple on a single match query\n");
325864562Sgshapiro				return NULL;
325964562Sgshapiro			}
326064562Sgshapiro		}
326164562Sgshapiro
326264562Sgshapiro		/* If we don't want multiple values and we have one, break */
326364562Sgshapiro		if (map->map_coldelim == '\0' && vp != NULL)
326464562Sgshapiro			break;
326564562Sgshapiro
326664562Sgshapiro		/* Cycle through all entries */
326764562Sgshapiro		for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
326864562Sgshapiro		     entry != NULL;
326964562Sgshapiro		     entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
327064562Sgshapiro		{
327164562Sgshapiro			BerElement *ber;
327264562Sgshapiro			char *attr;
327364562Sgshapiro			char **vals = NULL;
327464562Sgshapiro
327564562Sgshapiro			/*
327664562Sgshapiro			**  If matching only and found an entry,
327764562Sgshapiro			**  no need to spin through attributes
327864562Sgshapiro			*/
327964562Sgshapiro
328064562Sgshapiro			if (*statp == EX_OK &&
328164562Sgshapiro			    bitset(MF_MATCHONLY, map->map_mflags))
328264562Sgshapiro				continue;
328364562Sgshapiro
328464562Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
328564562Sgshapiro			/*
328664562Sgshapiro			**  Reset value to prevent lingering
328764562Sgshapiro			**  LDAP_DECODING_ERROR due to
328864562Sgshapiro			**  OpenLDAP 1.X's hack (see below)
328964562Sgshapiro			*/
329064562Sgshapiro
329164562Sgshapiro			lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
329264562Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
329364562Sgshapiro
329464562Sgshapiro			for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
329564562Sgshapiro							 &ber);
329664562Sgshapiro			     attr != NULL;
329764562Sgshapiro			     attr = ldap_next_attribute(lmap->ldap_ld, entry,
329864562Sgshapiro							ber))
329964562Sgshapiro			{
330064562Sgshapiro				char *tmp, *vp_tmp;
330164562Sgshapiro
330264562Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
330364562Sgshapiro				{
330464562Sgshapiro					vals = ldap_get_values(lmap->ldap_ld,
330564562Sgshapiro							       entry,
330664562Sgshapiro							       attr);
330764562Sgshapiro					if (vals == NULL)
330864562Sgshapiro					{
330964562Sgshapiro						errno = ldapmap_geterrno(lmap->ldap_ld);
331064562Sgshapiro						if (errno == LDAP_SUCCESS)
331164562Sgshapiro							continue;
331264562Sgshapiro
331364562Sgshapiro						/* Must be an error */
331464562Sgshapiro						errno += E_LDAPBASE;
331564562Sgshapiro						if (!bitset(MF_OPTIONAL,
331664562Sgshapiro							    map->map_mflags))
331764562Sgshapiro						{
331864562Sgshapiro							if (bitset(MF_NODEFER,
331964562Sgshapiro								   map->map_mflags))
332064562Sgshapiro								syserr("Error getting LDAP values in map %s",
332164562Sgshapiro								       map->map_mname);
332264562Sgshapiro							else
332364562Sgshapiro								syserr("421 4.0.0 Error getting LDAP values in map %s",
332464562Sgshapiro								       map->map_mname);
332564562Sgshapiro						}
332664562Sgshapiro						*statp = EX_TEMPFAIL;
332764562Sgshapiro# if USING_NETSCAPE_LDAP
332866494Sgshapiro						ldap_memfree(attr);
332964562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
333064562Sgshapiro						if (lmap->ldap_res != NULL)
333164562Sgshapiro						{
333264562Sgshapiro							ldap_msgfree(lmap->ldap_res);
333364562Sgshapiro							lmap->ldap_res = NULL;
333464562Sgshapiro						}
333564562Sgshapiro						(void) ldap_abandon(lmap->ldap_ld,
333664562Sgshapiro								    msgid);
333764562Sgshapiro						if (vp != NULL)
333864562Sgshapiro							free(vp);
333964562Sgshapiro						return NULL;
334064562Sgshapiro					}
334164562Sgshapiro				}
334264562Sgshapiro
334364562Sgshapiro				*statp = EX_OK;
334464562Sgshapiro
334564562Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
334664562Sgshapiro				/*
334764562Sgshapiro				**  Reset value to prevent lingering
334864562Sgshapiro				**  LDAP_DECODING_ERROR due to
334964562Sgshapiro				**  OpenLDAP 1.X's hack (see below)
335064562Sgshapiro				*/
335164562Sgshapiro
335264562Sgshapiro				lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
335364562Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
335464562Sgshapiro
335564562Sgshapiro				/*
335664562Sgshapiro				**  If matching only,
335764562Sgshapiro				**  no need to spin through entries
335864562Sgshapiro				*/
335964562Sgshapiro
336064562Sgshapiro				if (bitset(MF_MATCHONLY, map->map_mflags))
336164562Sgshapiro					continue;
336264562Sgshapiro
336364562Sgshapiro				/*
336464562Sgshapiro				**  If we don't want multiple values,
336564562Sgshapiro				**  return first found.
336664562Sgshapiro				*/
336764562Sgshapiro
336864562Sgshapiro				if (map->map_coldelim == '\0')
336964562Sgshapiro				{
337064562Sgshapiro					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
337164562Sgshapiro					{
337264562Sgshapiro						vp = newstr(attr);
337364562Sgshapiro# if USING_NETSCAPE_LDAP
337466494Sgshapiro						ldap_memfree(attr);
337564562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
337664562Sgshapiro						break;
337764562Sgshapiro					}
337864562Sgshapiro
337964562Sgshapiro					if (vals[0] == NULL)
338064562Sgshapiro					{
338164562Sgshapiro						ldap_value_free(vals);
338264562Sgshapiro# if USING_NETSCAPE_LDAP
338366494Sgshapiro						ldap_memfree(attr);
338464562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
338564562Sgshapiro						continue;
338664562Sgshapiro					}
338764562Sgshapiro
338864562Sgshapiro					vp = newstr(vals[0]);
338964562Sgshapiro					ldap_value_free(vals);
339064562Sgshapiro# if USING_NETSCAPE_LDAP
339166494Sgshapiro					ldap_memfree(attr);
339264562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
339364562Sgshapiro					break;
339464562Sgshapiro				}
339564562Sgshapiro
339664562Sgshapiro				/* attributes only */
339764562Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
339864562Sgshapiro				{
339964562Sgshapiro					if (vp == NULL)
340064562Sgshapiro						vp = newstr(attr);
340164562Sgshapiro					else
340264562Sgshapiro					{
340364562Sgshapiro						vsize = strlen(vp) +
340464562Sgshapiro							strlen(attr) + 2;
340564562Sgshapiro						tmp = xalloc(vsize);
340664562Sgshapiro						snprintf(tmp, vsize, "%s%c%s",
340764562Sgshapiro							 vp, map->map_coldelim,
340864562Sgshapiro							 attr);
340964562Sgshapiro						free(vp);
341064562Sgshapiro						vp = tmp;
341164562Sgshapiro					}
341264562Sgshapiro# if USING_NETSCAPE_LDAP
341366494Sgshapiro					ldap_memfree(attr);
341464562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
341564562Sgshapiro					continue;
341664562Sgshapiro				}
341764562Sgshapiro
341864562Sgshapiro				/*
341964562Sgshapiro				**  If there is more than one,
342064562Sgshapiro				**  munge then into a map_coldelim
342164562Sgshapiro				**  separated string
342264562Sgshapiro				*/
342364562Sgshapiro
342464562Sgshapiro				vsize = 0;
342564562Sgshapiro				for (i = 0; vals[i] != NULL; i++)
342664562Sgshapiro					vsize += strlen(vals[i]) + 1;
342764562Sgshapiro				vp_tmp = xalloc(vsize);
342864562Sgshapiro				*vp_tmp = '\0';
342964562Sgshapiro
343064562Sgshapiro				p = vp_tmp;
343164562Sgshapiro				for (i = 0; vals[i] != NULL; i++)
343264562Sgshapiro				{
343364562Sgshapiro					p += strlcpy(p, vals[i],
343464562Sgshapiro						     vsize - (p - vp_tmp));
343564562Sgshapiro					if (p >= vp_tmp + vsize)
343664562Sgshapiro						syserr("ldapmap_lookup: Internal error: buffer too small for LDAP values");
343764562Sgshapiro					if (vals[i + 1] != NULL)
343864562Sgshapiro						*p++ = map->map_coldelim;
343964562Sgshapiro				}
344064562Sgshapiro
344164562Sgshapiro				ldap_value_free(vals);
344264562Sgshapiro# if USING_NETSCAPE_LDAP
344366494Sgshapiro				ldap_memfree(attr);
344464562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
344564562Sgshapiro				if (vp == NULL)
344664562Sgshapiro				{
344764562Sgshapiro					vp = vp_tmp;
344864562Sgshapiro					continue;
344964562Sgshapiro				}
345064562Sgshapiro				vsize = strlen(vp) + strlen(vp_tmp) + 2;
345164562Sgshapiro				tmp = xalloc(vsize);
345264562Sgshapiro				snprintf(tmp, vsize, "%s%c%s",
345364562Sgshapiro					 vp, map->map_coldelim, vp_tmp);
345464562Sgshapiro
345564562Sgshapiro				free(vp);
345664562Sgshapiro				free(vp_tmp);
345764562Sgshapiro				vp = tmp;
345864562Sgshapiro			}
345964562Sgshapiro			errno = ldapmap_geterrno(lmap->ldap_ld);
346064562Sgshapiro
346164562Sgshapiro			/*
346264562Sgshapiro			**  We check errno != LDAP_DECODING_ERROR since
346364562Sgshapiro			**  OpenLDAP 1.X has a very ugly *undocumented*
346464562Sgshapiro			**  hack of returning this error code from
346564562Sgshapiro			**  ldap_next_attribute() if the library freed the
346664562Sgshapiro			**  ber attribute.  See:
346764562Sgshapiro			**  http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
346864562Sgshapiro			*/
346964562Sgshapiro
347064562Sgshapiro			if (errno != LDAP_SUCCESS &&
347164562Sgshapiro			    errno != LDAP_DECODING_ERROR)
347264562Sgshapiro			{
347364562Sgshapiro				/* Must be an error */
347464562Sgshapiro				errno += E_LDAPBASE;
347564562Sgshapiro				if (!bitset(MF_OPTIONAL, map->map_mflags))
347664562Sgshapiro				{
347764562Sgshapiro					if (bitset(MF_NODEFER, map->map_mflags))
347864562Sgshapiro						syserr("Error getting LDAP attributes in map %s",
347964562Sgshapiro						       map->map_mname);
348064562Sgshapiro					else
348164562Sgshapiro						syserr("421 4.0.0 Error getting LDAP attributes in map %s",
348264562Sgshapiro						       map->map_mname);
348364562Sgshapiro				}
348464562Sgshapiro				*statp = EX_TEMPFAIL;
348564562Sgshapiro				if (lmap->ldap_res != NULL)
348664562Sgshapiro				{
348764562Sgshapiro					ldap_msgfree(lmap->ldap_res);
348864562Sgshapiro					lmap->ldap_res = NULL;
348964562Sgshapiro				}
349064562Sgshapiro				(void) ldap_abandon(lmap->ldap_ld, msgid);
349164562Sgshapiro				if (vp != NULL)
349264562Sgshapiro					free(vp);
349364562Sgshapiro				return NULL;
349464562Sgshapiro			}
349564562Sgshapiro
349664562Sgshapiro			/* We don't want multiple values and we have one */
349764562Sgshapiro			if (map->map_coldelim == '\0' && vp != NULL)
349864562Sgshapiro				break;
349964562Sgshapiro		}
350064562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld);
350164562Sgshapiro		if (errno != LDAP_SUCCESS && errno != LDAP_DECODING_ERROR)
350264562Sgshapiro		{
350364562Sgshapiro			/* Must be an error */
350464562Sgshapiro			errno += E_LDAPBASE;
350538032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
350638032Speter			{
350764562Sgshapiro				if (bitset(MF_NODEFER, map->map_mflags))
350864562Sgshapiro					syserr("Error getting LDAP entries in map %s",
350964562Sgshapiro					       map->map_mname);
351064562Sgshapiro				else
351164562Sgshapiro					syserr("421 4.0.0 Error getting LDAP entries in map %s",
351264562Sgshapiro					       map->map_mname);
351338032Speter			}
351438032Speter			*statp = EX_TEMPFAIL;
351564562Sgshapiro			if (lmap->ldap_res != NULL)
351664562Sgshapiro			{
351764562Sgshapiro				ldap_msgfree(lmap->ldap_res);
351864562Sgshapiro				lmap->ldap_res = NULL;
351964562Sgshapiro			}
352064562Sgshapiro			(void) ldap_abandon(lmap->ldap_ld, msgid);
352164562Sgshapiro			if (vp != NULL)
352264562Sgshapiro				free(vp);
352364562Sgshapiro			return NULL;
352438032Speter		}
352564562Sgshapiro		ldap_msgfree(lmap->ldap_res);
352664562Sgshapiro		lmap->ldap_res = NULL;
352738032Speter	}
352838032Speter
352964562Sgshapiro	/*
353064562Sgshapiro	**  If grabbing all results at once for MF_NOREWRITE and
353164562Sgshapiro	**  only want a single match, make sure that's all we have
353264562Sgshapiro	*/
353364562Sgshapiro
353464562Sgshapiro	if (ret == LDAP_RES_SEARCH_RESULT &&
353564562Sgshapiro	    bitset(MF_NOREWRITE|MF_SINGLEMATCH, map->map_mflags))
353638032Speter	{
353764562Sgshapiro		entries += ldap_count_entries(lmap->ldap_ld, lmap->ldap_res);
353864562Sgshapiro		if (entries > 1)
353964562Sgshapiro		{
354064562Sgshapiro			*statp = EX_NOTFOUND;
354164562Sgshapiro			if (lmap->ldap_res != NULL)
354264562Sgshapiro			{
354364562Sgshapiro				ldap_msgfree(lmap->ldap_res);
354464562Sgshapiro				lmap->ldap_res = NULL;
354564562Sgshapiro			}
354664562Sgshapiro			if (vp != NULL)
354764562Sgshapiro				free(vp);
354864562Sgshapiro			return NULL;
354964562Sgshapiro		}
355064562Sgshapiro		*statp = EX_OK;
355138032Speter	}
355238032Speter
355364562Sgshapiro	if (ret == 0)
355464562Sgshapiro		errno = ETIMEDOUT;
355564562Sgshapiro	else
355664562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld);
355764562Sgshapiro	if (errno != LDAP_SUCCESS)
355838032Speter	{
355964562Sgshapiro		/* Must be an error */
356064562Sgshapiro		if (ret != 0)
356164562Sgshapiro			errno += E_LDAPBASE;
356264562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
356364562Sgshapiro		{
356464562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
356564562Sgshapiro				syserr("Error getting LDAP results in map %s",
356664562Sgshapiro				       map->map_mname);
356764562Sgshapiro			else
356864562Sgshapiro				syserr("421 4.0.0 Error getting LDAP results in map %s",
356964562Sgshapiro				       map->map_mname);
357064562Sgshapiro		}
357164562Sgshapiro		*statp = EX_TEMPFAIL;
357264562Sgshapiro		if (vp != NULL)
357364562Sgshapiro			free(vp);
357464562Sgshapiro		return NULL;
357538032Speter	}
357638032Speter
357764562Sgshapiro	/* Did we match anything? */
357871345Sgshapiro	if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags))
357964562Sgshapiro		return NULL;
358038032Speter
358164562Sgshapiro	/*
358264562Sgshapiro	**  If MF_NOREWRITE, we are special map which doesn't
358364562Sgshapiro	**  actually return a map value.  Instead, we don't free
358464562Sgshapiro	**  ldap_res and let the calling function process the LDAP
358564562Sgshapiro	**  results.  The caller should ldap_msgfree(lmap->ldap_res).
358664562Sgshapiro	*/
358738032Speter
358864562Sgshapiro	if (bitset(MF_NOREWRITE, map->map_mflags))
358964562Sgshapiro	{
359071345Sgshapiro		if (vp != NULL)
359171345Sgshapiro			free(vp);
359264562Sgshapiro		return "";
359364562Sgshapiro	}
359438032Speter
359564562Sgshapiro	if (*statp == EX_OK)
359664562Sgshapiro	{
359764562Sgshapiro		if (LogLevel > 9)
359864562Sgshapiro			sm_syslog(LOG_INFO, CurEnv->e_id,
359971345Sgshapiro				  "ldap %.100s => %s", name,
360071345Sgshapiro				  vp == NULL ? "<NULL>" : vp);
360164562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
360264562Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
360364562Sgshapiro		else
360471345Sgshapiro		{
360571345Sgshapiro			/* vp != NULL according to test above */
360664562Sgshapiro			result = map_rewrite(map, vp, strlen(vp), av);
360771345Sgshapiro		}
360871345Sgshapiro		if (vp != NULL)
360971345Sgshapiro			free(vp);
361064562Sgshapiro	}
361164562Sgshapiro	return result;
361238032Speter}
361338032Speter
361438032Speter/*
361564562Sgshapiro**  LDAPMAP_FINDCONN -- find an LDAP connection to the server
361664562Sgshapiro**
361764562Sgshapiro**	Cache LDAP connections based on the host, port, bind DN,
361866494Sgshapiro**	secret, and PID so we don't have multiple connections open to
361966494Sgshapiro**	the same server for different maps.  Need a separate connection
362066494Sgshapiro**	per PID since a parent process may close the map before the
362166494Sgshapiro**	child is done with it.
362264562Sgshapiro**
362364562Sgshapiro**	Parameters:
362464562Sgshapiro**		lmap -- LDAP map information
362564562Sgshapiro**
362664562Sgshapiro**	Returns:
362764562Sgshapiro**		Symbol table entry for the LDAP connection.
362864562Sgshapiro**
362938032Speter*/
363038032Speter
363164562Sgshapirostatic STAB *
363264562Sgshapiroldapmap_findconn(lmap)
363364562Sgshapiro	LDAPMAP_STRUCT *lmap;
363438032Speter{
363564562Sgshapiro	int len;
363664562Sgshapiro	char *nbuf;
363764562Sgshapiro	STAB *s;
363838032Speter
363964562Sgshapiro	len = (lmap->ldap_host == NULL ? strlen("localhost") :
364064562Sgshapiro					 strlen(lmap->ldap_host)) + 1 + 8 + 1 +
364164562Sgshapiro		(lmap->ldap_binddn == NULL ? 0 : strlen(lmap->ldap_binddn)) +
364264562Sgshapiro		1 +
364364562Sgshapiro		(lmap->ldap_secret == NULL ? 0 : strlen(lmap->ldap_secret)) +
364466494Sgshapiro		8 + 1;
364564562Sgshapiro	nbuf = xalloc(len);
364666494Sgshapiro	snprintf(nbuf, len, "%s%c%d%c%s%c%s%d",
364764562Sgshapiro		 (lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host),
364864562Sgshapiro		 CONDELSE,
364964562Sgshapiro		 lmap->ldap_port,
365064562Sgshapiro		 CONDELSE,
365164562Sgshapiro		 (lmap->ldap_binddn == NULL ? "" : lmap->ldap_binddn),
365264562Sgshapiro		 CONDELSE,
365366494Sgshapiro		 (lmap->ldap_secret == NULL ? "" : lmap->ldap_secret),
365466494Sgshapiro		 getpid());
365564562Sgshapiro	s = stab(nbuf, ST_LDAP, ST_ENTER);
365664562Sgshapiro	free(nbuf);
365764562Sgshapiro	return s;
365864562Sgshapiro}
365964562Sgshapiro/*
366064562Sgshapiro**  LDAPMAP_SETOPTS -- set LDAP options
366164562Sgshapiro**
366264562Sgshapiro**	Parameters:
366364562Sgshapiro**		ld -- LDAP session handle
366464562Sgshapiro**		lmap -- LDAP map information
366564562Sgshapiro**
366664562Sgshapiro**	Returns:
366764562Sgshapiro**		None.
366864562Sgshapiro**
366964562Sgshapiro*/
367064562Sgshapiro
367164562Sgshapirostatic void
367264562Sgshapiroldapmap_setopts(ld, lmap)
367364562Sgshapiro	LDAP *ld;
367464562Sgshapiro	LDAPMAP_STRUCT *lmap;
367564562Sgshapiro{
367664562Sgshapiro# if USE_LDAP_SET_OPTION
367764562Sgshapiro	ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
367864562Sgshapiro	if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
367964562Sgshapiro		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
368038032Speter	else
368164562Sgshapiro		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
368264562Sgshapiro	ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
368364562Sgshapiro	ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
368464562Sgshapiro# else /* USE_LDAP_SET_OPTION */
368564562Sgshapiro	/* From here on in we can use ldap internal timelimits */
368664562Sgshapiro	ld->ld_deref = lmap->ldap_deref;
368764562Sgshapiro	ld->ld_options = lmap->ldap_options;
368864562Sgshapiro	ld->ld_sizelimit = lmap->ldap_sizelimit;
368964562Sgshapiro	ld->ld_timelimit = lmap->ldap_timelimit;
369064562Sgshapiro# endif /* USE_LDAP_SET_OPTION */
369138032Speter}
369264562Sgshapiro/*
369364562Sgshapiro**  LDAPMAP_GETERRNO -- get ldap errno value
369464562Sgshapiro**
369564562Sgshapiro**	Parameters:
369664562Sgshapiro**		ld -- LDAP session handle
369764562Sgshapiro**
369864562Sgshapiro**	Returns:
369964562Sgshapiro**		LDAP errno.
370064562Sgshapiro**
370164562Sgshapiro*/
370238032Speter
370364562Sgshapirostatic int
370464562Sgshapiroldapmap_geterrno(ld)
370564562Sgshapiro	LDAP *ld;
370664562Sgshapiro{
370764562Sgshapiro	int err = LDAP_SUCCESS;
370864562Sgshapiro
370964562Sgshapiro# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
371064562Sgshapiro	(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
371164562Sgshapiro# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
371264562Sgshapiro#  ifdef LDAP_OPT_SIZELIMIT
371364562Sgshapiro	err = ldap_get_lderrno(ld, NULL, NULL);
371464562Sgshapiro#  else /* LDAP_OPT_SIZELIMIT */
371564562Sgshapiro	err = ld->ld_errno;
371664562Sgshapiro
371764562Sgshapiro	/*
371864562Sgshapiro	**  Reset value to prevent lingering LDAP_DECODING_ERROR due to
371964562Sgshapiro	**  OpenLDAP 1.X's hack (see above)
372064562Sgshapiro	*/
372164562Sgshapiro
372264562Sgshapiro	ld->ld_errno = LDAP_SUCCESS;
372364562Sgshapiro#  endif /* LDAP_OPT_SIZELIMIT */
372464562Sgshapiro# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
372564562Sgshapiro	return err;
372664562Sgshapiro}
372764562Sgshapiro
372838032Speter/*
372964562Sgshapiro**  LDAPX_MAP_PARSEARGS -- print warning about use of ldapx map.
373038032Speter*/
373138032Speter
373238032Speterbool
373364562Sgshapiroldapx_map_parseargs(map, args)
373438032Speter	MAP *map;
373538032Speter	char *args;
373638032Speter{
373764562Sgshapiro	printf("Warning: The \"ldapx\" map class is deprecated and will be removed in a future\n");
373864562Sgshapiro	printf("         version.  Use the \"ldap\" map class instead for map \"%s\".\n",
373964562Sgshapiro	       map->map_mname);
374064562Sgshapiro	return ldapmap_parseargs(map, args);
374164562Sgshapiro}
374238032Speter
374364562Sgshapiro/*
374464562Sgshapiro**  LDAPMAP_PARSEARGS -- parse ldap map definition args.
374564562Sgshapiro*/
374638032Speter
374764562Sgshapirostruct lamvalues LDAPAuthMethods[] =
374864562Sgshapiro{
374964562Sgshapiro	{	"none",		LDAP_AUTH_NONE		},
375064562Sgshapiro	{	"simple",	LDAP_AUTH_SIMPLE	},
375164562Sgshapiro# ifdef LDAP_AUTH_KRBV4
375264562Sgshapiro	{	"krbv4",	LDAP_AUTH_KRBV4		},
375364562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
375464562Sgshapiro	{	NULL,		0			}
375564562Sgshapiro};
375638032Speter
375764562Sgshapirostruct ladvalues LDAPAliasDereference[] =
375864562Sgshapiro{
375964562Sgshapiro	{	"never",	LDAP_DEREF_NEVER	},
376064562Sgshapiro	{	"always",	LDAP_DEREF_ALWAYS	},
376164562Sgshapiro	{	"search",	LDAP_DEREF_SEARCHING	},
376264562Sgshapiro	{	"find",		LDAP_DEREF_FINDING	},
376364562Sgshapiro	{	NULL,		0			}
376464562Sgshapiro};
376538032Speter
376664562Sgshapirostruct lssvalues LDAPSearchScope[] =
376764562Sgshapiro{
376864562Sgshapiro	{	"base",		LDAP_SCOPE_BASE		},
376964562Sgshapiro	{	"one",		LDAP_SCOPE_ONELEVEL	},
377064562Sgshapiro	{	"sub",		LDAP_SCOPE_SUBTREE	},
377164562Sgshapiro	{	NULL,		0			}
377264562Sgshapiro};
377338032Speter
377464562Sgshapirobool
377564562Sgshapiroldapmap_parseargs(map, args)
377664562Sgshapiro	MAP *map;
377764562Sgshapiro	char *args;
377864562Sgshapiro{
377964562Sgshapiro	bool secretread = TRUE;
378064562Sgshapiro	int i;
378164562Sgshapiro	register char *p = args;
378264562Sgshapiro	LDAPMAP_STRUCT *lmap;
378364562Sgshapiro	struct lamvalues *lam;
378464562Sgshapiro	struct ladvalues *lad;
378564562Sgshapiro	struct lssvalues *lss;
378664562Sgshapiro	char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
378764562Sgshapiro
378864562Sgshapiro	/* Get ldap struct pointer from map */
378964562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
379064562Sgshapiro
379164562Sgshapiro	/* Check if setting the initial LDAP defaults */
379264562Sgshapiro	if (lmap == NULL || lmap != LDAPDefaults)
379364562Sgshapiro	{
379464562Sgshapiro		/* We need to alloc an LDAPMAP_STRUCT struct */
379564562Sgshapiro		lmap = (LDAPMAP_STRUCT *) xalloc(sizeof *lmap);
379664562Sgshapiro		if (LDAPDefaults == NULL)
379764562Sgshapiro			ldapmap_clear(lmap);
379864562Sgshapiro		else
379964562Sgshapiro			STRUCTCOPY(*LDAPDefaults, *lmap);
380064562Sgshapiro	}
380164562Sgshapiro
380264562Sgshapiro	/* there is no check whether there is really an argument */
380364562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
380464562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
380538032Speter	for (;;)
380638032Speter	{
380738032Speter		while (isascii(*p) && isspace(*p))
380838032Speter			p++;
380938032Speter		if (*p != '-')
381038032Speter			break;
381138032Speter		switch (*++p)
381238032Speter		{
381338032Speter		  case 'N':
381438032Speter			map->map_mflags |= MF_INCLNULL;
381538032Speter			map->map_mflags &= ~MF_TRY0NULL;
381638032Speter			break;
381738032Speter
381838032Speter		  case 'O':
381938032Speter			map->map_mflags &= ~MF_TRY1NULL;
382038032Speter			break;
382138032Speter
382238032Speter		  case 'o':
382338032Speter			map->map_mflags |= MF_OPTIONAL;
382438032Speter			break;
382538032Speter
382638032Speter		  case 'f':
382738032Speter			map->map_mflags |= MF_NOFOLDCASE;
382838032Speter			break;
382938032Speter
383038032Speter		  case 'm':
383138032Speter			map->map_mflags |= MF_MATCHONLY;
383238032Speter			break;
383338032Speter
383438032Speter		  case 'A':
383538032Speter			map->map_mflags |= MF_APPEND;
383638032Speter			break;
383738032Speter
383838032Speter		  case 'q':
383938032Speter			map->map_mflags |= MF_KEEPQUOTES;
384038032Speter			break;
384138032Speter
384238032Speter		  case 'a':
384338032Speter			map->map_app = ++p;
384438032Speter			break;
384538032Speter
384638032Speter		  case 'T':
384738032Speter			map->map_tapp = ++p;
384838032Speter			break;
384938032Speter
385064562Sgshapiro		  case 't':
385164562Sgshapiro			map->map_mflags |= MF_NODEFER;
385264562Sgshapiro			break;
385364562Sgshapiro
385464562Sgshapiro		  case 'S':
385564562Sgshapiro			map->map_spacesub = *++p;
385664562Sgshapiro			break;
385764562Sgshapiro
385864562Sgshapiro		  case 'D':
385964562Sgshapiro			map->map_mflags |= MF_DEFER;
386064562Sgshapiro			break;
386164562Sgshapiro
386264562Sgshapiro		  case 'z':
386364562Sgshapiro			if (*++p != '\\')
386464562Sgshapiro				map->map_coldelim = *p;
386564562Sgshapiro			else
386664562Sgshapiro			{
386764562Sgshapiro				switch (*++p)
386864562Sgshapiro				{
386964562Sgshapiro				  case 'n':
387064562Sgshapiro					map->map_coldelim = '\n';
387164562Sgshapiro					break;
387264562Sgshapiro
387364562Sgshapiro				  case 't':
387464562Sgshapiro					map->map_coldelim = '\t';
387564562Sgshapiro					break;
387664562Sgshapiro
387764562Sgshapiro				  default:
387864562Sgshapiro					map->map_coldelim = '\\';
387964562Sgshapiro				}
388064562Sgshapiro			}
388164562Sgshapiro			break;
388264562Sgshapiro
388364562Sgshapiro			/* Start of ldapmap specific args */
388438032Speter		  case 'k':		/* search field */
388538032Speter			while (isascii(*++p) && isspace(*p))
388638032Speter				continue;
388764562Sgshapiro			lmap->ldap_filter = p;
388838032Speter			break;
388938032Speter
389038032Speter		  case 'v':		/* attr to return */
389138032Speter			while (isascii(*++p) && isspace(*p))
389238032Speter				continue;
389364562Sgshapiro			lmap->ldap_attr[0] = p;
389464562Sgshapiro			lmap->ldap_attr[1] = NULL;
389538032Speter			break;
389638032Speter
389764562Sgshapiro		  case '1':
389864562Sgshapiro			map->map_mflags |= MF_SINGLEMATCH;
389964562Sgshapiro			break;
390064562Sgshapiro
390138032Speter			/* args stolen from ldapsearch.c */
390238032Speter		  case 'R':		/* don't auto chase referrals */
390364562Sgshapiro# ifdef LDAP_REFERRALS
390438032Speter			lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
390564562Sgshapiro# else /* LDAP_REFERRALS */
390638032Speter			syserr("compile with -DLDAP_REFERRALS for referral support\n");
390764562Sgshapiro# endif /* LDAP_REFERRALS */
390838032Speter			break;
390938032Speter
391064562Sgshapiro		  case 'n':		/* retrieve attribute names only */
391164562Sgshapiro			lmap->ldap_attrsonly = LDAPMAP_TRUE;
391238032Speter			break;
391338032Speter
391464562Sgshapiro		  case 'r':		/* alias dereferencing */
391564562Sgshapiro			while (isascii(*++p) && isspace(*p))
391664562Sgshapiro				continue;
391764562Sgshapiro
391864562Sgshapiro			if (strncasecmp(p, "LDAP_DEREF_", 11) == 0)
391964562Sgshapiro				p += 11;
392064562Sgshapiro
392164562Sgshapiro			for (lad = LDAPAliasDereference;
392264562Sgshapiro			     lad != NULL && lad->lad_name != NULL; lad++)
392338032Speter			{
392464562Sgshapiro				if (strncasecmp(p, lad->lad_name,
392564562Sgshapiro						strlen(lad->lad_name)) == 0)
392664562Sgshapiro					break;
392738032Speter			}
392864562Sgshapiro			if (lad->lad_name != NULL)
392964562Sgshapiro				lmap->ldap_deref = lad->lad_code;
393064562Sgshapiro			else
393138032Speter			{
393264562Sgshapiro				/* bad config line */
393364562Sgshapiro				if (!bitset(MCF_OPTFILE,
393464562Sgshapiro					    map->map_class->map_cflags))
393564562Sgshapiro				{
393664562Sgshapiro					char *ptr;
393764562Sgshapiro
393864562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
393964562Sgshapiro						*ptr = '\0';
394064562Sgshapiro					syserr("Deref must be [never|always|search|find] not %s in map %s",
394164562Sgshapiro						p, map->map_mname);
394264562Sgshapiro					if (ptr != NULL)
394364562Sgshapiro						*ptr = ' ';
394464562Sgshapiro					return FALSE;
394564562Sgshapiro				}
394638032Speter			}
394764562Sgshapiro			break;
394864562Sgshapiro
394964562Sgshapiro		  case 's':		/* search scope */
395064562Sgshapiro			while (isascii(*++p) && isspace(*p))
395164562Sgshapiro				continue;
395264562Sgshapiro
395364562Sgshapiro			if (strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
395464562Sgshapiro				p += 11;
395564562Sgshapiro
395664562Sgshapiro			for (lss = LDAPSearchScope;
395764562Sgshapiro			     lss != NULL && lss->lss_name != NULL; lss++)
395838032Speter			{
395964562Sgshapiro				if (strncasecmp(p, lss->lss_name,
396064562Sgshapiro						strlen(lss->lss_name)) == 0)
396164562Sgshapiro					break;
396238032Speter			}
396364562Sgshapiro			if (lss->lss_name != NULL)
396464562Sgshapiro				lmap->ldap_scope = lss->lss_code;
396538032Speter			else
396664562Sgshapiro			{
396764562Sgshapiro				/* bad config line */
396864562Sgshapiro				if (!bitset(MCF_OPTFILE,
396964562Sgshapiro					    map->map_class->map_cflags))
397038032Speter				{
397138032Speter					char *ptr;
397238032Speter
397338032Speter					if ((ptr = strchr(p, ' ')) != NULL)
397438032Speter						*ptr = '\0';
397538032Speter					syserr("Scope must be [base|one|sub] not %s in map %s",
397638032Speter						p, map->map_mname);
397738032Speter					if (ptr != NULL)
397838032Speter						*ptr = ' ';
397938032Speter					return FALSE;
398038032Speter				}
398138032Speter			}
398238032Speter			break;
398338032Speter
398438032Speter		  case 'h':		/* ldap host */
398538032Speter			while (isascii(*++p) && isspace(*p))
398638032Speter				continue;
398764562Sgshapiro			lmap->ldap_host = p;
398838032Speter			break;
398938032Speter
399038032Speter		  case 'b':		/* search base */
399138032Speter			while (isascii(*++p) && isspace(*p))
399238032Speter				continue;
399364562Sgshapiro			lmap->ldap_base = p;
399438032Speter			break;
399538032Speter
399638032Speter		  case 'p':		/* ldap port */
399738032Speter			while (isascii(*++p) && isspace(*p))
399838032Speter				continue;
399964562Sgshapiro			lmap->ldap_port = atoi(p);
400038032Speter			break;
400138032Speter
400238032Speter		  case 'l':		/* time limit */
400338032Speter			while (isascii(*++p) && isspace(*p))
400438032Speter				continue;
400564562Sgshapiro			lmap->ldap_timelimit = atoi(p);
400664562Sgshapiro			lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit;
400738032Speter			break;
400838032Speter
400964562Sgshapiro		  case 'Z':
401064562Sgshapiro			while (isascii(*++p) && isspace(*p))
401164562Sgshapiro				continue;
401264562Sgshapiro			lmap->ldap_sizelimit = atoi(p);
401364562Sgshapiro			break;
401464562Sgshapiro
401564562Sgshapiro		  case 'd':		/* Dn to bind to server as */
401664562Sgshapiro			while (isascii(*++p) && isspace(*p))
401764562Sgshapiro				continue;
401864562Sgshapiro			lmap->ldap_binddn = p;
401964562Sgshapiro			break;
402064562Sgshapiro
402164562Sgshapiro		  case 'M':		/* Method for binding */
402264562Sgshapiro			while (isascii(*++p) && isspace(*p))
402364562Sgshapiro				continue;
402464562Sgshapiro
402564562Sgshapiro			if (strncasecmp(p, "LDAP_AUTH_", 10) == 0)
402664562Sgshapiro				p += 10;
402764562Sgshapiro
402864562Sgshapiro			for (lam = LDAPAuthMethods;
402964562Sgshapiro			     lam != NULL && lam->lam_name != NULL; lam++)
403064562Sgshapiro			{
403164562Sgshapiro				if (strncasecmp(p, lam->lam_name,
403264562Sgshapiro						strlen(lam->lam_name)) == 0)
403364562Sgshapiro					break;
403464562Sgshapiro			}
403564562Sgshapiro			if (lam->lam_name != NULL)
403664562Sgshapiro				lmap->ldap_method = lam->lam_code;
403764562Sgshapiro			else
403864562Sgshapiro			{
403964562Sgshapiro				/* bad config line */
404064562Sgshapiro				if (!bitset(MCF_OPTFILE,
404164562Sgshapiro					    map->map_class->map_cflags))
404264562Sgshapiro				{
404364562Sgshapiro					char *ptr;
404464562Sgshapiro
404564562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
404664562Sgshapiro						*ptr = '\0';
404764562Sgshapiro					syserr("Method for binding must be [none|simple|krbv4] not %s in map %s",
404864562Sgshapiro						p, map->map_mname);
404964562Sgshapiro					if (ptr != NULL)
405064562Sgshapiro						*ptr = ' ';
405164562Sgshapiro					return FALSE;
405264562Sgshapiro				}
405364562Sgshapiro			}
405464562Sgshapiro
405564562Sgshapiro			break;
405664562Sgshapiro
405764562Sgshapiro			/*
405864562Sgshapiro			**  This is a string that is dependent on the
405964562Sgshapiro			**  method used defined above.
406064562Sgshapiro			*/
406164562Sgshapiro
406264562Sgshapiro		  case 'P':		/* Secret password for binding */
406364562Sgshapiro			 while (isascii(*++p) && isspace(*p))
406464562Sgshapiro				continue;
406564562Sgshapiro			lmap->ldap_secret = p;
406664562Sgshapiro			secretread = FALSE;
406764562Sgshapiro			break;
406864562Sgshapiro
406964562Sgshapiro		  default:
407064562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
407164562Sgshapiro			break;
407238032Speter		}
407338032Speter
407464562Sgshapiro		/* need to account for quoted strings here */
407564562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
407638032Speter		{
407738032Speter			if (*p == '"')
407838032Speter			{
407938032Speter				while (*++p != '"' && *p != '\0')
408038032Speter					continue;
408138032Speter				if (*p != '\0')
408238032Speter					p++;
408338032Speter			}
408438032Speter			else
408538032Speter				p++;
408638032Speter		}
408738032Speter
408838032Speter		if (*p != '\0')
408938032Speter			*p++ = '\0';
409038032Speter	}
409138032Speter
409238032Speter	if (map->map_app != NULL)
409364562Sgshapiro		map->map_app = newstr(ldapmap_dequote(map->map_app));
409438032Speter	if (map->map_tapp != NULL)
409564562Sgshapiro		map->map_tapp = newstr(ldapmap_dequote(map->map_tapp));
409638032Speter
409738032Speter	/*
409842575Speter	**  We need to swallow up all the stuff into a struct
409942575Speter	**  and dump it into map->map_dbptr1
410038032Speter	*/
410138032Speter
410264562Sgshapiro	if (lmap->ldap_host != NULL &&
410364562Sgshapiro	    (LDAPDefaults == NULL ||
410464562Sgshapiro	     LDAPDefaults == lmap ||
410564562Sgshapiro	     LDAPDefaults->ldap_host != lmap->ldap_host))
410664562Sgshapiro		lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host));
410764562Sgshapiro	map->map_domain = lmap->ldap_host;
410864562Sgshapiro
410964562Sgshapiro	if (lmap->ldap_binddn != NULL &&
411064562Sgshapiro	    (LDAPDefaults == NULL ||
411164562Sgshapiro	     LDAPDefaults == lmap ||
411264562Sgshapiro	     LDAPDefaults->ldap_binddn != lmap->ldap_binddn))
411364562Sgshapiro		lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn));
411464562Sgshapiro
411564562Sgshapiro	if (lmap->ldap_secret != NULL &&
411664562Sgshapiro	    (LDAPDefaults == NULL ||
411764562Sgshapiro	     LDAPDefaults == lmap ||
411864562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
411938032Speter	{
412064562Sgshapiro		FILE *sfd;
412164562Sgshapiro		long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
412238032Speter
412364562Sgshapiro		if (DontLockReadFiles)
412464562Sgshapiro			sff |= SFF_NOLOCK;
412538032Speter
412664562Sgshapiro		/* need to use method to map secret to passwd string */
412764562Sgshapiro		switch (lmap->ldap_method)
412864562Sgshapiro		{
412964562Sgshapiro		  case LDAP_AUTH_NONE:
413064562Sgshapiro			/* Do nothing */
413164562Sgshapiro			break;
413238032Speter
413364562Sgshapiro		  case LDAP_AUTH_SIMPLE:
413438032Speter
413564562Sgshapiro			/*
413664562Sgshapiro			**  Secret is the name of a file with
413764562Sgshapiro			**  the first line as the password.
413864562Sgshapiro			*/
413964562Sgshapiro
414064562Sgshapiro			/* Already read in the secret? */
414164562Sgshapiro			if (secretread)
414264562Sgshapiro				break;
414364562Sgshapiro
414464562Sgshapiro			sfd = safefopen(ldapmap_dequote(lmap->ldap_secret),
414564562Sgshapiro					O_RDONLY, 0, sff);
414664562Sgshapiro			if (sfd == NULL)
414764562Sgshapiro			{
414864562Sgshapiro				syserr("LDAP map: cannot open secret %s",
414964562Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
415064562Sgshapiro				return FALSE;
415164562Sgshapiro			}
415264562Sgshapiro			lmap->ldap_secret = sfgets(m_tmp, LDAPMAP_MAX_PASSWD,
415366494Sgshapiro						   sfd, TimeOuts.to_fileopen,
415466494Sgshapiro						   "ldapmap_parseargs");
415564562Sgshapiro			(void) fclose(sfd);
415664562Sgshapiro			if (lmap->ldap_secret != NULL &&
415764562Sgshapiro			    strlen(m_tmp) > 0)
415864562Sgshapiro			{
415964562Sgshapiro				/* chomp newline */
416064562Sgshapiro				if (m_tmp[strlen(m_tmp) - 1] == '\n')
416164562Sgshapiro					m_tmp[strlen(m_tmp) - 1] = '\0';
416264562Sgshapiro
416364562Sgshapiro				lmap->ldap_secret = m_tmp;
416464562Sgshapiro			}
416564562Sgshapiro			break;
416664562Sgshapiro
416764562Sgshapiro# ifdef LDAP_AUTH_KRBV4
416864562Sgshapiro		  case LDAP_AUTH_KRBV4:
416964562Sgshapiro
417064562Sgshapiro			/*
417164562Sgshapiro			**  Secret is where the ticket file is
417264562Sgshapiro			**  stashed
417364562Sgshapiro			*/
417464562Sgshapiro
417564562Sgshapiro			snprintf(m_tmp, MAXPATHLEN + LDAPMAP_MAX_PASSWD,
417664562Sgshapiro				 "KRBTKFILE=%s",
417764562Sgshapiro				 ldapmap_dequote(lmap->ldap_secret));
417864562Sgshapiro			lmap->ldap_secret = m_tmp;
417964562Sgshapiro			break;
418064562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
418164562Sgshapiro
418264562Sgshapiro		  default:	       /* Should NEVER get here */
418364562Sgshapiro			syserr("LDAP map: Illegal value in lmap method");
418464562Sgshapiro			return FALSE;
418564562Sgshapiro			break;
418664562Sgshapiro		}
418738032Speter	}
418838032Speter
418964562Sgshapiro	if (lmap->ldap_secret != NULL &&
419064562Sgshapiro	    (LDAPDefaults == NULL ||
419164562Sgshapiro	     LDAPDefaults == lmap ||
419264562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
419364562Sgshapiro		lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret));
419438032Speter
419564562Sgshapiro	if (lmap->ldap_base != NULL &&
419664562Sgshapiro	    (LDAPDefaults == NULL ||
419764562Sgshapiro	     LDAPDefaults == lmap ||
419864562Sgshapiro	     LDAPDefaults->ldap_base != lmap->ldap_base))
419964562Sgshapiro		lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base));
420064562Sgshapiro
420164562Sgshapiro	/*
420264562Sgshapiro	**  Save the server from extra work.  If request is for a single
420364562Sgshapiro	**  match, tell the server to only return enough records to
420464562Sgshapiro	**  determine if there is a single match or not.  This can not
420564562Sgshapiro	**  be one since the server would only return one and we wouldn't
420664562Sgshapiro	**  know if there were others available.
420764562Sgshapiro	*/
420864562Sgshapiro
420964562Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
421064562Sgshapiro		lmap->ldap_sizelimit = 2;
421164562Sgshapiro
421264562Sgshapiro	/* If setting defaults, don't process ldap_filter and ldap_attr */
421364562Sgshapiro	if (lmap == LDAPDefaults)
421464562Sgshapiro		return TRUE;
421564562Sgshapiro
421664562Sgshapiro	if (lmap->ldap_filter != NULL)
421764562Sgshapiro		lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
421838032Speter	else
421938032Speter	{
422038032Speter		if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
422138032Speter		{
422238032Speter			syserr("No filter given in map %s", map->map_mname);
422338032Speter			return FALSE;
422438032Speter		}
422538032Speter	}
422664562Sgshapiro
422764562Sgshapiro	if (lmap->ldap_attr[0] != NULL)
422838032Speter	{
422964562Sgshapiro		i = 0;
423064562Sgshapiro		p = ldapmap_dequote(lmap->ldap_attr[0]);
423164562Sgshapiro		lmap->ldap_attr[0] = NULL;
423264562Sgshapiro
423364562Sgshapiro		while (p != NULL)
423438032Speter		{
423564562Sgshapiro			char *v;
423664562Sgshapiro
423764562Sgshapiro			while (isascii(*p) && isspace(*p))
423864562Sgshapiro				p++;
423964562Sgshapiro			if (*p == '\0')
424064562Sgshapiro				break;
424164562Sgshapiro			v = p;
424264562Sgshapiro			p = strchr(v, ',');
424364562Sgshapiro			if (p != NULL)
424464562Sgshapiro				*p++ = '\0';
424564562Sgshapiro
424671345Sgshapiro			if (i >= LDAPMAP_MAX_ATTR)
424764562Sgshapiro			{
424864562Sgshapiro				syserr("Too many return attributes in %s (max %d)",
424964562Sgshapiro				       map->map_mname, LDAPMAP_MAX_ATTR);
425064562Sgshapiro				return FALSE;
425164562Sgshapiro			}
425264562Sgshapiro			if (*v != '\0')
425364562Sgshapiro				lmap->ldap_attr[i++] = newstr(v);
425438032Speter		}
425564562Sgshapiro		lmap->ldap_attr[i] = NULL;
425638032Speter	}
425738032Speter
425838032Speter	map->map_db1 = (ARBPTR_T) lmap;
425938032Speter	return TRUE;
426038032Speter}
426138032Speter
426264562Sgshapiro/*
426364562Sgshapiro**  LDAPMAP_CLEAR -- set default values for LDAPMAP_STRUCT
426464562Sgshapiro**
426564562Sgshapiro**	Parameters:
426664562Sgshapiro**		lmap -- pointer to LDAPMAP_STRUCT to clear
426764562Sgshapiro**
426864562Sgshapiro**	Returns:
426964562Sgshapiro**		None.
427064562Sgshapiro**
427164562Sgshapiro*/
427264562Sgshapiro
427364562Sgshapirostatic void
427464562Sgshapiroldapmap_clear(lmap)
427564562Sgshapiro	LDAPMAP_STRUCT *lmap;
427664562Sgshapiro{
427764562Sgshapiro	lmap->ldap_host = NULL;
427864562Sgshapiro	lmap->ldap_port = LDAP_PORT;
427964562Sgshapiro	lmap->ldap_deref = LDAP_DEREF_NEVER;
428064562Sgshapiro	lmap->ldap_timelimit = LDAP_NO_LIMIT;
428164562Sgshapiro	lmap->ldap_sizelimit = LDAP_NO_LIMIT;
428264562Sgshapiro# ifdef LDAP_REFERRALS
428364562Sgshapiro	lmap->ldap_options = LDAP_OPT_REFERRALS;
428464562Sgshapiro# else /* LDAP_REFERRALS */
428564562Sgshapiro	lmap->ldap_options = 0;
428664562Sgshapiro# endif /* LDAP_REFERRALS */
428764562Sgshapiro	lmap->ldap_binddn = NULL;
428864562Sgshapiro	lmap->ldap_secret = NULL;
428964562Sgshapiro	lmap->ldap_method = LDAP_AUTH_SIMPLE;
429064562Sgshapiro	lmap->ldap_base = NULL;
429164562Sgshapiro	lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
429264562Sgshapiro	lmap->ldap_attrsonly = LDAPMAP_FALSE;
429364562Sgshapiro	lmap->ldap_timeout.tv_sec = 0;
429464562Sgshapiro	lmap->ldap_timeout.tv_usec = 0;
429564562Sgshapiro	lmap->ldap_ld = NULL;
429664562Sgshapiro	lmap->ldap_filter = NULL;
429764562Sgshapiro	lmap->ldap_attr[0] = NULL;
429864562Sgshapiro	lmap->ldap_res = NULL;
429964562Sgshapiro}
430038032Speter/*
430164562Sgshapiro**  LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
430264562Sgshapiro**
430364562Sgshapiro**	Parameters:
430464562Sgshapiro**		spec -- map argument string from LDAPDefaults option
430564562Sgshapiro**
430664562Sgshapiro**	Returns:
430764562Sgshapiro**		None.
430864562Sgshapiro**
430964562Sgshapiro*/
431064562Sgshapiro
431164562Sgshapirovoid
431264562Sgshapiroldapmap_set_defaults(spec)
431364562Sgshapiro	char *spec;
431464562Sgshapiro{
431564562Sgshapiro	MAP map;
431664562Sgshapiro
431764562Sgshapiro	/* Allocate and set the default values */
431864562Sgshapiro	if (LDAPDefaults == NULL)
431964562Sgshapiro		LDAPDefaults = (LDAPMAP_STRUCT *) xalloc(sizeof *LDAPDefaults);
432064562Sgshapiro	ldapmap_clear(LDAPDefaults);
432164562Sgshapiro
432264562Sgshapiro	memset(&map, '\0', sizeof map);
432364562Sgshapiro	map.map_db1 = (ARBPTR_T) LDAPDefaults;
432464562Sgshapiro
432564562Sgshapiro	(void) ldapmap_parseargs(&map, spec);
432664562Sgshapiro
432764562Sgshapiro	/* These should never be set in LDAPDefaults */
432864562Sgshapiro	if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) ||
432964562Sgshapiro	    map.map_spacesub != SpaceSub ||
433064562Sgshapiro	    map.map_app != NULL ||
433164562Sgshapiro	    map.map_tapp != NULL)
433264562Sgshapiro	{
433364562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
433464562Sgshapiro		if (map.map_app != NULL)
433564562Sgshapiro		{
433664562Sgshapiro			free(map.map_app);
433764562Sgshapiro			map.map_app = NULL;
433864562Sgshapiro		}
433964562Sgshapiro		if (map.map_tapp != NULL)
434064562Sgshapiro		{
434164562Sgshapiro			free(map.map_tapp);
434264562Sgshapiro			map.map_tapp = NULL;
434364562Sgshapiro		}
434464562Sgshapiro	}
434564562Sgshapiro
434664562Sgshapiro	if (LDAPDefaults->ldap_filter != NULL)
434764562Sgshapiro	{
434864562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
434964562Sgshapiro		/* don't free, it isn't malloc'ed in parseargs */
435064562Sgshapiro		LDAPDefaults->ldap_filter = NULL;
435164562Sgshapiro	}
435264562Sgshapiro
435364562Sgshapiro	if (LDAPDefaults->ldap_attr[0] != NULL)
435464562Sgshapiro	{
435564562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes");
435664562Sgshapiro		/* don't free, they aren't malloc'ed in parseargs */
435764562Sgshapiro		LDAPDefaults->ldap_attr[0] = NULL;
435864562Sgshapiro	}
435964562Sgshapiro}
436064562Sgshapiro#endif /* LDAPMAP */
436164562Sgshapiro/*
436264562Sgshapiro**  PH map
436364562Sgshapiro*/
436464562Sgshapiro
436564562Sgshapiro#ifdef PH_MAP
436664562Sgshapiro
436764562Sgshapiro/*
436864562Sgshapiro**  Support for the CCSO Nameserver (ph/qi).
436964562Sgshapiro**  This code is intended to replace the so-called "ph mailer".
437064562Sgshapiro**  Contributed by Mark D. Roth <roth@uiuc.edu>.  Contact him for support.
437164562Sgshapiro*/
437264562Sgshapiro
437364562Sgshapiro# include <qiapi.h>
437464562Sgshapiro# include <qicode.h>
437564562Sgshapiro
437664562Sgshapiro/*
437764562Sgshapiro**  PH_MAP_PARSEARGS -- parse ph map definition args.
437864562Sgshapiro*/
437964562Sgshapiro
438064562Sgshapirobool
438164562Sgshapiroph_map_parseargs(map, args)
438264562Sgshapiro	MAP *map;
438364562Sgshapiro	char *args;
438464562Sgshapiro{
438564562Sgshapiro	int i;
438664562Sgshapiro	register int done;
438764562Sgshapiro	PH_MAP_STRUCT *pmap = NULL;
438864562Sgshapiro	register char *p = args;
438964562Sgshapiro
439064562Sgshapiro	pmap = (PH_MAP_STRUCT *) xalloc(sizeof *pmap);
439164562Sgshapiro
439264562Sgshapiro	/* defaults */
439364562Sgshapiro	pmap->ph_servers = NULL;
439464562Sgshapiro	pmap->ph_field_list = NULL;
439564562Sgshapiro	pmap->ph_to_server = NULL;
439664562Sgshapiro	pmap->ph_from_server = NULL;
439764562Sgshapiro	pmap->ph_sockfd = -1;
439864562Sgshapiro	pmap->ph_timeout = 0;
439964562Sgshapiro
440064562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
440164562Sgshapiro	for (;;)
440264562Sgshapiro	{
440364562Sgshapiro		while (isascii(*p) && isspace(*p))
440464562Sgshapiro			p++;
440564562Sgshapiro		if (*p != '-')
440664562Sgshapiro			break;
440764562Sgshapiro		switch (*++p)
440864562Sgshapiro		{
440964562Sgshapiro		  case 'N':
441064562Sgshapiro			map->map_mflags |= MF_INCLNULL;
441164562Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
441264562Sgshapiro			break;
441364562Sgshapiro
441464562Sgshapiro		  case 'O':
441564562Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
441664562Sgshapiro			break;
441764562Sgshapiro
441864562Sgshapiro		  case 'o':
441964562Sgshapiro			map->map_mflags |= MF_OPTIONAL;
442064562Sgshapiro			break;
442164562Sgshapiro
442264562Sgshapiro		  case 'f':
442364562Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
442464562Sgshapiro			break;
442564562Sgshapiro
442664562Sgshapiro		  case 'm':
442764562Sgshapiro			map->map_mflags |= MF_MATCHONLY;
442864562Sgshapiro			break;
442964562Sgshapiro
443064562Sgshapiro		  case 'A':
443164562Sgshapiro			map->map_mflags |= MF_APPEND;
443264562Sgshapiro			break;
443364562Sgshapiro
443464562Sgshapiro		  case 'q':
443564562Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
443664562Sgshapiro			break;
443764562Sgshapiro
443864562Sgshapiro		  case 't':
443964562Sgshapiro			map->map_mflags |= MF_NODEFER;
444064562Sgshapiro			break;
444164562Sgshapiro
444264562Sgshapiro		  case 'a':
444364562Sgshapiro			map->map_app = ++p;
444464562Sgshapiro			break;
444564562Sgshapiro
444664562Sgshapiro		  case 'T':
444764562Sgshapiro			map->map_tapp = ++p;
444864562Sgshapiro			break;
444964562Sgshapiro
445064562Sgshapiro#if _FFR_PHMAP_TIMEOUT
445164562Sgshapiro		  case 'l':
445264562Sgshapiro			while (isascii(*++p) && isspace(*p))
445364562Sgshapiro				continue;
445464562Sgshapiro			pmap->ph_timeout = atoi(p);
445564562Sgshapiro			break;
445664562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
445764562Sgshapiro
445864562Sgshapiro		  case 'S':
445964562Sgshapiro			map->map_spacesub = *++p;
446064562Sgshapiro			break;
446164562Sgshapiro
446264562Sgshapiro		  case 'D':
446364562Sgshapiro			map->map_mflags |= MF_DEFER;
446464562Sgshapiro			break;
446564562Sgshapiro
446664562Sgshapiro		  case 'h':		/* PH server list */
446764562Sgshapiro			while (isascii(*++p) && isspace(*p))
446864562Sgshapiro				continue;
446964562Sgshapiro			pmap->ph_servers = p;
447064562Sgshapiro			break;
447164562Sgshapiro
447264562Sgshapiro		  case 'v':		/* fields to search for */
447364562Sgshapiro			while (isascii(*++p) && isspace(*p))
447464562Sgshapiro				continue;
447564562Sgshapiro			pmap->ph_field_list = p;
447664562Sgshapiro			break;
447764562Sgshapiro
447864562Sgshapiro		  default:
447964562Sgshapiro			syserr("ph_map_parseargs: unknown option -%c\n", *p);
448064562Sgshapiro		}
448164562Sgshapiro
448264562Sgshapiro		/* try to account for quoted strings */
448364562Sgshapiro		done = isascii(*p) && isspace(*p);
448464562Sgshapiro		while (*p != '\0' && !done)
448564562Sgshapiro		{
448664562Sgshapiro			if (*p == '"')
448764562Sgshapiro			{
448864562Sgshapiro				while (*++p != '"' && *p != '\0')
448964562Sgshapiro					continue;
449064562Sgshapiro				if (*p != '\0')
449164562Sgshapiro					p++;
449264562Sgshapiro			}
449364562Sgshapiro			else
449464562Sgshapiro				p++;
449564562Sgshapiro			done = isascii(*p) && isspace(*p);
449664562Sgshapiro		}
449764562Sgshapiro
449864562Sgshapiro		if (*p != '\0')
449964562Sgshapiro			*p++ = '\0';
450064562Sgshapiro	}
450164562Sgshapiro
450264562Sgshapiro	if (map->map_app != NULL)
450364562Sgshapiro		map->map_app = newstr(ph_map_dequote(map->map_app));
450464562Sgshapiro	if (map->map_tapp != NULL)
450564562Sgshapiro		map->map_tapp = newstr(ph_map_dequote(map->map_tapp));
450664562Sgshapiro
450764562Sgshapiro	if (pmap->ph_field_list != NULL)
450864562Sgshapiro		pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
450964562Sgshapiro	else
451064562Sgshapiro		pmap->ph_field_list = DEFAULT_PH_MAP_FIELDS;
451164562Sgshapiro
451264562Sgshapiro	if (pmap->ph_servers != NULL)
451364562Sgshapiro		pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
451464562Sgshapiro	else
451564562Sgshapiro	{
451664562Sgshapiro		syserr("ph_map_parseargs: -h flag is required");
451764562Sgshapiro		return FALSE;
451864562Sgshapiro	}
451964562Sgshapiro
452064562Sgshapiro	map->map_db1 = (ARBPTR_T) pmap;
452164562Sgshapiro	return TRUE;
452264562Sgshapiro}
452364562Sgshapiro
452464562Sgshapiro#if _FFR_PHMAP_TIMEOUT
452564562Sgshapiro/*
452664562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
452764562Sgshapiro*/
452864562Sgshapiro
452964562Sgshapirostatic void
453064562Sgshapiroph_map_safeclose(map)
453164562Sgshapiro	MAP *map;
453264562Sgshapiro{
453364562Sgshapiro	int save_errno = errno;
453464562Sgshapiro	PH_MAP_STRUCT *pmap;
453564562Sgshapiro
453664562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
453764562Sgshapiro
453864562Sgshapiro	if (pmap->ph_sockfd != -1)
453964562Sgshapiro	{
454064562Sgshapiro		(void) close(pmap->ph_sockfd);
454164562Sgshapiro		pmap->ph_sockfd = -1;
454264562Sgshapiro	}
454364562Sgshapiro	if (pmap->ph_from_server != NULL)
454464562Sgshapiro	{
454564562Sgshapiro		(void) fclose(pmap->ph_from_server);
454664562Sgshapiro		pmap->ph_from_server = NULL;
454764562Sgshapiro	}
454864562Sgshapiro	if (pmap->ph_to_server != NULL)
454964562Sgshapiro	{
455064562Sgshapiro		(void) fclose(pmap->ph_to_server);
455164562Sgshapiro		pmap->ph_to_server = NULL;
455264562Sgshapiro	}
455364562Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
455464562Sgshapiro	errno = save_errno;
455564562Sgshapiro}
455664562Sgshapiro
455764562Sgshapirovoid
455864562Sgshapiroph_map_close(map)
455964562Sgshapiro	MAP *map;
456064562Sgshapiro{
456164562Sgshapiro	PH_MAP_STRUCT *pmap;
456264562Sgshapiro
456364562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
456464562Sgshapiro	(void) fprintf(pmap->ph_to_server, "quit\n");
456564562Sgshapiro	(void) fflush(pmap->ph_to_server);
456664562Sgshapiro	ph_map_safeclose(map);
456764562Sgshapiro}
456864562Sgshapiro
456964562Sgshapirostatic jmp_buf  PHTimeout;
457064562Sgshapiro
457164562Sgshapiro/* ARGSUSED */
457264562Sgshapirostatic void
457364562Sgshapiroph_timeout_func(sig_no)
457464562Sgshapiro	int sig_no;
457564562Sgshapiro{
457664562Sgshapiro	longjmp(PHTimeout, 1);
457764562Sgshapiro}
457864562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
457964562Sgshapiro/*
458064562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
458164562Sgshapiro*/
458264562Sgshapiro
458364562Sgshapirovoid
458464562Sgshapiroph_map_close(map)
458564562Sgshapiro	MAP *map;
458664562Sgshapiro{
458764562Sgshapiro	PH_MAP_STRUCT *pmap;
458864562Sgshapiro
458964562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
459064562Sgshapiro	CloseQi(pmap->ph_to_server, pmap->ph_from_server);
459164562Sgshapiro	pmap->ph_to_server = NULL;
459264562Sgshapiro	pmap->ph_from_server = NULL;
459364562Sgshapiro}
459464562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
459564562Sgshapiro
459664562Sgshapiro/*
459764562Sgshapiro**  PH_MAP_OPEN -- sub for opening PH map
459864562Sgshapiro*/
459964562Sgshapirobool
460064562Sgshapiroph_map_open(map, mode)
460164562Sgshapiro	MAP *map;
460264562Sgshapiro	int mode;
460364562Sgshapiro{
460464562Sgshapiro#if !_FFR_PHMAP_TIMEOUT
460564562Sgshapiro	int save_errno = 0;
460664562Sgshapiro#endif /* !_FFR_PHMAP_TIMEOUT */
460764562Sgshapiro	int j;
460864562Sgshapiro	char *hostlist, *tmp;
460964562Sgshapiro	QIR *server_data = NULL;
461064562Sgshapiro	PH_MAP_STRUCT *pmap;
461164562Sgshapiro#if _FFR_PHMAP_TIMEOUT
461264562Sgshapiro	register EVENT *ev = NULL;
461364562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
461464562Sgshapiro
461564562Sgshapiro	if (tTd(38, 2))
461664562Sgshapiro		dprintf("ph_map_open(%s)\n", map->map_mname);
461764562Sgshapiro
461864562Sgshapiro	mode &= O_ACCMODE;
461964562Sgshapiro	if (mode != O_RDONLY)
462064562Sgshapiro	{
462164562Sgshapiro		/* issue a pseudo-error message */
462264562Sgshapiro# ifdef ENOSYS
462364562Sgshapiro		errno = ENOSYS;
462464562Sgshapiro# else /* ENOSYS */
462564562Sgshapiro#  ifdef EFTYPE
462664562Sgshapiro		errno = EFTYPE;
462764562Sgshapiro#  else /* EFTYPE */
462864562Sgshapiro		errno = ENXIO;
462964562Sgshapiro#  endif /* EFTYPE */
463064562Sgshapiro# endif /* ENOSYS */
463164562Sgshapiro		return FALSE;
463264562Sgshapiro	}
463364562Sgshapiro
463466494Sgshapiro	if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER &&
463566494Sgshapiro	    bitset(MF_DEFER, map->map_mflags))
463666494Sgshapiro	{
463766494Sgshapiro		if (tTd(9, 1))
463866494Sgshapiro			dprintf("ph_map_open(%s) => DEFERRED\n",
463971345Sgshapiro				map->map_mname);
464066494Sgshapiro
464166494Sgshapiro		/*
464266494Sgshapiro		** Unset MF_DEFER here so that map_lookup() returns
464366494Sgshapiro		** a temporary failure using the bogus map and
464466494Sgshapiro		** map->map_tapp instead of the default permanent error.
464566494Sgshapiro		*/
464666494Sgshapiro
464766494Sgshapiro		map->map_mflags &= ~MF_DEFER;
464866494Sgshapiro		return FALSE;
464966494Sgshapiro	}
465066494Sgshapiro
465164562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
465264562Sgshapiro
465364562Sgshapiro	hostlist = newstr(pmap->ph_servers);
465464562Sgshapiro	tmp = strtok(hostlist, " ");
465564562Sgshapiro	do
465664562Sgshapiro	{
465764562Sgshapiro#if _FFR_PHMAP_TIMEOUT
465864562Sgshapiro		if (pmap->ph_timeout != 0)
465964562Sgshapiro		{
466064562Sgshapiro			if (setjmp(PHTimeout) != 0)
466164562Sgshapiro			{
466264562Sgshapiro				ev = NULL;
466364562Sgshapiro				if (LogLevel > 1)
466464562Sgshapiro					sm_syslog(LOG_NOTICE, CurEnv->e_id,
466564562Sgshapiro						  "timeout connecting to PH server %.100s",
466664562Sgshapiro						  tmp);
466764562Sgshapiro# ifdef ETIMEDOUT
466864562Sgshapiro				errno = ETIMEDOUT;
466964562Sgshapiro# else /* ETIMEDOUT */
467066494Sgshapiro				errno = EAGAIN;
467164562Sgshapiro# endif /* ETIMEDOUT */
467264562Sgshapiro				goto ph_map_open_abort;
467364562Sgshapiro			}
467464562Sgshapiro			ev = setevent(pmap->ph_timeout, ph_timeout_func, 0);
467564562Sgshapiro		}
467664562Sgshapiro		if (!OpenQiSock(tmp, &(pmap->ph_sockfd)) &&
467764562Sgshapiro		    !Sock2FILEs(pmap->ph_sockfd, &(pmap->ph_to_server),
467864562Sgshapiro				&(pmap->ph_from_server)) &&
467964562Sgshapiro		    fprintf(pmap->ph_to_server, "id sendmail+phmap\n") >= 0 &&
468064562Sgshapiro		    fflush(pmap->ph_to_server) == 0 &&
468164562Sgshapiro		    (server_data = ReadQi(pmap->ph_from_server, &j)) != NULL &&
468264562Sgshapiro		    server_data->code == 200)
468364562Sgshapiro		{
468464562Sgshapiro			if (ev != NULL)
468564562Sgshapiro				clrevent(ev);
468664562Sgshapiro			FreeQIR(server_data);
468764562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
468864562Sgshapiro		if (OpenQi(tmp, &(pmap->ph_to_server),
468964562Sgshapiro			   &(pmap->ph_from_server)) >= 0)
469064562Sgshapiro		{
469164562Sgshapiro			if (fprintf(pmap->ph_to_server,
469264562Sgshapiro				    "id sendmail+phmap\n") < 0 ||
469364562Sgshapiro			    fflush(pmap->ph_to_server) < 0 ||
469464562Sgshapiro			    (server_data = ReadQi(pmap->ph_from_server,
469564562Sgshapiro						  &j)) == NULL ||
469664562Sgshapiro			    server_data->code != 200)
469764562Sgshapiro			{
469864562Sgshapiro				save_errno = errno;
469964562Sgshapiro				CloseQi(pmap->ph_to_server,
470064562Sgshapiro					pmap->ph_from_server);
470164562Sgshapiro				continue;
470264562Sgshapiro			}
470364562Sgshapiro			if (server_data != NULL)
470464562Sgshapiro				FreeQIR(server_data);
470564562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
470664562Sgshapiro			free(hostlist);
470764562Sgshapiro			return TRUE;
470864562Sgshapiro		}
470964562Sgshapiro#if _FFR_PHMAP_TIMEOUT
471064562Sgshapiro  ph_map_open_abort:
471164562Sgshapiro		if (ev != NULL)
471264562Sgshapiro			clrevent(ev);
471364562Sgshapiro		ph_map_safeclose(map);
471464562Sgshapiro		if (server_data != NULL)
471564562Sgshapiro		{
471664562Sgshapiro			FreeQIR(server_data);
471764562Sgshapiro			server_data = NULL;
471864562Sgshapiro		}
471964562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
472064562Sgshapiro		save_errno = errno;
472164562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
472264562Sgshapiro	} while (tmp = strtok(NULL, " "));
472364562Sgshapiro
472464562Sgshapiro#if !_FFR_PHMAP_TIMEOUT
472564562Sgshapiro	errno = save_errno;
472664562Sgshapiro#endif /* !_FFR_PHMAP_TIMEOUT */
472766494Sgshapiro	if (bitset(MF_NODEFER, map->map_mflags))
472864562Sgshapiro	{
472966494Sgshapiro		if (errno == 0)
473064562Sgshapiro			errno = EAGAIN;
473166494Sgshapiro		syserr("ph_map_open: %s: cannot connect to PH server",
473266494Sgshapiro		       map->map_mname);
473364562Sgshapiro	}
473466494Sgshapiro	else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1)
473564562Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
473666494Sgshapiro			  "ph_map_open: %s: cannot connect to PH server",
473766494Sgshapiro			  map->map_mname);
473864562Sgshapiro	free(hostlist);
473964562Sgshapiro	return FALSE;
474064562Sgshapiro}
474164562Sgshapiro
474264562Sgshapiro/*
474364562Sgshapiro**  PH_MAP_LOOKUP -- look up key from ph server
474464562Sgshapiro*/
474564562Sgshapiro
474664562Sgshapiro#if _FFR_PHMAP_TIMEOUT
474764562Sgshapiro# define MAX_PH_FIELDS	20
474864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
474964562Sgshapiro
475064562Sgshapirochar *
475164562Sgshapiroph_map_lookup(map, key, args, pstat)
475264562Sgshapiro	MAP *map;
475364562Sgshapiro	char *key;
475464562Sgshapiro	char **args;
475564562Sgshapiro	int *pstat;
475664562Sgshapiro{
475764562Sgshapiro	int j;
475864562Sgshapiro	size_t sz;
475964562Sgshapiro	char *tmp, *tmp2;
476064562Sgshapiro	char *message = NULL, *field = NULL, *fmtkey;
476164562Sgshapiro	QIR *server_data = NULL;
476264562Sgshapiro	QIR *qirp;
476364562Sgshapiro	char keybuf[MAXKEY + 1], fieldbuf[101];
476464562Sgshapiro#if _FFR_PHMAP_TIMEOUT
476564562Sgshapiro	QIR *hold_data[MAX_PH_FIELDS];
476664562Sgshapiro	int hold_data_idx = 0;
476764562Sgshapiro	register EVENT *ev = NULL;
476864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
476964562Sgshapiro	PH_MAP_STRUCT *pmap;
477064562Sgshapiro
477164562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
477264562Sgshapiro
477364562Sgshapiro	*pstat = EX_OK;
477464562Sgshapiro
477564562Sgshapiro#if _FFR_PHMAP_TIMEOUT
477664562Sgshapiro	if (pmap->ph_timeout != 0)
477764562Sgshapiro	{
477864562Sgshapiro		if (setjmp(PHTimeout) != 0)
477964562Sgshapiro		{
478064562Sgshapiro			ev = NULL;
478164562Sgshapiro			if (LogLevel > 1)
478264562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
478364562Sgshapiro					  "timeout during PH lookup of %.100s",
478464562Sgshapiro					  key);
478564562Sgshapiro# ifdef ETIMEDOUT
478664562Sgshapiro			errno = ETIMEDOUT;
478764562Sgshapiro# else /* ETIMEDOUT */
478864562Sgshapiro			errno = 0;
478964562Sgshapiro# endif /* ETIMEDOUT */
479064562Sgshapiro			*pstat = EX_TEMPFAIL;
479164562Sgshapiro			goto ph_map_lookup_abort;
479264562Sgshapiro		}
479364562Sgshapiro		ev = setevent(pmap->ph_timeout, ph_timeout_func, 0);
479464562Sgshapiro	}
479564562Sgshapiro
479664562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
479764562Sgshapiro	/* check all relevant fields */
479864562Sgshapiro	tmp = pmap->ph_field_list;
479964562Sgshapiro	do
480064562Sgshapiro	{
480164562Sgshapiro#if _FFR_PHMAP_TIMEOUT
480264562Sgshapiro		server_data = NULL;
480364562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
480464562Sgshapiro		while (isascii(*tmp) && isspace(*tmp))
480564562Sgshapiro			tmp++;
480664562Sgshapiro		if (*tmp == '\0')
480764562Sgshapiro			break;
480864562Sgshapiro		sz = strcspn(tmp, " ") + 1;
480964562Sgshapiro		if (sz > sizeof fieldbuf)
481064562Sgshapiro			sz = sizeof fieldbuf;
481164562Sgshapiro		(void) strlcpy(fieldbuf, tmp, sz);
481264562Sgshapiro		field = fieldbuf;
481364562Sgshapiro		tmp += sz;
481464562Sgshapiro
481564562Sgshapiro		(void) strlcpy(keybuf, key, sizeof keybuf);
481664562Sgshapiro		fmtkey = keybuf;
481764562Sgshapiro		if (strcmp(field, "alias") == 0)
481864562Sgshapiro		{
481964562Sgshapiro			/*
482064562Sgshapiro			**  for alias lookups, replace any punctuation
482164562Sgshapiro			**  characters with '-'
482264562Sgshapiro			*/
482364562Sgshapiro
482464562Sgshapiro			for (tmp2 = fmtkey; *tmp2 !=  '\0'; tmp2++)
482564562Sgshapiro			{
482664562Sgshapiro				if (isascii(*tmp2) && ispunct(*tmp2))
482764562Sgshapiro					*tmp2 = '-';
482864562Sgshapiro			}
482964562Sgshapiro			tmp2 = field;
483064562Sgshapiro		}
483164562Sgshapiro		else if (strcmp(field,"spacedname") == 0)
483264562Sgshapiro		{
483364562Sgshapiro			/*
483464562Sgshapiro			**  for "spaced" name lookups, replace any
483564562Sgshapiro			**  punctuation characters with a space
483664562Sgshapiro			*/
483764562Sgshapiro
483864562Sgshapiro			for (tmp2 = fmtkey; *tmp2 != '\0'; tmp2++)
483964562Sgshapiro			{
484064562Sgshapiro				if (isascii(*tmp2) && ispunct(*tmp2) &&
484164562Sgshapiro				    *tmp2 != '*')
484264562Sgshapiro					*tmp2 = ' ';
484364562Sgshapiro			}
484464562Sgshapiro			tmp2 = &(field[6]);
484564562Sgshapiro		}
484664562Sgshapiro		else
484764562Sgshapiro			tmp2 = field;
484864562Sgshapiro
484964562Sgshapiro		if (LogLevel > 9)
485064562Sgshapiro			sm_syslog(LOG_NOTICE, CurEnv->e_id,
485164562Sgshapiro				  "ph_map_lookup: query %s=\"%s\" return email",
485264562Sgshapiro				  tmp2, fmtkey);
485364562Sgshapiro		if (tTd(38, 20))
485464562Sgshapiro			dprintf("ph_map_lookup: query %s=\"%s\" return email\n",
485564562Sgshapiro				tmp2, fmtkey);
485664562Sgshapiro
485764562Sgshapiro		j = 0;
485864562Sgshapiro
485964562Sgshapiro		if (fprintf(pmap->ph_to_server, "query %s=%s return email\n",
486064562Sgshapiro			    tmp2, fmtkey) < 0)
486164562Sgshapiro			message = "qi query command failed";
486264562Sgshapiro		else if (fflush(pmap->ph_to_server) < 0)
486364562Sgshapiro			message = "qi fflush failed";
486464562Sgshapiro		else if ((server_data = ReadQi(pmap->ph_from_server,
486564562Sgshapiro					       &j)) == NULL)
486664562Sgshapiro			message = "ReadQi() returned NULL";
486764562Sgshapiro
486864562Sgshapiro#if _FFR_PHMAP_TIMEOUT
486964562Sgshapiro		if ((hold_data[hold_data_idx] = server_data) != NULL)
487064562Sgshapiro		{
487164562Sgshapiro			/* save pointer for later free() */
487264562Sgshapiro			hold_data_idx++;
487364562Sgshapiro		}
487464562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
487564562Sgshapiro
487664562Sgshapiro		if (server_data == NULL ||
487764562Sgshapiro		    (server_data->code >= 400 &&
487864562Sgshapiro		     server_data->code < 500))
487964562Sgshapiro		{
488064562Sgshapiro			/* temporary failure */
488164562Sgshapiro			*pstat = EX_TEMPFAIL;
488264562Sgshapiro#if _FFR_PHMAP_TIMEOUT
488364562Sgshapiro			break;
488464562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
488564562Sgshapiro			if (server_data != NULL)
488664562Sgshapiro			{
488764562Sgshapiro				FreeQIR(server_data);
488864562Sgshapiro				server_data = NULL;
488964562Sgshapiro			}
489064562Sgshapiro			return NULL;
489164562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
489264562Sgshapiro		}
489364562Sgshapiro
489464562Sgshapiro		/*
489564562Sgshapiro		**  if we found a single match, break out.
489664562Sgshapiro		**  otherwise, try the next field.
489764562Sgshapiro		*/
489864562Sgshapiro
489964562Sgshapiro		if (j == 1)
490064562Sgshapiro			break;
490164562Sgshapiro
490264562Sgshapiro		/*
490364562Sgshapiro		**  check for a single response which is an error:
490464562Sgshapiro		**  ReadQi() doesn't set j on error responses,
490564562Sgshapiro		**  but we should stop here instead of moving on if
490664562Sgshapiro		**  it happens (e.g., alias found but email field empty)
490764562Sgshapiro		*/
490864562Sgshapiro
490964562Sgshapiro		for (qirp = server_data;
491064562Sgshapiro		     qirp != NULL && qirp->code < 0;
491164562Sgshapiro		     qirp++)
491264562Sgshapiro		{
491364562Sgshapiro			if (tTd(38, 20))
491464562Sgshapiro				dprintf("ph_map_lookup: QIR: %d:%d:%d:%s\n",
491564562Sgshapiro					qirp->code, qirp->subcode, qirp->field,
491664562Sgshapiro					(qirp->message ? qirp->message
491764562Sgshapiro					 : "[NULL]"));
491864562Sgshapiro			if (qirp->code <= -500)
491964562Sgshapiro			{
492064562Sgshapiro				j = 0;
492164562Sgshapiro				goto ph_map_lookup_abort;
492264562Sgshapiro			}
492364562Sgshapiro		}
492464562Sgshapiro
492564562Sgshapiro#if _FFR_PHMAP_TIMEOUT
492664562Sgshapiro	} while (*tmp != '\0' && hold_data_idx < MAX_PH_FIELDS);
492764562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
492864562Sgshapiro	} while (*tmp != '\0');
492964562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
493064562Sgshapiro
493164562Sgshapiro  ph_map_lookup_abort:
493264562Sgshapiro#if _FFR_PHMAP_TIMEOUT
493364562Sgshapiro	if (ev != NULL)
493464562Sgshapiro		clrevent(ev);
493564562Sgshapiro
493664562Sgshapiro	/*
493764562Sgshapiro	**  Return EX_TEMPFAIL if the timer popped
493864562Sgshapiro	**  or we got a temporary PH error
493964562Sgshapiro	*/
494064562Sgshapiro
494164562Sgshapiro	if (*pstat == EX_TEMPFAIL)
494264562Sgshapiro		ph_map_safeclose(map);
494364562Sgshapiro
494464562Sgshapiro	/* if we didn't find a single match, bail out */
494564562Sgshapiro	if (*pstat == EX_OK && j != 1)
494664562Sgshapiro		*pstat = EX_UNAVAILABLE;
494764562Sgshapiro
494864562Sgshapiro	if (*pstat == EX_OK)
494964562Sgshapiro	{
495064562Sgshapiro		/*
495164562Sgshapiro		** skip leading whitespace and chop at first address
495264562Sgshapiro		*/
495364562Sgshapiro
495464562Sgshapiro		for (tmp = server_data->message;
495564562Sgshapiro		     isascii(*tmp) && isspace(*tmp);
495664562Sgshapiro		     tmp++)
495764562Sgshapiro			continue;
495864562Sgshapiro
495964562Sgshapiro		for (tmp2 = tmp; *tmp2 != '\0'; tmp2++)
496064562Sgshapiro		{
496164562Sgshapiro			if (isascii(*tmp2) && isspace(*tmp2))
496264562Sgshapiro			{
496364562Sgshapiro				*tmp2 = '\0';
496464562Sgshapiro				break;
496564562Sgshapiro			}
496664562Sgshapiro		}
496764562Sgshapiro
496864562Sgshapiro		if (tTd(38,20))
496964562Sgshapiro			dprintf("ph_map_lookup: %s => %s\n", key, tmp);
497064562Sgshapiro
497164562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
497264562Sgshapiro			message = map_rewrite(map, key, strlen(key), NULL);
497364562Sgshapiro		else
497464562Sgshapiro			message = map_rewrite(map, tmp, strlen(tmp), args);
497564562Sgshapiro	}
497664562Sgshapiro
497764562Sgshapiro	/*
497864562Sgshapiro	**  Deferred free() of returned server_data values
497964562Sgshapiro	**  the deferral is to avoid the risk of a free() being
498064562Sgshapiro	**  interrupted by the event timer.  By now the timeout event
498164562Sgshapiro	**  has been cleared and none of the data is still in use.
498264562Sgshapiro	*/
498364562Sgshapiro
498464562Sgshapiro	while (--hold_data_idx >= 0)
498564562Sgshapiro	{
498664562Sgshapiro		if (hold_data[hold_data_idx] != NULL)
498764562Sgshapiro			FreeQIR(hold_data[hold_data_idx]);
498864562Sgshapiro	}
498964562Sgshapiro
499064562Sgshapiro	if (*pstat == EX_OK)
499164562Sgshapiro		return message;
499264562Sgshapiro
499364562Sgshapiro	return NULL;
499464562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
499564562Sgshapiro	/* if we didn't find a single match, bail out */
499664562Sgshapiro	if (j != 1)
499764562Sgshapiro	{
499864562Sgshapiro		*pstat = EX_UNAVAILABLE;
499964562Sgshapiro		if (server_data != NULL)
500064562Sgshapiro		{
500164562Sgshapiro			FreeQIR(server_data);
500264562Sgshapiro			server_data = NULL;
500364562Sgshapiro		}
500464562Sgshapiro		return NULL;
500564562Sgshapiro	}
500664562Sgshapiro
500764562Sgshapiro	/*
500864562Sgshapiro	** skip leading whitespace and chop at first address
500964562Sgshapiro	*/
501064562Sgshapiro
501164562Sgshapiro	for (tmp = server_data->message;
501264562Sgshapiro	     isascii(*tmp) && isspace(*tmp);
501364562Sgshapiro	     tmp++)
501464562Sgshapiro		continue;
501564562Sgshapiro
501664562Sgshapiro	for (tmp2 = tmp; *tmp2 != '\0'; tmp2++)
501764562Sgshapiro	{
501864562Sgshapiro		if (isascii(*tmp2) && isspace(*tmp2))
501964562Sgshapiro		{
502064562Sgshapiro			*tmp2 = '\0';
502164562Sgshapiro			break;
502264562Sgshapiro		}
502364562Sgshapiro	}
502464562Sgshapiro
502564562Sgshapiro	if (tTd(38,20))
502664562Sgshapiro		dprintf("ph_map_lookup: %s => %s\n", key, tmp);
502764562Sgshapiro
502864562Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
502964562Sgshapiro		message = map_rewrite(map, key, strlen(key), NULL);
503064562Sgshapiro	else
503164562Sgshapiro		message = map_rewrite(map, tmp, strlen(tmp), args);
503264562Sgshapiro	if (server_data != NULL)
503364562Sgshapiro	{
503464562Sgshapiro		FreeQIR(server_data);
503564562Sgshapiro		server_data = NULL;
503664562Sgshapiro	}
503764562Sgshapiro	return message;
503864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
503964562Sgshapiro}
504064562Sgshapiro#endif /* PH_MAP */
504164562Sgshapiro/*
504242575Speter**  syslog map
504338032Speter*/
504438032Speter
504538032Speter#define map_prio	map_lockfd	/* overload field */
504638032Speter
504738032Speter/*
504842575Speter**  SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
504938032Speter*/
505038032Speter
505138032Speterbool
505238032Spetersyslog_map_parseargs(map, args)
505338032Speter	MAP *map;
505438032Speter	char *args;
505538032Speter{
505638032Speter	char *p = args;
505738032Speter	char *priority = NULL;
505838032Speter
505964562Sgshapiro	/* there is no check whether there is really an argument */
506064562Sgshapiro	while (*p != '\0')
506138032Speter	{
506238032Speter		while (isascii(*p) && isspace(*p))
506338032Speter			p++;
506438032Speter		if (*p != '-')
506538032Speter			break;
506664562Sgshapiro		++p;
506764562Sgshapiro		if (*p == 'D')
506864562Sgshapiro		{
506964562Sgshapiro			map->map_mflags |= MF_DEFER;
507064562Sgshapiro			++p;
507164562Sgshapiro		}
507264562Sgshapiro		else if (*p == 'S')
507364562Sgshapiro		{
507464562Sgshapiro			map->map_spacesub = *++p;
507564562Sgshapiro			if (*p != '\0')
507664562Sgshapiro				p++;
507764562Sgshapiro		}
507864562Sgshapiro		else if (*p == 'L')
507964562Sgshapiro		{
508064562Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p))
508164562Sgshapiro				continue;
508264562Sgshapiro			if (*p == '\0')
508364562Sgshapiro				break;
508464562Sgshapiro			priority = p;
508564562Sgshapiro			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
508664562Sgshapiro				p++;
508764562Sgshapiro			if (*p != '\0')
508864562Sgshapiro				*p++ = '\0';
508964562Sgshapiro		}
509064562Sgshapiro		else
509164562Sgshapiro		{
509264562Sgshapiro			syserr("Illegal option %c map syslog", *p);
509364562Sgshapiro			++p;
509464562Sgshapiro		}
509538032Speter	}
509638032Speter
509738032Speter	if (priority == NULL)
509838032Speter		map->map_prio = LOG_INFO;
509938032Speter	else
510038032Speter	{
510138032Speter		if (strncasecmp("LOG_", priority, 4) == 0)
510238032Speter			priority += 4;
510338032Speter
510438032Speter#ifdef LOG_EMERG
510538032Speter		if (strcasecmp("EMERG", priority) == 0)
510638032Speter			map->map_prio = LOG_EMERG;
510738032Speter		else
510864562Sgshapiro#endif /* LOG_EMERG */
510938032Speter#ifdef LOG_ALERT
511038032Speter		if (strcasecmp("ALERT", priority) == 0)
511138032Speter			map->map_prio = LOG_ALERT;
511238032Speter		else
511364562Sgshapiro#endif /* LOG_ALERT */
511438032Speter#ifdef LOG_CRIT
511538032Speter		if (strcasecmp("CRIT", priority) == 0)
511638032Speter			map->map_prio = LOG_CRIT;
511738032Speter		else
511864562Sgshapiro#endif /* LOG_CRIT */
511938032Speter#ifdef LOG_ERR
512038032Speter		if (strcasecmp("ERR", priority) == 0)
512138032Speter			map->map_prio = LOG_ERR;
512238032Speter		else
512364562Sgshapiro#endif /* LOG_ERR */
512438032Speter#ifdef LOG_WARNING
512538032Speter		if (strcasecmp("WARNING", priority) == 0)
512638032Speter			map->map_prio = LOG_WARNING;
512738032Speter		else
512864562Sgshapiro#endif /* LOG_WARNING */
512938032Speter#ifdef LOG_NOTICE
513038032Speter		if (strcasecmp("NOTICE", priority) == 0)
513138032Speter			map->map_prio = LOG_NOTICE;
513238032Speter		else
513364562Sgshapiro#endif /* LOG_NOTICE */
513438032Speter#ifdef LOG_INFO
513538032Speter		if (strcasecmp("INFO", priority) == 0)
513638032Speter			map->map_prio = LOG_INFO;
513738032Speter		else
513864562Sgshapiro#endif /* LOG_INFO */
513938032Speter#ifdef LOG_DEBUG
514038032Speter		if (strcasecmp("DEBUG", priority) == 0)
514138032Speter			map->map_prio = LOG_DEBUG;
514238032Speter		else
514364562Sgshapiro#endif /* LOG_DEBUG */
514438032Speter		{
514538032Speter			syserr("syslog_map_parseargs: Unknown priority %s\n",
514638032Speter			       priority);
514738032Speter			return FALSE;
514838032Speter		}
514938032Speter	}
515038032Speter	return TRUE;
515138032Speter}
515238032Speter
515338032Speter/*
515442575Speter**  SYSLOG_MAP_LOOKUP -- rewrite and syslog message.  Always return empty string
515538032Speter*/
515638032Speter
515738032Speterchar *
515838032Spetersyslog_map_lookup(map, string, args, statp)
515938032Speter	MAP *map;
516038032Speter	char *string;
516138032Speter	char **args;
516238032Speter	int *statp;
516338032Speter{
516438032Speter	char *ptr = map_rewrite(map, string, strlen(string), args);
516538032Speter
516638032Speter	if (ptr != NULL)
516738032Speter	{
516838032Speter		if (tTd(38, 20))
516964562Sgshapiro			dprintf("syslog_map_lookup(%s (priority %d): %s\n",
517064562Sgshapiro				map->map_mname, map->map_prio, ptr);
517138032Speter
517238032Speter		sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
517338032Speter	}
517438032Speter
517538032Speter	*statp = EX_OK;
517638032Speter	return "";
517738032Speter}
517838032Speter
517938032Speter/*
518038032Speter**  HESIOD Modules
518138032Speter*/
518238032Speter
518338032Speter#ifdef HESIOD
518438032Speter
518538032Speterbool
518638032Speterhes_map_open(map, mode)
518738032Speter	MAP *map;
518838032Speter	int mode;
518938032Speter{
519038032Speter	if (tTd(38, 2))
519164562Sgshapiro		dprintf("hes_map_open(%s, %s, %d)\n",
519238032Speter			map->map_mname, map->map_file, mode);
519338032Speter
519438032Speter	if (mode != O_RDONLY)
519538032Speter	{
519638032Speter		/* issue a pseudo-error message */
519764562Sgshapiro# ifdef ENOSYS
519838032Speter		errno = ENOSYS;
519964562Sgshapiro# else /* ENOSYS */
520064562Sgshapiro#  ifdef EFTYPE
520138032Speter		errno = EFTYPE;
520264562Sgshapiro#  else /* EFTYPE */
520338032Speter		errno = ENXIO;
520464562Sgshapiro#  endif /* EFTYPE */
520564562Sgshapiro# endif /* ENOSYS */
520638032Speter		return FALSE;
520738032Speter	}
520838032Speter
520964562Sgshapiro# ifdef HESIOD_INIT
521038032Speter	if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
521138032Speter		return TRUE;
521238032Speter
521338032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
521464562Sgshapiro		syserr("421 4.0.0 cannot initialize Hesiod map (%s)",
521538032Speter			errstring(errno));
521638032Speter	return FALSE;
521764562Sgshapiro# else /* HESIOD_INIT */
521838032Speter	if (hes_error() == HES_ER_UNINIT)
521938032Speter		hes_init();
522038032Speter	switch (hes_error())
522138032Speter	{
522238032Speter	  case HES_ER_OK:
522338032Speter	  case HES_ER_NOTFOUND:
522438032Speter		return TRUE;
522538032Speter	}
522638032Speter
522738032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
522864562Sgshapiro		syserr("421 4.0.0 cannot initialize Hesiod map (%d)", hes_error());
522938032Speter
523038032Speter	return FALSE;
523164562Sgshapiro# endif /* HESIOD_INIT */
523238032Speter}
523338032Speter
523438032Speterchar *
523538032Speterhes_map_lookup(map, name, av, statp)
523638032Speter	MAP *map;
523738032Speter	char *name;
523838032Speter	char **av;
523938032Speter	int *statp;
524038032Speter{
524138032Speter	char **hp;
524238032Speter
524338032Speter	if (tTd(38, 20))
524464562Sgshapiro		dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
524538032Speter
524638032Speter	if (name[0] == '\\')
524738032Speter	{
524838032Speter		char *np;
524938032Speter		int nl;
525038032Speter		char nbuf[MAXNAME];
525138032Speter
525238032Speter		nl = strlen(name);
525338032Speter		if (nl < sizeof nbuf - 1)
525438032Speter			np = nbuf;
525538032Speter		else
525638032Speter			np = xalloc(strlen(name) + 2);
525738032Speter		np[0] = '\\';
525864562Sgshapiro		(void) strlcpy(&np[1], name, (sizeof nbuf) - 1);
525964562Sgshapiro# ifdef HESIOD_INIT
526038032Speter		hp = hesiod_resolve(HesiodContext, np, map->map_file);
526164562Sgshapiro# else /* HESIOD_INIT */
526238032Speter		hp = hes_resolve(np, map->map_file);
526364562Sgshapiro# endif /* HESIOD_INIT */
526438032Speter		if (np != nbuf)
526538032Speter			free(np);
526638032Speter	}
526738032Speter	else
526838032Speter	{
526964562Sgshapiro# ifdef HESIOD_INIT
527038032Speter		hp = hesiod_resolve(HesiodContext, name, map->map_file);
527164562Sgshapiro# else /* HESIOD_INIT */
527238032Speter		hp = hes_resolve(name, map->map_file);
527364562Sgshapiro# endif /* HESIOD_INIT */
527438032Speter	}
527564562Sgshapiro# ifdef HESIOD_INIT
527638032Speter	if (hp == NULL)
527738032Speter		return NULL;
527838032Speter	if (*hp == NULL)
527938032Speter	{
528038032Speter		hesiod_free_list(HesiodContext, hp);
528138032Speter		switch (errno)
528238032Speter		{
528338032Speter		  case ENOENT:
528438032Speter			  *statp = EX_NOTFOUND;
528538032Speter			  break;
528638032Speter		  case ECONNREFUSED:
528738032Speter		  case EMSGSIZE:
528838032Speter			  *statp = EX_TEMPFAIL;
528938032Speter			  break;
529038032Speter		  case ENOMEM:
529138032Speter		  default:
529238032Speter			  *statp = EX_UNAVAILABLE;
529338032Speter			  break;
529438032Speter		}
529538032Speter		return NULL;
529638032Speter	}
529764562Sgshapiro# else /* HESIOD_INIT */
529838032Speter	if (hp == NULL || hp[0] == NULL)
529938032Speter	{
530038032Speter		switch (hes_error())
530138032Speter		{
530238032Speter		  case HES_ER_OK:
530338032Speter			*statp = EX_OK;
530438032Speter			break;
530538032Speter
530638032Speter		  case HES_ER_NOTFOUND:
530738032Speter			*statp = EX_NOTFOUND;
530838032Speter			break;
530938032Speter
531038032Speter		  case HES_ER_CONFIG:
531138032Speter			*statp = EX_UNAVAILABLE;
531238032Speter			break;
531338032Speter
531438032Speter		  case HES_ER_NET:
531538032Speter			*statp = EX_TEMPFAIL;
531638032Speter			break;
531738032Speter		}
531838032Speter		return NULL;
531938032Speter	}
532064562Sgshapiro# endif /* HESIOD_INIT */
532138032Speter
532238032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
532338032Speter		return map_rewrite(map, name, strlen(name), NULL);
532438032Speter	else
532538032Speter		return map_rewrite(map, hp[0], strlen(hp[0]), av);
532638032Speter}
532738032Speter
532864562Sgshapiro#endif /* HESIOD */
532938032Speter/*
533038032Speter**  NeXT NETINFO Modules
533138032Speter*/
533238032Speter
533338032Speter#if NETINFO
533438032Speter
533538032Speter# define NETINFO_DEFAULT_DIR		"/aliases"
533638032Speter# define NETINFO_DEFAULT_PROPERTY	"members"
533738032Speter
533838032Speter/*
533938032Speter**  NI_MAP_OPEN -- open NetInfo Aliases
534038032Speter*/
534138032Speter
534238032Speterbool
534338032Speterni_map_open(map, mode)
534438032Speter	MAP *map;
534538032Speter	int mode;
534638032Speter{
534738032Speter	if (tTd(38, 2))
534864562Sgshapiro		dprintf("ni_map_open(%s, %s, %d)\n",
534938032Speter			map->map_mname, map->map_file, mode);
535038032Speter	mode &= O_ACCMODE;
535138032Speter
535238032Speter	if (*map->map_file == '\0')
535338032Speter		map->map_file = NETINFO_DEFAULT_DIR;
535438032Speter
535538032Speter	if (map->map_valcolnm == NULL)
535638032Speter		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
535738032Speter
535838032Speter	if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
535938032Speter		map->map_coldelim = ',';
536038032Speter
536138032Speter	return TRUE;
536238032Speter}
536338032Speter
536438032Speter
536538032Speter/*
536638032Speter**  NI_MAP_LOOKUP -- look up a datum in NetInfo
536738032Speter*/
536838032Speter
536938032Speterchar *
537038032Speterni_map_lookup(map, name, av, statp)
537138032Speter	MAP *map;
537238032Speter	char *name;
537338032Speter	char **av;
537438032Speter	int *statp;
537538032Speter{
537638032Speter	char *res;
537738032Speter	char *propval;
537838032Speter
537938032Speter	if (tTd(38, 20))
538064562Sgshapiro		dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
538138032Speter
538238032Speter	propval = ni_propval(map->map_file, map->map_keycolnm, name,
538338032Speter			     map->map_valcolnm, map->map_coldelim);
538438032Speter
538538032Speter	if (propval == NULL)
538638032Speter		return NULL;
538738032Speter
538838032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
538938032Speter		res = map_rewrite(map, name, strlen(name), NULL);
539038032Speter	else
539138032Speter		res = map_rewrite(map, propval, strlen(propval), av);
539238032Speter	free(propval);
539338032Speter	return res;
539438032Speter}
539538032Speter
539638032Speter
539764562Sgshapirostatic bool
539838032Speterni_getcanonname(name, hbsize, statp)
539938032Speter	char *name;
540038032Speter	int hbsize;
540138032Speter	int *statp;
540238032Speter{
540338032Speter	char *vptr;
540438032Speter	char *ptr;
540538032Speter	char nbuf[MAXNAME + 1];
540638032Speter
540738032Speter	if (tTd(38, 20))
540864562Sgshapiro		dprintf("ni_getcanonname(%s)\n", name);
540938032Speter
541064562Sgshapiro	if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
541138032Speter	{
541238032Speter		*statp = EX_UNAVAILABLE;
541338032Speter		return FALSE;
541438032Speter	}
541538032Speter	shorten_hostname(nbuf);
541638032Speter
541738032Speter	/* we only accept single token search key */
541838032Speter	if (strchr(nbuf, '.'))
541938032Speter	{
542038032Speter		*statp = EX_NOHOST;
542138032Speter		return FALSE;
542238032Speter	}
542338032Speter
542438032Speter	/* Do the search */
542538032Speter	vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
542638032Speter
542738032Speter	if (vptr == NULL)
542838032Speter	{
542938032Speter		*statp = EX_NOHOST;
543038032Speter		return FALSE;
543138032Speter	}
543238032Speter
543338032Speter	/* Only want the first machine name */
543438032Speter	if ((ptr = strchr(vptr, '\n')) != NULL)
543538032Speter		*ptr = '\0';
543638032Speter
543738032Speter	if (hbsize >= strlen(vptr))
543838032Speter	{
543964562Sgshapiro		(void) strlcpy(name, vptr, hbsize);
544064562Sgshapiro		free(vptr);
544138032Speter		*statp = EX_OK;
544238032Speter		return TRUE;
544338032Speter	}
544438032Speter	*statp = EX_UNAVAILABLE;
544538032Speter	free(vptr);
544638032Speter	return FALSE;
544738032Speter}
544838032Speter
544938032Speter
545038032Speter/*
545138032Speter**  NI_PROPVAL -- NetInfo property value lookup routine
545238032Speter**
545338032Speter**	Parameters:
545438032Speter**		keydir -- the NetInfo directory name in which to search
545538032Speter**			for the key.
545638032Speter**		keyprop -- the name of the property in which to find the
545738032Speter**			property we are interested.  Defaults to "name".
545838032Speter**		keyval -- the value for which we are really searching.
545938032Speter**		valprop -- the property name for the value in which we
546038032Speter**			are interested.
546138032Speter**		sepchar -- if non-nil, this can be multiple-valued, and
546238032Speter**			we should return a string separated by this
546338032Speter**			character.
546438032Speter**
546538032Speter**	Returns:
546638032Speter**		NULL -- if:
546738032Speter**			1. the directory is not found
546838032Speter**			2. the property name is not found
546938032Speter**			3. the property contains multiple values
547064562Sgshapiro**			4. some error occurred
547138032Speter**		else -- the value of the lookup.
547238032Speter**
547338032Speter**	Example:
547438032Speter**		To search for an alias value, use:
547538032Speter**		  ni_propval("/aliases", "name", aliasname, "members", ',')
547638032Speter**
547738032Speter**	Notes:
547864562Sgshapiro**		Caller should free the return value of ni_proval
547938032Speter*/
548038032Speter
548138032Speter# include <netinfo/ni.h>
548238032Speter
548364562Sgshapiro# define LOCAL_NETINFO_DOMAIN	"."
548464562Sgshapiro# define PARENT_NETINFO_DOMAIN	".."
548564562Sgshapiro# define MAX_NI_LEVELS		256
548638032Speter
548738032Speterchar *
548838032Speterni_propval(keydir, keyprop, keyval, valprop, sepchar)
548938032Speter	char *keydir;
549038032Speter	char *keyprop;
549138032Speter	char *keyval;
549238032Speter	char *valprop;
549338032Speter	int sepchar;
549438032Speter{
549538032Speter	char *propval = NULL;
549638032Speter	int i;
549764562Sgshapiro	int j, alen, l;
549838032Speter	void *ni = NULL;
549938032Speter	void *lastni = NULL;
550038032Speter	ni_status nis;
550138032Speter	ni_id nid;
550238032Speter	ni_namelist ninl;
550338032Speter	register char *p;
550438032Speter	char keybuf[1024];
550538032Speter
550638032Speter	/*
550738032Speter	**  Create the full key from the two parts.
550838032Speter	**
550938032Speter	**	Note that directory can end with, e.g., "name=" to specify
551038032Speter	**	an alternate search property.
551138032Speter	*/
551238032Speter
551338032Speter	i = strlen(keydir) + strlen(keyval) + 2;
551438032Speter	if (keyprop != NULL)
551538032Speter		i += strlen(keyprop) + 1;
551664562Sgshapiro	if (i >= sizeof keybuf)
551738032Speter		return NULL;
551864562Sgshapiro	(void) strlcpy(keybuf, keydir, sizeof keybuf);
551964562Sgshapiro	(void) strlcat(keybuf, "/", sizeof keybuf);
552038032Speter	if (keyprop != NULL)
552138032Speter	{
552264562Sgshapiro		(void) strlcat(keybuf, keyprop, sizeof keybuf);
552364562Sgshapiro		(void) strlcat(keybuf, "=", sizeof keybuf);
552438032Speter	}
552564562Sgshapiro	(void) strlcat(keybuf, keyval, sizeof keybuf);
552638032Speter
552738032Speter	if (tTd(38, 21))
552864562Sgshapiro		dprintf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n",
552938032Speter			keydir, keyprop, keyval, valprop, sepchar, keybuf);
553038032Speter	/*
553138032Speter	**  If the passed directory and property name are found
553238032Speter	**  in one of netinfo domains we need to search (starting
553338032Speter	**  from the local domain moving all the way back to the
553438032Speter	**  root domain) set propval to the property's value
553538032Speter	**  and return it.
553638032Speter	*/
553738032Speter
553838032Speter	for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
553938032Speter	{
554038032Speter		if (i == 0)
554138032Speter		{
554238032Speter			nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
554338032Speter			if (tTd(38, 20))
554464562Sgshapiro				dprintf("ni_open(LOCAL) = %d\n", nis);
554538032Speter		}
554638032Speter		else
554738032Speter		{
554838032Speter			if (lastni != NULL)
554938032Speter				ni_free(lastni);
555038032Speter			lastni = ni;
555138032Speter			nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
555238032Speter			if (tTd(38, 20))
555364562Sgshapiro				dprintf("ni_open(PARENT) = %d\n", nis);
555438032Speter		}
555538032Speter
555638032Speter		/*
555738032Speter		**  Don't bother if we didn't get a handle on a
555838032Speter		**  proper domain.  This is not necessarily an error.
555938032Speter		**  We would get a positive ni_status if, for instance
556038032Speter		**  we never found the directory or property and tried
556138032Speter		**  to open the parent of the root domain!
556238032Speter		*/
556338032Speter
556438032Speter		if (nis != 0)
556538032Speter			break;
556638032Speter
556738032Speter		/*
556838032Speter		**  Find the path to the server information.
556938032Speter		*/
557038032Speter
557138032Speter		if (ni_pathsearch(ni, &nid, keybuf) != 0)
557238032Speter			continue;
557338032Speter
557438032Speter		/*
557538032Speter		**  Find associated value information.
557638032Speter		*/
557738032Speter
557838032Speter		if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
557938032Speter			continue;
558038032Speter
558138032Speter		if (tTd(38, 20))
558264562Sgshapiro			dprintf("ni_lookupprop: len=%d\n",
558364562Sgshapiro				ninl.ni_namelist_len);
558464562Sgshapiro
558538032Speter		/*
558638032Speter		**  See if we have an acceptable number of values.
558738032Speter		*/
558838032Speter
558938032Speter		if (ninl.ni_namelist_len <= 0)
559038032Speter			continue;
559138032Speter
559238032Speter		if (sepchar == '\0' && ninl.ni_namelist_len > 1)
559338032Speter		{
559438032Speter			ni_namelist_free(&ninl);
559538032Speter			continue;
559638032Speter		}
559738032Speter
559838032Speter		/*
559938032Speter		**  Calculate number of bytes needed and build result
560038032Speter		*/
560138032Speter
560238032Speter		alen = 1;
560338032Speter		for (j = 0; j < ninl.ni_namelist_len; j++)
560438032Speter			alen += strlen(ninl.ni_namelist_val[j]) + 1;
560538032Speter		propval = p = xalloc(alen);
560638032Speter		for (j = 0; j < ninl.ni_namelist_len; j++)
560738032Speter		{
560864562Sgshapiro			(void) strlcpy(p, ninl.ni_namelist_val[j], alen);
560964562Sgshapiro			l = strlen(p);
561064562Sgshapiro			p += l;
561138032Speter			*p++ = sepchar;
561264562Sgshapiro			alen -= l + 1;
561338032Speter		}
561438032Speter		*--p = '\0';
561538032Speter
561638032Speter		ni_namelist_free(&ninl);
561738032Speter	}
561838032Speter
561938032Speter	/*
562038032Speter	**  Clean up.
562138032Speter	*/
562238032Speter
562338032Speter	if (ni != NULL)
562438032Speter		ni_free(ni);
562538032Speter	if (lastni != NULL && ni != lastni)
562638032Speter		ni_free(lastni);
562738032Speter	if (tTd(38, 20))
562864562Sgshapiro		dprintf("ni_propval returns: '%s'\n", propval);
562938032Speter
563038032Speter	return propval;
563138032Speter}
563238032Speter
563342575Speter#endif /* NETINFO */
563438032Speter/*
563538032Speter**  TEXT (unindexed text file) Modules
563638032Speter**
563738032Speter**	This code donated by Sun Microsystems.
563838032Speter*/
563938032Speter
564038032Speter#define map_sff		map_lockfd	/* overload field */
564138032Speter
564238032Speter
564338032Speter/*
564438032Speter**  TEXT_MAP_OPEN -- open text table
564538032Speter*/
564638032Speter
564738032Speterbool
564838032Spetertext_map_open(map, mode)
564938032Speter	MAP *map;
565038032Speter	int mode;
565138032Speter{
565264562Sgshapiro	long sff;
565338032Speter	int i;
565438032Speter
565538032Speter	if (tTd(38, 2))
565664562Sgshapiro		dprintf("text_map_open(%s, %s, %d)\n",
565738032Speter			map->map_mname, map->map_file, mode);
565838032Speter
565938032Speter	mode &= O_ACCMODE;
566038032Speter	if (mode != O_RDONLY)
566138032Speter	{
566238032Speter		errno = EPERM;
566338032Speter		return FALSE;
566438032Speter	}
566538032Speter
566638032Speter	if (*map->map_file == '\0')
566738032Speter	{
566838032Speter		syserr("text map \"%s\": file name required",
566938032Speter			map->map_mname);
567038032Speter		return FALSE;
567138032Speter	}
567238032Speter
567338032Speter	if (map->map_file[0] != '/')
567438032Speter	{
567538032Speter		syserr("text map \"%s\": file name must be fully qualified",
567638032Speter			map->map_mname);
567738032Speter		return FALSE;
567838032Speter	}
567938032Speter
568038032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
568164562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
568238032Speter		sff |= SFF_NOWLINK;
568364562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
568438032Speter		sff |= SFF_SAFEDIRPATH;
568538032Speter	if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
568638032Speter			  sff, S_IRUSR, NULL)) != 0)
568738032Speter	{
568864562Sgshapiro		int save_errno = errno;
568964562Sgshapiro
569038032Speter		/* cannot open this map */
569138032Speter		if (tTd(38, 2))
569264562Sgshapiro			dprintf("\tunsafe map file: %d\n", i);
569364562Sgshapiro		errno = save_errno;
569438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
569538032Speter			syserr("text map \"%s\": unsafe map file %s",
569638032Speter				map->map_mname, map->map_file);
569738032Speter		return FALSE;
569838032Speter	}
569938032Speter
570038032Speter	if (map->map_keycolnm == NULL)
570138032Speter		map->map_keycolno = 0;
570238032Speter	else
570338032Speter	{
570438032Speter		if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
570538032Speter		{
570638032Speter			syserr("text map \"%s\", file %s: -k should specify a number, not %s",
570738032Speter				map->map_mname, map->map_file,
570838032Speter				map->map_keycolnm);
570938032Speter			return FALSE;
571038032Speter		}
571138032Speter		map->map_keycolno = atoi(map->map_keycolnm);
571238032Speter	}
571338032Speter
571438032Speter	if (map->map_valcolnm == NULL)
571538032Speter		map->map_valcolno = 0;
571638032Speter	else
571738032Speter	{
571838032Speter		if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
571938032Speter		{
572038032Speter			syserr("text map \"%s\", file %s: -v should specify a number, not %s",
572138032Speter					map->map_mname, map->map_file,
572238032Speter					map->map_valcolnm);
572338032Speter			return FALSE;
572438032Speter		}
572538032Speter		map->map_valcolno = atoi(map->map_valcolnm);
572638032Speter	}
572738032Speter
572838032Speter	if (tTd(38, 2))
572938032Speter	{
573064562Sgshapiro		dprintf("text_map_open(%s, %s): delimiter = ",
573138032Speter			map->map_mname, map->map_file);
573238032Speter		if (map->map_coldelim == '\0')
573364562Sgshapiro			dprintf("(white space)\n");
573438032Speter		else
573564562Sgshapiro			dprintf("%c\n", map->map_coldelim);
573638032Speter	}
573738032Speter
573838032Speter	map->map_sff = sff;
573938032Speter	return TRUE;
574038032Speter}
574138032Speter
574238032Speter
574338032Speter/*
574438032Speter**  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
574538032Speter*/
574638032Speter
574738032Speterchar *
574838032Spetertext_map_lookup(map, name, av, statp)
574938032Speter	MAP *map;
575038032Speter	char *name;
575138032Speter	char **av;
575238032Speter	int *statp;
575338032Speter{
575438032Speter	char *vp;
575538032Speter	auto int vsize;
575638032Speter	int buflen;
575738032Speter	FILE *f;
575838032Speter	char delim;
575938032Speter	int key_idx;
576038032Speter	bool found_it;
576164562Sgshapiro	long sff = map->map_sff;
576238032Speter	char search_key[MAXNAME + 1];
576338032Speter	char linebuf[MAXLINE];
576438032Speter	char buf[MAXNAME + 1];
576538032Speter
576638032Speter	found_it = FALSE;
576738032Speter	if (tTd(38, 20))
576864562Sgshapiro		dprintf("text_map_lookup(%s, %s)\n", map->map_mname,  name);
576938032Speter
577038032Speter	buflen = strlen(name);
577138032Speter	if (buflen > sizeof search_key - 1)
577238032Speter		buflen = sizeof search_key - 1;
577364562Sgshapiro	memmove(search_key, name, buflen);
577438032Speter	search_key[buflen] = '\0';
577538032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
577638032Speter		makelower(search_key);
577738032Speter
577838032Speter	f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
577938032Speter	if (f == NULL)
578038032Speter	{
578138032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
578238032Speter		*statp = EX_UNAVAILABLE;
578338032Speter		return NULL;
578438032Speter	}
578538032Speter	key_idx = map->map_keycolno;
578638032Speter	delim = map->map_coldelim;
578738032Speter	while (fgets(linebuf, MAXLINE, f) != NULL)
578838032Speter	{
578938032Speter		char *p;
579038032Speter
579138032Speter		/* skip comment line */
579238032Speter		if (linebuf[0] == '#')
579338032Speter			continue;
579438032Speter		p = strchr(linebuf, '\n');
579538032Speter		if (p != NULL)
579638032Speter			*p = '\0';
579738032Speter		p = get_column(linebuf, key_idx, delim, buf, sizeof buf);
579838032Speter		if (p != NULL && strcasecmp(search_key, p) == 0)
579938032Speter		{
580038032Speter			found_it = TRUE;
580138032Speter			break;
580238032Speter		}
580338032Speter	}
580464562Sgshapiro	(void) fclose(f);
580538032Speter	if (!found_it)
580638032Speter	{
580738032Speter		*statp = EX_NOTFOUND;
580838032Speter		return NULL;
580938032Speter	}
581038032Speter	vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof buf);
581142575Speter	if (vp == NULL)
581242575Speter	{
581342575Speter		*statp = EX_NOTFOUND;
581442575Speter		return NULL;
581542575Speter	}
581638032Speter	vsize = strlen(vp);
581738032Speter	*statp = EX_OK;
581838032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
581938032Speter		return map_rewrite(map, name, strlen(name), NULL);
582038032Speter	else
582138032Speter		return map_rewrite(map, vp, vsize, av);
582238032Speter}
582338032Speter
582438032Speter/*
582538032Speter**  TEXT_GETCANONNAME -- look up canonical name in hosts file
582638032Speter*/
582738032Speter
582864562Sgshapirostatic bool
582938032Spetertext_getcanonname(name, hbsize, statp)
583038032Speter	char *name;
583138032Speter	int hbsize;
583238032Speter	int *statp;
583338032Speter{
583438032Speter	bool found;
583538032Speter	FILE *f;
583638032Speter	char linebuf[MAXLINE];
583738032Speter	char cbuf[MAXNAME + 1];
583838032Speter	char nbuf[MAXNAME + 1];
583938032Speter
584038032Speter	if (tTd(38, 20))
584164562Sgshapiro		dprintf("text_getcanonname(%s)\n", name);
584238032Speter
584338032Speter	if (strlen(name) >= (SIZE_T) sizeof nbuf)
584438032Speter	{
584538032Speter		*statp = EX_UNAVAILABLE;
584638032Speter		return FALSE;
584738032Speter	}
584864562Sgshapiro	(void) strlcpy(nbuf, name, sizeof nbuf);
584938032Speter	shorten_hostname(nbuf);
585038032Speter
585138032Speter	f = fopen(HostsFile, "r");
585238032Speter	if (f == NULL)
585338032Speter	{
585438032Speter		*statp = EX_UNAVAILABLE;
585538032Speter		return FALSE;
585638032Speter	}
585738032Speter	found = FALSE;
585838032Speter	while (!found && fgets(linebuf, MAXLINE, f) != NULL)
585938032Speter	{
586038032Speter		char *p = strpbrk(linebuf, "#\n");
586138032Speter
586238032Speter		if (p != NULL)
586338032Speter			*p = '\0';
586438032Speter		if (linebuf[0] != '\0')
586538032Speter			found = extract_canonname(nbuf, linebuf, cbuf, sizeof cbuf);
586638032Speter	}
586764562Sgshapiro	(void) fclose(f);
586838032Speter	if (!found)
586938032Speter	{
587038032Speter		*statp = EX_NOHOST;
587138032Speter		return FALSE;
587238032Speter	}
587338032Speter
587438032Speter	if ((SIZE_T) hbsize >= strlen(cbuf))
587538032Speter	{
587664562Sgshapiro		(void) strlcpy(name, cbuf, hbsize);
587738032Speter		*statp = EX_OK;
587838032Speter		return TRUE;
587938032Speter	}
588038032Speter	*statp = EX_UNAVAILABLE;
588138032Speter	return FALSE;
588238032Speter}
588338032Speter/*
588438032Speter**  STAB (Symbol Table) Modules
588538032Speter*/
588638032Speter
588738032Speter
588838032Speter/*
588938032Speter**  STAB_MAP_LOOKUP -- look up alias in symbol table
589038032Speter*/
589138032Speter
589238032Speter/* ARGSUSED2 */
589338032Speterchar *
589438032Speterstab_map_lookup(map, name, av, pstat)
589538032Speter	register MAP *map;
589638032Speter	char *name;
589738032Speter	char **av;
589838032Speter	int *pstat;
589938032Speter{
590038032Speter	register STAB *s;
590138032Speter
590238032Speter	if (tTd(38, 20))
590364562Sgshapiro		dprintf("stab_lookup(%s, %s)\n",
590438032Speter			map->map_mname, name);
590538032Speter
590638032Speter	s = stab(name, ST_ALIAS, ST_FIND);
590738032Speter	if (s != NULL)
590864562Sgshapiro		return s->s_alias;
590964562Sgshapiro	return NULL;
591038032Speter}
591138032Speter
591238032Speter
591338032Speter/*
591438032Speter**  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
591538032Speter*/
591638032Speter
591738032Spetervoid
591838032Speterstab_map_store(map, lhs, rhs)
591938032Speter	register MAP *map;
592038032Speter	char *lhs;
592138032Speter	char *rhs;
592238032Speter{
592338032Speter	register STAB *s;
592438032Speter
592538032Speter	s = stab(lhs, ST_ALIAS, ST_ENTER);
592638032Speter	s->s_alias = newstr(rhs);
592738032Speter}
592838032Speter
592938032Speter
593038032Speter/*
593138032Speter**  STAB_MAP_OPEN -- initialize (reads data file)
593238032Speter**
593338032Speter**	This is a wierd case -- it is only intended as a fallback for
593438032Speter**	aliases.  For this reason, opens for write (only during a
593538032Speter**	"newaliases") always fails, and opens for read open the
593638032Speter**	actual underlying text file instead of the database.
593738032Speter*/
593838032Speter
593938032Speterbool
594038032Speterstab_map_open(map, mode)
594138032Speter	register MAP *map;
594238032Speter	int mode;
594338032Speter{
594438032Speter	FILE *af;
594564562Sgshapiro	long sff;
594638032Speter	struct stat st;
594738032Speter
594838032Speter	if (tTd(38, 2))
594964562Sgshapiro		dprintf("stab_map_open(%s, %s, %d)\n",
595038032Speter			map->map_mname, map->map_file, mode);
595138032Speter
595238032Speter	mode &= O_ACCMODE;
595338032Speter	if (mode != O_RDONLY)
595438032Speter	{
595538032Speter		errno = EPERM;
595638032Speter		return FALSE;
595738032Speter	}
595838032Speter
595938032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
596064562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
596138032Speter		sff |= SFF_NOWLINK;
596264562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
596338032Speter		sff |= SFF_SAFEDIRPATH;
596438032Speter	af = safefopen(map->map_file, O_RDONLY, 0444, sff);
596538032Speter	if (af == NULL)
596638032Speter		return FALSE;
596738032Speter	readaliases(map, af, FALSE, FALSE);
596838032Speter
596938032Speter	if (fstat(fileno(af), &st) >= 0)
597038032Speter		map->map_mtime = st.st_mtime;
597164562Sgshapiro	(void) fclose(af);
597238032Speter
597338032Speter	return TRUE;
597438032Speter}
597538032Speter/*
597638032Speter**  Implicit Modules
597738032Speter**
597838032Speter**	Tries several types.  For back compatibility of aliases.
597938032Speter*/
598038032Speter
598138032Speter
598238032Speter/*
598338032Speter**  IMPL_MAP_LOOKUP -- lookup in best open database
598438032Speter*/
598538032Speter
598638032Speterchar *
598738032Speterimpl_map_lookup(map, name, av, pstat)
598838032Speter	MAP *map;
598938032Speter	char *name;
599038032Speter	char **av;
599138032Speter	int *pstat;
599238032Speter{
599338032Speter	if (tTd(38, 20))
599464562Sgshapiro		dprintf("impl_map_lookup(%s, %s)\n",
599538032Speter			map->map_mname, name);
599638032Speter
599738032Speter#ifdef NEWDB
599838032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
599938032Speter		return db_map_lookup(map, name, av, pstat);
600064562Sgshapiro#endif /* NEWDB */
600138032Speter#ifdef NDBM
600238032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
600338032Speter		return ndbm_map_lookup(map, name, av, pstat);
600464562Sgshapiro#endif /* NDBM */
600538032Speter	return stab_map_lookup(map, name, av, pstat);
600638032Speter}
600738032Speter
600838032Speter/*
600938032Speter**  IMPL_MAP_STORE -- store in open databases
601038032Speter*/
601138032Speter
601238032Spetervoid
601338032Speterimpl_map_store(map, lhs, rhs)
601438032Speter	MAP *map;
601538032Speter	char *lhs;
601638032Speter	char *rhs;
601738032Speter{
601838032Speter	if (tTd(38, 12))
601964562Sgshapiro		dprintf("impl_map_store(%s, %s, %s)\n",
602038032Speter			map->map_mname, lhs, rhs);
602138032Speter#ifdef NEWDB
602238032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
602338032Speter		db_map_store(map, lhs, rhs);
602464562Sgshapiro#endif /* NEWDB */
602538032Speter#ifdef NDBM
602638032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
602738032Speter		ndbm_map_store(map, lhs, rhs);
602864562Sgshapiro#endif /* NDBM */
602938032Speter	stab_map_store(map, lhs, rhs);
603038032Speter}
603138032Speter
603238032Speter/*
603338032Speter**  IMPL_MAP_OPEN -- implicit database open
603438032Speter*/
603538032Speter
603638032Speterbool
603738032Speterimpl_map_open(map, mode)
603838032Speter	MAP *map;
603938032Speter	int mode;
604038032Speter{
604138032Speter	if (tTd(38, 2))
604264562Sgshapiro		dprintf("impl_map_open(%s, %s, %d)\n",
604338032Speter			map->map_mname, map->map_file, mode);
604438032Speter
604538032Speter	mode &= O_ACCMODE;
604638032Speter#ifdef NEWDB
604738032Speter	map->map_mflags |= MF_IMPL_HASH;
604838032Speter	if (hash_map_open(map, mode))
604938032Speter	{
605038032Speter# ifdef NDBM_YP_COMPAT
605138032Speter		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
605264562Sgshapiro# endif /* NDBM_YP_COMPAT */
605338032Speter			return TRUE;
605438032Speter	}
605538032Speter	else
605638032Speter		map->map_mflags &= ~MF_IMPL_HASH;
605764562Sgshapiro#endif /* NEWDB */
605838032Speter#ifdef NDBM
605938032Speter	map->map_mflags |= MF_IMPL_NDBM;
606038032Speter	if (ndbm_map_open(map, mode))
606138032Speter	{
606238032Speter		return TRUE;
606338032Speter	}
606438032Speter	else
606538032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
606664562Sgshapiro#endif /* NDBM */
606738032Speter
606838032Speter#if defined(NEWDB) || defined(NDBM)
606938032Speter	if (Verbose)
607038032Speter		message("WARNING: cannot open alias database %s%s",
607138032Speter			map->map_file,
607238032Speter			mode == O_RDONLY ? "; reading text version" : "");
607364562Sgshapiro#else /* defined(NEWDB) || defined(NDBM) */
607438032Speter	if (mode != O_RDONLY)
607538032Speter		usrerr("Cannot rebuild aliases: no database format defined");
607664562Sgshapiro#endif /* defined(NEWDB) || defined(NDBM) */
607738032Speter
607838032Speter	if (mode == O_RDONLY)
607938032Speter		return stab_map_open(map, mode);
608038032Speter	else
608138032Speter		return FALSE;
608238032Speter}
608338032Speter
608438032Speter
608538032Speter/*
608638032Speter**  IMPL_MAP_CLOSE -- close any open database(s)
608738032Speter*/
608838032Speter
608938032Spetervoid
609038032Speterimpl_map_close(map)
609138032Speter	MAP *map;
609238032Speter{
609338032Speter	if (tTd(38, 9))
609464562Sgshapiro		dprintf("impl_map_close(%s, %s, %lx)\n",
609538032Speter			map->map_mname, map->map_file, map->map_mflags);
609638032Speter#ifdef NEWDB
609738032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
609838032Speter	{
609938032Speter		db_map_close(map);
610038032Speter		map->map_mflags &= ~MF_IMPL_HASH;
610138032Speter	}
610264562Sgshapiro#endif /* NEWDB */
610338032Speter
610438032Speter#ifdef NDBM
610538032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
610638032Speter	{
610738032Speter		ndbm_map_close(map);
610838032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
610938032Speter	}
611064562Sgshapiro#endif /* NDBM */
611138032Speter}
611238032Speter/*
611338032Speter**  User map class.
611438032Speter**
611538032Speter**	Provides access to the system password file.
611638032Speter*/
611738032Speter
611838032Speter/*
611938032Speter**  USER_MAP_OPEN -- open user map
612038032Speter**
612138032Speter**	Really just binds field names to field numbers.
612238032Speter*/
612338032Speter
612438032Speterbool
612538032Speteruser_map_open(map, mode)
612638032Speter	MAP *map;
612738032Speter	int mode;
612838032Speter{
612938032Speter	if (tTd(38, 2))
613064562Sgshapiro		dprintf("user_map_open(%s, %d)\n",
613138032Speter			map->map_mname, mode);
613238032Speter
613338032Speter	mode &= O_ACCMODE;
613438032Speter	if (mode != O_RDONLY)
613538032Speter	{
613638032Speter		/* issue a pseudo-error message */
613738032Speter#ifdef ENOSYS
613838032Speter		errno = ENOSYS;
613964562Sgshapiro#else /* ENOSYS */
614038032Speter# ifdef EFTYPE
614138032Speter		errno = EFTYPE;
614264562Sgshapiro# else /* EFTYPE */
614338032Speter		errno = ENXIO;
614464562Sgshapiro# endif /* EFTYPE */
614564562Sgshapiro#endif /* ENOSYS */
614638032Speter		return FALSE;
614738032Speter	}
614838032Speter	if (map->map_valcolnm == NULL)
614964562Sgshapiro		/* EMPTY */
615038032Speter		/* nothing */ ;
615138032Speter	else if (strcasecmp(map->map_valcolnm, "name") == 0)
615238032Speter		map->map_valcolno = 1;
615338032Speter	else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
615438032Speter		map->map_valcolno = 2;
615538032Speter	else if (strcasecmp(map->map_valcolnm, "uid") == 0)
615638032Speter		map->map_valcolno = 3;
615738032Speter	else if (strcasecmp(map->map_valcolnm, "gid") == 0)
615838032Speter		map->map_valcolno = 4;
615938032Speter	else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
616038032Speter		map->map_valcolno = 5;
616138032Speter	else if (strcasecmp(map->map_valcolnm, "dir") == 0)
616238032Speter		map->map_valcolno = 6;
616338032Speter	else if (strcasecmp(map->map_valcolnm, "shell") == 0)
616438032Speter		map->map_valcolno = 7;
616538032Speter	else
616638032Speter	{
616738032Speter		syserr("User map %s: unknown column name %s",
616838032Speter			map->map_mname, map->map_valcolnm);
616938032Speter		return FALSE;
617038032Speter	}
617138032Speter	return TRUE;
617238032Speter}
617338032Speter
617438032Speter
617538032Speter/*
617638032Speter**  USER_MAP_LOOKUP -- look up a user in the passwd file.
617738032Speter*/
617838032Speter
617938032Speter/* ARGSUSED3 */
618038032Speterchar *
618138032Speteruser_map_lookup(map, key, av, statp)
618238032Speter	MAP *map;
618338032Speter	char *key;
618438032Speter	char **av;
618538032Speter	int *statp;
618638032Speter{
618738032Speter	struct passwd *pw;
618838032Speter	auto bool fuzzy;
618938032Speter
619038032Speter	if (tTd(38, 20))
619164562Sgshapiro		dprintf("user_map_lookup(%s, %s)\n",
619238032Speter			map->map_mname, key);
619338032Speter
619438032Speter	pw = finduser(key, &fuzzy);
619538032Speter	if (pw == NULL)
619638032Speter		return NULL;
619738032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
619838032Speter		return map_rewrite(map, key, strlen(key), NULL);
619938032Speter	else
620038032Speter	{
620138032Speter		char *rwval = NULL;
620238032Speter		char buf[30];
620338032Speter
620438032Speter		switch (map->map_valcolno)
620538032Speter		{
620638032Speter		  case 0:
620738032Speter		  case 1:
620838032Speter			rwval = pw->pw_name;
620938032Speter			break;
621038032Speter
621138032Speter		  case 2:
621238032Speter			rwval = pw->pw_passwd;
621338032Speter			break;
621438032Speter
621538032Speter		  case 3:
621664562Sgshapiro			snprintf(buf, sizeof buf, "%d", (int) pw->pw_uid);
621738032Speter			rwval = buf;
621838032Speter			break;
621938032Speter
622038032Speter		  case 4:
622164562Sgshapiro			snprintf(buf, sizeof buf, "%d", (int) pw->pw_gid);
622238032Speter			rwval = buf;
622338032Speter			break;
622438032Speter
622538032Speter		  case 5:
622638032Speter			rwval = pw->pw_gecos;
622738032Speter			break;
622838032Speter
622938032Speter		  case 6:
623038032Speter			rwval = pw->pw_dir;
623138032Speter			break;
623238032Speter
623338032Speter		  case 7:
623438032Speter			rwval = pw->pw_shell;
623538032Speter			break;
623638032Speter		}
623738032Speter		return map_rewrite(map, rwval, strlen(rwval), av);
623838032Speter	}
623938032Speter}
624038032Speter/*
624138032Speter**  Program map type.
624238032Speter**
624338032Speter**	This provides access to arbitrary programs.  It should be used
624438032Speter**	only very sparingly, since there is no way to bound the cost
624538032Speter**	of invoking an arbitrary program.
624638032Speter*/
624738032Speter
624838032Speterchar *
624938032Speterprog_map_lookup(map, name, av, statp)
625038032Speter	MAP *map;
625138032Speter	char *name;
625238032Speter	char **av;
625338032Speter	int *statp;
625438032Speter{
625538032Speter	int i;
625664562Sgshapiro	int save_errno;
625738032Speter	int fd;
625864562Sgshapiro	int status;
625938032Speter	auto pid_t pid;
626064562Sgshapiro	register char *p;
626138032Speter	char *rval;
626238032Speter	char *argv[MAXPV + 1];
626338032Speter	char buf[MAXLINE];
626438032Speter
626538032Speter	if (tTd(38, 20))
626664562Sgshapiro		dprintf("prog_map_lookup(%s, %s) %s\n",
626738032Speter			map->map_mname, name, map->map_file);
626838032Speter
626938032Speter	i = 0;
627038032Speter	argv[i++] = map->map_file;
627138032Speter	if (map->map_rebuild != NULL)
627238032Speter	{
627338032Speter		snprintf(buf, sizeof buf, "%s", map->map_rebuild);
627438032Speter		for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
627538032Speter		{
627638032Speter			if (i >= MAXPV - 1)
627738032Speter				break;
627838032Speter			argv[i++] = p;
627938032Speter		}
628038032Speter	}
628138032Speter	argv[i++] = name;
628238032Speter	argv[i] = NULL;
628338032Speter	if (tTd(38, 21))
628438032Speter	{
628564562Sgshapiro		dprintf("prog_open:");
628638032Speter		for (i = 0; argv[i] != NULL; i++)
628764562Sgshapiro			dprintf(" %s", argv[i]);
628864562Sgshapiro		dprintf("\n");
628938032Speter	}
629038032Speter	(void) blocksignal(SIGCHLD);
629138032Speter	pid = prog_open(argv, &fd, CurEnv);
629238032Speter	if (pid < 0)
629338032Speter	{
629438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
629538032Speter			syserr("prog_map_lookup(%s) failed (%s) -- closing",
629638032Speter				map->map_mname, errstring(errno));
629738032Speter		else if (tTd(38, 9))
629864562Sgshapiro			dprintf("prog_map_lookup(%s) failed (%s) -- closing",
629938032Speter				map->map_mname, errstring(errno));
630038032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
630138032Speter		*statp = EX_OSFILE;
630238032Speter		return NULL;
630338032Speter	}
630438032Speter	i = read(fd, buf, sizeof buf - 1);
630538032Speter	if (i < 0)
630638032Speter	{
630738032Speter		syserr("prog_map_lookup(%s): read error %s\n",
630838032Speter			map->map_mname, errstring(errno));
630938032Speter		rval = NULL;
631038032Speter	}
631138032Speter	else if (i == 0)
631238032Speter	{
631338032Speter		if (tTd(38, 20))
631464562Sgshapiro			dprintf("prog_map_lookup(%s): empty answer\n",
631538032Speter				map->map_mname);
631638032Speter		rval = NULL;
631738032Speter	}
631838032Speter	else
631938032Speter	{
632038032Speter		buf[i] = '\0';
632138032Speter		p = strchr(buf, '\n');
632238032Speter		if (p != NULL)
632338032Speter			*p = '\0';
632438032Speter
632538032Speter		/* collect the return value */
632638032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
632738032Speter			rval = map_rewrite(map, name, strlen(name), NULL);
632838032Speter		else
632938032Speter			rval = map_rewrite(map, buf, strlen(buf), NULL);
633038032Speter
633138032Speter		/* now flush any additional output */
633238032Speter		while ((i = read(fd, buf, sizeof buf)) > 0)
633338032Speter			continue;
633438032Speter	}
633538032Speter
633638032Speter	/* wait for the process to terminate */
633764562Sgshapiro	(void) close(fd);
633864562Sgshapiro	status = waitfor(pid);
633964562Sgshapiro	save_errno = errno;
634038032Speter	(void) releasesignal(SIGCHLD);
634164562Sgshapiro	errno = save_errno;
634238032Speter
634364562Sgshapiro	if (status == -1)
634438032Speter	{
634538032Speter		syserr("prog_map_lookup(%s): wait error %s\n",
634638032Speter			map->map_mname, errstring(errno));
634738032Speter		*statp = EX_SOFTWARE;
634838032Speter		rval = NULL;
634938032Speter	}
635064562Sgshapiro	else if (WIFEXITED(status))
635138032Speter	{
635264562Sgshapiro		if ((*statp = WEXITSTATUS(status)) != EX_OK)
635338032Speter			rval = NULL;
635438032Speter	}
635538032Speter	else
635638032Speter	{
635738032Speter		syserr("prog_map_lookup(%s): child died on signal %d",
635864562Sgshapiro			map->map_mname, status);
635938032Speter		*statp = EX_UNAVAILABLE;
636038032Speter		rval = NULL;
636138032Speter	}
636238032Speter	return rval;
636338032Speter}
636438032Speter/*
636538032Speter**  Sequenced map type.
636638032Speter**
636738032Speter**	Tries each map in order until something matches, much like
636838032Speter**	implicit.  Stores go to the first map in the list that can
636938032Speter**	support storing.
637038032Speter**
637138032Speter**	This is slightly unusual in that there are two interfaces.
637238032Speter**	The "sequence" interface lets you stack maps arbitrarily.
637338032Speter**	The "switch" interface builds a sequence map by looking
637438032Speter**	at a system-dependent configuration file such as
637538032Speter**	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
637638032Speter**
637738032Speter**	We don't need an explicit open, since all maps are
637838032Speter**	opened during startup, including underlying maps.
637938032Speter*/
638038032Speter
638138032Speter/*
638238032Speter**  SEQ_MAP_PARSE -- Sequenced map parsing
638338032Speter*/
638438032Speter
638538032Speterbool
638638032Speterseq_map_parse(map, ap)
638738032Speter	MAP *map;
638838032Speter	char *ap;
638938032Speter{
639038032Speter	int maxmap;
639138032Speter
639238032Speter	if (tTd(38, 2))
639364562Sgshapiro		dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
639438032Speter	maxmap = 0;
639538032Speter	while (*ap != '\0')
639638032Speter	{
639738032Speter		register char *p;
639838032Speter		STAB *s;
639938032Speter
640038032Speter		/* find beginning of map name */
640138032Speter		while (isascii(*ap) && isspace(*ap))
640238032Speter			ap++;
640364562Sgshapiro		for (p = ap;
640464562Sgshapiro		     (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.';
640564562Sgshapiro		     p++)
640638032Speter			continue;
640738032Speter		if (*p != '\0')
640838032Speter			*p++ = '\0';
640938032Speter		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
641038032Speter			p++;
641138032Speter		if (*ap == '\0')
641238032Speter		{
641338032Speter			ap = p;
641438032Speter			continue;
641538032Speter		}
641638032Speter		s = stab(ap, ST_MAP, ST_FIND);
641738032Speter		if (s == NULL)
641838032Speter		{
641938032Speter			syserr("Sequence map %s: unknown member map %s",
642038032Speter				map->map_mname, ap);
642138032Speter		}
642238032Speter		else if (maxmap == MAXMAPSTACK)
642338032Speter		{
642438032Speter			syserr("Sequence map %s: too many member maps (%d max)",
642538032Speter				map->map_mname, MAXMAPSTACK);
642638032Speter			maxmap++;
642738032Speter		}
642838032Speter		else if (maxmap < MAXMAPSTACK)
642938032Speter		{
643038032Speter			map->map_stack[maxmap++] = &s->s_map;
643138032Speter		}
643238032Speter		ap = p;
643338032Speter	}
643438032Speter	return TRUE;
643538032Speter}
643638032Speter
643738032Speter
643838032Speter/*
643938032Speter**  SWITCH_MAP_OPEN -- open a switched map
644038032Speter**
644138032Speter**	This looks at the system-dependent configuration and builds
644238032Speter**	a sequence map that does the same thing.
644338032Speter**
644438032Speter**	Every system must define a switch_map_find routine in conf.c
644538032Speter**	that will return the list of service types associated with a
644638032Speter**	given service class.
644738032Speter*/
644838032Speter
644938032Speterbool
645038032Speterswitch_map_open(map, mode)
645138032Speter	MAP *map;
645238032Speter	int mode;
645338032Speter{
645438032Speter	int mapno;
645538032Speter	int nmaps;
645638032Speter	char *maptype[MAXMAPSTACK];
645738032Speter
645838032Speter	if (tTd(38, 2))
645964562Sgshapiro		dprintf("switch_map_open(%s, %s, %d)\n",
646038032Speter			map->map_mname, map->map_file, mode);
646138032Speter
646238032Speter	mode &= O_ACCMODE;
646338032Speter	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
646438032Speter	if (tTd(38, 19))
646538032Speter	{
646664562Sgshapiro		dprintf("\tswitch_map_find => %d\n", nmaps);
646738032Speter		for (mapno = 0; mapno < nmaps; mapno++)
646864562Sgshapiro			dprintf("\t\t%s\n", maptype[mapno]);
646938032Speter	}
647038032Speter	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
647138032Speter		return FALSE;
647238032Speter
647338032Speter	for (mapno = 0; mapno < nmaps; mapno++)
647438032Speter	{
647538032Speter		register STAB *s;
647638032Speter		char nbuf[MAXNAME + 1];
647738032Speter
647838032Speter		if (maptype[mapno] == NULL)
647938032Speter			continue;
648038032Speter		(void) snprintf(nbuf, sizeof nbuf, "%s.%s",
648138032Speter			map->map_mname, maptype[mapno]);
648238032Speter		s = stab(nbuf, ST_MAP, ST_FIND);
648338032Speter		if (s == NULL)
648438032Speter		{
648538032Speter			syserr("Switch map %s: unknown member map %s",
648638032Speter				map->map_mname, nbuf);
648738032Speter		}
648838032Speter		else
648938032Speter		{
649038032Speter			map->map_stack[mapno] = &s->s_map;
649138032Speter			if (tTd(38, 4))
649264562Sgshapiro				dprintf("\tmap_stack[%d] = %s:%s\n",
649338032Speter					mapno, s->s_map.map_class->map_cname,
649438032Speter					nbuf);
649538032Speter		}
649638032Speter	}
649738032Speter	return TRUE;
649838032Speter}
649938032Speter
650038032Speter
650138032Speter/*
650238032Speter**  SEQ_MAP_CLOSE -- close all underlying maps
650338032Speter*/
650438032Speter
650538032Spetervoid
650638032Speterseq_map_close(map)
650738032Speter	MAP *map;
650838032Speter{
650938032Speter	int mapno;
651038032Speter
651138032Speter	if (tTd(38, 9))
651264562Sgshapiro		dprintf("seq_map_close(%s)\n", map->map_mname);
651338032Speter
651438032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
651538032Speter	{
651638032Speter		MAP *mm = map->map_stack[mapno];
651738032Speter
651838032Speter		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
651938032Speter			continue;
652038032Speter		mm->map_class->map_close(mm);
652138032Speter		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
652238032Speter	}
652338032Speter}
652438032Speter
652538032Speter
652638032Speter/*
652738032Speter**  SEQ_MAP_LOOKUP -- sequenced map lookup
652838032Speter*/
652938032Speter
653038032Speterchar *
653138032Speterseq_map_lookup(map, key, args, pstat)
653238032Speter	MAP *map;
653338032Speter	char *key;
653438032Speter	char **args;
653538032Speter	int *pstat;
653638032Speter{
653738032Speter	int mapno;
653838032Speter	int mapbit = 0x01;
653938032Speter	bool tempfail = FALSE;
654038032Speter
654138032Speter	if (tTd(38, 20))
654264562Sgshapiro		dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
654338032Speter
654438032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
654538032Speter	{
654638032Speter		MAP *mm = map->map_stack[mapno];
654738032Speter		char *rv;
654838032Speter
654938032Speter		if (mm == NULL)
655038032Speter			continue;
655164562Sgshapiro		if (!bitset(MF_OPEN, mm->map_mflags) &&
655264562Sgshapiro		    !openmap(mm))
655338032Speter		{
655438032Speter			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
655538032Speter			{
655638032Speter				*pstat = EX_UNAVAILABLE;
655738032Speter				return NULL;
655838032Speter			}
655938032Speter			continue;
656038032Speter		}
656138032Speter		*pstat = EX_OK;
656238032Speter		rv = mm->map_class->map_lookup(mm, key, args, pstat);
656338032Speter		if (rv != NULL)
656438032Speter			return rv;
656538032Speter		if (*pstat == EX_TEMPFAIL)
656638032Speter		{
656738032Speter			if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
656838032Speter				return NULL;
656938032Speter			tempfail = TRUE;
657038032Speter		}
657138032Speter		else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
657238032Speter			break;
657338032Speter	}
657438032Speter	if (tempfail)
657538032Speter		*pstat = EX_TEMPFAIL;
657638032Speter	else if (*pstat == EX_OK)
657738032Speter		*pstat = EX_NOTFOUND;
657838032Speter	return NULL;
657938032Speter}
658038032Speter
658138032Speter
658238032Speter/*
658338032Speter**  SEQ_MAP_STORE -- sequenced map store
658438032Speter*/
658538032Speter
658638032Spetervoid
658738032Speterseq_map_store(map, key, val)
658838032Speter	MAP *map;
658938032Speter	char *key;
659038032Speter	char *val;
659138032Speter{
659238032Speter	int mapno;
659338032Speter
659438032Speter	if (tTd(38, 12))
659564562Sgshapiro		dprintf("seq_map_store(%s, %s, %s)\n",
659638032Speter			map->map_mname, key, val);
659738032Speter
659838032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
659938032Speter	{
660038032Speter		MAP *mm = map->map_stack[mapno];
660138032Speter
660238032Speter		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
660338032Speter			continue;
660438032Speter
660538032Speter		mm->map_class->map_store(mm, key, val);
660638032Speter		return;
660738032Speter	}
660838032Speter	syserr("seq_map_store(%s, %s, %s): no writable map",
660938032Speter		map->map_mname, key, val);
661038032Speter}
661138032Speter/*
661238032Speter**  NULL stubs
661338032Speter*/
661438032Speter
661538032Speter/* ARGSUSED */
661638032Speterbool
661738032Speternull_map_open(map, mode)
661838032Speter	MAP *map;
661938032Speter	int mode;
662038032Speter{
662138032Speter	return TRUE;
662238032Speter}
662338032Speter
662438032Speter/* ARGSUSED */
662538032Spetervoid
662638032Speternull_map_close(map)
662738032Speter	MAP *map;
662838032Speter{
662938032Speter	return;
663038032Speter}
663138032Speter
663238032Speterchar *
663338032Speternull_map_lookup(map, key, args, pstat)
663438032Speter	MAP *map;
663538032Speter	char *key;
663638032Speter	char **args;
663738032Speter	int *pstat;
663838032Speter{
663938032Speter	*pstat = EX_NOTFOUND;
664038032Speter	return NULL;
664138032Speter}
664238032Speter
664338032Speter/* ARGSUSED */
664438032Spetervoid
664538032Speternull_map_store(map, key, val)
664638032Speter	MAP *map;
664738032Speter	char *key;
664838032Speter	char *val;
664938032Speter{
665038032Speter	return;
665138032Speter}
665238032Speter
665338032Speter
665438032Speter/*
665538032Speter**  BOGUS stubs
665638032Speter*/
665738032Speter
665838032Speterchar *
665938032Speterbogus_map_lookup(map, key, args, pstat)
666038032Speter	MAP *map;
666138032Speter	char *key;
666238032Speter	char **args;
666338032Speter	int *pstat;
666438032Speter{
666538032Speter	*pstat = EX_TEMPFAIL;
666638032Speter	return NULL;
666738032Speter}
666838032Speter
666938032SpeterMAPCLASS	BogusMapClass =
667038032Speter{
667138032Speter	"bogus-map",		NULL,		0,
667238032Speter	NULL,		bogus_map_lookup,	null_map_store,
667338032Speter	null_map_open,	null_map_close,
667438032Speter};
667538032Speter/*
667664562Sgshapiro**  MACRO modules
667764562Sgshapiro*/
667864562Sgshapiro
667964562Sgshapirochar *
668064562Sgshapiromacro_map_lookup(map, name, av, statp)
668164562Sgshapiro	MAP *map;
668264562Sgshapiro	char *name;
668364562Sgshapiro	char **av;
668464562Sgshapiro	int *statp;
668564562Sgshapiro{
668664562Sgshapiro	int mid;
668764562Sgshapiro
668864562Sgshapiro	if (tTd(38, 20))
668964562Sgshapiro		dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
669064562Sgshapiro			name == NULL ? "NULL" : name);
669164562Sgshapiro
669264562Sgshapiro	if (name == NULL ||
669364562Sgshapiro	    *name == '\0' ||
669464562Sgshapiro	    (mid = macid(name, NULL)) == '\0')
669564562Sgshapiro	{
669664562Sgshapiro		*statp = EX_CONFIG;
669764562Sgshapiro		return NULL;
669864562Sgshapiro	}
669964562Sgshapiro
670064562Sgshapiro	if (av[1] == NULL)
670164562Sgshapiro		define(mid, NULL, CurEnv);
670264562Sgshapiro	else
670364562Sgshapiro		define(mid, newstr(av[1]), CurEnv);
670464562Sgshapiro
670564562Sgshapiro	*statp = EX_OK;
670664562Sgshapiro	return "";
670764562Sgshapiro}
670864562Sgshapiro/*
670938032Speter**  REGEX modules
671038032Speter*/
671138032Speter
671238032Speter#ifdef MAP_REGEX
671338032Speter
671438032Speter# include <regex.h>
671538032Speter
671638032Speter# define DEFAULT_DELIM	CONDELSE
671738032Speter
671838032Speter# define END_OF_FIELDS	-1
671938032Speter
672038032Speter# define ERRBUF_SIZE	80
672138032Speter# define MAX_MATCH	32
672238032Speter
672364562Sgshapiro# define xnalloc(s)	memset(xalloc(s), '\0', s);
672438032Speter
672538032Speterstruct regex_map
672638032Speter{
672771345Sgshapiro	regex_t	*regex_pattern_buf;	/* xalloc it */
672838032Speter	int	*regex_subfields;	/* move to type MAP */
672964562Sgshapiro	char	*regex_delim;		/* move to type MAP */
673038032Speter};
673138032Speter
673238032Speterstatic int
673338032Speterparse_fields(s, ibuf, blen, nr_substrings)
673438032Speter	char *s;
673538032Speter	int *ibuf;		/* array */
673638032Speter	int blen;		/* number of elements in ibuf */
673738032Speter	int nr_substrings;	/* number of substrings in the pattern */
673838032Speter{
673938032Speter	register char *cp;
674038032Speter	int i = 0;
674138032Speter	bool lastone = FALSE;
674238032Speter
674338032Speter	blen--;		/* for terminating END_OF_FIELDS */
674438032Speter	cp = s;
674538032Speter	do
674638032Speter	{
674738032Speter		for (;; cp++)
674838032Speter		{
674938032Speter			if (*cp == ',')
675038032Speter			{
675138032Speter				*cp = '\0';
675238032Speter				break;
675338032Speter			}
675438032Speter			if (*cp == '\0')
675538032Speter			{
675638032Speter				lastone = TRUE;
675738032Speter				break;
675838032Speter			}
675938032Speter		}
676038032Speter		if (i < blen)
676138032Speter		{
676238032Speter			int val = atoi(s);
676338032Speter
676438032Speter			if (val < 0 || val >= nr_substrings)
676538032Speter			{
676638032Speter				syserr("field (%d) out of range, only %d substrings in pattern",
676738032Speter				       val, nr_substrings);
676838032Speter				return -1;
676938032Speter			}
677038032Speter			ibuf[i++] = val;
677138032Speter		}
677238032Speter		else
677338032Speter		{
677438032Speter			syserr("too many fields, %d max\n", blen);
677538032Speter			return -1;
677638032Speter		}
677738032Speter		s = ++cp;
677838032Speter	} while (!lastone);
677938032Speter	ibuf[i] = END_OF_FIELDS;
678038032Speter	return i;
678138032Speter}
678238032Speter
678338032Speterbool
678438032Speterregex_map_init(map, ap)
678538032Speter	MAP *map;
678638032Speter	char *ap;
678738032Speter{
678838032Speter	int regerr;
678938032Speter	struct regex_map *map_p;
679038032Speter	register char *p;
679138032Speter	char *sub_param = NULL;
679238032Speter	int pflags;
679338032Speter	static char defdstr[] = { (char)DEFAULT_DELIM, '\0' };
679438032Speter
679538032Speter	if (tTd(38, 2))
679664562Sgshapiro		dprintf("regex_map_init: mapname '%s', args '%s'\n",
679764562Sgshapiro			map->map_mname, ap);
679838032Speter
679938032Speter	pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
680038032Speter
680138032Speter	p = ap;
680238032Speter
680364562Sgshapiro	map_p = (struct regex_map *) xnalloc(sizeof *map_p);
680471345Sgshapiro	map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t));
680538032Speter
680638032Speter	for (;;)
680764562Sgshapiro	{
680838032Speter		while (isascii(*p) && isspace(*p))
680938032Speter			p++;
681038032Speter		if (*p != '-')
681138032Speter			break;
681238032Speter		switch (*++p)
681338032Speter		{
681438032Speter		  case 'n':	/* not */
681538032Speter			map->map_mflags |= MF_REGEX_NOT;
681638032Speter			break;
681738032Speter
681838032Speter		  case 'f':	/* case sensitive */
681938032Speter			map->map_mflags |= MF_NOFOLDCASE;
682038032Speter			pflags &= ~REG_ICASE;
682138032Speter			break;
682238032Speter
682338032Speter		  case 'b':	/* basic regular expressions */
682438032Speter			pflags &= ~REG_EXTENDED;
682538032Speter			break;
682638032Speter
682738032Speter		  case 's':	/* substring match () syntax */
682838032Speter			sub_param = ++p;
682938032Speter			pflags &= ~REG_NOSUB;
683038032Speter			break;
683138032Speter
683238032Speter		  case 'd':	/* delimiter */
683364562Sgshapiro			map_p->regex_delim = ++p;
683438032Speter			break;
683538032Speter
683638032Speter		  case 'a':	/* map append */
683738032Speter			map->map_app = ++p;
683838032Speter			break;
683938032Speter
684038032Speter		  case 'm':	/* matchonly */
684138032Speter			map->map_mflags |= MF_MATCHONLY;
684238032Speter			break;
684338032Speter
684464562Sgshapiro		  case 'S':
684564562Sgshapiro			map->map_spacesub = *++p;
684664562Sgshapiro			break;
684764562Sgshapiro
684864562Sgshapiro		  case 'D':
684964562Sgshapiro			map->map_mflags |= MF_DEFER;
685064562Sgshapiro			break;
685164562Sgshapiro
685238032Speter		}
685364562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
685464562Sgshapiro			p++;
685564562Sgshapiro		if (*p != '\0')
685664562Sgshapiro			*p++ = '\0';
685738032Speter	}
685838032Speter	if (tTd(38, 3))
685964562Sgshapiro		dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
686038032Speter
686171345Sgshapiro	if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0)
686238032Speter	{
686338032Speter		/* Errorhandling */
686438032Speter		char errbuf[ERRBUF_SIZE];
686538032Speter
686671345Sgshapiro		(void) regerror(regerr, map_p->regex_pattern_buf,
686764562Sgshapiro			 errbuf, ERRBUF_SIZE);
686838032Speter		syserr("pattern-compile-error: %s\n", errbuf);
686971345Sgshapiro		free(map_p->regex_pattern_buf);
687038032Speter		free(map_p);
687138032Speter		return FALSE;
687238032Speter	}
687338032Speter
687438032Speter	if (map->map_app != NULL)
687538032Speter		map->map_app = newstr(map->map_app);
687664562Sgshapiro	if (map_p->regex_delim != NULL)
687764562Sgshapiro		map_p->regex_delim = newstr(map_p->regex_delim);
687838032Speter	else
687964562Sgshapiro		map_p->regex_delim = defdstr;
688038032Speter
688138032Speter	if (!bitset(REG_NOSUB, pflags))
688238032Speter	{
688338032Speter		/* substring matching */
688438032Speter		int substrings;
688564562Sgshapiro		int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1));
688638032Speter
688771345Sgshapiro		substrings = map_p->regex_pattern_buf->re_nsub + 1;
688838032Speter
688938032Speter		if (tTd(38, 3))
689064562Sgshapiro			dprintf("regex_map_init: nr of substrings %d\n",
689164562Sgshapiro				substrings);
689238032Speter
689338032Speter		if (substrings >= MAX_MATCH)
689438032Speter		{
689538032Speter			syserr("too many substrings, %d max\n", MAX_MATCH);
689671345Sgshapiro			free(map_p->regex_pattern_buf);
689738032Speter			free(map_p);
689838032Speter			return FALSE;
689938032Speter		}
690038032Speter		if (sub_param != NULL && sub_param[0] != '\0')
690138032Speter		{
690238032Speter			/* optional parameter -sfields */
690338032Speter			if (parse_fields(sub_param, fields,
690438032Speter					 MAX_MATCH + 1, substrings) == -1)
690538032Speter				return FALSE;
690638032Speter		}
690738032Speter		else
690838032Speter		{
690964562Sgshapiro			/* set default fields */
691038032Speter			int i;
691138032Speter
691238032Speter			for (i = 0; i < substrings; i++)
691338032Speter				fields[i] = i;
691438032Speter			fields[i] = END_OF_FIELDS;
691538032Speter		}
691638032Speter		map_p->regex_subfields = fields;
691738032Speter		if (tTd(38, 3))
691838032Speter		{
691938032Speter			int *ip;
692038032Speter
692164562Sgshapiro			dprintf("regex_map_init: subfields");
692238032Speter			for (ip = fields; *ip != END_OF_FIELDS; ip++)
692364562Sgshapiro				dprintf(" %d", *ip);
692464562Sgshapiro			dprintf("\n");
692538032Speter		}
692638032Speter	}
692738032Speter	map->map_db1 = (ARBPTR_T)map_p;	/* dirty hack */
692838032Speter
692938032Speter	return TRUE;
693038032Speter}
693138032Speter
693238032Speterstatic char *
693338032Speterregex_map_rewrite(map, s, slen, av)
693438032Speter	MAP *map;
693538032Speter	const char *s;
693638032Speter	size_t slen;
693738032Speter	char **av;
693838032Speter{
693938032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
694038032Speter		return map_rewrite(map, av[0], strlen(av[0]), NULL);
694138032Speter	else
694238032Speter		return map_rewrite(map, s, slen, NULL);
694338032Speter}
694438032Speter
694538032Speterchar *
694638032Speterregex_map_lookup(map, name, av, statp)
694738032Speter	MAP *map;
694838032Speter	char *name;
694938032Speter	char **av;
695038032Speter	int *statp;
695138032Speter{
695238032Speter	int reg_res;
695338032Speter	struct regex_map *map_p;
695438032Speter	regmatch_t pmatch[MAX_MATCH];
695538032Speter
695638032Speter	if (tTd(38, 20))
695738032Speter	{
695838032Speter		char **cpp;
695938032Speter
696064562Sgshapiro		dprintf("regex_map_lookup: key '%s'\n", name);
696164562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
696264562Sgshapiro			dprintf("regex_map_lookup: arg '%s'\n", *cpp);
696338032Speter	}
696438032Speter
696538032Speter	map_p = (struct regex_map *)(map->map_db1);
696671345Sgshapiro	reg_res = regexec(map_p->regex_pattern_buf,
696764562Sgshapiro			  name, MAX_MATCH, pmatch, 0);
696838032Speter
696938032Speter	if (bitset(MF_REGEX_NOT, map->map_mflags))
697038032Speter	{
697138032Speter		/* option -n */
697238032Speter		if (reg_res == REG_NOMATCH)
697338032Speter			return regex_map_rewrite(map, "", (size_t)0, av);
697438032Speter		else
697538032Speter			return NULL;
697638032Speter	}
697738032Speter	if (reg_res == REG_NOMATCH)
697838032Speter		return NULL;
697938032Speter
698038032Speter	if (map_p->regex_subfields != NULL)
698138032Speter	{
698238032Speter		/* option -s */
698338032Speter		static char retbuf[MAXNAME];
698438032Speter		int fields[MAX_MATCH + 1];
698538032Speter		bool first = TRUE;
698638032Speter		int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
698738032Speter		bool quotemode = FALSE, bslashmode = FALSE;
698838032Speter		register char *dp, *sp;
698938032Speter		char *endp, *ldp;
699038032Speter		int *ip;
699138032Speter
699238032Speter		dp = retbuf;
699338032Speter		ldp = retbuf + sizeof(retbuf) - 1;
699438032Speter
699538032Speter		if (av[1] != NULL)
699638032Speter		{
699738032Speter			if (parse_fields(av[1], fields, MAX_MATCH + 1,
699871345Sgshapiro					 (int) map_p->regex_pattern_buf->re_nsub + 1) == -1)
699938032Speter			{
700038032Speter				*statp = EX_CONFIG;
700138032Speter				return NULL;
700238032Speter			}
700338032Speter			ip = fields;
700438032Speter		}
700538032Speter		else
700638032Speter			ip = map_p->regex_subfields;
700738032Speter
700838032Speter		for ( ; *ip != END_OF_FIELDS; ip++)
700938032Speter		{
701038032Speter			if (!first)
701138032Speter			{
701264562Sgshapiro				for (sp = map_p->regex_delim; *sp; sp++)
701338032Speter				{
701438032Speter					if (dp < ldp)
701538032Speter						*dp++ = *sp;
701638032Speter				}
701738032Speter			}
701838032Speter			else
701938032Speter				first = FALSE;
702038032Speter
702138032Speter
702271345Sgshapiro			if (*ip >= MAX_MATCH ||
702371345Sgshapiro			    pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
702438032Speter				continue;
702538032Speter
702638032Speter			sp = name + pmatch[*ip].rm_so;
702738032Speter			endp = name + pmatch[*ip].rm_eo;
702838032Speter			for (; endp > sp; sp++)
702938032Speter			{
703038032Speter				if (dp < ldp)
703138032Speter				{
703264562Sgshapiro					if (bslashmode)
703364562Sgshapiro					{
703438032Speter						*dp++ = *sp;
703538032Speter						bslashmode = FALSE;
703638032Speter					}
703764562Sgshapiro					else if (quotemode && *sp != '"' &&
703838032Speter						*sp != '\\')
703938032Speter					{
704038032Speter						*dp++ = *sp;
704138032Speter					}
704238032Speter					else switch(*dp++ = *sp)
704338032Speter					{
704438032Speter						case '\\':
704538032Speter						bslashmode = TRUE;
704638032Speter						break;
704738032Speter
704838032Speter						case '(':
704938032Speter						cmntcnt++;
705038032Speter						break;
705138032Speter
705238032Speter						case ')':
705338032Speter						cmntcnt--;
705438032Speter						break;
705538032Speter
705638032Speter						case '<':
705738032Speter						anglecnt++;
705838032Speter						break;
705938032Speter
706038032Speter						case '>':
706138032Speter						anglecnt--;
706238032Speter						break;
706338032Speter
706438032Speter						case ' ':
706538032Speter						spacecnt++;
706638032Speter						break;
706738032Speter
706838032Speter						case '"':
706938032Speter						quotemode = !quotemode;
707038032Speter						break;
707138032Speter					}
707238032Speter				}
707338032Speter			}
707438032Speter		}
707538032Speter		if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
707638032Speter		    bslashmode || spacecnt != 0)
707738032Speter		{
707864562Sgshapiro			sm_syslog(LOG_WARNING, NOQID,
707964562Sgshapiro				  "Warning: regex may cause prescan() failure map=%s lookup=%s",
708064562Sgshapiro				  map->map_mname, name);
708138032Speter			return NULL;
708238032Speter		}
708338032Speter
708438032Speter		*dp = '\0';
708538032Speter
708638032Speter		return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
708738032Speter	}
708838032Speter	return regex_map_rewrite(map, "", (size_t)0, av);
708938032Speter}
709038032Speter#endif /* MAP_REGEX */
709164562Sgshapiro/*
709264562Sgshapiro**  NSD modules
709364562Sgshapiro*/
709464562Sgshapiro#ifdef MAP_NSD
709564562Sgshapiro
709664562Sgshapiro# include <ndbm.h>
709764562Sgshapiro# define _DATUM_DEFINED
709864562Sgshapiro# include <ns_api.h>
709964562Sgshapiro
710064562Sgshapirotypedef struct ns_map_list
710164562Sgshapiro{
710264562Sgshapiro	ns_map_t *map;
710364562Sgshapiro	char *mapname;
710464562Sgshapiro	struct ns_map_list *next;
710564562Sgshapiro} ns_map_list_t;
710664562Sgshapiro
710764562Sgshapirostatic ns_map_t *
710864562Sgshapirons_map_t_find(mapname)
710964562Sgshapiro	char *mapname;
711064562Sgshapiro{
711164562Sgshapiro	static ns_map_list_t *ns_maps = NULL;
711264562Sgshapiro	ns_map_list_t *ns_map;
711364562Sgshapiro
711464562Sgshapiro	/* walk the list of maps looking for the correctly named map */
711564562Sgshapiro	for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next)
711664562Sgshapiro	{
711764562Sgshapiro		if (strcmp(ns_map->mapname, mapname) == 0)
711864562Sgshapiro			break;
711964562Sgshapiro	}
712064562Sgshapiro
712164562Sgshapiro	/* if we are looking at a NULL ns_map_list_t, then create a new one */
712264562Sgshapiro	if (ns_map == NULL)
712364562Sgshapiro	{
712464562Sgshapiro		ns_map = (ns_map_list_t *) xalloc(sizeof *ns_map);
712564562Sgshapiro		ns_map->mapname = newstr(mapname);
712664562Sgshapiro		ns_map->map = (ns_map_t *) xalloc(sizeof *ns_map->map);
712764562Sgshapiro		ns_map->next = ns_maps;
712864562Sgshapiro		ns_maps = ns_map;
712964562Sgshapiro	}
713064562Sgshapiro	return ns_map->map;
713164562Sgshapiro}
713264562Sgshapiro
713364562Sgshapirochar *
713464562Sgshapironsd_map_lookup(map, name, av, statp)
713564562Sgshapiro	MAP *map;
713664562Sgshapiro	char *name;
713764562Sgshapiro	char **av;
713864562Sgshapiro	int *statp;
713964562Sgshapiro{
714071345Sgshapiro	int buflen, r;
714164562Sgshapiro	char *p;
714264562Sgshapiro	ns_map_t *ns_map;
714364562Sgshapiro	char keybuf[MAXNAME + 1];
714464562Sgshapiro	char buf[MAXLINE];
714564562Sgshapiro
714664562Sgshapiro	if (tTd(38, 20))
714764562Sgshapiro		dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
714864562Sgshapiro
714964562Sgshapiro	buflen = strlen(name);
715064562Sgshapiro	if (buflen > sizeof keybuf - 1)
715164562Sgshapiro		buflen = sizeof keybuf - 1;
715264562Sgshapiro	memmove(keybuf, name, buflen);
715364562Sgshapiro	keybuf[buflen] = '\0';
715464562Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
715564562Sgshapiro		makelower(keybuf);
715664562Sgshapiro
715764562Sgshapiro	ns_map = ns_map_t_find(map->map_file);
715864562Sgshapiro	if (ns_map == NULL)
715964562Sgshapiro	{
716064562Sgshapiro		if (tTd(38, 20))
716164562Sgshapiro			dprintf("nsd_map_t_find failed\n");
716271345Sgshapiro		*statp = EX_UNAVAILABLE;
716364562Sgshapiro		return NULL;
716464562Sgshapiro	}
716571345Sgshapiro	r = ns_lookup(ns_map, NULL, map->map_file, keybuf, NULL, buf, MAXLINE);
716671345Sgshapiro	if (r == NS_UNAVAIL || r == NS_TRYAGAIN)
716771345Sgshapiro	{
716871345Sgshapiro		*statp = EX_TEMPFAIL;
716964562Sgshapiro		return NULL;
717071345Sgshapiro	}
717171345Sgshapiro	if (r == NS_BADREQ || r == NS_NOPERM)
717271345Sgshapiro	{
717371345Sgshapiro		*statp = EX_CONFIG;
717471345Sgshapiro		return NULL;
717571345Sgshapiro	}
717671345Sgshapiro	if (r != NS_SUCCESS)
717771345Sgshapiro	{
717871345Sgshapiro		*statp = EX_NOTFOUND;
717971345Sgshapiro		return NULL;
718071345Sgshapiro	}
718164562Sgshapiro
718271345Sgshapiro	*statp = EX_OK;
718371345Sgshapiro
718464562Sgshapiro	/* Null out trailing \n */
718564562Sgshapiro	if ((p = strchr(buf, '\n')) != NULL)
718664562Sgshapiro		*p = '\0';
718764562Sgshapiro
718864562Sgshapiro	return map_rewrite(map, buf, strlen(buf), av);
718964562Sgshapiro}
719064562Sgshapiro#endif /* MAP_NSD */
719164562Sgshapiro
719264562Sgshapirochar *
719364562Sgshapiroarith_map_lookup(map, name, av, statp)
719464562Sgshapiro	MAP *map;
719564562Sgshapiro	char *name;
719664562Sgshapiro	char **av;
719764562Sgshapiro	int *statp;
719864562Sgshapiro{
719964562Sgshapiro	long r;
720064562Sgshapiro	long v[2];
720164562Sgshapiro	bool res = FALSE;
720264562Sgshapiro	bool boolres;
720364562Sgshapiro	static char result[16];
720464562Sgshapiro	char **cpp;
720564562Sgshapiro
720664562Sgshapiro	if (tTd(38, 2))
720764562Sgshapiro	{
720864562Sgshapiro		dprintf("arith_map_lookup: key '%s'\n", name);
720964562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
721064562Sgshapiro			dprintf("arith_map_lookup: arg '%s'\n", *cpp);
721164562Sgshapiro	}
721264562Sgshapiro	r = 0;
721364562Sgshapiro	boolres = FALSE;
721464562Sgshapiro	cpp = av;
721564562Sgshapiro	*statp = EX_OK;
721664562Sgshapiro
721764562Sgshapiro	/*
721864562Sgshapiro	**  read arguments for arith map
721964562Sgshapiro	**  - no check is made whether they are really numbers
722064562Sgshapiro	**  - just ignores args after the second
722164562Sgshapiro	*/
722264562Sgshapiro	for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
722364562Sgshapiro		v[r++] = strtol(*cpp, NULL, 0);
722464562Sgshapiro
722564562Sgshapiro	/* operator and (at least) two operands given? */
722664562Sgshapiro	if (name != NULL && r == 2)
722764562Sgshapiro	{
722864562Sgshapiro		switch(*name)
722964562Sgshapiro		{
723064562Sgshapiro#if _FFR_ARITH
723164562Sgshapiro		  case '|':
723264562Sgshapiro			r = v[0] | v[1];
723364562Sgshapiro			break;
723464562Sgshapiro
723564562Sgshapiro		  case '&':
723664562Sgshapiro			r = v[0] & v[1];
723764562Sgshapiro			break;
723864562Sgshapiro
723964562Sgshapiro		  case '%':
724064562Sgshapiro			if (v[1] == 0)
724164562Sgshapiro				return NULL;
724264562Sgshapiro			r = v[0] % v[1];
724364562Sgshapiro			break;
724464562Sgshapiro#endif /* _FFR_ARITH */
724564562Sgshapiro
724664562Sgshapiro		  case '+':
724764562Sgshapiro			r = v[0] + v[1];
724864562Sgshapiro			break;
724964562Sgshapiro
725064562Sgshapiro		  case '-':
725164562Sgshapiro			r = v[0] - v[1];
725264562Sgshapiro			break;
725364562Sgshapiro
725464562Sgshapiro		  case '*':
725564562Sgshapiro			r = v[0] * v[1];
725664562Sgshapiro			break;
725764562Sgshapiro
725864562Sgshapiro		  case '/':
725964562Sgshapiro			if (v[1] == 0)
726064562Sgshapiro				return NULL;
726164562Sgshapiro			r = v[0] / v[1];
726264562Sgshapiro			break;
726364562Sgshapiro
726464562Sgshapiro		  case 'l':
726564562Sgshapiro			res = v[0] < v[1];
726664562Sgshapiro			boolres = TRUE;
726764562Sgshapiro			break;
726864562Sgshapiro
726964562Sgshapiro		  case '=':
727064562Sgshapiro			res = v[0] == v[1];
727164562Sgshapiro			boolres = TRUE;
727264562Sgshapiro			break;
727364562Sgshapiro
727464562Sgshapiro		  default:
727564562Sgshapiro			/* XXX */
727664562Sgshapiro			*statp = EX_CONFIG;
727764562Sgshapiro			if (LogLevel > 10)
727864562Sgshapiro				sm_syslog(LOG_WARNING, NOQID,
727964562Sgshapiro					  "arith_map: unknown operator %c",
728064562Sgshapiro					  isprint(*name) ? *name : '?');
728164562Sgshapiro			return NULL;
728264562Sgshapiro		}
728364562Sgshapiro		if (boolres)
728464562Sgshapiro			snprintf(result, sizeof result, res ? "TRUE" : "FALSE");
728564562Sgshapiro		else
728664562Sgshapiro			snprintf(result, sizeof result, "%ld", r);
728764562Sgshapiro		return result;
728864562Sgshapiro	}
728964562Sgshapiro	*statp = EX_CONFIG;
729064562Sgshapiro	return NULL;
729164562Sgshapiro}
7292