138032Speter/*
2261194Sgshapiro * Copyright (c) 1998-2008 Proofpoint, 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
1464562Sgshapiro#include <sendmail.h>
1538032Speter
16266527SgshapiroSM_RCSID("@(#)$Id: map.c,v 8.713 2013-11-22 20:51:55 ca Exp $")
1764562Sgshapiro
1890792Sgshapiro#if LDAPMAP
1990792Sgshapiro# include <sm/ldap.h>
20363466Sgshapiro#endif
2190792Sgshapiro
2290792Sgshapiro#if NDBM
2338032Speter# include <ndbm.h>
2438032Speter# ifdef R_FIRST
2538032Speter  ERROR README:	You are running the Berkeley DB version of ndbm.h.  See
2638032Speter  ERROR README:	the README file about tweaking Berkeley DB so it can
2738032Speter  ERROR README:	coexist with NDBM, or delete -DNDBM from the Makefile
2838032Speter  ERROR README: and use -DNEWDB instead.
2964562Sgshapiro# endif /* R_FIRST */
3064562Sgshapiro#endif /* NDBM */
3190792Sgshapiro#if NEWDB
32110560Sgshapiro# include "sm/bdb.h"
33363466Sgshapiro#endif
3490792Sgshapiro#if NIS
3538032Speter  struct dom_binding;	/* forward reference needed on IRIX */
3638032Speter# include <rpcsvc/ypclnt.h>
3790792Sgshapiro# if NDBM
3838032Speter#  define NDBM_YP_COMPAT	/* create YP-compatible NDBM files */
39363466Sgshapiro# endif
4064562Sgshapiro#endif /* NIS */
41363466Sgshapiro#if CDB
42363466Sgshapiro# include <cdb.h>
43363466Sgshapiro#endif
4438032Speter
45168515Sgshapiro#include "map.h"
46168515Sgshapiro
4790792Sgshapiro#if NEWDB
4864562Sgshapiro# if DB_VERSION_MAJOR < 2
4964562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
50363466Sgshapiro# endif
5164562Sgshapiro# if DB_VERSION_MAJOR == 2
5264562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
53363466Sgshapiro# endif
5464562Sgshapiro# if DB_VERSION_MAJOR > 2
5564562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, void **));
56363466Sgshapiro# endif
5764562Sgshapiro#endif /* NEWDB */
5873188Sgshapirostatic bool	extract_canonname __P((char *, char *, char *, char[], int));
5990792Sgshapirostatic void	map_close __P((STAB *, int));
6090792Sgshapirostatic void	map_init __P((STAB *, int));
6164562Sgshapiro#ifdef LDAPMAP
6290792Sgshapirostatic STAB *	ldapmap_findconn __P((SM_LDAP_STRUCT *));
63363466Sgshapiro#endif
6490792Sgshapiro#if NISPLUS
6564562Sgshapirostatic bool	nisplus_getcanonname __P((char *, int, int *));
66363466Sgshapiro#endif
6790792Sgshapiro#if NIS
6864562Sgshapirostatic bool	nis_getcanonname __P((char *, int, int *));
69363466Sgshapiro#endif
7064562Sgshapiro#if NETINFO
7164562Sgshapirostatic bool	ni_getcanonname __P((char *, int, int *));
72363466Sgshapiro#endif
7364562Sgshapirostatic bool	text_getcanonname __P((char *, int, int *));
74132943Sgshapiro#if SOCKETMAP
75132943Sgshapirostatic STAB	*socket_map_findconn __P((const char*));
7664562Sgshapiro
77132943Sgshapiro/* XXX arbitrary limit for sanity */
78132943Sgshapiro# define SOCKETMAP_MAXL 1000000
79132943Sgshapiro#endif /* SOCKETMAP */
80132943Sgshapiro
8190792Sgshapiro/* default error message for trying to open a map in write mode */
8290792Sgshapiro#ifdef ENOSYS
8390792Sgshapiro# define SM_EMAPCANTWRITE	ENOSYS
8490792Sgshapiro#else /* ENOSYS */
8590792Sgshapiro# ifdef EFTYPE
8690792Sgshapiro#  define SM_EMAPCANTWRITE	EFTYPE
87363466Sgshapiro# else
8890792Sgshapiro#  define SM_EMAPCANTWRITE	ENXIO
89363466Sgshapiro# endif
9090792Sgshapiro#endif /* ENOSYS */
9190792Sgshapiro
9238032Speter/*
9338032Speter**  MAP.C -- implementations for various map classes.
9438032Speter**
9538032Speter**	Each map class implements a series of functions:
9638032Speter**
9738032Speter**	bool map_parse(MAP *map, char *args)
9890792Sgshapiro**		Parse the arguments from the config file.  Return true
9990792Sgshapiro**		if they were ok, false otherwise.  Fill in map with the
10038032Speter**		values.
10138032Speter**
10238032Speter**	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
10338032Speter**		Look up the key in the given map.  If found, do any
10438032Speter**		rewriting the map wants (including "args" if desired)
10538032Speter**		and return the value.  Set *pstat to the appropriate status
10638032Speter**		on error and return NULL.  Args will be NULL if called
10738032Speter**		from the alias routines, although this should probably
10838032Speter**		not be relied upon.  It is suggested you call map_rewrite
10938032Speter**		to return the results -- it takes care of null termination
11038032Speter**		and uses a dynamically expanded buffer as needed.
11138032Speter**
11238032Speter**	void map_store(MAP *map, char *key, char *value)
11338032Speter**		Store the key:value pair in the map.
11438032Speter**
11538032Speter**	bool map_open(MAP *map, int mode)
11638032Speter**		Open the map for the indicated mode.  Mode should
11790792Sgshapiro**		be either O_RDONLY or O_RDWR.  Return true if it
11890792Sgshapiro**		was opened successfully, false otherwise.  If the open
11990792Sgshapiro**		failed and the MF_OPTIONAL flag is not set, it should
12038032Speter**		also print an error.  If the MF_ALIAS bit is set
12138032Speter**		and this map class understands the @:@ convention, it
12238032Speter**		should call aliaswait() before returning.
12338032Speter**
12438032Speter**	void map_close(MAP *map)
12538032Speter**		Close the map.
12638032Speter**
12738032Speter**	This file also includes the implementation for getcanonname.
12838032Speter**	It is currently implemented in a pretty ad-hoc manner; it ought
12938032Speter**	to be more properly integrated into the map structure.
13038032Speter*/
13138032Speter
13238032Speter#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
13338032Speter# define LOCK_ON_OPEN	1	/* we can open/create a locked file */
134363466Sgshapiro#else
13538032Speter# define LOCK_ON_OPEN	0	/* no such luck -- bend over backwards */
136363466Sgshapiro#endif
13738032Speter
13890792Sgshapiro/*
13938032Speter**  MAP_PARSEARGS -- parse config line arguments for database lookup
14038032Speter**
14138032Speter**	This is a generic version of the map_parse method.
14238032Speter**
14338032Speter**	Parameters:
14438032Speter**		map -- the map being initialized.
14538032Speter**		ap -- a pointer to the args on the config line.
14638032Speter**
14738032Speter**	Returns:
14890792Sgshapiro**		true -- if everything parsed OK.
14990792Sgshapiro**		false -- otherwise.
15038032Speter**
15138032Speter**	Side Effects:
15238032Speter**		null terminates the filename; stores it in map
15338032Speter*/
15438032Speter
15538032Speterbool
15638032Spetermap_parseargs(map, ap)
15738032Speter	MAP *map;
15838032Speter	char *ap;
15938032Speter{
16038032Speter	register char *p = ap;
16138032Speter
16264562Sgshapiro	/*
16390792Sgshapiro	**  There is no check whether there is really an argument,
16490792Sgshapiro	**  but that's not important enough to warrant extra code.
16564562Sgshapiro	*/
16690792Sgshapiro
16790792Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
16864562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
16938032Speter	for (;;)
17038032Speter	{
171363466Sgshapiro		while (SM_ISSPACE(*p))
17238032Speter			p++;
17338032Speter		if (*p != '-')
17438032Speter			break;
17538032Speter		switch (*++p)
17638032Speter		{
17738032Speter		  case 'A':
17838032Speter			map->map_mflags |= MF_APPEND;
17938032Speter			break;
18038032Speter
18138032Speter		  case 'a':
18238032Speter			map->map_app = ++p;
18338032Speter			break;
18438032Speter
185363466Sgshapiro		  case 'D':
186363466Sgshapiro			map->map_mflags |= MF_DEFER;
187363466Sgshapiro			break;
188363466Sgshapiro
189285229Sgshapiro		  case 'd':
190285229Sgshapiro			{
191285229Sgshapiro				char *h;
192285229Sgshapiro
193285229Sgshapiro				++p;
194285229Sgshapiro				h = strchr(p, ' ');
195285229Sgshapiro				if (h != NULL)
196285229Sgshapiro					*h = '\0';
197285229Sgshapiro				map->map_timeout = convtime(p, 's');
198285229Sgshapiro				if (h != NULL)
199285229Sgshapiro					*h = ' ';
200285229Sgshapiro			}
201285229Sgshapiro			break;
202285229Sgshapiro
203363466Sgshapiro		  case 'f':
204363466Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
20538032Speter			break;
20638032Speter
20738032Speter		  case 'k':
20838032Speter			while (isascii(*++p) && isspace(*p))
20938032Speter				continue;
21038032Speter			map->map_keycolnm = p;
21138032Speter			break;
21238032Speter
213363466Sgshapiro		  case 'm':
214363466Sgshapiro			map->map_mflags |= MF_MATCHONLY;
215363466Sgshapiro			break;
216363466Sgshapiro
217363466Sgshapiro		  case 'N':
218363466Sgshapiro			map->map_mflags |= MF_INCLNULL;
219363466Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
220363466Sgshapiro			break;
221363466Sgshapiro
222363466Sgshapiro		  case 'O':
223363466Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
224363466Sgshapiro			break;
225363466Sgshapiro
226363466Sgshapiro		  case 'o':
227363466Sgshapiro			map->map_mflags |= MF_OPTIONAL;
228363466Sgshapiro			break;
229363466Sgshapiro
230363466Sgshapiro		  case 'q':
231363466Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
232363466Sgshapiro			break;
233363466Sgshapiro
234363466Sgshapiro		  case 'S':
235363466Sgshapiro			map->map_spacesub = *++p;
236363466Sgshapiro			break;
237363466Sgshapiro
238363466Sgshapiro		  case 'T':
239363466Sgshapiro			map->map_tapp = ++p;
240363466Sgshapiro			break;
241363466Sgshapiro
242363466Sgshapiro		  case 't':
243363466Sgshapiro			map->map_mflags |= MF_NODEFER;
244363466Sgshapiro			break;
245363466Sgshapiro
24638032Speter		  case 'v':
24738032Speter			while (isascii(*++p) && isspace(*p))
24838032Speter				continue;
24938032Speter			map->map_valcolnm = p;
25038032Speter			break;
25138032Speter
25238032Speter		  case 'z':
25338032Speter			if (*++p != '\\')
25438032Speter				map->map_coldelim = *p;
25538032Speter			else
25638032Speter			{
25738032Speter				switch (*++p)
25838032Speter				{
25938032Speter				  case 'n':
26038032Speter					map->map_coldelim = '\n';
26138032Speter					break;
26238032Speter
26338032Speter				  case 't':
26438032Speter					map->map_coldelim = '\t';
26538032Speter					break;
26638032Speter
26738032Speter				  default:
26838032Speter					map->map_coldelim = '\\';
26938032Speter				}
27038032Speter			}
27138032Speter			break;
27238032Speter
27364562Sgshapiro		  default:
27464562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
27564562Sgshapiro			break;
27638032Speter		}
277363466Sgshapiro		while (*p != '\0' && !(SM_ISSPACE(*p)))
27838032Speter			p++;
27938032Speter		if (*p != '\0')
28038032Speter			*p++ = '\0';
28138032Speter	}
28238032Speter	if (map->map_app != NULL)
28338032Speter		map->map_app = newstr(map->map_app);
28438032Speter	if (map->map_tapp != NULL)
28538032Speter		map->map_tapp = newstr(map->map_tapp);
28638032Speter	if (map->map_keycolnm != NULL)
28738032Speter		map->map_keycolnm = newstr(map->map_keycolnm);
28838032Speter	if (map->map_valcolnm != NULL)
28938032Speter		map->map_valcolnm = newstr(map->map_valcolnm);
29038032Speter
29138032Speter	if (*p != '\0')
29238032Speter	{
29338032Speter		map->map_file = p;
294363466Sgshapiro		while (*p != '\0' && !(SM_ISSPACE(*p)))
29538032Speter			p++;
29638032Speter		if (*p != '\0')
29738032Speter			*p++ = '\0';
29838032Speter		map->map_file = newstr(map->map_file);
29938032Speter	}
30038032Speter
301363466Sgshapiro	while (*p != '\0' && SM_ISSPACE(*p))
30238032Speter		p++;
30338032Speter	if (*p != '\0')
30438032Speter		map->map_rebuild = newstr(p);
30538032Speter
30638032Speter	if (map->map_file == NULL &&
30738032Speter	    !bitset(MCF_OPTFILE, map->map_class->map_cflags))
30838032Speter	{
30938032Speter		syserr("No file name for %s map %s",
31038032Speter			map->map_class->map_cname, map->map_mname);
31190792Sgshapiro		return false;
31238032Speter	}
31390792Sgshapiro	return true;
31438032Speter}
31590792Sgshapiro/*
31638032Speter**  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
31738032Speter**
31838032Speter**	It also adds the map_app string.  It can be used as a utility
31938032Speter**	in the map_lookup method.
32038032Speter**
32138032Speter**	Parameters:
32238032Speter**		map -- the map that causes this.
32338032Speter**		s -- the string to rewrite, NOT necessarily null terminated.
32438032Speter**		slen -- the length of s.
32538032Speter**		av -- arguments to interpolate into buf.
32638032Speter**
32738032Speter**	Returns:
32838032Speter**		Pointer to rewritten result.  This is static data that
32938032Speter**		should be copied if it is to be saved!
33038032Speter*/
33138032Speter
33238032Speterchar *
33338032Spetermap_rewrite(map, s, slen, av)
33438032Speter	register MAP *map;
33538032Speter	register const char *s;
33638032Speter	size_t slen;
33738032Speter	char **av;
33838032Speter{
33938032Speter	register char *bp;
34038032Speter	register char c;
34138032Speter	char **avp;
34238032Speter	register char *ap;
34338032Speter	size_t l;
34438032Speter	size_t len;
34538032Speter	static size_t buflen = 0;
34638032Speter	static char *buf = NULL;
34738032Speter
34838032Speter	if (tTd(39, 1))
34938032Speter	{
35090792Sgshapiro		sm_dprintf("map_rewrite(%.*s), av =", (int) slen, s);
35138032Speter		if (av == NULL)
35290792Sgshapiro			sm_dprintf(" (nullv)");
35338032Speter		else
35438032Speter		{
35538032Speter			for (avp = av; *avp != NULL; avp++)
35690792Sgshapiro				sm_dprintf("\n\t%s", *avp);
35738032Speter		}
35890792Sgshapiro		sm_dprintf("\n");
35938032Speter	}
36038032Speter
36138032Speter	/* count expected size of output (can safely overestimate) */
36238032Speter	l = len = slen;
36338032Speter	if (av != NULL)
36438032Speter	{
36538032Speter		const char *sp = s;
36638032Speter
36738032Speter		while (l-- > 0 && (c = *sp++) != '\0')
36838032Speter		{
36938032Speter			if (c != '%')
37038032Speter				continue;
37138032Speter			if (l-- <= 0)
37238032Speter				break;
37338032Speter			c = *sp++;
37438032Speter			if (!(isascii(c) && isdigit(c)))
37538032Speter				continue;
37638032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
37738032Speter				continue;
37838032Speter			if (*avp == NULL)
37938032Speter				continue;
38038032Speter			len += strlen(*avp);
38138032Speter		}
38238032Speter	}
38338032Speter	if (map->map_app != NULL)
38438032Speter		len += strlen(map->map_app);
38538032Speter	if (buflen < ++len)
38638032Speter	{
38738032Speter		/* need to malloc additional space */
38838032Speter		buflen = len;
38938032Speter		if (buf != NULL)
39077349Sgshapiro			sm_free(buf);
39190792Sgshapiro		buf = sm_pmalloc_x(buflen);
39238032Speter	}
39338032Speter
39438032Speter	bp = buf;
39538032Speter	if (av == NULL)
39638032Speter	{
39764562Sgshapiro		memmove(bp, s, slen);
39838032Speter		bp += slen;
39964562Sgshapiro
40064562Sgshapiro		/* assert(len > slen); */
40164562Sgshapiro		len -= slen;
40238032Speter	}
40338032Speter	else
40438032Speter	{
40538032Speter		while (slen-- > 0 && (c = *s++) != '\0')
40638032Speter		{
40738032Speter			if (c != '%')
40838032Speter			{
40938032Speter  pushc:
410120256Sgshapiro				if (len-- <= 1)
41190792Sgshapiro				     break;
41238032Speter				*bp++ = c;
41338032Speter				continue;
41438032Speter			}
41538032Speter			if (slen-- <= 0 || (c = *s++) == '\0')
41638032Speter				c = '%';
41738032Speter			if (c == '%')
41838032Speter				goto pushc;
41938032Speter			if (!(isascii(c) && isdigit(c)))
42038032Speter			{
421120256Sgshapiro				if (len-- <= 1)
422120256Sgshapiro				     break;
42338032Speter				*bp++ = '%';
42438032Speter				goto pushc;
42538032Speter			}
42638032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
42738032Speter				continue;
42838032Speter			if (*avp == NULL)
42938032Speter				continue;
43038032Speter
43138032Speter			/* transliterate argument into output string */
43264562Sgshapiro			for (ap = *avp; (c = *ap++) != '\0' && len > 0; --len)
43338032Speter				*bp++ = c;
43438032Speter		}
43538032Speter	}
43664562Sgshapiro	if (map->map_app != NULL && len > 0)
43790792Sgshapiro		(void) sm_strlcpy(bp, map->map_app, len);
43838032Speter	else
43938032Speter		*bp = '\0';
44038032Speter	if (tTd(39, 1))
44190792Sgshapiro		sm_dprintf("map_rewrite => %s\n", buf);
44238032Speter	return buf;
44338032Speter}
44490792Sgshapiro/*
44564562Sgshapiro**  INITMAPS -- rebuild alias maps
44638032Speter**
44738032Speter**	Parameters:
44864562Sgshapiro**		none.
44938032Speter**
45038032Speter**	Returns:
45138032Speter**		none.
45238032Speter*/
45338032Speter
45438032Spetervoid
45564562Sgshapiroinitmaps()
45638032Speter{
45738032Speter#if XDEBUG
45838032Speter	checkfd012("entering initmaps");
459363466Sgshapiro#endif
46038032Speter	stabapply(map_init, 0);
46138032Speter#if XDEBUG
46238032Speter	checkfd012("exiting initmaps");
463363466Sgshapiro#endif
46438032Speter}
46590792Sgshapiro/*
46664562Sgshapiro**  MAP_INIT -- rebuild a map
46764562Sgshapiro**
46864562Sgshapiro**	Parameters:
46964562Sgshapiro**		s -- STAB entry: if map: try to rebuild
47064562Sgshapiro**		unused -- unused variable
47164562Sgshapiro**
47264562Sgshapiro**	Returns:
47364562Sgshapiro**		none.
47464562Sgshapiro**
47564562Sgshapiro**	Side Effects:
47664562Sgshapiro**		will close already open rebuildable map.
47764562Sgshapiro*/
47838032Speter
47964562Sgshapiro/* ARGSUSED1 */
48064562Sgshapirostatic void
48164562Sgshapiromap_init(s, unused)
48238032Speter	register STAB *s;
48364562Sgshapiro	int unused;
48438032Speter{
48538032Speter	register MAP *map;
48638032Speter
48738032Speter	/* has to be a map */
48890792Sgshapiro	if (s->s_symtype != ST_MAP)
48938032Speter		return;
49038032Speter
49138032Speter	map = &s->s_map;
49238032Speter	if (!bitset(MF_VALID, map->map_mflags))
49338032Speter		return;
49438032Speter
49538032Speter	if (tTd(38, 2))
49690792Sgshapiro		sm_dprintf("map_init(%s:%s, %s)\n",
49738032Speter			map->map_class->map_cname == NULL ? "NULL" :
49838032Speter				map->map_class->map_cname,
49938032Speter			map->map_mname == NULL ? "NULL" : map->map_mname,
50064562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
50138032Speter
50264562Sgshapiro	if (!bitset(MF_ALIAS, map->map_mflags) ||
50364562Sgshapiro	    !bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
50438032Speter	{
50538032Speter		if (tTd(38, 3))
50690792Sgshapiro			sm_dprintf("\tnot rebuildable\n");
50738032Speter		return;
50838032Speter	}
50938032Speter
51038032Speter	/* if already open, close it (for nested open) */
51138032Speter	if (bitset(MF_OPEN, map->map_mflags))
51238032Speter	{
51377349Sgshapiro		map->map_mflags |= MF_CLOSING;
51438032Speter		map->map_class->map_close(map);
51577349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
51638032Speter	}
51738032Speter
51890792Sgshapiro	(void) rebuildaliases(map, false);
51964562Sgshapiro	return;
52064562Sgshapiro}
52190792Sgshapiro/*
52264562Sgshapiro**  OPENMAP -- open a map
52364562Sgshapiro**
52464562Sgshapiro**	Parameters:
52564562Sgshapiro**		map -- map to open (it must not be open).
52664562Sgshapiro**
52764562Sgshapiro**	Returns:
52864562Sgshapiro**		whether open succeeded.
52964562Sgshapiro*/
53064562Sgshapiro
53164562Sgshapirobool
53264562Sgshapiroopenmap(map)
53364562Sgshapiro	MAP *map;
53464562Sgshapiro{
53590792Sgshapiro	bool restore = false;
53664562Sgshapiro	bool savehold = HoldErrs;
53764562Sgshapiro	bool savequick = QuickAbort;
53864562Sgshapiro	int saveerrors = Errors;
53964562Sgshapiro
54064562Sgshapiro	if (!bitset(MF_VALID, map->map_mflags))
54190792Sgshapiro		return false;
54264562Sgshapiro
54364562Sgshapiro	/* better safe than sorry... */
54464562Sgshapiro	if (bitset(MF_OPEN, map->map_mflags))
54590792Sgshapiro		return true;
54664562Sgshapiro
54764562Sgshapiro	/* Don't send a map open error out via SMTP */
54864562Sgshapiro	if ((OnlyOneError || QuickAbort) &&
54964562Sgshapiro	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))
55038032Speter	{
55190792Sgshapiro		restore = true;
55290792Sgshapiro		HoldErrs = true;
55390792Sgshapiro		QuickAbort = false;
55438032Speter	}
55538032Speter
55664562Sgshapiro	errno = 0;
55738032Speter	if (map->map_class->map_open(map, O_RDONLY))
55838032Speter	{
55938032Speter		if (tTd(38, 4))
56090792Sgshapiro			sm_dprintf("openmap()\t%s:%s %s: valid\n",
56138032Speter				map->map_class->map_cname == NULL ? "NULL" :
56238032Speter					map->map_class->map_cname,
56338032Speter				map->map_mname == NULL ? "NULL" :
56438032Speter					map->map_mname,
56538032Speter				map->map_file == NULL ? "NULL" :
56638032Speter					map->map_file);
56738032Speter		map->map_mflags |= MF_OPEN;
56890792Sgshapiro		map->map_pid = CurrentPid;
56938032Speter	}
57038032Speter	else
57138032Speter	{
57238032Speter		if (tTd(38, 4))
57390792Sgshapiro			sm_dprintf("openmap()\t%s:%s %s: invalid%s%s\n",
57438032Speter				map->map_class->map_cname == NULL ? "NULL" :
57538032Speter					map->map_class->map_cname,
57638032Speter				map->map_mname == NULL ? "NULL" :
57738032Speter					map->map_mname,
57838032Speter				map->map_file == NULL ? "NULL" :
57938032Speter					map->map_file,
58064562Sgshapiro				errno == 0 ? "" : ": ",
58190792Sgshapiro				errno == 0 ? "" : sm_errstring(errno));
58238032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
58338032Speter		{
58438032Speter			extern MAPCLASS BogusMapClass;
58538032Speter
58690792Sgshapiro			map->map_orgclass = map->map_class;
58738032Speter			map->map_class = &BogusMapClass;
58890792Sgshapiro			map->map_mflags |= MF_OPEN|MF_OPENBOGUS;
58990792Sgshapiro			map->map_pid = CurrentPid;
59038032Speter		}
59164562Sgshapiro		else
59264562Sgshapiro		{
59364562Sgshapiro			/* don't try again */
59464562Sgshapiro			map->map_mflags &= ~MF_VALID;
59564562Sgshapiro		}
59638032Speter	}
59764562Sgshapiro
59864562Sgshapiro	if (restore)
59964562Sgshapiro	{
60064562Sgshapiro		Errors = saveerrors;
60164562Sgshapiro		HoldErrs = savehold;
60264562Sgshapiro		QuickAbort = savequick;
60364562Sgshapiro	}
60464562Sgshapiro
60564562Sgshapiro	return bitset(MF_OPEN, map->map_mflags);
60638032Speter}
60790792Sgshapiro/*
60842575Speter**  CLOSEMAPS -- close all open maps opened by the current pid.
60942575Speter**
61042575Speter**	Parameters:
61190792Sgshapiro**		bogus -- only close bogus maps.
61242575Speter**
61342575Speter**	Returns:
61442575Speter**		none.
61542575Speter*/
61642575Speter
61742575Spetervoid
61890792Sgshapiroclosemaps(bogus)
61990792Sgshapiro	bool bogus;
62042575Speter{
62190792Sgshapiro	stabapply(map_close, bogus);
62242575Speter}
62390792Sgshapiro/*
62464562Sgshapiro**  MAP_CLOSE -- close a map opened by the current pid.
62564562Sgshapiro**
62664562Sgshapiro**	Parameters:
62790792Sgshapiro**		s -- STAB entry: if map: try to close
62890792Sgshapiro**		bogus -- only close bogus maps or MCF_NOTPERSIST maps.
62964562Sgshapiro**
63064562Sgshapiro**	Returns:
63164562Sgshapiro**		none.
63264562Sgshapiro*/
63342575Speter
63464562Sgshapirostatic void
63590792Sgshapiromap_close(s, bogus)
63642575Speter	register STAB *s;
63790792Sgshapiro	int bogus;	/* int because of stabapply(), used as bool */
63842575Speter{
63942575Speter	MAP *map;
64090792Sgshapiro	extern MAPCLASS BogusMapClass;
64142575Speter
64290792Sgshapiro	if (s->s_symtype != ST_MAP)
64342575Speter		return;
64464562Sgshapiro
64542575Speter	map = &s->s_map;
64642575Speter
64790792Sgshapiro	/*
64890792Sgshapiro	**  close the map iff:
64990792Sgshapiro	**  it is valid and open and opened by this process
65090792Sgshapiro	**  and (!bogus or it's a bogus map or it is not persistent)
65190792Sgshapiro	**  negate this: return iff
65290792Sgshapiro	**  it is not valid or it is not open or not opened by this process
65390792Sgshapiro	**  or (bogus and it's not a bogus map and it's not not-persistent)
65490792Sgshapiro	*/
65590792Sgshapiro
65642575Speter	if (!bitset(MF_VALID, map->map_mflags) ||
65742575Speter	    !bitset(MF_OPEN, map->map_mflags) ||
65877349Sgshapiro	    bitset(MF_CLOSING, map->map_mflags) ||
65990792Sgshapiro	    map->map_pid != CurrentPid ||
66090792Sgshapiro	    (bogus && map->map_class != &BogusMapClass &&
66190792Sgshapiro	     !bitset(MCF_NOTPERSIST, map->map_class->map_cflags)))
66242575Speter		return;
66364562Sgshapiro
66490792Sgshapiro	if (map->map_class == &BogusMapClass && map->map_orgclass != NULL &&
66590792Sgshapiro	    map->map_orgclass != &BogusMapClass)
66690792Sgshapiro		map->map_class = map->map_orgclass;
66742575Speter	if (tTd(38, 5))
66890792Sgshapiro		sm_dprintf("closemaps: closing %s (%s)\n",
66964562Sgshapiro			map->map_mname == NULL ? "NULL" : map->map_mname,
67064562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
67164562Sgshapiro
67290792Sgshapiro	if (!bitset(MF_OPENBOGUS, map->map_mflags))
67390792Sgshapiro	{
67490792Sgshapiro		map->map_mflags |= MF_CLOSING;
67590792Sgshapiro		map->map_class->map_close(map);
67690792Sgshapiro	}
67790792Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_OPENBOGUS|MF_CLOSING);
67842575Speter}
679168515Sgshapiro
680168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
681168515Sgshapiroextern int getdomainname();
682168515Sgshapiro
683168515Sgshapiro/* this is mainly for backward compatibility in Sun environment */
684168515Sgshapirostatic char *
685168515Sgshapirosun_init_domain()
686168515Sgshapiro{
687168515Sgshapiro	/*
688168515Sgshapiro	**  Get the domain name from the kernel.
689168515Sgshapiro	**  If it does not start with a leading dot, then remove
690168515Sgshapiro	**  the first component.  Since leading dots are funny Unix
691168515Sgshapiro	**  files, we treat a leading "+" the same as a leading dot.
692168515Sgshapiro	**  Finally, force there to be at least one dot in the domain name
693168515Sgshapiro	**  (i.e. top-level domains are not allowed, like "com", must be
694168515Sgshapiro	**  something like "sun.com").
695168515Sgshapiro	*/
696168515Sgshapiro
697168515Sgshapiro	char buf[MAXNAME];
698168515Sgshapiro	char *period, *autodomain;
699168515Sgshapiro
700168515Sgshapiro	if (getdomainname(buf, sizeof buf) < 0)
701168515Sgshapiro		return NULL;
702168515Sgshapiro
703168515Sgshapiro	if (buf[0] == '\0')
704168515Sgshapiro		return NULL;
705168515Sgshapiro
706168515Sgshapiro	if (tTd(0, 20))
707168515Sgshapiro		printf("domainname = %s\n", buf);
708168515Sgshapiro
709168515Sgshapiro	if (buf[0] == '+')
710168515Sgshapiro		buf[0] = '.';
711168515Sgshapiro	period = strchr(buf, '.');
712168515Sgshapiro	if (period == NULL)
713168515Sgshapiro		autodomain = buf;
714168515Sgshapiro	else
715168515Sgshapiro		autodomain = period + 1;
716168515Sgshapiro	if (strchr(autodomain, '.') == NULL)
717168515Sgshapiro		return newstr(buf);
718168515Sgshapiro	else
719168515Sgshapiro		return newstr(autodomain);
720168515Sgshapiro}
721168515Sgshapiro#endif /* SUN_EXTENSIONS && SUN_INIT_DOMAIN */
722168515Sgshapiro
72390792Sgshapiro/*
72438032Speter**  GETCANONNAME -- look up name using service switch
72538032Speter**
72638032Speter**	Parameters:
72738032Speter**		host -- the host name to look up.
72838032Speter**		hbsize -- the size of the host buffer.
72938032Speter**		trymx -- if set, try MX records.
73090792Sgshapiro**		pttl -- pointer to return TTL (can be NULL).
73138032Speter**
73238032Speter**	Returns:
733363466Sgshapiro**		>0 -- if the host was found.
734363466Sgshapiro**		0 -- otherwise.
73538032Speter*/
73638032Speter
737363466Sgshapiroint
73890792Sgshapirogetcanonname(host, hbsize, trymx, pttl)
73938032Speter	char *host;
74038032Speter	int hbsize;
74138032Speter	bool trymx;
74290792Sgshapiro	int *pttl;
74338032Speter{
74438032Speter	int nmaps;
74538032Speter	int mapno;
74690792Sgshapiro	bool found = false;
74790792Sgshapiro	bool got_tempfail = false;
748203004Sgshapiro	auto int status = EX_UNAVAILABLE;
74938032Speter	char *maptype[MAXMAPSTACK];
75038032Speter	short mapreturn[MAXMAPACTIONS];
751168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
752168515Sgshapiro	bool should_try_nis_domain = false;
753168515Sgshapiro	static char *nis_domain = NULL;
754168515Sgshapiro#endif
755363466Sgshapiro	bool secure = true;	/* consider all maps secure by default */
75638032Speter
75738032Speter	nmaps = switch_map_find("hosts", maptype, mapreturn);
758363466Sgshapiro	if (pttl != NULL)
75990792Sgshapiro		*pttl = SM_DEFAULT_TTL;
76038032Speter	for (mapno = 0; mapno < nmaps; mapno++)
76138032Speter	{
76238032Speter		int i;
76338032Speter
76438032Speter		if (tTd(38, 20))
76590792Sgshapiro			sm_dprintf("getcanonname(%s), trying %s\n",
76638032Speter				host, maptype[mapno]);
76738032Speter		if (strcmp("files", maptype[mapno]) == 0)
76838032Speter		{
76964562Sgshapiro			found = text_getcanonname(host, hbsize, &status);
77038032Speter		}
77190792Sgshapiro#if NIS
77238032Speter		else if (strcmp("nis", maptype[mapno]) == 0)
77338032Speter		{
77464562Sgshapiro			found = nis_getcanonname(host, hbsize, &status);
775168515Sgshapiro# if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
776168515Sgshapiro			if (nis_domain == NULL)
777168515Sgshapiro				nis_domain = sun_init_domain();
778363466Sgshapiro# endif
77938032Speter		}
78064562Sgshapiro#endif /* NIS */
78190792Sgshapiro#if NISPLUS
78238032Speter		else if (strcmp("nisplus", maptype[mapno]) == 0)
78338032Speter		{
78464562Sgshapiro			found = nisplus_getcanonname(host, hbsize, &status);
785168515Sgshapiro# if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
786168515Sgshapiro			if (nis_domain == NULL)
787168515Sgshapiro				nis_domain = sun_init_domain();
788363466Sgshapiro# endif
78938032Speter		}
79064562Sgshapiro#endif /* NISPLUS */
79138032Speter#if NAMED_BIND
79238032Speter		else if (strcmp("dns", maptype[mapno]) == 0)
79338032Speter		{
794363466Sgshapiro			int r;
795363466Sgshapiro
796363466Sgshapiro			r = dns_getcanonname(host, hbsize, trymx, &status,
797363466Sgshapiro					pttl);
798363466Sgshapiro			secure = HOST_SECURE == r;
799363466Sgshapiro			found = r > 0;
80038032Speter		}
80164562Sgshapiro#endif /* NAMED_BIND */
80238032Speter#if NETINFO
80338032Speter		else if (strcmp("netinfo", maptype[mapno]) == 0)
80438032Speter		{
80564562Sgshapiro			found = ni_getcanonname(host, hbsize, &status);
80638032Speter		}
80764562Sgshapiro#endif /* NETINFO */
80838032Speter		else
80938032Speter		{
81090792Sgshapiro			found = false;
81164562Sgshapiro			status = EX_UNAVAILABLE;
81238032Speter		}
81338032Speter
81438032Speter		/*
81538032Speter		**  Heuristic: if $m is not set, we are running during system
81638032Speter		**  startup.  In this case, when a name is apparently found
81738032Speter		**  but has no dot, treat is as not found.  This avoids
81838032Speter		**  problems if /etc/hosts has no FQDN but is listed first
81938032Speter		**  in the service switch.
82038032Speter		*/
82138032Speter
82238032Speter		if (found &&
82338032Speter		    (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
82438032Speter			break;
82538032Speter
826168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
827168515Sgshapiro		if (found)
828168515Sgshapiro			should_try_nis_domain = true;
829168515Sgshapiro		/* but don't break, as we need to try all methods first */
830168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
831168515Sgshapiro
83238032Speter		/* see if we should continue */
83364562Sgshapiro		if (status == EX_TEMPFAIL)
83438032Speter		{
83538032Speter			i = MA_TRYAGAIN;
83690792Sgshapiro			got_tempfail = true;
83738032Speter		}
83864562Sgshapiro		else if (status == EX_NOTFOUND)
83938032Speter			i = MA_NOTFOUND;
84038032Speter		else
84138032Speter			i = MA_UNAVAIL;
84238032Speter		if (bitset(1 << mapno, mapreturn[i]))
84338032Speter			break;
84438032Speter	}
84538032Speter
84638032Speter	if (found)
84738032Speter	{
84838032Speter		char *d;
84938032Speter
85038032Speter		if (tTd(38, 20))
851363466Sgshapiro			sm_dprintf("getcanonname(%s), found, ad=%d\n", host, secure);
85238032Speter
85338032Speter		/*
85438032Speter		**  If returned name is still single token, compensate
85538032Speter		**  by tagging on $m.  This is because some sites set
85638032Speter		**  up their DNS or NIS databases wrong.
85738032Speter		*/
85838032Speter
85938032Speter		if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
86038032Speter		{
86138032Speter			d = macvalue('m', CurEnv);
86238032Speter			if (d != NULL &&
86338032Speter			    hbsize > (int) (strlen(host) + strlen(d) + 1))
86438032Speter			{
86538032Speter				if (host[strlen(host) - 1] != '.')
86690792Sgshapiro					(void) sm_strlcat2(host, ".", d,
86790792Sgshapiro							   hbsize);
86890792Sgshapiro				else
86990792Sgshapiro					(void) sm_strlcat(host, d, hbsize);
87038032Speter			}
87138032Speter			else
872168515Sgshapiro			{
873168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
874168515Sgshapiro				if (VendorCode == VENDOR_SUN &&
875168515Sgshapiro				    should_try_nis_domain)
876168515Sgshapiro				{
877168515Sgshapiro					goto try_nis_domain;
878168515Sgshapiro				}
879168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
880363466Sgshapiro				return HOST_NOTFOUND;
881168515Sgshapiro			}
88238032Speter		}
883363466Sgshapiro		return secure ? HOST_SECURE : HOST_OK;
88438032Speter	}
88538032Speter
886168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
887168515Sgshapiro	if (VendorCode == VENDOR_SUN && should_try_nis_domain)
888168515Sgshapiro	{
889168515Sgshapiro  try_nis_domain:
890168515Sgshapiro		if (nis_domain != NULL &&
891168515Sgshapiro		    strlen(nis_domain) + strlen(host) + 1 < hbsize)
892168515Sgshapiro		{
893168515Sgshapiro			(void) sm_strlcat2(host, ".", nis_domain, hbsize);
894363466Sgshapiro			return HOST_OK;
895168515Sgshapiro		}
896168515Sgshapiro	}
897168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
898168515Sgshapiro
89938032Speter	if (tTd(38, 20))
90090792Sgshapiro		sm_dprintf("getcanonname(%s), failed, status=%d\n", host,
90190792Sgshapiro			status);
90238032Speter
90338032Speter	if (got_tempfail)
90473188Sgshapiro		SM_SET_H_ERRNO(TRY_AGAIN);
90538032Speter	else
90673188Sgshapiro		SM_SET_H_ERRNO(HOST_NOT_FOUND);
90790792Sgshapiro
908363466Sgshapiro	return HOST_NOTFOUND;
90938032Speter}
91090792Sgshapiro/*
91138032Speter**  EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
91238032Speter**
91338032Speter**	Parameters:
91438032Speter**		name -- the name against which to match.
91573188Sgshapiro**		dot -- where to reinsert '.' to get FQDN
91638032Speter**		line -- the /etc/hosts line.
91738032Speter**		cbuf -- the location to store the result.
91838032Speter**		cbuflen -- the size of cbuf.
91938032Speter**
92038032Speter**	Returns:
92190792Sgshapiro**		true -- if the line matched the desired name.
92290792Sgshapiro**		false -- otherwise.
92338032Speter*/
92438032Speter
92564562Sgshapirostatic bool
92673188Sgshapiroextract_canonname(name, dot, line, cbuf, cbuflen)
92738032Speter	char *name;
92873188Sgshapiro	char *dot;
92938032Speter	char *line;
93038032Speter	char cbuf[];
93138032Speter	int cbuflen;
93238032Speter{
93338032Speter	int i;
93438032Speter	char *p;
93590792Sgshapiro	bool found = false;
93638032Speter
93738032Speter	cbuf[0] = '\0';
93838032Speter	if (line[0] == '#')
93990792Sgshapiro		return false;
94038032Speter
94138032Speter	for (i = 1; ; i++)
94238032Speter	{
94338032Speter		char nbuf[MAXNAME + 1];
94438032Speter
945168515Sgshapiro		p = get_column(line, i, '\0', nbuf, sizeof(nbuf));
94638032Speter		if (p == NULL)
94738032Speter			break;
94838032Speter		if (*p == '\0')
94938032Speter			continue;
95038032Speter		if (cbuf[0] == '\0' ||
95138032Speter		    (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
95238032Speter		{
95390792Sgshapiro			(void) sm_strlcpy(cbuf, p, cbuflen);
95438032Speter		}
95590792Sgshapiro		if (sm_strcasecmp(name, p) == 0)
95690792Sgshapiro			found = true;
95773188Sgshapiro		else if (dot != NULL)
95873188Sgshapiro		{
95973188Sgshapiro			/* try looking for the FQDN as well */
96073188Sgshapiro			*dot = '.';
96190792Sgshapiro			if (sm_strcasecmp(name, p) == 0)
96290792Sgshapiro				found = true;
96373188Sgshapiro			*dot = '\0';
96473188Sgshapiro		}
96538032Speter	}
96638032Speter	if (found && strchr(cbuf, '.') == NULL)
96738032Speter	{
96838032Speter		/* try to add a domain on the end of the name */
96938032Speter		char *domain = macvalue('m', CurEnv);
97038032Speter
97138032Speter		if (domain != NULL &&
97264562Sgshapiro		    strlen(domain) + (i = strlen(cbuf)) + 1 < (size_t) cbuflen)
97338032Speter		{
97464562Sgshapiro			p = &cbuf[i];
97538032Speter			*p++ = '.';
97690792Sgshapiro			(void) sm_strlcpy(p, domain, cbuflen - i - 1);
97738032Speter		}
97838032Speter	}
97938032Speter	return found;
98038032Speter}
98190792Sgshapiro
98290792Sgshapiro/*
98390792Sgshapiro**  DNS modules
98490792Sgshapiro*/
98590792Sgshapiro
98690792Sgshapiro#if NAMED_BIND
98790792Sgshapiro# if DNSMAP
98890792Sgshapiro
98990792Sgshapiro#  include "sm_resolve.h"
99090792Sgshapiro#  if NETINET || NETINET6
99190792Sgshapiro#   include <arpa/inet.h>
992363466Sgshapiro#  endif
99390792Sgshapiro
99490792Sgshapiro/*
99590792Sgshapiro**  DNS_MAP_OPEN -- stub to check proper value for dns map type
99690792Sgshapiro*/
99790792Sgshapiro
99890792Sgshapirobool
99990792Sgshapirodns_map_open(map, mode)
100090792Sgshapiro	MAP *map;
100190792Sgshapiro	int mode;
100290792Sgshapiro{
100390792Sgshapiro	if (tTd(38,2))
100490792Sgshapiro		sm_dprintf("dns_map_open(%s, %d)\n", map->map_mname, mode);
100590792Sgshapiro
100690792Sgshapiro	mode &= O_ACCMODE;
100790792Sgshapiro	if (mode != O_RDONLY)
100890792Sgshapiro	{
100990792Sgshapiro		/* issue a pseudo-error message */
101090792Sgshapiro		errno = SM_EMAPCANTWRITE;
101190792Sgshapiro		return false;
101290792Sgshapiro	}
101390792Sgshapiro	return true;
101490792Sgshapiro}
101590792Sgshapiro
101690792Sgshapiro/*
101790792Sgshapiro**  DNS_MAP_PARSEARGS -- parse dns map definition args.
101890792Sgshapiro**
101990792Sgshapiro**	Parameters:
102090792Sgshapiro**		map -- pointer to MAP
102190792Sgshapiro**		args -- pointer to the args on the config line.
102290792Sgshapiro**
102390792Sgshapiro**	Returns:
102490792Sgshapiro**		true -- if everything parsed OK.
102590792Sgshapiro**		false -- otherwise.
102690792Sgshapiro*/
102790792Sgshapiro
1028168515Sgshapiro#define map_sizelimit	map_lockfd	/* overload field */
102990792Sgshapiro
103090792Sgshapirostruct dns_map
103190792Sgshapiro{
103290792Sgshapiro	int dns_m_type;
1033363466Sgshapiro	unsigned int dns_m_options;
103490792Sgshapiro};
103590792Sgshapiro
103690792Sgshapirobool
103790792Sgshapirodns_map_parseargs(map,args)
103890792Sgshapiro	MAP *map;
103990792Sgshapiro	char *args;
104090792Sgshapiro{
104190792Sgshapiro	register char *p = args;
104290792Sgshapiro	struct dns_map *map_p;
104390792Sgshapiro
1044168515Sgshapiro	map_p = (struct dns_map *) xalloc(sizeof(*map_p));
1045363466Sgshapiro	memset(map_p, '\0', sizeof(*map_p));
104690792Sgshapiro	map_p->dns_m_type = -1;
104790792Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
104890792Sgshapiro
104990792Sgshapiro	for (;;)
105090792Sgshapiro	{
1051363466Sgshapiro		while (SM_ISSPACE(*p))
105290792Sgshapiro			p++;
105390792Sgshapiro		if (*p != '-')
105490792Sgshapiro			break;
105590792Sgshapiro		switch (*++p)
105690792Sgshapiro		{
1057363466Sgshapiro#if DNSSEC_TEST
1058363466Sgshapiro		  case '@':
1059363466Sgshapiro			++p;
1060363466Sgshapiro			if (nsportip(p) < 0)
1061363466Sgshapiro				syserr("dns map %s: nsportip(%s)=failed",
1062363466Sgshapiro					map->map_mname, p);
106390792Sgshapiro			break;
1064363466Sgshapiro#endif /* DNSSEC_TEST */
106590792Sgshapiro
106690792Sgshapiro		  case 'A':
106790792Sgshapiro			map->map_mflags |= MF_APPEND;
106890792Sgshapiro			break;
106990792Sgshapiro
107090792Sgshapiro		  case 'a':
107190792Sgshapiro			map->map_app = ++p;
107290792Sgshapiro			break;
107390792Sgshapiro
1074363466Sgshapiro		  case 'B':		/* base domain */
1075363466Sgshapiro			{
1076363466Sgshapiro				char *h;
1077363466Sgshapiro
1078363466Sgshapiro				while (isascii(*++p) && isspace(*p))
1079363466Sgshapiro					continue;
1080363466Sgshapiro				h = strchr(p, ' ');
1081363466Sgshapiro				if (h != NULL)
1082363466Sgshapiro					*h = '\0';
1083363466Sgshapiro
1084363466Sgshapiro				/*
1085363466Sgshapiro				**  slight abuse of map->map_file; it isn't
1086363466Sgshapiro				**	used otherwise in this map type.
1087363466Sgshapiro				*/
1088363466Sgshapiro
1089363466Sgshapiro				map->map_file = newstr(p);
1090363466Sgshapiro				if (h != NULL)
1091363466Sgshapiro					*h = ' ';
1092363466Sgshapiro			}
109390792Sgshapiro			break;
109490792Sgshapiro
109590792Sgshapiro		  case 'd':
109690792Sgshapiro			{
109790792Sgshapiro				char *h;
109890792Sgshapiro
109990792Sgshapiro				++p;
110090792Sgshapiro				h = strchr(p, ' ');
110190792Sgshapiro				if (h != NULL)
110290792Sgshapiro					*h = '\0';
110390792Sgshapiro				map->map_timeout = convtime(p, 's');
110490792Sgshapiro				if (h != NULL)
110590792Sgshapiro					*h = ' ';
110690792Sgshapiro			}
110790792Sgshapiro			break;
110890792Sgshapiro
1109363466Sgshapiro		  case 'f':
1110363466Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
1111363466Sgshapiro			break;
1112363466Sgshapiro
1113363466Sgshapiro		  case 'm':
1114363466Sgshapiro			map->map_mflags |= MF_MATCHONLY;
1115363466Sgshapiro			break;
1116363466Sgshapiro
1117363466Sgshapiro		  case 'N':
1118363466Sgshapiro			map->map_mflags |= MF_INCLNULL;
1119363466Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
1120363466Sgshapiro			break;
1121363466Sgshapiro
1122363466Sgshapiro		  case 'O':
1123363466Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
1124363466Sgshapiro			break;
1125363466Sgshapiro
1126363466Sgshapiro		  case 'o':
1127363466Sgshapiro			map->map_mflags |= MF_OPTIONAL;
1128363466Sgshapiro			break;
1129363466Sgshapiro
1130363466Sgshapiro		  case 'q':
1131363466Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
1132363466Sgshapiro			break;
1133363466Sgshapiro
1134363466Sgshapiro		  case 'S':
1135363466Sgshapiro#if defined(RES_USE_EDNS0) && defined(RES_USE_DNSSEC)
1136363466Sgshapiro			map_p->dns_m_options |= SM_RES_DNSSEC;
1137363466Sgshapiro#endif
1138363466Sgshapiro			break;
1139363466Sgshapiro
114090792Sgshapiro		  case 'r':
114190792Sgshapiro			while (isascii(*++p) && isspace(*p))
114290792Sgshapiro				continue;
114390792Sgshapiro			map->map_retry = atoi(p);
114490792Sgshapiro			break;
114590792Sgshapiro
1146363466Sgshapiro		  case 't':
1147363466Sgshapiro			map->map_mflags |= MF_NODEFER;
1148363466Sgshapiro			break;
1149363466Sgshapiro
1150363466Sgshapiro		  case 'T':
1151363466Sgshapiro			map->map_tapp = ++p;
1152363466Sgshapiro			break;
1153363466Sgshapiro
115490792Sgshapiro		  case 'z':
115590792Sgshapiro			if (*++p != '\\')
115690792Sgshapiro				map->map_coldelim = *p;
115790792Sgshapiro			else
115890792Sgshapiro			{
115990792Sgshapiro				switch (*++p)
116090792Sgshapiro				{
116190792Sgshapiro				  case 'n':
116290792Sgshapiro					map->map_coldelim = '\n';
116390792Sgshapiro					break;
116490792Sgshapiro
116590792Sgshapiro				  case 't':
116690792Sgshapiro					map->map_coldelim = '\t';
116790792Sgshapiro					break;
116890792Sgshapiro
116990792Sgshapiro				  default:
117090792Sgshapiro					map->map_coldelim = '\\';
117190792Sgshapiro				}
117290792Sgshapiro			}
117390792Sgshapiro			break;
117490792Sgshapiro
117590792Sgshapiro		  case 'Z':
117690792Sgshapiro			while (isascii(*++p) && isspace(*p))
117790792Sgshapiro				continue;
117890792Sgshapiro			map->map_sizelimit = atoi(p);
117990792Sgshapiro			break;
118090792Sgshapiro
118190792Sgshapiro			/* Start of dns_map specific args */
118290792Sgshapiro		  case 'R':		/* search field */
118390792Sgshapiro			{
118490792Sgshapiro				char *h;
118590792Sgshapiro
118690792Sgshapiro				while (isascii(*++p) && isspace(*p))
118790792Sgshapiro					continue;
118890792Sgshapiro				h = strchr(p, ' ');
118990792Sgshapiro				if (h != NULL)
119090792Sgshapiro					*h = '\0';
119190792Sgshapiro				map_p->dns_m_type = dns_string_to_type(p);
119290792Sgshapiro				if (h != NULL)
119390792Sgshapiro					*h = ' ';
119490792Sgshapiro				if (map_p->dns_m_type < 0)
119590792Sgshapiro					syserr("dns map %s: wrong type %s",
119690792Sgshapiro						map->map_mname, p);
119790792Sgshapiro			}
119890792Sgshapiro			break;
119990792Sgshapiro
120090792Sgshapiro		}
1201363466Sgshapiro		while (*p != '\0' && !(SM_ISSPACE(*p)))
120290792Sgshapiro			p++;
120390792Sgshapiro		if (*p != '\0')
120490792Sgshapiro			*p++ = '\0';
120590792Sgshapiro	}
120690792Sgshapiro	if (map_p->dns_m_type < 0)
120790792Sgshapiro		syserr("dns map %s: missing -R type", map->map_mname);
120890792Sgshapiro	if (map->map_app != NULL)
120990792Sgshapiro		map->map_app = newstr(map->map_app);
121090792Sgshapiro	if (map->map_tapp != NULL)
121190792Sgshapiro		map->map_tapp = newstr(map->map_tapp);
121290792Sgshapiro
121390792Sgshapiro	/*
1214168515Sgshapiro	**  Assumption: assert(sizeof(int) <= sizeof(ARBPTR_T));
121590792Sgshapiro	**  Even if this assumption is wrong, we use only one byte,
121690792Sgshapiro	**  so it doesn't really matter.
121790792Sgshapiro	*/
121890792Sgshapiro
121990792Sgshapiro	map->map_db1 = (ARBPTR_T) map_p;
122090792Sgshapiro	return true;
122190792Sgshapiro}
122290792Sgshapiro
122390792Sgshapiro/*
122490792Sgshapiro**  DNS_MAP_LOOKUP -- perform dns map lookup.
122590792Sgshapiro**
122690792Sgshapiro**	Parameters:
122790792Sgshapiro**		map -- pointer to MAP
122890792Sgshapiro**		name -- name to lookup
122990792Sgshapiro**		av -- arguments to interpolate into buf.
123090792Sgshapiro**		statp -- pointer to status (EX_)
123190792Sgshapiro**
123290792Sgshapiro**	Returns:
123390792Sgshapiro**		result of lookup if succeeded.
123490792Sgshapiro**		NULL -- otherwise.
123590792Sgshapiro*/
123690792Sgshapiro
123790792Sgshapirochar *
123890792Sgshapirodns_map_lookup(map, name, av, statp)
123990792Sgshapiro	MAP *map;
124090792Sgshapiro	char *name;
124190792Sgshapiro	char **av;
124290792Sgshapiro	int *statp;
124390792Sgshapiro{
124490792Sgshapiro	int resnum = 0;
124590792Sgshapiro	char *vp = NULL, *result = NULL;
124690792Sgshapiro	size_t vsize;
124790792Sgshapiro	struct dns_map *map_p;
124890792Sgshapiro	RESOURCE_RECORD_T *rr = NULL;
124990792Sgshapiro	DNS_REPLY_T *r = NULL;
1250363466Sgshapiro	unsigned int options;
125190792Sgshapiro#  if NETINET6
125290792Sgshapiro	static char buf6[INET6_ADDRSTRLEN];
1253363466Sgshapiro#  endif
125490792Sgshapiro
125590792Sgshapiro	if (tTd(38, 20))
125690792Sgshapiro		sm_dprintf("dns_map_lookup(%s, %s)\n",
125790792Sgshapiro			   map->map_mname, name);
125890792Sgshapiro
125990792Sgshapiro	map_p = (struct dns_map *)(map->map_db1);
1260363466Sgshapiro	options = map_p->dns_m_options;
126190792Sgshapiro	if (map->map_file != NULL && *map->map_file != '\0')
126290792Sgshapiro	{
126390792Sgshapiro		size_t len;
126490792Sgshapiro		char *appdomain;
126590792Sgshapiro
126690792Sgshapiro		len = strlen(map->map_file) + strlen(name) + 2;
126790792Sgshapiro		appdomain = (char *) sm_malloc(len);
126890792Sgshapiro		if (appdomain == NULL)
126990792Sgshapiro		{
127090792Sgshapiro			*statp = EX_UNAVAILABLE;
127190792Sgshapiro			return NULL;
127290792Sgshapiro		}
127390792Sgshapiro		(void) sm_strlcpyn(appdomain, len, 3, name, ".", map->map_file);
1274363466Sgshapiro		r = dns_lookup_map(appdomain, C_IN, map_p->dns_m_type,
1275363466Sgshapiro				   map->map_timeout, map->map_retry, options);
127690792Sgshapiro		sm_free(appdomain);
127790792Sgshapiro	}
127890792Sgshapiro	else
127990792Sgshapiro	{
1280363466Sgshapiro		r = dns_lookup_map(name, C_IN, map_p->dns_m_type,
1281363466Sgshapiro				   map->map_timeout, map->map_retry, options);
128290792Sgshapiro	}
128390792Sgshapiro
128490792Sgshapiro	if (r == NULL)
128590792Sgshapiro	{
128690792Sgshapiro		result = NULL;
1287120256Sgshapiro		if (h_errno == TRY_AGAIN || transienterror(errno))
128890792Sgshapiro			*statp = EX_TEMPFAIL;
128990792Sgshapiro		else
129090792Sgshapiro			*statp = EX_NOTFOUND;
129190792Sgshapiro		goto cleanup;
129290792Sgshapiro	}
129390792Sgshapiro	*statp = EX_OK;
129490792Sgshapiro	for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next)
129590792Sgshapiro	{
129690792Sgshapiro		char *type = NULL;
129790792Sgshapiro		char *value = NULL;
129890792Sgshapiro
129990792Sgshapiro		switch (rr->rr_type)
130090792Sgshapiro		{
130190792Sgshapiro		  case T_NS:
130290792Sgshapiro			type = "T_NS";
130390792Sgshapiro			value = rr->rr_u.rr_txt;
130490792Sgshapiro			break;
130590792Sgshapiro		  case T_CNAME:
130690792Sgshapiro			type = "T_CNAME";
130790792Sgshapiro			value = rr->rr_u.rr_txt;
130890792Sgshapiro			break;
130990792Sgshapiro		  case T_AFSDB:
131090792Sgshapiro			type = "T_AFSDB";
131190792Sgshapiro			value = rr->rr_u.rr_mx->mx_r_domain;
131290792Sgshapiro			break;
131390792Sgshapiro		  case T_SRV:
131490792Sgshapiro			type = "T_SRV";
131590792Sgshapiro			value = rr->rr_u.rr_srv->srv_r_target;
131690792Sgshapiro			break;
131790792Sgshapiro		  case T_PTR:
131890792Sgshapiro			type = "T_PTR";
131990792Sgshapiro			value = rr->rr_u.rr_txt;
132090792Sgshapiro			break;
132190792Sgshapiro		  case T_TXT:
132290792Sgshapiro			type = "T_TXT";
132390792Sgshapiro			value = rr->rr_u.rr_txt;
132490792Sgshapiro			break;
132590792Sgshapiro		  case T_MX:
132690792Sgshapiro			type = "T_MX";
132790792Sgshapiro			value = rr->rr_u.rr_mx->mx_r_domain;
132890792Sgshapiro			break;
132990792Sgshapiro#  if NETINET
133090792Sgshapiro		  case T_A:
133190792Sgshapiro			type = "T_A";
133290792Sgshapiro			value = inet_ntoa(*(rr->rr_u.rr_a));
133390792Sgshapiro			break;
133490792Sgshapiro#  endif /* NETINET */
133590792Sgshapiro#  if NETINET6
133690792Sgshapiro		  case T_AAAA:
133790792Sgshapiro			type = "T_AAAA";
133890792Sgshapiro			value = anynet_ntop(rr->rr_u.rr_aaaa, buf6,
1339168515Sgshapiro					    sizeof(buf6));
134090792Sgshapiro			break;
134190792Sgshapiro#  endif /* NETINET6 */
1342363466Sgshapiro# ifdef T_TLSA
1343363466Sgshapiro		  case T_TLSA:
1344363466Sgshapiro			type = "T_TLSA";
1345363466Sgshapiro			value = rr->rr_u.rr_txt;
1346363466Sgshapiro			break;
1347363466Sgshapiro# endif /* T_TLSA */
134890792Sgshapiro		}
134990792Sgshapiro
135098841Sgshapiro		(void) strreplnonprt(value, 'X');
135190792Sgshapiro		if (map_p->dns_m_type != rr->rr_type)
135290792Sgshapiro		{
135390792Sgshapiro			if (tTd(38, 40))
135490792Sgshapiro				sm_dprintf("\tskipping type %s (%d) value %s\n",
135590792Sgshapiro					   type != NULL ? type : "<UNKNOWN>",
135690792Sgshapiro					   rr->rr_type,
135790792Sgshapiro					   value != NULL ? value : "<NO VALUE>");
135890792Sgshapiro			continue;
135990792Sgshapiro		}
136090792Sgshapiro
136190792Sgshapiro#  if NETINET6
136290792Sgshapiro		if (rr->rr_type == T_AAAA && value == NULL)
136390792Sgshapiro		{
136490792Sgshapiro			result = NULL;
136590792Sgshapiro			*statp = EX_DATAERR;
136690792Sgshapiro			if (tTd(38, 40))
136790792Sgshapiro				sm_dprintf("\tbad T_AAAA conversion\n");
136890792Sgshapiro			goto cleanup;
136990792Sgshapiro		}
137090792Sgshapiro#  endif /* NETINET6 */
137190792Sgshapiro		if (tTd(38, 40))
137290792Sgshapiro			sm_dprintf("\tfound type %s (%d) value %s\n",
137390792Sgshapiro				   type != NULL ? type : "<UNKNOWN>",
137490792Sgshapiro				   rr->rr_type,
137590792Sgshapiro				   value != NULL ? value : "<NO VALUE>");
137690792Sgshapiro		if (value != NULL &&
137790792Sgshapiro		    (map->map_coldelim == '\0' ||
137890792Sgshapiro		     map->map_sizelimit == 1 ||
137990792Sgshapiro		     bitset(MF_MATCHONLY, map->map_mflags)))
138090792Sgshapiro		{
138190792Sgshapiro			/* Only care about the first match */
138290792Sgshapiro			vp = newstr(value);
138390792Sgshapiro			break;
138490792Sgshapiro		}
138590792Sgshapiro		else if (vp == NULL)
138690792Sgshapiro		{
138790792Sgshapiro			/* First result */
138890792Sgshapiro			vp = newstr(value);
138990792Sgshapiro		}
139090792Sgshapiro		else
139190792Sgshapiro		{
139290792Sgshapiro			/* concatenate the results */
139390792Sgshapiro			int sz;
139490792Sgshapiro			char *new;
139590792Sgshapiro
139690792Sgshapiro			sz = strlen(vp) + strlen(value) + 2;
139790792Sgshapiro			new = xalloc(sz);
139890792Sgshapiro			(void) sm_snprintf(new, sz, "%s%c%s",
139990792Sgshapiro					   vp, map->map_coldelim, value);
140090792Sgshapiro			sm_free(vp);
140190792Sgshapiro			vp = new;
140290792Sgshapiro			if (map->map_sizelimit > 0 &&
140390792Sgshapiro			    ++resnum >= map->map_sizelimit)
140490792Sgshapiro				break;
140590792Sgshapiro		}
140690792Sgshapiro	}
140790792Sgshapiro	if (vp == NULL)
140890792Sgshapiro	{
140990792Sgshapiro		result = NULL;
141090792Sgshapiro		*statp = EX_NOTFOUND;
141190792Sgshapiro		if (tTd(38, 40))
141290792Sgshapiro			sm_dprintf("\tno match found\n");
141390792Sgshapiro		goto cleanup;
141490792Sgshapiro	}
141590792Sgshapiro
141690792Sgshapiro	/* Cleanly truncate for rulesets */
141790792Sgshapiro	truncate_at_delim(vp, PSBUFSIZE / 2, map->map_coldelim);
141890792Sgshapiro
141990792Sgshapiro	vsize = strlen(vp);
142090792Sgshapiro
142190792Sgshapiro	if (LogLevel > 9)
142290792Sgshapiro		sm_syslog(LOG_INFO, CurEnv->e_id, "dns %.100s => %s",
142390792Sgshapiro			  name, vp);
142490792Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
142590792Sgshapiro		result = map_rewrite(map, name, strlen(name), NULL);
142690792Sgshapiro	else
142790792Sgshapiro		result = map_rewrite(map, vp, vsize, av);
142890792Sgshapiro
142990792Sgshapiro  cleanup:
143090792Sgshapiro	if (vp != NULL)
143190792Sgshapiro		sm_free(vp);
1432363466Sgshapiro	dns_free_data(r);
143390792Sgshapiro	return result;
143490792Sgshapiro}
143590792Sgshapiro# endif /* DNSMAP */
143690792Sgshapiro#endif /* NAMED_BIND */
143790792Sgshapiro
143890792Sgshapiro/*
143938032Speter**  NDBM modules
144038032Speter*/
144138032Speter
144290792Sgshapiro#if NDBM
144338032Speter
144438032Speter/*
144538032Speter**  NDBM_MAP_OPEN -- DBM-style map open
144638032Speter*/
144738032Speter
144838032Speterbool
144938032Speterndbm_map_open(map, mode)
145038032Speter	MAP *map;
145138032Speter	int mode;
145238032Speter{
145338032Speter	register DBM *dbm;
145464562Sgshapiro	int save_errno;
145538032Speter	int dfd;
145638032Speter	int pfd;
145764562Sgshapiro	long sff;
145838032Speter	int ret;
145938032Speter	int smode = S_IREAD;
146098121Sgshapiro	char dirfile[MAXPATHLEN];
146198121Sgshapiro	char pagfile[MAXPATHLEN];
146264562Sgshapiro	struct stat st;
146338032Speter	struct stat std, stp;
146438032Speter
146538032Speter	if (tTd(38, 2))
146690792Sgshapiro		sm_dprintf("ndbm_map_open(%s, %s, %d)\n",
146738032Speter			map->map_mname, map->map_file, mode);
146838032Speter	map->map_lockfd = -1;
146938032Speter	mode &= O_ACCMODE;
147038032Speter
147138032Speter	/* do initial file and directory checks */
1472168515Sgshapiro	if (sm_strlcpyn(dirfile, sizeof(dirfile), 2,
1473168515Sgshapiro			map->map_file, ".dir") >= sizeof(dirfile) ||
1474168515Sgshapiro	    sm_strlcpyn(pagfile, sizeof(pagfile), 2,
1475168515Sgshapiro			map->map_file, ".pag") >= sizeof(pagfile))
147698121Sgshapiro	{
147798121Sgshapiro		errno = 0;
147898121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
147998121Sgshapiro			syserr("dbm map \"%s\": map file %s name too long",
148098121Sgshapiro				map->map_mname, map->map_file);
148198121Sgshapiro		return false;
148298121Sgshapiro	}
148338032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
148438032Speter	if (mode == O_RDWR)
148538032Speter	{
148638032Speter		sff |= SFF_CREAT;
148764562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
148838032Speter			sff |= SFF_NOSLINK;
148964562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
149038032Speter			sff |= SFF_NOHLINK;
149138032Speter		smode = S_IWRITE;
149238032Speter	}
149338032Speter	else
149438032Speter	{
149564562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
149638032Speter			sff |= SFF_NOWLINK;
149738032Speter	}
149864562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
149938032Speter		sff |= SFF_SAFEDIRPATH;
150038032Speter	ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
150190792Sgshapiro		       sff, smode, &std);
150238032Speter	if (ret == 0)
150338032Speter		ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
150438032Speter			       sff, smode, &stp);
150564562Sgshapiro
150638032Speter	if (ret != 0)
150738032Speter	{
150838032Speter		char *prob = "unsafe";
150938032Speter
151038032Speter		/* cannot open this map */
151138032Speter		if (ret == ENOENT)
151238032Speter			prob = "missing";
151338032Speter		if (tTd(38, 2))
151490792Sgshapiro			sm_dprintf("\t%s map file: %d\n", prob, ret);
151538032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
151638032Speter			syserr("dbm map \"%s\": %s map file %s",
151738032Speter				map->map_mname, prob, map->map_file);
151890792Sgshapiro		return false;
151938032Speter	}
152038032Speter	if (std.st_mode == ST_MODE_NOFILE)
152138032Speter		mode |= O_CREAT|O_EXCL;
152238032Speter
152364562Sgshapiro# if LOCK_ON_OPEN
152438032Speter	if (mode == O_RDONLY)
152538032Speter		mode |= O_SHLOCK;
152638032Speter	else
152738032Speter		mode |= O_TRUNC|O_EXLOCK;
152864562Sgshapiro# else /* LOCK_ON_OPEN */
152938032Speter	if ((mode & O_ACCMODE) == O_RDWR)
153038032Speter	{
153164562Sgshapiro#  if NOFTRUNCATE
153238032Speter		/*
153338032Speter		**  Warning: race condition.  Try to lock the file as
153438032Speter		**  quickly as possible after opening it.
153538032Speter		**	This may also have security problems on some systems,
153638032Speter		**	but there isn't anything we can do about it.
153738032Speter		*/
153838032Speter
153938032Speter		mode |= O_TRUNC;
154064562Sgshapiro#  else /* NOFTRUNCATE */
154138032Speter		/*
154238032Speter		**  This ugly code opens the map without truncating it,
154338032Speter		**  locks the file, then truncates it.  Necessary to
154438032Speter		**  avoid race conditions.
154538032Speter		*/
154638032Speter
154738032Speter		int dirfd;
154838032Speter		int pagfd;
154964562Sgshapiro		long sff = SFF_CREAT|SFF_OPENASROOT;
155038032Speter
155164562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
155238032Speter			sff |= SFF_NOSLINK;
155364562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
155438032Speter			sff |= SFF_NOHLINK;
155538032Speter
155638032Speter		dirfd = safeopen(dirfile, mode, DBMMODE, sff);
155738032Speter		pagfd = safeopen(pagfile, mode, DBMMODE, sff);
155838032Speter
155938032Speter		if (dirfd < 0 || pagfd < 0)
156038032Speter		{
156164562Sgshapiro			save_errno = errno;
156238032Speter			if (dirfd >= 0)
156338032Speter				(void) close(dirfd);
156438032Speter			if (pagfd >= 0)
156538032Speter				(void) close(pagfd);
156638032Speter			errno = save_errno;
156738032Speter			syserr("ndbm_map_open: cannot create database %s",
156838032Speter				map->map_file);
156990792Sgshapiro			return false;
157038032Speter		}
157138032Speter		if (ftruncate(dirfd, (off_t) 0) < 0 ||
157238032Speter		    ftruncate(pagfd, (off_t) 0) < 0)
157338032Speter		{
157464562Sgshapiro			save_errno = errno;
157538032Speter			(void) close(dirfd);
157638032Speter			(void) close(pagfd);
157738032Speter			errno = save_errno;
157838032Speter			syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
157938032Speter				map->map_file);
158090792Sgshapiro			return false;
158138032Speter		}
158238032Speter
158338032Speter		/* if new file, get "before" bits for later filechanged check */
158438032Speter		if (std.st_mode == ST_MODE_NOFILE &&
158538032Speter		    (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
158638032Speter		{
158764562Sgshapiro			save_errno = errno;
158838032Speter			(void) close(dirfd);
158938032Speter			(void) close(pagfd);
159038032Speter			errno = save_errno;
159138032Speter			syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
159238032Speter				map->map_file);
159390792Sgshapiro			return false;
159438032Speter		}
159538032Speter
159638032Speter		/* have to save the lock for the duration (bletch) */
159738032Speter		map->map_lockfd = dirfd;
159864562Sgshapiro		(void) close(pagfd);
159938032Speter
160038032Speter		/* twiddle bits for dbm_open */
160138032Speter		mode &= ~(O_CREAT|O_EXCL);
160264562Sgshapiro#  endif /* NOFTRUNCATE */
160338032Speter	}
160464562Sgshapiro# endif /* LOCK_ON_OPEN */
160538032Speter
160638032Speter	/* open the database */
160738032Speter	dbm = dbm_open(map->map_file, mode, DBMMODE);
160838032Speter	if (dbm == NULL)
160938032Speter	{
161064562Sgshapiro		save_errno = errno;
161138032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
161290792Sgshapiro		    aliaswait(map, ".pag", false))
161390792Sgshapiro			return true;
161464562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
161538032Speter		if (map->map_lockfd >= 0)
161664562Sgshapiro			(void) close(map->map_lockfd);
1617363466Sgshapiro# endif
161838032Speter		errno = save_errno;
161938032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
162038032Speter			syserr("Cannot open DBM database %s", map->map_file);
162190792Sgshapiro		return false;
162238032Speter	}
162338032Speter	dfd = dbm_dirfno(dbm);
162438032Speter	pfd = dbm_pagfno(dbm);
162538032Speter	if (dfd == pfd)
162638032Speter	{
162738032Speter		/* heuristic: if files are linked, this is actually gdbm */
162838032Speter		dbm_close(dbm);
162964562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
163038032Speter		if (map->map_lockfd >= 0)
163164562Sgshapiro			(void) close(map->map_lockfd);
1632363466Sgshapiro# endif
163338032Speter		errno = 0;
163438032Speter		syserr("dbm map \"%s\": cannot support GDBM",
163538032Speter			map->map_mname);
163690792Sgshapiro		return false;
163738032Speter	}
163838032Speter
163938032Speter	if (filechanged(dirfile, dfd, &std) ||
164038032Speter	    filechanged(pagfile, pfd, &stp))
164138032Speter	{
164264562Sgshapiro		save_errno = errno;
164338032Speter		dbm_close(dbm);
164464562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
164538032Speter		if (map->map_lockfd >= 0)
164664562Sgshapiro			(void) close(map->map_lockfd);
1647363466Sgshapiro# endif
164838032Speter		errno = save_errno;
164938032Speter		syserr("ndbm_map_open(%s): file changed after open",
165038032Speter			map->map_file);
165190792Sgshapiro		return false;
165238032Speter	}
165338032Speter
165438032Speter	map->map_db1 = (ARBPTR_T) dbm;
165564562Sgshapiro
165664562Sgshapiro	/*
165764562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
165864562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
165964562Sgshapiro	**  map_mtime to be set
166064562Sgshapiro	*/
166164562Sgshapiro
166277349Sgshapiro	if (fstat(pfd, &st) >= 0)
166364562Sgshapiro		map->map_mtime = st.st_mtime;
166464562Sgshapiro
166538032Speter	if (mode == O_RDONLY)
166638032Speter	{
166764562Sgshapiro# if LOCK_ON_OPEN
166838032Speter		if (dfd >= 0)
166938032Speter			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
167038032Speter		if (pfd >= 0)
167138032Speter			(void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
167264562Sgshapiro# endif /* LOCK_ON_OPEN */
167338032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
167490792Sgshapiro		    !aliaswait(map, ".pag", true))
167590792Sgshapiro			return false;
167638032Speter	}
167738032Speter	else
167838032Speter	{
167938032Speter		map->map_mflags |= MF_LOCKED;
168042575Speter		if (geteuid() == 0 && TrustedUid != 0)
168138032Speter		{
168264562Sgshapiro#  if HASFCHOWN
168342575Speter			if (fchown(dfd, TrustedUid, -1) < 0 ||
168442575Speter			    fchown(pfd, TrustedUid, -1) < 0)
168538032Speter			{
168638032Speter				int err = errno;
168738032Speter
168838032Speter				sm_syslog(LOG_ALERT, NOQID,
168938032Speter					  "ownership change on %s failed: %s",
169090792Sgshapiro					  map->map_file, sm_errstring(err));
169138032Speter				message("050 ownership change on %s failed: %s",
169290792Sgshapiro					map->map_file, sm_errstring(err));
169338032Speter			}
169490792Sgshapiro#  else /* HASFCHOWN */
169590792Sgshapiro			sm_syslog(LOG_ALERT, NOQID,
169690792Sgshapiro				  "no fchown(): cannot change ownership on %s",
169790792Sgshapiro				  map->map_file);
169890792Sgshapiro			message("050 no fchown(): cannot change ownership on %s",
169990792Sgshapiro				map->map_file);
170064562Sgshapiro#  endif /* HASFCHOWN */
170138032Speter		}
170238032Speter	}
170390792Sgshapiro	return true;
170438032Speter}
170538032Speter
170638032Speter
170738032Speter/*
170838032Speter**  NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
170938032Speter*/
171038032Speter
171138032Speterchar *
171238032Speterndbm_map_lookup(map, name, av, statp)
171338032Speter	MAP *map;
171438032Speter	char *name;
171538032Speter	char **av;
171638032Speter	int *statp;
171738032Speter{
171838032Speter	datum key, val;
171977349Sgshapiro	int dfd, pfd;
172038032Speter	char keybuf[MAXNAME + 1];
172138032Speter	struct stat stbuf;
172238032Speter
172338032Speter	if (tTd(38, 20))
172490792Sgshapiro		sm_dprintf("ndbm_map_lookup(%s, %s)\n",
172538032Speter			map->map_mname, name);
172638032Speter
172738032Speter	key.dptr = name;
172838032Speter	key.dsize = strlen(name);
172938032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
173038032Speter	{
1731168515Sgshapiro		if (key.dsize > sizeof(keybuf) - 1)
1732168515Sgshapiro			key.dsize = sizeof(keybuf) - 1;
173364562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
173438032Speter		keybuf[key.dsize] = '\0';
173538032Speter		makelower(keybuf);
173638032Speter		key.dptr = keybuf;
173738032Speter	}
173838032Speterlockdbm:
173977349Sgshapiro	dfd = dbm_dirfno((DBM *) map->map_db1);
174077349Sgshapiro	if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
174177349Sgshapiro		(void) lockfile(dfd, map->map_file, ".dir", LOCK_SH);
174277349Sgshapiro	pfd = dbm_pagfno((DBM *) map->map_db1);
174377349Sgshapiro	if (pfd < 0 || fstat(pfd, &stbuf) < 0 ||
174477349Sgshapiro	    stbuf.st_mtime > map->map_mtime)
174538032Speter	{
174638032Speter		/* Reopen the database to sync the cache */
174738032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
174838032Speter								 : O_RDONLY;
174938032Speter
175077349Sgshapiro		if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
175177349Sgshapiro			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
175277349Sgshapiro		map->map_mflags |= MF_CLOSING;
175338032Speter		map->map_class->map_close(map);
175477349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
175538032Speter		if (map->map_class->map_open(map, omode))
175638032Speter		{
175738032Speter			map->map_mflags |= MF_OPEN;
175890792Sgshapiro			map->map_pid = CurrentPid;
1759203004Sgshapiro			if ((omode & O_ACCMODE) == O_RDWR)
176038032Speter				map->map_mflags |= MF_WRITABLE;
176138032Speter			goto lockdbm;
176238032Speter		}
176338032Speter		else
176438032Speter		{
176538032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
176638032Speter			{
176738032Speter				extern MAPCLASS BogusMapClass;
176838032Speter
176938032Speter				*statp = EX_TEMPFAIL;
177090792Sgshapiro				map->map_orgclass = map->map_class;
177138032Speter				map->map_class = &BogusMapClass;
177238032Speter				map->map_mflags |= MF_OPEN;
177390792Sgshapiro				map->map_pid = CurrentPid;
177438032Speter				syserr("Cannot reopen NDBM database %s",
177538032Speter					map->map_file);
177638032Speter			}
177738032Speter			return NULL;
177838032Speter		}
177938032Speter	}
178038032Speter	val.dptr = NULL;
178138032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
178238032Speter	{
178338032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
178438032Speter		if (val.dptr != NULL)
178538032Speter			map->map_mflags &= ~MF_TRY1NULL;
178638032Speter	}
178738032Speter	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
178838032Speter	{
178938032Speter		key.dsize++;
179038032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
179138032Speter		if (val.dptr != NULL)
179238032Speter			map->map_mflags &= ~MF_TRY0NULL;
179338032Speter	}
179477349Sgshapiro	if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
179577349Sgshapiro		(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
179638032Speter	if (val.dptr == NULL)
179738032Speter		return NULL;
179838032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
179938032Speter		return map_rewrite(map, name, strlen(name), NULL);
180038032Speter	else
180138032Speter		return map_rewrite(map, val.dptr, val.dsize, av);
180238032Speter}
180338032Speter
180438032Speter
180538032Speter/*
180638032Speter**  NDBM_MAP_STORE -- store a datum in the database
180738032Speter*/
180838032Speter
180938032Spetervoid
181038032Speterndbm_map_store(map, lhs, rhs)
181138032Speter	register MAP *map;
181238032Speter	char *lhs;
181338032Speter	char *rhs;
181438032Speter{
181538032Speter	datum key;
181638032Speter	datum data;
181764562Sgshapiro	int status;
181838032Speter	char keybuf[MAXNAME + 1];
181938032Speter
182038032Speter	if (tTd(38, 12))
182190792Sgshapiro		sm_dprintf("ndbm_map_store(%s, %s, %s)\n",
182238032Speter			map->map_mname, lhs, rhs);
182338032Speter
182438032Speter	key.dsize = strlen(lhs);
182538032Speter	key.dptr = lhs;
182638032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
182738032Speter	{
1828168515Sgshapiro		if (key.dsize > sizeof(keybuf) - 1)
1829168515Sgshapiro			key.dsize = sizeof(keybuf) - 1;
183064562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
183138032Speter		keybuf[key.dsize] = '\0';
183238032Speter		makelower(keybuf);
183338032Speter		key.dptr = keybuf;
183438032Speter	}
183538032Speter
183638032Speter	data.dsize = strlen(rhs);
183738032Speter	data.dptr = rhs;
183838032Speter
183938032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
184038032Speter	{
184138032Speter		key.dsize++;
184238032Speter		data.dsize++;
184338032Speter	}
184438032Speter
184564562Sgshapiro	status = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
184664562Sgshapiro	if (status > 0)
184738032Speter	{
184838032Speter		if (!bitset(MF_APPEND, map->map_mflags))
184938032Speter			message("050 Warning: duplicate alias name %s", lhs);
185038032Speter		else
185138032Speter		{
185238032Speter			static char *buf = NULL;
185338032Speter			static int bufsiz = 0;
185438032Speter			auto int xstat;
185538032Speter			datum old;
185638032Speter
185738032Speter			old.dptr = ndbm_map_lookup(map, key.dptr,
185890792Sgshapiro						   (char **) NULL, &xstat);
185938032Speter			if (old.dptr != NULL && *(char *) old.dptr != '\0')
186038032Speter			{
186138032Speter				old.dsize = strlen(old.dptr);
186238032Speter				if (data.dsize + old.dsize + 2 > bufsiz)
186338032Speter				{
186438032Speter					if (buf != NULL)
186590792Sgshapiro						(void) sm_free(buf);
186638032Speter					bufsiz = data.dsize + old.dsize + 2;
186790792Sgshapiro					buf = sm_pmalloc_x(bufsiz);
186838032Speter				}
186990792Sgshapiro				(void) sm_strlcpyn(buf, bufsiz, 3,
187090792Sgshapiro					data.dptr, ",", old.dptr);
187138032Speter				data.dsize = data.dsize + old.dsize + 1;
187238032Speter				data.dptr = buf;
187338032Speter				if (tTd(38, 9))
187490792Sgshapiro					sm_dprintf("ndbm_map_store append=%s\n",
1875363466Sgshapiro						data.dptr);
187638032Speter			}
187738032Speter		}
187864562Sgshapiro		status = dbm_store((DBM *) map->map_db1,
187964562Sgshapiro				   key, data, DBM_REPLACE);
188038032Speter	}
188164562Sgshapiro	if (status != 0)
188264562Sgshapiro		syserr("readaliases: dbm put (%s): %d", lhs, status);
188338032Speter}
188438032Speter
188538032Speter
188638032Speter/*
188738032Speter**  NDBM_MAP_CLOSE -- close the database
188838032Speter*/
188938032Speter
189038032Spetervoid
189138032Speterndbm_map_close(map)
189238032Speter	register MAP  *map;
189338032Speter{
189438032Speter	if (tTd(38, 9))
189590792Sgshapiro		sm_dprintf("ndbm_map_close(%s, %s, %lx)\n",
189638032Speter			map->map_mname, map->map_file, map->map_mflags);
189738032Speter
189838032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
189938032Speter	{
190064562Sgshapiro# ifdef NDBM_YP_COMPAT
190138032Speter		bool inclnull;
190242575Speter		char buf[MAXHOSTNAMELEN];
190338032Speter
190438032Speter		inclnull = bitset(MF_INCLNULL, map->map_mflags);
190538032Speter		map->map_mflags &= ~MF_INCLNULL;
190638032Speter
190738032Speter		if (strstr(map->map_file, "/yp/") != NULL)
190838032Speter		{
190938032Speter			long save_mflags = map->map_mflags;
191038032Speter
191138032Speter			map->map_mflags |= MF_NOFOLDCASE;
191238032Speter
1913168515Sgshapiro			(void) sm_snprintf(buf, sizeof(buf), "%010ld", curtime());
191438032Speter			ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
191538032Speter
1916168515Sgshapiro			(void) gethostname(buf, sizeof(buf));
191738032Speter			ndbm_map_store(map, "YP_MASTER_NAME", buf);
191838032Speter
191938032Speter			map->map_mflags = save_mflags;
192038032Speter		}
192138032Speter
192238032Speter		if (inclnull)
192338032Speter			map->map_mflags |= MF_INCLNULL;
192464562Sgshapiro# endif /* NDBM_YP_COMPAT */
192538032Speter
192638032Speter		/* write out the distinguished alias */
192738032Speter		ndbm_map_store(map, "@", "@");
192838032Speter	}
192938032Speter	dbm_close((DBM *) map->map_db1);
193038032Speter
193138032Speter	/* release lock (if needed) */
193264562Sgshapiro# if !LOCK_ON_OPEN
193338032Speter	if (map->map_lockfd >= 0)
193438032Speter		(void) close(map->map_lockfd);
1935363466Sgshapiro# endif
193638032Speter}
193738032Speter
193864562Sgshapiro#endif /* NDBM */
193990792Sgshapiro/*
194038032Speter**  NEWDB (Hash and BTree) Modules
194138032Speter*/
194238032Speter
194390792Sgshapiro#if NEWDB
194438032Speter
194538032Speter/*
194638032Speter**  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
194738032Speter**
194838032Speter**	These do rather bizarre locking.  If you can lock on open,
194938032Speter**	do that to avoid the condition of opening a database that
195038032Speter**	is being rebuilt.  If you don't, we'll try to fake it, but
195138032Speter**	there will be a race condition.  If opening for read-only,
195238032Speter**	we immediately release the lock to avoid freezing things up.
195338032Speter**	We really ought to hold the lock, but guarantee that we won't
195438032Speter**	be pokey about it.  That's hard to do.
195538032Speter*/
195638032Speter
195738032Speter/* these should be K line arguments */
195864562Sgshapiro# if DB_VERSION_MAJOR < 2
195964562Sgshapiro#  define db_cachesize	cachesize
196064562Sgshapiro#  define h_nelem	nelem
196164562Sgshapiro#  ifndef DB_CACHE_SIZE
196264562Sgshapiro#   define DB_CACHE_SIZE	(1024 * 1024)	/* database memory cache size */
1963363466Sgshapiro#  endif
196464562Sgshapiro#  ifndef DB_HASH_NELEM
196564562Sgshapiro#   define DB_HASH_NELEM	4096		/* (starting) size of hash table */
1966363466Sgshapiro#  endif
196764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
196838032Speter
196938032Speterbool
197038032Speterbt_map_open(map, mode)
197138032Speter	MAP *map;
197238032Speter	int mode;
197338032Speter{
197464562Sgshapiro# if DB_VERSION_MAJOR < 2
197538032Speter	BTREEINFO btinfo;
1976363466Sgshapiro# endif
197764562Sgshapiro# if DB_VERSION_MAJOR == 2
197838032Speter	DB_INFO btinfo;
1979363466Sgshapiro# endif
198064562Sgshapiro# if DB_VERSION_MAJOR > 2
198164562Sgshapiro	void *btinfo = NULL;
1982363466Sgshapiro# endif
198338032Speter
198438032Speter	if (tTd(38, 2))
198590792Sgshapiro		sm_dprintf("bt_map_open(%s, %s, %d)\n",
198638032Speter			map->map_mname, map->map_file, mode);
198738032Speter
198864562Sgshapiro# if DB_VERSION_MAJOR < 3
1989168515Sgshapiro	memset(&btinfo, '\0', sizeof(btinfo));
199064562Sgshapiro#  ifdef DB_CACHE_SIZE
199138032Speter	btinfo.db_cachesize = DB_CACHE_SIZE;
1992363466Sgshapiro#  endif
199364562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
199464562Sgshapiro
199538032Speter	return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
199638032Speter}
199738032Speter
199838032Speterbool
199938032Speterhash_map_open(map, mode)
200038032Speter	MAP *map;
200138032Speter	int mode;
200238032Speter{
200364562Sgshapiro# if DB_VERSION_MAJOR < 2
200438032Speter	HASHINFO hinfo;
2005363466Sgshapiro# endif
200664562Sgshapiro# if DB_VERSION_MAJOR == 2
200738032Speter	DB_INFO hinfo;
2008363466Sgshapiro# endif
200964562Sgshapiro# if DB_VERSION_MAJOR > 2
201064562Sgshapiro	void *hinfo = NULL;
2011363466Sgshapiro# endif
201238032Speter
201338032Speter	if (tTd(38, 2))
201490792Sgshapiro		sm_dprintf("hash_map_open(%s, %s, %d)\n",
201538032Speter			map->map_mname, map->map_file, mode);
201638032Speter
201764562Sgshapiro# if DB_VERSION_MAJOR < 3
2018168515Sgshapiro	memset(&hinfo, '\0', sizeof(hinfo));
201964562Sgshapiro#  ifdef DB_HASH_NELEM
202038032Speter	hinfo.h_nelem = DB_HASH_NELEM;
2021363466Sgshapiro#  endif
202264562Sgshapiro#  ifdef DB_CACHE_SIZE
202338032Speter	hinfo.db_cachesize = DB_CACHE_SIZE;
2024363466Sgshapiro#  endif
202564562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
202664562Sgshapiro
202738032Speter	return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
202838032Speter}
202938032Speter
203064562Sgshapirostatic bool
203138032Speterdb_map_open(map, mode, mapclassname, dbtype, openinfo)
203238032Speter	MAP *map;
203338032Speter	int mode;
203438032Speter	char *mapclassname;
203538032Speter	DBTYPE dbtype;
203664562Sgshapiro# if DB_VERSION_MAJOR < 2
203738032Speter	const void *openinfo;
2038363466Sgshapiro# endif
203964562Sgshapiro# if DB_VERSION_MAJOR == 2
204038032Speter	DB_INFO *openinfo;
2041363466Sgshapiro# endif
204264562Sgshapiro# if DB_VERSION_MAJOR > 2
204364562Sgshapiro	void **openinfo;
2044363466Sgshapiro# endif
204538032Speter{
204638032Speter	DB *db = NULL;
204738032Speter	int i;
204838032Speter	int omode;
204938032Speter	int smode = S_IREAD;
205038032Speter	int fd;
205164562Sgshapiro	long sff;
205264562Sgshapiro	int save_errno;
205338032Speter	struct stat st;
205498121Sgshapiro	char buf[MAXPATHLEN];
205538032Speter
205638032Speter	/* do initial file and directory checks */
2057168515Sgshapiro	if (sm_strlcpy(buf, map->map_file, sizeof(buf)) >= sizeof(buf))
205898121Sgshapiro	{
205998121Sgshapiro		errno = 0;
206098121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
206198121Sgshapiro			syserr("map \"%s\": map file %s name too long",
206298121Sgshapiro				map->map_mname, map->map_file);
206398121Sgshapiro		return false;
206498121Sgshapiro	}
206538032Speter	i = strlen(buf);
206638032Speter	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
206798121Sgshapiro	{
2068168515Sgshapiro		if (sm_strlcat(buf, ".db", sizeof(buf)) >= sizeof(buf))
206998121Sgshapiro		{
207098121Sgshapiro			errno = 0;
207198121Sgshapiro			if (!bitset(MF_OPTIONAL, map->map_mflags))
207298121Sgshapiro				syserr("map \"%s\": map file %s name too long",
207398121Sgshapiro					map->map_mname, map->map_file);
207498121Sgshapiro			return false;
207598121Sgshapiro		}
207698121Sgshapiro	}
207738032Speter
207838032Speter	mode &= O_ACCMODE;
207938032Speter	omode = mode;
208038032Speter
208138032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
208238032Speter	if (mode == O_RDWR)
208338032Speter	{
208438032Speter		sff |= SFF_CREAT;
208564562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
208638032Speter			sff |= SFF_NOSLINK;
208764562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
208838032Speter			sff |= SFF_NOHLINK;
208938032Speter		smode = S_IWRITE;
209038032Speter	}
209138032Speter	else
209238032Speter	{
209364562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
209438032Speter			sff |= SFF_NOWLINK;
209538032Speter	}
209664562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
209738032Speter		sff |= SFF_SAFEDIRPATH;
209838032Speter	i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
209964562Sgshapiro
210038032Speter	if (i != 0)
210138032Speter	{
210238032Speter		char *prob = "unsafe";
210338032Speter
210438032Speter		/* cannot open this map */
210538032Speter		if (i == ENOENT)
210638032Speter			prob = "missing";
210738032Speter		if (tTd(38, 2))
210890792Sgshapiro			sm_dprintf("\t%s map file: %s\n", prob, sm_errstring(i));
210938032Speter		errno = i;
211038032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
211138032Speter			syserr("%s map \"%s\": %s map file %s",
211238032Speter				mapclassname, map->map_mname, prob, buf);
211390792Sgshapiro		return false;
211438032Speter	}
211538032Speter	if (st.st_mode == ST_MODE_NOFILE)
211638032Speter		omode |= O_CREAT|O_EXCL;
211738032Speter
211838032Speter	map->map_lockfd = -1;
211938032Speter
212064562Sgshapiro# if LOCK_ON_OPEN
212138032Speter	if (mode == O_RDWR)
212238032Speter		omode |= O_TRUNC|O_EXLOCK;
212338032Speter	else
212438032Speter		omode |= O_SHLOCK;
212564562Sgshapiro# else /* LOCK_ON_OPEN */
212638032Speter	/*
212738032Speter	**  Pre-lock the file to avoid race conditions.  In particular,
212838032Speter	**  since dbopen returns NULL if the file is zero length, we
212938032Speter	**  must have a locked instance around the dbopen.
213038032Speter	*/
213138032Speter
213238032Speter	fd = open(buf, omode, DBMMODE);
213338032Speter	if (fd < 0)
213438032Speter	{
213538032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
213638032Speter			syserr("db_map_open: cannot pre-open database %s", buf);
213790792Sgshapiro		return false;
213838032Speter	}
213938032Speter
214038032Speter	/* make sure no baddies slipped in just before the open... */
214138032Speter	if (filechanged(buf, fd, &st))
214238032Speter	{
214364562Sgshapiro		save_errno = errno;
214438032Speter		(void) close(fd);
214538032Speter		errno = save_errno;
214638032Speter		syserr("db_map_open(%s): file changed after pre-open", buf);
214790792Sgshapiro		return false;
214838032Speter	}
214938032Speter
215038032Speter	/* if new file, get the "before" bits for later filechanged check */
215138032Speter	if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
215238032Speter	{
215364562Sgshapiro		save_errno = errno;
215438032Speter		(void) close(fd);
215538032Speter		errno = save_errno;
215638032Speter		syserr("db_map_open(%s): cannot fstat pre-opened file",
215738032Speter			buf);
215890792Sgshapiro		return false;
215938032Speter	}
216038032Speter
216138032Speter	/* actually lock the pre-opened file */
216238032Speter	if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
216338032Speter		syserr("db_map_open: cannot lock %s", buf);
216438032Speter
216538032Speter	/* set up mode bits for dbopen */
216638032Speter	if (mode == O_RDWR)
216738032Speter		omode |= O_TRUNC;
216838032Speter	omode &= ~(O_EXCL|O_CREAT);
216964562Sgshapiro# endif /* LOCK_ON_OPEN */
217038032Speter
217164562Sgshapiro# if DB_VERSION_MAJOR < 2
217238032Speter	db = dbopen(buf, omode, DBMMODE, dbtype, openinfo);
217364562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
217438032Speter	{
217538032Speter		int flags = 0;
217664562Sgshapiro#  if DB_VERSION_MAJOR > 2
217764562Sgshapiro		int ret;
2178363466Sgshapiro#  endif
217938032Speter
218038032Speter		if (mode == O_RDONLY)
218138032Speter			flags |= DB_RDONLY;
218238032Speter		if (bitset(O_CREAT, omode))
218338032Speter			flags |= DB_CREATE;
218438032Speter		if (bitset(O_TRUNC, omode))
218538032Speter			flags |= DB_TRUNCATE;
2186110560Sgshapiro		SM_DB_FLAG_ADD(flags);
218738032Speter
218864562Sgshapiro#  if DB_VERSION_MAJOR > 2
218964562Sgshapiro		ret = db_create(&db, NULL, 0);
219064562Sgshapiro#  ifdef DB_CACHE_SIZE
219164562Sgshapiro		if (ret == 0 && db != NULL)
219264562Sgshapiro		{
219364562Sgshapiro			ret = db->set_cachesize(db, 0, DB_CACHE_SIZE, 0);
219464562Sgshapiro			if (ret != 0)
219564562Sgshapiro			{
219664562Sgshapiro				(void) db->close(db, 0);
219764562Sgshapiro				db = NULL;
219864562Sgshapiro			}
219964562Sgshapiro		}
220064562Sgshapiro#  endif /* DB_CACHE_SIZE */
220164562Sgshapiro#  ifdef DB_HASH_NELEM
220264562Sgshapiro		if (dbtype == DB_HASH && ret == 0 && db != NULL)
220364562Sgshapiro		{
220464562Sgshapiro			ret = db->set_h_nelem(db, DB_HASH_NELEM);
220564562Sgshapiro			if (ret != 0)
220664562Sgshapiro			{
220764562Sgshapiro				(void) db->close(db, 0);
220864562Sgshapiro				db = NULL;
220964562Sgshapiro			}
221064562Sgshapiro		}
221164562Sgshapiro#  endif /* DB_HASH_NELEM */
221264562Sgshapiro		if (ret == 0 && db != NULL)
221364562Sgshapiro		{
2214110560Sgshapiro			ret = db->open(db,
2215110560Sgshapiro					DBTXN	/* transaction for DB 4.1 */
2216110560Sgshapiro					buf, NULL, dbtype, flags, DBMMODE);
221764562Sgshapiro			if (ret != 0)
221864562Sgshapiro			{
221973188Sgshapiro#ifdef DB_OLD_VERSION
222073188Sgshapiro				if (ret == DB_OLD_VERSION)
222173188Sgshapiro					ret = EINVAL;
222273188Sgshapiro#endif /* DB_OLD_VERSION */
222364562Sgshapiro				(void) db->close(db, 0);
222464562Sgshapiro				db = NULL;
222564562Sgshapiro			}
222664562Sgshapiro		}
222764562Sgshapiro		errno = ret;
222864562Sgshapiro#  else /* DB_VERSION_MAJOR > 2 */
222938032Speter		errno = db_open(buf, dbtype, flags, DBMMODE,
223038032Speter				NULL, openinfo, &db);
223164562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
223238032Speter	}
223364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
223464562Sgshapiro	save_errno = errno;
223538032Speter
223664562Sgshapiro# if !LOCK_ON_OPEN
223738032Speter	if (mode == O_RDWR)
223838032Speter		map->map_lockfd = fd;
223938032Speter	else
224038032Speter		(void) close(fd);
224164562Sgshapiro# endif /* !LOCK_ON_OPEN */
224238032Speter
224338032Speter	if (db == NULL)
224438032Speter	{
224538032Speter		if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
224690792Sgshapiro		    aliaswait(map, ".db", false))
224790792Sgshapiro			return true;
224864562Sgshapiro# if !LOCK_ON_OPEN
224938032Speter		if (map->map_lockfd >= 0)
225038032Speter			(void) close(map->map_lockfd);
2251363466Sgshapiro# endif
225264562Sgshapiro		errno = save_errno;
225338032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
225438032Speter			syserr("Cannot open %s database %s",
225538032Speter				mapclassname, buf);
225690792Sgshapiro		return false;
225738032Speter	}
225838032Speter
225964562Sgshapiro# if DB_VERSION_MAJOR < 2
226038032Speter	fd = db->fd(db);
2261363466Sgshapiro# else
226238032Speter	fd = -1;
226338032Speter	errno = db->fd(db, &fd);
226464562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
226538032Speter	if (filechanged(buf, fd, &st))
226638032Speter	{
226764562Sgshapiro		save_errno = errno;
226864562Sgshapiro# if DB_VERSION_MAJOR < 2
226964562Sgshapiro		(void) db->close(db);
2270363466Sgshapiro# else
227138032Speter		errno = db->close(db, 0);
227264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
227364562Sgshapiro# if !LOCK_ON_OPEN
227438032Speter		if (map->map_lockfd >= 0)
227564562Sgshapiro			(void) close(map->map_lockfd);
2276363466Sgshapiro# endif
227738032Speter		errno = save_errno;
227838032Speter		syserr("db_map_open(%s): file changed after open", buf);
227990792Sgshapiro		return false;
228038032Speter	}
228138032Speter
228238032Speter	if (mode == O_RDWR)
228338032Speter		map->map_mflags |= MF_LOCKED;
228464562Sgshapiro# if LOCK_ON_OPEN
228538032Speter	if (fd >= 0 && mode == O_RDONLY)
228638032Speter	{
228738032Speter		(void) lockfile(fd, buf, NULL, LOCK_UN);
228838032Speter	}
228964562Sgshapiro# endif /* LOCK_ON_OPEN */
229038032Speter
229138032Speter	/* try to make sure that at least the database header is on disk */
229238032Speter	if (mode == O_RDWR)
229338032Speter	{
229438032Speter		(void) db->sync(db, 0);
229542575Speter		if (geteuid() == 0 && TrustedUid != 0)
229638032Speter		{
229764562Sgshapiro#  if HASFCHOWN
229842575Speter			if (fchown(fd, TrustedUid, -1) < 0)
229938032Speter			{
230038032Speter				int err = errno;
230138032Speter
230238032Speter				sm_syslog(LOG_ALERT, NOQID,
230338032Speter					  "ownership change on %s failed: %s",
230490792Sgshapiro					  buf, sm_errstring(err));
230538032Speter				message("050 ownership change on %s failed: %s",
230690792Sgshapiro					buf, sm_errstring(err));
230738032Speter			}
230890792Sgshapiro#  else /* HASFCHOWN */
230990792Sgshapiro			sm_syslog(LOG_ALERT, NOQID,
231090792Sgshapiro				  "no fchown(): cannot change ownership on %s",
231190792Sgshapiro				  map->map_file);
231290792Sgshapiro			message("050 no fchown(): cannot change ownership on %s",
231390792Sgshapiro				map->map_file);
231464562Sgshapiro#  endif /* HASFCHOWN */
231538032Speter		}
231638032Speter	}
231738032Speter
231864562Sgshapiro	map->map_db2 = (ARBPTR_T) db;
231964562Sgshapiro
232064562Sgshapiro	/*
232164562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
232264562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
232364562Sgshapiro	**  map_mtime to be set
232464562Sgshapiro	*/
232564562Sgshapiro
232638032Speter	if (fd >= 0 && fstat(fd, &st) >= 0)
232738032Speter		map->map_mtime = st.st_mtime;
232838032Speter
232938032Speter	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
233090792Sgshapiro	    !aliaswait(map, ".db", true))
233190792Sgshapiro		return false;
233290792Sgshapiro	return true;
233338032Speter}
233438032Speter
233538032Speter
233638032Speter/*
233738032Speter**  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
233838032Speter*/
233938032Speter
234038032Speterchar *
234138032Speterdb_map_lookup(map, name, av, statp)
234238032Speter	MAP *map;
234338032Speter	char *name;
234438032Speter	char **av;
234538032Speter	int *statp;
234638032Speter{
234738032Speter	DBT key, val;
234838032Speter	register DB *db = (DB *) map->map_db2;
234938032Speter	int i;
235038032Speter	int st;
235164562Sgshapiro	int save_errno;
235238032Speter	int fd;
235338032Speter	struct stat stbuf;
235438032Speter	char keybuf[MAXNAME + 1];
235598121Sgshapiro	char buf[MAXPATHLEN];
235638032Speter
2357168515Sgshapiro	memset(&key, '\0', sizeof(key));
2358168515Sgshapiro	memset(&val, '\0', sizeof(val));
235938032Speter
236038032Speter	if (tTd(38, 20))
236190792Sgshapiro		sm_dprintf("db_map_lookup(%s, %s)\n",
236238032Speter			map->map_mname, name);
236338032Speter
2364168515Sgshapiro	if (sm_strlcpy(buf, map->map_file, sizeof(buf)) >= sizeof(buf))
236598121Sgshapiro	{
236698121Sgshapiro		errno = 0;
236798121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
236898121Sgshapiro			syserr("map \"%s\": map file %s name too long",
236998121Sgshapiro				map->map_mname, map->map_file);
237098121Sgshapiro		return NULL;
237198121Sgshapiro	}
237298121Sgshapiro	i = strlen(buf);
237338032Speter	if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
237438032Speter		buf[i - 3] = '\0';
237538032Speter
237638032Speter	key.size = strlen(name);
2377168515Sgshapiro	if (key.size > sizeof(keybuf) - 1)
2378168515Sgshapiro		key.size = sizeof(keybuf) - 1;
237938032Speter	key.data = keybuf;
238064562Sgshapiro	memmove(keybuf, name, key.size);
238138032Speter	keybuf[key.size] = '\0';
238238032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
238338032Speter		makelower(keybuf);
238438032Speter  lockdb:
238564562Sgshapiro# if DB_VERSION_MAJOR < 2
238638032Speter	fd = db->fd(db);
2387363466Sgshapiro# else
238838032Speter	fd = -1;
238938032Speter	errno = db->fd(db, &fd);
239064562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
239138032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
239238032Speter		(void) lockfile(fd, buf, ".db", LOCK_SH);
239338032Speter	if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
239438032Speter	{
239538032Speter		/* Reopen the database to sync the cache */
239638032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
239738032Speter								 : O_RDONLY;
239838032Speter
239964562Sgshapiro		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
240064562Sgshapiro			(void) lockfile(fd, buf, ".db", LOCK_UN);
240177349Sgshapiro		map->map_mflags |= MF_CLOSING;
240238032Speter		map->map_class->map_close(map);
240377349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
240438032Speter		if (map->map_class->map_open(map, omode))
240538032Speter		{
240638032Speter			map->map_mflags |= MF_OPEN;
240790792Sgshapiro			map->map_pid = CurrentPid;
2408203004Sgshapiro			if ((omode & O_ACCMODE) == O_RDWR)
240938032Speter				map->map_mflags |= MF_WRITABLE;
241038032Speter			db = (DB *) map->map_db2;
241138032Speter			goto lockdb;
241238032Speter		}
241338032Speter		else
241438032Speter		{
241538032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
241638032Speter			{
241738032Speter				extern MAPCLASS BogusMapClass;
241838032Speter
241938032Speter				*statp = EX_TEMPFAIL;
242090792Sgshapiro				map->map_orgclass = map->map_class;
242138032Speter				map->map_class = &BogusMapClass;
242238032Speter				map->map_mflags |= MF_OPEN;
242390792Sgshapiro				map->map_pid = CurrentPid;
242438032Speter				syserr("Cannot reopen DB database %s",
242538032Speter					map->map_file);
242638032Speter			}
242738032Speter			return NULL;
242838032Speter		}
242938032Speter	}
243038032Speter
243138032Speter	st = 1;
243238032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
243338032Speter	{
243464562Sgshapiro# if DB_VERSION_MAJOR < 2
243538032Speter		st = db->get(db, &key, &val, 0);
243664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
243738032Speter		errno = db->get(db, NULL, &key, &val, 0);
243838032Speter		switch (errno)
243938032Speter		{
244038032Speter		  case DB_NOTFOUND:
244138032Speter		  case DB_KEYEMPTY:
244238032Speter			st = 1;
244338032Speter			break;
244438032Speter
244538032Speter		  case 0:
244638032Speter			st = 0;
244738032Speter			break;
244838032Speter
244938032Speter		  default:
245038032Speter			st = -1;
245138032Speter			break;
245238032Speter		}
245364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
245438032Speter		if (st == 0)
245538032Speter			map->map_mflags &= ~MF_TRY1NULL;
245638032Speter	}
245738032Speter	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
245838032Speter	{
245938032Speter		key.size++;
246064562Sgshapiro# if DB_VERSION_MAJOR < 2
246138032Speter		st = db->get(db, &key, &val, 0);
246264562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
246338032Speter		errno = db->get(db, NULL, &key, &val, 0);
246438032Speter		switch (errno)
246538032Speter		{
246638032Speter		  case DB_NOTFOUND:
246738032Speter		  case DB_KEYEMPTY:
246838032Speter			st = 1;
246938032Speter			break;
247038032Speter
247138032Speter		  case 0:
247238032Speter			st = 0;
247338032Speter			break;
247438032Speter
247538032Speter		  default:
247638032Speter			st = -1;
247738032Speter			break;
247838032Speter		}
247964562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
248038032Speter		if (st == 0)
248138032Speter			map->map_mflags &= ~MF_TRY0NULL;
248238032Speter	}
248364562Sgshapiro	save_errno = errno;
248438032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
248538032Speter		(void) lockfile(fd, buf, ".db", LOCK_UN);
248638032Speter	if (st != 0)
248738032Speter	{
248864562Sgshapiro		errno = save_errno;
248938032Speter		if (st < 0)
249038032Speter			syserr("db_map_lookup: get (%s)", name);
249138032Speter		return NULL;
249238032Speter	}
249338032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
249438032Speter		return map_rewrite(map, name, strlen(name), NULL);
249538032Speter	else
249638032Speter		return map_rewrite(map, val.data, val.size, av);
249738032Speter}
249838032Speter
249938032Speter
250038032Speter/*
250138032Speter**  DB_MAP_STORE -- store a datum in the NEWDB database
250238032Speter*/
250338032Speter
250438032Spetervoid
250538032Speterdb_map_store(map, lhs, rhs)
250638032Speter	register MAP *map;
250738032Speter	char *lhs;
250838032Speter	char *rhs;
250938032Speter{
251064562Sgshapiro	int status;
251138032Speter	DBT key;
251238032Speter	DBT data;
251338032Speter	register DB *db = map->map_db2;
251438032Speter	char keybuf[MAXNAME + 1];
251538032Speter
2516168515Sgshapiro	memset(&key, '\0', sizeof(key));
2517168515Sgshapiro	memset(&data, '\0', sizeof(data));
251838032Speter
251938032Speter	if (tTd(38, 12))
252090792Sgshapiro		sm_dprintf("db_map_store(%s, %s, %s)\n",
252138032Speter			map->map_mname, lhs, rhs);
252238032Speter
252338032Speter	key.size = strlen(lhs);
252438032Speter	key.data = lhs;
252538032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
252638032Speter	{
2527168515Sgshapiro		if (key.size > sizeof(keybuf) - 1)
2528168515Sgshapiro			key.size = sizeof(keybuf) - 1;
252964562Sgshapiro		memmove(keybuf, key.data, key.size);
253038032Speter		keybuf[key.size] = '\0';
253138032Speter		makelower(keybuf);
253238032Speter		key.data = keybuf;
253338032Speter	}
253438032Speter
253538032Speter	data.size = strlen(rhs);
253638032Speter	data.data = rhs;
253738032Speter
253838032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
253938032Speter	{
254038032Speter		key.size++;
254138032Speter		data.size++;
254238032Speter	}
254338032Speter
254464562Sgshapiro# if DB_VERSION_MAJOR < 2
254564562Sgshapiro	status = db->put(db, &key, &data, R_NOOVERWRITE);
254664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
254738032Speter	errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE);
254838032Speter	switch (errno)
254938032Speter	{
255038032Speter	  case DB_KEYEXIST:
255164562Sgshapiro		status = 1;
255238032Speter		break;
255338032Speter
255438032Speter	  case 0:
255564562Sgshapiro		status = 0;
255638032Speter		break;
255738032Speter
255838032Speter	  default:
255964562Sgshapiro		status = -1;
256038032Speter		break;
256138032Speter	}
256264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
256364562Sgshapiro	if (status > 0)
256438032Speter	{
256538032Speter		if (!bitset(MF_APPEND, map->map_mflags))
256638032Speter			message("050 Warning: duplicate alias name %s", lhs);
256738032Speter		else
256838032Speter		{
256938032Speter			static char *buf = NULL;
257038032Speter			static int bufsiz = 0;
257138032Speter			DBT old;
257238032Speter
2573168515Sgshapiro			memset(&old, '\0', sizeof(old));
257438032Speter
257564562Sgshapiro			old.data = db_map_lookup(map, key.data,
257690792Sgshapiro						 (char **) NULL, &status);
257738032Speter			if (old.data != NULL)
257838032Speter			{
257938032Speter				old.size = strlen(old.data);
258090792Sgshapiro				if (data.size + old.size + 2 > (size_t) bufsiz)
258138032Speter				{
258238032Speter					if (buf != NULL)
258377349Sgshapiro						sm_free(buf);
258438032Speter					bufsiz = data.size + old.size + 2;
258590792Sgshapiro					buf = sm_pmalloc_x(bufsiz);
258638032Speter				}
258790792Sgshapiro				(void) sm_strlcpyn(buf, bufsiz, 3,
258890792Sgshapiro					(char *) data.data, ",",
258990792Sgshapiro					(char *) old.data);
259038032Speter				data.size = data.size + old.size + 1;
259138032Speter				data.data = buf;
259238032Speter				if (tTd(38, 9))
259390792Sgshapiro					sm_dprintf("db_map_store append=%s\n",
259464562Sgshapiro						(char *) data.data);
259538032Speter			}
259638032Speter		}
259764562Sgshapiro# if DB_VERSION_MAJOR < 2
259864562Sgshapiro		status = db->put(db, &key, &data, 0);
2599363466Sgshapiro# else
260064562Sgshapiro		status = errno = db->put(db, NULL, &key, &data, 0);
260164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
260238032Speter	}
260364562Sgshapiro	if (status != 0)
260438032Speter		syserr("readaliases: db put (%s)", lhs);
260538032Speter}
260638032Speter
260738032Speter
260838032Speter/*
260938032Speter**  DB_MAP_CLOSE -- add distinguished entries and close the database
261038032Speter*/
261138032Speter
261238032Spetervoid
261338032Speterdb_map_close(map)
261438032Speter	MAP *map;
261538032Speter{
261638032Speter	register DB *db = map->map_db2;
261738032Speter
261838032Speter	if (tTd(38, 9))
261990792Sgshapiro		sm_dprintf("db_map_close(%s, %s, %lx)\n",
262038032Speter			map->map_mname, map->map_file, map->map_mflags);
262138032Speter
262238032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
262338032Speter	{
262438032Speter		/* write out the distinguished alias */
262538032Speter		db_map_store(map, "@", "@");
262638032Speter	}
262738032Speter
262838032Speter	(void) db->sync(db, 0);
262938032Speter
263064562Sgshapiro# if !LOCK_ON_OPEN
263138032Speter	if (map->map_lockfd >= 0)
263238032Speter		(void) close(map->map_lockfd);
263364562Sgshapiro# endif /* !LOCK_ON_OPEN */
263438032Speter
263564562Sgshapiro# if DB_VERSION_MAJOR < 2
263638032Speter	if (db->close(db) != 0)
263764562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
263842575Speter	/*
263942575Speter	**  Berkeley DB can use internal shared memory
264042575Speter	**  locking for its memory pool.  Closing a map
264142575Speter	**  opened by another process will interfere
264242575Speter	**  with the shared memory and locks of the parent
264342575Speter	**  process leaving things in a bad state.
264443730Speter	*/
264543730Speter
264643730Speter	/*
264742575Speter	**  If this map was not opened by the current
264843730Speter	**  process, do not close the map but recover
264942575Speter	**  the file descriptor.
265042575Speter	*/
265190792Sgshapiro
265290792Sgshapiro	if (map->map_pid != CurrentPid)
265342575Speter	{
265442575Speter		int fd = -1;
265542575Speter
265642575Speter		errno = db->fd(db, &fd);
265742575Speter		if (fd >= 0)
265842575Speter			(void) close(fd);
265942575Speter		return;
266042575Speter	}
266142575Speter
266238032Speter	if ((errno = db->close(db, 0)) != 0)
266364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
266442575Speter		syserr("db_map_close(%s, %s, %lx): db close failure",
266542575Speter			map->map_mname, map->map_file, map->map_mflags);
266638032Speter}
266764562Sgshapiro#endif /* NEWDB */
2668363466Sgshapiro
2669363466Sgshapiro#if CDB
267090792Sgshapiro/*
2671363466Sgshapiro**  CDB Modules
2672363466Sgshapiro*/
2673363466Sgshapiro
2674363466Sgshapirostatic bool	smdb_add_extension __P((char *, int, char *, char *));
2675363466Sgshapiro
2676363466Sgshapiro/*
2677363466Sgshapiro**  SMDB_ADD_EXTENSION -- Adds an extension to a file name.
2678363466Sgshapiro**
2679363466Sgshapiro**	Just adds a . followed by a string to a db_name if there
2680363466Sgshapiro**	is room and the db_name does not already have that extension.
2681363466Sgshapiro**
2682363466Sgshapiro**	Parameters:
2683363466Sgshapiro**		full_name -- The final file name.
2684363466Sgshapiro**		max_full_name_len -- The max length for full_name.
2685363466Sgshapiro**		db_name -- The name of the db.
2686363466Sgshapiro**		extension -- The extension to add.
2687363466Sgshapiro**
2688363466Sgshapiro**	Returns:
2689363466Sgshapiro**		SMDBE_OK -- Success.
2690363466Sgshapiro**		Anything else is an error. Look up more info about the
2691363466Sgshapiro**		error in the comments for the specific open() used.
2692363466Sgshapiro*/
2693363466Sgshapiro
2694363466Sgshapirostatic bool
2695363466Sgshapirosmdb_add_extension(full_name, max_full_name_len, db_name, extension)
2696363466Sgshapiro	char *full_name;
2697363466Sgshapiro	int max_full_name_len;
2698363466Sgshapiro	char *db_name;
2699363466Sgshapiro	char *extension;
2700363466Sgshapiro{
2701363466Sgshapiro	int extension_len;
2702363466Sgshapiro	int db_name_len;
2703363466Sgshapiro
2704363466Sgshapiro	if (full_name == NULL || db_name == NULL || extension == NULL)
2705363466Sgshapiro		return false; /* SMDBE_INVALID_PARAMETER; */
2706363466Sgshapiro
2707363466Sgshapiro	extension_len = strlen(extension);
2708363466Sgshapiro	db_name_len = strlen(db_name);
2709363466Sgshapiro
2710363466Sgshapiro	if (extension_len + db_name_len + 2 > max_full_name_len)
2711363466Sgshapiro		return false; /* SMDBE_DB_NAME_TOO_LONG; */
2712363466Sgshapiro
2713363466Sgshapiro	if (db_name_len < extension_len + 1 ||
2714363466Sgshapiro	    db_name[db_name_len - extension_len - 1] != '.' ||
2715363466Sgshapiro	    strcmp(&db_name[db_name_len - extension_len], extension) != 0)
2716363466Sgshapiro		(void) sm_snprintf(full_name, max_full_name_len, "%s.%s",
2717363466Sgshapiro				   db_name, extension);
2718363466Sgshapiro	else
2719363466Sgshapiro		(void) sm_strlcpy(full_name, db_name, max_full_name_len);
2720363466Sgshapiro
2721363466Sgshapiro	return true;
2722363466Sgshapiro}
2723363466Sgshapiro
2724363466Sgshapirobool
2725363466Sgshapirocdb_map_open(map, mode)
2726363466Sgshapiro	MAP *map;
2727363466Sgshapiro	int mode;
2728363466Sgshapiro{
2729363466Sgshapiro	int fd, status, omode, smode;
2730363466Sgshapiro	long sff;
2731363466Sgshapiro	struct stat st;
2732363466Sgshapiro	char buf[MAXPATHLEN];
2733363466Sgshapiro
2734363466Sgshapiro	if (tTd(38, 2))
2735363466Sgshapiro		sm_dprintf("cdb_map_open(%s, %s, %d)\n",
2736363466Sgshapiro			map->map_mname, map->map_file, mode);
2737363466Sgshapiro	map->map_db1 = (ARBPTR_T)NULL;
2738363466Sgshapiro	map->map_db2 = (ARBPTR_T)NULL;
2739363466Sgshapiro
2740363466Sgshapiro	mode &= O_ACCMODE;
2741363466Sgshapiro	omode = mode;
2742363466Sgshapiro
2743363466Sgshapiro	/*
2744363466Sgshapiro	**  Notes:
2745363466Sgshapiro	**  If a temporary file is used, then there must be some check
2746363466Sgshapiro	**  that the rename() is "safe" (i.e., does not overwrite some
2747363466Sgshapiro	**  "other" file created by an attacker).
2748363466Sgshapiro	**
2749363466Sgshapiro	**  The code to add the extension and to set up safefile()
2750363466Sgshapiro	**  and open() should be in a common function
2751363466Sgshapiro	**  (it would be nice to re-use libsmdb?)
2752363466Sgshapiro	*/
2753363466Sgshapiro
2754363466Sgshapiro	if (!smdb_add_extension(buf, sizeof(buf), map->map_file, CDBext))
2755363466Sgshapiro	{
2756363466Sgshapiro		errno = 0;
2757363466Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
2758363466Sgshapiro			syserr("cdb map \"%s\": map file %s name too long",
2759363466Sgshapiro				map->map_mname, map->map_file);
2760363466Sgshapiro		return false;
2761363466Sgshapiro	}
2762363466Sgshapiro
2763363466Sgshapiro	sff = SFF_ROOTOK|SFF_REGONLY;
2764363466Sgshapiro	if (mode == O_RDWR)
2765363466Sgshapiro	{
2766363466Sgshapiro		if (sm_strlcat(buf, ".tmp", sizeof buf) >= sizeof buf)
2767363466Sgshapiro		{
2768363466Sgshapiro			errno = 0;
2769363466Sgshapiro			if (!bitset(MF_OPTIONAL, map->map_mflags))
2770363466Sgshapiro				syserr("cdb map \"%s\": map file %s name too long",
2771363466Sgshapiro					map->map_mname, map->map_file);
2772363466Sgshapiro			return false;
2773363466Sgshapiro		}
2774363466Sgshapiro		sff |= SFF_CREAT;
2775363466Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
2776363466Sgshapiro			sff |= SFF_NOSLINK;
2777363466Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
2778363466Sgshapiro			sff |= SFF_NOHLINK;
2779363466Sgshapiro		smode = S_IWRITE;
2780363466Sgshapiro	}
2781363466Sgshapiro	else
2782363466Sgshapiro	{
2783363466Sgshapiro		smode = S_IREAD;
2784363466Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
2785363466Sgshapiro			sff |= SFF_NOWLINK;
2786363466Sgshapiro	}
2787363466Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
2788363466Sgshapiro		sff |= SFF_SAFEDIRPATH;
2789363466Sgshapiro	status = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
2790363466Sgshapiro	if (status != 0)
2791363466Sgshapiro	{
2792363466Sgshapiro		char *prob = "unsafe";
2793363466Sgshapiro
2794363466Sgshapiro		/* cannot open this map */
2795363466Sgshapiro		if (status == ENOENT)
2796363466Sgshapiro			prob = "missing";
2797363466Sgshapiro		errno = status;
2798363466Sgshapiro		if (tTd(38, 2))
2799363466Sgshapiro			sm_dprintf("\t%s map file: %s\n", prob, sm_errstring(status));
2800363466Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
2801363466Sgshapiro			syserr("%s map \"%s\": %s map file %s",
2802363466Sgshapiro				map->map_mname, prob, buf, sm_errstring(status));
2803363466Sgshapiro		return false;
2804363466Sgshapiro	}
2805363466Sgshapiro
2806363466Sgshapiro	if (st.st_mode == ST_MODE_NOFILE)
2807363466Sgshapiro		omode |= O_CREAT|O_EXCL;
2808363466Sgshapiro# if LOCK_ON_OPEN
2809363466Sgshapiro	if (mode == O_RDWR)
2810363466Sgshapiro		omode |= O_TRUNC|O_EXLOCK;
2811363466Sgshapiro	else
2812363466Sgshapiro		omode |= O_SHLOCK;
2813363466Sgshapiro# else
2814363466Sgshapiro	if (mode == O_RDWR)
2815363466Sgshapiro		omode |= O_TRUNC;
2816363466Sgshapiro# endif /* LOCK_ON_OPEN */
2817363466Sgshapiro
2818363466Sgshapiro	fd = open(buf, omode, DBMMODE);
2819363466Sgshapiro	if (fd < 0)
2820363466Sgshapiro	{
2821363466Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
2822363466Sgshapiro			syserr("cdb_map_open: cannot open database %s", buf);
2823363466Sgshapiro		return false;
2824363466Sgshapiro	}
2825363466Sgshapiro
2826363466Sgshapiro# if !LOCK_ON_OPEN
2827363466Sgshapiro	/* make sure no baddies slipped in just before the open... */
2828363466Sgshapiro	if (filechanged(buf, fd, &st))
2829363466Sgshapiro	{
2830363466Sgshapiro		int save_errno;
2831363466Sgshapiro
2832363466Sgshapiro		save_errno = errno;
2833363466Sgshapiro		(void) close(fd);
2834363466Sgshapiro		errno = save_errno;
2835363466Sgshapiro		syserr("cdb_map_open(%s): file changed after open", buf);
2836363466Sgshapiro		return false;
2837363466Sgshapiro	}
2838363466Sgshapiro
2839363466Sgshapiro	/* actually lock the opened file */
2840363466Sgshapiro	if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
2841363466Sgshapiro		syserr("cdb_map_open: cannot lock %s", buf);
2842363466Sgshapiro# endif /* !LOCK_ON_OPEN */
2843363466Sgshapiro
2844363466Sgshapiro	/* only for aliases! */
2845363466Sgshapiro	if (mode == O_RDWR)
2846363466Sgshapiro	{
2847363466Sgshapiro		struct cdb_make *cdbmp;
2848363466Sgshapiro
2849363466Sgshapiro		cdbmp = (struct cdb_make *) xalloc(sizeof(*cdbmp));
2850363466Sgshapiro		status = cdb_make_start(cdbmp, fd);
2851363466Sgshapiro		if (status != 0)
2852363466Sgshapiro		{
2853363466Sgshapiro			close(fd);
2854363466Sgshapiro			if (!bitset(MF_OPTIONAL, map->map_mflags))
2855363466Sgshapiro				syserr("initialization of cdb map (make) failed");
2856363466Sgshapiro			return false;
2857363466Sgshapiro		}
2858363466Sgshapiro
2859363466Sgshapiro		map->map_db2 = (ARBPTR_T)cdbmp;
2860363466Sgshapiro		return true;
2861363466Sgshapiro	}
2862363466Sgshapiro	else
2863363466Sgshapiro	{
2864363466Sgshapiro		struct cdb *cdbp;
2865363466Sgshapiro
2866363466Sgshapiro		cdbp = (struct cdb *) xalloc(sizeof(*cdbp));
2867363466Sgshapiro		status = cdb_init(cdbp, fd);
2868363466Sgshapiro		if (status != 0)
2869363466Sgshapiro		{
2870363466Sgshapiro			close(fd);
2871363466Sgshapiro			if (!bitset(MF_OPTIONAL, map->map_mflags))
2872363466Sgshapiro				syserr("initialization of cdb map failed");
2873363466Sgshapiro			return false;
2874363466Sgshapiro		}
2875363466Sgshapiro		map->map_db1 = (ARBPTR_T)cdbp;
2876363466Sgshapiro		return true;
2877363466Sgshapiro	}
2878363466Sgshapiro
2879363466Sgshapiro	/* NOTREACHED */
2880363466Sgshapiro	return false;
2881363466Sgshapiro}
2882363466Sgshapiro
2883363466Sgshapirochar *
2884363466Sgshapirocdb_map_lookup (map, name, av, statp)
2885363466Sgshapiro	MAP * map;
2886363466Sgshapiro	char *name;
2887363466Sgshapiro	char **av;
2888363466Sgshapiro	int *statp;
2889363466Sgshapiro{
2890363466Sgshapiro	char * data;
2891363466Sgshapiro	struct cdb *cdbmap;
2892363466Sgshapiro	unsigned int klen, dlen;
2893363466Sgshapiro	int st;
2894363466Sgshapiro	char key[MAXNAME+1];
2895363466Sgshapiro
2896363466Sgshapiro	data = NULL;
2897363466Sgshapiro	cdbmap = map->map_db1;
2898363466Sgshapiro	if (tTd(38, 20))
2899363466Sgshapiro		sm_dprintf("cdb_map_lookup(%s, %s)\n", map->map_mname, name);
2900363466Sgshapiro
2901363466Sgshapiro	klen = strlen(name);
2902363466Sgshapiro	if (klen > sizeof(key) - 1)
2903363466Sgshapiro		klen = sizeof(key) - 1;
2904363466Sgshapiro	memmove(key, name, klen);
2905363466Sgshapiro	key[klen] = '\0';
2906363466Sgshapiro
2907363466Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
2908363466Sgshapiro		makelower(key);
2909363466Sgshapiro
2910363466Sgshapiro	st = 0;
2911363466Sgshapiro	if (bitset(MF_TRY0NULL, map->map_mflags))
2912363466Sgshapiro	{
2913363466Sgshapiro		st = cdb_find(cdbmap, key, klen);
2914363466Sgshapiro		if (st == 1)
2915363466Sgshapiro			 map->map_mflags &= ~MF_TRY1NULL;
2916363466Sgshapiro	}
2917363466Sgshapiro	if (st != 1 && bitset(MF_TRY1NULL, map->map_mflags))
2918363466Sgshapiro	{
2919363466Sgshapiro		st = cdb_find(cdbmap, key, klen + 1);
2920363466Sgshapiro		if (st == 1)
2921363466Sgshapiro			 map->map_mflags &= ~MF_TRY0NULL;
2922363466Sgshapiro	}
2923363466Sgshapiro	if (st != 1)
2924363466Sgshapiro	{
2925363466Sgshapiro		if (st < 0)
2926363466Sgshapiro			syserr("cdb_map_lookup: get (%s)", name);
2927363466Sgshapiro		return NULL;
2928363466Sgshapiro	}
2929363466Sgshapiro	else
2930363466Sgshapiro	{
2931363466Sgshapiro		dlen = cdb_datalen(cdbmap);
2932363466Sgshapiro		data = malloc(dlen + 1);
2933363466Sgshapiro		cdb_read(cdbmap, data, dlen, cdb_datapos(cdbmap));
2934363466Sgshapiro		data[dlen] = '\0';
2935363466Sgshapiro	}
2936363466Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
2937363466Sgshapiro		return map_rewrite(map, name, strlen(name), NULL);
2938363466Sgshapiro	else
2939363466Sgshapiro		return map_rewrite(map, data, dlen, av);
2940363466Sgshapiro}
2941363466Sgshapiro
2942363466Sgshapiro/*
2943363466Sgshapiro**  CDB_MAP_STORE -- store a datum in the CDB database
2944363466Sgshapiro*/
2945363466Sgshapiro
2946363466Sgshapirovoid
2947363466Sgshapirocdb_map_store(map, lhs, rhs)
2948363466Sgshapiro	MAP *map;
2949363466Sgshapiro	char *lhs;
2950363466Sgshapiro	char *rhs;
2951363466Sgshapiro{
2952363466Sgshapiro	struct cdb_make *cdbmp;
2953363466Sgshapiro	size_t klen;
2954363466Sgshapiro	size_t vlen;
2955363466Sgshapiro	int status;
2956363466Sgshapiro	char keybuf[MAXNAME + 1];
2957363466Sgshapiro
2958363466Sgshapiro	cdbmp = map->map_db2;
2959363466Sgshapiro	if (cdbmp == NULL)
2960363466Sgshapiro		return;	/* XXX */
2961363466Sgshapiro
2962363466Sgshapiro	klen = strlen(lhs);
2963363466Sgshapiro	vlen = strlen(rhs);
2964363466Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
2965363466Sgshapiro	{
2966363466Sgshapiro		if (klen > sizeof(keybuf) - 1)
2967363466Sgshapiro			klen = sizeof(keybuf) - 1;
2968363466Sgshapiro		memmove(keybuf, lhs, klen);
2969363466Sgshapiro		keybuf[klen] = '\0';
2970363466Sgshapiro		makelower(keybuf);
2971363466Sgshapiro		lhs = keybuf;
2972363466Sgshapiro	}
2973363466Sgshapiro
2974363466Sgshapiro	if (bitset(MF_INCLNULL, map->map_mflags))
2975363466Sgshapiro	{
2976363466Sgshapiro		klen++;
2977363466Sgshapiro		vlen++;
2978363466Sgshapiro	}
2979363466Sgshapiro
2980363466Sgshapiro	/* flags? */
2981363466Sgshapiro	status = cdb_make_put(cdbmp, lhs, klen, rhs, vlen, 0);
2982363466Sgshapiro	/* and now? */
2983363466Sgshapiro}
2984363466Sgshapiro
2985363466Sgshapirovoid
2986363466Sgshapirocdb_map_close(map)
2987363466Sgshapiro	MAP * map;
2988363466Sgshapiro{
2989363466Sgshapiro	struct cdb *cdbp;
2990363466Sgshapiro	struct cdb_make *cdbmp;
2991363466Sgshapiro	int fd;
2992363466Sgshapiro
2993363466Sgshapiro	fd = -1;
2994363466Sgshapiro	cdbp = map->map_db1;
2995363466Sgshapiro	if (cdbp != NULL)
2996363466Sgshapiro	{
2997363466Sgshapiro		if (tTd(38, 20))
2998363466Sgshapiro			sm_dprintf("cdb_map_close(%p)\n", (void *)cdbp);
2999363466Sgshapiro		fd = cdb_fileno(cdbp);
3000363466Sgshapiro		cdb_free(cdbp);
3001363466Sgshapiro		sm_free(cdbp);
3002363466Sgshapiro		cdbp = NULL;
3003363466Sgshapiro	}
3004363466Sgshapiro	cdbmp = map->map_db2;
3005363466Sgshapiro	if (cdbmp != NULL)
3006363466Sgshapiro	{
3007363466Sgshapiro		char tmpfn[MAXPATHLEN], cdbfn[MAXPATHLEN];
3008363466Sgshapiro
3009363466Sgshapiro		if (tTd(38, 20))
3010363466Sgshapiro			sm_dprintf("cdb_map_close(%p)\n", (void *)cdbmp);
3011363466Sgshapiro		fd = cdb_fileno(cdbmp);
3012363466Sgshapiro
3013363466Sgshapiro		/* write out the distinguished alias */
3014363466Sgshapiro		/* XXX Why isn't this in a common place? */
3015363466Sgshapiro		cdb_map_store(map, "@", "@");
3016363466Sgshapiro
3017363466Sgshapiro		if (cdb_make_finish(cdbmp) != 0)
3018363466Sgshapiro			syserr("cdb: failed to write %s", map->map_file);
3019363466Sgshapiro		if (fd >=0)
3020363466Sgshapiro		{
3021363466Sgshapiro			if (fsync(fd) == -1)
3022363466Sgshapiro				syserr("cdb: fsync(%s) failed", map->map_file);
3023363466Sgshapiro			if (close(fd) == -1)
3024363466Sgshapiro				syserr("cdb: close(%s) failed", map->map_file);
3025363466Sgshapiro		}
3026363466Sgshapiro
3027363466Sgshapiro		if (!smdb_add_extension(cdbfn, sizeof(cdbfn), map->map_file,
3028363466Sgshapiro					CDBext))
3029363466Sgshapiro		{
3030363466Sgshapiro			syserr("cdb: add extension to %s failed",
3031363466Sgshapiro				map->map_file);
3032363466Sgshapiro		}
3033363466Sgshapiro		if (sm_strlcpy(tmpfn, cdbfn, sizeof tmpfn) >= sizeof tmpfn ||
3034363466Sgshapiro		    sm_strlcat(tmpfn, ".tmp", sizeof tmpfn) >= sizeof tmpfn)
3035363466Sgshapiro		{
3036363466Sgshapiro			syserr("cdb: set temp filename for %s failed",
3037363466Sgshapiro				map->map_file);
3038363466Sgshapiro		}
3039363466Sgshapiro		if (tTd(38, 80))
3040363466Sgshapiro			sm_dprintf("rename(%s, %s)\n", tmpfn, cdbfn);
3041363466Sgshapiro		if (rename(tmpfn, cdbfn) == -1)
3042363466Sgshapiro			syserr("cdb: rename(%s, %s) failed", tmpfn, cdbfn);
3043363466Sgshapiro		sm_free(cdbmp);
3044363466Sgshapiro		cdbmp = NULL;
3045363466Sgshapiro	}
3046363466Sgshapiro	if (fd >=0)
3047363466Sgshapiro		close(fd);
3048363466Sgshapiro}
3049363466Sgshapiro#endif /* CDB */
3050363466Sgshapiro
3051363466Sgshapiro/*
305238032Speter**  NIS Modules
305338032Speter*/
305438032Speter
305590792Sgshapiro#if NIS
305638032Speter
305738032Speter# ifndef YPERR_BUSY
305838032Speter#  define YPERR_BUSY	16
3059363466Sgshapiro# endif
306038032Speter
306138032Speter/*
306238032Speter**  NIS_MAP_OPEN -- open DBM map
306338032Speter*/
306438032Speter
306538032Speterbool
306638032Speternis_map_open(map, mode)
306738032Speter	MAP *map;
306838032Speter	int mode;
306938032Speter{
307038032Speter	int yperr;
307138032Speter	register char *p;
307238032Speter	auto char *vp;
307338032Speter	auto int vsize;
307438032Speter
307538032Speter	if (tTd(38, 2))
307690792Sgshapiro		sm_dprintf("nis_map_open(%s, %s, %d)\n",
307738032Speter			map->map_mname, map->map_file, mode);
307838032Speter
307938032Speter	mode &= O_ACCMODE;
308038032Speter	if (mode != O_RDONLY)
308138032Speter	{
308238032Speter		/* issue a pseudo-error message */
308390792Sgshapiro		errno = SM_EMAPCANTWRITE;
308490792Sgshapiro		return false;
308538032Speter	}
308638032Speter
308738032Speter	p = strchr(map->map_file, '@');
308838032Speter	if (p != NULL)
308938032Speter	{
309038032Speter		*p++ = '\0';
309138032Speter		if (*p != '\0')
309238032Speter			map->map_domain = p;
309338032Speter	}
309438032Speter
309538032Speter	if (*map->map_file == '\0')
309638032Speter		map->map_file = "mail.aliases";
309738032Speter
309838032Speter	if (map->map_domain == NULL)
309938032Speter	{
310038032Speter		yperr = yp_get_default_domain(&map->map_domain);
310138032Speter		if (yperr != 0)
310238032Speter		{
310338032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
310494334Sgshapiro				syserr("451 4.3.5 NIS map %s specified, but NIS not running",
310564562Sgshapiro				       map->map_file);
310690792Sgshapiro			return false;
310738032Speter		}
310838032Speter	}
310938032Speter
311038032Speter	/* check to see if this map actually exists */
311164562Sgshapiro	vp = NULL;
311238032Speter	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
311338032Speter			&vp, &vsize);
311438032Speter	if (tTd(38, 10))
311590792Sgshapiro		sm_dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n",
311638032Speter			map->map_domain, map->map_file, yperr_string(yperr));
311764562Sgshapiro	if (vp != NULL)
311877349Sgshapiro		sm_free(vp);
311964562Sgshapiro
312038032Speter	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
312138032Speter	{
312238032Speter		/*
312338032Speter		**  We ought to be calling aliaswait() here if this is an
3124363466Sgshapiro		**  alias file, but powerful HP-UX NIS servers apparently
312538032Speter		**  don't insert the @:@ token into the alias map when it
312638032Speter		**  is rebuilt, so aliaswait() just hangs.  I hate HP-UX.
312738032Speter		*/
312838032Speter
312964562Sgshapiro# if 0
313038032Speter		if (!bitset(MF_ALIAS, map->map_mflags) ||
313190792Sgshapiro		    aliaswait(map, NULL, true))
3132363466Sgshapiro# endif
313390792Sgshapiro			return true;
313438032Speter	}
313538032Speter
313638032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
313738032Speter	{
313894334Sgshapiro		syserr("451 4.3.5 Cannot bind to map %s in domain %s: %s",
313938032Speter			map->map_file, map->map_domain, yperr_string(yperr));
314038032Speter	}
314138032Speter
314290792Sgshapiro	return false;
314338032Speter}
314438032Speter
314538032Speter
314638032Speter/*
314738032Speter**  NIS_MAP_LOOKUP -- look up a datum in a NIS map
314838032Speter*/
314938032Speter
315038032Speter/* ARGSUSED3 */
315138032Speterchar *
315238032Speternis_map_lookup(map, name, av, statp)
315338032Speter	MAP *map;
315438032Speter	char *name;
315538032Speter	char **av;
315638032Speter	int *statp;
315738032Speter{
315838032Speter	char *vp;
315938032Speter	auto int vsize;
316038032Speter	int buflen;
316138032Speter	int yperr;
316238032Speter	char keybuf[MAXNAME + 1];
316390792Sgshapiro	char *SM_NONVOLATILE result = NULL;
316438032Speter
316538032Speter	if (tTd(38, 20))
316690792Sgshapiro		sm_dprintf("nis_map_lookup(%s, %s)\n",
316738032Speter			map->map_mname, name);
316838032Speter
316938032Speter	buflen = strlen(name);
3170168515Sgshapiro	if (buflen > sizeof(keybuf) - 1)
3171168515Sgshapiro		buflen = sizeof(keybuf) - 1;
317264562Sgshapiro	memmove(keybuf, name, buflen);
317338032Speter	keybuf[buflen] = '\0';
317438032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
317538032Speter		makelower(keybuf);
317638032Speter	yperr = YPERR_KEY;
317764562Sgshapiro	vp = NULL;
317838032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
317938032Speter	{
318038032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
318138032Speter			     &vp, &vsize);
318238032Speter		if (yperr == 0)
318338032Speter			map->map_mflags &= ~MF_TRY1NULL;
318438032Speter	}
318538032Speter	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
318638032Speter	{
3187363466Sgshapiro		SM_FREE(vp);
318838032Speter		buflen++;
318938032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
319038032Speter			     &vp, &vsize);
319138032Speter		if (yperr == 0)
319238032Speter			map->map_mflags &= ~MF_TRY0NULL;
319338032Speter	}
319438032Speter	if (yperr != 0)
319538032Speter	{
319638032Speter		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
319738032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
319864562Sgshapiro		if (vp != NULL)
319977349Sgshapiro			sm_free(vp);
320038032Speter		return NULL;
320138032Speter	}
320290792Sgshapiro	SM_TRY
320390792Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
320490792Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
320590792Sgshapiro		else
320690792Sgshapiro			result = map_rewrite(map, vp, vsize, av);
320790792Sgshapiro	SM_FINALLY
320864562Sgshapiro		if (vp != NULL)
320977349Sgshapiro			sm_free(vp);
321090792Sgshapiro	SM_END_TRY
321190792Sgshapiro	return result;
321238032Speter}
321338032Speter
321438032Speter
321538032Speter/*
321638032Speter**  NIS_GETCANONNAME -- look up canonical name in NIS
321738032Speter*/
321838032Speter
321964562Sgshapirostatic bool
322038032Speternis_getcanonname(name, hbsize, statp)
322138032Speter	char *name;
322238032Speter	int hbsize;
322338032Speter	int *statp;
322438032Speter{
322538032Speter	char *vp;
322638032Speter	auto int vsize;
322738032Speter	int keylen;
322838032Speter	int yperr;
322990792Sgshapiro	static bool try0null = true;
323090792Sgshapiro	static bool try1null = true;
323138032Speter	static char *yp_domain = NULL;
323238032Speter	char host_record[MAXLINE];
323338032Speter	char cbuf[MAXNAME];
323438032Speter	char nbuf[MAXNAME + 1];
323538032Speter
323638032Speter	if (tTd(38, 20))
323790792Sgshapiro		sm_dprintf("nis_getcanonname(%s)\n", name);
323838032Speter
3239168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
324038032Speter	{
324138032Speter		*statp = EX_UNAVAILABLE;
324290792Sgshapiro		return false;
324338032Speter	}
324473188Sgshapiro	(void) shorten_hostname(nbuf);
324538032Speter	keylen = strlen(nbuf);
324638032Speter
324738032Speter	if (yp_domain == NULL)
324864562Sgshapiro		(void) yp_get_default_domain(&yp_domain);
324938032Speter	makelower(nbuf);
325038032Speter	yperr = YPERR_KEY;
325164562Sgshapiro	vp = NULL;
325238032Speter	if (try0null)
325338032Speter	{
325438032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
325538032Speter			     &vp, &vsize);
325638032Speter		if (yperr == 0)
325790792Sgshapiro			try1null = false;
325838032Speter	}
325938032Speter	if (yperr == YPERR_KEY && try1null)
326038032Speter	{
3261363466Sgshapiro		SM_FREE(vp);
326238032Speter		keylen++;
326338032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
326438032Speter			     &vp, &vsize);
326538032Speter		if (yperr == 0)
326690792Sgshapiro			try0null = false;
326738032Speter	}
326838032Speter	if (yperr != 0)
326938032Speter	{
327038032Speter		if (yperr == YPERR_KEY)
327138032Speter			*statp = EX_NOHOST;
327238032Speter		else if (yperr == YPERR_BUSY)
327338032Speter			*statp = EX_TEMPFAIL;
327438032Speter		else
327538032Speter			*statp = EX_UNAVAILABLE;
327664562Sgshapiro		if (vp != NULL)
327777349Sgshapiro			sm_free(vp);
327890792Sgshapiro		return false;
327938032Speter	}
3280168515Sgshapiro	(void) sm_strlcpy(host_record, vp, sizeof(host_record));
328177349Sgshapiro	sm_free(vp);
328238032Speter	if (tTd(38, 44))
328390792Sgshapiro		sm_dprintf("got record `%s'\n", host_record);
328490792Sgshapiro	vp = strpbrk(host_record, "#\n");
328590792Sgshapiro	if (vp != NULL)
328690792Sgshapiro		*vp = '\0';
3287168515Sgshapiro	if (!extract_canonname(nbuf, NULL, host_record, cbuf, sizeof(cbuf)))
328838032Speter	{
328938032Speter		/* this should not happen, but.... */
329038032Speter		*statp = EX_NOHOST;
329190792Sgshapiro		return false;
329238032Speter	}
329390792Sgshapiro	if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
329438032Speter	{
329538032Speter		*statp = EX_UNAVAILABLE;
329690792Sgshapiro		return false;
329738032Speter	}
329838032Speter	*statp = EX_OK;
329990792Sgshapiro	return true;
330038032Speter}
330138032Speter
330264562Sgshapiro#endif /* NIS */
330390792Sgshapiro/*
330438032Speter**  NISPLUS Modules
330538032Speter**
330638032Speter**	This code donated by Sun Microsystems.
330738032Speter*/
330838032Speter
330990792Sgshapiro#if NISPLUS
331038032Speter
331164562Sgshapiro# undef NIS		/* symbol conflict in nis.h */
331264562Sgshapiro# undef T_UNSPEC	/* symbol conflict in nis.h -> ... -> sys/tiuser.h */
331364562Sgshapiro# include <rpcsvc/nis.h>
331464562Sgshapiro# include <rpcsvc/nislib.h>
3315249729Sgshapiro# ifndef NIS_TABLE_OBJ
3316249729Sgshapiro#  define NIS_TABLE_OBJ TABLE_OBJ
3317363466Sgshapiro# endif
331838032Speter
331964562Sgshapiro# define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
332064562Sgshapiro# define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
332164562Sgshapiro# define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
332264562Sgshapiro# define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
332338032Speter
332438032Speter/*
332538032Speter**  NISPLUS_MAP_OPEN -- open nisplus table
332638032Speter*/
332738032Speter
332838032Speterbool
332938032Speternisplus_map_open(map, mode)
333038032Speter	MAP *map;
333138032Speter	int mode;
333238032Speter{
333338032Speter	nis_result *res = NULL;
333438032Speter	int retry_cnt, max_col, i;
333538032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
333638032Speter
333738032Speter	if (tTd(38, 2))
333890792Sgshapiro		sm_dprintf("nisplus_map_open(%s, %s, %d)\n",
333938032Speter			map->map_mname, map->map_file, mode);
334038032Speter
334138032Speter	mode &= O_ACCMODE;
334238032Speter	if (mode != O_RDONLY)
334338032Speter	{
334438032Speter		errno = EPERM;
334590792Sgshapiro		return false;
334638032Speter	}
334738032Speter
334838032Speter	if (*map->map_file == '\0')
334938032Speter		map->map_file = "mail_aliases.org_dir";
335038032Speter
335138032Speter	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
335238032Speter	{
335338032Speter		/* set default NISPLUS Domain to $m */
335438032Speter		map->map_domain = newstr(nisplus_default_domain());
335538032Speter		if (tTd(38, 2))
335690792Sgshapiro			sm_dprintf("nisplus_map_open(%s): using domain %s\n",
335764562Sgshapiro				map->map_file, map->map_domain);
335838032Speter	}
335938032Speter	if (!PARTIAL_NAME(map->map_file))
336038032Speter	{
336138032Speter		map->map_domain = newstr("");
3362168515Sgshapiro		(void) sm_strlcpy(qbuf, map->map_file, sizeof(qbuf));
336338032Speter	}
336438032Speter	else
336538032Speter	{
336638032Speter		/* check to see if this map actually exists */
3367168515Sgshapiro		(void) sm_strlcpyn(qbuf, sizeof(qbuf), 3,
336890792Sgshapiro				   map->map_file, ".", map->map_domain);
336938032Speter	}
337038032Speter
337138032Speter	retry_cnt = 0;
337238032Speter	while (res == NULL || res->status != NIS_SUCCESS)
337338032Speter	{
337438032Speter		res = nis_lookup(qbuf, FOLLOW_LINKS);
337538032Speter		switch (res->status)
337638032Speter		{
337738032Speter		  case NIS_SUCCESS:
337838032Speter			break;
337938032Speter
338038032Speter		  case NIS_TRYAGAIN:
338138032Speter		  case NIS_RPCERROR:
338238032Speter		  case NIS_NAMEUNREACHABLE:
338338032Speter			if (retry_cnt++ > 4)
338438032Speter			{
338538032Speter				errno = EAGAIN;
338690792Sgshapiro				return false;
338738032Speter			}
338838032Speter			/* try not to overwhelm hosed server */
338938032Speter			sleep(2);
339038032Speter			break;
339138032Speter
339238032Speter		  default:		/* all other nisplus errors */
339364562Sgshapiro# if 0
339438032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
339594334Sgshapiro				syserr("451 4.3.5 Cannot find table %s.%s: %s",
339638032Speter					map->map_file, map->map_domain,
339738032Speter					nis_sperrno(res->status));
339864562Sgshapiro# endif /* 0 */
339938032Speter			errno = EAGAIN;
340090792Sgshapiro			return false;
340138032Speter		}
340238032Speter	}
340338032Speter
340438032Speter	if (NIS_RES_NUMOBJ(res) != 1 ||
3405249729Sgshapiro	    (NIS_RES_OBJECT(res)->zo_data.zo_type != NIS_TABLE_OBJ))
340638032Speter	{
340738032Speter		if (tTd(38, 10))
340890792Sgshapiro			sm_dprintf("nisplus_map_open: %s is not a table\n", qbuf);
340964562Sgshapiro# if 0
341038032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
341194334Sgshapiro			syserr("451 4.3.5 %s.%s: %s is not a table",
341238032Speter				map->map_file, map->map_domain,
341338032Speter				nis_sperrno(res->status));
341464562Sgshapiro# endif /* 0 */
341538032Speter		errno = EBADF;
341690792Sgshapiro		return false;
341738032Speter	}
341838032Speter	/* default key column is column 0 */
341938032Speter	if (map->map_keycolnm == NULL)
342038032Speter		map->map_keycolnm = newstr(COL_NAME(res,0));
342138032Speter
342238032Speter	max_col = COL_MAX(res);
342338032Speter
342438032Speter	/* verify the key column exist */
342590792Sgshapiro	for (i = 0; i < max_col; i++)
342638032Speter	{
342764562Sgshapiro		if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0)
342838032Speter			break;
342938032Speter	}
343038032Speter	if (i == max_col)
343138032Speter	{
343238032Speter		if (tTd(38, 2))
343390792Sgshapiro			sm_dprintf("nisplus_map_open(%s): can not find key column %s\n",
343438032Speter				map->map_file, map->map_keycolnm);
343538032Speter		errno = ENOENT;
343690792Sgshapiro		return false;
343738032Speter	}
343838032Speter
343938032Speter	/* default value column is the last column */
344038032Speter	if (map->map_valcolnm == NULL)
344138032Speter	{
344238032Speter		map->map_valcolno = max_col - 1;
344390792Sgshapiro		return true;
344438032Speter	}
344538032Speter
344664562Sgshapiro	for (i = 0; i< max_col; i++)
344738032Speter	{
344838032Speter		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
344938032Speter		{
345038032Speter			map->map_valcolno = i;
345190792Sgshapiro			return true;
345238032Speter		}
345338032Speter	}
345438032Speter
345538032Speter	if (tTd(38, 2))
345690792Sgshapiro		sm_dprintf("nisplus_map_open(%s): can not find column %s\n",
345764562Sgshapiro			map->map_file, map->map_keycolnm);
345838032Speter	errno = ENOENT;
345990792Sgshapiro	return false;
346038032Speter}
346138032Speter
346238032Speter
346338032Speter/*
346438032Speter**  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
346538032Speter*/
346638032Speter
346738032Speterchar *
346838032Speternisplus_map_lookup(map, name, av, statp)
346938032Speter	MAP *map;
347038032Speter	char *name;
347138032Speter	char **av;
347238032Speter	int *statp;
347338032Speter{
347438032Speter	char *p;
347538032Speter	auto int vsize;
347638032Speter	char *skp;
347738032Speter	int skleft;
347838032Speter	char search_key[MAXNAME + 4];
347938032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
348038032Speter	nis_result *result;
348138032Speter
348238032Speter	if (tTd(38, 20))
348390792Sgshapiro		sm_dprintf("nisplus_map_lookup(%s, %s)\n",
348438032Speter			map->map_mname, name);
348538032Speter
348638032Speter	if (!bitset(MF_OPEN, map->map_mflags))
348738032Speter	{
348838032Speter		if (nisplus_map_open(map, O_RDONLY))
348942575Speter		{
349038032Speter			map->map_mflags |= MF_OPEN;
349190792Sgshapiro			map->map_pid = CurrentPid;
349242575Speter		}
349338032Speter		else
349438032Speter		{
349538032Speter			*statp = EX_UNAVAILABLE;
349638032Speter			return NULL;
349738032Speter		}
349838032Speter	}
349938032Speter
350038032Speter	/*
350138032Speter	**  Copy the name to the key buffer, escaping double quote characters
350238032Speter	**  by doubling them and quoting "]" and "," to avoid having the
350338032Speter	**  NIS+ parser choke on them.
350438032Speter	*/
350538032Speter
3506168515Sgshapiro	skleft = sizeof(search_key) - 4;
350738032Speter	skp = search_key;
350838032Speter	for (p = name; *p != '\0' && skleft > 0; p++)
350938032Speter	{
351038032Speter		switch (*p)
351138032Speter		{
351238032Speter		  case ']':
351338032Speter		  case ',':
351438032Speter			/* quote the character */
351538032Speter			*skp++ = '"';
351638032Speter			*skp++ = *p;
351738032Speter			*skp++ = '"';
351838032Speter			skleft -= 3;
351938032Speter			break;
352038032Speter
352138032Speter		  case '"':
352238032Speter			/* double the quote */
352338032Speter			*skp++ = '"';
352438032Speter			skleft--;
352564562Sgshapiro			/* FALLTHROUGH */
352638032Speter
352738032Speter		  default:
352838032Speter			*skp++ = *p;
352938032Speter			skleft--;
353038032Speter			break;
353138032Speter		}
353238032Speter	}
353338032Speter	*skp = '\0';
353438032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
353538032Speter		makelower(search_key);
353638032Speter
353738032Speter	/* construct the query */
353838032Speter	if (PARTIAL_NAME(map->map_file))
3539168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf), "[%s=%s],%s.%s",
354038032Speter			map->map_keycolnm, search_key, map->map_file,
354138032Speter			map->map_domain);
354238032Speter	else
3543168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf), "[%s=%s],%s",
354438032Speter			map->map_keycolnm, search_key, map->map_file);
354538032Speter
354638032Speter	if (tTd(38, 20))
354790792Sgshapiro		sm_dprintf("qbuf=%s\n", qbuf);
354838032Speter	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
354938032Speter	if (result->status == NIS_SUCCESS)
355038032Speter	{
355138032Speter		int count;
355238032Speter		char *str;
355338032Speter
355438032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
355538032Speter		{
355638032Speter			if (LogLevel > 10)
355738032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
355864562Sgshapiro					  "%s: lookup error, expected 1 entry, got %d",
355964562Sgshapiro					  map->map_file, count);
356038032Speter
356138032Speter			/* ignore second entry */
356238032Speter			if (tTd(38, 20))
356390792Sgshapiro				sm_dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
356438032Speter					name, count);
356538032Speter		}
356638032Speter
356738032Speter		p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
356838032Speter		/* set the length of the result */
356938032Speter		if (p == NULL)
357038032Speter			p = "";
357138032Speter		vsize = strlen(p);
357238032Speter		if (tTd(38, 20))
357390792Sgshapiro			sm_dprintf("nisplus_map_lookup(%s), found %s\n",
357438032Speter				name, p);
357538032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
357638032Speter			str = map_rewrite(map, name, strlen(name), NULL);
357738032Speter		else
357838032Speter			str = map_rewrite(map, p, vsize, av);
357938032Speter		nis_freeresult(result);
358038032Speter		*statp = EX_OK;
358138032Speter		return str;
358238032Speter	}
358338032Speter	else
358438032Speter	{
358538032Speter		if (result->status == NIS_NOTFOUND)
358638032Speter			*statp = EX_NOTFOUND;
358738032Speter		else if (result->status == NIS_TRYAGAIN)
358838032Speter			*statp = EX_TEMPFAIL;
358938032Speter		else
359038032Speter		{
359138032Speter			*statp = EX_UNAVAILABLE;
359238032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
359338032Speter		}
359438032Speter	}
359538032Speter	if (tTd(38, 20))
359690792Sgshapiro		sm_dprintf("nisplus_map_lookup(%s), failed\n", name);
359738032Speter	nis_freeresult(result);
359838032Speter	return NULL;
359938032Speter}
360038032Speter
360138032Speter
360238032Speter
360338032Speter/*
360438032Speter**  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
360538032Speter*/
360638032Speter
360764562Sgshapirostatic bool
360838032Speternisplus_getcanonname(name, hbsize, statp)
360938032Speter	char *name;
361038032Speter	int hbsize;
361138032Speter	int *statp;
361238032Speter{
361338032Speter	char *vp;
361438032Speter	auto int vsize;
361538032Speter	nis_result *result;
361638032Speter	char *p;
361738032Speter	char nbuf[MAXNAME + 1];
361838032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
361938032Speter
3620168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
362138032Speter	{
362238032Speter		*statp = EX_UNAVAILABLE;
362390792Sgshapiro		return false;
362438032Speter	}
362573188Sgshapiro	(void) shorten_hostname(nbuf);
362638032Speter
362738032Speter	p = strchr(nbuf, '.');
362838032Speter	if (p == NULL)
362938032Speter	{
363038032Speter		/* single token */
3631168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf),
363290792Sgshapiro			"[name=%s],hosts.org_dir", nbuf);
363338032Speter	}
363438032Speter	else if (p[1] != '\0')
363538032Speter	{
363638032Speter		/* multi token -- take only first token in nbuf */
363738032Speter		*p = '\0';
3638168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf),
363990792Sgshapiro				   "[name=%s],hosts.org_dir.%s", nbuf, &p[1]);
364038032Speter	}
364138032Speter	else
364238032Speter	{
364338032Speter		*statp = EX_NOHOST;
364490792Sgshapiro		return false;
364538032Speter	}
364638032Speter
364738032Speter	if (tTd(38, 20))
364894334Sgshapiro		sm_dprintf("\nnisplus_getcanonname(%s), qbuf=%s\n",
364990792Sgshapiro			   name, qbuf);
365038032Speter
365138032Speter	result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
365290792Sgshapiro			  NULL, NULL);
365338032Speter
365438032Speter	if (result->status == NIS_SUCCESS)
365538032Speter	{
365638032Speter		int count;
365738032Speter		char *domain;
365838032Speter
365938032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
366038032Speter		{
366138032Speter			if (LogLevel > 10)
366238032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
366364562Sgshapiro					  "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
366464562Sgshapiro					  count);
366538032Speter
366638032Speter			/* ignore second entry */
366738032Speter			if (tTd(38, 20))
366894334Sgshapiro				sm_dprintf("nisplus_getcanonname(%s), got %d entries, all but first ignored\n",
366990792Sgshapiro					   name, count);
367038032Speter		}
367138032Speter
367238032Speter		if (tTd(38, 20))
367394334Sgshapiro			sm_dprintf("nisplus_getcanonname(%s), found in directory \"%s\"\n",
367490792Sgshapiro				   name, (NIS_RES_OBJECT(result))->zo_domain);
367538032Speter
367638032Speter
367738032Speter		vp = ((NIS_RES_OBJECT(result))->EN_col(0));
367838032Speter		vsize = strlen(vp);
367938032Speter		if (tTd(38, 20))
368090792Sgshapiro			sm_dprintf("nisplus_getcanonname(%s), found %s\n",
368190792Sgshapiro				   name, vp);
368238032Speter		if (strchr(vp, '.') != NULL)
368338032Speter		{
368438032Speter			domain = "";
368538032Speter		}
368638032Speter		else
368738032Speter		{
368838032Speter			domain = macvalue('m', CurEnv);
368938032Speter			if (domain == NULL)
369038032Speter				domain = "";
369138032Speter		}
369238032Speter		if (hbsize > vsize + (int) strlen(domain) + 1)
369338032Speter		{
369438032Speter			if (domain[0] == '\0')
369590792Sgshapiro				(void) sm_strlcpy(name, vp, hbsize);
369638032Speter			else
369790792Sgshapiro				(void) sm_snprintf(name, hbsize,
369890792Sgshapiro						   "%s.%s", vp, domain);
369938032Speter			*statp = EX_OK;
370038032Speter		}
370138032Speter		else
370238032Speter			*statp = EX_NOHOST;
370338032Speter		nis_freeresult(result);
370490792Sgshapiro		return true;
370538032Speter	}
370638032Speter	else
370738032Speter	{
370838032Speter		if (result->status == NIS_NOTFOUND)
370938032Speter			*statp = EX_NOHOST;
371038032Speter		else if (result->status == NIS_TRYAGAIN)
371138032Speter			*statp = EX_TEMPFAIL;
371238032Speter		else
371338032Speter			*statp = EX_UNAVAILABLE;
371438032Speter	}
371538032Speter	if (tTd(38, 20))
371690792Sgshapiro		sm_dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
371790792Sgshapiro			   name, result->status, *statp);
371838032Speter	nis_freeresult(result);
371990792Sgshapiro	return false;
372038032Speter}
372138032Speter
372238032Speterchar *
372338032Speternisplus_default_domain()
372438032Speter{
372538032Speter	static char default_domain[MAXNAME + 1] = "";
372638032Speter	char *p;
372738032Speter
372838032Speter	if (default_domain[0] != '\0')
372964562Sgshapiro		return default_domain;
373038032Speter
373138032Speter	p = nis_local_directory();
3732168515Sgshapiro	(void) sm_strlcpy(default_domain, p, sizeof(default_domain));
373338032Speter	return default_domain;
373438032Speter}
373538032Speter
373638032Speter#endif /* NISPLUS */
373790792Sgshapiro/*
373838032Speter**  LDAP Modules
373938032Speter*/
374038032Speter
374164562Sgshapiro/*
374264562Sgshapiro**  LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs
374364562Sgshapiro*/
374464562Sgshapiro
374564562Sgshapiro#if defined(LDAPMAP) || defined(PH_MAP)
374664562Sgshapiro
374790792Sgshapiro# if PH_MAP
374864562Sgshapiro#  define ph_map_dequote ldapmap_dequote
3749363466Sgshapiro# endif
375064562Sgshapiro
375190792Sgshapirostatic char *ldapmap_dequote __P((char *));
375290792Sgshapiro
375390792Sgshapirostatic char *
375464562Sgshapiroldapmap_dequote(str)
375564562Sgshapiro	char *str;
375664562Sgshapiro{
375764562Sgshapiro	char *p;
375864562Sgshapiro	char *start;
375964562Sgshapiro
376064562Sgshapiro	if (str == NULL)
376164562Sgshapiro		return NULL;
376264562Sgshapiro
376364562Sgshapiro	p = str;
376464562Sgshapiro	if (*p == '"')
376564562Sgshapiro	{
376664562Sgshapiro		/* Should probably swallow initial whitespace here */
376764562Sgshapiro		start = ++p;
376864562Sgshapiro	}
376964562Sgshapiro	else
377064562Sgshapiro		return str;
377164562Sgshapiro	while (*p != '"' && *p != '\0')
377264562Sgshapiro		p++;
377364562Sgshapiro	if (*p != '\0')
377464562Sgshapiro		*p = '\0';
377564562Sgshapiro	return start;
377664562Sgshapiro}
377764562Sgshapiro#endif /* defined(LDAPMAP) || defined(PH_MAP) */
377864562Sgshapiro
377990792Sgshapiro#if LDAPMAP
378038032Speter
378190792Sgshapirostatic SM_LDAP_STRUCT *LDAPDefaults = NULL;
378238032Speter
378338032Speter/*
378464562Sgshapiro**  LDAPMAP_OPEN -- open LDAP map
378538032Speter**
378664562Sgshapiro**	Connect to the LDAP server.  Re-use existing connections since a
378764562Sgshapiro**	single server connection to a host (with the same host, port,
378864562Sgshapiro**	bind DN, and secret) can answer queries for multiple maps.
378938032Speter*/
379038032Speter
379138032Speterbool
379264562Sgshapiroldapmap_open(map, mode)
379338032Speter	MAP *map;
379438032Speter	int mode;
379538032Speter{
379690792Sgshapiro	SM_LDAP_STRUCT *lmap;
379764562Sgshapiro	STAB *s;
3798132943Sgshapiro	char *id;
379964562Sgshapiro
380038032Speter	if (tTd(38, 2))
380190792Sgshapiro		sm_dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode);
380238032Speter
3803168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && \
3804168515Sgshapiro    HASLDAPGETALIASBYNAME
3805168515Sgshapiro	if (VendorCode == VENDOR_SUN &&
3806168515Sgshapiro	    strcmp(map->map_mname, "aliases.ldap") == 0)
3807168515Sgshapiro	{
3808168515Sgshapiro		return true;
3809168515Sgshapiro	}
3810168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && ... */
3811168515Sgshapiro
381238032Speter	mode &= O_ACCMODE;
381364562Sgshapiro
381464562Sgshapiro	/* sendmail doesn't have the ability to write to LDAP (yet) */
381538032Speter	if (mode != O_RDONLY)
381638032Speter	{
381738032Speter		/* issue a pseudo-error message */
381890792Sgshapiro		errno = SM_EMAPCANTWRITE;
381990792Sgshapiro		return false;
382038032Speter	}
382164562Sgshapiro
382290792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
382364562Sgshapiro
382464562Sgshapiro	s = ldapmap_findconn(lmap);
382577349Sgshapiro	if (s->s_lmap != NULL)
382664562Sgshapiro	{
382764562Sgshapiro		/* Already have a connection open to this LDAP server */
382890792Sgshapiro		lmap->ldap_ld = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_ld;
382990792Sgshapiro		lmap->ldap_pid = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_pid;
383077349Sgshapiro
383177349Sgshapiro		/* Add this map as head of linked list */
383277349Sgshapiro		lmap->ldap_next = s->s_lmap;
383377349Sgshapiro		s->s_lmap = map;
383477349Sgshapiro
383566494Sgshapiro		if (tTd(38, 2))
383690792Sgshapiro			sm_dprintf("using cached connection\n");
383790792Sgshapiro		return true;
383864562Sgshapiro	}
383964562Sgshapiro
384066494Sgshapiro	if (tTd(38, 2))
384190792Sgshapiro		sm_dprintf("opening new connection\n");
384266494Sgshapiro
3843132943Sgshapiro	if (lmap->ldap_host != NULL)
3844132943Sgshapiro		id = lmap->ldap_host;
3845132943Sgshapiro	else if (lmap->ldap_uri != NULL)
3846132943Sgshapiro		id = lmap->ldap_uri;
3847132943Sgshapiro	else
3848132943Sgshapiro		id = "localhost";
3849132943Sgshapiro
3850203004Sgshapiro	if (tTd(74, 104))
3851203004Sgshapiro	{
3852203004Sgshapiro		extern MAPCLASS NullMapClass;
3853203004Sgshapiro
3854203004Sgshapiro		/* debug mode: don't actually open an LDAP connection */
3855203004Sgshapiro		map->map_orgclass = map->map_class;
3856203004Sgshapiro		map->map_class = &NullMapClass;
3857203004Sgshapiro		map->map_mflags |= MF_OPEN;
3858203004Sgshapiro		map->map_pid = CurrentPid;
3859203004Sgshapiro		return true;
3860203004Sgshapiro	}
3861203004Sgshapiro
386264562Sgshapiro	/* No connection yet, connect */
386390792Sgshapiro	if (!sm_ldap_start(map->map_mname, lmap))
386438032Speter	{
386590792Sgshapiro		if (errno == ETIMEDOUT)
386638032Speter		{
386738032Speter			if (LogLevel > 1)
386838032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
3869244833Sgshapiro					  "timeout connecting to LDAP server %.100s",
3870132943Sgshapiro					  id);
387138032Speter		}
387238032Speter
387338032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
387438032Speter		{
387564562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
3876132943Sgshapiro			{
387764562Sgshapiro				syserr("%s failed to %s in map %s",
387864562Sgshapiro# if USE_LDAP_INIT
387990792Sgshapiro				       "ldap_init/ldap_bind",
3880363466Sgshapiro# else
388164562Sgshapiro				       "ldap_open",
3882363466Sgshapiro# endif
3883132943Sgshapiro				       id, map->map_mname);
3884132943Sgshapiro			}
388564562Sgshapiro			else
3886132943Sgshapiro			{
388794334Sgshapiro				syserr("451 4.3.5 %s failed to %s in map %s",
388864562Sgshapiro# if USE_LDAP_INIT
388990792Sgshapiro				       "ldap_init/ldap_bind",
3890363466Sgshapiro# else
389164562Sgshapiro				       "ldap_open",
3892363466Sgshapiro# endif
3893132943Sgshapiro				       id, map->map_mname);
3894132943Sgshapiro			}
389538032Speter		}
389690792Sgshapiro		return false;
389738032Speter	}
389838032Speter
389990792Sgshapiro	/* Save connection for reuse */
390090792Sgshapiro	s->s_lmap = map;
390190792Sgshapiro	return true;
390238032Speter}
390338032Speter
390438032Speter/*
390564562Sgshapiro**  LDAPMAP_CLOSE -- close ldap map
390638032Speter*/
390738032Speter
390838032Spetervoid
390964562Sgshapiroldapmap_close(map)
391038032Speter	MAP *map;
391138032Speter{
391290792Sgshapiro	SM_LDAP_STRUCT *lmap;
391364562Sgshapiro	STAB *s;
391443730Speter
391564562Sgshapiro	if (tTd(38, 2))
391690792Sgshapiro		sm_dprintf("ldapmap_close(%s)\n", map->map_mname);
391764562Sgshapiro
391890792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
391964562Sgshapiro
392064562Sgshapiro	/* Check if already closed */
392164562Sgshapiro	if (lmap->ldap_ld == NULL)
392264562Sgshapiro		return;
392364562Sgshapiro
392477349Sgshapiro	/* Close the LDAP connection */
392590792Sgshapiro	sm_ldap_close(lmap);
392677349Sgshapiro
392777349Sgshapiro	/* Mark all the maps that share the connection as closed */
392864562Sgshapiro	s = ldapmap_findconn(lmap);
392964562Sgshapiro
393077349Sgshapiro	while (s->s_lmap != NULL)
393177349Sgshapiro	{
393277349Sgshapiro		MAP *smap = s->s_lmap;
393364562Sgshapiro
393477349Sgshapiro		if (tTd(38, 2) && smap != map)
393590792Sgshapiro			sm_dprintf("ldapmap_close(%s): closed %s (shared LDAP connection)\n",
393690792Sgshapiro				   map->map_mname, smap->map_mname);
393777349Sgshapiro		smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
393890792Sgshapiro		lmap = (SM_LDAP_STRUCT *) smap->map_db1;
393964562Sgshapiro		lmap->ldap_ld = NULL;
394077349Sgshapiro		s->s_lmap = lmap->ldap_next;
394177349Sgshapiro		lmap->ldap_next = NULL;
394243730Speter	}
394338032Speter}
394438032Speter
394564562Sgshapiro# ifdef SUNET_ID
394643730Speter/*
394790792Sgshapiro**  SUNET_ID_HASH -- Convert a string to its Sunet_id canonical form
394842575Speter**  This only makes sense at Stanford University.
394938032Speter*/
395038032Speter
395190792Sgshapirostatic char *
395238032Spetersunet_id_hash(str)
395338032Speter	char *str;
395438032Speter{
395538032Speter	char *p, *p_last;
395638032Speter
395738032Speter	p = str;
395838032Speter	p_last = p;
395938032Speter	while (*p != '\0')
396038032Speter	{
3961203004Sgshapiro		if (isascii(*p) && (islower(*p) || isdigit(*p)))
396238032Speter		{
396338032Speter			*p_last = *p;
396438032Speter			p_last++;
396538032Speter		}
3966203004Sgshapiro		else if (isascii(*p) && isupper(*p))
396738032Speter		{
396838032Speter			*p_last = tolower(*p);
396938032Speter			p_last++;
397038032Speter		}
397138032Speter		++p;
397238032Speter	}
397338032Speter	if (*p_last != '\0')
397438032Speter		*p_last = '\0';
397564562Sgshapiro	return str;
397638032Speter}
3977168515Sgshapiro#  define SM_CONVERT_ID(str)	sunet_id_hash(str)
3978168515Sgshapiro# else /* SUNET_ID */
3979168515Sgshapiro#  define SM_CONVERT_ID(str)	makelower(str)
398064562Sgshapiro# endif /* SUNET_ID */
398138032Speter
398238032Speter/*
398364562Sgshapiro**  LDAPMAP_LOOKUP -- look up a datum in a LDAP map
398438032Speter*/
398538032Speter
398638032Speterchar *
398764562Sgshapiroldapmap_lookup(map, name, av, statp)
398838032Speter	MAP *map;
398938032Speter	char *name;
399038032Speter	char **av;
399138032Speter	int *statp;
399238032Speter{
3993132943Sgshapiro	int flags;
3994168515Sgshapiro	int i;
399594334Sgshapiro	int plen = 0;
399694334Sgshapiro	int psize = 0;
399764562Sgshapiro	int msgid;
399890792Sgshapiro	int save_errno;
399990792Sgshapiro	char *vp, *p;
400064562Sgshapiro	char *result = NULL;
4001132943Sgshapiro	SM_RPOOL_T *rpool;
400290792Sgshapiro	SM_LDAP_STRUCT *lmap = NULL;
4003168515Sgshapiro	char *argv[SM_LDAP_ARGS];
4004157001Sgshapiro	char keybuf[MAXKEY];
4005168515Sgshapiro#if SM_LDAP_ARGS != MAX_MAP_ARGS
4006168515Sgshapiro# ERROR _SM_LDAP_ARGS must be the same as _MAX_MAP_ARGS
4007363466Sgshapiro#endif
400838032Speter
4009168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && \
4010168515Sgshapiro    HASLDAPGETALIASBYNAME
4011168515Sgshapiro	if (VendorCode == VENDOR_SUN &&
4012168515Sgshapiro	    strcmp(map->map_mname, "aliases.ldap") == 0)
4013168515Sgshapiro	{
4014168515Sgshapiro		int rc;
4015173340Sgshapiro#if defined(GETLDAPALIASBYNAME_VERSION) && (GETLDAPALIASBYNAME_VERSION >= 2)
4016173340Sgshapiro		extern char *__getldapaliasbyname();
4017173340Sgshapiro		char *answer;
401838032Speter
4019173340Sgshapiro		answer = __getldapaliasbyname(name, &rc);
4020173340Sgshapiro#else
4021173340Sgshapiro		char answer[MAXNAME + 1];
4022173340Sgshapiro
4023168515Sgshapiro		rc = __getldapaliasbyname(name, answer, sizeof(answer));
4024173340Sgshapiro#endif
4025168515Sgshapiro		if (rc != 0)
4026168515Sgshapiro		{
4027168515Sgshapiro			if (tTd(38, 20))
4028168515Sgshapiro				sm_dprintf("getldapaliasbyname(%.100s) failed, errno=%d\n",
4029168515Sgshapiro					   name, errno);
4030168515Sgshapiro			*statp = EX_NOTFOUND;
4031168515Sgshapiro			return NULL;
4032168515Sgshapiro		}
4033168515Sgshapiro		*statp = EX_OK;
4034168515Sgshapiro		if (tTd(38, 20))
4035168515Sgshapiro			sm_dprintf("getldapaliasbyname(%.100s) => %s\n", name,
4036168515Sgshapiro				   answer);
4037168515Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
4038168515Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
4039168515Sgshapiro		else
4040168515Sgshapiro			result = map_rewrite(map, answer, strlen(answer), av);
4041173340Sgshapiro#if defined(GETLDAPALIASBYNAME_VERSION) && (GETLDAPALIASBYNAME_VERSION >= 2)
4042173340Sgshapiro		free(answer);
4043173340Sgshapiro#endif
4044168515Sgshapiro		return result;
4045168515Sgshapiro	}
4046168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && ... */
4047168515Sgshapiro
404838032Speter	/* Get ldap struct pointer from map */
404990792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
405090792Sgshapiro	sm_ldap_setopts(lmap->ldap_ld, lmap);
405138032Speter
4052168515Sgshapiro	if (lmap->ldap_multi_args)
4053168515Sgshapiro	{
4054168515Sgshapiro		SM_REQUIRE(av != NULL);
4055168515Sgshapiro		memset(argv, '\0', sizeof(argv));
4056168515Sgshapiro		for (i = 0; i < SM_LDAP_ARGS && av[i] != NULL; i++)
4057168515Sgshapiro		{
4058168515Sgshapiro			argv[i] = sm_strdup(av[i]);
4059168515Sgshapiro			if (argv[i] == NULL)
4060168515Sgshapiro			{
4061168515Sgshapiro				int save_errno, j;
406238032Speter
4063168515Sgshapiro				save_errno = errno;
4064168515Sgshapiro				for (j = 0; j < i && argv[j] != NULL; j++)
4065168515Sgshapiro					SM_FREE(argv[j]);
4066168515Sgshapiro				*statp = EX_TEMPFAIL;
4067168515Sgshapiro				errno = save_errno;
4068168515Sgshapiro				return NULL;
4069168515Sgshapiro			}
4070168515Sgshapiro
4071168515Sgshapiro			if (!bitset(MF_NOFOLDCASE, map->map_mflags))
4072168515Sgshapiro				SM_CONVERT_ID(av[i]);
4073168515Sgshapiro		}
4074168515Sgshapiro	}
4075168515Sgshapiro	else
407664562Sgshapiro	{
4077168515Sgshapiro		(void) sm_strlcpy(keybuf, name, sizeof(keybuf));
4078168515Sgshapiro
4079168515Sgshapiro		if (!bitset(MF_NOFOLDCASE, map->map_mflags))
4080168515Sgshapiro			SM_CONVERT_ID(keybuf);
408164562Sgshapiro	}
408238032Speter
4083168515Sgshapiro	if (tTd(38, 20))
408438032Speter	{
4085168515Sgshapiro		if (lmap->ldap_multi_args)
4086168515Sgshapiro		{
4087168515Sgshapiro			sm_dprintf("ldapmap_lookup(%s, argv)\n",
4088168515Sgshapiro				map->map_mname);
4089168515Sgshapiro			for (i = 0; i < SM_LDAP_ARGS; i++)
4090168515Sgshapiro			{
4091168515Sgshapiro				sm_dprintf("   argv[%d] = %s\n", i,
4092168515Sgshapiro					   argv[i] == NULL ? "NULL" : argv[i]);
4093168515Sgshapiro			}
4094168515Sgshapiro		}
4095168515Sgshapiro		else
4096168515Sgshapiro		{
4097168515Sgshapiro			sm_dprintf("ldapmap_lookup(%s, %s)\n",
4098168515Sgshapiro				   map->map_mname, name);
4099168515Sgshapiro		}
4100168515Sgshapiro	}
4101168515Sgshapiro
4102168515Sgshapiro	if (lmap->ldap_multi_args)
4103168515Sgshapiro	{
4104168515Sgshapiro		msgid = sm_ldap_search_m(lmap, argv);
4105168515Sgshapiro
4106168515Sgshapiro		/* free the argv array and its content, no longer needed */
4107168515Sgshapiro		for (i = 0; i < SM_LDAP_ARGS && argv[i] != NULL; i++)
4108168515Sgshapiro			SM_FREE(argv[i]);
4109168515Sgshapiro	}
4110168515Sgshapiro	else
4111168515Sgshapiro		msgid = sm_ldap_search(lmap, keybuf);
4112168515Sgshapiro	if (msgid == SM_LDAP_ERR)
4113168515Sgshapiro	{
411490792Sgshapiro		errno = sm_ldap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
411577349Sgshapiro		save_errno = errno;
411664562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
411738032Speter		{
4118168515Sgshapiro			/*
4119168515Sgshapiro			**  Do not include keybuf as this error may be shown
4120168515Sgshapiro			**  to outsiders.
4121168515Sgshapiro			*/
4122168515Sgshapiro
412364562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
4124168515Sgshapiro				syserr("Error in ldap_search in map %s",
4125168515Sgshapiro				       map->map_mname);
412664562Sgshapiro			else
4127168515Sgshapiro				syserr("451 4.3.5 Error in ldap_search in map %s",
4128168515Sgshapiro				       map->map_mname);
412938032Speter		}
413064562Sgshapiro		*statp = EX_TEMPFAIL;
413190792Sgshapiro		switch (save_errno - E_LDAPBASE)
413290792Sgshapiro		{
413394334Sgshapiro# ifdef LDAP_SERVER_DOWN
413490792Sgshapiro		  case LDAP_SERVER_DOWN:
4135363466Sgshapiro# endif
413690792Sgshapiro		  case LDAP_TIMEOUT:
413790792Sgshapiro		  case LDAP_UNAVAILABLE:
413866494Sgshapiro			/* server disappeared, try reopen on next search */
413977349Sgshapiro			ldapmap_close(map);
414090792Sgshapiro			break;
414166494Sgshapiro		}
414277349Sgshapiro		errno = save_errno;
414364562Sgshapiro		return NULL;
414464562Sgshapiro	}
4145168515Sgshapiro#if SM_LDAP_ERROR_ON_MISSING_ARGS
4146168515Sgshapiro	else if (msgid == SM_LDAP_ERR_ARG_MISS)
4147168515Sgshapiro	{
4148168515Sgshapiro		if (bitset(MF_NODEFER, map->map_mflags))
4149168515Sgshapiro			syserr("Error in ldap_search in map %s, too few arguments",
4150168515Sgshapiro			       map->map_mname);
4151168515Sgshapiro		else
4152168515Sgshapiro			syserr("554 5.3.5 Error in ldap_search in map %s, too few arguments",
4153168515Sgshapiro			       map->map_mname);
4154168515Sgshapiro		*statp = EX_CONFIG;
4155168515Sgshapiro		return NULL;
4156168515Sgshapiro	}
4157168515Sgshapiro#endif /* SM_LDAP_ERROR_ON_MISSING_ARGS */
415864562Sgshapiro
415964562Sgshapiro	*statp = EX_NOTFOUND;
416064562Sgshapiro	vp = NULL;
416164562Sgshapiro
4162132943Sgshapiro	flags = 0;
4163132943Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
4164132943Sgshapiro		flags |= SM_LDAP_SINGLEMATCH;
4165132943Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
4166132943Sgshapiro		flags |= SM_LDAP_MATCHONLY;
4167157001Sgshapiro# if _FFR_LDAP_SINGLEDN
4168157001Sgshapiro	if (bitset(MF_SINGLEDN, map->map_mflags))
4169157001Sgshapiro		flags |= SM_LDAP_SINGLEDN;
4170363466Sgshapiro# endif
417190792Sgshapiro
4172132943Sgshapiro	/* Create an rpool for search related memory usage */
4173132943Sgshapiro	rpool = sm_rpool_new_x(NULL);
417490792Sgshapiro
4175132943Sgshapiro	p = NULL;
4176132943Sgshapiro	*statp = sm_ldap_results(lmap, msgid, flags, map->map_coldelim,
4177132943Sgshapiro				 rpool, &p, &plen, &psize, NULL);
4178132943Sgshapiro	save_errno = errno;
417990792Sgshapiro
4180132943Sgshapiro	/* Copy result so rpool can be freed */
4181132943Sgshapiro	if (*statp == EX_OK && p != NULL)
4182132943Sgshapiro		vp = newstr(p);
4183132943Sgshapiro	sm_rpool_free(rpool);
418490792Sgshapiro
4185132943Sgshapiro	/* need to restart LDAP connection? */
4186132943Sgshapiro	if (*statp == EX_RESTART)
418764562Sgshapiro	{
4188132943Sgshapiro		*statp = EX_TEMPFAIL;
4189132943Sgshapiro		ldapmap_close(map);
419038032Speter	}
419138032Speter
4192132943Sgshapiro	errno = save_errno;
4193132943Sgshapiro	if (*statp != EX_OK && *statp != EX_NOTFOUND)
419438032Speter	{
419564562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
419664562Sgshapiro		{
419764562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
4198244833Sgshapiro				syserr("Error getting LDAP results, map=%s, name=%s",
4199244833Sgshapiro				       map->map_mname, name);
420064562Sgshapiro			else
4201244833Sgshapiro				syserr("451 4.3.5 Error getting LDAP results, map=%s, name=%s",
4202244833Sgshapiro				       map->map_mname, name);
420364562Sgshapiro		}
420477349Sgshapiro		errno = save_errno;
420564562Sgshapiro		return NULL;
420638032Speter	}
420790792Sgshapiro
420864562Sgshapiro	/* Did we match anything? */
420971345Sgshapiro	if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags))
421064562Sgshapiro		return NULL;
421138032Speter
421264562Sgshapiro	if (*statp == EX_OK)
421364562Sgshapiro	{
421464562Sgshapiro		if (LogLevel > 9)
421564562Sgshapiro			sm_syslog(LOG_INFO, CurEnv->e_id,
4216244833Sgshapiro				  "ldap=%s, %.100s=>%s", map->map_mname, name,
421771345Sgshapiro				  vp == NULL ? "<NULL>" : vp);
421864562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
421964562Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
422064562Sgshapiro		else
422171345Sgshapiro		{
422271345Sgshapiro			/* vp != NULL according to test above */
422364562Sgshapiro			result = map_rewrite(map, vp, strlen(vp), av);
422471345Sgshapiro		}
422571345Sgshapiro		if (vp != NULL)
422690792Sgshapiro			sm_free(vp); /* XXX */
422764562Sgshapiro	}
422864562Sgshapiro	return result;
422938032Speter}
423038032Speter
423138032Speter/*
423264562Sgshapiro**  LDAPMAP_FINDCONN -- find an LDAP connection to the server
423364562Sgshapiro**
423464562Sgshapiro**	Cache LDAP connections based on the host, port, bind DN,
423566494Sgshapiro**	secret, and PID so we don't have multiple connections open to
423666494Sgshapiro**	the same server for different maps.  Need a separate connection
423766494Sgshapiro**	per PID since a parent process may close the map before the
423866494Sgshapiro**	child is done with it.
423964562Sgshapiro**
424064562Sgshapiro**	Parameters:
424164562Sgshapiro**		lmap -- LDAP map information
424264562Sgshapiro**
424364562Sgshapiro**	Returns:
424464562Sgshapiro**		Symbol table entry for the LDAP connection.
424538032Speter*/
424638032Speter
424764562Sgshapirostatic STAB *
424864562Sgshapiroldapmap_findconn(lmap)
424990792Sgshapiro	SM_LDAP_STRUCT *lmap;
425038032Speter{
425194334Sgshapiro	char *format;
425264562Sgshapiro	char *nbuf;
4253132943Sgshapiro	char *id;
425490792Sgshapiro	STAB *SM_NONVOLATILE s = NULL;
425538032Speter
4256132943Sgshapiro	if (lmap->ldap_host != NULL)
4257132943Sgshapiro		id = lmap->ldap_host;
4258132943Sgshapiro	else if (lmap->ldap_uri != NULL)
4259132943Sgshapiro		id = lmap->ldap_uri;
4260132943Sgshapiro	else
4261132943Sgshapiro		id = "localhost";
4262132943Sgshapiro
426394334Sgshapiro	format = "%s%c%d%c%d%c%s%c%s%d";
426494334Sgshapiro	nbuf = sm_stringf_x(format,
4265132943Sgshapiro			    id,
426690792Sgshapiro			    CONDELSE,
426790792Sgshapiro			    lmap->ldap_port,
426890792Sgshapiro			    CONDELSE,
426994334Sgshapiro			    lmap->ldap_version,
427094334Sgshapiro			    CONDELSE,
427190792Sgshapiro			    (lmap->ldap_binddn == NULL ? ""
427290792Sgshapiro						       : lmap->ldap_binddn),
427390792Sgshapiro			    CONDELSE,
427490792Sgshapiro			    (lmap->ldap_secret == NULL ? ""
427590792Sgshapiro						       : lmap->ldap_secret),
427690792Sgshapiro			    (int) CurrentPid);
427790792Sgshapiro	SM_TRY
427890792Sgshapiro		s = stab(nbuf, ST_LMAP, ST_ENTER);
427990792Sgshapiro	SM_FINALLY
428090792Sgshapiro		sm_free(nbuf);
428190792Sgshapiro	SM_END_TRY
428264562Sgshapiro	return s;
428364562Sgshapiro}
428438032Speter/*
428564562Sgshapiro**  LDAPMAP_PARSEARGS -- parse ldap map definition args.
428664562Sgshapiro*/
428738032Speter
428890792Sgshapirostatic struct lamvalues LDAPAuthMethods[] =
428964562Sgshapiro{
429064562Sgshapiro	{	"none",		LDAP_AUTH_NONE		},
429164562Sgshapiro	{	"simple",	LDAP_AUTH_SIMPLE	},
429264562Sgshapiro# ifdef LDAP_AUTH_KRBV4
429364562Sgshapiro	{	"krbv4",	LDAP_AUTH_KRBV4		},
4294363466Sgshapiro# endif
429564562Sgshapiro	{	NULL,		0			}
429664562Sgshapiro};
429738032Speter
429890792Sgshapirostatic struct ladvalues LDAPAliasDereference[] =
429964562Sgshapiro{
430064562Sgshapiro	{	"never",	LDAP_DEREF_NEVER	},
430164562Sgshapiro	{	"always",	LDAP_DEREF_ALWAYS	},
430264562Sgshapiro	{	"search",	LDAP_DEREF_SEARCHING	},
430364562Sgshapiro	{	"find",		LDAP_DEREF_FINDING	},
430464562Sgshapiro	{	NULL,		0			}
430564562Sgshapiro};
430638032Speter
430790792Sgshapirostatic struct lssvalues LDAPSearchScope[] =
430864562Sgshapiro{
430964562Sgshapiro	{	"base",		LDAP_SCOPE_BASE		},
431064562Sgshapiro	{	"one",		LDAP_SCOPE_ONELEVEL	},
431164562Sgshapiro	{	"sub",		LDAP_SCOPE_SUBTREE	},
431264562Sgshapiro	{	NULL,		0			}
431364562Sgshapiro};
431438032Speter
431564562Sgshapirobool
431664562Sgshapiroldapmap_parseargs(map, args)
431764562Sgshapiro	MAP *map;
431864562Sgshapiro	char *args;
431964562Sgshapiro{
432090792Sgshapiro	bool secretread = true;
4321132943Sgshapiro	bool attrssetup = false;
432264562Sgshapiro	int i;
432364562Sgshapiro	register char *p = args;
432490792Sgshapiro	SM_LDAP_STRUCT *lmap;
432564562Sgshapiro	struct lamvalues *lam;
432664562Sgshapiro	struct ladvalues *lad;
432764562Sgshapiro	struct lssvalues *lss;
432890792Sgshapiro	char ldapfilt[MAXLINE];
432964562Sgshapiro	char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
433064562Sgshapiro
433164562Sgshapiro	/* Get ldap struct pointer from map */
433290792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
433364562Sgshapiro
433464562Sgshapiro	/* Check if setting the initial LDAP defaults */
433564562Sgshapiro	if (lmap == NULL || lmap != LDAPDefaults)
433664562Sgshapiro	{
433790792Sgshapiro		/* We need to alloc an SM_LDAP_STRUCT struct */
4338168515Sgshapiro		lmap = (SM_LDAP_STRUCT *) xalloc(sizeof(*lmap));
433964562Sgshapiro		if (LDAPDefaults == NULL)
434090792Sgshapiro			sm_ldap_clear(lmap);
434164562Sgshapiro		else
434264562Sgshapiro			STRUCTCOPY(*LDAPDefaults, *lmap);
434364562Sgshapiro	}
434464562Sgshapiro
434564562Sgshapiro	/* there is no check whether there is really an argument */
434664562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
434764562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
434890792Sgshapiro
434990792Sgshapiro	/* Check if setting up an alias or file class LDAP map */
435090792Sgshapiro	if (bitset(MF_ALIAS, map->map_mflags))
435190792Sgshapiro	{
435290792Sgshapiro		/* Comma separate if used as an alias file */
435390792Sgshapiro		map->map_coldelim = ',';
435490792Sgshapiro		if (*args == '\0')
435590792Sgshapiro		{
435690792Sgshapiro			int n;
435790792Sgshapiro			char *lc;
435890792Sgshapiro			char jbuf[MAXHOSTNAMELEN];
435990792Sgshapiro			char lcbuf[MAXLINE];
436090792Sgshapiro
436190792Sgshapiro			/* Get $j */
4362168515Sgshapiro			expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope);
436390792Sgshapiro			if (jbuf[0] == '\0')
436490792Sgshapiro			{
436590792Sgshapiro				(void) sm_strlcpy(jbuf, "localhost",
4366168515Sgshapiro						  sizeof(jbuf));
436790792Sgshapiro			}
436890792Sgshapiro
436990792Sgshapiro			lc = macvalue(macid("{sendmailMTACluster}"), CurEnv);
437090792Sgshapiro			if (lc == NULL)
437190792Sgshapiro				lc = "";
437290792Sgshapiro			else
437390792Sgshapiro			{
4374168515Sgshapiro				expand(lc, lcbuf, sizeof(lcbuf), CurEnv);
437590792Sgshapiro				lc = lcbuf;
437690792Sgshapiro			}
437790792Sgshapiro
4378168515Sgshapiro			n = sm_snprintf(ldapfilt, sizeof(ldapfilt),
437990792Sgshapiro					"(&(objectClass=sendmailMTAAliasObject)(sendmailMTAAliasGrouping=aliases)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))(sendmailMTAKey=%%0))",
438090792Sgshapiro					lc, jbuf);
4381168515Sgshapiro			if (n >= sizeof(ldapfilt))
438290792Sgshapiro			{
438390792Sgshapiro				syserr("%s: Default LDAP string too long",
438490792Sgshapiro				       map->map_mname);
438590792Sgshapiro				return false;
438690792Sgshapiro			}
438790792Sgshapiro
438890792Sgshapiro			/* default args for an alias LDAP entry */
438990792Sgshapiro			lmap->ldap_filter = ldapfilt;
4390132943Sgshapiro			lmap->ldap_attr[0] = "objectClass";
4391132943Sgshapiro			lmap->ldap_attr_type[0] = SM_LDAP_ATTR_OBJCLASS;
4392132943Sgshapiro			lmap->ldap_attr_needobjclass[0] = NULL;
4393132943Sgshapiro			lmap->ldap_attr[1] = "sendmailMTAAliasValue";
4394132943Sgshapiro			lmap->ldap_attr_type[1] = SM_LDAP_ATTR_NORMAL;
4395132943Sgshapiro			lmap->ldap_attr_needobjclass[1] = NULL;
4396132943Sgshapiro			lmap->ldap_attr[2] = "sendmailMTAAliasSearch";
4397132943Sgshapiro			lmap->ldap_attr_type[2] = SM_LDAP_ATTR_FILTER;
4398132943Sgshapiro			lmap->ldap_attr_needobjclass[2] = "sendmailMTAMapObject";
4399132943Sgshapiro			lmap->ldap_attr[3] = "sendmailMTAAliasURL";
4400132943Sgshapiro			lmap->ldap_attr_type[3] = SM_LDAP_ATTR_URL;
4401132943Sgshapiro			lmap->ldap_attr_needobjclass[3] = "sendmailMTAMapObject";
4402132943Sgshapiro			lmap->ldap_attr[4] = NULL;
4403132943Sgshapiro			lmap->ldap_attr_type[4] = SM_LDAP_ATTR_NONE;
4404132943Sgshapiro			lmap->ldap_attr_needobjclass[4] = NULL;
4405132943Sgshapiro			attrssetup = true;
440690792Sgshapiro		}
440790792Sgshapiro	}
440890792Sgshapiro	else if (bitset(MF_FILECLASS, map->map_mflags))
440990792Sgshapiro	{
441090792Sgshapiro		/* Space separate if used as a file class file */
441190792Sgshapiro		map->map_coldelim = ' ';
441290792Sgshapiro	}
441390792Sgshapiro
4414363466Sgshapiro# if LDAP_NETWORK_TIMEOUT
4415363466Sgshapiro	if (0 == lmap->ldap_networktmo)
4416363466Sgshapiro		lmap->ldap_networktmo = (LDAP_NETWORK_TIMEOUT > 1)
4417363466Sgshapiro					? LDAP_NETWORK_TIMEOUT : 60;
4418363466Sgshapiro# endif
4419203004Sgshapiro
442038032Speter	for (;;)
442138032Speter	{
4422363466Sgshapiro		while (SM_ISSPACE(*p))
442338032Speter			p++;
442438032Speter		if (*p != '-')
442538032Speter			break;
442638032Speter		switch (*++p)
442738032Speter		{
4428173340Sgshapiro		  case 'A':
4429173340Sgshapiro			map->map_mflags |= MF_APPEND;
443038032Speter			break;
443138032Speter
4432173340Sgshapiro		  case 'a':
4433173340Sgshapiro			map->map_app = ++p;
443438032Speter			break;
443538032Speter
4436173340Sgshapiro		  case 'D':
4437173340Sgshapiro			map->map_mflags |= MF_DEFER;
443838032Speter			break;
443938032Speter
444038032Speter		  case 'f':
444138032Speter			map->map_mflags |= MF_NOFOLDCASE;
444238032Speter			break;
444338032Speter
444438032Speter		  case 'm':
444538032Speter			map->map_mflags |= MF_MATCHONLY;
444638032Speter			break;
444738032Speter
4448173340Sgshapiro		  case 'N':
4449173340Sgshapiro			map->map_mflags |= MF_INCLNULL;
4450173340Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
445138032Speter			break;
445238032Speter
4453173340Sgshapiro		  case 'O':
4454173340Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
4455173340Sgshapiro			break;
4456173340Sgshapiro
4457173340Sgshapiro		  case 'o':
4458173340Sgshapiro			map->map_mflags |= MF_OPTIONAL;
4459173340Sgshapiro			break;
4460173340Sgshapiro
446138032Speter		  case 'q':
446238032Speter			map->map_mflags |= MF_KEEPQUOTES;
446338032Speter			break;
446438032Speter
4465173340Sgshapiro		  case 'S':
4466173340Sgshapiro			map->map_spacesub = *++p;
446738032Speter			break;
446838032Speter
446938032Speter		  case 'T':
447038032Speter			map->map_tapp = ++p;
447138032Speter			break;
447238032Speter
447364562Sgshapiro		  case 't':
447464562Sgshapiro			map->map_mflags |= MF_NODEFER;
447564562Sgshapiro			break;
447664562Sgshapiro
447764562Sgshapiro		  case 'z':
447864562Sgshapiro			if (*++p != '\\')
447964562Sgshapiro				map->map_coldelim = *p;
448064562Sgshapiro			else
448164562Sgshapiro			{
448264562Sgshapiro				switch (*++p)
448364562Sgshapiro				{
448464562Sgshapiro				  case 'n':
448564562Sgshapiro					map->map_coldelim = '\n';
448664562Sgshapiro					break;
448764562Sgshapiro
448864562Sgshapiro				  case 't':
448964562Sgshapiro					map->map_coldelim = '\t';
449064562Sgshapiro					break;
449164562Sgshapiro
449264562Sgshapiro				  default:
449364562Sgshapiro					map->map_coldelim = '\\';
449464562Sgshapiro				}
449564562Sgshapiro			}
449664562Sgshapiro			break;
449764562Sgshapiro
449864562Sgshapiro			/* Start of ldapmap specific args */
4499173340Sgshapiro		  case '1':
4500173340Sgshapiro			map->map_mflags |= MF_SINGLEMATCH;
4501173340Sgshapiro			break;
450290792Sgshapiro
4503173340Sgshapiro# if _FFR_LDAP_SINGLEDN
4504173340Sgshapiro		  case '2':
4505173340Sgshapiro			map->map_mflags |= MF_SINGLEDN;
4506173340Sgshapiro			break;
4507173340Sgshapiro# endif /* _FFR_LDAP_SINGLEDN */
450890792Sgshapiro
4509173340Sgshapiro		  case 'b':		/* search base */
4510173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4511173340Sgshapiro				continue;
4512173340Sgshapiro			lmap->ldap_base = p;
4513173340Sgshapiro			break;
4514173340Sgshapiro
4515363466Sgshapiro# if LDAP_NETWORK_TIMEOUT
4516173340Sgshapiro		  case 'c':		/* network (connect) timeout */
4517173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4518173340Sgshapiro				continue;
4519203004Sgshapiro			lmap->ldap_networktmo = atoi(p);
4520173340Sgshapiro			break;
4521363466Sgshapiro# endif /* LDAP_NETWORK_TIMEOUT */
4522173340Sgshapiro
4523173340Sgshapiro		  case 'd':		/* Dn to bind to server as */
4524173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4525173340Sgshapiro				continue;
4526173340Sgshapiro			lmap->ldap_binddn = p;
4527173340Sgshapiro			break;
4528173340Sgshapiro
4529173340Sgshapiro		  case 'H':		/* Use LDAP URI */
4530173340Sgshapiro#  if !USE_LDAP_INIT
4531173340Sgshapiro			syserr("Must compile with -DUSE_LDAP_INIT to use LDAP URIs (-H) in map %s",
4532173340Sgshapiro			       map->map_mname);
4533173340Sgshapiro			return false;
4534173340Sgshapiro#   else /* !USE_LDAP_INIT */
4535173340Sgshapiro			if (lmap->ldap_host != NULL)
4536173340Sgshapiro			{
4537173340Sgshapiro				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
4538173340Sgshapiro				       map->map_mname);
4539173340Sgshapiro				return false;
454090792Sgshapiro			}
4541173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4542173340Sgshapiro				continue;
4543173340Sgshapiro			lmap->ldap_uri = p;
454490792Sgshapiro			break;
4545173340Sgshapiro#  endif /* !USE_LDAP_INIT */
454690792Sgshapiro
4547173340Sgshapiro		  case 'h':		/* ldap host */
4548173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4549173340Sgshapiro				continue;
4550173340Sgshapiro			if (lmap->ldap_uri != NULL)
4551173340Sgshapiro			{
4552173340Sgshapiro				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
4553173340Sgshapiro				       map->map_mname);
4554173340Sgshapiro				return false;
4555173340Sgshapiro			}
4556173340Sgshapiro			lmap->ldap_host = p;
4557173340Sgshapiro			break;
4558173340Sgshapiro
4559173340Sgshapiro		  case 'K':
4560173340Sgshapiro			lmap->ldap_multi_args = true;
4561173340Sgshapiro			break;
4562173340Sgshapiro
456338032Speter		  case 'k':		/* search field */
456438032Speter			while (isascii(*++p) && isspace(*p))
456538032Speter				continue;
456664562Sgshapiro			lmap->ldap_filter = p;
456738032Speter			break;
456838032Speter
4569173340Sgshapiro		  case 'l':		/* time limit */
457038032Speter			while (isascii(*++p) && isspace(*p))
457138032Speter				continue;
4572173340Sgshapiro			lmap->ldap_timelimit = atoi(p);
4573173340Sgshapiro			lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit;
457438032Speter			break;
457538032Speter
4576173340Sgshapiro		  case 'M':		/* Method for binding */
4577173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4578173340Sgshapiro				continue;
4579173340Sgshapiro
4580173340Sgshapiro			if (sm_strncasecmp(p, "LDAP_AUTH_", 10) == 0)
4581173340Sgshapiro				p += 10;
4582173340Sgshapiro
4583173340Sgshapiro			for (lam = LDAPAuthMethods;
4584173340Sgshapiro			     lam != NULL && lam->lam_name != NULL; lam++)
4585173340Sgshapiro			{
4586173340Sgshapiro				if (sm_strncasecmp(p, lam->lam_name,
4587173340Sgshapiro						   strlen(lam->lam_name)) == 0)
4588173340Sgshapiro					break;
4589173340Sgshapiro			}
4590173340Sgshapiro			if (lam->lam_name != NULL)
4591173340Sgshapiro				lmap->ldap_method = lam->lam_code;
4592173340Sgshapiro			else
4593173340Sgshapiro			{
4594173340Sgshapiro				/* bad config line */
4595173340Sgshapiro				if (!bitset(MCF_OPTFILE,
4596173340Sgshapiro					    map->map_class->map_cflags))
4597173340Sgshapiro				{
4598173340Sgshapiro					char *ptr;
4599173340Sgshapiro
4600173340Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
4601173340Sgshapiro						*ptr = '\0';
4602173340Sgshapiro					syserr("Method for binding must be [none|simple|krbv4] (not %s) in map %s",
4603173340Sgshapiro						p, map->map_mname);
4604173340Sgshapiro					if (ptr != NULL)
4605173340Sgshapiro						*ptr = ' ';
4606173340Sgshapiro					return false;
4607173340Sgshapiro				}
4608173340Sgshapiro			}
460964562Sgshapiro			break;
461064562Sgshapiro
4611173340Sgshapiro		  case 'n':		/* retrieve attribute names only */
4612173340Sgshapiro			lmap->ldap_attrsonly = LDAPMAP_TRUE;
4613157001Sgshapiro			break;
4614157001Sgshapiro
4615173340Sgshapiro			/*
4616173340Sgshapiro			**  This is a string that is dependent on the
4617173340Sgshapiro			**  method used defined by 'M'.
4618173340Sgshapiro			*/
4619173340Sgshapiro
4620173340Sgshapiro		  case 'P':		/* Secret password for binding */
4621173340Sgshapiro			 while (isascii(*++p) && isspace(*p))
4622173340Sgshapiro				continue;
4623173340Sgshapiro			lmap->ldap_secret = p;
4624173340Sgshapiro			secretread = false;
4625173340Sgshapiro			break;
4626173340Sgshapiro
4627173340Sgshapiro		  case 'p':		/* ldap port */
4628173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4629173340Sgshapiro				continue;
4630173340Sgshapiro			lmap->ldap_port = atoi(p);
4631173340Sgshapiro			break;
4632173340Sgshapiro
463338032Speter			/* args stolen from ldapsearch.c */
463438032Speter		  case 'R':		/* don't auto chase referrals */
463564562Sgshapiro# ifdef LDAP_REFERRALS
463638032Speter			lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
4637363466Sgshapiro# else
463890792Sgshapiro			syserr("compile with -DLDAP_REFERRALS for referral support");
463964562Sgshapiro# endif /* LDAP_REFERRALS */
464038032Speter			break;
464138032Speter
464264562Sgshapiro		  case 'r':		/* alias dereferencing */
464364562Sgshapiro			while (isascii(*++p) && isspace(*p))
464464562Sgshapiro				continue;
464564562Sgshapiro
464690792Sgshapiro			if (sm_strncasecmp(p, "LDAP_DEREF_", 11) == 0)
464764562Sgshapiro				p += 11;
464864562Sgshapiro
464964562Sgshapiro			for (lad = LDAPAliasDereference;
465064562Sgshapiro			     lad != NULL && lad->lad_name != NULL; lad++)
465138032Speter			{
465290792Sgshapiro				if (sm_strncasecmp(p, lad->lad_name,
465390792Sgshapiro						   strlen(lad->lad_name)) == 0)
465464562Sgshapiro					break;
465538032Speter			}
465664562Sgshapiro			if (lad->lad_name != NULL)
465764562Sgshapiro				lmap->ldap_deref = lad->lad_code;
465864562Sgshapiro			else
465938032Speter			{
466064562Sgshapiro				/* bad config line */
466164562Sgshapiro				if (!bitset(MCF_OPTFILE,
466264562Sgshapiro					    map->map_class->map_cflags))
466364562Sgshapiro				{
466464562Sgshapiro					char *ptr;
466564562Sgshapiro
466664562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
466764562Sgshapiro						*ptr = '\0';
466873188Sgshapiro					syserr("Deref must be [never|always|search|find] (not %s) in map %s",
466964562Sgshapiro						p, map->map_mname);
467064562Sgshapiro					if (ptr != NULL)
467164562Sgshapiro						*ptr = ' ';
467290792Sgshapiro					return false;
467364562Sgshapiro				}
467438032Speter			}
467564562Sgshapiro			break;
467664562Sgshapiro
467764562Sgshapiro		  case 's':		/* search scope */
467864562Sgshapiro			while (isascii(*++p) && isspace(*p))
467964562Sgshapiro				continue;
468064562Sgshapiro
468190792Sgshapiro			if (sm_strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
468264562Sgshapiro				p += 11;
468364562Sgshapiro
468464562Sgshapiro			for (lss = LDAPSearchScope;
468564562Sgshapiro			     lss != NULL && lss->lss_name != NULL; lss++)
468638032Speter			{
468790792Sgshapiro				if (sm_strncasecmp(p, lss->lss_name,
468890792Sgshapiro						   strlen(lss->lss_name)) == 0)
468964562Sgshapiro					break;
469038032Speter			}
469164562Sgshapiro			if (lss->lss_name != NULL)
469264562Sgshapiro				lmap->ldap_scope = lss->lss_code;
469338032Speter			else
469464562Sgshapiro			{
469564562Sgshapiro				/* bad config line */
469664562Sgshapiro				if (!bitset(MCF_OPTFILE,
469764562Sgshapiro					    map->map_class->map_cflags))
469838032Speter				{
469938032Speter					char *ptr;
470038032Speter
470138032Speter					if ((ptr = strchr(p, ' ')) != NULL)
470238032Speter						*ptr = '\0';
470373188Sgshapiro					syserr("Scope must be [base|one|sub] (not %s) in map %s",
470438032Speter						p, map->map_mname);
470538032Speter					if (ptr != NULL)
470638032Speter						*ptr = ' ';
470790792Sgshapiro					return false;
470838032Speter				}
470938032Speter			}
471038032Speter			break;
471138032Speter
4712173340Sgshapiro		  case 'V':
4713173340Sgshapiro			if (*++p != '\\')
4714173340Sgshapiro				lmap->ldap_attrsep = *p;
471564562Sgshapiro			else
471664562Sgshapiro			{
4717173340Sgshapiro				switch (*++p)
471864562Sgshapiro				{
4719173340Sgshapiro				  case 'n':
4720173340Sgshapiro					lmap->ldap_attrsep = '\n';
4721173340Sgshapiro					break;
472264562Sgshapiro
4723173340Sgshapiro				  case 't':
4724173340Sgshapiro					lmap->ldap_attrsep = '\t';
4725173340Sgshapiro					break;
4726173340Sgshapiro
4727173340Sgshapiro				  default:
4728173340Sgshapiro					lmap->ldap_attrsep = '\\';
472964562Sgshapiro				}
473064562Sgshapiro			}
473164562Sgshapiro			break;
473264562Sgshapiro
4733173340Sgshapiro		  case 'v':		/* attr to return */
473494334Sgshapiro			while (isascii(*++p) && isspace(*p))
473594334Sgshapiro				continue;
4736173340Sgshapiro			lmap->ldap_attr[0] = p;
4737173340Sgshapiro			lmap->ldap_attr[1] = NULL;
473894334Sgshapiro			break;
473994334Sgshapiro
474094334Sgshapiro		  case 'w':
474194334Sgshapiro			/* -w should be for passwd, -P should be for version */
474294334Sgshapiro			while (isascii(*++p) && isspace(*p))
474394334Sgshapiro				continue;
474494334Sgshapiro			lmap->ldap_version = atoi(p);
4745132943Sgshapiro# ifdef LDAP_VERSION_MAX
474694334Sgshapiro			if (lmap->ldap_version > LDAP_VERSION_MAX)
474794334Sgshapiro			{
474894334Sgshapiro				syserr("LDAP version %d exceeds max of %d in map %s",
474994334Sgshapiro				       lmap->ldap_version, LDAP_VERSION_MAX,
475094334Sgshapiro				       map->map_mname);
475194334Sgshapiro				return false;
475294334Sgshapiro			}
4753132943Sgshapiro# endif /* LDAP_VERSION_MAX */
4754132943Sgshapiro# ifdef LDAP_VERSION_MIN
475594334Sgshapiro			if (lmap->ldap_version < LDAP_VERSION_MIN)
475694334Sgshapiro			{
475794334Sgshapiro				syserr("LDAP version %d is lower than min of %d in map %s",
475894334Sgshapiro				       lmap->ldap_version, LDAP_VERSION_MIN,
475994334Sgshapiro				       map->map_mname);
476094334Sgshapiro				return false;
476194334Sgshapiro			}
4762132943Sgshapiro# endif /* LDAP_VERSION_MIN */
476394334Sgshapiro			break;
476494334Sgshapiro
4765363466Sgshapiro		  case 'x':
4766363466Sgshapiro# if _FFR_SM_LDAP_DBG
4767363466Sgshapiro			while (isascii(*++p) && isspace(*p))
4768363466Sgshapiro				continue;
4769363466Sgshapiro			lmap->ldap_debug = atoi(p);
4770363466Sgshapiro# endif
4771363466Sgshapiro			break;
4772363466Sgshapiro
4773173340Sgshapiro		  case 'Z':
4774173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4775173340Sgshapiro				continue;
4776173340Sgshapiro			lmap->ldap_sizelimit = atoi(p);
4777168515Sgshapiro			break;
4778168515Sgshapiro
477964562Sgshapiro		  default:
478064562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
478164562Sgshapiro			break;
478238032Speter		}
478338032Speter
478464562Sgshapiro		/* need to account for quoted strings here */
4785363466Sgshapiro		while (*p != '\0' && !(SM_ISSPACE(*p)))
478638032Speter		{
478738032Speter			if (*p == '"')
478838032Speter			{
478938032Speter				while (*++p != '"' && *p != '\0')
479038032Speter					continue;
479138032Speter				if (*p != '\0')
479238032Speter					p++;
479338032Speter			}
479438032Speter			else
479538032Speter				p++;
479638032Speter		}
479738032Speter
479838032Speter		if (*p != '\0')
479938032Speter			*p++ = '\0';
480038032Speter	}
480138032Speter
480238032Speter	if (map->map_app != NULL)
480364562Sgshapiro		map->map_app = newstr(ldapmap_dequote(map->map_app));
480438032Speter	if (map->map_tapp != NULL)
480564562Sgshapiro		map->map_tapp = newstr(ldapmap_dequote(map->map_tapp));
480638032Speter
480738032Speter	/*
480842575Speter	**  We need to swallow up all the stuff into a struct
480942575Speter	**  and dump it into map->map_dbptr1
481038032Speter	*/
481138032Speter
4812132943Sgshapiro	if (lmap->ldap_host != NULL &&
481364562Sgshapiro	    (LDAPDefaults == NULL ||
481464562Sgshapiro	     LDAPDefaults == lmap ||
4815132943Sgshapiro	     LDAPDefaults->ldap_host != lmap->ldap_host))
4816132943Sgshapiro		lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host));
4817132943Sgshapiro	map->map_domain = lmap->ldap_host;
481864562Sgshapiro
4819132943Sgshapiro	if (lmap->ldap_uri != NULL &&
4820132943Sgshapiro	    (LDAPDefaults == NULL ||
4821132943Sgshapiro	     LDAPDefaults == lmap ||
4822132943Sgshapiro	     LDAPDefaults->ldap_uri != lmap->ldap_uri))
4823132943Sgshapiro		lmap->ldap_uri = newstr(ldapmap_dequote(lmap->ldap_uri));
4824132943Sgshapiro	map->map_domain = lmap->ldap_uri;
4825132943Sgshapiro
482664562Sgshapiro	if (lmap->ldap_binddn != NULL &&
482764562Sgshapiro	    (LDAPDefaults == NULL ||
482864562Sgshapiro	     LDAPDefaults == lmap ||
482964562Sgshapiro	     LDAPDefaults->ldap_binddn != lmap->ldap_binddn))
483064562Sgshapiro		lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn));
483164562Sgshapiro
483264562Sgshapiro	if (lmap->ldap_secret != NULL &&
483364562Sgshapiro	    (LDAPDefaults == NULL ||
483464562Sgshapiro	     LDAPDefaults == lmap ||
483564562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
483638032Speter	{
483790792Sgshapiro		SM_FILE_T *sfd;
483864562Sgshapiro		long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
483938032Speter
484064562Sgshapiro		if (DontLockReadFiles)
484164562Sgshapiro			sff |= SFF_NOLOCK;
484238032Speter
484364562Sgshapiro		/* need to use method to map secret to passwd string */
484464562Sgshapiro		switch (lmap->ldap_method)
484564562Sgshapiro		{
484664562Sgshapiro		  case LDAP_AUTH_NONE:
484764562Sgshapiro			/* Do nothing */
484864562Sgshapiro			break;
484938032Speter
485064562Sgshapiro		  case LDAP_AUTH_SIMPLE:
485138032Speter
485264562Sgshapiro			/*
485364562Sgshapiro			**  Secret is the name of a file with
485464562Sgshapiro			**  the first line as the password.
485564562Sgshapiro			*/
485664562Sgshapiro
485764562Sgshapiro			/* Already read in the secret? */
485864562Sgshapiro			if (secretread)
485964562Sgshapiro				break;
486064562Sgshapiro
486164562Sgshapiro			sfd = safefopen(ldapmap_dequote(lmap->ldap_secret),
486264562Sgshapiro					O_RDONLY, 0, sff);
486364562Sgshapiro			if (sfd == NULL)
486464562Sgshapiro			{
486564562Sgshapiro				syserr("LDAP map: cannot open secret %s",
486664562Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
486790792Sgshapiro				return false;
486864562Sgshapiro			}
4869168515Sgshapiro			lmap->ldap_secret = sfgets(m_tmp, sizeof(m_tmp),
487066494Sgshapiro						   sfd, TimeOuts.to_fileopen,
487166494Sgshapiro						   "ldapmap_parseargs");
487290792Sgshapiro			(void) sm_io_close(sfd, SM_TIME_DEFAULT);
487398121Sgshapiro			if (strlen(m_tmp) > LDAPMAP_MAX_PASSWD)
487498121Sgshapiro			{
487598121Sgshapiro				syserr("LDAP map: secret in %s too long",
487698121Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
487798121Sgshapiro				return false;
487898121Sgshapiro			}
487964562Sgshapiro			if (lmap->ldap_secret != NULL &&
488064562Sgshapiro			    strlen(m_tmp) > 0)
488164562Sgshapiro			{
488264562Sgshapiro				/* chomp newline */
488364562Sgshapiro				if (m_tmp[strlen(m_tmp) - 1] == '\n')
488464562Sgshapiro					m_tmp[strlen(m_tmp) - 1] = '\0';
488564562Sgshapiro
488664562Sgshapiro				lmap->ldap_secret = m_tmp;
488764562Sgshapiro			}
488864562Sgshapiro			break;
488964562Sgshapiro
489064562Sgshapiro# ifdef LDAP_AUTH_KRBV4
489164562Sgshapiro		  case LDAP_AUTH_KRBV4:
489264562Sgshapiro
489364562Sgshapiro			/*
489464562Sgshapiro			**  Secret is where the ticket file is
489564562Sgshapiro			**  stashed
489664562Sgshapiro			*/
489764562Sgshapiro
4898168515Sgshapiro			(void) sm_snprintf(m_tmp, sizeof(m_tmp),
489990792Sgshapiro				"KRBTKFILE=%s",
490090792Sgshapiro				ldapmap_dequote(lmap->ldap_secret));
490164562Sgshapiro			lmap->ldap_secret = m_tmp;
490264562Sgshapiro			break;
490364562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
490464562Sgshapiro
490564562Sgshapiro		  default:	       /* Should NEVER get here */
490664562Sgshapiro			syserr("LDAP map: Illegal value in lmap method");
490790792Sgshapiro			return false;
490890792Sgshapiro			/* NOTREACHED */
490964562Sgshapiro			break;
491064562Sgshapiro		}
491138032Speter	}
491238032Speter
491364562Sgshapiro	if (lmap->ldap_secret != NULL &&
491464562Sgshapiro	    (LDAPDefaults == NULL ||
491564562Sgshapiro	     LDAPDefaults == lmap ||
491664562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
491764562Sgshapiro		lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret));
491838032Speter
491964562Sgshapiro	if (lmap->ldap_base != NULL &&
492064562Sgshapiro	    (LDAPDefaults == NULL ||
492164562Sgshapiro	     LDAPDefaults == lmap ||
492264562Sgshapiro	     LDAPDefaults->ldap_base != lmap->ldap_base))
492364562Sgshapiro		lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base));
492464562Sgshapiro
492564562Sgshapiro	/*
492664562Sgshapiro	**  Save the server from extra work.  If request is for a single
492764562Sgshapiro	**  match, tell the server to only return enough records to
492864562Sgshapiro	**  determine if there is a single match or not.  This can not
492964562Sgshapiro	**  be one since the server would only return one and we wouldn't
493064562Sgshapiro	**  know if there were others available.
493164562Sgshapiro	*/
493264562Sgshapiro
493364562Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
493464562Sgshapiro		lmap->ldap_sizelimit = 2;
493564562Sgshapiro
493664562Sgshapiro	/* If setting defaults, don't process ldap_filter and ldap_attr */
493764562Sgshapiro	if (lmap == LDAPDefaults)
493890792Sgshapiro		return true;
493964562Sgshapiro
494064562Sgshapiro	if (lmap->ldap_filter != NULL)
494164562Sgshapiro		lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
494238032Speter	else
494338032Speter	{
494438032Speter		if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
494538032Speter		{
494638032Speter			syserr("No filter given in map %s", map->map_mname);
494790792Sgshapiro			return false;
494838032Speter		}
494938032Speter	}
495064562Sgshapiro
4951132943Sgshapiro	if (!attrssetup && lmap->ldap_attr[0] != NULL)
495238032Speter	{
495390792Sgshapiro		bool recurse = false;
495494334Sgshapiro		bool normalseen = false;
495590792Sgshapiro
495664562Sgshapiro		i = 0;
495764562Sgshapiro		p = ldapmap_dequote(lmap->ldap_attr[0]);
495864562Sgshapiro		lmap->ldap_attr[0] = NULL;
495964562Sgshapiro
496094334Sgshapiro		/* Prime the attr list with the objectClass attribute */
496194334Sgshapiro		lmap->ldap_attr[i] = "objectClass";
496294334Sgshapiro		lmap->ldap_attr_type[i] = SM_LDAP_ATTR_OBJCLASS;
496394334Sgshapiro		lmap->ldap_attr_needobjclass[i] = NULL;
496494334Sgshapiro		i++;
496594334Sgshapiro
496664562Sgshapiro		while (p != NULL)
496738032Speter		{
496864562Sgshapiro			char *v;
496964562Sgshapiro
4970363466Sgshapiro			while (SM_ISSPACE(*p))
497164562Sgshapiro				p++;
497264562Sgshapiro			if (*p == '\0')
497364562Sgshapiro				break;
497464562Sgshapiro			v = p;
497564562Sgshapiro			p = strchr(v, ',');
497664562Sgshapiro			if (p != NULL)
497764562Sgshapiro				*p++ = '\0';
497864562Sgshapiro
497971345Sgshapiro			if (i >= LDAPMAP_MAX_ATTR)
498064562Sgshapiro			{
498164562Sgshapiro				syserr("Too many return attributes in %s (max %d)",
498264562Sgshapiro				       map->map_mname, LDAPMAP_MAX_ATTR);
498390792Sgshapiro				return false;
498464562Sgshapiro			}
498564562Sgshapiro			if (*v != '\0')
498690792Sgshapiro			{
498794334Sgshapiro				int j;
498894334Sgshapiro				int use;
498990792Sgshapiro				char *type;
499094334Sgshapiro				char *needobjclass;
499190792Sgshapiro
499290792Sgshapiro				type = strchr(v, ':');
499390792Sgshapiro				if (type != NULL)
499494334Sgshapiro				{
499590792Sgshapiro					*type++ = '\0';
499694334Sgshapiro					needobjclass = strchr(type, ':');
499794334Sgshapiro					if (needobjclass != NULL)
499894334Sgshapiro						*needobjclass++ = '\0';
499994334Sgshapiro				}
500094334Sgshapiro				else
500194334Sgshapiro				{
500294334Sgshapiro					needobjclass = NULL;
500394334Sgshapiro				}
500490792Sgshapiro
500594334Sgshapiro				use = i;
500690792Sgshapiro
500794334Sgshapiro				/* allow override on "objectClass" type */
500894334Sgshapiro				if (sm_strcasecmp(v, "objectClass") == 0 &&
500994334Sgshapiro				    lmap->ldap_attr_type[0] == SM_LDAP_ATTR_OBJCLASS)
501090792Sgshapiro				{
501194334Sgshapiro					use = 0;
501294334Sgshapiro				}
501394334Sgshapiro				else
501494334Sgshapiro				{
501594334Sgshapiro					/*
501694334Sgshapiro					**  Don't add something to attribute
501794334Sgshapiro					**  list twice.
501894334Sgshapiro					*/
501994334Sgshapiro
502094334Sgshapiro					for (j = 1; j < i; j++)
502190792Sgshapiro					{
502294334Sgshapiro						if (sm_strcasecmp(v, lmap->ldap_attr[j]) == 0)
502394334Sgshapiro						{
502494334Sgshapiro							syserr("Duplicate attribute (%s) in %s",
502594334Sgshapiro							       v, map->map_mname);
502694334Sgshapiro							return false;
502794334Sgshapiro						}
502890792Sgshapiro					}
502994334Sgshapiro
503094334Sgshapiro					lmap->ldap_attr[use] = newstr(v);
503194334Sgshapiro					if (needobjclass != NULL &&
503294334Sgshapiro					    *needobjclass != '\0' &&
503394334Sgshapiro					    *needobjclass != '*')
503490792Sgshapiro					{
503594334Sgshapiro						lmap->ldap_attr_needobjclass[use] = newstr(needobjclass);
503694334Sgshapiro					}
503794334Sgshapiro					else
503894334Sgshapiro					{
503994334Sgshapiro						lmap->ldap_attr_needobjclass[use] = NULL;
504094334Sgshapiro					}
504194334Sgshapiro
504294334Sgshapiro				}
504394334Sgshapiro
504494334Sgshapiro				if (type != NULL && *type != '\0')
504594334Sgshapiro				{
504694334Sgshapiro					if (sm_strcasecmp(type, "dn") == 0)
504794334Sgshapiro					{
504890792Sgshapiro						recurse = true;
504994334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_DN;
505090792Sgshapiro					}
505190792Sgshapiro					else if (sm_strcasecmp(type, "filter") == 0)
505290792Sgshapiro					{
505390792Sgshapiro						recurse = true;
505494334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_FILTER;
505590792Sgshapiro					}
505690792Sgshapiro					else if (sm_strcasecmp(type, "url") == 0)
505790792Sgshapiro					{
505890792Sgshapiro						recurse = true;
505994334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_URL;
506090792Sgshapiro					}
506194334Sgshapiro					else if (sm_strcasecmp(type, "normal") == 0)
506290792Sgshapiro					{
506394334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
506494334Sgshapiro						normalseen = true;
506590792Sgshapiro					}
506690792Sgshapiro					else
506790792Sgshapiro					{
506890792Sgshapiro						syserr("Unknown attribute type (%s) in %s",
506990792Sgshapiro						       type, map->map_mname);
507090792Sgshapiro						return false;
507190792Sgshapiro					}
507290792Sgshapiro				}
507390792Sgshapiro				else
507494334Sgshapiro				{
507594334Sgshapiro					lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
507694334Sgshapiro					normalseen = true;
507794334Sgshapiro				}
507890792Sgshapiro				i++;
507990792Sgshapiro			}
508038032Speter		}
508164562Sgshapiro		lmap->ldap_attr[i] = NULL;
5082141858Sgshapiro
5083141858Sgshapiro		/* Set in case needed in future code */
5084132943Sgshapiro		attrssetup = true;
5085141858Sgshapiro
508694334Sgshapiro		if (recurse && !normalseen)
508790792Sgshapiro		{
508894334Sgshapiro			syserr("LDAP recursion requested in %s but no returnable attribute given",
508990792Sgshapiro			       map->map_mname);
509090792Sgshapiro			return false;
509190792Sgshapiro		}
509290792Sgshapiro		if (recurse && lmap->ldap_attrsonly == LDAPMAP_TRUE)
509390792Sgshapiro		{
509490792Sgshapiro			syserr("LDAP recursion requested in %s can not be used with -n",
509590792Sgshapiro			       map->map_mname);
509690792Sgshapiro			return false;
509790792Sgshapiro		}
509838032Speter	}
509938032Speter	map->map_db1 = (ARBPTR_T) lmap;
510090792Sgshapiro	return true;
510138032Speter}
510238032Speter
510364562Sgshapiro/*
510464562Sgshapiro**  LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
510564562Sgshapiro**
510664562Sgshapiro**	Parameters:
510764562Sgshapiro**		spec -- map argument string from LDAPDefaults option
510864562Sgshapiro**
510964562Sgshapiro**	Returns:
511064562Sgshapiro**		None.
511164562Sgshapiro*/
511264562Sgshapiro
511364562Sgshapirovoid
511464562Sgshapiroldapmap_set_defaults(spec)
511564562Sgshapiro	char *spec;
511664562Sgshapiro{
511773188Sgshapiro	STAB *class;
511864562Sgshapiro	MAP map;
511964562Sgshapiro
512064562Sgshapiro	/* Allocate and set the default values */
512164562Sgshapiro	if (LDAPDefaults == NULL)
5122168515Sgshapiro		LDAPDefaults = (SM_LDAP_STRUCT *) xalloc(sizeof(*LDAPDefaults));
512390792Sgshapiro	sm_ldap_clear(LDAPDefaults);
512464562Sgshapiro
5125168515Sgshapiro	memset(&map, '\0', sizeof(map));
512673188Sgshapiro
512773188Sgshapiro	/* look up the class */
512873188Sgshapiro	class = stab("ldap", ST_MAPCLASS, ST_FIND);
512973188Sgshapiro	if (class == NULL)
513073188Sgshapiro	{
513173188Sgshapiro		syserr("readcf: LDAPDefaultSpec: class ldap not available");
513273188Sgshapiro		return;
513373188Sgshapiro	}
513473188Sgshapiro	map.map_class = &class->s_mapclass;
513564562Sgshapiro	map.map_db1 = (ARBPTR_T) LDAPDefaults;
513673188Sgshapiro	map.map_mname = "O LDAPDefaultSpec";
513764562Sgshapiro
513864562Sgshapiro	(void) ldapmap_parseargs(&map, spec);
513964562Sgshapiro
514064562Sgshapiro	/* These should never be set in LDAPDefaults */
514164562Sgshapiro	if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) ||
514264562Sgshapiro	    map.map_spacesub != SpaceSub ||
514364562Sgshapiro	    map.map_app != NULL ||
514464562Sgshapiro	    map.map_tapp != NULL)
514564562Sgshapiro	{
514664562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
5147363466Sgshapiro		SM_FREE(map.map_app);
5148363466Sgshapiro		SM_FREE(map.map_tapp);
514964562Sgshapiro	}
515064562Sgshapiro
515164562Sgshapiro	if (LDAPDefaults->ldap_filter != NULL)
515264562Sgshapiro	{
515364562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
515494334Sgshapiro
515564562Sgshapiro		/* don't free, it isn't malloc'ed in parseargs */
515664562Sgshapiro		LDAPDefaults->ldap_filter = NULL;
515764562Sgshapiro	}
515864562Sgshapiro
515964562Sgshapiro	if (LDAPDefaults->ldap_attr[0] != NULL)
516064562Sgshapiro	{
516164562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes");
516264562Sgshapiro		/* don't free, they aren't malloc'ed in parseargs */
516364562Sgshapiro		LDAPDefaults->ldap_attr[0] = NULL;
516464562Sgshapiro	}
516564562Sgshapiro}
516664562Sgshapiro#endif /* LDAPMAP */
516790792Sgshapiro/*
516864562Sgshapiro**  PH map
516964562Sgshapiro*/
517064562Sgshapiro
517190792Sgshapiro#if PH_MAP
517264562Sgshapiro
517364562Sgshapiro/*
517464562Sgshapiro**  Support for the CCSO Nameserver (ph/qi).
517564562Sgshapiro**  This code is intended to replace the so-called "ph mailer".
5176168515Sgshapiro**  Contributed by Mark D. Roth.  Contact him for support.
517764562Sgshapiro*/
517864562Sgshapiro
517990792Sgshapiro/* what version of the ph map code we're running */
5180110560Sgshapirostatic char phmap_id[128];
518164562Sgshapiro
518290792Sgshapiro/* sendmail version for phmap id string */
518390792Sgshapiroextern const char Version[];
518490792Sgshapiro
5185132943Sgshapiro/* assume we're using nph-1.2.x if not specified */
5186110560Sgshapiro# ifndef NPH_VERSION
5187132943Sgshapiro#  define NPH_VERSION		10200
5188110560Sgshapiro# endif
5189110560Sgshapiro
5190110560Sgshapiro/* compatibility for versions older than nph-1.2.0 */
5191110560Sgshapiro# if NPH_VERSION < 10200
5192110560Sgshapiro#  define PH_OPEN_ROUNDROBIN	PH_ROUNDROBIN
5193110560Sgshapiro#  define PH_OPEN_DONTID	PH_DONTID
5194110560Sgshapiro#  define PH_CLOSE_FAST		PH_FASTCLOSE
5195110560Sgshapiro#  define PH_ERR_DATAERR	PH_DATAERR
5196110560Sgshapiro#  define PH_ERR_NOMATCH	PH_NOMATCH
5197110560Sgshapiro# endif /* NPH_VERSION < 10200 */
5198110560Sgshapiro
519964562Sgshapiro/*
520064562Sgshapiro**  PH_MAP_PARSEARGS -- parse ph map definition args.
520164562Sgshapiro*/
520264562Sgshapiro
520364562Sgshapirobool
520464562Sgshapiroph_map_parseargs(map, args)
520564562Sgshapiro	MAP *map;
520664562Sgshapiro	char *args;
520764562Sgshapiro{
520890792Sgshapiro	register bool done;
520990792Sgshapiro	register char *p = args;
521064562Sgshapiro	PH_MAP_STRUCT *pmap = NULL;
521164562Sgshapiro
521290792Sgshapiro	/* initialize version string */
5213168515Sgshapiro	(void) sm_snprintf(phmap_id, sizeof(phmap_id),
521490792Sgshapiro			   "sendmail-%s phmap-20010529 libphclient-%s",
521590792Sgshapiro			   Version, libphclient_version);
521690792Sgshapiro
5217168515Sgshapiro	pmap = (PH_MAP_STRUCT *) xalloc(sizeof(*pmap));
521864562Sgshapiro
521964562Sgshapiro	/* defaults */
522064562Sgshapiro	pmap->ph_servers = NULL;
522164562Sgshapiro	pmap->ph_field_list = NULL;
522290792Sgshapiro	pmap->ph = NULL;
522364562Sgshapiro	pmap->ph_timeout = 0;
522490792Sgshapiro	pmap->ph_fastclose = 0;
522564562Sgshapiro
522664562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
522764562Sgshapiro	for (;;)
522864562Sgshapiro	{
5229363466Sgshapiro		while (SM_ISSPACE(*p))
523064562Sgshapiro			p++;
523164562Sgshapiro		if (*p != '-')
523264562Sgshapiro			break;
523364562Sgshapiro		switch (*++p)
523464562Sgshapiro		{
523564562Sgshapiro		  case 'N':
523664562Sgshapiro			map->map_mflags |= MF_INCLNULL;
523764562Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
523864562Sgshapiro			break;
523964562Sgshapiro
524064562Sgshapiro		  case 'O':
524164562Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
524264562Sgshapiro			break;
524364562Sgshapiro
524464562Sgshapiro		  case 'o':
524564562Sgshapiro			map->map_mflags |= MF_OPTIONAL;
524664562Sgshapiro			break;
524764562Sgshapiro
524864562Sgshapiro		  case 'f':
524964562Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
525064562Sgshapiro			break;
525164562Sgshapiro
525264562Sgshapiro		  case 'm':
525364562Sgshapiro			map->map_mflags |= MF_MATCHONLY;
525464562Sgshapiro			break;
525564562Sgshapiro
525664562Sgshapiro		  case 'A':
525764562Sgshapiro			map->map_mflags |= MF_APPEND;
525864562Sgshapiro			break;
525964562Sgshapiro
526064562Sgshapiro		  case 'q':
526164562Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
526264562Sgshapiro			break;
526364562Sgshapiro
526464562Sgshapiro		  case 't':
526564562Sgshapiro			map->map_mflags |= MF_NODEFER;
526664562Sgshapiro			break;
526764562Sgshapiro
526864562Sgshapiro		  case 'a':
526964562Sgshapiro			map->map_app = ++p;
527064562Sgshapiro			break;
527164562Sgshapiro
527264562Sgshapiro		  case 'T':
527364562Sgshapiro			map->map_tapp = ++p;
527464562Sgshapiro			break;
527564562Sgshapiro
527664562Sgshapiro		  case 'l':
527764562Sgshapiro			while (isascii(*++p) && isspace(*p))
527864562Sgshapiro				continue;
527964562Sgshapiro			pmap->ph_timeout = atoi(p);
528064562Sgshapiro			break;
528164562Sgshapiro
528264562Sgshapiro		  case 'S':
528364562Sgshapiro			map->map_spacesub = *++p;
528464562Sgshapiro			break;
528564562Sgshapiro
528664562Sgshapiro		  case 'D':
528764562Sgshapiro			map->map_mflags |= MF_DEFER;
528864562Sgshapiro			break;
528964562Sgshapiro
529064562Sgshapiro		  case 'h':		/* PH server list */
529164562Sgshapiro			while (isascii(*++p) && isspace(*p))
529264562Sgshapiro				continue;
529364562Sgshapiro			pmap->ph_servers = p;
529464562Sgshapiro			break;
529564562Sgshapiro
529690792Sgshapiro		  case 'k':		/* fields to search for */
529764562Sgshapiro			while (isascii(*++p) && isspace(*p))
529864562Sgshapiro				continue;
529964562Sgshapiro			pmap->ph_field_list = p;
530064562Sgshapiro			break;
530164562Sgshapiro
530264562Sgshapiro		  default:
530390792Sgshapiro			syserr("ph_map_parseargs: unknown option -%c", *p);
530464562Sgshapiro		}
530564562Sgshapiro
530664562Sgshapiro		/* try to account for quoted strings */
5307363466Sgshapiro		done = SM_ISSPACE(*p);
530864562Sgshapiro		while (*p != '\0' && !done)
530964562Sgshapiro		{
531064562Sgshapiro			if (*p == '"')
531164562Sgshapiro			{
531264562Sgshapiro				while (*++p != '"' && *p != '\0')
531364562Sgshapiro					continue;
531464562Sgshapiro				if (*p != '\0')
531564562Sgshapiro					p++;
531664562Sgshapiro			}
531764562Sgshapiro			else
531864562Sgshapiro				p++;
5319363466Sgshapiro			done = SM_ISSPACE(*p);
532064562Sgshapiro		}
532164562Sgshapiro
532264562Sgshapiro		if (*p != '\0')
532364562Sgshapiro			*p++ = '\0';
532464562Sgshapiro	}
532564562Sgshapiro
532664562Sgshapiro	if (map->map_app != NULL)
532764562Sgshapiro		map->map_app = newstr(ph_map_dequote(map->map_app));
532864562Sgshapiro	if (map->map_tapp != NULL)
532964562Sgshapiro		map->map_tapp = newstr(ph_map_dequote(map->map_tapp));
533064562Sgshapiro
533164562Sgshapiro	if (pmap->ph_field_list != NULL)
533264562Sgshapiro		pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
533364562Sgshapiro
533464562Sgshapiro	if (pmap->ph_servers != NULL)
533564562Sgshapiro		pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
533664562Sgshapiro	else
533764562Sgshapiro	{
533864562Sgshapiro		syserr("ph_map_parseargs: -h flag is required");
533990792Sgshapiro		return false;
534064562Sgshapiro	}
534164562Sgshapiro
534264562Sgshapiro	map->map_db1 = (ARBPTR_T) pmap;
534390792Sgshapiro	return true;
534464562Sgshapiro}
534564562Sgshapiro
534664562Sgshapiro/*
534764562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
534864562Sgshapiro*/
534964562Sgshapiro
535090792Sgshapirovoid
535190792Sgshapiroph_map_close(map)
535264562Sgshapiro	MAP *map;
535364562Sgshapiro{
535464562Sgshapiro	PH_MAP_STRUCT *pmap;
535564562Sgshapiro
535664562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
535790792Sgshapiro	if (tTd(38, 9))
535894334Sgshapiro		sm_dprintf("ph_map_close(%s): pmap->ph_fastclose=%d\n",
535990792Sgshapiro			   map->map_mname, pmap->ph_fastclose);
536064562Sgshapiro
536190792Sgshapiro
536290792Sgshapiro	if (pmap->ph != NULL)
536364562Sgshapiro	{
536490792Sgshapiro		ph_set_sendhook(pmap->ph, NULL);
536590792Sgshapiro		ph_set_recvhook(pmap->ph, NULL);
536690792Sgshapiro		ph_close(pmap->ph, pmap->ph_fastclose);
536764562Sgshapiro	}
536890792Sgshapiro
536964562Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
537064562Sgshapiro}
537164562Sgshapiro
537264562Sgshapirostatic jmp_buf  PHTimeout;
537364562Sgshapiro
537464562Sgshapiro/* ARGSUSED */
537564562Sgshapirostatic void
537690792Sgshapiroph_timeout(unused)
537790792Sgshapiro	int unused;
537864562Sgshapiro{
537977349Sgshapiro	/*
538077349Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
538177349Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
538277349Sgshapiro	**	DOING.
538377349Sgshapiro	*/
538477349Sgshapiro
538577349Sgshapiro	errno = ETIMEDOUT;
538664562Sgshapiro	longjmp(PHTimeout, 1);
538764562Sgshapiro}
538864562Sgshapiro
538990792Sgshapirostatic void
5390110560Sgshapiro#if NPH_VERSION >= 10200
5391110560Sgshapiroph_map_send_debug(appdata, text)
5392110560Sgshapiro	void *appdata;
5393110560Sgshapiro#else
539490792Sgshapiroph_map_send_debug(text)
5395110560Sgshapiro#endif
539690792Sgshapiro	char *text;
539764562Sgshapiro{
539890792Sgshapiro	if (LogLevel > 9)
539990792Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
540090792Sgshapiro			  "ph_map_send_debug: ==> %s", text);
540190792Sgshapiro	if (tTd(38, 20))
540290792Sgshapiro		sm_dprintf("ph_map_send_debug: ==> %s\n", text);
540390792Sgshapiro}
540464562Sgshapiro
540590792Sgshapirostatic void
5406110560Sgshapiro#if NPH_VERSION >= 10200
5407110560Sgshapiroph_map_recv_debug(appdata, text)
5408110560Sgshapiro	void *appdata;
5409110560Sgshapiro#else
541090792Sgshapiroph_map_recv_debug(text)
5411110560Sgshapiro#endif
541290792Sgshapiro	char *text;
541390792Sgshapiro{
541490792Sgshapiro	if (LogLevel > 10)
541590792Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
541690792Sgshapiro			  "ph_map_recv_debug: <== %s", text);
541790792Sgshapiro	if (tTd(38, 21))
541890792Sgshapiro		sm_dprintf("ph_map_recv_debug: <== %s\n", text);
541964562Sgshapiro}
542064562Sgshapiro
542190792Sgshapiro/*
542264562Sgshapiro**  PH_MAP_OPEN -- sub for opening PH map
542364562Sgshapiro*/
542464562Sgshapirobool
542564562Sgshapiroph_map_open(map, mode)
542664562Sgshapiro	MAP *map;
542764562Sgshapiro	int mode;
542864562Sgshapiro{
542990792Sgshapiro	PH_MAP_STRUCT *pmap;
543090792Sgshapiro	register SM_EVENT *ev = NULL;
543164562Sgshapiro	int save_errno = 0;
543290792Sgshapiro	char *hostlist, *host;
543364562Sgshapiro
543464562Sgshapiro	if (tTd(38, 2))
543590792Sgshapiro		sm_dprintf("ph_map_open(%s)\n", map->map_mname);
543664562Sgshapiro
543764562Sgshapiro	mode &= O_ACCMODE;
543864562Sgshapiro	if (mode != O_RDONLY)
543964562Sgshapiro	{
544064562Sgshapiro		/* issue a pseudo-error message */
544190792Sgshapiro		errno = SM_EMAPCANTWRITE;
544290792Sgshapiro		return false;
544364562Sgshapiro	}
544464562Sgshapiro
544566494Sgshapiro	if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER &&
544666494Sgshapiro	    bitset(MF_DEFER, map->map_mflags))
544766494Sgshapiro	{
544866494Sgshapiro		if (tTd(9, 1))
544990792Sgshapiro			sm_dprintf("ph_map_open(%s) => DEFERRED\n",
545090792Sgshapiro				   map->map_mname);
545166494Sgshapiro
545266494Sgshapiro		/*
545390792Sgshapiro		**  Unset MF_DEFER here so that map_lookup() returns
545490792Sgshapiro		**  a temporary failure using the bogus map and
545590792Sgshapiro		**  map->map_tapp instead of the default permanent error.
545666494Sgshapiro		*/
545766494Sgshapiro
545866494Sgshapiro		map->map_mflags &= ~MF_DEFER;
545990792Sgshapiro		return false;
546066494Sgshapiro	}
546166494Sgshapiro
546264562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
546390792Sgshapiro	pmap->ph_fastclose = 0;		/* refresh field for reopen */
546464562Sgshapiro
546590792Sgshapiro	/* try each host in the list */
546664562Sgshapiro	hostlist = newstr(pmap->ph_servers);
546790792Sgshapiro	for (host = strtok(hostlist, " ");
546890792Sgshapiro	     host != NULL;
546990792Sgshapiro	     host = strtok(NULL, " "))
547064562Sgshapiro	{
547190792Sgshapiro		/* set timeout */
547264562Sgshapiro		if (pmap->ph_timeout != 0)
547364562Sgshapiro		{
547464562Sgshapiro			if (setjmp(PHTimeout) != 0)
547564562Sgshapiro			{
547664562Sgshapiro				ev = NULL;
547764562Sgshapiro				if (LogLevel > 1)
547864562Sgshapiro					sm_syslog(LOG_NOTICE, CurEnv->e_id,
547964562Sgshapiro						  "timeout connecting to PH server %.100s",
548090792Sgshapiro						  host);
548164562Sgshapiro				errno = ETIMEDOUT;
548264562Sgshapiro				goto ph_map_open_abort;
548364562Sgshapiro			}
548490792Sgshapiro			ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
548564562Sgshapiro		}
548690792Sgshapiro
548790792Sgshapiro		/* open connection to server */
5488110560Sgshapiro		if (ph_open(&(pmap->ph), host,
5489110560Sgshapiro			    PH_OPEN_ROUNDROBIN|PH_OPEN_DONTID,
5490110560Sgshapiro			    ph_map_send_debug, ph_map_recv_debug
5491110560Sgshapiro#if NPH_VERSION >= 10200
5492110560Sgshapiro			    , NULL
5493110560Sgshapiro#endif
5494110560Sgshapiro			    ) == 0
5495110560Sgshapiro		    && ph_id(pmap->ph, phmap_id) == 0)
549664562Sgshapiro		{
549764562Sgshapiro			if (ev != NULL)
549890792Sgshapiro				sm_clrevent(ev);
549990792Sgshapiro			sm_free(hostlist); /* XXX */
550090792Sgshapiro			return true;
550164562Sgshapiro		}
550290792Sgshapiro
550364562Sgshapiro  ph_map_open_abort:
550490792Sgshapiro		save_errno = errno;
550564562Sgshapiro		if (ev != NULL)
550690792Sgshapiro			sm_clrevent(ev);
5507110560Sgshapiro		pmap->ph_fastclose = PH_CLOSE_FAST;
550890792Sgshapiro		ph_map_close(map);
550990792Sgshapiro		errno = save_errno;
551090792Sgshapiro	}
551164562Sgshapiro
551266494Sgshapiro	if (bitset(MF_NODEFER, map->map_mflags))
551364562Sgshapiro	{
551466494Sgshapiro		if (errno == 0)
551564562Sgshapiro			errno = EAGAIN;
551666494Sgshapiro		syserr("ph_map_open: %s: cannot connect to PH server",
551766494Sgshapiro		       map->map_mname);
551864562Sgshapiro	}
551966494Sgshapiro	else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1)
552064562Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
552166494Sgshapiro			  "ph_map_open: %s: cannot connect to PH server",
552266494Sgshapiro			  map->map_mname);
552390792Sgshapiro	sm_free(hostlist); /* XXX */
552490792Sgshapiro	return false;
552564562Sgshapiro}
552664562Sgshapiro
552764562Sgshapiro/*
552864562Sgshapiro**  PH_MAP_LOOKUP -- look up key from ph server
552964562Sgshapiro*/
553064562Sgshapiro
553164562Sgshapirochar *
553264562Sgshapiroph_map_lookup(map, key, args, pstat)
553364562Sgshapiro	MAP *map;
553464562Sgshapiro	char *key;
553564562Sgshapiro	char **args;
553664562Sgshapiro	int *pstat;
553764562Sgshapiro{
553890792Sgshapiro	int i, save_errno = 0;
553990792Sgshapiro	register SM_EVENT *ev = NULL;
554064562Sgshapiro	PH_MAP_STRUCT *pmap;
554190792Sgshapiro	char *value = NULL;
554264562Sgshapiro
554364562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
554464562Sgshapiro
554564562Sgshapiro	*pstat = EX_OK;
554664562Sgshapiro
554790792Sgshapiro	/* set timeout */
554864562Sgshapiro	if (pmap->ph_timeout != 0)
554964562Sgshapiro	{
555064562Sgshapiro		if (setjmp(PHTimeout) != 0)
555164562Sgshapiro		{
555264562Sgshapiro			ev = NULL;
555364562Sgshapiro			if (LogLevel > 1)
555464562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
555564562Sgshapiro					  "timeout during PH lookup of %.100s",
555664562Sgshapiro					  key);
555764562Sgshapiro			errno = ETIMEDOUT;
555864562Sgshapiro			*pstat = EX_TEMPFAIL;
555964562Sgshapiro			goto ph_map_lookup_abort;
556064562Sgshapiro		}
556190792Sgshapiro		ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
556264562Sgshapiro	}
556364562Sgshapiro
556490792Sgshapiro	/* perform lookup */
556590792Sgshapiro	i = ph_email_resolve(pmap->ph, key, pmap->ph_field_list, &value);
556690792Sgshapiro	if (i == -1)
556790792Sgshapiro		*pstat = EX_TEMPFAIL;
5568110560Sgshapiro	else if (i == PH_ERR_NOMATCH || i == PH_ERR_DATAERR)
556990792Sgshapiro		*pstat = EX_UNAVAILABLE;
557064562Sgshapiro
557164562Sgshapiro  ph_map_lookup_abort:
557264562Sgshapiro	if (ev != NULL)
557390792Sgshapiro		sm_clrevent(ev);
557464562Sgshapiro
557564562Sgshapiro	/*
557690792Sgshapiro	**  Close the connection if the timer popped
557764562Sgshapiro	**  or we got a temporary PH error
557864562Sgshapiro	*/
557964562Sgshapiro
558064562Sgshapiro	if (*pstat == EX_TEMPFAIL)
558190792Sgshapiro	{
558290792Sgshapiro		save_errno = errno;
5583110560Sgshapiro		pmap->ph_fastclose = PH_CLOSE_FAST;
558490792Sgshapiro		ph_map_close(map);
558590792Sgshapiro		errno = save_errno;
558690792Sgshapiro	}
558764562Sgshapiro
558864562Sgshapiro	if (*pstat == EX_OK)
558964562Sgshapiro	{
559064562Sgshapiro		if (tTd(38,20))
559190792Sgshapiro			sm_dprintf("ph_map_lookup: %s => %s\n", key, value);
559264562Sgshapiro
559364562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
559490792Sgshapiro			return map_rewrite(map, key, strlen(key), NULL);
559564562Sgshapiro		else
559690792Sgshapiro			return map_rewrite(map, value, strlen(value), args);
559764562Sgshapiro	}
559864562Sgshapiro
559964562Sgshapiro	return NULL;
560064562Sgshapiro}
560164562Sgshapiro#endif /* PH_MAP */
5602168515Sgshapiro
560390792Sgshapiro/*
560442575Speter**  syslog map
560538032Speter*/
560638032Speter
560738032Speter#define map_prio	map_lockfd	/* overload field */
560838032Speter
560938032Speter/*
561042575Speter**  SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
561138032Speter*/
561238032Speter
561338032Speterbool
561438032Spetersyslog_map_parseargs(map, args)
561538032Speter	MAP *map;
561638032Speter	char *args;
561738032Speter{
561838032Speter	char *p = args;
561938032Speter	char *priority = NULL;
562038032Speter
562164562Sgshapiro	/* there is no check whether there is really an argument */
562264562Sgshapiro	while (*p != '\0')
562338032Speter	{
5624363466Sgshapiro		while (SM_ISSPACE(*p))
562538032Speter			p++;
562638032Speter		if (*p != '-')
562738032Speter			break;
562864562Sgshapiro		++p;
562964562Sgshapiro		if (*p == 'D')
563064562Sgshapiro		{
563164562Sgshapiro			map->map_mflags |= MF_DEFER;
563264562Sgshapiro			++p;
563364562Sgshapiro		}
563464562Sgshapiro		else if (*p == 'S')
563564562Sgshapiro		{
563664562Sgshapiro			map->map_spacesub = *++p;
563764562Sgshapiro			if (*p != '\0')
563864562Sgshapiro				p++;
563964562Sgshapiro		}
564064562Sgshapiro		else if (*p == 'L')
564164562Sgshapiro		{
5642363466Sgshapiro			while (*++p != '\0' && SM_ISSPACE(*p))
564364562Sgshapiro				continue;
564464562Sgshapiro			if (*p == '\0')
564564562Sgshapiro				break;
564664562Sgshapiro			priority = p;
5647363466Sgshapiro			while (*p != '\0' && !(SM_ISSPACE(*p)))
564864562Sgshapiro				p++;
564964562Sgshapiro			if (*p != '\0')
565064562Sgshapiro				*p++ = '\0';
565164562Sgshapiro		}
565264562Sgshapiro		else
565364562Sgshapiro		{
565464562Sgshapiro			syserr("Illegal option %c map syslog", *p);
565564562Sgshapiro			++p;
565664562Sgshapiro		}
565738032Speter	}
565838032Speter
565938032Speter	if (priority == NULL)
566038032Speter		map->map_prio = LOG_INFO;
566138032Speter	else
566238032Speter	{
566390792Sgshapiro		if (sm_strncasecmp("LOG_", priority, 4) == 0)
566438032Speter			priority += 4;
566538032Speter
566638032Speter#ifdef LOG_EMERG
566790792Sgshapiro		if (sm_strcasecmp("EMERG", priority) == 0)
566838032Speter			map->map_prio = LOG_EMERG;
566938032Speter		else
567064562Sgshapiro#endif /* LOG_EMERG */
567138032Speter#ifdef LOG_ALERT
567290792Sgshapiro		if (sm_strcasecmp("ALERT", priority) == 0)
567338032Speter			map->map_prio = LOG_ALERT;
567438032Speter		else
567564562Sgshapiro#endif /* LOG_ALERT */
567638032Speter#ifdef LOG_CRIT
567790792Sgshapiro		if (sm_strcasecmp("CRIT", priority) == 0)
567838032Speter			map->map_prio = LOG_CRIT;
567938032Speter		else
568064562Sgshapiro#endif /* LOG_CRIT */
568138032Speter#ifdef LOG_ERR
568290792Sgshapiro		if (sm_strcasecmp("ERR", priority) == 0)
568338032Speter			map->map_prio = LOG_ERR;
568438032Speter		else
568564562Sgshapiro#endif /* LOG_ERR */
568638032Speter#ifdef LOG_WARNING
568790792Sgshapiro		if (sm_strcasecmp("WARNING", priority) == 0)
568838032Speter			map->map_prio = LOG_WARNING;
568938032Speter		else
569064562Sgshapiro#endif /* LOG_WARNING */
569138032Speter#ifdef LOG_NOTICE
569290792Sgshapiro		if (sm_strcasecmp("NOTICE", priority) == 0)
569338032Speter			map->map_prio = LOG_NOTICE;
569438032Speter		else
569564562Sgshapiro#endif /* LOG_NOTICE */
569638032Speter#ifdef LOG_INFO
569790792Sgshapiro		if (sm_strcasecmp("INFO", priority) == 0)
569838032Speter			map->map_prio = LOG_INFO;
569938032Speter		else
570064562Sgshapiro#endif /* LOG_INFO */
570138032Speter#ifdef LOG_DEBUG
570290792Sgshapiro		if (sm_strcasecmp("DEBUG", priority) == 0)
570338032Speter			map->map_prio = LOG_DEBUG;
570438032Speter		else
570564562Sgshapiro#endif /* LOG_DEBUG */
570638032Speter		{
570790792Sgshapiro			syserr("syslog_map_parseargs: Unknown priority %s",
570838032Speter			       priority);
570990792Sgshapiro			return false;
571038032Speter		}
571138032Speter	}
571290792Sgshapiro	return true;
571338032Speter}
571438032Speter
571538032Speter/*
571642575Speter**  SYSLOG_MAP_LOOKUP -- rewrite and syslog message.  Always return empty string
571738032Speter*/
571838032Speter
571938032Speterchar *
572038032Spetersyslog_map_lookup(map, string, args, statp)
572138032Speter	MAP *map;
572238032Speter	char *string;
572338032Speter	char **args;
572438032Speter	int *statp;
572538032Speter{
572638032Speter	char *ptr = map_rewrite(map, string, strlen(string), args);
572738032Speter
572838032Speter	if (ptr != NULL)
572938032Speter	{
573038032Speter		if (tTd(38, 20))
573190792Sgshapiro			sm_dprintf("syslog_map_lookup(%s (priority %d): %s\n",
573264562Sgshapiro				map->map_mname, map->map_prio, ptr);
573338032Speter
573438032Speter		sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
573538032Speter	}
573638032Speter
573738032Speter	*statp = EX_OK;
573838032Speter	return "";
573938032Speter}
574038032Speter
5741168515Sgshapiro#if _FFR_DPRINTF_MAP
574290792Sgshapiro/*
5743168515Sgshapiro**  dprintf map
5744168515Sgshapiro*/
5745168515Sgshapiro
5746168515Sgshapiro#define map_dbg_level	map_lockfd	/* overload field */
5747168515Sgshapiro
5748168515Sgshapiro/*
5749168515Sgshapiro**  DPRINTF_MAP_PARSEARGS -- check for priority level to dprintf messages.
5750168515Sgshapiro*/
5751168515Sgshapiro
5752168515Sgshapirobool
5753168515Sgshapirodprintf_map_parseargs(map, args)
5754168515Sgshapiro	MAP *map;
5755168515Sgshapiro	char *args;
5756168515Sgshapiro{
5757168515Sgshapiro	char *p = args;
5758168515Sgshapiro	char *dbg_level = NULL;
5759168515Sgshapiro
5760168515Sgshapiro	/* there is no check whether there is really an argument */
5761168515Sgshapiro	while (*p != '\0')
5762168515Sgshapiro	{
5763363466Sgshapiro		while (SM_ISSPACE(*p))
5764168515Sgshapiro			p++;
5765168515Sgshapiro		if (*p != '-')
5766168515Sgshapiro			break;
5767168515Sgshapiro		++p;
5768168515Sgshapiro		if (*p == 'D')
5769168515Sgshapiro		{
5770168515Sgshapiro			map->map_mflags |= MF_DEFER;
5771168515Sgshapiro			++p;
5772168515Sgshapiro		}
5773168515Sgshapiro		else if (*p == 'S')
5774168515Sgshapiro		{
5775168515Sgshapiro			map->map_spacesub = *++p;
5776168515Sgshapiro			if (*p != '\0')
5777168515Sgshapiro				p++;
5778168515Sgshapiro		}
5779168515Sgshapiro		else if (*p == 'd')
5780168515Sgshapiro		{
5781363466Sgshapiro			while (*++p != '\0' && SM_ISSPACE(*p))
5782168515Sgshapiro				continue;
5783168515Sgshapiro			if (*p == '\0')
5784168515Sgshapiro				break;
5785168515Sgshapiro			dbg_level = p;
5786363466Sgshapiro			while (*p != '\0' && !(SM_ISSPACE(*p)))
5787168515Sgshapiro				p++;
5788168515Sgshapiro			if (*p != '\0')
5789168515Sgshapiro				*p++ = '\0';
5790168515Sgshapiro		}
5791168515Sgshapiro		else
5792168515Sgshapiro		{
5793168515Sgshapiro			syserr("Illegal option %c map dprintf", *p);
5794168515Sgshapiro			++p;
5795168515Sgshapiro		}
5796168515Sgshapiro	}
5797168515Sgshapiro
5798168515Sgshapiro	if (dbg_level == NULL)
5799168515Sgshapiro		map->map_dbg_level = 0;
5800168515Sgshapiro	else
5801168515Sgshapiro	{
5802168515Sgshapiro		if (!(isascii(*dbg_level) && isdigit(*dbg_level)))
5803168515Sgshapiro		{
5804168515Sgshapiro			syserr("dprintf map \"%s\", file %s: -d should specify a number, not %s",
5805168515Sgshapiro				map->map_mname, map->map_file,
5806168515Sgshapiro				dbg_level);
5807168515Sgshapiro			return false;
5808168515Sgshapiro		}
5809168515Sgshapiro		map->map_dbg_level = atoi(dbg_level);
5810168515Sgshapiro	}
5811168515Sgshapiro	return true;
5812168515Sgshapiro}
5813168515Sgshapiro
5814168515Sgshapiro/*
5815168515Sgshapiro**  DPRINTF_MAP_LOOKUP -- rewrite and print message.  Always return empty string
5816168515Sgshapiro*/
5817168515Sgshapiro
5818168515Sgshapirochar *
5819168515Sgshapirodprintf_map_lookup(map, string, args, statp)
5820168515Sgshapiro	MAP *map;
5821168515Sgshapiro	char *string;
5822168515Sgshapiro	char **args;
5823168515Sgshapiro	int *statp;
5824168515Sgshapiro{
5825168515Sgshapiro	char *ptr = map_rewrite(map, string, strlen(string), args);
5826168515Sgshapiro
5827168515Sgshapiro	if (ptr != NULL && tTd(85, map->map_dbg_level))
5828168515Sgshapiro		sm_dprintf("%s\n", ptr);
5829168515Sgshapiro	*statp = EX_OK;
5830168515Sgshapiro	return "";
5831168515Sgshapiro}
5832168515Sgshapiro#endif /* _FFR_DPRINTF_MAP */
5833168515Sgshapiro
5834168515Sgshapiro/*
583538032Speter**  HESIOD Modules
583638032Speter*/
583738032Speter
583890792Sgshapiro#if HESIOD
583938032Speter
584038032Speterbool
584138032Speterhes_map_open(map, mode)
584238032Speter	MAP *map;
584338032Speter	int mode;
584438032Speter{
584538032Speter	if (tTd(38, 2))
584690792Sgshapiro		sm_dprintf("hes_map_open(%s, %s, %d)\n",
584738032Speter			map->map_mname, map->map_file, mode);
584838032Speter
584938032Speter	if (mode != O_RDONLY)
585038032Speter	{
585138032Speter		/* issue a pseudo-error message */
585290792Sgshapiro		errno = SM_EMAPCANTWRITE;
585390792Sgshapiro		return false;
585438032Speter	}
585538032Speter
585664562Sgshapiro# ifdef HESIOD_INIT
585738032Speter	if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
585890792Sgshapiro		return true;
585938032Speter
586038032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
586194334Sgshapiro		syserr("451 4.3.5 cannot initialize Hesiod map (%s)",
586290792Sgshapiro			sm_errstring(errno));
586390792Sgshapiro	return false;
586464562Sgshapiro# else /* HESIOD_INIT */
586538032Speter	if (hes_error() == HES_ER_UNINIT)
586638032Speter		hes_init();
586738032Speter	switch (hes_error())
586838032Speter	{
586938032Speter	  case HES_ER_OK:
587038032Speter	  case HES_ER_NOTFOUND:
587190792Sgshapiro		return true;
587238032Speter	}
587338032Speter
587438032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
587594334Sgshapiro		syserr("451 4.3.5 cannot initialize Hesiod map (%d)", hes_error());
587638032Speter
587790792Sgshapiro	return false;
587864562Sgshapiro# endif /* HESIOD_INIT */
587938032Speter}
588038032Speter
588138032Speterchar *
588238032Speterhes_map_lookup(map, name, av, statp)
588338032Speter	MAP *map;
588438032Speter	char *name;
588538032Speter	char **av;
588638032Speter	int *statp;
588738032Speter{
588838032Speter	char **hp;
588938032Speter
589038032Speter	if (tTd(38, 20))
589190792Sgshapiro		sm_dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
589238032Speter
589338032Speter	if (name[0] == '\\')
589438032Speter	{
589538032Speter		char *np;
589638032Speter		int nl;
589777349Sgshapiro		int save_errno;
589838032Speter		char nbuf[MAXNAME];
589938032Speter
590038032Speter		nl = strlen(name);
5901168515Sgshapiro		if (nl < sizeof(nbuf) - 1)
590238032Speter			np = nbuf;
590338032Speter		else
590438032Speter			np = xalloc(strlen(name) + 2);
590538032Speter		np[0] = '\\';
5906168515Sgshapiro		(void) sm_strlcpy(&np[1], name, (sizeof(nbuf)) - 1);
590764562Sgshapiro# ifdef HESIOD_INIT
590838032Speter		hp = hesiod_resolve(HesiodContext, np, map->map_file);
5909363466Sgshapiro# else
591038032Speter		hp = hes_resolve(np, map->map_file);
591164562Sgshapiro# endif /* HESIOD_INIT */
591277349Sgshapiro		save_errno = errno;
591338032Speter		if (np != nbuf)
591490792Sgshapiro			sm_free(np); /* XXX */
591577349Sgshapiro		errno = save_errno;
591638032Speter	}
591738032Speter	else
591838032Speter	{
591964562Sgshapiro# ifdef HESIOD_INIT
592038032Speter		hp = hesiod_resolve(HesiodContext, name, map->map_file);
5921363466Sgshapiro# else
592238032Speter		hp = hes_resolve(name, map->map_file);
592364562Sgshapiro# endif /* HESIOD_INIT */
592438032Speter	}
592564562Sgshapiro# ifdef HESIOD_INIT
592677349Sgshapiro	if (hp == NULL || *hp == NULL)
592738032Speter	{
592838032Speter		switch (errno)
592938032Speter		{
593038032Speter		  case ENOENT:
593138032Speter			  *statp = EX_NOTFOUND;
593238032Speter			  break;
593338032Speter		  case ECONNREFUSED:
593438032Speter			  *statp = EX_TEMPFAIL;
593538032Speter			  break;
593690792Sgshapiro		  case EMSGSIZE:
593738032Speter		  case ENOMEM:
593838032Speter		  default:
593938032Speter			  *statp = EX_UNAVAILABLE;
594038032Speter			  break;
594138032Speter		}
594282017Sgshapiro		if (hp != NULL)
594382017Sgshapiro			hesiod_free_list(HesiodContext, hp);
594438032Speter		return NULL;
594538032Speter	}
594664562Sgshapiro# else /* HESIOD_INIT */
594738032Speter	if (hp == NULL || hp[0] == NULL)
594838032Speter	{
594938032Speter		switch (hes_error())
595038032Speter		{
595138032Speter		  case HES_ER_OK:
595238032Speter			*statp = EX_OK;
595338032Speter			break;
595438032Speter
595538032Speter		  case HES_ER_NOTFOUND:
595638032Speter			*statp = EX_NOTFOUND;
595738032Speter			break;
595838032Speter
595938032Speter		  case HES_ER_CONFIG:
596038032Speter			*statp = EX_UNAVAILABLE;
596138032Speter			break;
596238032Speter
596338032Speter		  case HES_ER_NET:
596438032Speter			*statp = EX_TEMPFAIL;
596538032Speter			break;
596638032Speter		}
596738032Speter		return NULL;
596838032Speter	}
596964562Sgshapiro# endif /* HESIOD_INIT */
597038032Speter
597138032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
597238032Speter		return map_rewrite(map, name, strlen(name), NULL);
597338032Speter	else
597438032Speter		return map_rewrite(map, hp[0], strlen(hp[0]), av);
597538032Speter}
597638032Speter
597790792Sgshapiro/*
597890792Sgshapiro**  HES_MAP_CLOSE -- free the Hesiod context
597990792Sgshapiro*/
598090792Sgshapiro
598190792Sgshapirovoid
598290792Sgshapirohes_map_close(map)
598390792Sgshapiro	MAP *map;
598490792Sgshapiro{
598590792Sgshapiro	if (tTd(38, 20))
598690792Sgshapiro		sm_dprintf("hes_map_close(%s)\n", map->map_file);
598790792Sgshapiro
598890792Sgshapiro# ifdef HESIOD_INIT
598990792Sgshapiro	/* Free the hesiod context */
599090792Sgshapiro	if (HesiodContext != NULL)
599190792Sgshapiro	{
599290792Sgshapiro		hesiod_end(HesiodContext);
599390792Sgshapiro		HesiodContext = NULL;
599490792Sgshapiro	}
599590792Sgshapiro# endif /* HESIOD_INIT */
599690792Sgshapiro}
599790792Sgshapiro
599864562Sgshapiro#endif /* HESIOD */
599990792Sgshapiro/*
600038032Speter**  NeXT NETINFO Modules
600138032Speter*/
600238032Speter
600338032Speter#if NETINFO
600438032Speter
600538032Speter# define NETINFO_DEFAULT_DIR		"/aliases"
600638032Speter# define NETINFO_DEFAULT_PROPERTY	"members"
600738032Speter
600838032Speter/*
600938032Speter**  NI_MAP_OPEN -- open NetInfo Aliases
601038032Speter*/
601138032Speter
601238032Speterbool
601338032Speterni_map_open(map, mode)
601438032Speter	MAP *map;
601538032Speter	int mode;
601638032Speter{
601738032Speter	if (tTd(38, 2))
601890792Sgshapiro		sm_dprintf("ni_map_open(%s, %s, %d)\n",
601938032Speter			map->map_mname, map->map_file, mode);
602038032Speter	mode &= O_ACCMODE;
602138032Speter
602238032Speter	if (*map->map_file == '\0')
602338032Speter		map->map_file = NETINFO_DEFAULT_DIR;
602438032Speter
602538032Speter	if (map->map_valcolnm == NULL)
602638032Speter		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
602738032Speter
602890792Sgshapiro	if (map->map_coldelim == '\0')
602990792Sgshapiro	{
603090792Sgshapiro		if (bitset(MF_ALIAS, map->map_mflags))
603190792Sgshapiro			map->map_coldelim = ',';
603290792Sgshapiro		else if (bitset(MF_FILECLASS, map->map_mflags))
603390792Sgshapiro			map->map_coldelim = ' ';
603490792Sgshapiro	}
603590792Sgshapiro	return true;
603638032Speter}
603738032Speter
603838032Speter
603938032Speter/*
604038032Speter**  NI_MAP_LOOKUP -- look up a datum in NetInfo
604138032Speter*/
604238032Speter
604338032Speterchar *
604438032Speterni_map_lookup(map, name, av, statp)
604538032Speter	MAP *map;
604638032Speter	char *name;
604738032Speter	char **av;
604838032Speter	int *statp;
604938032Speter{
605038032Speter	char *res;
605138032Speter	char *propval;
605238032Speter
605338032Speter	if (tTd(38, 20))
605490792Sgshapiro		sm_dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
605538032Speter
605638032Speter	propval = ni_propval(map->map_file, map->map_keycolnm, name,
605738032Speter			     map->map_valcolnm, map->map_coldelim);
605838032Speter
605938032Speter	if (propval == NULL)
606038032Speter		return NULL;
606138032Speter
606290792Sgshapiro	SM_TRY
606390792Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
606490792Sgshapiro			res = map_rewrite(map, name, strlen(name), NULL);
606590792Sgshapiro		else
606690792Sgshapiro			res = map_rewrite(map, propval, strlen(propval), av);
606790792Sgshapiro	SM_FINALLY
606890792Sgshapiro		sm_free(propval);
606990792Sgshapiro	SM_END_TRY
607038032Speter	return res;
607138032Speter}
607238032Speter
607338032Speter
607464562Sgshapirostatic bool
607538032Speterni_getcanonname(name, hbsize, statp)
607638032Speter	char *name;
607738032Speter	int hbsize;
607838032Speter	int *statp;
607938032Speter{
608038032Speter	char *vptr;
608138032Speter	char *ptr;
608238032Speter	char nbuf[MAXNAME + 1];
608338032Speter
608438032Speter	if (tTd(38, 20))
608590792Sgshapiro		sm_dprintf("ni_getcanonname(%s)\n", name);
608638032Speter
6087168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
608838032Speter	{
608938032Speter		*statp = EX_UNAVAILABLE;
609090792Sgshapiro		return false;
609138032Speter	}
609273188Sgshapiro	(void) shorten_hostname(nbuf);
609338032Speter
609438032Speter	/* we only accept single token search key */
609538032Speter	if (strchr(nbuf, '.'))
609638032Speter	{
609738032Speter		*statp = EX_NOHOST;
609890792Sgshapiro		return false;
609938032Speter	}
610038032Speter
610138032Speter	/* Do the search */
610238032Speter	vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
610338032Speter
610438032Speter	if (vptr == NULL)
610538032Speter	{
610638032Speter		*statp = EX_NOHOST;
610790792Sgshapiro		return false;
610838032Speter	}
610938032Speter
611038032Speter	/* Only want the first machine name */
611138032Speter	if ((ptr = strchr(vptr, '\n')) != NULL)
611238032Speter		*ptr = '\0';
611338032Speter
611490792Sgshapiro	if (sm_strlcpy(name, vptr, hbsize) >= hbsize)
611538032Speter	{
611677349Sgshapiro		sm_free(vptr);
611790792Sgshapiro		*statp = EX_UNAVAILABLE;
611890792Sgshapiro		return true;
611938032Speter	}
612077349Sgshapiro	sm_free(vptr);
612190792Sgshapiro	*statp = EX_OK;
612290792Sgshapiro	return false;
612338032Speter}
612490792Sgshapiro#endif /* NETINFO */
612538032Speter/*
612638032Speter**  TEXT (unindexed text file) Modules
612738032Speter**
612838032Speter**	This code donated by Sun Microsystems.
612938032Speter*/
613038032Speter
613138032Speter#define map_sff		map_lockfd	/* overload field */
613238032Speter
613338032Speter
613438032Speter/*
613538032Speter**  TEXT_MAP_OPEN -- open text table
613638032Speter*/
613738032Speter
613838032Speterbool
613938032Spetertext_map_open(map, mode)
614038032Speter	MAP *map;
614138032Speter	int mode;
614238032Speter{
614364562Sgshapiro	long sff;
614438032Speter	int i;
614538032Speter
614638032Speter	if (tTd(38, 2))
614790792Sgshapiro		sm_dprintf("text_map_open(%s, %s, %d)\n",
614838032Speter			map->map_mname, map->map_file, mode);
614938032Speter
615038032Speter	mode &= O_ACCMODE;
615138032Speter	if (mode != O_RDONLY)
615238032Speter	{
615338032Speter		errno = EPERM;
615490792Sgshapiro		return false;
615538032Speter	}
615638032Speter
615738032Speter	if (*map->map_file == '\0')
615838032Speter	{
615938032Speter		syserr("text map \"%s\": file name required",
616038032Speter			map->map_mname);
616190792Sgshapiro		return false;
616238032Speter	}
616338032Speter
616438032Speter	if (map->map_file[0] != '/')
616538032Speter	{
616638032Speter		syserr("text map \"%s\": file name must be fully qualified",
616738032Speter			map->map_mname);
616890792Sgshapiro		return false;
616938032Speter	}
617038032Speter
617138032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
617264562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
617338032Speter		sff |= SFF_NOWLINK;
617464562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
617538032Speter		sff |= SFF_SAFEDIRPATH;
617638032Speter	if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
617738032Speter			  sff, S_IRUSR, NULL)) != 0)
617838032Speter	{
617964562Sgshapiro		int save_errno = errno;
618064562Sgshapiro
618138032Speter		/* cannot open this map */
618238032Speter		if (tTd(38, 2))
618390792Sgshapiro			sm_dprintf("\tunsafe map file: %d\n", i);
618464562Sgshapiro		errno = save_errno;
618538032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
618638032Speter			syserr("text map \"%s\": unsafe map file %s",
618738032Speter				map->map_mname, map->map_file);
618890792Sgshapiro		return false;
618938032Speter	}
619038032Speter
619138032Speter	if (map->map_keycolnm == NULL)
619238032Speter		map->map_keycolno = 0;
619338032Speter	else
619438032Speter	{
619538032Speter		if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
619638032Speter		{
619738032Speter			syserr("text map \"%s\", file %s: -k should specify a number, not %s",
619838032Speter				map->map_mname, map->map_file,
619938032Speter				map->map_keycolnm);
620090792Sgshapiro			return false;
620138032Speter		}
620238032Speter		map->map_keycolno = atoi(map->map_keycolnm);
620338032Speter	}
620438032Speter
620538032Speter	if (map->map_valcolnm == NULL)
620638032Speter		map->map_valcolno = 0;
620738032Speter	else
620838032Speter	{
620938032Speter		if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
621038032Speter		{
621138032Speter			syserr("text map \"%s\", file %s: -v should specify a number, not %s",
621238032Speter					map->map_mname, map->map_file,
621338032Speter					map->map_valcolnm);
621490792Sgshapiro			return false;
621538032Speter		}
621638032Speter		map->map_valcolno = atoi(map->map_valcolnm);
621738032Speter	}
621838032Speter
621938032Speter	if (tTd(38, 2))
622038032Speter	{
622190792Sgshapiro		sm_dprintf("text_map_open(%s, %s): delimiter = ",
622238032Speter			map->map_mname, map->map_file);
622338032Speter		if (map->map_coldelim == '\0')
622490792Sgshapiro			sm_dprintf("(white space)\n");
622538032Speter		else
622690792Sgshapiro			sm_dprintf("%c\n", map->map_coldelim);
622738032Speter	}
622838032Speter
622938032Speter	map->map_sff = sff;
623090792Sgshapiro	return true;
623138032Speter}
623238032Speter
623338032Speter
623438032Speter/*
623538032Speter**  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
623638032Speter*/
623738032Speter
623838032Speterchar *
623938032Spetertext_map_lookup(map, name, av, statp)
624038032Speter	MAP *map;
624138032Speter	char *name;
624238032Speter	char **av;
624338032Speter	int *statp;
624438032Speter{
624538032Speter	char *vp;
624638032Speter	auto int vsize;
624738032Speter	int buflen;
624890792Sgshapiro	SM_FILE_T *f;
624938032Speter	char delim;
625038032Speter	int key_idx;
625138032Speter	bool found_it;
625264562Sgshapiro	long sff = map->map_sff;
625338032Speter	char search_key[MAXNAME + 1];
625438032Speter	char linebuf[MAXLINE];
625538032Speter	char buf[MAXNAME + 1];
625638032Speter
625790792Sgshapiro	found_it = false;
625838032Speter	if (tTd(38, 20))
625990792Sgshapiro		sm_dprintf("text_map_lookup(%s, %s)\n", map->map_mname,  name);
626038032Speter
626138032Speter	buflen = strlen(name);
6262168515Sgshapiro	if (buflen > sizeof(search_key) - 1)
6263168515Sgshapiro		buflen = sizeof(search_key) - 1;	/* XXX just cut if off? */
626464562Sgshapiro	memmove(search_key, name, buflen);
626538032Speter	search_key[buflen] = '\0';
626638032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
626738032Speter		makelower(search_key);
626838032Speter
626938032Speter	f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
627038032Speter	if (f == NULL)
627138032Speter	{
627238032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
627338032Speter		*statp = EX_UNAVAILABLE;
627438032Speter		return NULL;
627538032Speter	}
627638032Speter	key_idx = map->map_keycolno;
627738032Speter	delim = map->map_coldelim;
627898121Sgshapiro	while (sm_io_fgets(f, SM_TIME_DEFAULT,
6279249729Sgshapiro			   linebuf, sizeof(linebuf)) >= 0)
628038032Speter	{
628138032Speter		char *p;
628238032Speter
628338032Speter		/* skip comment line */
628438032Speter		if (linebuf[0] == '#')
628538032Speter			continue;
628638032Speter		p = strchr(linebuf, '\n');
628738032Speter		if (p != NULL)
628838032Speter			*p = '\0';
6289168515Sgshapiro		p = get_column(linebuf, key_idx, delim, buf, sizeof(buf));
629090792Sgshapiro		if (p != NULL && sm_strcasecmp(search_key, p) == 0)
629138032Speter		{
629290792Sgshapiro			found_it = true;
629338032Speter			break;
629438032Speter		}
629538032Speter	}
629690792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
629738032Speter	if (!found_it)
629838032Speter	{
629938032Speter		*statp = EX_NOTFOUND;
630038032Speter		return NULL;
630138032Speter	}
6302168515Sgshapiro	vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof(buf));
630342575Speter	if (vp == NULL)
630442575Speter	{
630542575Speter		*statp = EX_NOTFOUND;
630642575Speter		return NULL;
630742575Speter	}
630838032Speter	vsize = strlen(vp);
630938032Speter	*statp = EX_OK;
631038032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
631138032Speter		return map_rewrite(map, name, strlen(name), NULL);
631238032Speter	else
631338032Speter		return map_rewrite(map, vp, vsize, av);
631438032Speter}
631538032Speter
631638032Speter/*
631738032Speter**  TEXT_GETCANONNAME -- look up canonical name in hosts file
631838032Speter*/
631938032Speter
632064562Sgshapirostatic bool
632138032Spetertext_getcanonname(name, hbsize, statp)
632238032Speter	char *name;
632338032Speter	int hbsize;
632438032Speter	int *statp;
632538032Speter{
632638032Speter	bool found;
632773188Sgshapiro	char *dot;
632890792Sgshapiro	SM_FILE_T *f;
632938032Speter	char linebuf[MAXLINE];
633038032Speter	char cbuf[MAXNAME + 1];
633138032Speter	char nbuf[MAXNAME + 1];
633238032Speter
633338032Speter	if (tTd(38, 20))
633490792Sgshapiro		sm_dprintf("text_getcanonname(%s)\n", name);
633538032Speter
6336168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
633738032Speter	{
633838032Speter		*statp = EX_UNAVAILABLE;
633990792Sgshapiro		return false;
634038032Speter	}
634173188Sgshapiro	dot = shorten_hostname(nbuf);
634238032Speter
634390792Sgshapiro	f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, HostsFile, SM_IO_RDONLY,
634490792Sgshapiro		       NULL);
634538032Speter	if (f == NULL)
634638032Speter	{
634738032Speter		*statp = EX_UNAVAILABLE;
634890792Sgshapiro		return false;
634938032Speter	}
635090792Sgshapiro	found = false;
635190792Sgshapiro	while (!found &&
635298121Sgshapiro		sm_io_fgets(f, SM_TIME_DEFAULT,
6353249729Sgshapiro			    linebuf, sizeof(linebuf)) >= 0)
635438032Speter	{
635538032Speter		char *p = strpbrk(linebuf, "#\n");
635638032Speter
635738032Speter		if (p != NULL)
635838032Speter			*p = '\0';
635938032Speter		if (linebuf[0] != '\0')
636073188Sgshapiro			found = extract_canonname(nbuf, dot, linebuf,
6361168515Sgshapiro						  cbuf, sizeof(cbuf));
636238032Speter	}
636390792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
636438032Speter	if (!found)
636538032Speter	{
636638032Speter		*statp = EX_NOHOST;
636790792Sgshapiro		return false;
636838032Speter	}
636938032Speter
637090792Sgshapiro	if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
637138032Speter	{
637290792Sgshapiro		*statp = EX_UNAVAILABLE;
637390792Sgshapiro		return false;
637438032Speter	}
637590792Sgshapiro	*statp = EX_OK;
637690792Sgshapiro	return true;
637738032Speter}
637890792Sgshapiro/*
637938032Speter**  STAB (Symbol Table) Modules
638038032Speter*/
638138032Speter
638238032Speter
638338032Speter/*
638438032Speter**  STAB_MAP_LOOKUP -- look up alias in symbol table
638538032Speter*/
638638032Speter
638738032Speter/* ARGSUSED2 */
638838032Speterchar *
638938032Speterstab_map_lookup(map, name, av, pstat)
639038032Speter	register MAP *map;
639138032Speter	char *name;
639238032Speter	char **av;
639338032Speter	int *pstat;
639438032Speter{
639538032Speter	register STAB *s;
639638032Speter
639738032Speter	if (tTd(38, 20))
639890792Sgshapiro		sm_dprintf("stab_lookup(%s, %s)\n",
639938032Speter			map->map_mname, name);
640038032Speter
640138032Speter	s = stab(name, ST_ALIAS, ST_FIND);
6402147078Sgshapiro	if (s == NULL)
6403147078Sgshapiro		return NULL;
6404147078Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
6405147078Sgshapiro		return map_rewrite(map, name, strlen(name), NULL);
6406147078Sgshapiro	else
6407147078Sgshapiro		return map_rewrite(map, s->s_alias, strlen(s->s_alias), av);
640838032Speter}
640938032Speter
641038032Speter/*
641138032Speter**  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
641238032Speter*/
641338032Speter
641438032Spetervoid
641538032Speterstab_map_store(map, lhs, rhs)
641638032Speter	register MAP *map;
641738032Speter	char *lhs;
641838032Speter	char *rhs;
641938032Speter{
642038032Speter	register STAB *s;
642138032Speter
642238032Speter	s = stab(lhs, ST_ALIAS, ST_ENTER);
642338032Speter	s->s_alias = newstr(rhs);
642438032Speter}
642538032Speter
642638032Speter
642738032Speter/*
642838032Speter**  STAB_MAP_OPEN -- initialize (reads data file)
642938032Speter**
6430223067Sgshapiro**	This is a weird case -- it is only intended as a fallback for
643138032Speter**	aliases.  For this reason, opens for write (only during a
643238032Speter**	"newaliases") always fails, and opens for read open the
643338032Speter**	actual underlying text file instead of the database.
643438032Speter*/
643538032Speter
643638032Speterbool
643738032Speterstab_map_open(map, mode)
643838032Speter	register MAP *map;
643938032Speter	int mode;
644038032Speter{
644190792Sgshapiro	SM_FILE_T *af;
644264562Sgshapiro	long sff;
644338032Speter	struct stat st;
644438032Speter
644538032Speter	if (tTd(38, 2))
644690792Sgshapiro		sm_dprintf("stab_map_open(%s, %s, %d)\n",
644738032Speter			map->map_mname, map->map_file, mode);
644838032Speter
644938032Speter	mode &= O_ACCMODE;
645038032Speter	if (mode != O_RDONLY)
645138032Speter	{
645238032Speter		errno = EPERM;
645390792Sgshapiro		return false;
645438032Speter	}
645538032Speter
645638032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
645764562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
645838032Speter		sff |= SFF_NOWLINK;
645964562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
646038032Speter		sff |= SFF_SAFEDIRPATH;
646138032Speter	af = safefopen(map->map_file, O_RDONLY, 0444, sff);
646238032Speter	if (af == NULL)
646390792Sgshapiro		return false;
646490792Sgshapiro	readaliases(map, af, false, false);
646538032Speter
646690792Sgshapiro	if (fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &st) >= 0)
646738032Speter		map->map_mtime = st.st_mtime;
646890792Sgshapiro	(void) sm_io_close(af, SM_TIME_DEFAULT);
646938032Speter
647090792Sgshapiro	return true;
647138032Speter}
647290792Sgshapiro/*
647338032Speter**  Implicit Modules
647438032Speter**
647538032Speter**	Tries several types.  For back compatibility of aliases.
647638032Speter*/
647738032Speter
647838032Speter
647938032Speter/*
648038032Speter**  IMPL_MAP_LOOKUP -- lookup in best open database
648138032Speter*/
648238032Speter
648338032Speterchar *
648438032Speterimpl_map_lookup(map, name, av, pstat)
648538032Speter	MAP *map;
648638032Speter	char *name;
648738032Speter	char **av;
648838032Speter	int *pstat;
648938032Speter{
649038032Speter	if (tTd(38, 20))
649190792Sgshapiro		sm_dprintf("impl_map_lookup(%s, %s)\n",
649238032Speter			map->map_mname, name);
649338032Speter
649490792Sgshapiro#if NEWDB
649538032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
649638032Speter		return db_map_lookup(map, name, av, pstat);
6497363466Sgshapiro#endif
649890792Sgshapiro#if NDBM
649938032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
650038032Speter		return ndbm_map_lookup(map, name, av, pstat);
6501363466Sgshapiro#endif
6502363466Sgshapiro#if CDB
6503363466Sgshapiro	if (bitset(MF_IMPL_CDB, map->map_mflags))
6504363466Sgshapiro		return cdb_map_lookup(map, name, av, pstat);
6505363466Sgshapiro#endif
650638032Speter	return stab_map_lookup(map, name, av, pstat);
650738032Speter}
650838032Speter
650938032Speter/*
651038032Speter**  IMPL_MAP_STORE -- store in open databases
651138032Speter*/
651238032Speter
651338032Spetervoid
651438032Speterimpl_map_store(map, lhs, rhs)
651538032Speter	MAP *map;
651638032Speter	char *lhs;
651738032Speter	char *rhs;
651838032Speter{
651938032Speter	if (tTd(38, 12))
652090792Sgshapiro		sm_dprintf("impl_map_store(%s, %s, %s)\n",
652138032Speter			map->map_mname, lhs, rhs);
652290792Sgshapiro#if NEWDB
652338032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
652438032Speter		db_map_store(map, lhs, rhs);
6525363466Sgshapiro#endif
652690792Sgshapiro#if NDBM
652738032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
652838032Speter		ndbm_map_store(map, lhs, rhs);
6529363466Sgshapiro#endif
6530363466Sgshapiro#if CDB
6531363466Sgshapiro	if (bitset(MF_IMPL_CDB, map->map_mflags))
6532363466Sgshapiro		cdb_map_store(map, lhs, rhs);
6533363466Sgshapiro#endif
653438032Speter	stab_map_store(map, lhs, rhs);
653538032Speter}
653638032Speter
653738032Speter/*
653838032Speter**  IMPL_MAP_OPEN -- implicit database open
653938032Speter*/
654038032Speter
654138032Speterbool
654238032Speterimpl_map_open(map, mode)
654338032Speter	MAP *map;
654438032Speter	int mode;
654538032Speter{
6546363466Sgshapiro	bool wasopt;
6547363466Sgshapiro
654838032Speter	if (tTd(38, 2))
654990792Sgshapiro		sm_dprintf("impl_map_open(%s, %s, %d)\n",
655038032Speter			map->map_mname, map->map_file, mode);
655138032Speter
655238032Speter	mode &= O_ACCMODE;
6553363466Sgshapiro	wasopt = bitset(MF_OPTIONAL, map->map_mflags);
6554363466Sgshapiro
6555363466Sgshapiro	/* suppress error msgs */
6556363466Sgshapiro	map->map_mflags |= MF_OPTIONAL;
655790792Sgshapiro#if NEWDB
655838032Speter	map->map_mflags |= MF_IMPL_HASH;
655938032Speter	if (hash_map_open(map, mode))
656038032Speter	{
656138032Speter# ifdef NDBM_YP_COMPAT
656238032Speter		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
6563363466Sgshapiro# endif
6564363466Sgshapiro			goto ok;
656538032Speter	}
656638032Speter	else
656738032Speter		map->map_mflags &= ~MF_IMPL_HASH;
656864562Sgshapiro#endif /* NEWDB */
656990792Sgshapiro#if NDBM
657038032Speter	map->map_mflags |= MF_IMPL_NDBM;
657138032Speter	if (ndbm_map_open(map, mode))
6572363466Sgshapiro		goto ok;
657338032Speter	else
657438032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
657564562Sgshapiro#endif /* NDBM */
657638032Speter
6577363466Sgshapiro#if CDB
6578363466Sgshapiro	map->map_mflags |= MF_IMPL_CDB;
6579363466Sgshapiro	if (cdb_map_open(map, mode))
6580363466Sgshapiro		goto ok;
6581363466Sgshapiro	else
6582363466Sgshapiro		map->map_mflags &= ~MF_IMPL_CDB;
6583363466Sgshapiro#endif /* CDB */
6584363466Sgshapiro
6585363466Sgshapiro	if (!bitset(MF_ALIAS, map->map_mflags))
6586363466Sgshapiro		goto fail;
6587363466Sgshapiro#if NEWDB || NDBM || CDB
658838032Speter	if (Verbose)
658938032Speter		message("WARNING: cannot open alias database %s%s",
659038032Speter			map->map_file,
659138032Speter			mode == O_RDONLY ? "; reading text version" : "");
6592363466Sgshapiro#else
659338032Speter	if (mode != O_RDONLY)
659438032Speter		usrerr("Cannot rebuild aliases: no database format defined");
6595363466Sgshapiro#endif
659638032Speter
6597363466Sgshapiro	if (mode == O_RDONLY && stab_map_open(map, mode))
6598363466Sgshapiro		goto ok;
6599363466Sgshapiro
6600363466Sgshapiro  fail:
6601363466Sgshapiro	if (!wasopt)
6602363466Sgshapiro		map->map_mflags &= ~MF_OPTIONAL;
6603363466Sgshapiro	return false;
6604363466Sgshapiro
6605363466Sgshapiro  ok:
6606363466Sgshapiro	if (!wasopt)
6607363466Sgshapiro		map->map_mflags &= ~MF_OPTIONAL;
6608363466Sgshapiro	return true;
660938032Speter}
661038032Speter
661138032Speter
661238032Speter/*
661338032Speter**  IMPL_MAP_CLOSE -- close any open database(s)
661438032Speter*/
661538032Speter
661638032Spetervoid
661738032Speterimpl_map_close(map)
661838032Speter	MAP *map;
661938032Speter{
662038032Speter	if (tTd(38, 9))
662190792Sgshapiro		sm_dprintf("impl_map_close(%s, %s, %lx)\n",
662238032Speter			map->map_mname, map->map_file, map->map_mflags);
662390792Sgshapiro#if NEWDB
662438032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
662538032Speter	{
662638032Speter		db_map_close(map);
662738032Speter		map->map_mflags &= ~MF_IMPL_HASH;
662838032Speter	}
662964562Sgshapiro#endif /* NEWDB */
663038032Speter
663190792Sgshapiro#if NDBM
663238032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
663338032Speter	{
663438032Speter		ndbm_map_close(map);
663538032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
663638032Speter	}
663764562Sgshapiro#endif /* NDBM */
6638363466Sgshapiro#if CDB
6639363466Sgshapiro	if (bitset(MF_IMPL_CDB, map->map_mflags))
6640363466Sgshapiro	{
6641363466Sgshapiro		cdb_map_close(map);
6642363466Sgshapiro		map->map_mflags &= ~MF_IMPL_CDB;
6643363466Sgshapiro	}
6644363466Sgshapiro#endif /* CDB */
664538032Speter}
6646363466Sgshapiro
664790792Sgshapiro/*
664838032Speter**  User map class.
664938032Speter**
665038032Speter**	Provides access to the system password file.
665138032Speter*/
665238032Speter
665338032Speter/*
665438032Speter**  USER_MAP_OPEN -- open user map
665538032Speter**
665638032Speter**	Really just binds field names to field numbers.
665738032Speter*/
665838032Speter
665938032Speterbool
666038032Speteruser_map_open(map, mode)
666138032Speter	MAP *map;
666238032Speter	int mode;
666338032Speter{
666438032Speter	if (tTd(38, 2))
666590792Sgshapiro		sm_dprintf("user_map_open(%s, %d)\n",
666638032Speter			map->map_mname, mode);
666738032Speter
666838032Speter	mode &= O_ACCMODE;
666938032Speter	if (mode != O_RDONLY)
667038032Speter	{
667138032Speter		/* issue a pseudo-error message */
667290792Sgshapiro		errno = SM_EMAPCANTWRITE;
667390792Sgshapiro		return false;
667438032Speter	}
667538032Speter	if (map->map_valcolnm == NULL)
667664562Sgshapiro		/* EMPTY */
667738032Speter		/* nothing */ ;
667890792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "name") == 0)
667938032Speter		map->map_valcolno = 1;
668090792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "passwd") == 0)
668138032Speter		map->map_valcolno = 2;
668290792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "uid") == 0)
668338032Speter		map->map_valcolno = 3;
668490792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "gid") == 0)
668538032Speter		map->map_valcolno = 4;
668690792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "gecos") == 0)
668738032Speter		map->map_valcolno = 5;
668890792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "dir") == 0)
668938032Speter		map->map_valcolno = 6;
669090792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "shell") == 0)
669138032Speter		map->map_valcolno = 7;
669238032Speter	else
669338032Speter	{
669438032Speter		syserr("User map %s: unknown column name %s",
669538032Speter			map->map_mname, map->map_valcolnm);
669690792Sgshapiro		return false;
669738032Speter	}
669890792Sgshapiro	return true;
669938032Speter}
670038032Speter
670138032Speter
670238032Speter/*
670338032Speter**  USER_MAP_LOOKUP -- look up a user in the passwd file.
670438032Speter*/
670538032Speter
670638032Speter/* ARGSUSED3 */
670738032Speterchar *
670838032Speteruser_map_lookup(map, key, av, statp)
670938032Speter	MAP *map;
671038032Speter	char *key;
671138032Speter	char **av;
671238032Speter	int *statp;
671338032Speter{
671438032Speter	auto bool fuzzy;
671590792Sgshapiro	SM_MBDB_T user;
671638032Speter
671738032Speter	if (tTd(38, 20))
671890792Sgshapiro		sm_dprintf("user_map_lookup(%s, %s)\n",
671938032Speter			map->map_mname, key);
672038032Speter
672190792Sgshapiro	*statp = finduser(key, &fuzzy, &user);
672290792Sgshapiro	if (*statp != EX_OK)
672338032Speter		return NULL;
672438032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
672538032Speter		return map_rewrite(map, key, strlen(key), NULL);
672638032Speter	else
672738032Speter	{
672838032Speter		char *rwval = NULL;
672938032Speter		char buf[30];
673038032Speter
673138032Speter		switch (map->map_valcolno)
673238032Speter		{
673338032Speter		  case 0:
673438032Speter		  case 1:
673590792Sgshapiro			rwval = user.mbdb_name;
673638032Speter			break;
673738032Speter
673838032Speter		  case 2:
673990792Sgshapiro			rwval = "x";	/* passwd no longer supported */
674038032Speter			break;
674138032Speter
674238032Speter		  case 3:
6743168515Sgshapiro			(void) sm_snprintf(buf, sizeof(buf), "%d",
674490792Sgshapiro					   (int) user.mbdb_uid);
674538032Speter			rwval = buf;
674638032Speter			break;
674738032Speter
674838032Speter		  case 4:
6749168515Sgshapiro			(void) sm_snprintf(buf, sizeof(buf), "%d",
675090792Sgshapiro					   (int) user.mbdb_gid);
675138032Speter			rwval = buf;
675238032Speter			break;
675338032Speter
675438032Speter		  case 5:
675590792Sgshapiro			rwval = user.mbdb_fullname;
675638032Speter			break;
675738032Speter
675838032Speter		  case 6:
675990792Sgshapiro			rwval = user.mbdb_homedir;
676038032Speter			break;
676138032Speter
676238032Speter		  case 7:
676390792Sgshapiro			rwval = user.mbdb_shell;
676438032Speter			break;
6765159609Sgshapiro		  default:
6766159609Sgshapiro			syserr("user_map %s: bogus field %d",
6767159609Sgshapiro				map->map_mname, map->map_valcolno);
6768159609Sgshapiro			return NULL;
676938032Speter		}
677038032Speter		return map_rewrite(map, rwval, strlen(rwval), av);
677138032Speter	}
677238032Speter}
677390792Sgshapiro/*
677438032Speter**  Program map type.
677538032Speter**
677638032Speter**	This provides access to arbitrary programs.  It should be used
677738032Speter**	only very sparingly, since there is no way to bound the cost
677838032Speter**	of invoking an arbitrary program.
677938032Speter*/
678038032Speter
678138032Speterchar *
678238032Speterprog_map_lookup(map, name, av, statp)
678338032Speter	MAP *map;
678438032Speter	char *name;
678538032Speter	char **av;
678638032Speter	int *statp;
678738032Speter{
678838032Speter	int i;
678964562Sgshapiro	int save_errno;
679038032Speter	int fd;
679164562Sgshapiro	int status;
679238032Speter	auto pid_t pid;
679364562Sgshapiro	register char *p;
679438032Speter	char *rval;
679538032Speter	char *argv[MAXPV + 1];
679638032Speter	char buf[MAXLINE];
679738032Speter
679838032Speter	if (tTd(38, 20))
679990792Sgshapiro		sm_dprintf("prog_map_lookup(%s, %s) %s\n",
680038032Speter			map->map_mname, name, map->map_file);
680138032Speter
680238032Speter	i = 0;
680338032Speter	argv[i++] = map->map_file;
680438032Speter	if (map->map_rebuild != NULL)
680538032Speter	{
6806168515Sgshapiro		(void) sm_strlcpy(buf, map->map_rebuild, sizeof(buf));
680738032Speter		for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
680838032Speter		{
680938032Speter			if (i >= MAXPV - 1)
681038032Speter				break;
681138032Speter			argv[i++] = p;
681238032Speter		}
681338032Speter	}
681438032Speter	argv[i++] = name;
681538032Speter	argv[i] = NULL;
681638032Speter	if (tTd(38, 21))
681738032Speter	{
681890792Sgshapiro		sm_dprintf("prog_open:");
681938032Speter		for (i = 0; argv[i] != NULL; i++)
682090792Sgshapiro			sm_dprintf(" %s", argv[i]);
682190792Sgshapiro		sm_dprintf("\n");
682238032Speter	}
682390792Sgshapiro	(void) sm_blocksignal(SIGCHLD);
682438032Speter	pid = prog_open(argv, &fd, CurEnv);
682538032Speter	if (pid < 0)
682638032Speter	{
682738032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
682838032Speter			syserr("prog_map_lookup(%s) failed (%s) -- closing",
682990792Sgshapiro			       map->map_mname, sm_errstring(errno));
683038032Speter		else if (tTd(38, 9))
683190792Sgshapiro			sm_dprintf("prog_map_lookup(%s) failed (%s) -- closing",
683290792Sgshapiro				   map->map_mname, sm_errstring(errno));
683338032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
683438032Speter		*statp = EX_OSFILE;
683538032Speter		return NULL;
683638032Speter	}
6837168515Sgshapiro	i = read(fd, buf, sizeof(buf) - 1);
683838032Speter	if (i < 0)
683938032Speter	{
684090792Sgshapiro		syserr("prog_map_lookup(%s): read error %s",
684190792Sgshapiro		       map->map_mname, sm_errstring(errno));
684238032Speter		rval = NULL;
684338032Speter	}
684438032Speter	else if (i == 0)
684538032Speter	{
684638032Speter		if (tTd(38, 20))
684790792Sgshapiro			sm_dprintf("prog_map_lookup(%s): empty answer\n",
684890792Sgshapiro				   map->map_mname);
684938032Speter		rval = NULL;
685038032Speter	}
685138032Speter	else
685238032Speter	{
685338032Speter		buf[i] = '\0';
685438032Speter		p = strchr(buf, '\n');
685538032Speter		if (p != NULL)
685638032Speter			*p = '\0';
685738032Speter
685838032Speter		/* collect the return value */
685938032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
686038032Speter			rval = map_rewrite(map, name, strlen(name), NULL);
686138032Speter		else
686277349Sgshapiro			rval = map_rewrite(map, buf, strlen(buf), av);
686338032Speter
686438032Speter		/* now flush any additional output */
6865168515Sgshapiro		while ((i = read(fd, buf, sizeof(buf))) > 0)
686638032Speter			continue;
686738032Speter	}
686838032Speter
686938032Speter	/* wait for the process to terminate */
687064562Sgshapiro	(void) close(fd);
687164562Sgshapiro	status = waitfor(pid);
687264562Sgshapiro	save_errno = errno;
687390792Sgshapiro	(void) sm_releasesignal(SIGCHLD);
687464562Sgshapiro	errno = save_errno;
687538032Speter
687664562Sgshapiro	if (status == -1)
687738032Speter	{
687890792Sgshapiro		syserr("prog_map_lookup(%s): wait error %s",
687990792Sgshapiro		       map->map_mname, sm_errstring(errno));
688038032Speter		*statp = EX_SOFTWARE;
688138032Speter		rval = NULL;
688238032Speter	}
688364562Sgshapiro	else if (WIFEXITED(status))
688438032Speter	{
688564562Sgshapiro		if ((*statp = WEXITSTATUS(status)) != EX_OK)
688638032Speter			rval = NULL;
688738032Speter	}
688838032Speter	else
688938032Speter	{
689038032Speter		syserr("prog_map_lookup(%s): child died on signal %d",
689190792Sgshapiro		       map->map_mname, status);
689238032Speter		*statp = EX_UNAVAILABLE;
689338032Speter		rval = NULL;
689438032Speter	}
689538032Speter	return rval;
689638032Speter}
689790792Sgshapiro/*
689838032Speter**  Sequenced map type.
689938032Speter**
690038032Speter**	Tries each map in order until something matches, much like
690138032Speter**	implicit.  Stores go to the first map in the list that can
690238032Speter**	support storing.
690338032Speter**
690438032Speter**	This is slightly unusual in that there are two interfaces.
690538032Speter**	The "sequence" interface lets you stack maps arbitrarily.
690638032Speter**	The "switch" interface builds a sequence map by looking
690738032Speter**	at a system-dependent configuration file such as
690838032Speter**	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
690938032Speter**
691038032Speter**	We don't need an explicit open, since all maps are
691190792Sgshapiro**	opened on demand.
691238032Speter*/
691338032Speter
691438032Speter/*
691538032Speter**  SEQ_MAP_PARSE -- Sequenced map parsing
691638032Speter*/
691738032Speter
691838032Speterbool
691938032Speterseq_map_parse(map, ap)
692038032Speter	MAP *map;
692138032Speter	char *ap;
692238032Speter{
692338032Speter	int maxmap;
692438032Speter
692538032Speter	if (tTd(38, 2))
692690792Sgshapiro		sm_dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
692738032Speter	maxmap = 0;
692838032Speter	while (*ap != '\0')
692938032Speter	{
693038032Speter		register char *p;
693138032Speter		STAB *s;
693238032Speter
693338032Speter		/* find beginning of map name */
6934363466Sgshapiro		while (SM_ISSPACE(*ap))
693538032Speter			ap++;
693664562Sgshapiro		for (p = ap;
693764562Sgshapiro		     (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.';
693864562Sgshapiro		     p++)
693938032Speter			continue;
694038032Speter		if (*p != '\0')
694138032Speter			*p++ = '\0';
694238032Speter		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
694338032Speter			p++;
694438032Speter		if (*ap == '\0')
694538032Speter		{
694638032Speter			ap = p;
694738032Speter			continue;
694838032Speter		}
694938032Speter		s = stab(ap, ST_MAP, ST_FIND);
695038032Speter		if (s == NULL)
695138032Speter		{
695238032Speter			syserr("Sequence map %s: unknown member map %s",
695338032Speter				map->map_mname, ap);
695438032Speter		}
695590792Sgshapiro		else if (maxmap >= MAXMAPSTACK)
695638032Speter		{
695738032Speter			syserr("Sequence map %s: too many member maps (%d max)",
695838032Speter				map->map_mname, MAXMAPSTACK);
695938032Speter			maxmap++;
696038032Speter		}
696138032Speter		else if (maxmap < MAXMAPSTACK)
696238032Speter		{
696338032Speter			map->map_stack[maxmap++] = &s->s_map;
696438032Speter		}
696538032Speter		ap = p;
696638032Speter	}
696790792Sgshapiro	return true;
696838032Speter}
696938032Speter
697038032Speter/*
697138032Speter**  SWITCH_MAP_OPEN -- open a switched map
697238032Speter**
697338032Speter**	This looks at the system-dependent configuration and builds
697438032Speter**	a sequence map that does the same thing.
697538032Speter**
697638032Speter**	Every system must define a switch_map_find routine in conf.c
697738032Speter**	that will return the list of service types associated with a
697838032Speter**	given service class.
697938032Speter*/
698038032Speter
698138032Speterbool
698238032Speterswitch_map_open(map, mode)
698338032Speter	MAP *map;
698438032Speter	int mode;
698538032Speter{
698638032Speter	int mapno;
698738032Speter	int nmaps;
698838032Speter	char *maptype[MAXMAPSTACK];
698938032Speter
699038032Speter	if (tTd(38, 2))
699190792Sgshapiro		sm_dprintf("switch_map_open(%s, %s, %d)\n",
699238032Speter			map->map_mname, map->map_file, mode);
699338032Speter
699438032Speter	mode &= O_ACCMODE;
699538032Speter	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
699638032Speter	if (tTd(38, 19))
699738032Speter	{
699890792Sgshapiro		sm_dprintf("\tswitch_map_find => %d\n", nmaps);
699938032Speter		for (mapno = 0; mapno < nmaps; mapno++)
700090792Sgshapiro			sm_dprintf("\t\t%s\n", maptype[mapno]);
700138032Speter	}
700238032Speter	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
700390792Sgshapiro		return false;
700438032Speter
700538032Speter	for (mapno = 0; mapno < nmaps; mapno++)
700638032Speter	{
700738032Speter		register STAB *s;
700838032Speter		char nbuf[MAXNAME + 1];
700938032Speter
701038032Speter		if (maptype[mapno] == NULL)
701138032Speter			continue;
7012168515Sgshapiro		(void) sm_strlcpyn(nbuf, sizeof(nbuf), 3,
701390792Sgshapiro				   map->map_mname, ".", maptype[mapno]);
701438032Speter		s = stab(nbuf, ST_MAP, ST_FIND);
701538032Speter		if (s == NULL)
701638032Speter		{
701738032Speter			syserr("Switch map %s: unknown member map %s",
701838032Speter				map->map_mname, nbuf);
701938032Speter		}
702038032Speter		else
702138032Speter		{
702238032Speter			map->map_stack[mapno] = &s->s_map;
702338032Speter			if (tTd(38, 4))
702490792Sgshapiro				sm_dprintf("\tmap_stack[%d] = %s:%s\n",
702590792Sgshapiro					   mapno,
702690792Sgshapiro					   s->s_map.map_class->map_cname,
702790792Sgshapiro					   nbuf);
702838032Speter		}
702938032Speter	}
703090792Sgshapiro	return true;
703138032Speter}
703238032Speter
703390792Sgshapiro#if 0
703438032Speter/*
703538032Speter**  SEQ_MAP_CLOSE -- close all underlying maps
703638032Speter*/
703738032Speter
703838032Spetervoid
703938032Speterseq_map_close(map)
704038032Speter	MAP *map;
704138032Speter{
704238032Speter	int mapno;
704338032Speter
704438032Speter	if (tTd(38, 9))
704590792Sgshapiro		sm_dprintf("seq_map_close(%s)\n", map->map_mname);
704638032Speter
704738032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
704838032Speter	{
704938032Speter		MAP *mm = map->map_stack[mapno];
705038032Speter
705138032Speter		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
705238032Speter			continue;
705377349Sgshapiro		mm->map_mflags |= MF_CLOSING;
705438032Speter		mm->map_class->map_close(mm);
705577349Sgshapiro		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
705638032Speter	}
705738032Speter}
705890792Sgshapiro#endif /* 0 */
705938032Speter
706038032Speter/*
706138032Speter**  SEQ_MAP_LOOKUP -- sequenced map lookup
706238032Speter*/
706338032Speter
706438032Speterchar *
706538032Speterseq_map_lookup(map, key, args, pstat)
706638032Speter	MAP *map;
706738032Speter	char *key;
706838032Speter	char **args;
706938032Speter	int *pstat;
707038032Speter{
707138032Speter	int mapno;
707238032Speter	int mapbit = 0x01;
707390792Sgshapiro	bool tempfail = false;
707438032Speter
707538032Speter	if (tTd(38, 20))
707690792Sgshapiro		sm_dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
707738032Speter
707838032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
707938032Speter	{
708038032Speter		MAP *mm = map->map_stack[mapno];
708138032Speter		char *rv;
708238032Speter
708338032Speter		if (mm == NULL)
708438032Speter			continue;
708564562Sgshapiro		if (!bitset(MF_OPEN, mm->map_mflags) &&
708664562Sgshapiro		    !openmap(mm))
708738032Speter		{
708838032Speter			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
708938032Speter			{
709038032Speter				*pstat = EX_UNAVAILABLE;
709138032Speter				return NULL;
709238032Speter			}
709338032Speter			continue;
709438032Speter		}
709538032Speter		*pstat = EX_OK;
709638032Speter		rv = mm->map_class->map_lookup(mm, key, args, pstat);
709738032Speter		if (rv != NULL)
709838032Speter			return rv;
709938032Speter		if (*pstat == EX_TEMPFAIL)
710038032Speter		{
710138032Speter			if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
710238032Speter				return NULL;
710390792Sgshapiro			tempfail = true;
710438032Speter		}
710538032Speter		else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
710638032Speter			break;
710738032Speter	}
710838032Speter	if (tempfail)
710938032Speter		*pstat = EX_TEMPFAIL;
711038032Speter	else if (*pstat == EX_OK)
711138032Speter		*pstat = EX_NOTFOUND;
711238032Speter	return NULL;
711338032Speter}
711438032Speter
711538032Speter/*
711638032Speter**  SEQ_MAP_STORE -- sequenced map store
711738032Speter*/
711838032Speter
711938032Spetervoid
712038032Speterseq_map_store(map, key, val)
712138032Speter	MAP *map;
712238032Speter	char *key;
712338032Speter	char *val;
712438032Speter{
712538032Speter	int mapno;
712638032Speter
712738032Speter	if (tTd(38, 12))
712890792Sgshapiro		sm_dprintf("seq_map_store(%s, %s, %s)\n",
712938032Speter			map->map_mname, key, val);
713038032Speter
713138032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
713238032Speter	{
713338032Speter		MAP *mm = map->map_stack[mapno];
713438032Speter
713538032Speter		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
713638032Speter			continue;
713738032Speter
713838032Speter		mm->map_class->map_store(mm, key, val);
713938032Speter		return;
714038032Speter	}
714138032Speter	syserr("seq_map_store(%s, %s, %s): no writable map",
714238032Speter		map->map_mname, key, val);
714338032Speter}
714490792Sgshapiro/*
714538032Speter**  NULL stubs
714638032Speter*/
714738032Speter
714838032Speter/* ARGSUSED */
714938032Speterbool
715038032Speternull_map_open(map, mode)
715138032Speter	MAP *map;
715238032Speter	int mode;
715338032Speter{
715490792Sgshapiro	return true;
715538032Speter}
715638032Speter
715738032Speter/* ARGSUSED */
715838032Spetervoid
715938032Speternull_map_close(map)
716038032Speter	MAP *map;
716138032Speter{
716238032Speter	return;
716338032Speter}
716438032Speter
716538032Speterchar *
716638032Speternull_map_lookup(map, key, args, pstat)
716738032Speter	MAP *map;
716838032Speter	char *key;
716938032Speter	char **args;
717038032Speter	int *pstat;
717138032Speter{
717238032Speter	*pstat = EX_NOTFOUND;
717338032Speter	return NULL;
717438032Speter}
717538032Speter
717638032Speter/* ARGSUSED */
717738032Spetervoid
717838032Speternull_map_store(map, key, val)
717938032Speter	MAP *map;
718038032Speter	char *key;
718138032Speter	char *val;
718238032Speter{
718338032Speter	return;
718438032Speter}
718538032Speter
7186203004SgshapiroMAPCLASS	NullMapClass =
7187203004Sgshapiro{
7188203004Sgshapiro	"null-map",		NULL,			0,
7189203004Sgshapiro	NULL,			null_map_lookup,	null_map_store,
7190203004Sgshapiro	null_map_open,		null_map_close,
7191203004Sgshapiro};
7192203004Sgshapiro
719338032Speter/*
719438032Speter**  BOGUS stubs
719538032Speter*/
719638032Speter
719738032Speterchar *
719838032Speterbogus_map_lookup(map, key, args, pstat)
719938032Speter	MAP *map;
720038032Speter	char *key;
720138032Speter	char **args;
720238032Speter	int *pstat;
720338032Speter{
720438032Speter	*pstat = EX_TEMPFAIL;
720538032Speter	return NULL;
720638032Speter}
720738032Speter
720838032SpeterMAPCLASS	BogusMapClass =
720938032Speter{
721090792Sgshapiro	"bogus-map",		NULL,			0,
721190792Sgshapiro	NULL,			bogus_map_lookup,	null_map_store,
721290792Sgshapiro	null_map_open,		null_map_close,
721338032Speter};
721490792Sgshapiro/*
721564562Sgshapiro**  MACRO modules
721664562Sgshapiro*/
721764562Sgshapiro
721864562Sgshapirochar *
721964562Sgshapiromacro_map_lookup(map, name, av, statp)
722064562Sgshapiro	MAP *map;
722164562Sgshapiro	char *name;
722264562Sgshapiro	char **av;
722364562Sgshapiro	int *statp;
722464562Sgshapiro{
722564562Sgshapiro	int mid;
722664562Sgshapiro
722764562Sgshapiro	if (tTd(38, 20))
722890792Sgshapiro		sm_dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
722964562Sgshapiro			name == NULL ? "NULL" : name);
723064562Sgshapiro
723164562Sgshapiro	if (name == NULL ||
723264562Sgshapiro	    *name == '\0' ||
723390792Sgshapiro	    (mid = macid(name)) == 0)
723464562Sgshapiro	{
723564562Sgshapiro		*statp = EX_CONFIG;
723664562Sgshapiro		return NULL;
723764562Sgshapiro	}
723864562Sgshapiro
723964562Sgshapiro	if (av[1] == NULL)
724090792Sgshapiro		macdefine(&CurEnv->e_macro, A_PERM, mid, NULL);
724164562Sgshapiro	else
724290792Sgshapiro		macdefine(&CurEnv->e_macro, A_TEMP, mid, av[1]);
724364562Sgshapiro
724464562Sgshapiro	*statp = EX_OK;
724564562Sgshapiro	return "";
724664562Sgshapiro}
724790792Sgshapiro/*
724838032Speter**  REGEX modules
724938032Speter*/
725038032Speter
725190792Sgshapiro#if MAP_REGEX
725238032Speter
725338032Speter# include <regex.h>
725438032Speter
725538032Speter# define DEFAULT_DELIM	CONDELSE
725638032Speter# define END_OF_FIELDS	-1
725738032Speter# define ERRBUF_SIZE	80
725838032Speter# define MAX_MATCH	32
725938032Speter
726064562Sgshapiro# define xnalloc(s)	memset(xalloc(s), '\0', s);
726138032Speter
726238032Speterstruct regex_map
726338032Speter{
726471345Sgshapiro	regex_t	*regex_pattern_buf;	/* xalloc it */
726538032Speter	int	*regex_subfields;	/* move to type MAP */
726664562Sgshapiro	char	*regex_delim;		/* move to type MAP */
726738032Speter};
726838032Speter
7269141858Sgshapirostatic int	parse_fields __P((char *, int *, int, int));
7270141858Sgshapirostatic char	*regex_map_rewrite __P((MAP *, const char*, size_t, char **));
7271141858Sgshapiro
727238032Speterstatic int
727338032Speterparse_fields(s, ibuf, blen, nr_substrings)
727438032Speter	char *s;
727538032Speter	int *ibuf;		/* array */
727638032Speter	int blen;		/* number of elements in ibuf */
727738032Speter	int nr_substrings;	/* number of substrings in the pattern */
727838032Speter{
727938032Speter	register char *cp;
728038032Speter	int i = 0;
728190792Sgshapiro	bool lastone = false;
728238032Speter
728338032Speter	blen--;		/* for terminating END_OF_FIELDS */
728438032Speter	cp = s;
728538032Speter	do
728638032Speter	{
728738032Speter		for (;; cp++)
728838032Speter		{
728938032Speter			if (*cp == ',')
729038032Speter			{
729138032Speter				*cp = '\0';
729238032Speter				break;
729338032Speter			}
729438032Speter			if (*cp == '\0')
729538032Speter			{
729690792Sgshapiro				lastone = true;
729738032Speter				break;
729838032Speter			}
729938032Speter		}
730038032Speter		if (i < blen)
730138032Speter		{
730238032Speter			int val = atoi(s);
730338032Speter
730438032Speter			if (val < 0 || val >= nr_substrings)
730538032Speter			{
730638032Speter				syserr("field (%d) out of range, only %d substrings in pattern",
730738032Speter				       val, nr_substrings);
730838032Speter				return -1;
730938032Speter			}
731038032Speter			ibuf[i++] = val;
731138032Speter		}
731238032Speter		else
731338032Speter		{
731490792Sgshapiro			syserr("too many fields, %d max", blen);
731538032Speter			return -1;
731638032Speter		}
731738032Speter		s = ++cp;
731838032Speter	} while (!lastone);
731938032Speter	ibuf[i] = END_OF_FIELDS;
732038032Speter	return i;
732138032Speter}
732238032Speter
732338032Speterbool
732438032Speterregex_map_init(map, ap)
732538032Speter	MAP *map;
732638032Speter	char *ap;
732738032Speter{
732838032Speter	int regerr;
732938032Speter	struct regex_map *map_p;
733038032Speter	register char *p;
733138032Speter	char *sub_param = NULL;
733238032Speter	int pflags;
733390792Sgshapiro	static char defdstr[] = { (char) DEFAULT_DELIM, '\0' };
733438032Speter
733538032Speter	if (tTd(38, 2))
733690792Sgshapiro		sm_dprintf("regex_map_init: mapname '%s', args '%s'\n",
733764562Sgshapiro			map->map_mname, ap);
733838032Speter
733938032Speter	pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
734038032Speter	p = ap;
7341168515Sgshapiro	map_p = (struct regex_map *) xnalloc(sizeof(*map_p));
734271345Sgshapiro	map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t));
734338032Speter
734438032Speter	for (;;)
734564562Sgshapiro	{
7346363466Sgshapiro		while (SM_ISSPACE(*p))
734738032Speter			p++;
734838032Speter		if (*p != '-')
734938032Speter			break;
735038032Speter		switch (*++p)
735138032Speter		{
735238032Speter		  case 'n':	/* not */
735338032Speter			map->map_mflags |= MF_REGEX_NOT;
735438032Speter			break;
735538032Speter
735638032Speter		  case 'f':	/* case sensitive */
735738032Speter			map->map_mflags |= MF_NOFOLDCASE;
735838032Speter			pflags &= ~REG_ICASE;
735938032Speter			break;
736038032Speter
736138032Speter		  case 'b':	/* basic regular expressions */
736238032Speter			pflags &= ~REG_EXTENDED;
736338032Speter			break;
736438032Speter
736538032Speter		  case 's':	/* substring match () syntax */
736638032Speter			sub_param = ++p;
736738032Speter			pflags &= ~REG_NOSUB;
736838032Speter			break;
736938032Speter
737038032Speter		  case 'd':	/* delimiter */
737164562Sgshapiro			map_p->regex_delim = ++p;
737238032Speter			break;
737338032Speter
737438032Speter		  case 'a':	/* map append */
737538032Speter			map->map_app = ++p;
737638032Speter			break;
737738032Speter
737838032Speter		  case 'm':	/* matchonly */
737938032Speter			map->map_mflags |= MF_MATCHONLY;
738038032Speter			break;
738138032Speter
7382120256Sgshapiro		  case 'q':
7383120256Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
7384120256Sgshapiro			break;
7385120256Sgshapiro
738664562Sgshapiro		  case 'S':
738764562Sgshapiro			map->map_spacesub = *++p;
738864562Sgshapiro			break;
738964562Sgshapiro
739064562Sgshapiro		  case 'D':
739164562Sgshapiro			map->map_mflags |= MF_DEFER;
739264562Sgshapiro			break;
739364562Sgshapiro
739438032Speter		}
7395363466Sgshapiro		while (*p != '\0' && !(SM_ISSPACE(*p)))
739664562Sgshapiro			p++;
739764562Sgshapiro		if (*p != '\0')
739864562Sgshapiro			*p++ = '\0';
739938032Speter	}
740038032Speter	if (tTd(38, 3))
740190792Sgshapiro		sm_dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
740238032Speter
740371345Sgshapiro	if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0)
740438032Speter	{
740538032Speter		/* Errorhandling */
740638032Speter		char errbuf[ERRBUF_SIZE];
740738032Speter
740871345Sgshapiro		(void) regerror(regerr, map_p->regex_pattern_buf,
7409168515Sgshapiro			 errbuf, sizeof(errbuf));
741090792Sgshapiro		syserr("pattern-compile-error: %s", errbuf);
741190792Sgshapiro		sm_free(map_p->regex_pattern_buf); /* XXX */
741290792Sgshapiro		sm_free(map_p); /* XXX */
741390792Sgshapiro		return false;
741438032Speter	}
741538032Speter
741638032Speter	if (map->map_app != NULL)
741738032Speter		map->map_app = newstr(map->map_app);
741864562Sgshapiro	if (map_p->regex_delim != NULL)
741964562Sgshapiro		map_p->regex_delim = newstr(map_p->regex_delim);
742038032Speter	else
742164562Sgshapiro		map_p->regex_delim = defdstr;
742238032Speter
742338032Speter	if (!bitset(REG_NOSUB, pflags))
742438032Speter	{
742538032Speter		/* substring matching */
742638032Speter		int substrings;
742764562Sgshapiro		int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1));
742838032Speter
742971345Sgshapiro		substrings = map_p->regex_pattern_buf->re_nsub + 1;
743038032Speter
743138032Speter		if (tTd(38, 3))
743290792Sgshapiro			sm_dprintf("regex_map_init: nr of substrings %d\n",
743364562Sgshapiro				substrings);
743438032Speter
743538032Speter		if (substrings >= MAX_MATCH)
743638032Speter		{
743790792Sgshapiro			syserr("too many substrings, %d max", MAX_MATCH);
743890792Sgshapiro			sm_free(map_p->regex_pattern_buf); /* XXX */
743990792Sgshapiro			sm_free(map_p); /* XXX */
744090792Sgshapiro			return false;
744138032Speter		}
744238032Speter		if (sub_param != NULL && sub_param[0] != '\0')
744338032Speter		{
744438032Speter			/* optional parameter -sfields */
744538032Speter			if (parse_fields(sub_param, fields,
744638032Speter					 MAX_MATCH + 1, substrings) == -1)
744790792Sgshapiro				return false;
744838032Speter		}
744938032Speter		else
745038032Speter		{
745138032Speter			int i;
745238032Speter
745390792Sgshapiro			/* set default fields */
745438032Speter			for (i = 0; i < substrings; i++)
745538032Speter				fields[i] = i;
745638032Speter			fields[i] = END_OF_FIELDS;
745738032Speter		}
745838032Speter		map_p->regex_subfields = fields;
745938032Speter		if (tTd(38, 3))
746038032Speter		{
746138032Speter			int *ip;
746238032Speter
746390792Sgshapiro			sm_dprintf("regex_map_init: subfields");
746438032Speter			for (ip = fields; *ip != END_OF_FIELDS; ip++)
746590792Sgshapiro				sm_dprintf(" %d", *ip);
746690792Sgshapiro			sm_dprintf("\n");
746738032Speter		}
746838032Speter	}
746990792Sgshapiro	map->map_db1 = (ARBPTR_T) map_p;	/* dirty hack */
747090792Sgshapiro	return true;
747138032Speter}
747238032Speter
747338032Speterstatic char *
747438032Speterregex_map_rewrite(map, s, slen, av)
747538032Speter	MAP *map;
747638032Speter	const char *s;
747738032Speter	size_t slen;
747838032Speter	char **av;
747938032Speter{
748038032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
748138032Speter		return map_rewrite(map, av[0], strlen(av[0]), NULL);
748238032Speter	else
748377349Sgshapiro		return map_rewrite(map, s, slen, av);
748438032Speter}
748538032Speter
748638032Speterchar *
748738032Speterregex_map_lookup(map, name, av, statp)
748838032Speter	MAP *map;
748938032Speter	char *name;
749038032Speter	char **av;
749138032Speter	int *statp;
749238032Speter{
749338032Speter	int reg_res;
749438032Speter	struct regex_map *map_p;
749538032Speter	regmatch_t pmatch[MAX_MATCH];
749638032Speter
749738032Speter	if (tTd(38, 20))
749838032Speter	{
749938032Speter		char **cpp;
750038032Speter
750190792Sgshapiro		sm_dprintf("regex_map_lookup: key '%s'\n", name);
750264562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
750390792Sgshapiro			sm_dprintf("regex_map_lookup: arg '%s'\n", *cpp);
750438032Speter	}
750538032Speter
750638032Speter	map_p = (struct regex_map *)(map->map_db1);
750771345Sgshapiro	reg_res = regexec(map_p->regex_pattern_buf,
750864562Sgshapiro			  name, MAX_MATCH, pmatch, 0);
750938032Speter
751038032Speter	if (bitset(MF_REGEX_NOT, map->map_mflags))
751138032Speter	{
751238032Speter		/* option -n */
751338032Speter		if (reg_res == REG_NOMATCH)
751490792Sgshapiro			return regex_map_rewrite(map, "", (size_t) 0, av);
751538032Speter		else
751638032Speter			return NULL;
751738032Speter	}
751838032Speter	if (reg_res == REG_NOMATCH)
751938032Speter		return NULL;
752038032Speter
752138032Speter	if (map_p->regex_subfields != NULL)
752238032Speter	{
752338032Speter		/* option -s */
752438032Speter		static char retbuf[MAXNAME];
752538032Speter		int fields[MAX_MATCH + 1];
752690792Sgshapiro		bool first = true;
752738032Speter		int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
752890792Sgshapiro		bool quotemode = false, bslashmode = false;
752938032Speter		register char *dp, *sp;
753038032Speter		char *endp, *ldp;
753138032Speter		int *ip;
753238032Speter
753338032Speter		dp = retbuf;
753438032Speter		ldp = retbuf + sizeof(retbuf) - 1;
753538032Speter
753638032Speter		if (av[1] != NULL)
753738032Speter		{
753838032Speter			if (parse_fields(av[1], fields, MAX_MATCH + 1,
753971345Sgshapiro					 (int) map_p->regex_pattern_buf->re_nsub + 1) == -1)
754038032Speter			{
754138032Speter				*statp = EX_CONFIG;
754238032Speter				return NULL;
754338032Speter			}
754438032Speter			ip = fields;
754538032Speter		}
754638032Speter		else
754738032Speter			ip = map_p->regex_subfields;
754838032Speter
754938032Speter		for ( ; *ip != END_OF_FIELDS; ip++)
755038032Speter		{
755138032Speter			if (!first)
755238032Speter			{
755364562Sgshapiro				for (sp = map_p->regex_delim; *sp; sp++)
755438032Speter				{
755538032Speter					if (dp < ldp)
755638032Speter						*dp++ = *sp;
755738032Speter				}
755838032Speter			}
755938032Speter			else
756090792Sgshapiro				first = false;
756138032Speter
756271345Sgshapiro			if (*ip >= MAX_MATCH ||
756371345Sgshapiro			    pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
756438032Speter				continue;
756538032Speter
756638032Speter			sp = name + pmatch[*ip].rm_so;
756738032Speter			endp = name + pmatch[*ip].rm_eo;
756838032Speter			for (; endp > sp; sp++)
756938032Speter			{
757038032Speter				if (dp < ldp)
757138032Speter				{
757264562Sgshapiro					if (bslashmode)
757364562Sgshapiro					{
757438032Speter						*dp++ = *sp;
757590792Sgshapiro						bslashmode = false;
757638032Speter					}
757764562Sgshapiro					else if (quotemode && *sp != '"' &&
757838032Speter						*sp != '\\')
757938032Speter					{
758038032Speter						*dp++ = *sp;
758138032Speter					}
758290792Sgshapiro					else switch (*dp++ = *sp)
758338032Speter					{
758490792Sgshapiro					  case '\\':
758590792Sgshapiro						bslashmode = true;
758638032Speter						break;
758738032Speter
758890792Sgshapiro					  case '(':
758938032Speter						cmntcnt++;
759038032Speter						break;
759138032Speter
759290792Sgshapiro					  case ')':
759338032Speter						cmntcnt--;
759438032Speter						break;
759538032Speter
759690792Sgshapiro					  case '<':
759738032Speter						anglecnt++;
759838032Speter						break;
759938032Speter
760090792Sgshapiro					  case '>':
760138032Speter						anglecnt--;
760238032Speter						break;
760338032Speter
760490792Sgshapiro					  case ' ':
760538032Speter						spacecnt++;
760638032Speter						break;
760738032Speter
760890792Sgshapiro					  case '"':
760938032Speter						quotemode = !quotemode;
761038032Speter						break;
761138032Speter					}
761238032Speter				}
761338032Speter			}
761438032Speter		}
761538032Speter		if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
761638032Speter		    bslashmode || spacecnt != 0)
761738032Speter		{
761864562Sgshapiro			sm_syslog(LOG_WARNING, NOQID,
761964562Sgshapiro				  "Warning: regex may cause prescan() failure map=%s lookup=%s",
762064562Sgshapiro				  map->map_mname, name);
762138032Speter			return NULL;
762238032Speter		}
762338032Speter
762438032Speter		*dp = '\0';
762538032Speter
762638032Speter		return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
762738032Speter	}
762838032Speter	return regex_map_rewrite(map, "", (size_t)0, av);
762938032Speter}
763038032Speter#endif /* MAP_REGEX */
763190792Sgshapiro/*
763264562Sgshapiro**  NSD modules
763364562Sgshapiro*/
763490792Sgshapiro#if MAP_NSD
763564562Sgshapiro
763664562Sgshapiro# include <ndbm.h>
763764562Sgshapiro# define _DATUM_DEFINED
763864562Sgshapiro# include <ns_api.h>
763964562Sgshapiro
764064562Sgshapirotypedef struct ns_map_list
764164562Sgshapiro{
764290792Sgshapiro	ns_map_t		*map;		/* XXX ns_ ? */
764390792Sgshapiro	char			*mapname;
764490792Sgshapiro	struct ns_map_list	*next;
764564562Sgshapiro} ns_map_list_t;
764664562Sgshapiro
764764562Sgshapirostatic ns_map_t *
764864562Sgshapirons_map_t_find(mapname)
764964562Sgshapiro	char *mapname;
765064562Sgshapiro{
765164562Sgshapiro	static ns_map_list_t *ns_maps = NULL;
765264562Sgshapiro	ns_map_list_t *ns_map;
765364562Sgshapiro
765464562Sgshapiro	/* walk the list of maps looking for the correctly named map */
765564562Sgshapiro	for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next)
765664562Sgshapiro	{
765764562Sgshapiro		if (strcmp(ns_map->mapname, mapname) == 0)
765864562Sgshapiro			break;
765964562Sgshapiro	}
766064562Sgshapiro
766164562Sgshapiro	/* if we are looking at a NULL ns_map_list_t, then create a new one */
766264562Sgshapiro	if (ns_map == NULL)
766364562Sgshapiro	{
7664168515Sgshapiro		ns_map = (ns_map_list_t *) xalloc(sizeof(*ns_map));
766564562Sgshapiro		ns_map->mapname = newstr(mapname);
7666168515Sgshapiro		ns_map->map = (ns_map_t *) xalloc(sizeof(*ns_map->map));
7667168515Sgshapiro		memset(ns_map->map, '\0', sizeof(*ns_map->map));
766864562Sgshapiro		ns_map->next = ns_maps;
766964562Sgshapiro		ns_maps = ns_map;
767064562Sgshapiro	}
767164562Sgshapiro	return ns_map->map;
767264562Sgshapiro}
767364562Sgshapiro
767464562Sgshapirochar *
767564562Sgshapironsd_map_lookup(map, name, av, statp)
767664562Sgshapiro	MAP *map;
767764562Sgshapiro	char *name;
767864562Sgshapiro	char **av;
767964562Sgshapiro	int *statp;
768064562Sgshapiro{
768171345Sgshapiro	int buflen, r;
768264562Sgshapiro	char *p;
768364562Sgshapiro	ns_map_t *ns_map;
768464562Sgshapiro	char keybuf[MAXNAME + 1];
768564562Sgshapiro	char buf[MAXLINE];
768664562Sgshapiro
768764562Sgshapiro	if (tTd(38, 20))
768890792Sgshapiro		sm_dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
768964562Sgshapiro
769064562Sgshapiro	buflen = strlen(name);
7691168515Sgshapiro	if (buflen > sizeof(keybuf) - 1)
7692168515Sgshapiro		buflen = sizeof(keybuf) - 1;	/* XXX simply cut off? */
769364562Sgshapiro	memmove(keybuf, name, buflen);
769464562Sgshapiro	keybuf[buflen] = '\0';
769564562Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
769664562Sgshapiro		makelower(keybuf);
769764562Sgshapiro
769864562Sgshapiro	ns_map = ns_map_t_find(map->map_file);
769964562Sgshapiro	if (ns_map == NULL)
770064562Sgshapiro	{
770164562Sgshapiro		if (tTd(38, 20))
770290792Sgshapiro			sm_dprintf("nsd_map_t_find failed\n");
770371345Sgshapiro		*statp = EX_UNAVAILABLE;
770464562Sgshapiro		return NULL;
770564562Sgshapiro	}
770698121Sgshapiro	r = ns_lookup(ns_map, NULL, map->map_file, keybuf, NULL,
7707168515Sgshapiro		      buf, sizeof(buf));
770871345Sgshapiro	if (r == NS_UNAVAIL || r == NS_TRYAGAIN)
770971345Sgshapiro	{
771071345Sgshapiro		*statp = EX_TEMPFAIL;
771164562Sgshapiro		return NULL;
771271345Sgshapiro	}
771377349Sgshapiro	if (r == NS_BADREQ
771477349Sgshapiro# ifdef NS_NOPERM
771577349Sgshapiro	    || r == NS_NOPERM
7716363466Sgshapiro# endif
771777349Sgshapiro	    )
771871345Sgshapiro	{
771971345Sgshapiro		*statp = EX_CONFIG;
772071345Sgshapiro		return NULL;
772171345Sgshapiro	}
772271345Sgshapiro	if (r != NS_SUCCESS)
772371345Sgshapiro	{
772471345Sgshapiro		*statp = EX_NOTFOUND;
772571345Sgshapiro		return NULL;
772671345Sgshapiro	}
772764562Sgshapiro
772871345Sgshapiro	*statp = EX_OK;
772971345Sgshapiro
773064562Sgshapiro	/* Null out trailing \n */
773164562Sgshapiro	if ((p = strchr(buf, '\n')) != NULL)
773264562Sgshapiro		*p = '\0';
773364562Sgshapiro
773464562Sgshapiro	return map_rewrite(map, buf, strlen(buf), av);
773564562Sgshapiro}
773664562Sgshapiro#endif /* MAP_NSD */
773764562Sgshapiro
773864562Sgshapirochar *
773964562Sgshapiroarith_map_lookup(map, name, av, statp)
774064562Sgshapiro	MAP *map;
774164562Sgshapiro	char *name;
774264562Sgshapiro	char **av;
774364562Sgshapiro	int *statp;
774464562Sgshapiro{
774564562Sgshapiro	long r;
774664562Sgshapiro	long v[2];
774790792Sgshapiro	bool res = false;
774864562Sgshapiro	bool boolres;
774964562Sgshapiro	static char result[16];
775064562Sgshapiro	char **cpp;
775164562Sgshapiro
775264562Sgshapiro	if (tTd(38, 2))
775364562Sgshapiro	{
775490792Sgshapiro		sm_dprintf("arith_map_lookup: key '%s'\n", name);
775564562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
775690792Sgshapiro			sm_dprintf("arith_map_lookup: arg '%s'\n", *cpp);
775764562Sgshapiro	}
775864562Sgshapiro	r = 0;
775990792Sgshapiro	boolres = false;
776064562Sgshapiro	cpp = av;
776164562Sgshapiro	*statp = EX_OK;
776264562Sgshapiro
776364562Sgshapiro	/*
776464562Sgshapiro	**  read arguments for arith map
776564562Sgshapiro	**  - no check is made whether they are really numbers
776664562Sgshapiro	**  - just ignores args after the second
776764562Sgshapiro	*/
776890792Sgshapiro
776964562Sgshapiro	for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
777064562Sgshapiro		v[r++] = strtol(*cpp, NULL, 0);
777164562Sgshapiro
777264562Sgshapiro	/* operator and (at least) two operands given? */
777364562Sgshapiro	if (name != NULL && r == 2)
777464562Sgshapiro	{
777590792Sgshapiro		switch (*name)
777664562Sgshapiro		{
777764562Sgshapiro		  case '|':
777864562Sgshapiro			r = v[0] | v[1];
777964562Sgshapiro			break;
778064562Sgshapiro
778164562Sgshapiro		  case '&':
778264562Sgshapiro			r = v[0] & v[1];
778364562Sgshapiro			break;
778464562Sgshapiro
778564562Sgshapiro		  case '%':
778664562Sgshapiro			if (v[1] == 0)
778764562Sgshapiro				return NULL;
778864562Sgshapiro			r = v[0] % v[1];
778964562Sgshapiro			break;
779064562Sgshapiro		  case '+':
779164562Sgshapiro			r = v[0] + v[1];
779264562Sgshapiro			break;
779364562Sgshapiro
779464562Sgshapiro		  case '-':
779564562Sgshapiro			r = v[0] - v[1];
779664562Sgshapiro			break;
779764562Sgshapiro
779864562Sgshapiro		  case '*':
779964562Sgshapiro			r = v[0] * v[1];
780064562Sgshapiro			break;
780164562Sgshapiro
780264562Sgshapiro		  case '/':
780364562Sgshapiro			if (v[1] == 0)
780464562Sgshapiro				return NULL;
780564562Sgshapiro			r = v[0] / v[1];
780664562Sgshapiro			break;
780764562Sgshapiro
780864562Sgshapiro		  case 'l':
780964562Sgshapiro			res = v[0] < v[1];
781090792Sgshapiro			boolres = true;
781164562Sgshapiro			break;
781264562Sgshapiro
781364562Sgshapiro		  case '=':
781464562Sgshapiro			res = v[0] == v[1];
781590792Sgshapiro			boolres = true;
781664562Sgshapiro			break;
781764562Sgshapiro
7818168515Sgshapiro		  case 'r':
7819168515Sgshapiro			r = v[1] - v[0] + 1;
7820168515Sgshapiro			if (r <= 0)
7821168515Sgshapiro				return NULL;
7822168515Sgshapiro			r = get_random() % r + v[0];
7823168515Sgshapiro			break;
7824168515Sgshapiro
782564562Sgshapiro		  default:
782664562Sgshapiro			/* XXX */
782764562Sgshapiro			*statp = EX_CONFIG;
782864562Sgshapiro			if (LogLevel > 10)
782964562Sgshapiro				sm_syslog(LOG_WARNING, NOQID,
783064562Sgshapiro					  "arith_map: unknown operator %c",
7831203004Sgshapiro					  (isascii(*name) && isprint(*name)) ?
7832203004Sgshapiro					  *name : '?');
783364562Sgshapiro			return NULL;
783464562Sgshapiro		}
783564562Sgshapiro		if (boolres)
7836168515Sgshapiro			(void) sm_snprintf(result, sizeof(result),
783790792Sgshapiro				res ? "TRUE" : "FALSE");
783864562Sgshapiro		else
7839168515Sgshapiro			(void) sm_snprintf(result, sizeof(result), "%ld", r);
784064562Sgshapiro		return result;
784164562Sgshapiro	}
784264562Sgshapiro	*statp = EX_CONFIG;
784364562Sgshapiro	return NULL;
784464562Sgshapiro}
7845132943Sgshapiro
7846261194Sgshapirochar *
7847261194Sgshapiroarpa_map_lookup(map, name, av, statp)
7848261194Sgshapiro	MAP *map;
7849261194Sgshapiro	char *name;
7850261194Sgshapiro	char **av;
7851261194Sgshapiro	int *statp;
7852261194Sgshapiro{
7853261194Sgshapiro	int r;
7854261194Sgshapiro	char *rval;
7855261194Sgshapiro	char result[128];	/* IPv6: 64 + 10 + 1 would be enough */
7856261194Sgshapiro
7857261194Sgshapiro	if (tTd(38, 2))
7858261194Sgshapiro		sm_dprintf("arpa_map_lookup: key '%s'\n", name);
7859261194Sgshapiro	*statp = EX_DATAERR;
7860261194Sgshapiro	r = 1;
7861261194Sgshapiro	memset(result, '\0', sizeof(result));
7862261194Sgshapiro	rval = NULL;
7863261194Sgshapiro
7864261194Sgshapiro# if NETINET6
7865261194Sgshapiro	if (sm_strncasecmp(name, "IPv6:", 5) == 0)
7866261194Sgshapiro	{
7867261194Sgshapiro		struct in6_addr in6_addr;
7868261194Sgshapiro
7869261194Sgshapiro		r = anynet_pton(AF_INET6, name, &in6_addr);
7870261194Sgshapiro		if (r == 1)
7871261194Sgshapiro		{
7872261194Sgshapiro			static char hex_digits[] =
7873261194Sgshapiro				{ '0', '1', '2', '3', '4', '5', '6', '7', '8',
7874261194Sgshapiro				  '9', 'a', 'b', 'c', 'd', 'e', 'f' };
7875261194Sgshapiro
7876261194Sgshapiro			unsigned char *src;
7877261194Sgshapiro			char *dst;
7878261194Sgshapiro			int i;
7879261194Sgshapiro
7880261194Sgshapiro			src = (unsigned char *) &in6_addr;
7881261194Sgshapiro			dst = result;
7882261194Sgshapiro			for (i = 15; i >= 0; i--) {
7883261194Sgshapiro				*dst++ = hex_digits[src[i] & 0x0f];
7884261194Sgshapiro				*dst++ = '.';
7885261194Sgshapiro				*dst++ = hex_digits[(src[i] >> 4) & 0x0f];
7886261194Sgshapiro				if (i > 0)
7887261194Sgshapiro					*dst++ = '.';
7888261194Sgshapiro			}
7889261194Sgshapiro			*statp = EX_OK;
7890261194Sgshapiro		}
7891261194Sgshapiro	}
7892261194Sgshapiro	else
7893261194Sgshapiro# endif /* NETINET6 */
7894261194Sgshapiro# if NETINET
7895261194Sgshapiro	{
7896261194Sgshapiro		struct in_addr in_addr;
7897261194Sgshapiro
7898285229Sgshapiro		r = inet_pton(AF_INET, name, &in_addr);
7899261194Sgshapiro		if (r == 1)
7900261194Sgshapiro		{
7901261194Sgshapiro			unsigned char *src;
7902261194Sgshapiro
7903261194Sgshapiro			src = (unsigned char *) &in_addr;
7904261194Sgshapiro			(void) snprintf(result, sizeof(result),
7905261194Sgshapiro				"%u.%u.%u.%u",
7906261194Sgshapiro				src[3], src[2], src[1], src[0]);
7907261194Sgshapiro			*statp = EX_OK;
7908261194Sgshapiro		}
7909261194Sgshapiro	}
7910261194Sgshapiro# endif /* NETINET */
7911261194Sgshapiro	if (r < 0)
7912261194Sgshapiro		*statp = EX_UNAVAILABLE;
7913261194Sgshapiro	if (tTd(38, 2))
7914261194Sgshapiro		sm_dprintf("arpa_map_lookup: r=%d, result='%s'\n", r, result);
7915261194Sgshapiro	if (*statp == EX_OK)
7916261194Sgshapiro	{
7917261194Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
7918261194Sgshapiro			rval = map_rewrite(map, name, strlen(name), NULL);
7919261194Sgshapiro		else
7920261194Sgshapiro			rval = map_rewrite(map, result, strlen(result), av);
7921261194Sgshapiro	}
7922261194Sgshapiro	return rval;
7923261194Sgshapiro}
7924261194Sgshapiro
7925363466Sgshapiro#if _FFR_SETDEBUG_MAP
7926363466Sgshapirochar *
7927363466Sgshapirosetdebug_map_lookup(map, name, av, statp)
7928363466Sgshapiro	MAP *map;
7929363466Sgshapiro	char *name;
7930363466Sgshapiro	char **av;
7931363466Sgshapiro	int *statp;
7932363466Sgshapiro{
7933363466Sgshapiro
7934363466Sgshapiro	if (tTd(38, 2))
7935363466Sgshapiro	{
7936363466Sgshapiro		char **cpp;
7937363466Sgshapiro
7938363466Sgshapiro		sm_dprintf("setdebug_map_lookup: key '%s'\n", name);
7939363466Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
7940363466Sgshapiro			sm_dprintf("setdebug_map_lookup: arg '%s'\n", *cpp);
7941363466Sgshapiro	}
7942363466Sgshapiro	*statp = EX_OK;
7943363466Sgshapiro	tTflag(name);
7944363466Sgshapiro	return NULL;
7945363466Sgshapiro}
7946363466Sgshapiro#endif
7947363466Sgshapiro
7948363466Sgshapiro#if _FFR_SETOPT_MAP
7949363466Sgshapirochar *
7950363466Sgshapirosetopt_map_lookup(map, name, av, statp)
7951363466Sgshapiro	MAP *map;
7952363466Sgshapiro	char *name;
7953363466Sgshapiro	char **av;
7954363466Sgshapiro	int *statp;
7955363466Sgshapiro{
7956363466Sgshapiro# if !_FFR_SETANYOPT
7957363466Sgshapiro	int val;
7958363466Sgshapiro# endif
7959363466Sgshapiro	char **cpp;
7960363466Sgshapiro
7961363466Sgshapiro	if (tTd(38, 2))
7962363466Sgshapiro	{
7963363466Sgshapiro		sm_dprintf("setopt_map_lookup: key '%s'\n", name);
7964363466Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
7965363466Sgshapiro			sm_dprintf("setopt_map_lookup: arg '%s'\n", *cpp);
7966363466Sgshapiro	}
7967363466Sgshapiro# if _FFR_SETANYOPT
7968363466Sgshapiro	/*
7969363466Sgshapiro	**  API screwed up...
7970363466Sgshapiro	**  first arg is the "short" name and second is the entire string...
7971363466Sgshapiro	*/
7972363466Sgshapiro
7973363466Sgshapiro	sm_dprintf("setoption: name=%s\n", name);
7974363466Sgshapiro	setoption(' ', name, true, false, CurEnv);
7975363466Sgshapiro	*statp = EX_OK;
7976363466Sgshapiro	return NULL;
7977363466Sgshapiro# else /* _FFR_SETANYOPT */
7978363466Sgshapiro	*statp = EX_CONFIG;
7979363466Sgshapiro
7980363466Sgshapiro	cpp = av;
7981363466Sgshapiro	if (cpp == NULL || ++cpp == NULL || *cpp == NULL)
7982363466Sgshapiro		return NULL;
7983363466Sgshapiro	*statp = EX_OK;
7984363466Sgshapiro	errno = 0;
7985363466Sgshapiro	val = strtol(*cpp, NULL, 0);
7986363466Sgshapiro	/* check for valid number? */
7987363466Sgshapiro
7988363466Sgshapiro	/* use a table? */
7989363466Sgshapiro	if (sm_strcasecmp(name, "LogLevel") == 0)
7990363466Sgshapiro	{
7991363466Sgshapiro		LogLevel = val;
7992363466Sgshapiro		sm_dprintf("LogLevel=%d\n", val);
7993363466Sgshapiro		return NULL;
7994363466Sgshapiro	}
7995363466Sgshapiro# endif /* _FFR_SETANYOPT */
7996363466Sgshapiro	*statp = EX_CONFIG;
7997363466Sgshapiro	return NULL;
7998363466Sgshapiro}
7999363466Sgshapiro#endif
8000363466Sgshapiro
8001363466Sgshapiro
8002132943Sgshapiro#if SOCKETMAP
8003132943Sgshapiro
8004132943Sgshapiro# if NETINET || NETINET6
8005132943Sgshapiro#  include <arpa/inet.h>
8006363466Sgshapiro# endif
8007132943Sgshapiro
8008132943Sgshapiro# define socket_map_next map_stack[0]
8009132943Sgshapiro
8010132943Sgshapiro/*
8011132943Sgshapiro**  SOCKET_MAP_OPEN -- open socket table
8012132943Sgshapiro*/
8013132943Sgshapiro
8014132943Sgshapirobool
8015132943Sgshapirosocket_map_open(map, mode)
8016132943Sgshapiro	MAP *map;
8017132943Sgshapiro	int mode;
8018132943Sgshapiro{
8019132943Sgshapiro	STAB *s;
8020132943Sgshapiro	int sock = 0;
8021285229Sgshapiro	int tmo;
8022132943Sgshapiro	SOCKADDR_LEN_T addrlen = 0;
8023132943Sgshapiro	int addrno = 0;
8024132943Sgshapiro	int save_errno;
8025132943Sgshapiro	char *p;
8026132943Sgshapiro	char *colon;
8027132943Sgshapiro	char *at;
8028132943Sgshapiro	struct hostent *hp = NULL;
8029132943Sgshapiro	SOCKADDR addr;
8030132943Sgshapiro
8031132943Sgshapiro	if (tTd(38, 2))
8032132943Sgshapiro		sm_dprintf("socket_map_open(%s, %s, %d)\n",
8033132943Sgshapiro			map->map_mname, map->map_file, mode);
8034132943Sgshapiro
8035132943Sgshapiro	mode &= O_ACCMODE;
8036132943Sgshapiro
8037132943Sgshapiro	/* sendmail doesn't have the ability to write to SOCKET (yet) */
8038132943Sgshapiro	if (mode != O_RDONLY)
8039132943Sgshapiro	{
8040132943Sgshapiro		/* issue a pseudo-error message */
8041132943Sgshapiro		errno = SM_EMAPCANTWRITE;
8042132943Sgshapiro		return false;
8043132943Sgshapiro	}
8044132943Sgshapiro
8045132943Sgshapiro	if (*map->map_file == '\0')
8046132943Sgshapiro	{
8047132943Sgshapiro		syserr("socket map \"%s\": empty or missing socket information",
8048132943Sgshapiro			map->map_mname);
8049132943Sgshapiro		return false;
8050132943Sgshapiro	}
8051132943Sgshapiro
8052132943Sgshapiro	s = socket_map_findconn(map->map_file);
8053132943Sgshapiro	if (s->s_socketmap != NULL)
8054132943Sgshapiro	{
8055132943Sgshapiro		/* Copy open connection */
8056132943Sgshapiro		map->map_db1 = s->s_socketmap->map_db1;
8057132943Sgshapiro
8058132943Sgshapiro		/* Add this map as head of linked list */
8059132943Sgshapiro		map->socket_map_next = s->s_socketmap;
8060132943Sgshapiro		s->s_socketmap = map;
8061132943Sgshapiro
8062132943Sgshapiro		if (tTd(38, 2))
8063132943Sgshapiro			sm_dprintf("using cached connection\n");
8064132943Sgshapiro		return true;
8065132943Sgshapiro	}
8066132943Sgshapiro
8067132943Sgshapiro	if (tTd(38, 2))
8068132943Sgshapiro		sm_dprintf("opening new connection\n");
8069132943Sgshapiro
8070132943Sgshapiro	/* following code is ripped from milter.c */
8071132943Sgshapiro	/* XXX It should be put in a library... */
8072132943Sgshapiro
8073132943Sgshapiro	/* protocol:filename or protocol:port@host */
8074168515Sgshapiro	memset(&addr, '\0', sizeof(addr));
8075132943Sgshapiro	p = map->map_file;
8076132943Sgshapiro	colon = strchr(p, ':');
8077132943Sgshapiro	if (colon != NULL)
8078132943Sgshapiro	{
8079132943Sgshapiro		*colon = '\0';
8080132943Sgshapiro
8081132943Sgshapiro		if (*p == '\0')
8082132943Sgshapiro		{
8083132943Sgshapiro# if NETUNIX
8084132943Sgshapiro			/* default to AF_UNIX */
8085132943Sgshapiro			addr.sa.sa_family = AF_UNIX;
8086132943Sgshapiro# else /* NETUNIX */
8087132943Sgshapiro#  if NETINET
8088132943Sgshapiro			/* default to AF_INET */
8089132943Sgshapiro			addr.sa.sa_family = AF_INET;
8090132943Sgshapiro#  else /* NETINET */
8091132943Sgshapiro#   if NETINET6
8092132943Sgshapiro			/* default to AF_INET6 */
8093132943Sgshapiro			addr.sa.sa_family = AF_INET6;
8094132943Sgshapiro#   else /* NETINET6 */
8095132943Sgshapiro			/* no protocols available */
8096132943Sgshapiro			syserr("socket map \"%s\": no valid socket protocols available",
8097132943Sgshapiro			map->map_mname);
8098132943Sgshapiro			return false;
8099132943Sgshapiro#   endif /* NETINET6 */
8100132943Sgshapiro#  endif /* NETINET */
8101132943Sgshapiro# endif /* NETUNIX */
8102132943Sgshapiro		}
8103132943Sgshapiro# if NETUNIX
8104132943Sgshapiro		else if (sm_strcasecmp(p, "unix") == 0 ||
8105132943Sgshapiro			 sm_strcasecmp(p, "local") == 0)
8106132943Sgshapiro			addr.sa.sa_family = AF_UNIX;
8107132943Sgshapiro# endif /* NETUNIX */
8108132943Sgshapiro# if NETINET
8109132943Sgshapiro		else if (sm_strcasecmp(p, "inet") == 0)
8110132943Sgshapiro			addr.sa.sa_family = AF_INET;
8111132943Sgshapiro# endif /* NETINET */
8112132943Sgshapiro# if NETINET6
8113132943Sgshapiro		else if (sm_strcasecmp(p, "inet6") == 0)
8114132943Sgshapiro			addr.sa.sa_family = AF_INET6;
8115132943Sgshapiro# endif /* NETINET6 */
8116132943Sgshapiro		else
8117132943Sgshapiro		{
8118132943Sgshapiro# ifdef EPROTONOSUPPORT
8119132943Sgshapiro			errno = EPROTONOSUPPORT;
8120363466Sgshapiro# else
8121132943Sgshapiro			errno = EINVAL;
8122132943Sgshapiro# endif /* EPROTONOSUPPORT */
8123132943Sgshapiro			syserr("socket map \"%s\": unknown socket type %s",
8124132943Sgshapiro			       map->map_mname, p);
8125132943Sgshapiro			return false;
8126132943Sgshapiro		}
8127132943Sgshapiro		*colon++ = ':';
8128132943Sgshapiro	}
8129132943Sgshapiro	else
8130132943Sgshapiro	{
8131132943Sgshapiro		colon = p;
8132132943Sgshapiro#if NETUNIX
8133132943Sgshapiro		/* default to AF_UNIX */
8134132943Sgshapiro		addr.sa.sa_family = AF_UNIX;
8135132943Sgshapiro#else /* NETUNIX */
8136132943Sgshapiro# if NETINET
8137132943Sgshapiro		/* default to AF_INET */
8138132943Sgshapiro		addr.sa.sa_family = AF_INET;
8139132943Sgshapiro# else /* NETINET */
8140132943Sgshapiro#  if NETINET6
8141132943Sgshapiro		/* default to AF_INET6 */
8142132943Sgshapiro		addr.sa.sa_family = AF_INET6;
8143132943Sgshapiro#  else /* NETINET6 */
8144132943Sgshapiro		syserr("socket map \"%s\": unknown socket type %s",
8145132943Sgshapiro		       map->map_mname, p);
8146132943Sgshapiro		return false;
8147132943Sgshapiro#  endif /* NETINET6 */
8148132943Sgshapiro# endif /* NETINET */
8149132943Sgshapiro#endif /* NETUNIX */
8150132943Sgshapiro	}
8151132943Sgshapiro
8152132943Sgshapiro# if NETUNIX
8153132943Sgshapiro	if (addr.sa.sa_family == AF_UNIX)
8154132943Sgshapiro	{
8155132943Sgshapiro		long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK;
8156132943Sgshapiro
8157132943Sgshapiro		at = colon;
8158168515Sgshapiro		if (strlen(colon) >= sizeof(addr.sunix.sun_path))
8159132943Sgshapiro		{
8160132943Sgshapiro			syserr("socket map \"%s\": local socket name %s too long",
8161132943Sgshapiro			       map->map_mname, colon);
8162132943Sgshapiro			return false;
8163132943Sgshapiro		}
8164132943Sgshapiro		errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
8165132943Sgshapiro				 S_IRUSR|S_IWUSR, NULL);
8166132943Sgshapiro
8167132943Sgshapiro		if (errno != 0)
8168132943Sgshapiro		{
8169132943Sgshapiro			/* if not safe, don't create */
8170132943Sgshapiro				syserr("socket map \"%s\": local socket name %s unsafe",
8171132943Sgshapiro			       map->map_mname, colon);
8172132943Sgshapiro			return false;
8173132943Sgshapiro		}
8174132943Sgshapiro
8175132943Sgshapiro		(void) sm_strlcpy(addr.sunix.sun_path, colon,
8176168515Sgshapiro			       sizeof(addr.sunix.sun_path));
8177168515Sgshapiro		addrlen = sizeof(struct sockaddr_un);
8178132943Sgshapiro	}
8179132943Sgshapiro	else
8180132943Sgshapiro# endif /* NETUNIX */
8181132943Sgshapiro# if NETINET || NETINET6
8182132943Sgshapiro	if (false
8183132943Sgshapiro#  if NETINET
8184132943Sgshapiro		 || addr.sa.sa_family == AF_INET
8185363466Sgshapiro#  endif
8186132943Sgshapiro#  if NETINET6
8187132943Sgshapiro		 || addr.sa.sa_family == AF_INET6
8188363466Sgshapiro#  endif
8189132943Sgshapiro		 )
8190132943Sgshapiro	{
8191132943Sgshapiro		unsigned short port;
8192132943Sgshapiro
8193132943Sgshapiro		/* Parse port@host */
8194132943Sgshapiro		at = strchr(colon, '@');
8195132943Sgshapiro		if (at == NULL)
8196132943Sgshapiro		{
8197132943Sgshapiro			syserr("socket map \"%s\": bad address %s (expected port@host)",
8198132943Sgshapiro				       map->map_mname, colon);
8199132943Sgshapiro			return false;
8200132943Sgshapiro		}
8201132943Sgshapiro		*at = '\0';
8202132943Sgshapiro		if (isascii(*colon) && isdigit(*colon))
8203132943Sgshapiro			port = htons((unsigned short) atoi(colon));
8204132943Sgshapiro		else
8205132943Sgshapiro		{
8206132943Sgshapiro#  ifdef NO_GETSERVBYNAME
8207132943Sgshapiro			syserr("socket map \"%s\": invalid port number %s",
8208132943Sgshapiro				       map->map_mname, colon);
8209132943Sgshapiro			return false;
8210132943Sgshapiro#  else /* NO_GETSERVBYNAME */
8211132943Sgshapiro			register struct servent *sp;
8212132943Sgshapiro
8213132943Sgshapiro			sp = getservbyname(colon, "tcp");
8214132943Sgshapiro			if (sp == NULL)
8215132943Sgshapiro			{
8216132943Sgshapiro				syserr("socket map \"%s\": unknown port name %s",
8217132943Sgshapiro					       map->map_mname, colon);
8218132943Sgshapiro				return false;
8219132943Sgshapiro			}
8220132943Sgshapiro			port = sp->s_port;
8221132943Sgshapiro#  endif /* NO_GETSERVBYNAME */
8222132943Sgshapiro		}
8223132943Sgshapiro		*at++ = '@';
8224132943Sgshapiro		if (*at == '[')
8225132943Sgshapiro		{
8226132943Sgshapiro			char *end;
8227132943Sgshapiro
8228132943Sgshapiro			end = strchr(at, ']');
8229132943Sgshapiro			if (end != NULL)
8230132943Sgshapiro			{
8231132943Sgshapiro				bool found = false;
8232132943Sgshapiro#  if NETINET
8233132943Sgshapiro				unsigned long hid = INADDR_NONE;
8234363466Sgshapiro#  endif
8235132943Sgshapiro#  if NETINET6
8236132943Sgshapiro				struct sockaddr_in6 hid6;
8237363466Sgshapiro#  endif
8238132943Sgshapiro
8239132943Sgshapiro				*end = '\0';
8240132943Sgshapiro#  if NETINET
8241132943Sgshapiro				if (addr.sa.sa_family == AF_INET &&
8242132943Sgshapiro				    (hid = inet_addr(&at[1])) != INADDR_NONE)
8243132943Sgshapiro				{
8244132943Sgshapiro					addr.sin.sin_addr.s_addr = hid;
8245132943Sgshapiro					addr.sin.sin_port = port;
8246132943Sgshapiro					found = true;
8247132943Sgshapiro				}
8248132943Sgshapiro#  endif /* NETINET */
8249132943Sgshapiro#  if NETINET6
8250168515Sgshapiro				(void) memset(&hid6, '\0', sizeof(hid6));
8251132943Sgshapiro				if (addr.sa.sa_family == AF_INET6 &&
8252132943Sgshapiro				    anynet_pton(AF_INET6, &at[1],
8253132943Sgshapiro						&hid6.sin6_addr) == 1)
8254132943Sgshapiro				{
8255132943Sgshapiro					addr.sin6.sin6_addr = hid6.sin6_addr;
8256132943Sgshapiro					addr.sin6.sin6_port = port;
8257132943Sgshapiro					found = true;
8258132943Sgshapiro				}
8259132943Sgshapiro#  endif /* NETINET6 */
8260132943Sgshapiro				*end = ']';
8261132943Sgshapiro				if (!found)
8262132943Sgshapiro				{
8263132943Sgshapiro					syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
8264132943Sgshapiro					       map->map_mname, at);
8265132943Sgshapiro					return false;
8266132943Sgshapiro				}
8267132943Sgshapiro			}
8268132943Sgshapiro			else
8269132943Sgshapiro			{
8270132943Sgshapiro				syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
8271132943Sgshapiro				       map->map_mname, at);
8272132943Sgshapiro				return false;
8273132943Sgshapiro			}
8274132943Sgshapiro		}
8275132943Sgshapiro		else
8276132943Sgshapiro		{
8277132943Sgshapiro			hp = sm_gethostbyname(at, addr.sa.sa_family);
8278132943Sgshapiro			if (hp == NULL)
8279132943Sgshapiro			{
8280132943Sgshapiro				syserr("socket map \"%s\": Unknown host name %s",
8281132943Sgshapiro					map->map_mname, at);
8282132943Sgshapiro				return false;
8283132943Sgshapiro			}
8284132943Sgshapiro			addr.sa.sa_family = hp->h_addrtype;
8285132943Sgshapiro			switch (hp->h_addrtype)
8286132943Sgshapiro			{
8287132943Sgshapiro#  if NETINET
8288132943Sgshapiro			  case AF_INET:
8289132943Sgshapiro				memmove(&addr.sin.sin_addr,
8290132943Sgshapiro					hp->h_addr, INADDRSZ);
8291132943Sgshapiro				addr.sin.sin_port = port;
8292168515Sgshapiro				addrlen = sizeof(struct sockaddr_in);
8293132943Sgshapiro				addrno = 1;
8294132943Sgshapiro				break;
8295132943Sgshapiro#  endif /* NETINET */
8296132943Sgshapiro
8297132943Sgshapiro#  if NETINET6
8298132943Sgshapiro			  case AF_INET6:
8299132943Sgshapiro				memmove(&addr.sin6.sin6_addr,
8300132943Sgshapiro					hp->h_addr, IN6ADDRSZ);
8301132943Sgshapiro				addr.sin6.sin6_port = port;
8302168515Sgshapiro				addrlen = sizeof(struct sockaddr_in6);
8303132943Sgshapiro				addrno = 1;
8304132943Sgshapiro				break;
8305132943Sgshapiro#  endif /* NETINET6 */
8306132943Sgshapiro
8307132943Sgshapiro			  default:
8308132943Sgshapiro				syserr("socket map \"%s\": Unknown protocol for %s (%d)",
8309132943Sgshapiro					map->map_mname, at, hp->h_addrtype);
8310132943Sgshapiro#  if NETINET6
8311132943Sgshapiro				freehostent(hp);
8312363466Sgshapiro#  endif
8313132943Sgshapiro				return false;
8314132943Sgshapiro			}
8315132943Sgshapiro		}
8316132943Sgshapiro	}
8317132943Sgshapiro	else
8318132943Sgshapiro# endif /* NETINET || NETINET6 */
8319132943Sgshapiro	{
8320132943Sgshapiro		syserr("socket map \"%s\": unknown socket protocol",
8321132943Sgshapiro			map->map_mname);
8322132943Sgshapiro		return false;
8323132943Sgshapiro	}
8324132943Sgshapiro
8325132943Sgshapiro	/* nope, actually connecting */
8326132943Sgshapiro	for (;;)
8327132943Sgshapiro	{
8328132943Sgshapiro		sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
8329132943Sgshapiro		if (sock < 0)
8330132943Sgshapiro		{
8331132943Sgshapiro			save_errno = errno;
8332132943Sgshapiro			if (tTd(38, 5))
8333132943Sgshapiro				sm_dprintf("socket map \"%s\": error creating socket: %s\n",
8334132943Sgshapiro					   map->map_mname,
8335132943Sgshapiro					   sm_errstring(save_errno));
8336132943Sgshapiro# if NETINET6
8337132943Sgshapiro			if (hp != NULL)
8338132943Sgshapiro				freehostent(hp);
8339132943Sgshapiro# endif /* NETINET6 */
8340132943Sgshapiro			return false;
8341132943Sgshapiro		}
8342132943Sgshapiro
8343132943Sgshapiro		if (connect(sock, (struct sockaddr *) &addr, addrlen) >= 0)
8344132943Sgshapiro			break;
8345132943Sgshapiro
8346132943Sgshapiro		/* couldn't connect.... try next address */
8347132943Sgshapiro		save_errno = errno;
8348132943Sgshapiro		p = CurHostName;
8349132943Sgshapiro		CurHostName = at;
8350132943Sgshapiro		if (tTd(38, 5))
8351132943Sgshapiro			sm_dprintf("socket_open (%s): open %s failed: %s\n",
8352132943Sgshapiro				map->map_mname, at, sm_errstring(save_errno));
8353132943Sgshapiro		CurHostName = p;
8354132943Sgshapiro		(void) close(sock);
8355132943Sgshapiro
8356132943Sgshapiro		/* try next address */
8357132943Sgshapiro		if (hp != NULL && hp->h_addr_list[addrno] != NULL)
8358132943Sgshapiro		{
8359132943Sgshapiro			switch (addr.sa.sa_family)
8360132943Sgshapiro			{
8361132943Sgshapiro# if NETINET
8362132943Sgshapiro			  case AF_INET:
8363132943Sgshapiro				memmove(&addr.sin.sin_addr,
8364132943Sgshapiro					hp->h_addr_list[addrno++],
8365132943Sgshapiro					INADDRSZ);
8366132943Sgshapiro				break;
8367132943Sgshapiro# endif /* NETINET */
8368132943Sgshapiro
8369132943Sgshapiro# if NETINET6
8370132943Sgshapiro			  case AF_INET6:
8371132943Sgshapiro				memmove(&addr.sin6.sin6_addr,
8372132943Sgshapiro					hp->h_addr_list[addrno++],
8373132943Sgshapiro					IN6ADDRSZ);
8374132943Sgshapiro				break;
8375132943Sgshapiro# endif /* NETINET6 */
8376132943Sgshapiro
8377132943Sgshapiro			  default:
8378132943Sgshapiro				if (tTd(38, 5))
8379132943Sgshapiro					sm_dprintf("socket map \"%s\": Unknown protocol for %s (%d)\n",
8380132943Sgshapiro						   map->map_mname, at,
8381132943Sgshapiro						   hp->h_addrtype);
8382132943Sgshapiro# if NETINET6
8383132943Sgshapiro				freehostent(hp);
8384363466Sgshapiro# endif
8385132943Sgshapiro				return false;
8386132943Sgshapiro			}
8387132943Sgshapiro			continue;
8388132943Sgshapiro		}
8389132943Sgshapiro		p = CurHostName;
8390132943Sgshapiro		CurHostName = at;
8391132943Sgshapiro		if (tTd(38, 5))
8392132943Sgshapiro			sm_dprintf("socket map \"%s\": error connecting to socket map: %s\n",
8393132943Sgshapiro				   map->map_mname, sm_errstring(save_errno));
8394132943Sgshapiro		CurHostName = p;
8395132943Sgshapiro# if NETINET6
8396132943Sgshapiro		if (hp != NULL)
8397132943Sgshapiro			freehostent(hp);
8398363466Sgshapiro# endif
8399132943Sgshapiro		return false;
8400132943Sgshapiro	}
8401132943Sgshapiro# if NETINET6
8402132943Sgshapiro	if (hp != NULL)
8403132943Sgshapiro	{
8404132943Sgshapiro		freehostent(hp);
8405132943Sgshapiro		hp = NULL;
8406132943Sgshapiro	}
8407132943Sgshapiro# endif /* NETINET6 */
8408132943Sgshapiro	if ((map->map_db1 = (ARBPTR_T) sm_io_open(SmFtStdiofd,
8409132943Sgshapiro						  SM_TIME_DEFAULT,
8410132943Sgshapiro						  (void *) &sock,
8411132943Sgshapiro						  SM_IO_RDWR,
8412132943Sgshapiro						  NULL)) == NULL)
8413132943Sgshapiro	{
8414132943Sgshapiro		close(sock);
8415132943Sgshapiro		if (tTd(38, 2))
8416132943Sgshapiro		    sm_dprintf("socket_open (%s): failed to create stream: %s\n",
8417132943Sgshapiro			       map->map_mname, sm_errstring(errno));
8418132943Sgshapiro		return false;
8419132943Sgshapiro	}
8420132943Sgshapiro
8421285229Sgshapiro	tmo = map->map_timeout;
8422285229Sgshapiro	if (tmo == 0)
8423285229Sgshapiro		tmo = 30000;	/* default: 30s */
8424285229Sgshapiro	else
8425285229Sgshapiro		tmo *= 1000;	/* s -> ms */
8426285229Sgshapiro	sm_io_setinfo(map->map_db1, SM_IO_WHAT_TIMEOUT, &tmo);
8427285229Sgshapiro
8428132943Sgshapiro	/* Save connection for reuse */
8429132943Sgshapiro	s->s_socketmap = map;
8430132943Sgshapiro	return true;
8431132943Sgshapiro}
8432132943Sgshapiro
8433132943Sgshapiro/*
8434132943Sgshapiro**  SOCKET_MAP_FINDCONN -- find a SOCKET connection to the server
8435132943Sgshapiro**
8436132943Sgshapiro**	Cache SOCKET connections based on the connection specifier
8437132943Sgshapiro**	and PID so we don't have multiple connections open to
8438132943Sgshapiro**	the same server for different maps.  Need a separate connection
8439132943Sgshapiro**	per PID since a parent process may close the map before the
8440132943Sgshapiro**	child is done with it.
8441132943Sgshapiro**
8442132943Sgshapiro**	Parameters:
8443132943Sgshapiro**		conn -- SOCKET map connection specifier
8444132943Sgshapiro**
8445132943Sgshapiro**	Returns:
8446132943Sgshapiro**		Symbol table entry for the SOCKET connection.
8447132943Sgshapiro*/
8448132943Sgshapiro
8449132943Sgshapirostatic STAB *
8450132943Sgshapirosocket_map_findconn(conn)
8451132943Sgshapiro	const char *conn;
8452132943Sgshapiro{
8453132943Sgshapiro	char *nbuf;
8454132943Sgshapiro	STAB *SM_NONVOLATILE s = NULL;
8455132943Sgshapiro
8456132943Sgshapiro	nbuf = sm_stringf_x("%s%c%d", conn, CONDELSE, (int) CurrentPid);
8457132943Sgshapiro	SM_TRY
8458132943Sgshapiro		s = stab(nbuf, ST_SOCKETMAP, ST_ENTER);
8459132943Sgshapiro	SM_FINALLY
8460132943Sgshapiro		sm_free(nbuf);
8461132943Sgshapiro	SM_END_TRY
8462132943Sgshapiro	return s;
8463132943Sgshapiro}
8464132943Sgshapiro
8465132943Sgshapiro/*
8466132943Sgshapiro**  SOCKET_MAP_CLOSE -- close the socket
8467132943Sgshapiro*/
8468132943Sgshapiro
8469132943Sgshapirovoid
8470132943Sgshapirosocket_map_close(map)
8471132943Sgshapiro	MAP *map;
8472132943Sgshapiro{
8473132943Sgshapiro	STAB *s;
8474132943Sgshapiro	MAP *smap;
8475132943Sgshapiro
8476132943Sgshapiro	if (tTd(38, 20))
8477132943Sgshapiro		sm_dprintf("socket_map_close(%s), pid=%ld\n", map->map_file,
8478132943Sgshapiro			(long) CurrentPid);
8479132943Sgshapiro
8480132943Sgshapiro	/* Check if already closed */
8481132943Sgshapiro	if (map->map_db1 == NULL)
8482132943Sgshapiro	{
8483132943Sgshapiro		if (tTd(38, 20))
8484132943Sgshapiro			sm_dprintf("socket_map_close(%s) already closed\n",
8485132943Sgshapiro				map->map_file);
8486132943Sgshapiro		return;
8487132943Sgshapiro	}
8488132943Sgshapiro	sm_io_close((SM_FILE_T *)map->map_db1, SM_TIME_DEFAULT);
8489132943Sgshapiro
8490132943Sgshapiro	/* Mark all the maps that share the connection as closed */
8491132943Sgshapiro	s = socket_map_findconn(map->map_file);
8492132943Sgshapiro	smap = s->s_socketmap;
8493132943Sgshapiro	while (smap != NULL)
8494132943Sgshapiro	{
8495132943Sgshapiro		MAP *next;
8496132943Sgshapiro
8497132943Sgshapiro		if (tTd(38, 2) && smap != map)
8498132943Sgshapiro			sm_dprintf("socket_map_close(%s): closed %s (shared SOCKET connection)\n",
8499132943Sgshapiro				map->map_mname, smap->map_mname);
8500132943Sgshapiro
8501132943Sgshapiro		smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
8502132943Sgshapiro		smap->map_db1 = NULL;
8503132943Sgshapiro		next = smap->socket_map_next;
8504132943Sgshapiro		smap->socket_map_next = NULL;
8505132943Sgshapiro		smap = next;
8506132943Sgshapiro	}
8507132943Sgshapiro	s->s_socketmap = NULL;
8508132943Sgshapiro}
8509132943Sgshapiro
8510132943Sgshapiro/*
8511132943Sgshapiro** SOCKET_MAP_LOOKUP -- look up a datum in a SOCKET table
8512132943Sgshapiro*/
8513132943Sgshapiro
8514132943Sgshapirochar *
8515132943Sgshapirosocket_map_lookup(map, name, av, statp)
8516132943Sgshapiro	MAP *map;
8517132943Sgshapiro	char *name;
8518132943Sgshapiro	char **av;
8519132943Sgshapiro	int *statp;
8520132943Sgshapiro{
8521132943Sgshapiro	unsigned int nettolen, replylen, recvlen;
8522363466Sgshapiro	int ret;
8523147078Sgshapiro	char *replybuf, *rval, *value, *status, *key;
8524132943Sgshapiro	SM_FILE_T *f;
8525147078Sgshapiro	char keybuf[MAXNAME + 1];
8526132943Sgshapiro
8527132943Sgshapiro	replybuf = NULL;
8528132943Sgshapiro	rval = NULL;
8529132943Sgshapiro	f = (SM_FILE_T *)map->map_db1;
8530132943Sgshapiro	if (tTd(38, 20))
8531132943Sgshapiro		sm_dprintf("socket_map_lookup(%s, %s) %s\n",
8532132943Sgshapiro			map->map_mname, name, map->map_file);
8533132943Sgshapiro
8534147078Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
8535147078Sgshapiro	{
8536147078Sgshapiro		nettolen = strlen(name);
8537168515Sgshapiro		if (nettolen > sizeof(keybuf) - 1)
8538168515Sgshapiro			nettolen = sizeof(keybuf) - 1;
8539147078Sgshapiro		memmove(keybuf, name, nettolen);
8540147078Sgshapiro		keybuf[nettolen] = '\0';
8541147078Sgshapiro		makelower(keybuf);
8542147078Sgshapiro		key = keybuf;
8543147078Sgshapiro	}
8544147078Sgshapiro	else
8545147078Sgshapiro		key = name;
8546147078Sgshapiro
8547147078Sgshapiro	nettolen = strlen(map->map_mname) + 1 + strlen(key);
8548132943Sgshapiro	SM_ASSERT(nettolen > strlen(map->map_mname));
8549147078Sgshapiro	SM_ASSERT(nettolen > strlen(key));
8550132943Sgshapiro	if ((sm_io_fprintf(f, SM_TIME_DEFAULT, "%u:%s %s,",
8551147078Sgshapiro			   nettolen, map->map_mname, key) == SM_IO_EOF) ||
8552132943Sgshapiro	    (sm_io_flush(f, SM_TIME_DEFAULT) != 0) ||
8553132943Sgshapiro	    (sm_io_error(f)))
8554132943Sgshapiro	{
8555132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): failed to send lookup request",
8556132943Sgshapiro			map->map_mname);
8557132943Sgshapiro		*statp = EX_TEMPFAIL;
8558132943Sgshapiro		goto errcl;
8559132943Sgshapiro	}
8560132943Sgshapiro
8561363466Sgshapiro	if ((ret = sm_io_fscanf(f, SM_TIME_DEFAULT, "%9u", &replylen)) != 1)
8562132943Sgshapiro	{
8563285229Sgshapiro		if (errno == EAGAIN)
8564285229Sgshapiro		{
8565285229Sgshapiro			syserr("451 4.3.0 socket_map_lookup(%s): read timeout",
8566285229Sgshapiro				map->map_mname);
8567285229Sgshapiro		}
8568363466Sgshapiro		else if (SM_IO_EOF == ret)
8569363466Sgshapiro		{
8570363466Sgshapiro			if (LogLevel > 9)
8571363466Sgshapiro				sm_syslog(LOG_INFO, CurEnv->e_id,
8572363466Sgshapiro					"socket_map_lookup(%s): EOF",
8573363466Sgshapiro					map->map_mname);
8574363466Sgshapiro		}
8575285229Sgshapiro		else
8576285229Sgshapiro		{
8577285229Sgshapiro			syserr("451 4.3.0 socket_map_lookup(%s): failed to read length parameter of reply %d",
8578285229Sgshapiro				map->map_mname, errno);
8579285229Sgshapiro		}
8580132943Sgshapiro		*statp = EX_TEMPFAIL;
8581132943Sgshapiro		goto errcl;
8582132943Sgshapiro	}
8583132943Sgshapiro	if (replylen > SOCKETMAP_MAXL)
8584132943Sgshapiro	{
8585132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): reply too long: %u",
8586132943Sgshapiro			   map->map_mname, replylen);
8587132943Sgshapiro		*statp = EX_TEMPFAIL;
8588132943Sgshapiro		goto errcl;
8589132943Sgshapiro	}
8590132943Sgshapiro	if (sm_io_getc(f, SM_TIME_DEFAULT) != ':')
8591132943Sgshapiro	{
8592132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): missing ':' in reply",
8593132943Sgshapiro			map->map_mname);
8594132943Sgshapiro		*statp = EX_TEMPFAIL;
8595132943Sgshapiro		goto error;
8596132943Sgshapiro	}
8597132943Sgshapiro
8598132943Sgshapiro	replybuf = (char *) sm_malloc(replylen + 1);
8599132943Sgshapiro	if (replybuf == NULL)
8600132943Sgshapiro	{
8601132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): can't allocate %u bytes",
8602132943Sgshapiro			map->map_mname, replylen + 1);
8603132943Sgshapiro		*statp = EX_OSERR;
8604132943Sgshapiro		goto error;
8605132943Sgshapiro	}
8606132943Sgshapiro
8607132943Sgshapiro	recvlen = sm_io_read(f, SM_TIME_DEFAULT, replybuf, replylen);
8608132943Sgshapiro	if (recvlen < replylen)
8609132943Sgshapiro	{
8610132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): received only %u of %u reply characters",
8611132943Sgshapiro			   map->map_mname, recvlen, replylen);
8612132943Sgshapiro		*statp = EX_TEMPFAIL;
8613132943Sgshapiro		goto errcl;
8614132943Sgshapiro	}
8615132943Sgshapiro	if (sm_io_getc(f, SM_TIME_DEFAULT) != ',')
8616132943Sgshapiro	{
8617132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): missing ',' in reply",
8618132943Sgshapiro			map->map_mname);
8619132943Sgshapiro		*statp = EX_TEMPFAIL;
8620132943Sgshapiro		goto errcl;
8621132943Sgshapiro	}
8622132943Sgshapiro	status = replybuf;
8623132943Sgshapiro	replybuf[recvlen] = '\0';
8624132943Sgshapiro	value = strchr(replybuf, ' ');
8625132943Sgshapiro	if (value != NULL)
8626132943Sgshapiro	{
8627132943Sgshapiro		*value = '\0';
8628132943Sgshapiro		value++;
8629132943Sgshapiro	}
8630132943Sgshapiro	if (strcmp(status, "OK") == 0)
8631132943Sgshapiro	{
8632132943Sgshapiro		*statp = EX_OK;
8633132943Sgshapiro
8634132943Sgshapiro		/* collect the return value */
8635132943Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
8636147078Sgshapiro			rval = map_rewrite(map, key, strlen(key), NULL);
8637132943Sgshapiro		else
8638132943Sgshapiro			rval = map_rewrite(map, value, strlen(value), av);
8639132943Sgshapiro	}
8640132943Sgshapiro	else if (strcmp(status, "NOTFOUND") == 0)
8641132943Sgshapiro	{
8642132943Sgshapiro		*statp = EX_NOTFOUND;
8643132943Sgshapiro		if (tTd(38, 20))
8644132943Sgshapiro			sm_dprintf("socket_map_lookup(%s): %s not found\n",
8645147078Sgshapiro				map->map_mname, key);
8646132943Sgshapiro	}
8647132943Sgshapiro	else
8648132943Sgshapiro	{
8649132943Sgshapiro		if (tTd(38, 5))
8650132943Sgshapiro			sm_dprintf("socket_map_lookup(%s, %s): server returned error: type=%s, reason=%s\n",
8651147078Sgshapiro				map->map_mname, key, status,
8652132943Sgshapiro				value ? value : "");
8653132943Sgshapiro		if ((strcmp(status, "TEMP") == 0) ||
8654132943Sgshapiro		    (strcmp(status, "TIMEOUT") == 0))
8655132943Sgshapiro			*statp = EX_TEMPFAIL;
8656132943Sgshapiro		else if(strcmp(status, "PERM") == 0)
8657132943Sgshapiro			*statp = EX_UNAVAILABLE;
8658132943Sgshapiro		else
8659132943Sgshapiro			*statp = EX_PROTOCOL;
8660132943Sgshapiro	}
8661132943Sgshapiro
8662132943Sgshapiro	if (replybuf != NULL)
8663132943Sgshapiro		sm_free(replybuf);
8664132943Sgshapiro	return rval;
8665132943Sgshapiro
8666132943Sgshapiro  errcl:
8667132943Sgshapiro	socket_map_close(map);
8668132943Sgshapiro  error:
8669132943Sgshapiro	if (replybuf != NULL)
8670132943Sgshapiro		sm_free(replybuf);
8671132943Sgshapiro	return rval;
8672132943Sgshapiro}
8673132943Sgshapiro#endif /* SOCKETMAP */
8674