map.c revision 120256
138032Speter/*
2120256Sgshapiro * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1992, 1995-1997 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1992, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1464562Sgshapiro#include <sendmail.h>
1538032Speter
16120256SgshapiroSM_RCSID("@(#)$Id: map.c,v 8.645.2.10 2003/07/24 18:24:17 ca Exp $")
1764562Sgshapiro
1890792Sgshapiro#if LDAPMAP
1990792Sgshapiro# include <sm/ldap.h>
2090792Sgshapiro#endif /* LDAPMAP */
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"
3364562Sgshapiro#endif /* NEWDB */
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 */
3964562Sgshapiro# endif /* NDBM */
4064562Sgshapiro#endif /* NIS */
4138032Speter
4290792Sgshapiro#if NEWDB
4364562Sgshapiro# if DB_VERSION_MAJOR < 2
4464562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
4564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
4664562Sgshapiro# if DB_VERSION_MAJOR == 2
4764562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
4864562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
4964562Sgshapiro# if DB_VERSION_MAJOR > 2
5064562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, void **));
5164562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
5264562Sgshapiro#endif /* NEWDB */
5373188Sgshapirostatic bool	extract_canonname __P((char *, char *, char *, char[], int));
5490792Sgshapirostatic void	map_close __P((STAB *, int));
5590792Sgshapirostatic void	map_init __P((STAB *, int));
5664562Sgshapiro#ifdef LDAPMAP
5790792Sgshapirostatic STAB *	ldapmap_findconn __P((SM_LDAP_STRUCT *));
5864562Sgshapiro#endif /* LDAPMAP */
5990792Sgshapiro#if NISPLUS
6064562Sgshapirostatic bool	nisplus_getcanonname __P((char *, int, int *));
6164562Sgshapiro#endif /* NISPLUS */
6290792Sgshapiro#if NIS
6364562Sgshapirostatic bool	nis_getcanonname __P((char *, int, int *));
6464562Sgshapiro#endif /* NIS */
6564562Sgshapiro#if NETINFO
6664562Sgshapirostatic bool	ni_getcanonname __P((char *, int, int *));
6764562Sgshapiro#endif /* NETINFO */
6864562Sgshapirostatic bool	text_getcanonname __P((char *, int, int *));
6964562Sgshapiro
7090792Sgshapiro/* default error message for trying to open a map in write mode */
7190792Sgshapiro#ifdef ENOSYS
7290792Sgshapiro# define SM_EMAPCANTWRITE	ENOSYS
7390792Sgshapiro#else /* ENOSYS */
7490792Sgshapiro# ifdef EFTYPE
7590792Sgshapiro#  define SM_EMAPCANTWRITE	EFTYPE
7690792Sgshapiro# else /* EFTYPE */
7790792Sgshapiro#  define SM_EMAPCANTWRITE	ENXIO
7890792Sgshapiro# endif /* EFTYPE */
7990792Sgshapiro#endif /* ENOSYS */
8090792Sgshapiro
8138032Speter/*
8238032Speter**  MAP.C -- implementations for various map classes.
8338032Speter**
8438032Speter**	Each map class implements a series of functions:
8538032Speter**
8638032Speter**	bool map_parse(MAP *map, char *args)
8790792Sgshapiro**		Parse the arguments from the config file.  Return true
8890792Sgshapiro**		if they were ok, false otherwise.  Fill in map with the
8938032Speter**		values.
9038032Speter**
9138032Speter**	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
9238032Speter**		Look up the key in the given map.  If found, do any
9338032Speter**		rewriting the map wants (including "args" if desired)
9438032Speter**		and return the value.  Set *pstat to the appropriate status
9538032Speter**		on error and return NULL.  Args will be NULL if called
9638032Speter**		from the alias routines, although this should probably
9738032Speter**		not be relied upon.  It is suggested you call map_rewrite
9838032Speter**		to return the results -- it takes care of null termination
9938032Speter**		and uses a dynamically expanded buffer as needed.
10038032Speter**
10138032Speter**	void map_store(MAP *map, char *key, char *value)
10238032Speter**		Store the key:value pair in the map.
10338032Speter**
10438032Speter**	bool map_open(MAP *map, int mode)
10538032Speter**		Open the map for the indicated mode.  Mode should
10690792Sgshapiro**		be either O_RDONLY or O_RDWR.  Return true if it
10790792Sgshapiro**		was opened successfully, false otherwise.  If the open
10890792Sgshapiro**		failed and the MF_OPTIONAL flag is not set, it should
10938032Speter**		also print an error.  If the MF_ALIAS bit is set
11038032Speter**		and this map class understands the @:@ convention, it
11138032Speter**		should call aliaswait() before returning.
11238032Speter**
11338032Speter**	void map_close(MAP *map)
11438032Speter**		Close the map.
11538032Speter**
11638032Speter**	This file also includes the implementation for getcanonname.
11738032Speter**	It is currently implemented in a pretty ad-hoc manner; it ought
11838032Speter**	to be more properly integrated into the map structure.
11938032Speter*/
12038032Speter
12138032Speter#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
12238032Speter# define LOCK_ON_OPEN	1	/* we can open/create a locked file */
12364562Sgshapiro#else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
12438032Speter# define LOCK_ON_OPEN	0	/* no such luck -- bend over backwards */
12564562Sgshapiro#endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
12638032Speter
12790792Sgshapiro/*
12838032Speter**  MAP_PARSEARGS -- parse config line arguments for database lookup
12938032Speter**
13038032Speter**	This is a generic version of the map_parse method.
13138032Speter**
13238032Speter**	Parameters:
13338032Speter**		map -- the map being initialized.
13438032Speter**		ap -- a pointer to the args on the config line.
13538032Speter**
13638032Speter**	Returns:
13790792Sgshapiro**		true -- if everything parsed OK.
13890792Sgshapiro**		false -- otherwise.
13938032Speter**
14038032Speter**	Side Effects:
14138032Speter**		null terminates the filename; stores it in map
14238032Speter*/
14338032Speter
14438032Speterbool
14538032Spetermap_parseargs(map, ap)
14638032Speter	MAP *map;
14738032Speter	char *ap;
14838032Speter{
14938032Speter	register char *p = ap;
15038032Speter
15164562Sgshapiro	/*
15290792Sgshapiro	**  There is no check whether there is really an argument,
15390792Sgshapiro	**  but that's not important enough to warrant extra code.
15464562Sgshapiro	*/
15590792Sgshapiro
15690792Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
15764562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
15838032Speter	for (;;)
15938032Speter	{
16038032Speter		while (isascii(*p) && isspace(*p))
16138032Speter			p++;
16238032Speter		if (*p != '-')
16338032Speter			break;
16438032Speter		switch (*++p)
16538032Speter		{
16638032Speter		  case 'N':
16738032Speter			map->map_mflags |= MF_INCLNULL;
16838032Speter			map->map_mflags &= ~MF_TRY0NULL;
16938032Speter			break;
17038032Speter
17138032Speter		  case 'O':
17238032Speter			map->map_mflags &= ~MF_TRY1NULL;
17338032Speter			break;
17438032Speter
17538032Speter		  case 'o':
17638032Speter			map->map_mflags |= MF_OPTIONAL;
17738032Speter			break;
17838032Speter
17938032Speter		  case 'f':
18038032Speter			map->map_mflags |= MF_NOFOLDCASE;
18138032Speter			break;
18238032Speter
18338032Speter		  case 'm':
18438032Speter			map->map_mflags |= MF_MATCHONLY;
18538032Speter			break;
18638032Speter
18738032Speter		  case 'A':
18838032Speter			map->map_mflags |= MF_APPEND;
18938032Speter			break;
19038032Speter
19138032Speter		  case 'q':
19238032Speter			map->map_mflags |= MF_KEEPQUOTES;
19338032Speter			break;
19438032Speter
19538032Speter		  case 'a':
19638032Speter			map->map_app = ++p;
19738032Speter			break;
19838032Speter
19938032Speter		  case 'T':
20038032Speter			map->map_tapp = ++p;
20138032Speter			break;
20238032Speter
20338032Speter		  case 'k':
20438032Speter			while (isascii(*++p) && isspace(*p))
20538032Speter				continue;
20638032Speter			map->map_keycolnm = p;
20738032Speter			break;
20838032Speter
20938032Speter		  case 'v':
21038032Speter			while (isascii(*++p) && isspace(*p))
21138032Speter				continue;
21238032Speter			map->map_valcolnm = p;
21338032Speter			break;
21438032Speter
21538032Speter		  case 'z':
21638032Speter			if (*++p != '\\')
21738032Speter				map->map_coldelim = *p;
21838032Speter			else
21938032Speter			{
22038032Speter				switch (*++p)
22138032Speter				{
22238032Speter				  case 'n':
22338032Speter					map->map_coldelim = '\n';
22438032Speter					break;
22538032Speter
22638032Speter				  case 't':
22738032Speter					map->map_coldelim = '\t';
22838032Speter					break;
22938032Speter
23038032Speter				  default:
23138032Speter					map->map_coldelim = '\\';
23238032Speter				}
23338032Speter			}
23438032Speter			break;
23538032Speter
23638032Speter		  case 't':
23738032Speter			map->map_mflags |= MF_NODEFER;
23838032Speter			break;
23938032Speter
24064562Sgshapiro
24164562Sgshapiro		  case 'S':
24264562Sgshapiro			map->map_spacesub = *++p;
24338032Speter			break;
24438032Speter
24564562Sgshapiro		  case 'D':
24664562Sgshapiro			map->map_mflags |= MF_DEFER;
24738032Speter			break;
24864562Sgshapiro
24964562Sgshapiro		  default:
25064562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
25164562Sgshapiro			break;
25238032Speter		}
25338032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
25438032Speter			p++;
25538032Speter		if (*p != '\0')
25638032Speter			*p++ = '\0';
25738032Speter	}
25838032Speter	if (map->map_app != NULL)
25938032Speter		map->map_app = newstr(map->map_app);
26038032Speter	if (map->map_tapp != NULL)
26138032Speter		map->map_tapp = newstr(map->map_tapp);
26238032Speter	if (map->map_keycolnm != NULL)
26338032Speter		map->map_keycolnm = newstr(map->map_keycolnm);
26438032Speter	if (map->map_valcolnm != NULL)
26538032Speter		map->map_valcolnm = newstr(map->map_valcolnm);
26638032Speter
26738032Speter	if (*p != '\0')
26838032Speter	{
26938032Speter		map->map_file = p;
27038032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
27138032Speter			p++;
27238032Speter		if (*p != '\0')
27338032Speter			*p++ = '\0';
27438032Speter		map->map_file = newstr(map->map_file);
27538032Speter	}
27638032Speter
27738032Speter	while (*p != '\0' && isascii(*p) && isspace(*p))
27838032Speter		p++;
27938032Speter	if (*p != '\0')
28038032Speter		map->map_rebuild = newstr(p);
28138032Speter
28238032Speter	if (map->map_file == NULL &&
28338032Speter	    !bitset(MCF_OPTFILE, map->map_class->map_cflags))
28438032Speter	{
28538032Speter		syserr("No file name for %s map %s",
28638032Speter			map->map_class->map_cname, map->map_mname);
28790792Sgshapiro		return false;
28838032Speter	}
28990792Sgshapiro	return true;
29038032Speter}
29190792Sgshapiro/*
29238032Speter**  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
29338032Speter**
29438032Speter**	It also adds the map_app string.  It can be used as a utility
29538032Speter**	in the map_lookup method.
29638032Speter**
29738032Speter**	Parameters:
29838032Speter**		map -- the map that causes this.
29938032Speter**		s -- the string to rewrite, NOT necessarily null terminated.
30038032Speter**		slen -- the length of s.
30138032Speter**		av -- arguments to interpolate into buf.
30238032Speter**
30338032Speter**	Returns:
30438032Speter**		Pointer to rewritten result.  This is static data that
30538032Speter**		should be copied if it is to be saved!
30638032Speter*/
30738032Speter
30838032Speterchar *
30938032Spetermap_rewrite(map, s, slen, av)
31038032Speter	register MAP *map;
31138032Speter	register const char *s;
31238032Speter	size_t slen;
31338032Speter	char **av;
31438032Speter{
31538032Speter	register char *bp;
31638032Speter	register char c;
31738032Speter	char **avp;
31838032Speter	register char *ap;
31938032Speter	size_t l;
32038032Speter	size_t len;
32138032Speter	static size_t buflen = 0;
32238032Speter	static char *buf = NULL;
32338032Speter
32438032Speter	if (tTd(39, 1))
32538032Speter	{
32690792Sgshapiro		sm_dprintf("map_rewrite(%.*s), av =", (int) slen, s);
32738032Speter		if (av == NULL)
32890792Sgshapiro			sm_dprintf(" (nullv)");
32938032Speter		else
33038032Speter		{
33138032Speter			for (avp = av; *avp != NULL; avp++)
33290792Sgshapiro				sm_dprintf("\n\t%s", *avp);
33338032Speter		}
33490792Sgshapiro		sm_dprintf("\n");
33538032Speter	}
33638032Speter
33738032Speter	/* count expected size of output (can safely overestimate) */
33838032Speter	l = len = slen;
33938032Speter	if (av != NULL)
34038032Speter	{
34138032Speter		const char *sp = s;
34238032Speter
34338032Speter		while (l-- > 0 && (c = *sp++) != '\0')
34438032Speter		{
34538032Speter			if (c != '%')
34638032Speter				continue;
34738032Speter			if (l-- <= 0)
34838032Speter				break;
34938032Speter			c = *sp++;
35038032Speter			if (!(isascii(c) && isdigit(c)))
35138032Speter				continue;
35238032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
35338032Speter				continue;
35438032Speter			if (*avp == NULL)
35538032Speter				continue;
35638032Speter			len += strlen(*avp);
35738032Speter		}
35838032Speter	}
35938032Speter	if (map->map_app != NULL)
36038032Speter		len += strlen(map->map_app);
36138032Speter	if (buflen < ++len)
36238032Speter	{
36338032Speter		/* need to malloc additional space */
36438032Speter		buflen = len;
36538032Speter		if (buf != NULL)
36677349Sgshapiro			sm_free(buf);
36790792Sgshapiro		buf = sm_pmalloc_x(buflen);
36838032Speter	}
36938032Speter
37038032Speter	bp = buf;
37138032Speter	if (av == NULL)
37238032Speter	{
37364562Sgshapiro		memmove(bp, s, slen);
37438032Speter		bp += slen;
37564562Sgshapiro
37664562Sgshapiro		/* assert(len > slen); */
37764562Sgshapiro		len -= slen;
37838032Speter	}
37938032Speter	else
38038032Speter	{
38138032Speter		while (slen-- > 0 && (c = *s++) != '\0')
38238032Speter		{
38338032Speter			if (c != '%')
38438032Speter			{
38538032Speter  pushc:
386120256Sgshapiro				if (len-- <= 1)
38790792Sgshapiro				     break;
38838032Speter				*bp++ = c;
38938032Speter				continue;
39038032Speter			}
39138032Speter			if (slen-- <= 0 || (c = *s++) == '\0')
39238032Speter				c = '%';
39338032Speter			if (c == '%')
39438032Speter				goto pushc;
39538032Speter			if (!(isascii(c) && isdigit(c)))
39638032Speter			{
397120256Sgshapiro				if (len-- <= 1)
398120256Sgshapiro				     break;
39938032Speter				*bp++ = '%';
40038032Speter				goto pushc;
40138032Speter			}
40238032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
40338032Speter				continue;
40438032Speter			if (*avp == NULL)
40538032Speter				continue;
40638032Speter
40738032Speter			/* transliterate argument into output string */
40864562Sgshapiro			for (ap = *avp; (c = *ap++) != '\0' && len > 0; --len)
40938032Speter				*bp++ = c;
41038032Speter		}
41138032Speter	}
41264562Sgshapiro	if (map->map_app != NULL && len > 0)
41390792Sgshapiro		(void) sm_strlcpy(bp, map->map_app, len);
41438032Speter	else
41538032Speter		*bp = '\0';
41638032Speter	if (tTd(39, 1))
41790792Sgshapiro		sm_dprintf("map_rewrite => %s\n", buf);
41838032Speter	return buf;
41938032Speter}
42090792Sgshapiro/*
42164562Sgshapiro**  INITMAPS -- rebuild alias maps
42238032Speter**
42338032Speter**	Parameters:
42464562Sgshapiro**		none.
42538032Speter**
42638032Speter**	Returns:
42738032Speter**		none.
42838032Speter*/
42938032Speter
43038032Spetervoid
43164562Sgshapiroinitmaps()
43238032Speter{
43338032Speter#if XDEBUG
43438032Speter	checkfd012("entering initmaps");
43564562Sgshapiro#endif /* XDEBUG */
43638032Speter	stabapply(map_init, 0);
43738032Speter#if XDEBUG
43838032Speter	checkfd012("exiting initmaps");
43964562Sgshapiro#endif /* XDEBUG */
44038032Speter}
44190792Sgshapiro/*
44264562Sgshapiro**  MAP_INIT -- rebuild a map
44364562Sgshapiro**
44464562Sgshapiro**	Parameters:
44564562Sgshapiro**		s -- STAB entry: if map: try to rebuild
44664562Sgshapiro**		unused -- unused variable
44764562Sgshapiro**
44864562Sgshapiro**	Returns:
44964562Sgshapiro**		none.
45064562Sgshapiro**
45164562Sgshapiro**	Side Effects:
45264562Sgshapiro**		will close already open rebuildable map.
45364562Sgshapiro*/
45438032Speter
45564562Sgshapiro/* ARGSUSED1 */
45664562Sgshapirostatic void
45764562Sgshapiromap_init(s, unused)
45838032Speter	register STAB *s;
45964562Sgshapiro	int unused;
46038032Speter{
46138032Speter	register MAP *map;
46238032Speter
46338032Speter	/* has to be a map */
46490792Sgshapiro	if (s->s_symtype != ST_MAP)
46538032Speter		return;
46638032Speter
46738032Speter	map = &s->s_map;
46838032Speter	if (!bitset(MF_VALID, map->map_mflags))
46938032Speter		return;
47038032Speter
47138032Speter	if (tTd(38, 2))
47290792Sgshapiro		sm_dprintf("map_init(%s:%s, %s)\n",
47338032Speter			map->map_class->map_cname == NULL ? "NULL" :
47438032Speter				map->map_class->map_cname,
47538032Speter			map->map_mname == NULL ? "NULL" : map->map_mname,
47664562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
47738032Speter
47864562Sgshapiro	if (!bitset(MF_ALIAS, map->map_mflags) ||
47964562Sgshapiro	    !bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
48038032Speter	{
48138032Speter		if (tTd(38, 3))
48290792Sgshapiro			sm_dprintf("\tnot rebuildable\n");
48338032Speter		return;
48438032Speter	}
48538032Speter
48638032Speter	/* if already open, close it (for nested open) */
48738032Speter	if (bitset(MF_OPEN, map->map_mflags))
48838032Speter	{
48977349Sgshapiro		map->map_mflags |= MF_CLOSING;
49038032Speter		map->map_class->map_close(map);
49177349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
49238032Speter	}
49338032Speter
49490792Sgshapiro	(void) rebuildaliases(map, false);
49564562Sgshapiro	return;
49664562Sgshapiro}
49790792Sgshapiro/*
49864562Sgshapiro**  OPENMAP -- open a map
49964562Sgshapiro**
50064562Sgshapiro**	Parameters:
50164562Sgshapiro**		map -- map to open (it must not be open).
50264562Sgshapiro**
50364562Sgshapiro**	Returns:
50464562Sgshapiro**		whether open succeeded.
50564562Sgshapiro*/
50664562Sgshapiro
50764562Sgshapirobool
50864562Sgshapiroopenmap(map)
50964562Sgshapiro	MAP *map;
51064562Sgshapiro{
51190792Sgshapiro	bool restore = false;
51264562Sgshapiro	bool savehold = HoldErrs;
51364562Sgshapiro	bool savequick = QuickAbort;
51464562Sgshapiro	int saveerrors = Errors;
51564562Sgshapiro
51664562Sgshapiro	if (!bitset(MF_VALID, map->map_mflags))
51790792Sgshapiro		return false;
51864562Sgshapiro
51964562Sgshapiro	/* better safe than sorry... */
52064562Sgshapiro	if (bitset(MF_OPEN, map->map_mflags))
52190792Sgshapiro		return true;
52264562Sgshapiro
52364562Sgshapiro	/* Don't send a map open error out via SMTP */
52464562Sgshapiro	if ((OnlyOneError || QuickAbort) &&
52564562Sgshapiro	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))
52638032Speter	{
52790792Sgshapiro		restore = true;
52890792Sgshapiro		HoldErrs = true;
52990792Sgshapiro		QuickAbort = false;
53038032Speter	}
53138032Speter
53264562Sgshapiro	errno = 0;
53338032Speter	if (map->map_class->map_open(map, O_RDONLY))
53438032Speter	{
53538032Speter		if (tTd(38, 4))
53690792Sgshapiro			sm_dprintf("openmap()\t%s:%s %s: valid\n",
53738032Speter				map->map_class->map_cname == NULL ? "NULL" :
53838032Speter					map->map_class->map_cname,
53938032Speter				map->map_mname == NULL ? "NULL" :
54038032Speter					map->map_mname,
54138032Speter				map->map_file == NULL ? "NULL" :
54238032Speter					map->map_file);
54338032Speter		map->map_mflags |= MF_OPEN;
54490792Sgshapiro		map->map_pid = CurrentPid;
54538032Speter	}
54638032Speter	else
54738032Speter	{
54838032Speter		if (tTd(38, 4))
54990792Sgshapiro			sm_dprintf("openmap()\t%s:%s %s: invalid%s%s\n",
55038032Speter				map->map_class->map_cname == NULL ? "NULL" :
55138032Speter					map->map_class->map_cname,
55238032Speter				map->map_mname == NULL ? "NULL" :
55338032Speter					map->map_mname,
55438032Speter				map->map_file == NULL ? "NULL" :
55538032Speter					map->map_file,
55664562Sgshapiro				errno == 0 ? "" : ": ",
55790792Sgshapiro				errno == 0 ? "" : sm_errstring(errno));
55838032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
55938032Speter		{
56038032Speter			extern MAPCLASS BogusMapClass;
56138032Speter
56290792Sgshapiro			map->map_orgclass = map->map_class;
56338032Speter			map->map_class = &BogusMapClass;
56490792Sgshapiro			map->map_mflags |= MF_OPEN|MF_OPENBOGUS;
56590792Sgshapiro			map->map_pid = CurrentPid;
56638032Speter		}
56764562Sgshapiro		else
56864562Sgshapiro		{
56964562Sgshapiro			/* don't try again */
57064562Sgshapiro			map->map_mflags &= ~MF_VALID;
57164562Sgshapiro		}
57238032Speter	}
57364562Sgshapiro
57464562Sgshapiro	if (restore)
57564562Sgshapiro	{
57664562Sgshapiro		Errors = saveerrors;
57764562Sgshapiro		HoldErrs = savehold;
57864562Sgshapiro		QuickAbort = savequick;
57964562Sgshapiro	}
58064562Sgshapiro
58164562Sgshapiro	return bitset(MF_OPEN, map->map_mflags);
58238032Speter}
58390792Sgshapiro/*
58442575Speter**  CLOSEMAPS -- close all open maps opened by the current pid.
58542575Speter**
58642575Speter**	Parameters:
58790792Sgshapiro**		bogus -- only close bogus maps.
58842575Speter**
58942575Speter**	Returns:
59042575Speter**		none.
59142575Speter*/
59242575Speter
59342575Spetervoid
59490792Sgshapiroclosemaps(bogus)
59590792Sgshapiro	bool bogus;
59642575Speter{
59790792Sgshapiro	stabapply(map_close, bogus);
59842575Speter}
59990792Sgshapiro/*
60064562Sgshapiro**  MAP_CLOSE -- close a map opened by the current pid.
60164562Sgshapiro**
60264562Sgshapiro**	Parameters:
60390792Sgshapiro**		s -- STAB entry: if map: try to close
60490792Sgshapiro**		bogus -- only close bogus maps or MCF_NOTPERSIST maps.
60564562Sgshapiro**
60664562Sgshapiro**	Returns:
60764562Sgshapiro**		none.
60864562Sgshapiro*/
60942575Speter
61042575Speter/* ARGSUSED1 */
61164562Sgshapirostatic void
61290792Sgshapiromap_close(s, bogus)
61342575Speter	register STAB *s;
61490792Sgshapiro	int bogus;	/* int because of stabapply(), used as bool */
61542575Speter{
61642575Speter	MAP *map;
61790792Sgshapiro	extern MAPCLASS BogusMapClass;
61842575Speter
61990792Sgshapiro	if (s->s_symtype != ST_MAP)
62042575Speter		return;
62164562Sgshapiro
62242575Speter	map = &s->s_map;
62342575Speter
62490792Sgshapiro	/*
62590792Sgshapiro	**  close the map iff:
62690792Sgshapiro	**  it is valid and open and opened by this process
62790792Sgshapiro	**  and (!bogus or it's a bogus map or it is not persistent)
62890792Sgshapiro	**  negate this: return iff
62990792Sgshapiro	**  it is not valid or it is not open or not opened by this process
63090792Sgshapiro	**  or (bogus and it's not a bogus map and it's not not-persistent)
63190792Sgshapiro	*/
63290792Sgshapiro
63342575Speter	if (!bitset(MF_VALID, map->map_mflags) ||
63442575Speter	    !bitset(MF_OPEN, map->map_mflags) ||
63577349Sgshapiro	    bitset(MF_CLOSING, map->map_mflags) ||
63690792Sgshapiro	    map->map_pid != CurrentPid ||
63790792Sgshapiro	    (bogus && map->map_class != &BogusMapClass &&
63890792Sgshapiro	     !bitset(MCF_NOTPERSIST, map->map_class->map_cflags)))
63942575Speter		return;
64064562Sgshapiro
64190792Sgshapiro	if (map->map_class == &BogusMapClass && map->map_orgclass != NULL &&
64290792Sgshapiro	    map->map_orgclass != &BogusMapClass)
64390792Sgshapiro		map->map_class = map->map_orgclass;
64442575Speter	if (tTd(38, 5))
64590792Sgshapiro		sm_dprintf("closemaps: closing %s (%s)\n",
64664562Sgshapiro			map->map_mname == NULL ? "NULL" : map->map_mname,
64764562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
64864562Sgshapiro
64990792Sgshapiro	if (!bitset(MF_OPENBOGUS, map->map_mflags))
65090792Sgshapiro	{
65190792Sgshapiro		map->map_mflags |= MF_CLOSING;
65290792Sgshapiro		map->map_class->map_close(map);
65390792Sgshapiro	}
65490792Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_OPENBOGUS|MF_CLOSING);
65542575Speter}
65690792Sgshapiro/*
65738032Speter**  GETCANONNAME -- look up name using service switch
65838032Speter**
65938032Speter**	Parameters:
66038032Speter**		host -- the host name to look up.
66138032Speter**		hbsize -- the size of the host buffer.
66238032Speter**		trymx -- if set, try MX records.
66390792Sgshapiro**		pttl -- pointer to return TTL (can be NULL).
66438032Speter**
66538032Speter**	Returns:
66690792Sgshapiro**		true -- if the host was found.
66790792Sgshapiro**		false -- otherwise.
66838032Speter*/
66938032Speter
67038032Speterbool
67190792Sgshapirogetcanonname(host, hbsize, trymx, pttl)
67238032Speter	char *host;
67338032Speter	int hbsize;
67438032Speter	bool trymx;
67590792Sgshapiro	int *pttl;
67638032Speter{
67738032Speter	int nmaps;
67838032Speter	int mapno;
67990792Sgshapiro	bool found = false;
68090792Sgshapiro	bool got_tempfail = false;
68164562Sgshapiro	auto int status;
68238032Speter	char *maptype[MAXMAPSTACK];
68338032Speter	short mapreturn[MAXMAPACTIONS];
68438032Speter
68538032Speter	nmaps = switch_map_find("hosts", maptype, mapreturn);
68690792Sgshapiro	if (pttl != 0)
68790792Sgshapiro		*pttl = SM_DEFAULT_TTL;
68838032Speter	for (mapno = 0; mapno < nmaps; mapno++)
68938032Speter	{
69038032Speter		int i;
69138032Speter
69238032Speter		if (tTd(38, 20))
69390792Sgshapiro			sm_dprintf("getcanonname(%s), trying %s\n",
69438032Speter				host, maptype[mapno]);
69538032Speter		if (strcmp("files", maptype[mapno]) == 0)
69638032Speter		{
69764562Sgshapiro			found = text_getcanonname(host, hbsize, &status);
69838032Speter		}
69990792Sgshapiro#if NIS
70038032Speter		else if (strcmp("nis", maptype[mapno]) == 0)
70138032Speter		{
70264562Sgshapiro			found = nis_getcanonname(host, hbsize, &status);
70338032Speter		}
70464562Sgshapiro#endif /* NIS */
70590792Sgshapiro#if NISPLUS
70638032Speter		else if (strcmp("nisplus", maptype[mapno]) == 0)
70738032Speter		{
70864562Sgshapiro			found = nisplus_getcanonname(host, hbsize, &status);
70938032Speter		}
71064562Sgshapiro#endif /* NISPLUS */
71138032Speter#if NAMED_BIND
71238032Speter		else if (strcmp("dns", maptype[mapno]) == 0)
71338032Speter		{
71490792Sgshapiro			found = dns_getcanonname(host, hbsize, trymx, &status,							 pttl);
71538032Speter		}
71664562Sgshapiro#endif /* NAMED_BIND */
71738032Speter#if NETINFO
71838032Speter		else if (strcmp("netinfo", maptype[mapno]) == 0)
71938032Speter		{
72064562Sgshapiro			found = ni_getcanonname(host, hbsize, &status);
72138032Speter		}
72264562Sgshapiro#endif /* NETINFO */
72338032Speter		else
72438032Speter		{
72590792Sgshapiro			found = false;
72664562Sgshapiro			status = EX_UNAVAILABLE;
72738032Speter		}
72838032Speter
72938032Speter		/*
73038032Speter		**  Heuristic: if $m is not set, we are running during system
73138032Speter		**  startup.  In this case, when a name is apparently found
73238032Speter		**  but has no dot, treat is as not found.  This avoids
73338032Speter		**  problems if /etc/hosts has no FQDN but is listed first
73438032Speter		**  in the service switch.
73538032Speter		*/
73638032Speter
73738032Speter		if (found &&
73838032Speter		    (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
73938032Speter			break;
74038032Speter
74138032Speter		/* see if we should continue */
74264562Sgshapiro		if (status == EX_TEMPFAIL)
74338032Speter		{
74438032Speter			i = MA_TRYAGAIN;
74590792Sgshapiro			got_tempfail = true;
74638032Speter		}
74764562Sgshapiro		else if (status == EX_NOTFOUND)
74838032Speter			i = MA_NOTFOUND;
74938032Speter		else
75038032Speter			i = MA_UNAVAIL;
75138032Speter		if (bitset(1 << mapno, mapreturn[i]))
75238032Speter			break;
75338032Speter	}
75438032Speter
75538032Speter	if (found)
75638032Speter	{
75738032Speter		char *d;
75838032Speter
75938032Speter		if (tTd(38, 20))
76090792Sgshapiro			sm_dprintf("getcanonname(%s), found\n", host);
76138032Speter
76238032Speter		/*
76338032Speter		**  If returned name is still single token, compensate
76438032Speter		**  by tagging on $m.  This is because some sites set
76538032Speter		**  up their DNS or NIS databases wrong.
76638032Speter		*/
76738032Speter
76838032Speter		if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
76938032Speter		{
77038032Speter			d = macvalue('m', CurEnv);
77138032Speter			if (d != NULL &&
77238032Speter			    hbsize > (int) (strlen(host) + strlen(d) + 1))
77338032Speter			{
77438032Speter				if (host[strlen(host) - 1] != '.')
77590792Sgshapiro					(void) sm_strlcat2(host, ".", d,
77690792Sgshapiro							   hbsize);
77790792Sgshapiro				else
77890792Sgshapiro					(void) sm_strlcat(host, d, hbsize);
77938032Speter			}
78038032Speter			else
78190792Sgshapiro				return false;
78238032Speter		}
78390792Sgshapiro		return true;
78438032Speter	}
78538032Speter
78638032Speter	if (tTd(38, 20))
78790792Sgshapiro		sm_dprintf("getcanonname(%s), failed, status=%d\n", host,
78890792Sgshapiro			status);
78938032Speter
79038032Speter	if (got_tempfail)
79173188Sgshapiro		SM_SET_H_ERRNO(TRY_AGAIN);
79238032Speter	else
79373188Sgshapiro		SM_SET_H_ERRNO(HOST_NOT_FOUND);
79490792Sgshapiro
79590792Sgshapiro	return false;
79638032Speter}
79790792Sgshapiro/*
79838032Speter**  EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
79938032Speter**
80038032Speter**	Parameters:
80138032Speter**		name -- the name against which to match.
80273188Sgshapiro**		dot -- where to reinsert '.' to get FQDN
80338032Speter**		line -- the /etc/hosts line.
80438032Speter**		cbuf -- the location to store the result.
80538032Speter**		cbuflen -- the size of cbuf.
80638032Speter**
80738032Speter**	Returns:
80890792Sgshapiro**		true -- if the line matched the desired name.
80990792Sgshapiro**		false -- otherwise.
81038032Speter*/
81138032Speter
81264562Sgshapirostatic bool
81373188Sgshapiroextract_canonname(name, dot, line, cbuf, cbuflen)
81438032Speter	char *name;
81573188Sgshapiro	char *dot;
81638032Speter	char *line;
81738032Speter	char cbuf[];
81838032Speter	int cbuflen;
81938032Speter{
82038032Speter	int i;
82138032Speter	char *p;
82290792Sgshapiro	bool found = false;
82338032Speter
82438032Speter	cbuf[0] = '\0';
82538032Speter	if (line[0] == '#')
82690792Sgshapiro		return false;
82738032Speter
82838032Speter	for (i = 1; ; i++)
82938032Speter	{
83038032Speter		char nbuf[MAXNAME + 1];
83138032Speter
83238032Speter		p = get_column(line, i, '\0', nbuf, sizeof nbuf);
83338032Speter		if (p == NULL)
83438032Speter			break;
83538032Speter		if (*p == '\0')
83638032Speter			continue;
83738032Speter		if (cbuf[0] == '\0' ||
83838032Speter		    (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
83938032Speter		{
84090792Sgshapiro			(void) sm_strlcpy(cbuf, p, cbuflen);
84138032Speter		}
84290792Sgshapiro		if (sm_strcasecmp(name, p) == 0)
84390792Sgshapiro			found = true;
84473188Sgshapiro		else if (dot != NULL)
84573188Sgshapiro		{
84673188Sgshapiro			/* try looking for the FQDN as well */
84773188Sgshapiro			*dot = '.';
84890792Sgshapiro			if (sm_strcasecmp(name, p) == 0)
84990792Sgshapiro				found = true;
85073188Sgshapiro			*dot = '\0';
85173188Sgshapiro		}
85238032Speter	}
85338032Speter	if (found && strchr(cbuf, '.') == NULL)
85438032Speter	{
85538032Speter		/* try to add a domain on the end of the name */
85638032Speter		char *domain = macvalue('m', CurEnv);
85738032Speter
85838032Speter		if (domain != NULL &&
85964562Sgshapiro		    strlen(domain) + (i = strlen(cbuf)) + 1 < (size_t) cbuflen)
86038032Speter		{
86164562Sgshapiro			p = &cbuf[i];
86238032Speter			*p++ = '.';
86390792Sgshapiro			(void) sm_strlcpy(p, domain, cbuflen - i - 1);
86438032Speter		}
86538032Speter	}
86638032Speter	return found;
86738032Speter}
86890792Sgshapiro
86990792Sgshapiro/*
87090792Sgshapiro**  DNS modules
87190792Sgshapiro*/
87290792Sgshapiro
87390792Sgshapiro#if NAMED_BIND
87490792Sgshapiro# if DNSMAP
87590792Sgshapiro
87690792Sgshapiro#  include "sm_resolve.h"
87790792Sgshapiro#  if NETINET || NETINET6
87890792Sgshapiro#   include <arpa/inet.h>
87990792Sgshapiro#  endif /* NETINET || NETINET6 */
88090792Sgshapiro
88190792Sgshapiro/*
88290792Sgshapiro**  DNS_MAP_OPEN -- stub to check proper value for dns map type
88390792Sgshapiro*/
88490792Sgshapiro
88590792Sgshapirobool
88690792Sgshapirodns_map_open(map, mode)
88790792Sgshapiro	MAP *map;
88890792Sgshapiro	int mode;
88990792Sgshapiro{
89090792Sgshapiro	if (tTd(38,2))
89190792Sgshapiro		sm_dprintf("dns_map_open(%s, %d)\n", map->map_mname, mode);
89290792Sgshapiro
89390792Sgshapiro	mode &= O_ACCMODE;
89490792Sgshapiro	if (mode != O_RDONLY)
89590792Sgshapiro	{
89690792Sgshapiro		/* issue a pseudo-error message */
89790792Sgshapiro		errno = SM_EMAPCANTWRITE;
89890792Sgshapiro		return false;
89990792Sgshapiro	}
90090792Sgshapiro	return true;
90190792Sgshapiro}
90290792Sgshapiro
90390792Sgshapiro/*
90490792Sgshapiro**  DNS_MAP_PARSEARGS -- parse dns map definition args.
90590792Sgshapiro**
90690792Sgshapiro**	Parameters:
90790792Sgshapiro**		map -- pointer to MAP
90890792Sgshapiro**		args -- pointer to the args on the config line.
90990792Sgshapiro**
91090792Sgshapiro**	Returns:
91190792Sgshapiro**		true -- if everything parsed OK.
91290792Sgshapiro**		false -- otherwise.
91390792Sgshapiro*/
91490792Sgshapiro
91590792Sgshapiro#  if _FFR_DNSMAP_MULTILIMIT
91690792Sgshapiro#   if !_FFR_DNSMAP_MULTI
91790792Sgshapiro  ERROR README:	You must define _FFR_DNSMAP_MULTI to use _FFR_DNSMAP_MULTILIMIT
91890792Sgshapiro#   endif /* ! _FFR_DNSMAP_MULTI */
91990792Sgshapiro#  endif /* _FFR_DNSMAP_MULTILIMIT */
92090792Sgshapiro
92190792Sgshapiro#  if _FFR_DNSMAP_MULTI
92290792Sgshapiro#   if _FFR_DNSMAP_MULTILIMIT
92390792Sgshapiro#    define map_sizelimit	map_lockfd	/* overload field */
92490792Sgshapiro#   endif /* _FFR_DNSMAP_MULTILIMIT */
92590792Sgshapiro#  endif /* _FFR_DNSMAP_MULTI */
92690792Sgshapiro
92790792Sgshapirostruct dns_map
92890792Sgshapiro{
92990792Sgshapiro	int dns_m_type;
93090792Sgshapiro};
93190792Sgshapiro
93290792Sgshapirobool
93390792Sgshapirodns_map_parseargs(map,args)
93490792Sgshapiro	MAP *map;
93590792Sgshapiro	char *args;
93690792Sgshapiro{
93790792Sgshapiro	register char *p = args;
93890792Sgshapiro	struct dns_map *map_p;
93990792Sgshapiro
94090792Sgshapiro	map_p = (struct dns_map *) xalloc(sizeof *map_p);
94190792Sgshapiro	map_p->dns_m_type = -1;
94290792Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
94390792Sgshapiro
94490792Sgshapiro	for (;;)
94590792Sgshapiro	{
94690792Sgshapiro		while (isascii(*p) && isspace(*p))
94790792Sgshapiro			p++;
94890792Sgshapiro		if (*p != '-')
94990792Sgshapiro			break;
95090792Sgshapiro		switch (*++p)
95190792Sgshapiro		{
95290792Sgshapiro		  case 'N':
95390792Sgshapiro			map->map_mflags |= MF_INCLNULL;
95490792Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
95590792Sgshapiro			break;
95690792Sgshapiro
95790792Sgshapiro		  case 'O':
95890792Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
95990792Sgshapiro			break;
96090792Sgshapiro
96190792Sgshapiro		  case 'o':
96290792Sgshapiro			map->map_mflags |= MF_OPTIONAL;
96390792Sgshapiro			break;
96490792Sgshapiro
96590792Sgshapiro		  case 'f':
96690792Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
96790792Sgshapiro			break;
96890792Sgshapiro
96990792Sgshapiro		  case 'm':
97090792Sgshapiro			map->map_mflags |= MF_MATCHONLY;
97190792Sgshapiro			break;
97290792Sgshapiro
97390792Sgshapiro		  case 'A':
97490792Sgshapiro			map->map_mflags |= MF_APPEND;
97590792Sgshapiro			break;
97690792Sgshapiro
97790792Sgshapiro		  case 'q':
97890792Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
97990792Sgshapiro			break;
98090792Sgshapiro
98190792Sgshapiro		  case 't':
98290792Sgshapiro			map->map_mflags |= MF_NODEFER;
98390792Sgshapiro			break;
98490792Sgshapiro
98590792Sgshapiro		  case 'a':
98690792Sgshapiro			map->map_app = ++p;
98790792Sgshapiro			break;
98890792Sgshapiro
98990792Sgshapiro		  case 'T':
99090792Sgshapiro			map->map_tapp = ++p;
99190792Sgshapiro			break;
99290792Sgshapiro
99390792Sgshapiro		  case 'd':
99490792Sgshapiro			{
99590792Sgshapiro				char *h;
99690792Sgshapiro
99790792Sgshapiro				++p;
99890792Sgshapiro				h = strchr(p, ' ');
99990792Sgshapiro				if (h != NULL)
100090792Sgshapiro					*h = '\0';
100190792Sgshapiro				map->map_timeout = convtime(p, 's');
100290792Sgshapiro				if (h != NULL)
100390792Sgshapiro					*h = ' ';
100490792Sgshapiro			}
100590792Sgshapiro			break;
100690792Sgshapiro
100790792Sgshapiro		  case 'r':
100890792Sgshapiro			while (isascii(*++p) && isspace(*p))
100990792Sgshapiro				continue;
101090792Sgshapiro			map->map_retry = atoi(p);
101190792Sgshapiro			break;
101290792Sgshapiro
101390792Sgshapiro#  if _FFR_DNSMAP_MULTI
101490792Sgshapiro		  case 'z':
101590792Sgshapiro			if (*++p != '\\')
101690792Sgshapiro				map->map_coldelim = *p;
101790792Sgshapiro			else
101890792Sgshapiro			{
101990792Sgshapiro				switch (*++p)
102090792Sgshapiro				{
102190792Sgshapiro				  case 'n':
102290792Sgshapiro					map->map_coldelim = '\n';
102390792Sgshapiro					break;
102490792Sgshapiro
102590792Sgshapiro				  case 't':
102690792Sgshapiro					map->map_coldelim = '\t';
102790792Sgshapiro					break;
102890792Sgshapiro
102990792Sgshapiro				  default:
103090792Sgshapiro					map->map_coldelim = '\\';
103190792Sgshapiro				}
103290792Sgshapiro			}
103390792Sgshapiro			break;
103490792Sgshapiro
103590792Sgshapiro#   if _FFR_DNSMAP_MULTILIMIT
103690792Sgshapiro		  case 'Z':
103790792Sgshapiro			while (isascii(*++p) && isspace(*p))
103890792Sgshapiro				continue;
103990792Sgshapiro			map->map_sizelimit = atoi(p);
104090792Sgshapiro			break;
104190792Sgshapiro#   endif /* _FFR_DNSMAP_MULTILIMIT */
104290792Sgshapiro#  endif /* _FFR_DNSMAP_MULTI */
104390792Sgshapiro
104490792Sgshapiro			/* Start of dns_map specific args */
104590792Sgshapiro		  case 'R':		/* search field */
104690792Sgshapiro			{
104790792Sgshapiro				char *h;
104890792Sgshapiro
104990792Sgshapiro				while (isascii(*++p) && isspace(*p))
105090792Sgshapiro					continue;
105190792Sgshapiro				h = strchr(p, ' ');
105290792Sgshapiro				if (h != NULL)
105390792Sgshapiro					*h = '\0';
105490792Sgshapiro				map_p->dns_m_type = dns_string_to_type(p);
105590792Sgshapiro				if (h != NULL)
105690792Sgshapiro					*h = ' ';
105790792Sgshapiro				if (map_p->dns_m_type < 0)
105890792Sgshapiro					syserr("dns map %s: wrong type %s",
105990792Sgshapiro						map->map_mname, p);
106090792Sgshapiro			}
106190792Sgshapiro			break;
106290792Sgshapiro
106390792Sgshapiro#  if _FFR_DNSMAP_BASE
106490792Sgshapiro		  case 'B':		/* base domain */
106590792Sgshapiro			{
106690792Sgshapiro				char *h;
106790792Sgshapiro
106890792Sgshapiro				while (isascii(*++p) && isspace(*p))
106990792Sgshapiro					continue;
107090792Sgshapiro				h = strchr(p, ' ');
107190792Sgshapiro				if (h != NULL)
107290792Sgshapiro					*h = '\0';
107390792Sgshapiro
107490792Sgshapiro				/*
107590792Sgshapiro				**  slight abuse of map->map_file; it isn't
107690792Sgshapiro				**	used otherwise in this map type.
107790792Sgshapiro				*/
107890792Sgshapiro
107990792Sgshapiro				map->map_file = newstr(p);
108090792Sgshapiro				if (h != NULL)
108190792Sgshapiro					*h = ' ';
108290792Sgshapiro			}
108390792Sgshapiro			break;
108490792Sgshapiro#  endif /* _FFR_DNSMAP_BASE */
108590792Sgshapiro
108690792Sgshapiro		}
108790792Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
108890792Sgshapiro			p++;
108990792Sgshapiro		if (*p != '\0')
109090792Sgshapiro			*p++ = '\0';
109190792Sgshapiro	}
109290792Sgshapiro	if (map_p->dns_m_type < 0)
109390792Sgshapiro		syserr("dns map %s: missing -R type", map->map_mname);
109490792Sgshapiro	if (map->map_app != NULL)
109590792Sgshapiro		map->map_app = newstr(map->map_app);
109690792Sgshapiro	if (map->map_tapp != NULL)
109790792Sgshapiro		map->map_tapp = newstr(map->map_tapp);
109890792Sgshapiro
109990792Sgshapiro	/*
110090792Sgshapiro	**  Assumption: assert(sizeof int <= sizeof(ARBPTR_T));
110190792Sgshapiro	**  Even if this assumption is wrong, we use only one byte,
110290792Sgshapiro	**  so it doesn't really matter.
110390792Sgshapiro	*/
110490792Sgshapiro
110590792Sgshapiro	map->map_db1 = (ARBPTR_T) map_p;
110690792Sgshapiro	return true;
110790792Sgshapiro}
110890792Sgshapiro
110990792Sgshapiro/*
111090792Sgshapiro**  DNS_MAP_LOOKUP -- perform dns map lookup.
111190792Sgshapiro**
111290792Sgshapiro**	Parameters:
111390792Sgshapiro**		map -- pointer to MAP
111490792Sgshapiro**		name -- name to lookup
111590792Sgshapiro**		av -- arguments to interpolate into buf.
111690792Sgshapiro**		statp -- pointer to status (EX_)
111790792Sgshapiro**
111890792Sgshapiro**	Returns:
111990792Sgshapiro**		result of lookup if succeeded.
112090792Sgshapiro**		NULL -- otherwise.
112190792Sgshapiro*/
112290792Sgshapiro
112390792Sgshapirochar *
112490792Sgshapirodns_map_lookup(map, name, av, statp)
112590792Sgshapiro	MAP *map;
112690792Sgshapiro	char *name;
112790792Sgshapiro	char **av;
112890792Sgshapiro	int *statp;
112990792Sgshapiro{
113090792Sgshapiro#  if _FFR_DNSMAP_MULTI
113190792Sgshapiro#   if _FFR_DNSMAP_MULTILIMIT
113290792Sgshapiro	int resnum = 0;
113390792Sgshapiro#   endif /* _FFR_DNSMAP_MULTILIMIT */
113490792Sgshapiro#  endif /* _FFR_DNSMAP_MULTI */
113590792Sgshapiro	char *vp = NULL, *result = NULL;
113690792Sgshapiro	size_t vsize;
113790792Sgshapiro	struct dns_map *map_p;
113890792Sgshapiro	RESOURCE_RECORD_T *rr = NULL;
113990792Sgshapiro	DNS_REPLY_T *r = NULL;
114090792Sgshapiro#  if NETINET6
114190792Sgshapiro	static char buf6[INET6_ADDRSTRLEN];
114290792Sgshapiro#  endif /* NETINET6 */
114390792Sgshapiro
114490792Sgshapiro	if (tTd(38, 20))
114590792Sgshapiro		sm_dprintf("dns_map_lookup(%s, %s)\n",
114690792Sgshapiro			   map->map_mname, name);
114790792Sgshapiro
114890792Sgshapiro	map_p = (struct dns_map *)(map->map_db1);
114990792Sgshapiro#  if _FFR_DNSMAP_BASE
115090792Sgshapiro	if (map->map_file != NULL && *map->map_file != '\0')
115190792Sgshapiro	{
115290792Sgshapiro		size_t len;
115390792Sgshapiro		char *appdomain;
115490792Sgshapiro
115590792Sgshapiro		len = strlen(map->map_file) + strlen(name) + 2;
115690792Sgshapiro		appdomain = (char *) sm_malloc(len);
115790792Sgshapiro		if (appdomain == NULL)
115890792Sgshapiro		{
115990792Sgshapiro			*statp = EX_UNAVAILABLE;
116090792Sgshapiro			return NULL;
116190792Sgshapiro		}
116290792Sgshapiro		(void) sm_strlcpyn(appdomain, len, 3, name, ".", map->map_file);
116390792Sgshapiro		r = dns_lookup_int(appdomain, C_IN, map_p->dns_m_type,
116490792Sgshapiro				   map->map_timeout, map->map_retry);
116590792Sgshapiro		sm_free(appdomain);
116690792Sgshapiro	}
116790792Sgshapiro	else
116890792Sgshapiro#  endif /* _FFR_DNSMAP_BASE */
116990792Sgshapiro	{
117090792Sgshapiro		r = dns_lookup_int(name, C_IN, map_p->dns_m_type,
117190792Sgshapiro				   map->map_timeout, map->map_retry);
117290792Sgshapiro	}
117390792Sgshapiro
117490792Sgshapiro	if (r == NULL)
117590792Sgshapiro	{
117690792Sgshapiro		result = NULL;
1177120256Sgshapiro		if (h_errno == TRY_AGAIN || transienterror(errno))
117890792Sgshapiro			*statp = EX_TEMPFAIL;
117990792Sgshapiro		else
118090792Sgshapiro			*statp = EX_NOTFOUND;
118190792Sgshapiro		goto cleanup;
118290792Sgshapiro	}
118390792Sgshapiro	*statp = EX_OK;
118490792Sgshapiro	for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next)
118590792Sgshapiro	{
118690792Sgshapiro		char *type = NULL;
118790792Sgshapiro		char *value = NULL;
118890792Sgshapiro
118990792Sgshapiro		switch (rr->rr_type)
119090792Sgshapiro		{
119190792Sgshapiro		  case T_NS:
119290792Sgshapiro			type = "T_NS";
119390792Sgshapiro			value = rr->rr_u.rr_txt;
119490792Sgshapiro			break;
119590792Sgshapiro		  case T_CNAME:
119690792Sgshapiro			type = "T_CNAME";
119790792Sgshapiro			value = rr->rr_u.rr_txt;
119890792Sgshapiro			break;
119990792Sgshapiro		  case T_AFSDB:
120090792Sgshapiro			type = "T_AFSDB";
120190792Sgshapiro			value = rr->rr_u.rr_mx->mx_r_domain;
120290792Sgshapiro			break;
120390792Sgshapiro		  case T_SRV:
120490792Sgshapiro			type = "T_SRV";
120590792Sgshapiro			value = rr->rr_u.rr_srv->srv_r_target;
120690792Sgshapiro			break;
120790792Sgshapiro		  case T_PTR:
120890792Sgshapiro			type = "T_PTR";
120990792Sgshapiro			value = rr->rr_u.rr_txt;
121090792Sgshapiro			break;
121190792Sgshapiro		  case T_TXT:
121290792Sgshapiro			type = "T_TXT";
121390792Sgshapiro			value = rr->rr_u.rr_txt;
121490792Sgshapiro			break;
121590792Sgshapiro		  case T_MX:
121690792Sgshapiro			type = "T_MX";
121790792Sgshapiro			value = rr->rr_u.rr_mx->mx_r_domain;
121890792Sgshapiro			break;
121990792Sgshapiro#  if NETINET
122090792Sgshapiro		  case T_A:
122190792Sgshapiro			type = "T_A";
122290792Sgshapiro			value = inet_ntoa(*(rr->rr_u.rr_a));
122390792Sgshapiro			break;
122490792Sgshapiro#  endif /* NETINET */
122590792Sgshapiro#  if NETINET6
122690792Sgshapiro		  case T_AAAA:
122790792Sgshapiro			type = "T_AAAA";
122890792Sgshapiro			value = anynet_ntop(rr->rr_u.rr_aaaa, buf6,
122990792Sgshapiro					    sizeof buf6);
123090792Sgshapiro			break;
123190792Sgshapiro#  endif /* NETINET6 */
123290792Sgshapiro		}
123390792Sgshapiro
123498841Sgshapiro		(void) strreplnonprt(value, 'X');
123590792Sgshapiro		if (map_p->dns_m_type != rr->rr_type)
123690792Sgshapiro		{
123790792Sgshapiro			if (tTd(38, 40))
123890792Sgshapiro				sm_dprintf("\tskipping type %s (%d) value %s\n",
123990792Sgshapiro					   type != NULL ? type : "<UNKNOWN>",
124090792Sgshapiro					   rr->rr_type,
124190792Sgshapiro					   value != NULL ? value : "<NO VALUE>");
124290792Sgshapiro			continue;
124390792Sgshapiro		}
124490792Sgshapiro
124590792Sgshapiro#  if NETINET6
124690792Sgshapiro		if (rr->rr_type == T_AAAA && value == NULL)
124790792Sgshapiro		{
124890792Sgshapiro			result = NULL;
124990792Sgshapiro			*statp = EX_DATAERR;
125090792Sgshapiro			if (tTd(38, 40))
125190792Sgshapiro				sm_dprintf("\tbad T_AAAA conversion\n");
125290792Sgshapiro			goto cleanup;
125390792Sgshapiro		}
125490792Sgshapiro#  endif /* NETINET6 */
125590792Sgshapiro		if (tTd(38, 40))
125690792Sgshapiro			sm_dprintf("\tfound type %s (%d) value %s\n",
125790792Sgshapiro				   type != NULL ? type : "<UNKNOWN>",
125890792Sgshapiro				   rr->rr_type,
125990792Sgshapiro				   value != NULL ? value : "<NO VALUE>");
126090792Sgshapiro#  if _FFR_DNSMAP_MULTI
126190792Sgshapiro		if (value != NULL &&
126290792Sgshapiro		    (map->map_coldelim == '\0' ||
126390792Sgshapiro#   if _FFR_DNSMAP_MULTILIMIT
126490792Sgshapiro		     map->map_sizelimit == 1 ||
126590792Sgshapiro#   endif /* _FFR_DNSMAP_MULTILIMIT */
126690792Sgshapiro		     bitset(MF_MATCHONLY, map->map_mflags)))
126790792Sgshapiro		{
126890792Sgshapiro			/* Only care about the first match */
126990792Sgshapiro			vp = newstr(value);
127090792Sgshapiro			break;
127190792Sgshapiro		}
127290792Sgshapiro		else if (vp == NULL)
127390792Sgshapiro		{
127490792Sgshapiro			/* First result */
127590792Sgshapiro			vp = newstr(value);
127690792Sgshapiro		}
127790792Sgshapiro		else
127890792Sgshapiro		{
127990792Sgshapiro			/* concatenate the results */
128090792Sgshapiro			int sz;
128190792Sgshapiro			char *new;
128290792Sgshapiro
128390792Sgshapiro			sz = strlen(vp) + strlen(value) + 2;
128490792Sgshapiro			new = xalloc(sz);
128590792Sgshapiro			(void) sm_snprintf(new, sz, "%s%c%s",
128690792Sgshapiro					   vp, map->map_coldelim, value);
128790792Sgshapiro			sm_free(vp);
128890792Sgshapiro			vp = new;
128990792Sgshapiro#   if _FFR_DNSMAP_MULTILIMIT
129090792Sgshapiro			if (map->map_sizelimit > 0 &&
129190792Sgshapiro			    ++resnum >= map->map_sizelimit)
129290792Sgshapiro				break;
129390792Sgshapiro#   endif /* _FFR_DNSMAP_MULTILIMIT */
129490792Sgshapiro		}
129590792Sgshapiro#  else /* _FFR_DNSMAP_MULTI */
129690792Sgshapiro		vp = value;
129790792Sgshapiro		break;
129890792Sgshapiro#  endif /* _FFR_DNSMAP_MULTI */
129990792Sgshapiro	}
130090792Sgshapiro	if (vp == NULL)
130190792Sgshapiro	{
130290792Sgshapiro		result = NULL;
130390792Sgshapiro		*statp = EX_NOTFOUND;
130490792Sgshapiro		if (tTd(38, 40))
130590792Sgshapiro			sm_dprintf("\tno match found\n");
130690792Sgshapiro		goto cleanup;
130790792Sgshapiro	}
130890792Sgshapiro
130990792Sgshapiro#  if _FFR_DNSMAP_MULTI
131090792Sgshapiro	/* Cleanly truncate for rulesets */
131190792Sgshapiro	truncate_at_delim(vp, PSBUFSIZE / 2, map->map_coldelim);
131290792Sgshapiro#  endif /* _FFR_DNSMAP_MULTI */
131390792Sgshapiro
131490792Sgshapiro	vsize = strlen(vp);
131590792Sgshapiro
131690792Sgshapiro	if (LogLevel > 9)
131790792Sgshapiro		sm_syslog(LOG_INFO, CurEnv->e_id, "dns %.100s => %s",
131890792Sgshapiro			  name, vp);
131990792Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
132090792Sgshapiro		result = map_rewrite(map, name, strlen(name), NULL);
132190792Sgshapiro	else
132290792Sgshapiro		result = map_rewrite(map, vp, vsize, av);
132390792Sgshapiro
132490792Sgshapiro  cleanup:
132590792Sgshapiro#  if _FFR_DNSMAP_MULTI
132690792Sgshapiro	if (vp != NULL)
132790792Sgshapiro		sm_free(vp);
132890792Sgshapiro#  endif /* _FFR_DNSMAP_MULTI */
132990792Sgshapiro	if (r != NULL)
133090792Sgshapiro		dns_free_data(r);
133190792Sgshapiro	return result;
133290792Sgshapiro}
133390792Sgshapiro# endif /* DNSMAP */
133490792Sgshapiro#endif /* NAMED_BIND */
133590792Sgshapiro
133690792Sgshapiro/*
133738032Speter**  NDBM modules
133838032Speter*/
133938032Speter
134090792Sgshapiro#if NDBM
134138032Speter
134238032Speter/*
134338032Speter**  NDBM_MAP_OPEN -- DBM-style map open
134438032Speter*/
134538032Speter
134638032Speterbool
134738032Speterndbm_map_open(map, mode)
134838032Speter	MAP *map;
134938032Speter	int mode;
135038032Speter{
135138032Speter	register DBM *dbm;
135264562Sgshapiro	int save_errno;
135338032Speter	int dfd;
135438032Speter	int pfd;
135564562Sgshapiro	long sff;
135638032Speter	int ret;
135738032Speter	int smode = S_IREAD;
135898121Sgshapiro	char dirfile[MAXPATHLEN];
135998121Sgshapiro	char pagfile[MAXPATHLEN];
136064562Sgshapiro	struct stat st;
136138032Speter	struct stat std, stp;
136238032Speter
136338032Speter	if (tTd(38, 2))
136490792Sgshapiro		sm_dprintf("ndbm_map_open(%s, %s, %d)\n",
136538032Speter			map->map_mname, map->map_file, mode);
136638032Speter	map->map_lockfd = -1;
136738032Speter	mode &= O_ACCMODE;
136838032Speter
136938032Speter	/* do initial file and directory checks */
137098121Sgshapiro	if (sm_strlcpyn(dirfile, sizeof dirfile, 2,
137198121Sgshapiro			map->map_file, ".dir") >= sizeof dirfile ||
137298121Sgshapiro	    sm_strlcpyn(pagfile, sizeof pagfile, 2,
137398121Sgshapiro			map->map_file, ".pag") >= sizeof pagfile)
137498121Sgshapiro	{
137598121Sgshapiro		errno = 0;
137698121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
137798121Sgshapiro			syserr("dbm map \"%s\": map file %s name too long",
137898121Sgshapiro				map->map_mname, map->map_file);
137998121Sgshapiro		return false;
138098121Sgshapiro	}
138138032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
138238032Speter	if (mode == O_RDWR)
138338032Speter	{
138438032Speter		sff |= SFF_CREAT;
138564562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
138638032Speter			sff |= SFF_NOSLINK;
138764562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
138838032Speter			sff |= SFF_NOHLINK;
138938032Speter		smode = S_IWRITE;
139038032Speter	}
139138032Speter	else
139238032Speter	{
139364562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
139438032Speter			sff |= SFF_NOWLINK;
139538032Speter	}
139664562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
139738032Speter		sff |= SFF_SAFEDIRPATH;
139838032Speter	ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
139990792Sgshapiro		       sff, smode, &std);
140038032Speter	if (ret == 0)
140138032Speter		ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
140238032Speter			       sff, smode, &stp);
140364562Sgshapiro
140438032Speter	if (ret != 0)
140538032Speter	{
140638032Speter		char *prob = "unsafe";
140738032Speter
140838032Speter		/* cannot open this map */
140938032Speter		if (ret == ENOENT)
141038032Speter			prob = "missing";
141138032Speter		if (tTd(38, 2))
141290792Sgshapiro			sm_dprintf("\t%s map file: %d\n", prob, ret);
141338032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
141438032Speter			syserr("dbm map \"%s\": %s map file %s",
141538032Speter				map->map_mname, prob, map->map_file);
141690792Sgshapiro		return false;
141738032Speter	}
141838032Speter	if (std.st_mode == ST_MODE_NOFILE)
141938032Speter		mode |= O_CREAT|O_EXCL;
142038032Speter
142164562Sgshapiro# if LOCK_ON_OPEN
142238032Speter	if (mode == O_RDONLY)
142338032Speter		mode |= O_SHLOCK;
142438032Speter	else
142538032Speter		mode |= O_TRUNC|O_EXLOCK;
142664562Sgshapiro# else /* LOCK_ON_OPEN */
142738032Speter	if ((mode & O_ACCMODE) == O_RDWR)
142838032Speter	{
142964562Sgshapiro#  if NOFTRUNCATE
143038032Speter		/*
143138032Speter		**  Warning: race condition.  Try to lock the file as
143238032Speter		**  quickly as possible after opening it.
143338032Speter		**	This may also have security problems on some systems,
143438032Speter		**	but there isn't anything we can do about it.
143538032Speter		*/
143638032Speter
143738032Speter		mode |= O_TRUNC;
143864562Sgshapiro#  else /* NOFTRUNCATE */
143938032Speter		/*
144038032Speter		**  This ugly code opens the map without truncating it,
144138032Speter		**  locks the file, then truncates it.  Necessary to
144238032Speter		**  avoid race conditions.
144338032Speter		*/
144438032Speter
144538032Speter		int dirfd;
144638032Speter		int pagfd;
144764562Sgshapiro		long sff = SFF_CREAT|SFF_OPENASROOT;
144838032Speter
144964562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
145038032Speter			sff |= SFF_NOSLINK;
145164562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
145238032Speter			sff |= SFF_NOHLINK;
145338032Speter
145438032Speter		dirfd = safeopen(dirfile, mode, DBMMODE, sff);
145538032Speter		pagfd = safeopen(pagfile, mode, DBMMODE, sff);
145638032Speter
145738032Speter		if (dirfd < 0 || pagfd < 0)
145838032Speter		{
145964562Sgshapiro			save_errno = errno;
146038032Speter			if (dirfd >= 0)
146138032Speter				(void) close(dirfd);
146238032Speter			if (pagfd >= 0)
146338032Speter				(void) close(pagfd);
146438032Speter			errno = save_errno;
146538032Speter			syserr("ndbm_map_open: cannot create database %s",
146638032Speter				map->map_file);
146790792Sgshapiro			return false;
146838032Speter		}
146938032Speter		if (ftruncate(dirfd, (off_t) 0) < 0 ||
147038032Speter		    ftruncate(pagfd, (off_t) 0) < 0)
147138032Speter		{
147264562Sgshapiro			save_errno = errno;
147338032Speter			(void) close(dirfd);
147438032Speter			(void) close(pagfd);
147538032Speter			errno = save_errno;
147638032Speter			syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
147738032Speter				map->map_file);
147890792Sgshapiro			return false;
147938032Speter		}
148038032Speter
148138032Speter		/* if new file, get "before" bits for later filechanged check */
148238032Speter		if (std.st_mode == ST_MODE_NOFILE &&
148338032Speter		    (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
148438032Speter		{
148564562Sgshapiro			save_errno = errno;
148638032Speter			(void) close(dirfd);
148738032Speter			(void) close(pagfd);
148838032Speter			errno = save_errno;
148938032Speter			syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
149038032Speter				map->map_file);
149190792Sgshapiro			return false;
149238032Speter		}
149338032Speter
149438032Speter		/* have to save the lock for the duration (bletch) */
149538032Speter		map->map_lockfd = dirfd;
149664562Sgshapiro		(void) close(pagfd);
149738032Speter
149838032Speter		/* twiddle bits for dbm_open */
149938032Speter		mode &= ~(O_CREAT|O_EXCL);
150064562Sgshapiro#  endif /* NOFTRUNCATE */
150138032Speter	}
150264562Sgshapiro# endif /* LOCK_ON_OPEN */
150338032Speter
150438032Speter	/* open the database */
150538032Speter	dbm = dbm_open(map->map_file, mode, DBMMODE);
150638032Speter	if (dbm == NULL)
150738032Speter	{
150864562Sgshapiro		save_errno = errno;
150938032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
151090792Sgshapiro		    aliaswait(map, ".pag", false))
151190792Sgshapiro			return true;
151264562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
151338032Speter		if (map->map_lockfd >= 0)
151464562Sgshapiro			(void) close(map->map_lockfd);
151564562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
151638032Speter		errno = save_errno;
151738032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
151838032Speter			syserr("Cannot open DBM database %s", map->map_file);
151990792Sgshapiro		return false;
152038032Speter	}
152138032Speter	dfd = dbm_dirfno(dbm);
152238032Speter	pfd = dbm_pagfno(dbm);
152338032Speter	if (dfd == pfd)
152438032Speter	{
152538032Speter		/* heuristic: if files are linked, this is actually gdbm */
152638032Speter		dbm_close(dbm);
152764562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
152838032Speter		if (map->map_lockfd >= 0)
152964562Sgshapiro			(void) close(map->map_lockfd);
153064562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
153138032Speter		errno = 0;
153238032Speter		syserr("dbm map \"%s\": cannot support GDBM",
153338032Speter			map->map_mname);
153490792Sgshapiro		return false;
153538032Speter	}
153638032Speter
153738032Speter	if (filechanged(dirfile, dfd, &std) ||
153838032Speter	    filechanged(pagfile, pfd, &stp))
153938032Speter	{
154064562Sgshapiro		save_errno = errno;
154138032Speter		dbm_close(dbm);
154264562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
154338032Speter		if (map->map_lockfd >= 0)
154464562Sgshapiro			(void) close(map->map_lockfd);
154564562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
154638032Speter		errno = save_errno;
154738032Speter		syserr("ndbm_map_open(%s): file changed after open",
154838032Speter			map->map_file);
154990792Sgshapiro		return false;
155038032Speter	}
155138032Speter
155238032Speter	map->map_db1 = (ARBPTR_T) dbm;
155364562Sgshapiro
155464562Sgshapiro	/*
155564562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
155664562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
155764562Sgshapiro	**  map_mtime to be set
155864562Sgshapiro	*/
155964562Sgshapiro
156077349Sgshapiro	if (fstat(pfd, &st) >= 0)
156164562Sgshapiro		map->map_mtime = st.st_mtime;
156264562Sgshapiro
156338032Speter	if (mode == O_RDONLY)
156438032Speter	{
156564562Sgshapiro# if LOCK_ON_OPEN
156638032Speter		if (dfd >= 0)
156738032Speter			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
156838032Speter		if (pfd >= 0)
156938032Speter			(void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
157064562Sgshapiro# endif /* LOCK_ON_OPEN */
157138032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
157290792Sgshapiro		    !aliaswait(map, ".pag", true))
157390792Sgshapiro			return false;
157438032Speter	}
157538032Speter	else
157638032Speter	{
157738032Speter		map->map_mflags |= MF_LOCKED;
157842575Speter		if (geteuid() == 0 && TrustedUid != 0)
157938032Speter		{
158064562Sgshapiro#  if HASFCHOWN
158142575Speter			if (fchown(dfd, TrustedUid, -1) < 0 ||
158242575Speter			    fchown(pfd, TrustedUid, -1) < 0)
158338032Speter			{
158438032Speter				int err = errno;
158538032Speter
158638032Speter				sm_syslog(LOG_ALERT, NOQID,
158738032Speter					  "ownership change on %s failed: %s",
158890792Sgshapiro					  map->map_file, sm_errstring(err));
158938032Speter				message("050 ownership change on %s failed: %s",
159090792Sgshapiro					map->map_file, sm_errstring(err));
159138032Speter			}
159290792Sgshapiro#  else /* HASFCHOWN */
159390792Sgshapiro			sm_syslog(LOG_ALERT, NOQID,
159490792Sgshapiro				  "no fchown(): cannot change ownership on %s",
159590792Sgshapiro				  map->map_file);
159690792Sgshapiro			message("050 no fchown(): cannot change ownership on %s",
159790792Sgshapiro				map->map_file);
159864562Sgshapiro#  endif /* HASFCHOWN */
159938032Speter		}
160038032Speter	}
160190792Sgshapiro	return true;
160238032Speter}
160338032Speter
160438032Speter
160538032Speter/*
160638032Speter**  NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
160738032Speter*/
160838032Speter
160938032Speterchar *
161038032Speterndbm_map_lookup(map, name, av, statp)
161138032Speter	MAP *map;
161238032Speter	char *name;
161338032Speter	char **av;
161438032Speter	int *statp;
161538032Speter{
161638032Speter	datum key, val;
161777349Sgshapiro	int dfd, pfd;
161838032Speter	char keybuf[MAXNAME + 1];
161938032Speter	struct stat stbuf;
162038032Speter
162138032Speter	if (tTd(38, 20))
162290792Sgshapiro		sm_dprintf("ndbm_map_lookup(%s, %s)\n",
162338032Speter			map->map_mname, name);
162438032Speter
162538032Speter	key.dptr = name;
162638032Speter	key.dsize = strlen(name);
162738032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
162838032Speter	{
162938032Speter		if (key.dsize > sizeof keybuf - 1)
163038032Speter			key.dsize = sizeof keybuf - 1;
163164562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
163238032Speter		keybuf[key.dsize] = '\0';
163338032Speter		makelower(keybuf);
163438032Speter		key.dptr = keybuf;
163538032Speter	}
163638032Speterlockdbm:
163777349Sgshapiro	dfd = dbm_dirfno((DBM *) map->map_db1);
163877349Sgshapiro	if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
163977349Sgshapiro		(void) lockfile(dfd, map->map_file, ".dir", LOCK_SH);
164077349Sgshapiro	pfd = dbm_pagfno((DBM *) map->map_db1);
164177349Sgshapiro	if (pfd < 0 || fstat(pfd, &stbuf) < 0 ||
164277349Sgshapiro	    stbuf.st_mtime > map->map_mtime)
164338032Speter	{
164438032Speter		/* Reopen the database to sync the cache */
164538032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
164638032Speter								 : O_RDONLY;
164738032Speter
164877349Sgshapiro		if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
164977349Sgshapiro			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
165077349Sgshapiro		map->map_mflags |= MF_CLOSING;
165138032Speter		map->map_class->map_close(map);
165277349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
165338032Speter		if (map->map_class->map_open(map, omode))
165438032Speter		{
165538032Speter			map->map_mflags |= MF_OPEN;
165690792Sgshapiro			map->map_pid = CurrentPid;
165738032Speter			if ((omode && O_ACCMODE) == O_RDWR)
165838032Speter				map->map_mflags |= MF_WRITABLE;
165938032Speter			goto lockdbm;
166038032Speter		}
166138032Speter		else
166238032Speter		{
166338032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
166438032Speter			{
166538032Speter				extern MAPCLASS BogusMapClass;
166638032Speter
166738032Speter				*statp = EX_TEMPFAIL;
166890792Sgshapiro				map->map_orgclass = map->map_class;
166938032Speter				map->map_class = &BogusMapClass;
167038032Speter				map->map_mflags |= MF_OPEN;
167190792Sgshapiro				map->map_pid = CurrentPid;
167238032Speter				syserr("Cannot reopen NDBM database %s",
167338032Speter					map->map_file);
167438032Speter			}
167538032Speter			return NULL;
167638032Speter		}
167738032Speter	}
167838032Speter	val.dptr = NULL;
167938032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
168038032Speter	{
168138032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
168238032Speter		if (val.dptr != NULL)
168338032Speter			map->map_mflags &= ~MF_TRY1NULL;
168438032Speter	}
168538032Speter	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
168638032Speter	{
168738032Speter		key.dsize++;
168838032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
168938032Speter		if (val.dptr != NULL)
169038032Speter			map->map_mflags &= ~MF_TRY0NULL;
169138032Speter	}
169277349Sgshapiro	if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
169377349Sgshapiro		(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
169438032Speter	if (val.dptr == NULL)
169538032Speter		return NULL;
169638032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
169738032Speter		return map_rewrite(map, name, strlen(name), NULL);
169838032Speter	else
169938032Speter		return map_rewrite(map, val.dptr, val.dsize, av);
170038032Speter}
170138032Speter
170238032Speter
170338032Speter/*
170438032Speter**  NDBM_MAP_STORE -- store a datum in the database
170538032Speter*/
170638032Speter
170738032Spetervoid
170838032Speterndbm_map_store(map, lhs, rhs)
170938032Speter	register MAP *map;
171038032Speter	char *lhs;
171138032Speter	char *rhs;
171238032Speter{
171338032Speter	datum key;
171438032Speter	datum data;
171564562Sgshapiro	int status;
171638032Speter	char keybuf[MAXNAME + 1];
171738032Speter
171838032Speter	if (tTd(38, 12))
171990792Sgshapiro		sm_dprintf("ndbm_map_store(%s, %s, %s)\n",
172038032Speter			map->map_mname, lhs, rhs);
172138032Speter
172238032Speter	key.dsize = strlen(lhs);
172338032Speter	key.dptr = lhs;
172438032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
172538032Speter	{
172638032Speter		if (key.dsize > sizeof keybuf - 1)
172738032Speter			key.dsize = sizeof keybuf - 1;
172864562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
172938032Speter		keybuf[key.dsize] = '\0';
173038032Speter		makelower(keybuf);
173138032Speter		key.dptr = keybuf;
173238032Speter	}
173338032Speter
173438032Speter	data.dsize = strlen(rhs);
173538032Speter	data.dptr = rhs;
173638032Speter
173738032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
173838032Speter	{
173938032Speter		key.dsize++;
174038032Speter		data.dsize++;
174138032Speter	}
174238032Speter
174364562Sgshapiro	status = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
174464562Sgshapiro	if (status > 0)
174538032Speter	{
174638032Speter		if (!bitset(MF_APPEND, map->map_mflags))
174738032Speter			message("050 Warning: duplicate alias name %s", lhs);
174838032Speter		else
174938032Speter		{
175038032Speter			static char *buf = NULL;
175138032Speter			static int bufsiz = 0;
175238032Speter			auto int xstat;
175338032Speter			datum old;
175438032Speter
175538032Speter			old.dptr = ndbm_map_lookup(map, key.dptr,
175690792Sgshapiro						   (char **) NULL, &xstat);
175738032Speter			if (old.dptr != NULL && *(char *) old.dptr != '\0')
175838032Speter			{
175938032Speter				old.dsize = strlen(old.dptr);
176038032Speter				if (data.dsize + old.dsize + 2 > bufsiz)
176138032Speter				{
176238032Speter					if (buf != NULL)
176390792Sgshapiro						(void) sm_free(buf);
176438032Speter					bufsiz = data.dsize + old.dsize + 2;
176590792Sgshapiro					buf = sm_pmalloc_x(bufsiz);
176638032Speter				}
176790792Sgshapiro				(void) sm_strlcpyn(buf, bufsiz, 3,
176890792Sgshapiro					data.dptr, ",", old.dptr);
176938032Speter				data.dsize = data.dsize + old.dsize + 1;
177038032Speter				data.dptr = buf;
177138032Speter				if (tTd(38, 9))
177290792Sgshapiro					sm_dprintf("ndbm_map_store append=%s\n",
177364562Sgshapiro						data.dptr);
177438032Speter			}
177538032Speter		}
177664562Sgshapiro		status = dbm_store((DBM *) map->map_db1,
177764562Sgshapiro				   key, data, DBM_REPLACE);
177838032Speter	}
177964562Sgshapiro	if (status != 0)
178064562Sgshapiro		syserr("readaliases: dbm put (%s): %d", lhs, status);
178138032Speter}
178238032Speter
178338032Speter
178438032Speter/*
178538032Speter**  NDBM_MAP_CLOSE -- close the database
178638032Speter*/
178738032Speter
178838032Spetervoid
178938032Speterndbm_map_close(map)
179038032Speter	register MAP  *map;
179138032Speter{
179238032Speter	if (tTd(38, 9))
179390792Sgshapiro		sm_dprintf("ndbm_map_close(%s, %s, %lx)\n",
179438032Speter			map->map_mname, map->map_file, map->map_mflags);
179538032Speter
179638032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
179738032Speter	{
179864562Sgshapiro# ifdef NDBM_YP_COMPAT
179938032Speter		bool inclnull;
180042575Speter		char buf[MAXHOSTNAMELEN];
180138032Speter
180238032Speter		inclnull = bitset(MF_INCLNULL, map->map_mflags);
180338032Speter		map->map_mflags &= ~MF_INCLNULL;
180438032Speter
180538032Speter		if (strstr(map->map_file, "/yp/") != NULL)
180638032Speter		{
180738032Speter			long save_mflags = map->map_mflags;
180838032Speter
180938032Speter			map->map_mflags |= MF_NOFOLDCASE;
181038032Speter
181190792Sgshapiro			(void) sm_snprintf(buf, sizeof buf, "%010ld", curtime());
181238032Speter			ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
181338032Speter
181438032Speter			(void) gethostname(buf, sizeof buf);
181538032Speter			ndbm_map_store(map, "YP_MASTER_NAME", buf);
181638032Speter
181738032Speter			map->map_mflags = save_mflags;
181838032Speter		}
181938032Speter
182038032Speter		if (inclnull)
182138032Speter			map->map_mflags |= MF_INCLNULL;
182264562Sgshapiro# endif /* NDBM_YP_COMPAT */
182338032Speter
182438032Speter		/* write out the distinguished alias */
182538032Speter		ndbm_map_store(map, "@", "@");
182638032Speter	}
182738032Speter	dbm_close((DBM *) map->map_db1);
182838032Speter
182938032Speter	/* release lock (if needed) */
183064562Sgshapiro# if !LOCK_ON_OPEN
183138032Speter	if (map->map_lockfd >= 0)
183238032Speter		(void) close(map->map_lockfd);
183364562Sgshapiro# endif /* !LOCK_ON_OPEN */
183438032Speter}
183538032Speter
183664562Sgshapiro#endif /* NDBM */
183790792Sgshapiro/*
183838032Speter**  NEWDB (Hash and BTree) Modules
183938032Speter*/
184038032Speter
184190792Sgshapiro#if NEWDB
184238032Speter
184338032Speter/*
184438032Speter**  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
184538032Speter**
184638032Speter**	These do rather bizarre locking.  If you can lock on open,
184738032Speter**	do that to avoid the condition of opening a database that
184838032Speter**	is being rebuilt.  If you don't, we'll try to fake it, but
184938032Speter**	there will be a race condition.  If opening for read-only,
185038032Speter**	we immediately release the lock to avoid freezing things up.
185138032Speter**	We really ought to hold the lock, but guarantee that we won't
185238032Speter**	be pokey about it.  That's hard to do.
185338032Speter*/
185438032Speter
185538032Speter/* these should be K line arguments */
185664562Sgshapiro# if DB_VERSION_MAJOR < 2
185764562Sgshapiro#  define db_cachesize	cachesize
185864562Sgshapiro#  define h_nelem	nelem
185964562Sgshapiro#  ifndef DB_CACHE_SIZE
186064562Sgshapiro#   define DB_CACHE_SIZE	(1024 * 1024)	/* database memory cache size */
186164562Sgshapiro#  endif /* ! DB_CACHE_SIZE */
186264562Sgshapiro#  ifndef DB_HASH_NELEM
186364562Sgshapiro#   define DB_HASH_NELEM	4096		/* (starting) size of hash table */
186464562Sgshapiro#  endif /* ! DB_HASH_NELEM */
186564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
186638032Speter
186738032Speterbool
186838032Speterbt_map_open(map, mode)
186938032Speter	MAP *map;
187038032Speter	int mode;
187138032Speter{
187264562Sgshapiro# if DB_VERSION_MAJOR < 2
187338032Speter	BTREEINFO btinfo;
187464562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
187564562Sgshapiro# if DB_VERSION_MAJOR == 2
187638032Speter	DB_INFO btinfo;
187764562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
187864562Sgshapiro# if DB_VERSION_MAJOR > 2
187964562Sgshapiro	void *btinfo = NULL;
188064562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
188138032Speter
188238032Speter	if (tTd(38, 2))
188390792Sgshapiro		sm_dprintf("bt_map_open(%s, %s, %d)\n",
188438032Speter			map->map_mname, map->map_file, mode);
188538032Speter
188664562Sgshapiro# if DB_VERSION_MAJOR < 3
188764562Sgshapiro	memset(&btinfo, '\0', sizeof btinfo);
188864562Sgshapiro#  ifdef DB_CACHE_SIZE
188938032Speter	btinfo.db_cachesize = DB_CACHE_SIZE;
189064562Sgshapiro#  endif /* DB_CACHE_SIZE */
189164562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
189264562Sgshapiro
189338032Speter	return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
189438032Speter}
189538032Speter
189638032Speterbool
189738032Speterhash_map_open(map, mode)
189838032Speter	MAP *map;
189938032Speter	int mode;
190038032Speter{
190164562Sgshapiro# if DB_VERSION_MAJOR < 2
190238032Speter	HASHINFO hinfo;
190364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
190464562Sgshapiro# if DB_VERSION_MAJOR == 2
190538032Speter	DB_INFO hinfo;
190664562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
190764562Sgshapiro# if DB_VERSION_MAJOR > 2
190864562Sgshapiro	void *hinfo = NULL;
190964562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
191038032Speter
191138032Speter	if (tTd(38, 2))
191290792Sgshapiro		sm_dprintf("hash_map_open(%s, %s, %d)\n",
191338032Speter			map->map_mname, map->map_file, mode);
191438032Speter
191564562Sgshapiro# if DB_VERSION_MAJOR < 3
191664562Sgshapiro	memset(&hinfo, '\0', sizeof hinfo);
191764562Sgshapiro#  ifdef DB_HASH_NELEM
191838032Speter	hinfo.h_nelem = DB_HASH_NELEM;
191964562Sgshapiro#  endif /* DB_HASH_NELEM */
192064562Sgshapiro#  ifdef DB_CACHE_SIZE
192138032Speter	hinfo.db_cachesize = DB_CACHE_SIZE;
192264562Sgshapiro#  endif /* DB_CACHE_SIZE */
192364562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
192464562Sgshapiro
192538032Speter	return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
192638032Speter}
192738032Speter
192864562Sgshapirostatic bool
192938032Speterdb_map_open(map, mode, mapclassname, dbtype, openinfo)
193038032Speter	MAP *map;
193138032Speter	int mode;
193238032Speter	char *mapclassname;
193338032Speter	DBTYPE dbtype;
193464562Sgshapiro# if DB_VERSION_MAJOR < 2
193538032Speter	const void *openinfo;
193664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
193764562Sgshapiro# if DB_VERSION_MAJOR == 2
193838032Speter	DB_INFO *openinfo;
193964562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
194064562Sgshapiro# if DB_VERSION_MAJOR > 2
194164562Sgshapiro	void **openinfo;
194264562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
194338032Speter{
194438032Speter	DB *db = NULL;
194538032Speter	int i;
194638032Speter	int omode;
194738032Speter	int smode = S_IREAD;
194838032Speter	int fd;
194964562Sgshapiro	long sff;
195064562Sgshapiro	int save_errno;
195138032Speter	struct stat st;
195298121Sgshapiro	char buf[MAXPATHLEN];
195338032Speter
195438032Speter	/* do initial file and directory checks */
195598121Sgshapiro	if (sm_strlcpy(buf, map->map_file, sizeof buf) >= sizeof buf)
195698121Sgshapiro	{
195798121Sgshapiro		errno = 0;
195898121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
195998121Sgshapiro			syserr("map \"%s\": map file %s name too long",
196098121Sgshapiro				map->map_mname, map->map_file);
196198121Sgshapiro		return false;
196298121Sgshapiro	}
196338032Speter	i = strlen(buf);
196438032Speter	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
196598121Sgshapiro	{
196698121Sgshapiro		if (sm_strlcat(buf, ".db", sizeof buf) >= sizeof buf)
196798121Sgshapiro		{
196898121Sgshapiro			errno = 0;
196998121Sgshapiro			if (!bitset(MF_OPTIONAL, map->map_mflags))
197098121Sgshapiro				syserr("map \"%s\": map file %s name too long",
197198121Sgshapiro					map->map_mname, map->map_file);
197298121Sgshapiro			return false;
197398121Sgshapiro		}
197498121Sgshapiro	}
197538032Speter
197638032Speter	mode &= O_ACCMODE;
197738032Speter	omode = mode;
197838032Speter
197938032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
198038032Speter	if (mode == O_RDWR)
198138032Speter	{
198238032Speter		sff |= SFF_CREAT;
198364562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
198438032Speter			sff |= SFF_NOSLINK;
198564562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
198638032Speter			sff |= SFF_NOHLINK;
198738032Speter		smode = S_IWRITE;
198838032Speter	}
198938032Speter	else
199038032Speter	{
199164562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
199238032Speter			sff |= SFF_NOWLINK;
199338032Speter	}
199464562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
199538032Speter		sff |= SFF_SAFEDIRPATH;
199638032Speter	i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
199764562Sgshapiro
199838032Speter	if (i != 0)
199938032Speter	{
200038032Speter		char *prob = "unsafe";
200138032Speter
200238032Speter		/* cannot open this map */
200338032Speter		if (i == ENOENT)
200438032Speter			prob = "missing";
200538032Speter		if (tTd(38, 2))
200690792Sgshapiro			sm_dprintf("\t%s map file: %s\n", prob, sm_errstring(i));
200738032Speter		errno = i;
200838032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
200938032Speter			syserr("%s map \"%s\": %s map file %s",
201038032Speter				mapclassname, map->map_mname, prob, buf);
201190792Sgshapiro		return false;
201238032Speter	}
201338032Speter	if (st.st_mode == ST_MODE_NOFILE)
201438032Speter		omode |= O_CREAT|O_EXCL;
201538032Speter
201638032Speter	map->map_lockfd = -1;
201738032Speter
201864562Sgshapiro# if LOCK_ON_OPEN
201938032Speter	if (mode == O_RDWR)
202038032Speter		omode |= O_TRUNC|O_EXLOCK;
202138032Speter	else
202238032Speter		omode |= O_SHLOCK;
202364562Sgshapiro# else /* LOCK_ON_OPEN */
202438032Speter	/*
202538032Speter	**  Pre-lock the file to avoid race conditions.  In particular,
202638032Speter	**  since dbopen returns NULL if the file is zero length, we
202738032Speter	**  must have a locked instance around the dbopen.
202838032Speter	*/
202938032Speter
203038032Speter	fd = open(buf, omode, DBMMODE);
203138032Speter	if (fd < 0)
203238032Speter	{
203338032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
203438032Speter			syserr("db_map_open: cannot pre-open database %s", buf);
203590792Sgshapiro		return false;
203638032Speter	}
203738032Speter
203838032Speter	/* make sure no baddies slipped in just before the open... */
203938032Speter	if (filechanged(buf, fd, &st))
204038032Speter	{
204164562Sgshapiro		save_errno = errno;
204238032Speter		(void) close(fd);
204338032Speter		errno = save_errno;
204438032Speter		syserr("db_map_open(%s): file changed after pre-open", buf);
204590792Sgshapiro		return false;
204638032Speter	}
204738032Speter
204838032Speter	/* if new file, get the "before" bits for later filechanged check */
204938032Speter	if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
205038032Speter	{
205164562Sgshapiro		save_errno = errno;
205238032Speter		(void) close(fd);
205338032Speter		errno = save_errno;
205438032Speter		syserr("db_map_open(%s): cannot fstat pre-opened file",
205538032Speter			buf);
205690792Sgshapiro		return false;
205738032Speter	}
205838032Speter
205938032Speter	/* actually lock the pre-opened file */
206038032Speter	if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
206138032Speter		syserr("db_map_open: cannot lock %s", buf);
206238032Speter
206338032Speter	/* set up mode bits for dbopen */
206438032Speter	if (mode == O_RDWR)
206538032Speter		omode |= O_TRUNC;
206638032Speter	omode &= ~(O_EXCL|O_CREAT);
206764562Sgshapiro# endif /* LOCK_ON_OPEN */
206838032Speter
206964562Sgshapiro# if DB_VERSION_MAJOR < 2
207038032Speter	db = dbopen(buf, omode, DBMMODE, dbtype, openinfo);
207164562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
207238032Speter	{
207338032Speter		int flags = 0;
207464562Sgshapiro#  if DB_VERSION_MAJOR > 2
207564562Sgshapiro		int ret;
207664562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
207738032Speter
207838032Speter		if (mode == O_RDONLY)
207938032Speter			flags |= DB_RDONLY;
208038032Speter		if (bitset(O_CREAT, omode))
208138032Speter			flags |= DB_CREATE;
208238032Speter		if (bitset(O_TRUNC, omode))
208338032Speter			flags |= DB_TRUNCATE;
2084110560Sgshapiro		SM_DB_FLAG_ADD(flags);
208538032Speter
208664562Sgshapiro#  if DB_VERSION_MAJOR > 2
208764562Sgshapiro		ret = db_create(&db, NULL, 0);
208864562Sgshapiro#  ifdef DB_CACHE_SIZE
208964562Sgshapiro		if (ret == 0 && db != NULL)
209064562Sgshapiro		{
209164562Sgshapiro			ret = db->set_cachesize(db, 0, DB_CACHE_SIZE, 0);
209264562Sgshapiro			if (ret != 0)
209364562Sgshapiro			{
209464562Sgshapiro				(void) db->close(db, 0);
209564562Sgshapiro				db = NULL;
209664562Sgshapiro			}
209764562Sgshapiro		}
209864562Sgshapiro#  endif /* DB_CACHE_SIZE */
209964562Sgshapiro#  ifdef DB_HASH_NELEM
210064562Sgshapiro		if (dbtype == DB_HASH && ret == 0 && db != NULL)
210164562Sgshapiro		{
210264562Sgshapiro			ret = db->set_h_nelem(db, DB_HASH_NELEM);
210364562Sgshapiro			if (ret != 0)
210464562Sgshapiro			{
210564562Sgshapiro				(void) db->close(db, 0);
210664562Sgshapiro				db = NULL;
210764562Sgshapiro			}
210864562Sgshapiro		}
210964562Sgshapiro#  endif /* DB_HASH_NELEM */
211064562Sgshapiro		if (ret == 0 && db != NULL)
211164562Sgshapiro		{
2112110560Sgshapiro			ret = db->open(db,
2113110560Sgshapiro					DBTXN	/* transaction for DB 4.1 */
2114110560Sgshapiro					buf, NULL, dbtype, flags, DBMMODE);
211564562Sgshapiro			if (ret != 0)
211664562Sgshapiro			{
211773188Sgshapiro#ifdef DB_OLD_VERSION
211873188Sgshapiro				if (ret == DB_OLD_VERSION)
211973188Sgshapiro					ret = EINVAL;
212073188Sgshapiro#endif /* DB_OLD_VERSION */
212164562Sgshapiro				(void) db->close(db, 0);
212264562Sgshapiro				db = NULL;
212364562Sgshapiro			}
212464562Sgshapiro		}
212564562Sgshapiro		errno = ret;
212664562Sgshapiro#  else /* DB_VERSION_MAJOR > 2 */
212738032Speter		errno = db_open(buf, dbtype, flags, DBMMODE,
212838032Speter				NULL, openinfo, &db);
212964562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
213038032Speter	}
213164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
213264562Sgshapiro	save_errno = errno;
213338032Speter
213464562Sgshapiro# if !LOCK_ON_OPEN
213538032Speter	if (mode == O_RDWR)
213638032Speter		map->map_lockfd = fd;
213738032Speter	else
213838032Speter		(void) close(fd);
213964562Sgshapiro# endif /* !LOCK_ON_OPEN */
214038032Speter
214138032Speter	if (db == NULL)
214238032Speter	{
214338032Speter		if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
214490792Sgshapiro		    aliaswait(map, ".db", false))
214590792Sgshapiro			return true;
214664562Sgshapiro# if !LOCK_ON_OPEN
214738032Speter		if (map->map_lockfd >= 0)
214838032Speter			(void) close(map->map_lockfd);
214964562Sgshapiro# endif /* !LOCK_ON_OPEN */
215064562Sgshapiro		errno = save_errno;
215138032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
215238032Speter			syserr("Cannot open %s database %s",
215338032Speter				mapclassname, buf);
215490792Sgshapiro		return false;
215538032Speter	}
215638032Speter
215764562Sgshapiro# if DB_VERSION_MAJOR < 2
215838032Speter	fd = db->fd(db);
215964562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
216038032Speter	fd = -1;
216138032Speter	errno = db->fd(db, &fd);
216264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
216338032Speter	if (filechanged(buf, fd, &st))
216438032Speter	{
216564562Sgshapiro		save_errno = errno;
216664562Sgshapiro# if DB_VERSION_MAJOR < 2
216764562Sgshapiro		(void) db->close(db);
216864562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
216938032Speter		errno = db->close(db, 0);
217064562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
217164562Sgshapiro# if !LOCK_ON_OPEN
217238032Speter		if (map->map_lockfd >= 0)
217364562Sgshapiro			(void) close(map->map_lockfd);
217464562Sgshapiro# endif /* !LOCK_ON_OPEN */
217538032Speter		errno = save_errno;
217638032Speter		syserr("db_map_open(%s): file changed after open", buf);
217790792Sgshapiro		return false;
217838032Speter	}
217938032Speter
218038032Speter	if (mode == O_RDWR)
218138032Speter		map->map_mflags |= MF_LOCKED;
218264562Sgshapiro# if LOCK_ON_OPEN
218338032Speter	if (fd >= 0 && mode == O_RDONLY)
218438032Speter	{
218538032Speter		(void) lockfile(fd, buf, NULL, LOCK_UN);
218638032Speter	}
218764562Sgshapiro# endif /* LOCK_ON_OPEN */
218838032Speter
218938032Speter	/* try to make sure that at least the database header is on disk */
219038032Speter	if (mode == O_RDWR)
219138032Speter	{
219238032Speter		(void) db->sync(db, 0);
219342575Speter		if (geteuid() == 0 && TrustedUid != 0)
219438032Speter		{
219564562Sgshapiro#  if HASFCHOWN
219642575Speter			if (fchown(fd, TrustedUid, -1) < 0)
219738032Speter			{
219838032Speter				int err = errno;
219938032Speter
220038032Speter				sm_syslog(LOG_ALERT, NOQID,
220138032Speter					  "ownership change on %s failed: %s",
220290792Sgshapiro					  buf, sm_errstring(err));
220338032Speter				message("050 ownership change on %s failed: %s",
220490792Sgshapiro					buf, sm_errstring(err));
220538032Speter			}
220690792Sgshapiro#  else /* HASFCHOWN */
220790792Sgshapiro			sm_syslog(LOG_ALERT, NOQID,
220890792Sgshapiro				  "no fchown(): cannot change ownership on %s",
220990792Sgshapiro				  map->map_file);
221090792Sgshapiro			message("050 no fchown(): cannot change ownership on %s",
221190792Sgshapiro				map->map_file);
221264562Sgshapiro#  endif /* HASFCHOWN */
221338032Speter		}
221438032Speter	}
221538032Speter
221664562Sgshapiro	map->map_db2 = (ARBPTR_T) db;
221764562Sgshapiro
221864562Sgshapiro	/*
221964562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
222064562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
222164562Sgshapiro	**  map_mtime to be set
222264562Sgshapiro	*/
222364562Sgshapiro
222438032Speter	if (fd >= 0 && fstat(fd, &st) >= 0)
222538032Speter		map->map_mtime = st.st_mtime;
222638032Speter
222738032Speter	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
222890792Sgshapiro	    !aliaswait(map, ".db", true))
222990792Sgshapiro		return false;
223090792Sgshapiro	return true;
223138032Speter}
223238032Speter
223338032Speter
223438032Speter/*
223538032Speter**  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
223638032Speter*/
223738032Speter
223838032Speterchar *
223938032Speterdb_map_lookup(map, name, av, statp)
224038032Speter	MAP *map;
224138032Speter	char *name;
224238032Speter	char **av;
224338032Speter	int *statp;
224438032Speter{
224538032Speter	DBT key, val;
224638032Speter	register DB *db = (DB *) map->map_db2;
224738032Speter	int i;
224838032Speter	int st;
224964562Sgshapiro	int save_errno;
225038032Speter	int fd;
225138032Speter	struct stat stbuf;
225238032Speter	char keybuf[MAXNAME + 1];
225398121Sgshapiro	char buf[MAXPATHLEN];
225438032Speter
225564562Sgshapiro	memset(&key, '\0', sizeof key);
225664562Sgshapiro	memset(&val, '\0', sizeof val);
225738032Speter
225838032Speter	if (tTd(38, 20))
225990792Sgshapiro		sm_dprintf("db_map_lookup(%s, %s)\n",
226038032Speter			map->map_mname, name);
226138032Speter
226298121Sgshapiro	if (sm_strlcpy(buf, map->map_file, sizeof buf) >= sizeof buf)
226398121Sgshapiro	{
226498121Sgshapiro		errno = 0;
226598121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
226698121Sgshapiro			syserr("map \"%s\": map file %s name too long",
226798121Sgshapiro				map->map_mname, map->map_file);
226898121Sgshapiro		return NULL;
226998121Sgshapiro	}
227098121Sgshapiro	i = strlen(buf);
227138032Speter	if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
227238032Speter		buf[i - 3] = '\0';
227338032Speter
227438032Speter	key.size = strlen(name);
227538032Speter	if (key.size > sizeof keybuf - 1)
227638032Speter		key.size = sizeof keybuf - 1;
227738032Speter	key.data = keybuf;
227864562Sgshapiro	memmove(keybuf, name, key.size);
227938032Speter	keybuf[key.size] = '\0';
228038032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
228138032Speter		makelower(keybuf);
228238032Speter  lockdb:
228364562Sgshapiro# if DB_VERSION_MAJOR < 2
228438032Speter	fd = db->fd(db);
228564562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
228638032Speter	fd = -1;
228738032Speter	errno = db->fd(db, &fd);
228864562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
228938032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
229038032Speter		(void) lockfile(fd, buf, ".db", LOCK_SH);
229138032Speter	if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
229238032Speter	{
229338032Speter		/* Reopen the database to sync the cache */
229438032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
229538032Speter								 : O_RDONLY;
229638032Speter
229764562Sgshapiro		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
229864562Sgshapiro			(void) lockfile(fd, buf, ".db", LOCK_UN);
229977349Sgshapiro		map->map_mflags |= MF_CLOSING;
230038032Speter		map->map_class->map_close(map);
230177349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
230238032Speter		if (map->map_class->map_open(map, omode))
230338032Speter		{
230438032Speter			map->map_mflags |= MF_OPEN;
230590792Sgshapiro			map->map_pid = CurrentPid;
230638032Speter			if ((omode && O_ACCMODE) == O_RDWR)
230738032Speter				map->map_mflags |= MF_WRITABLE;
230838032Speter			db = (DB *) map->map_db2;
230938032Speter			goto lockdb;
231038032Speter		}
231138032Speter		else
231238032Speter		{
231338032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
231438032Speter			{
231538032Speter				extern MAPCLASS BogusMapClass;
231638032Speter
231738032Speter				*statp = EX_TEMPFAIL;
231890792Sgshapiro				map->map_orgclass = map->map_class;
231938032Speter				map->map_class = &BogusMapClass;
232038032Speter				map->map_mflags |= MF_OPEN;
232190792Sgshapiro				map->map_pid = CurrentPid;
232238032Speter				syserr("Cannot reopen DB database %s",
232338032Speter					map->map_file);
232438032Speter			}
232538032Speter			return NULL;
232638032Speter		}
232738032Speter	}
232838032Speter
232938032Speter	st = 1;
233038032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
233138032Speter	{
233264562Sgshapiro# if DB_VERSION_MAJOR < 2
233338032Speter		st = db->get(db, &key, &val, 0);
233464562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
233538032Speter		errno = db->get(db, NULL, &key, &val, 0);
233638032Speter		switch (errno)
233738032Speter		{
233838032Speter		  case DB_NOTFOUND:
233938032Speter		  case DB_KEYEMPTY:
234038032Speter			st = 1;
234138032Speter			break;
234238032Speter
234338032Speter		  case 0:
234438032Speter			st = 0;
234538032Speter			break;
234638032Speter
234738032Speter		  default:
234838032Speter			st = -1;
234938032Speter			break;
235038032Speter		}
235164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
235238032Speter		if (st == 0)
235338032Speter			map->map_mflags &= ~MF_TRY1NULL;
235438032Speter	}
235538032Speter	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
235638032Speter	{
235738032Speter		key.size++;
235864562Sgshapiro# if DB_VERSION_MAJOR < 2
235938032Speter		st = db->get(db, &key, &val, 0);
236064562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
236138032Speter		errno = db->get(db, NULL, &key, &val, 0);
236238032Speter		switch (errno)
236338032Speter		{
236438032Speter		  case DB_NOTFOUND:
236538032Speter		  case DB_KEYEMPTY:
236638032Speter			st = 1;
236738032Speter			break;
236838032Speter
236938032Speter		  case 0:
237038032Speter			st = 0;
237138032Speter			break;
237238032Speter
237338032Speter		  default:
237438032Speter			st = -1;
237538032Speter			break;
237638032Speter		}
237764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
237838032Speter		if (st == 0)
237938032Speter			map->map_mflags &= ~MF_TRY0NULL;
238038032Speter	}
238164562Sgshapiro	save_errno = errno;
238238032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
238338032Speter		(void) lockfile(fd, buf, ".db", LOCK_UN);
238438032Speter	if (st != 0)
238538032Speter	{
238664562Sgshapiro		errno = save_errno;
238738032Speter		if (st < 0)
238838032Speter			syserr("db_map_lookup: get (%s)", name);
238938032Speter		return NULL;
239038032Speter	}
239138032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
239238032Speter		return map_rewrite(map, name, strlen(name), NULL);
239338032Speter	else
239438032Speter		return map_rewrite(map, val.data, val.size, av);
239538032Speter}
239638032Speter
239738032Speter
239838032Speter/*
239938032Speter**  DB_MAP_STORE -- store a datum in the NEWDB database
240038032Speter*/
240138032Speter
240238032Spetervoid
240338032Speterdb_map_store(map, lhs, rhs)
240438032Speter	register MAP *map;
240538032Speter	char *lhs;
240638032Speter	char *rhs;
240738032Speter{
240864562Sgshapiro	int status;
240938032Speter	DBT key;
241038032Speter	DBT data;
241138032Speter	register DB *db = map->map_db2;
241238032Speter	char keybuf[MAXNAME + 1];
241338032Speter
241464562Sgshapiro	memset(&key, '\0', sizeof key);
241564562Sgshapiro	memset(&data, '\0', sizeof data);
241638032Speter
241738032Speter	if (tTd(38, 12))
241890792Sgshapiro		sm_dprintf("db_map_store(%s, %s, %s)\n",
241938032Speter			map->map_mname, lhs, rhs);
242038032Speter
242138032Speter	key.size = strlen(lhs);
242238032Speter	key.data = lhs;
242338032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
242438032Speter	{
242538032Speter		if (key.size > sizeof keybuf - 1)
242638032Speter			key.size = sizeof keybuf - 1;
242764562Sgshapiro		memmove(keybuf, key.data, key.size);
242838032Speter		keybuf[key.size] = '\0';
242938032Speter		makelower(keybuf);
243038032Speter		key.data = keybuf;
243138032Speter	}
243238032Speter
243338032Speter	data.size = strlen(rhs);
243438032Speter	data.data = rhs;
243538032Speter
243638032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
243738032Speter	{
243838032Speter		key.size++;
243938032Speter		data.size++;
244038032Speter	}
244138032Speter
244264562Sgshapiro# if DB_VERSION_MAJOR < 2
244364562Sgshapiro	status = db->put(db, &key, &data, R_NOOVERWRITE);
244464562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
244538032Speter	errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE);
244638032Speter	switch (errno)
244738032Speter	{
244838032Speter	  case DB_KEYEXIST:
244964562Sgshapiro		status = 1;
245038032Speter		break;
245138032Speter
245238032Speter	  case 0:
245364562Sgshapiro		status = 0;
245438032Speter		break;
245538032Speter
245638032Speter	  default:
245764562Sgshapiro		status = -1;
245838032Speter		break;
245938032Speter	}
246064562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
246164562Sgshapiro	if (status > 0)
246238032Speter	{
246338032Speter		if (!bitset(MF_APPEND, map->map_mflags))
246438032Speter			message("050 Warning: duplicate alias name %s", lhs);
246538032Speter		else
246638032Speter		{
246738032Speter			static char *buf = NULL;
246838032Speter			static int bufsiz = 0;
246938032Speter			DBT old;
247038032Speter
247164562Sgshapiro			memset(&old, '\0', sizeof old);
247238032Speter
247364562Sgshapiro			old.data = db_map_lookup(map, key.data,
247490792Sgshapiro						 (char **) NULL, &status);
247538032Speter			if (old.data != NULL)
247638032Speter			{
247738032Speter				old.size = strlen(old.data);
247890792Sgshapiro				if (data.size + old.size + 2 > (size_t) bufsiz)
247938032Speter				{
248038032Speter					if (buf != NULL)
248177349Sgshapiro						sm_free(buf);
248238032Speter					bufsiz = data.size + old.size + 2;
248390792Sgshapiro					buf = sm_pmalloc_x(bufsiz);
248438032Speter				}
248590792Sgshapiro				(void) sm_strlcpyn(buf, bufsiz, 3,
248690792Sgshapiro					(char *) data.data, ",",
248790792Sgshapiro					(char *) old.data);
248838032Speter				data.size = data.size + old.size + 1;
248938032Speter				data.data = buf;
249038032Speter				if (tTd(38, 9))
249190792Sgshapiro					sm_dprintf("db_map_store append=%s\n",
249264562Sgshapiro						(char *) data.data);
249338032Speter			}
249438032Speter		}
249564562Sgshapiro# if DB_VERSION_MAJOR < 2
249664562Sgshapiro		status = db->put(db, &key, &data, 0);
249764562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
249864562Sgshapiro		status = errno = db->put(db, NULL, &key, &data, 0);
249964562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
250038032Speter	}
250164562Sgshapiro	if (status != 0)
250238032Speter		syserr("readaliases: db put (%s)", lhs);
250338032Speter}
250438032Speter
250538032Speter
250638032Speter/*
250738032Speter**  DB_MAP_CLOSE -- add distinguished entries and close the database
250838032Speter*/
250938032Speter
251038032Spetervoid
251138032Speterdb_map_close(map)
251238032Speter	MAP *map;
251338032Speter{
251438032Speter	register DB *db = map->map_db2;
251538032Speter
251638032Speter	if (tTd(38, 9))
251790792Sgshapiro		sm_dprintf("db_map_close(%s, %s, %lx)\n",
251838032Speter			map->map_mname, map->map_file, map->map_mflags);
251938032Speter
252038032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
252138032Speter	{
252238032Speter		/* write out the distinguished alias */
252338032Speter		db_map_store(map, "@", "@");
252438032Speter	}
252538032Speter
252638032Speter	(void) db->sync(db, 0);
252738032Speter
252864562Sgshapiro# if !LOCK_ON_OPEN
252938032Speter	if (map->map_lockfd >= 0)
253038032Speter		(void) close(map->map_lockfd);
253164562Sgshapiro# endif /* !LOCK_ON_OPEN */
253238032Speter
253364562Sgshapiro# if DB_VERSION_MAJOR < 2
253438032Speter	if (db->close(db) != 0)
253564562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
253642575Speter	/*
253742575Speter	**  Berkeley DB can use internal shared memory
253842575Speter	**  locking for its memory pool.  Closing a map
253942575Speter	**  opened by another process will interfere
254042575Speter	**  with the shared memory and locks of the parent
254142575Speter	**  process leaving things in a bad state.
254243730Speter	*/
254343730Speter
254443730Speter	/*
254542575Speter	**  If this map was not opened by the current
254643730Speter	**  process, do not close the map but recover
254742575Speter	**  the file descriptor.
254842575Speter	*/
254990792Sgshapiro
255090792Sgshapiro	if (map->map_pid != CurrentPid)
255142575Speter	{
255242575Speter		int fd = -1;
255342575Speter
255442575Speter		errno = db->fd(db, &fd);
255542575Speter		if (fd >= 0)
255642575Speter			(void) close(fd);
255742575Speter		return;
255842575Speter	}
255942575Speter
256038032Speter	if ((errno = db->close(db, 0)) != 0)
256164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
256242575Speter		syserr("db_map_close(%s, %s, %lx): db close failure",
256342575Speter			map->map_mname, map->map_file, map->map_mflags);
256438032Speter}
256564562Sgshapiro#endif /* NEWDB */
256690792Sgshapiro/*
256738032Speter**  NIS Modules
256838032Speter*/
256938032Speter
257090792Sgshapiro#if NIS
257138032Speter
257238032Speter# ifndef YPERR_BUSY
257338032Speter#  define YPERR_BUSY	16
257464562Sgshapiro# endif /* ! YPERR_BUSY */
257538032Speter
257638032Speter/*
257738032Speter**  NIS_MAP_OPEN -- open DBM map
257838032Speter*/
257938032Speter
258038032Speterbool
258138032Speternis_map_open(map, mode)
258238032Speter	MAP *map;
258338032Speter	int mode;
258438032Speter{
258538032Speter	int yperr;
258638032Speter	register char *p;
258738032Speter	auto char *vp;
258838032Speter	auto int vsize;
258938032Speter
259038032Speter	if (tTd(38, 2))
259190792Sgshapiro		sm_dprintf("nis_map_open(%s, %s, %d)\n",
259238032Speter			map->map_mname, map->map_file, mode);
259338032Speter
259438032Speter	mode &= O_ACCMODE;
259538032Speter	if (mode != O_RDONLY)
259638032Speter	{
259738032Speter		/* issue a pseudo-error message */
259890792Sgshapiro		errno = SM_EMAPCANTWRITE;
259990792Sgshapiro		return false;
260038032Speter	}
260138032Speter
260238032Speter	p = strchr(map->map_file, '@');
260338032Speter	if (p != NULL)
260438032Speter	{
260538032Speter		*p++ = '\0';
260638032Speter		if (*p != '\0')
260738032Speter			map->map_domain = p;
260838032Speter	}
260938032Speter
261038032Speter	if (*map->map_file == '\0')
261138032Speter		map->map_file = "mail.aliases";
261238032Speter
261338032Speter	if (map->map_domain == NULL)
261438032Speter	{
261538032Speter		yperr = yp_get_default_domain(&map->map_domain);
261638032Speter		if (yperr != 0)
261738032Speter		{
261838032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
261994334Sgshapiro				syserr("451 4.3.5 NIS map %s specified, but NIS not running",
262064562Sgshapiro				       map->map_file);
262190792Sgshapiro			return false;
262238032Speter		}
262338032Speter	}
262438032Speter
262538032Speter	/* check to see if this map actually exists */
262664562Sgshapiro	vp = NULL;
262738032Speter	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
262838032Speter			&vp, &vsize);
262938032Speter	if (tTd(38, 10))
263090792Sgshapiro		sm_dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n",
263138032Speter			map->map_domain, map->map_file, yperr_string(yperr));
263264562Sgshapiro	if (vp != NULL)
263377349Sgshapiro		sm_free(vp);
263464562Sgshapiro
263538032Speter	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
263638032Speter	{
263738032Speter		/*
263838032Speter		**  We ought to be calling aliaswait() here if this is an
263938032Speter		**  alias file, but powerful HP-UX NIS servers  apparently
264038032Speter		**  don't insert the @:@ token into the alias map when it
264138032Speter		**  is rebuilt, so aliaswait() just hangs.  I hate HP-UX.
264238032Speter		*/
264338032Speter
264464562Sgshapiro# if 0
264538032Speter		if (!bitset(MF_ALIAS, map->map_mflags) ||
264690792Sgshapiro		    aliaswait(map, NULL, true))
264764562Sgshapiro# endif /* 0 */
264890792Sgshapiro			return true;
264938032Speter	}
265038032Speter
265138032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
265238032Speter	{
265394334Sgshapiro		syserr("451 4.3.5 Cannot bind to map %s in domain %s: %s",
265438032Speter			map->map_file, map->map_domain, yperr_string(yperr));
265538032Speter	}
265638032Speter
265790792Sgshapiro	return false;
265838032Speter}
265938032Speter
266038032Speter
266138032Speter/*
266238032Speter**  NIS_MAP_LOOKUP -- look up a datum in a NIS map
266338032Speter*/
266438032Speter
266538032Speter/* ARGSUSED3 */
266638032Speterchar *
266738032Speternis_map_lookup(map, name, av, statp)
266838032Speter	MAP *map;
266938032Speter	char *name;
267038032Speter	char **av;
267138032Speter	int *statp;
267238032Speter{
267338032Speter	char *vp;
267438032Speter	auto int vsize;
267538032Speter	int buflen;
267638032Speter	int yperr;
267738032Speter	char keybuf[MAXNAME + 1];
267890792Sgshapiro	char *SM_NONVOLATILE result = NULL;
267938032Speter
268038032Speter	if (tTd(38, 20))
268190792Sgshapiro		sm_dprintf("nis_map_lookup(%s, %s)\n",
268238032Speter			map->map_mname, name);
268338032Speter
268438032Speter	buflen = strlen(name);
268538032Speter	if (buflen > sizeof keybuf - 1)
268638032Speter		buflen = sizeof keybuf - 1;
268764562Sgshapiro	memmove(keybuf, name, buflen);
268838032Speter	keybuf[buflen] = '\0';
268938032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
269038032Speter		makelower(keybuf);
269138032Speter	yperr = YPERR_KEY;
269264562Sgshapiro	vp = NULL;
269338032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
269438032Speter	{
269538032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
269638032Speter			     &vp, &vsize);
269738032Speter		if (yperr == 0)
269838032Speter			map->map_mflags &= ~MF_TRY1NULL;
269938032Speter	}
270038032Speter	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
270138032Speter	{
270290792Sgshapiro		SM_FREE_CLR(vp);
270338032Speter		buflen++;
270438032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
270538032Speter			     &vp, &vsize);
270638032Speter		if (yperr == 0)
270738032Speter			map->map_mflags &= ~MF_TRY0NULL;
270838032Speter	}
270938032Speter	if (yperr != 0)
271038032Speter	{
271138032Speter		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
271238032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
271364562Sgshapiro		if (vp != NULL)
271477349Sgshapiro			sm_free(vp);
271538032Speter		return NULL;
271638032Speter	}
271790792Sgshapiro	SM_TRY
271890792Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
271990792Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
272090792Sgshapiro		else
272190792Sgshapiro			result = map_rewrite(map, vp, vsize, av);
272290792Sgshapiro	SM_FINALLY
272364562Sgshapiro		if (vp != NULL)
272477349Sgshapiro			sm_free(vp);
272590792Sgshapiro	SM_END_TRY
272690792Sgshapiro	return result;
272738032Speter}
272838032Speter
272938032Speter
273038032Speter/*
273138032Speter**  NIS_GETCANONNAME -- look up canonical name in NIS
273238032Speter*/
273338032Speter
273464562Sgshapirostatic bool
273538032Speternis_getcanonname(name, hbsize, statp)
273638032Speter	char *name;
273738032Speter	int hbsize;
273838032Speter	int *statp;
273938032Speter{
274038032Speter	char *vp;
274138032Speter	auto int vsize;
274238032Speter	int keylen;
274338032Speter	int yperr;
274490792Sgshapiro	static bool try0null = true;
274590792Sgshapiro	static bool try1null = true;
274638032Speter	static char *yp_domain = NULL;
274738032Speter	char host_record[MAXLINE];
274838032Speter	char cbuf[MAXNAME];
274938032Speter	char nbuf[MAXNAME + 1];
275038032Speter
275138032Speter	if (tTd(38, 20))
275290792Sgshapiro		sm_dprintf("nis_getcanonname(%s)\n", name);
275338032Speter
275490792Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
275538032Speter	{
275638032Speter		*statp = EX_UNAVAILABLE;
275790792Sgshapiro		return false;
275838032Speter	}
275973188Sgshapiro	(void) shorten_hostname(nbuf);
276038032Speter	keylen = strlen(nbuf);
276138032Speter
276238032Speter	if (yp_domain == NULL)
276364562Sgshapiro		(void) yp_get_default_domain(&yp_domain);
276438032Speter	makelower(nbuf);
276538032Speter	yperr = YPERR_KEY;
276664562Sgshapiro	vp = NULL;
276738032Speter	if (try0null)
276838032Speter	{
276938032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
277038032Speter			     &vp, &vsize);
277138032Speter		if (yperr == 0)
277290792Sgshapiro			try1null = false;
277338032Speter	}
277438032Speter	if (yperr == YPERR_KEY && try1null)
277538032Speter	{
277690792Sgshapiro		SM_FREE_CLR(vp);
277738032Speter		keylen++;
277838032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
277938032Speter			     &vp, &vsize);
278038032Speter		if (yperr == 0)
278190792Sgshapiro			try0null = false;
278238032Speter	}
278338032Speter	if (yperr != 0)
278438032Speter	{
278538032Speter		if (yperr == YPERR_KEY)
278638032Speter			*statp = EX_NOHOST;
278738032Speter		else if (yperr == YPERR_BUSY)
278838032Speter			*statp = EX_TEMPFAIL;
278938032Speter		else
279038032Speter			*statp = EX_UNAVAILABLE;
279164562Sgshapiro		if (vp != NULL)
279277349Sgshapiro			sm_free(vp);
279390792Sgshapiro		return false;
279438032Speter	}
279590792Sgshapiro	(void) sm_strlcpy(host_record, vp, sizeof host_record);
279677349Sgshapiro	sm_free(vp);
279738032Speter	if (tTd(38, 44))
279890792Sgshapiro		sm_dprintf("got record `%s'\n", host_record);
279990792Sgshapiro	vp = strpbrk(host_record, "#\n");
280090792Sgshapiro	if (vp != NULL)
280190792Sgshapiro		*vp = '\0';
280273188Sgshapiro	if (!extract_canonname(nbuf, NULL, host_record, cbuf, sizeof cbuf))
280338032Speter	{
280438032Speter		/* this should not happen, but.... */
280538032Speter		*statp = EX_NOHOST;
280690792Sgshapiro		return false;
280738032Speter	}
280890792Sgshapiro	if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
280938032Speter	{
281038032Speter		*statp = EX_UNAVAILABLE;
281190792Sgshapiro		return false;
281238032Speter	}
281338032Speter	*statp = EX_OK;
281490792Sgshapiro	return true;
281538032Speter}
281638032Speter
281764562Sgshapiro#endif /* NIS */
281890792Sgshapiro/*
281938032Speter**  NISPLUS Modules
282038032Speter**
282138032Speter**	This code donated by Sun Microsystems.
282238032Speter*/
282338032Speter
282490792Sgshapiro#if NISPLUS
282538032Speter
282664562Sgshapiro# undef NIS		/* symbol conflict in nis.h */
282764562Sgshapiro# undef T_UNSPEC	/* symbol conflict in nis.h -> ... -> sys/tiuser.h */
282864562Sgshapiro# include <rpcsvc/nis.h>
282964562Sgshapiro# include <rpcsvc/nislib.h>
283038032Speter
283164562Sgshapiro# define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
283264562Sgshapiro# define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
283364562Sgshapiro# define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
283464562Sgshapiro# define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
283538032Speter
283638032Speter/*
283738032Speter**  NISPLUS_MAP_OPEN -- open nisplus table
283838032Speter*/
283938032Speter
284038032Speterbool
284138032Speternisplus_map_open(map, mode)
284238032Speter	MAP *map;
284338032Speter	int mode;
284438032Speter{
284538032Speter	nis_result *res = NULL;
284638032Speter	int retry_cnt, max_col, i;
284738032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
284838032Speter
284938032Speter	if (tTd(38, 2))
285090792Sgshapiro		sm_dprintf("nisplus_map_open(%s, %s, %d)\n",
285138032Speter			map->map_mname, map->map_file, mode);
285238032Speter
285338032Speter	mode &= O_ACCMODE;
285438032Speter	if (mode != O_RDONLY)
285538032Speter	{
285638032Speter		errno = EPERM;
285790792Sgshapiro		return false;
285838032Speter	}
285938032Speter
286038032Speter	if (*map->map_file == '\0')
286138032Speter		map->map_file = "mail_aliases.org_dir";
286238032Speter
286338032Speter	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
286438032Speter	{
286538032Speter		/* set default NISPLUS Domain to $m */
286638032Speter		map->map_domain = newstr(nisplus_default_domain());
286738032Speter		if (tTd(38, 2))
286890792Sgshapiro			sm_dprintf("nisplus_map_open(%s): using domain %s\n",
286964562Sgshapiro				map->map_file, map->map_domain);
287038032Speter	}
287138032Speter	if (!PARTIAL_NAME(map->map_file))
287238032Speter	{
287338032Speter		map->map_domain = newstr("");
287490792Sgshapiro		(void) sm_strlcpy(qbuf, map->map_file, sizeof qbuf);
287538032Speter	}
287638032Speter	else
287738032Speter	{
287838032Speter		/* check to see if this map actually exists */
287990792Sgshapiro		(void) sm_strlcpyn(qbuf, sizeof qbuf, 3,
288090792Sgshapiro				   map->map_file, ".", map->map_domain);
288138032Speter	}
288238032Speter
288338032Speter	retry_cnt = 0;
288438032Speter	while (res == NULL || res->status != NIS_SUCCESS)
288538032Speter	{
288638032Speter		res = nis_lookup(qbuf, FOLLOW_LINKS);
288738032Speter		switch (res->status)
288838032Speter		{
288938032Speter		  case NIS_SUCCESS:
289038032Speter			break;
289138032Speter
289238032Speter		  case NIS_TRYAGAIN:
289338032Speter		  case NIS_RPCERROR:
289438032Speter		  case NIS_NAMEUNREACHABLE:
289538032Speter			if (retry_cnt++ > 4)
289638032Speter			{
289738032Speter				errno = EAGAIN;
289890792Sgshapiro				return false;
289938032Speter			}
290038032Speter			/* try not to overwhelm hosed server */
290138032Speter			sleep(2);
290238032Speter			break;
290338032Speter
290438032Speter		  default:		/* all other nisplus errors */
290564562Sgshapiro# if 0
290638032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
290794334Sgshapiro				syserr("451 4.3.5 Cannot find table %s.%s: %s",
290838032Speter					map->map_file, map->map_domain,
290938032Speter					nis_sperrno(res->status));
291064562Sgshapiro# endif /* 0 */
291138032Speter			errno = EAGAIN;
291290792Sgshapiro			return false;
291338032Speter		}
291438032Speter	}
291538032Speter
291638032Speter	if (NIS_RES_NUMOBJ(res) != 1 ||
291738032Speter	    (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
291838032Speter	{
291938032Speter		if (tTd(38, 10))
292090792Sgshapiro			sm_dprintf("nisplus_map_open: %s is not a table\n", qbuf);
292164562Sgshapiro# if 0
292238032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
292394334Sgshapiro			syserr("451 4.3.5 %s.%s: %s is not a table",
292438032Speter				map->map_file, map->map_domain,
292538032Speter				nis_sperrno(res->status));
292664562Sgshapiro# endif /* 0 */
292738032Speter		errno = EBADF;
292890792Sgshapiro		return false;
292938032Speter	}
293038032Speter	/* default key column is column 0 */
293138032Speter	if (map->map_keycolnm == NULL)
293238032Speter		map->map_keycolnm = newstr(COL_NAME(res,0));
293338032Speter
293438032Speter	max_col = COL_MAX(res);
293538032Speter
293638032Speter	/* verify the key column exist */
293790792Sgshapiro	for (i = 0; i < max_col; i++)
293838032Speter	{
293964562Sgshapiro		if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0)
294038032Speter			break;
294138032Speter	}
294238032Speter	if (i == max_col)
294338032Speter	{
294438032Speter		if (tTd(38, 2))
294590792Sgshapiro			sm_dprintf("nisplus_map_open(%s): can not find key column %s\n",
294638032Speter				map->map_file, map->map_keycolnm);
294738032Speter		errno = ENOENT;
294890792Sgshapiro		return false;
294938032Speter	}
295038032Speter
295138032Speter	/* default value column is the last column */
295238032Speter	if (map->map_valcolnm == NULL)
295338032Speter	{
295438032Speter		map->map_valcolno = max_col - 1;
295590792Sgshapiro		return true;
295638032Speter	}
295738032Speter
295864562Sgshapiro	for (i = 0; i< max_col; i++)
295938032Speter	{
296038032Speter		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
296138032Speter		{
296238032Speter			map->map_valcolno = i;
296390792Sgshapiro			return true;
296438032Speter		}
296538032Speter	}
296638032Speter
296738032Speter	if (tTd(38, 2))
296890792Sgshapiro		sm_dprintf("nisplus_map_open(%s): can not find column %s\n",
296964562Sgshapiro			map->map_file, map->map_keycolnm);
297038032Speter	errno = ENOENT;
297190792Sgshapiro	return false;
297238032Speter}
297338032Speter
297438032Speter
297538032Speter/*
297638032Speter**  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
297738032Speter*/
297838032Speter
297938032Speterchar *
298038032Speternisplus_map_lookup(map, name, av, statp)
298138032Speter	MAP *map;
298238032Speter	char *name;
298338032Speter	char **av;
298438032Speter	int *statp;
298538032Speter{
298638032Speter	char *p;
298738032Speter	auto int vsize;
298838032Speter	char *skp;
298938032Speter	int skleft;
299038032Speter	char search_key[MAXNAME + 4];
299138032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
299238032Speter	nis_result *result;
299338032Speter
299438032Speter	if (tTd(38, 20))
299590792Sgshapiro		sm_dprintf("nisplus_map_lookup(%s, %s)\n",
299638032Speter			map->map_mname, name);
299738032Speter
299838032Speter	if (!bitset(MF_OPEN, map->map_mflags))
299938032Speter	{
300038032Speter		if (nisplus_map_open(map, O_RDONLY))
300142575Speter		{
300238032Speter			map->map_mflags |= MF_OPEN;
300390792Sgshapiro			map->map_pid = CurrentPid;
300442575Speter		}
300538032Speter		else
300638032Speter		{
300738032Speter			*statp = EX_UNAVAILABLE;
300838032Speter			return NULL;
300938032Speter		}
301038032Speter	}
301138032Speter
301238032Speter	/*
301338032Speter	**  Copy the name to the key buffer, escaping double quote characters
301438032Speter	**  by doubling them and quoting "]" and "," to avoid having the
301538032Speter	**  NIS+ parser choke on them.
301638032Speter	*/
301738032Speter
301838032Speter	skleft = sizeof search_key - 4;
301938032Speter	skp = search_key;
302038032Speter	for (p = name; *p != '\0' && skleft > 0; p++)
302138032Speter	{
302238032Speter		switch (*p)
302338032Speter		{
302438032Speter		  case ']':
302538032Speter		  case ',':
302638032Speter			/* quote the character */
302738032Speter			*skp++ = '"';
302838032Speter			*skp++ = *p;
302938032Speter			*skp++ = '"';
303038032Speter			skleft -= 3;
303138032Speter			break;
303238032Speter
303338032Speter		  case '"':
303438032Speter			/* double the quote */
303538032Speter			*skp++ = '"';
303638032Speter			skleft--;
303764562Sgshapiro			/* FALLTHROUGH */
303838032Speter
303938032Speter		  default:
304038032Speter			*skp++ = *p;
304138032Speter			skleft--;
304238032Speter			break;
304338032Speter		}
304438032Speter	}
304538032Speter	*skp = '\0';
304638032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
304738032Speter		makelower(search_key);
304838032Speter
304938032Speter	/* construct the query */
305038032Speter	if (PARTIAL_NAME(map->map_file))
305190792Sgshapiro		(void) sm_snprintf(qbuf, sizeof qbuf, "[%s=%s],%s.%s",
305238032Speter			map->map_keycolnm, search_key, map->map_file,
305338032Speter			map->map_domain);
305438032Speter	else
305590792Sgshapiro		(void) sm_snprintf(qbuf, sizeof qbuf, "[%s=%s],%s",
305638032Speter			map->map_keycolnm, search_key, map->map_file);
305738032Speter
305838032Speter	if (tTd(38, 20))
305990792Sgshapiro		sm_dprintf("qbuf=%s\n", qbuf);
306038032Speter	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
306138032Speter	if (result->status == NIS_SUCCESS)
306238032Speter	{
306338032Speter		int count;
306438032Speter		char *str;
306538032Speter
306638032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
306738032Speter		{
306838032Speter			if (LogLevel > 10)
306938032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
307064562Sgshapiro					  "%s: lookup error, expected 1 entry, got %d",
307164562Sgshapiro					  map->map_file, count);
307238032Speter
307338032Speter			/* ignore second entry */
307438032Speter			if (tTd(38, 20))
307590792Sgshapiro				sm_dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
307638032Speter					name, count);
307738032Speter		}
307838032Speter
307938032Speter		p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
308038032Speter		/* set the length of the result */
308138032Speter		if (p == NULL)
308238032Speter			p = "";
308338032Speter		vsize = strlen(p);
308438032Speter		if (tTd(38, 20))
308590792Sgshapiro			sm_dprintf("nisplus_map_lookup(%s), found %s\n",
308638032Speter				name, p);
308738032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
308838032Speter			str = map_rewrite(map, name, strlen(name), NULL);
308938032Speter		else
309038032Speter			str = map_rewrite(map, p, vsize, av);
309138032Speter		nis_freeresult(result);
309238032Speter		*statp = EX_OK;
309338032Speter		return str;
309438032Speter	}
309538032Speter	else
309638032Speter	{
309738032Speter		if (result->status == NIS_NOTFOUND)
309838032Speter			*statp = EX_NOTFOUND;
309938032Speter		else if (result->status == NIS_TRYAGAIN)
310038032Speter			*statp = EX_TEMPFAIL;
310138032Speter		else
310238032Speter		{
310338032Speter			*statp = EX_UNAVAILABLE;
310438032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
310538032Speter		}
310638032Speter	}
310738032Speter	if (tTd(38, 20))
310890792Sgshapiro		sm_dprintf("nisplus_map_lookup(%s), failed\n", name);
310938032Speter	nis_freeresult(result);
311038032Speter	return NULL;
311138032Speter}
311238032Speter
311338032Speter
311438032Speter
311538032Speter/*
311638032Speter**  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
311738032Speter*/
311838032Speter
311964562Sgshapirostatic bool
312038032Speternisplus_getcanonname(name, hbsize, statp)
312138032Speter	char *name;
312238032Speter	int hbsize;
312338032Speter	int *statp;
312438032Speter{
312538032Speter	char *vp;
312638032Speter	auto int vsize;
312738032Speter	nis_result *result;
312838032Speter	char *p;
312938032Speter	char nbuf[MAXNAME + 1];
313038032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
313138032Speter
313290792Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
313338032Speter	{
313438032Speter		*statp = EX_UNAVAILABLE;
313590792Sgshapiro		return false;
313638032Speter	}
313773188Sgshapiro	(void) shorten_hostname(nbuf);
313838032Speter
313938032Speter	p = strchr(nbuf, '.');
314038032Speter	if (p == NULL)
314138032Speter	{
314238032Speter		/* single token */
314390792Sgshapiro		(void) sm_snprintf(qbuf, sizeof qbuf,
314490792Sgshapiro			"[name=%s],hosts.org_dir", nbuf);
314538032Speter	}
314638032Speter	else if (p[1] != '\0')
314738032Speter	{
314838032Speter		/* multi token -- take only first token in nbuf */
314938032Speter		*p = '\0';
315090792Sgshapiro		(void) sm_snprintf(qbuf, sizeof qbuf,
315190792Sgshapiro				   "[name=%s],hosts.org_dir.%s", nbuf, &p[1]);
315238032Speter	}
315338032Speter	else
315438032Speter	{
315538032Speter		*statp = EX_NOHOST;
315690792Sgshapiro		return false;
315738032Speter	}
315838032Speter
315938032Speter	if (tTd(38, 20))
316094334Sgshapiro		sm_dprintf("\nnisplus_getcanonname(%s), qbuf=%s\n",
316190792Sgshapiro			   name, qbuf);
316238032Speter
316338032Speter	result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
316490792Sgshapiro			  NULL, NULL);
316538032Speter
316638032Speter	if (result->status == NIS_SUCCESS)
316738032Speter	{
316838032Speter		int count;
316938032Speter		char *domain;
317038032Speter
317138032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
317238032Speter		{
317338032Speter			if (LogLevel > 10)
317438032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
317564562Sgshapiro					  "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
317664562Sgshapiro					  count);
317738032Speter
317838032Speter			/* ignore second entry */
317938032Speter			if (tTd(38, 20))
318094334Sgshapiro				sm_dprintf("nisplus_getcanonname(%s), got %d entries, all but first ignored\n",
318190792Sgshapiro					   name, count);
318238032Speter		}
318338032Speter
318438032Speter		if (tTd(38, 20))
318594334Sgshapiro			sm_dprintf("nisplus_getcanonname(%s), found in directory \"%s\"\n",
318690792Sgshapiro				   name, (NIS_RES_OBJECT(result))->zo_domain);
318738032Speter
318838032Speter
318938032Speter		vp = ((NIS_RES_OBJECT(result))->EN_col(0));
319038032Speter		vsize = strlen(vp);
319138032Speter		if (tTd(38, 20))
319290792Sgshapiro			sm_dprintf("nisplus_getcanonname(%s), found %s\n",
319390792Sgshapiro				   name, vp);
319438032Speter		if (strchr(vp, '.') != NULL)
319538032Speter		{
319638032Speter			domain = "";
319738032Speter		}
319838032Speter		else
319938032Speter		{
320038032Speter			domain = macvalue('m', CurEnv);
320138032Speter			if (domain == NULL)
320238032Speter				domain = "";
320338032Speter		}
320438032Speter		if (hbsize > vsize + (int) strlen(domain) + 1)
320538032Speter		{
320638032Speter			if (domain[0] == '\0')
320790792Sgshapiro				(void) sm_strlcpy(name, vp, hbsize);
320838032Speter			else
320990792Sgshapiro				(void) sm_snprintf(name, hbsize,
321090792Sgshapiro						   "%s.%s", vp, domain);
321138032Speter			*statp = EX_OK;
321238032Speter		}
321338032Speter		else
321438032Speter			*statp = EX_NOHOST;
321538032Speter		nis_freeresult(result);
321690792Sgshapiro		return true;
321738032Speter	}
321838032Speter	else
321938032Speter	{
322038032Speter		if (result->status == NIS_NOTFOUND)
322138032Speter			*statp = EX_NOHOST;
322238032Speter		else if (result->status == NIS_TRYAGAIN)
322338032Speter			*statp = EX_TEMPFAIL;
322438032Speter		else
322538032Speter			*statp = EX_UNAVAILABLE;
322638032Speter	}
322738032Speter	if (tTd(38, 20))
322890792Sgshapiro		sm_dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
322990792Sgshapiro			   name, result->status, *statp);
323038032Speter	nis_freeresult(result);
323190792Sgshapiro	return false;
323238032Speter}
323338032Speter
323438032Speterchar *
323538032Speternisplus_default_domain()
323638032Speter{
323738032Speter	static char default_domain[MAXNAME + 1] = "";
323838032Speter	char *p;
323938032Speter
324038032Speter	if (default_domain[0] != '\0')
324164562Sgshapiro		return default_domain;
324238032Speter
324338032Speter	p = nis_local_directory();
324490792Sgshapiro	(void) sm_strlcpy(default_domain, p, sizeof default_domain);
324538032Speter	return default_domain;
324638032Speter}
324738032Speter
324838032Speter#endif /* NISPLUS */
324990792Sgshapiro/*
325038032Speter**  LDAP Modules
325138032Speter*/
325238032Speter
325364562Sgshapiro/*
325464562Sgshapiro**  LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs
325564562Sgshapiro*/
325664562Sgshapiro
325764562Sgshapiro#if defined(LDAPMAP) || defined(PH_MAP)
325864562Sgshapiro
325990792Sgshapiro# if PH_MAP
326064562Sgshapiro#  define ph_map_dequote ldapmap_dequote
326164562Sgshapiro# endif /* PH_MAP */
326264562Sgshapiro
326390792Sgshapirostatic char *ldapmap_dequote __P((char *));
326490792Sgshapiro
326590792Sgshapirostatic char *
326664562Sgshapiroldapmap_dequote(str)
326764562Sgshapiro	char *str;
326864562Sgshapiro{
326964562Sgshapiro	char *p;
327064562Sgshapiro	char *start;
327164562Sgshapiro
327264562Sgshapiro	if (str == NULL)
327364562Sgshapiro		return NULL;
327464562Sgshapiro
327564562Sgshapiro	p = str;
327664562Sgshapiro	if (*p == '"')
327764562Sgshapiro	{
327864562Sgshapiro		/* Should probably swallow initial whitespace here */
327964562Sgshapiro		start = ++p;
328064562Sgshapiro	}
328164562Sgshapiro	else
328264562Sgshapiro		return str;
328364562Sgshapiro	while (*p != '"' && *p != '\0')
328464562Sgshapiro		p++;
328564562Sgshapiro	if (*p != '\0')
328664562Sgshapiro		*p = '\0';
328764562Sgshapiro	return start;
328864562Sgshapiro}
328964562Sgshapiro#endif /* defined(LDAPMAP) || defined(PH_MAP) */
329064562Sgshapiro
329190792Sgshapiro#if LDAPMAP
329238032Speter
329390792Sgshapirostatic SM_LDAP_STRUCT *LDAPDefaults = NULL;
329438032Speter
329538032Speter/*
329664562Sgshapiro**  LDAPMAP_OPEN -- open LDAP map
329738032Speter**
329864562Sgshapiro**	Connect to the LDAP server.  Re-use existing connections since a
329964562Sgshapiro**	single server connection to a host (with the same host, port,
330064562Sgshapiro**	bind DN, and secret) can answer queries for multiple maps.
330138032Speter*/
330238032Speter
330338032Speterbool
330464562Sgshapiroldapmap_open(map, mode)
330538032Speter	MAP *map;
330638032Speter	int mode;
330738032Speter{
330890792Sgshapiro	SM_LDAP_STRUCT *lmap;
330964562Sgshapiro	STAB *s;
331064562Sgshapiro
331138032Speter	if (tTd(38, 2))
331290792Sgshapiro		sm_dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode);
331338032Speter
331438032Speter	mode &= O_ACCMODE;
331564562Sgshapiro
331664562Sgshapiro	/* sendmail doesn't have the ability to write to LDAP (yet) */
331738032Speter	if (mode != O_RDONLY)
331838032Speter	{
331938032Speter		/* issue a pseudo-error message */
332090792Sgshapiro		errno = SM_EMAPCANTWRITE;
332190792Sgshapiro		return false;
332238032Speter	}
332364562Sgshapiro
332490792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
332564562Sgshapiro
332664562Sgshapiro	s = ldapmap_findconn(lmap);
332777349Sgshapiro	if (s->s_lmap != NULL)
332864562Sgshapiro	{
332964562Sgshapiro		/* Already have a connection open to this LDAP server */
333090792Sgshapiro		lmap->ldap_ld = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_ld;
333190792Sgshapiro		lmap->ldap_pid = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_pid;
333277349Sgshapiro
333377349Sgshapiro		/* Add this map as head of linked list */
333477349Sgshapiro		lmap->ldap_next = s->s_lmap;
333577349Sgshapiro		s->s_lmap = map;
333677349Sgshapiro
333766494Sgshapiro		if (tTd(38, 2))
333890792Sgshapiro			sm_dprintf("using cached connection\n");
333990792Sgshapiro		return true;
334064562Sgshapiro	}
334164562Sgshapiro
334266494Sgshapiro	if (tTd(38, 2))
334390792Sgshapiro		sm_dprintf("opening new connection\n");
334466494Sgshapiro
334564562Sgshapiro	/* No connection yet, connect */
334690792Sgshapiro	if (!sm_ldap_start(map->map_mname, lmap))
334738032Speter	{
334890792Sgshapiro		if (errno == ETIMEDOUT)
334938032Speter		{
335038032Speter			if (LogLevel > 1)
335138032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
335264562Sgshapiro					  "timeout conning to LDAP server %.100s",
335394334Sgshapiro					  lmap->ldap_target == NULL ? "localhost" : lmap->ldap_target);
335438032Speter		}
335538032Speter
335638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
335738032Speter		{
335864562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
335964562Sgshapiro				syserr("%s failed to %s in map %s",
336064562Sgshapiro# if USE_LDAP_INIT
336190792Sgshapiro				       "ldap_init/ldap_bind",
336264562Sgshapiro# else /* USE_LDAP_INIT */
336364562Sgshapiro				       "ldap_open",
336464562Sgshapiro# endif /* USE_LDAP_INIT */
336594334Sgshapiro				       lmap->ldap_target == NULL ? "localhost"
336694334Sgshapiro								 : lmap->ldap_target,
336764562Sgshapiro				       map->map_mname);
336864562Sgshapiro			else
336994334Sgshapiro				syserr("451 4.3.5 %s failed to %s in map %s",
337064562Sgshapiro# if USE_LDAP_INIT
337190792Sgshapiro				       "ldap_init/ldap_bind",
337264562Sgshapiro# else /* USE_LDAP_INIT */
337364562Sgshapiro				       "ldap_open",
337464562Sgshapiro# endif /* USE_LDAP_INIT */
337594334Sgshapiro				       lmap->ldap_target == NULL ? "localhost"
337694334Sgshapiro								 : lmap->ldap_target,
337764562Sgshapiro				       map->map_mname);
337838032Speter		}
337990792Sgshapiro		return false;
338038032Speter	}
338138032Speter
338290792Sgshapiro	/* Save connection for reuse */
338390792Sgshapiro	s->s_lmap = map;
338490792Sgshapiro	return true;
338538032Speter}
338638032Speter
338738032Speter/*
338864562Sgshapiro**  LDAPMAP_CLOSE -- close ldap map
338938032Speter*/
339038032Speter
339138032Spetervoid
339264562Sgshapiroldapmap_close(map)
339338032Speter	MAP *map;
339438032Speter{
339590792Sgshapiro	SM_LDAP_STRUCT *lmap;
339664562Sgshapiro	STAB *s;
339743730Speter
339864562Sgshapiro	if (tTd(38, 2))
339990792Sgshapiro		sm_dprintf("ldapmap_close(%s)\n", map->map_mname);
340064562Sgshapiro
340190792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
340264562Sgshapiro
340364562Sgshapiro	/* Check if already closed */
340464562Sgshapiro	if (lmap->ldap_ld == NULL)
340564562Sgshapiro		return;
340664562Sgshapiro
340777349Sgshapiro	/* Close the LDAP connection */
340890792Sgshapiro	sm_ldap_close(lmap);
340977349Sgshapiro
341077349Sgshapiro	/* Mark all the maps that share the connection as closed */
341164562Sgshapiro	s = ldapmap_findconn(lmap);
341264562Sgshapiro
341377349Sgshapiro	while (s->s_lmap != NULL)
341477349Sgshapiro	{
341577349Sgshapiro		MAP *smap = s->s_lmap;
341664562Sgshapiro
341777349Sgshapiro		if (tTd(38, 2) && smap != map)
341890792Sgshapiro			sm_dprintf("ldapmap_close(%s): closed %s (shared LDAP connection)\n",
341990792Sgshapiro				   map->map_mname, smap->map_mname);
342077349Sgshapiro		smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
342190792Sgshapiro		lmap = (SM_LDAP_STRUCT *) smap->map_db1;
342264562Sgshapiro		lmap->ldap_ld = NULL;
342377349Sgshapiro		s->s_lmap = lmap->ldap_next;
342477349Sgshapiro		lmap->ldap_next = NULL;
342543730Speter	}
342638032Speter}
342738032Speter
342864562Sgshapiro# ifdef SUNET_ID
342943730Speter/*
343090792Sgshapiro**  SUNET_ID_HASH -- Convert a string to its Sunet_id canonical form
343142575Speter**  This only makes sense at Stanford University.
343238032Speter*/
343338032Speter
343490792Sgshapirostatic char *
343538032Spetersunet_id_hash(str)
343638032Speter	char *str;
343738032Speter{
343838032Speter	char *p, *p_last;
343938032Speter
344038032Speter	p = str;
344138032Speter	p_last = p;
344238032Speter	while (*p != '\0')
344338032Speter	{
344438032Speter		if (islower(*p) || isdigit(*p))
344538032Speter		{
344638032Speter			*p_last = *p;
344738032Speter			p_last++;
344838032Speter		}
344938032Speter		else if (isupper(*p))
345038032Speter		{
345138032Speter			*p_last = tolower(*p);
345238032Speter			p_last++;
345338032Speter		}
345438032Speter		++p;
345538032Speter	}
345638032Speter	if (*p_last != '\0')
345738032Speter		*p_last = '\0';
345864562Sgshapiro	return str;
345938032Speter}
346064562Sgshapiro# endif /* SUNET_ID */
346138032Speter
346238032Speter/*
346364562Sgshapiro**  LDAPMAP_LOOKUP -- look up a datum in a LDAP map
346438032Speter*/
346538032Speter
346638032Speterchar *
346764562Sgshapiroldapmap_lookup(map, name, av, statp)
346838032Speter	MAP *map;
346938032Speter	char *name;
347038032Speter	char **av;
347138032Speter	int *statp;
347238032Speter{
347394334Sgshapiro# if _FFR_LDAP_RECURSION
347494334Sgshapiro	int plen = 0;
347594334Sgshapiro	int psize = 0;
347694334Sgshapiro# else /* _FFR_LDAP_RECURSION */
347794334Sgshapiro	int entries = 0;
347864562Sgshapiro	int i;
347994334Sgshapiro	int ret;
348094334Sgshapiro	int vsize;
348194334Sgshapiro# endif /* _FFR_LDAP_RECURSION */
348264562Sgshapiro	int msgid;
348390792Sgshapiro	int save_errno;
348490792Sgshapiro	char *vp, *p;
348564562Sgshapiro	char *result = NULL;
348690792Sgshapiro	SM_LDAP_STRUCT *lmap = NULL;
348738032Speter	char keybuf[MAXNAME + 1];
348838032Speter
348938032Speter	if (tTd(38, 20))
349090792Sgshapiro		sm_dprintf("ldapmap_lookup(%s, %s)\n", map->map_mname, name);
349138032Speter
349238032Speter	/* Get ldap struct pointer from map */
349390792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
349490792Sgshapiro	sm_ldap_setopts(lmap->ldap_ld, lmap);
349538032Speter
349690792Sgshapiro	(void) sm_strlcpy(keybuf, name, sizeof keybuf);
349738032Speter
349838032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
349964562Sgshapiro	{
350064562Sgshapiro# ifdef SUNET_ID
350138032Speter		sunet_id_hash(keybuf);
350264562Sgshapiro# else /* SUNET_ID */
350338032Speter		makelower(keybuf);
350464562Sgshapiro# endif /* SUNET_ID */
350564562Sgshapiro	}
350638032Speter
350790792Sgshapiro	msgid = sm_ldap_search(lmap, keybuf);
350864562Sgshapiro	if (msgid == -1)
350938032Speter	{
351090792Sgshapiro		errno = sm_ldap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
351177349Sgshapiro		save_errno = errno;
351264562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
351338032Speter		{
351464562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
351566494Sgshapiro				syserr("Error in ldap_search using %s in map %s",
351690792Sgshapiro				       keybuf, map->map_mname);
351764562Sgshapiro			else
351894334Sgshapiro				syserr("451 4.3.5 Error in ldap_search using %s in map %s",
351990792Sgshapiro				       keybuf, map->map_mname);
352038032Speter		}
352164562Sgshapiro		*statp = EX_TEMPFAIL;
352290792Sgshapiro		switch (save_errno - E_LDAPBASE)
352390792Sgshapiro		{
352494334Sgshapiro# ifdef LDAP_SERVER_DOWN
352590792Sgshapiro		  case LDAP_SERVER_DOWN:
352694334Sgshapiro# endif /* LDAP_SERVER_DOWN */
352790792Sgshapiro		  case LDAP_TIMEOUT:
352890792Sgshapiro		  case LDAP_UNAVAILABLE:
352966494Sgshapiro			/* server disappeared, try reopen on next search */
353077349Sgshapiro			ldapmap_close(map);
353190792Sgshapiro			break;
353266494Sgshapiro		}
353377349Sgshapiro		errno = save_errno;
353464562Sgshapiro		return NULL;
353564562Sgshapiro	}
353664562Sgshapiro
353764562Sgshapiro	*statp = EX_NOTFOUND;
353864562Sgshapiro	vp = NULL;
353964562Sgshapiro
354090792Sgshapiro# if _FFR_LDAP_RECURSION
354190792Sgshapiro	{
354290792Sgshapiro		int flags;
354390792Sgshapiro		SM_RPOOL_T *rpool;
354490792Sgshapiro
354590792Sgshapiro		flags = 0;
354690792Sgshapiro		if (bitset(MF_SINGLEMATCH, map->map_mflags))
354790792Sgshapiro			flags |= SM_LDAP_SINGLEMATCH;
354890792Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
354990792Sgshapiro			flags |= SM_LDAP_MATCHONLY;
355090792Sgshapiro
355190792Sgshapiro		/* Create an rpool for search related memory usage */
355290792Sgshapiro		rpool = sm_rpool_new_x(NULL);
355390792Sgshapiro
355490792Sgshapiro		p = NULL;
355590792Sgshapiro		*statp = sm_ldap_results(lmap, msgid, flags, map->map_coldelim,
355694334Sgshapiro					 rpool, &p, &plen, &psize, NULL);
355790792Sgshapiro		save_errno = errno;
355890792Sgshapiro
355990792Sgshapiro		/* Copy result so rpool can be freed */
356090792Sgshapiro		if (*statp == EX_OK && p != NULL)
356190792Sgshapiro			vp = newstr(p);
356290792Sgshapiro		sm_rpool_free(rpool);
356390792Sgshapiro
356490792Sgshapiro		/* need to restart LDAP connection? */
356590792Sgshapiro		if (*statp == EX_RESTART)
356690792Sgshapiro		{
356790792Sgshapiro			*statp = EX_TEMPFAIL;
356890792Sgshapiro			ldapmap_close(map);
356990792Sgshapiro		}
357090792Sgshapiro
357190792Sgshapiro		errno = save_errno;
357290792Sgshapiro		if (*statp != EX_OK && *statp != EX_NOTFOUND)
357390792Sgshapiro		{
357490792Sgshapiro			if (!bitset(MF_OPTIONAL, map->map_mflags))
357590792Sgshapiro			{
357690792Sgshapiro				if (bitset(MF_NODEFER, map->map_mflags))
357790792Sgshapiro					syserr("Error getting LDAP results in map %s",
357890792Sgshapiro					       map->map_mname);
357990792Sgshapiro				else
358094334Sgshapiro					syserr("451 4.3.5 Error getting LDAP results in map %s",
358190792Sgshapiro					       map->map_mname);
358290792Sgshapiro			}
358390792Sgshapiro			errno = save_errno;
358490792Sgshapiro			return NULL;
358590792Sgshapiro		}
358690792Sgshapiro	}
358794334Sgshapiro# else /* _FFR_LDAP_RECURSION */
358890792Sgshapiro
358990792Sgshapiro	/* Get results */
359090792Sgshapiro	while ((ret = ldap_result(lmap->ldap_ld, msgid, 0,
359164562Sgshapiro				  (lmap->ldap_timeout.tv_sec == 0 ? NULL :
359264562Sgshapiro				   &(lmap->ldap_timeout)),
359364562Sgshapiro				  &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
359464562Sgshapiro	{
359564562Sgshapiro		LDAPMessage *entry;
359664562Sgshapiro
359764562Sgshapiro		if (bitset(MF_SINGLEMATCH, map->map_mflags))
359838032Speter		{
359964562Sgshapiro			entries += ldap_count_entries(lmap->ldap_ld,
360064562Sgshapiro						      lmap->ldap_res);
360164562Sgshapiro			if (entries > 1)
360264562Sgshapiro			{
360364562Sgshapiro				*statp = EX_NOTFOUND;
360464562Sgshapiro				if (lmap->ldap_res != NULL)
360564562Sgshapiro				{
360664562Sgshapiro					ldap_msgfree(lmap->ldap_res);
360764562Sgshapiro					lmap->ldap_res = NULL;
360864562Sgshapiro				}
360964562Sgshapiro				(void) ldap_abandon(lmap->ldap_ld, msgid);
361064562Sgshapiro				if (vp != NULL)
361190792Sgshapiro					sm_free(vp); /* XXX */
361264562Sgshapiro				if (tTd(38, 25))
361390792Sgshapiro					sm_dprintf("ldap search found multiple on a single match query\n");
361464562Sgshapiro				return NULL;
361564562Sgshapiro			}
361664562Sgshapiro		}
361764562Sgshapiro
361864562Sgshapiro		/* If we don't want multiple values and we have one, break */
361964562Sgshapiro		if (map->map_coldelim == '\0' && vp != NULL)
362064562Sgshapiro			break;
362164562Sgshapiro
362264562Sgshapiro		/* Cycle through all entries */
362364562Sgshapiro		for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
362464562Sgshapiro		     entry != NULL;
362564562Sgshapiro		     entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
362664562Sgshapiro		{
362764562Sgshapiro			BerElement *ber;
362864562Sgshapiro			char *attr;
362964562Sgshapiro			char **vals = NULL;
363064562Sgshapiro
363164562Sgshapiro			/*
363264562Sgshapiro			**  If matching only and found an entry,
363364562Sgshapiro			**  no need to spin through attributes
363464562Sgshapiro			*/
363564562Sgshapiro
363664562Sgshapiro			if (*statp == EX_OK &&
363764562Sgshapiro			    bitset(MF_MATCHONLY, map->map_mflags))
363864562Sgshapiro				continue;
363964562Sgshapiro
364094334Sgshapiro#  if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
364164562Sgshapiro			/*
364264562Sgshapiro			**  Reset value to prevent lingering
364364562Sgshapiro			**  LDAP_DECODING_ERROR due to
364464562Sgshapiro			**  OpenLDAP 1.X's hack (see below)
364564562Sgshapiro			*/
364664562Sgshapiro
364764562Sgshapiro			lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
364894334Sgshapiro#  endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
364964562Sgshapiro
365064562Sgshapiro			for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
365164562Sgshapiro							 &ber);
365264562Sgshapiro			     attr != NULL;
365364562Sgshapiro			     attr = ldap_next_attribute(lmap->ldap_ld, entry,
365464562Sgshapiro							ber))
365564562Sgshapiro			{
365664562Sgshapiro				char *tmp, *vp_tmp;
365764562Sgshapiro
365864562Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
365964562Sgshapiro				{
366064562Sgshapiro					vals = ldap_get_values(lmap->ldap_ld,
366164562Sgshapiro							       entry,
366264562Sgshapiro							       attr);
366364562Sgshapiro					if (vals == NULL)
366464562Sgshapiro					{
366590792Sgshapiro						save_errno = sm_ldap_geterrno(lmap->ldap_ld);
366690792Sgshapiro						if (save_errno == LDAP_SUCCESS)
366790792Sgshapiro						{
366890792Sgshapiro							ldap_memfree(attr);
366964562Sgshapiro							continue;
367090792Sgshapiro						}
367164562Sgshapiro
367264562Sgshapiro						/* Must be an error */
367390792Sgshapiro						save_errno += E_LDAPBASE;
367464562Sgshapiro						if (!bitset(MF_OPTIONAL,
367564562Sgshapiro							    map->map_mflags))
367664562Sgshapiro						{
367790792Sgshapiro							errno = save_errno;
367864562Sgshapiro							if (bitset(MF_NODEFER,
367964562Sgshapiro								   map->map_mflags))
368064562Sgshapiro								syserr("Error getting LDAP values in map %s",
368164562Sgshapiro								       map->map_mname);
368264562Sgshapiro							else
368394334Sgshapiro								syserr("451 4.3.5 Error getting LDAP values in map %s",
368464562Sgshapiro								       map->map_mname);
368564562Sgshapiro						}
368664562Sgshapiro						*statp = EX_TEMPFAIL;
368766494Sgshapiro						ldap_memfree(attr);
368864562Sgshapiro						if (lmap->ldap_res != NULL)
368964562Sgshapiro						{
369064562Sgshapiro							ldap_msgfree(lmap->ldap_res);
369164562Sgshapiro							lmap->ldap_res = NULL;
369264562Sgshapiro						}
369364562Sgshapiro						(void) ldap_abandon(lmap->ldap_ld,
369464562Sgshapiro								    msgid);
369564562Sgshapiro						if (vp != NULL)
369690792Sgshapiro							sm_free(vp); /* XXX */
369790792Sgshapiro						errno = save_errno;
369864562Sgshapiro						return NULL;
369964562Sgshapiro					}
370064562Sgshapiro				}
370164562Sgshapiro
370264562Sgshapiro				*statp = EX_OK;
370364562Sgshapiro
370494334Sgshapiro#  if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
370564562Sgshapiro				/*
370664562Sgshapiro				**  Reset value to prevent lingering
370764562Sgshapiro				**  LDAP_DECODING_ERROR due to
370864562Sgshapiro				**  OpenLDAP 1.X's hack (see below)
370964562Sgshapiro				*/
371064562Sgshapiro
371164562Sgshapiro				lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
371294334Sgshapiro#  endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
371364562Sgshapiro
371464562Sgshapiro				/*
371564562Sgshapiro				**  If matching only,
371664562Sgshapiro				**  no need to spin through entries
371764562Sgshapiro				*/
371864562Sgshapiro
371964562Sgshapiro				if (bitset(MF_MATCHONLY, map->map_mflags))
372090792Sgshapiro				{
372190792Sgshapiro					if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
372290792Sgshapiro						ldap_value_free(vals);
372390792Sgshapiro
372490792Sgshapiro					ldap_memfree(attr);
372564562Sgshapiro					continue;
372690792Sgshapiro				}
372764562Sgshapiro
372864562Sgshapiro				/*
372964562Sgshapiro				**  If we don't want multiple values,
373064562Sgshapiro				**  return first found.
373164562Sgshapiro				*/
373264562Sgshapiro
373364562Sgshapiro				if (map->map_coldelim == '\0')
373464562Sgshapiro				{
373564562Sgshapiro					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
373664562Sgshapiro					{
373764562Sgshapiro						vp = newstr(attr);
373866494Sgshapiro						ldap_memfree(attr);
373964562Sgshapiro						break;
374064562Sgshapiro					}
374164562Sgshapiro
374264562Sgshapiro					if (vals[0] == NULL)
374364562Sgshapiro					{
374464562Sgshapiro						ldap_value_free(vals);
374566494Sgshapiro						ldap_memfree(attr);
374664562Sgshapiro						continue;
374764562Sgshapiro					}
374864562Sgshapiro
374990792Sgshapiro					vsize = strlen(vals[0]) + 1;
375090792Sgshapiro					if (lmap->ldap_attrsep != '\0')
375190792Sgshapiro						vsize += strlen(attr) + 1;
375290792Sgshapiro					vp = xalloc(vsize);
375390792Sgshapiro					if (lmap->ldap_attrsep != '\0')
375490792Sgshapiro						sm_snprintf(vp, vsize,
375590792Sgshapiro							    "%s%c%s",
375690792Sgshapiro							    attr,
375790792Sgshapiro							    lmap->ldap_attrsep,
375890792Sgshapiro							    vals[0]);
375990792Sgshapiro					else
376090792Sgshapiro						sm_strlcpy(vp, vals[0], vsize);
376164562Sgshapiro					ldap_value_free(vals);
376266494Sgshapiro					ldap_memfree(attr);
376364562Sgshapiro					break;
376464562Sgshapiro				}
376564562Sgshapiro
376664562Sgshapiro				/* attributes only */
376764562Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
376864562Sgshapiro				{
376964562Sgshapiro					if (vp == NULL)
377064562Sgshapiro						vp = newstr(attr);
377164562Sgshapiro					else
377264562Sgshapiro					{
377364562Sgshapiro						vsize = strlen(vp) +
377464562Sgshapiro							strlen(attr) + 2;
377564562Sgshapiro						tmp = xalloc(vsize);
377690792Sgshapiro						(void) sm_snprintf(tmp,
377790792Sgshapiro							vsize, "%s%c%s",
377890792Sgshapiro							vp, map->map_coldelim,
377990792Sgshapiro							attr);
378090792Sgshapiro						sm_free(vp); /* XXX */
378164562Sgshapiro						vp = tmp;
378264562Sgshapiro					}
378366494Sgshapiro					ldap_memfree(attr);
378464562Sgshapiro					continue;
378564562Sgshapiro				}
378664562Sgshapiro
378764562Sgshapiro				/*
378864562Sgshapiro				**  If there is more than one,
378964562Sgshapiro				**  munge then into a map_coldelim
379064562Sgshapiro				**  separated string
379164562Sgshapiro				*/
379264562Sgshapiro
379364562Sgshapiro				vsize = 0;
379464562Sgshapiro				for (i = 0; vals[i] != NULL; i++)
379590792Sgshapiro				{
379664562Sgshapiro					vsize += strlen(vals[i]) + 1;
379790792Sgshapiro					if (lmap->ldap_attrsep != '\0')
379890792Sgshapiro						vsize += strlen(attr) + 1;
379990792Sgshapiro				}
380064562Sgshapiro				vp_tmp = xalloc(vsize);
380164562Sgshapiro				*vp_tmp = '\0';
380264562Sgshapiro
380364562Sgshapiro				p = vp_tmp;
380464562Sgshapiro				for (i = 0; vals[i] != NULL; i++)
380564562Sgshapiro				{
380690792Sgshapiro					if (lmap->ldap_attrsep != '\0')
380790792Sgshapiro					{
380890792Sgshapiro						p += sm_strlcpy(p, attr,
380990792Sgshapiro								vsize - (p - vp_tmp));
3810102528Sgshapiro						if (p >= vp_tmp + vsize)
3811102528Sgshapiro							syserr("ldapmap_lookup: Internal error: buffer too small for LDAP values");
381290792Sgshapiro						*p++ = lmap->ldap_attrsep;
381390792Sgshapiro					}
381490792Sgshapiro					p += sm_strlcpy(p, vals[i],
381590792Sgshapiro							vsize - (p - vp_tmp));
381664562Sgshapiro					if (p >= vp_tmp + vsize)
381764562Sgshapiro						syserr("ldapmap_lookup: Internal error: buffer too small for LDAP values");
381864562Sgshapiro					if (vals[i + 1] != NULL)
381964562Sgshapiro						*p++ = map->map_coldelim;
382064562Sgshapiro				}
382164562Sgshapiro
382264562Sgshapiro				ldap_value_free(vals);
382366494Sgshapiro				ldap_memfree(attr);
382464562Sgshapiro				if (vp == NULL)
382564562Sgshapiro				{
382664562Sgshapiro					vp = vp_tmp;
382764562Sgshapiro					continue;
382864562Sgshapiro				}
382964562Sgshapiro				vsize = strlen(vp) + strlen(vp_tmp) + 2;
383064562Sgshapiro				tmp = xalloc(vsize);
383190792Sgshapiro				(void) sm_snprintf(tmp, vsize, "%s%c%s",
383264562Sgshapiro					 vp, map->map_coldelim, vp_tmp);
383364562Sgshapiro
383490792Sgshapiro				sm_free(vp); /* XXX */
383590792Sgshapiro				sm_free(vp_tmp); /* XXX */
383664562Sgshapiro				vp = tmp;
383764562Sgshapiro			}
383890792Sgshapiro			save_errno = sm_ldap_geterrno(lmap->ldap_ld);
383964562Sgshapiro
384064562Sgshapiro			/*
384164562Sgshapiro			**  We check errno != LDAP_DECODING_ERROR since
384264562Sgshapiro			**  OpenLDAP 1.X has a very ugly *undocumented*
384364562Sgshapiro			**  hack of returning this error code from
384464562Sgshapiro			**  ldap_next_attribute() if the library freed the
384564562Sgshapiro			**  ber attribute.  See:
384664562Sgshapiro			**  http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
384764562Sgshapiro			*/
384864562Sgshapiro
384990792Sgshapiro			if (save_errno != LDAP_SUCCESS &&
385090792Sgshapiro			    save_errno != LDAP_DECODING_ERROR)
385164562Sgshapiro			{
385264562Sgshapiro				/* Must be an error */
385390792Sgshapiro				save_errno += E_LDAPBASE;
385464562Sgshapiro				if (!bitset(MF_OPTIONAL, map->map_mflags))
385564562Sgshapiro				{
385690792Sgshapiro					errno = save_errno;
385764562Sgshapiro					if (bitset(MF_NODEFER, map->map_mflags))
385864562Sgshapiro						syserr("Error getting LDAP attributes in map %s",
385964562Sgshapiro						       map->map_mname);
386064562Sgshapiro					else
386194334Sgshapiro						syserr("451 4.3.5 Error getting LDAP attributes in map %s",
386264562Sgshapiro						       map->map_mname);
386364562Sgshapiro				}
386464562Sgshapiro				*statp = EX_TEMPFAIL;
386564562Sgshapiro				if (lmap->ldap_res != NULL)
386664562Sgshapiro				{
386764562Sgshapiro					ldap_msgfree(lmap->ldap_res);
386864562Sgshapiro					lmap->ldap_res = NULL;
386964562Sgshapiro				}
387064562Sgshapiro				(void) ldap_abandon(lmap->ldap_ld, msgid);
387164562Sgshapiro				if (vp != NULL)
387290792Sgshapiro					sm_free(vp); /* XXX */
387390792Sgshapiro				errno = save_errno;
387464562Sgshapiro				return NULL;
387564562Sgshapiro			}
387664562Sgshapiro
387764562Sgshapiro			/* We don't want multiple values and we have one */
387864562Sgshapiro			if (map->map_coldelim == '\0' && vp != NULL)
387964562Sgshapiro				break;
388064562Sgshapiro		}
388190792Sgshapiro		save_errno = sm_ldap_geterrno(lmap->ldap_ld);
388290792Sgshapiro		if (save_errno != LDAP_SUCCESS &&
388390792Sgshapiro		    save_errno != LDAP_DECODING_ERROR)
388464562Sgshapiro		{
388564562Sgshapiro			/* Must be an error */
388690792Sgshapiro			save_errno += E_LDAPBASE;
388738032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
388838032Speter			{
388990792Sgshapiro				errno = save_errno;
389064562Sgshapiro				if (bitset(MF_NODEFER, map->map_mflags))
389164562Sgshapiro					syserr("Error getting LDAP entries in map %s",
389264562Sgshapiro					       map->map_mname);
389364562Sgshapiro				else
389494334Sgshapiro					syserr("451 4.3.5 Error getting LDAP entries in map %s",
389564562Sgshapiro					       map->map_mname);
389638032Speter			}
389738032Speter			*statp = EX_TEMPFAIL;
389864562Sgshapiro			if (lmap->ldap_res != NULL)
389964562Sgshapiro			{
390064562Sgshapiro				ldap_msgfree(lmap->ldap_res);
390164562Sgshapiro				lmap->ldap_res = NULL;
390264562Sgshapiro			}
390364562Sgshapiro			(void) ldap_abandon(lmap->ldap_ld, msgid);
390464562Sgshapiro			if (vp != NULL)
390590792Sgshapiro				sm_free(vp); /* XXX */
390690792Sgshapiro			errno = save_errno;
390764562Sgshapiro			return NULL;
390838032Speter		}
390964562Sgshapiro		ldap_msgfree(lmap->ldap_res);
391064562Sgshapiro		lmap->ldap_res = NULL;
391138032Speter	}
391238032Speter
391364562Sgshapiro	if (ret == 0)
391490792Sgshapiro		save_errno = ETIMEDOUT;
391564562Sgshapiro	else
391690792Sgshapiro		save_errno = sm_ldap_geterrno(lmap->ldap_ld);
391790792Sgshapiro	if (save_errno != LDAP_SUCCESS)
391838032Speter	{
391964562Sgshapiro		if (ret != 0)
392090792Sgshapiro			save_errno += E_LDAPBASE;
392177349Sgshapiro
392264562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
392364562Sgshapiro		{
392490792Sgshapiro			errno = save_errno;
392564562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
392664562Sgshapiro				syserr("Error getting LDAP results in map %s",
392764562Sgshapiro				       map->map_mname);
392864562Sgshapiro			else
392994334Sgshapiro				syserr("451 4.3.5 Error getting LDAP results in map %s",
393064562Sgshapiro				       map->map_mname);
393164562Sgshapiro		}
393264562Sgshapiro		*statp = EX_TEMPFAIL;
393364562Sgshapiro		if (vp != NULL)
393490792Sgshapiro			sm_free(vp); /* XXX */
393590792Sgshapiro
393690792Sgshapiro		switch (save_errno - E_LDAPBASE)
393790792Sgshapiro		{
393894334Sgshapiro#  ifdef LDAP_SERVER_DOWN
393990792Sgshapiro		  case LDAP_SERVER_DOWN:
394094334Sgshapiro#  endif /* LDAP_SERVER_DOWN */
394190792Sgshapiro		  case LDAP_TIMEOUT:
394290792Sgshapiro		  case LDAP_UNAVAILABLE:
394377349Sgshapiro			/* server disappeared, try reopen on next search */
394477349Sgshapiro			ldapmap_close(map);
394590792Sgshapiro			break;
394677349Sgshapiro		}
394777349Sgshapiro		errno = save_errno;
394864562Sgshapiro		return NULL;
394938032Speter	}
395090792Sgshapiro# endif /* _FFR_LDAP_RECURSION */
395190792Sgshapiro
395264562Sgshapiro	/* Did we match anything? */
395371345Sgshapiro	if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags))
395464562Sgshapiro		return NULL;
395538032Speter
395664562Sgshapiro	if (*statp == EX_OK)
395764562Sgshapiro	{
395864562Sgshapiro		if (LogLevel > 9)
395964562Sgshapiro			sm_syslog(LOG_INFO, CurEnv->e_id,
396071345Sgshapiro				  "ldap %.100s => %s", name,
396171345Sgshapiro				  vp == NULL ? "<NULL>" : vp);
396264562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
396364562Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
396464562Sgshapiro		else
396571345Sgshapiro		{
396671345Sgshapiro			/* vp != NULL according to test above */
396764562Sgshapiro			result = map_rewrite(map, vp, strlen(vp), av);
396871345Sgshapiro		}
396971345Sgshapiro		if (vp != NULL)
397090792Sgshapiro			sm_free(vp); /* XXX */
397164562Sgshapiro	}
397264562Sgshapiro	return result;
397338032Speter}
397438032Speter
397538032Speter/*
397664562Sgshapiro**  LDAPMAP_FINDCONN -- find an LDAP connection to the server
397764562Sgshapiro**
397864562Sgshapiro**	Cache LDAP connections based on the host, port, bind DN,
397966494Sgshapiro**	secret, and PID so we don't have multiple connections open to
398066494Sgshapiro**	the same server for different maps.  Need a separate connection
398166494Sgshapiro**	per PID since a parent process may close the map before the
398266494Sgshapiro**	child is done with it.
398364562Sgshapiro**
398464562Sgshapiro**	Parameters:
398564562Sgshapiro**		lmap -- LDAP map information
398664562Sgshapiro**
398764562Sgshapiro**	Returns:
398864562Sgshapiro**		Symbol table entry for the LDAP connection.
398938032Speter*/
399038032Speter
399164562Sgshapirostatic STAB *
399264562Sgshapiroldapmap_findconn(lmap)
399390792Sgshapiro	SM_LDAP_STRUCT *lmap;
399438032Speter{
399594334Sgshapiro	char *format;
399664562Sgshapiro	char *nbuf;
399790792Sgshapiro	STAB *SM_NONVOLATILE s = NULL;
399838032Speter
399994334Sgshapiro# if _FFR_LDAP_SETVERSION
400094334Sgshapiro	format = "%s%c%d%c%d%c%s%c%s%d";
400194334Sgshapiro# else /* _FFR_LDAP_SETVERSION */
400294334Sgshapiro	format = "%s%c%d%c%s%c%s%d";
400394334Sgshapiro# endif /* _FFR_LDAP_SETVERSION */
400494334Sgshapiro	nbuf = sm_stringf_x(format,
400594334Sgshapiro			    (lmap->ldap_target == NULL ? "localhost"
400694334Sgshapiro						       : lmap->ldap_target),
400790792Sgshapiro			    CONDELSE,
400890792Sgshapiro			    lmap->ldap_port,
400990792Sgshapiro			    CONDELSE,
401094334Sgshapiro# if _FFR_LDAP_SETVERSION
401194334Sgshapiro			    lmap->ldap_version,
401294334Sgshapiro			    CONDELSE,
401394334Sgshapiro# endif /* _FFR_LDAP_SETVERSION */
401490792Sgshapiro			    (lmap->ldap_binddn == NULL ? ""
401590792Sgshapiro						       : lmap->ldap_binddn),
401690792Sgshapiro			    CONDELSE,
401790792Sgshapiro			    (lmap->ldap_secret == NULL ? ""
401890792Sgshapiro						       : lmap->ldap_secret),
401990792Sgshapiro			    (int) CurrentPid);
402090792Sgshapiro	SM_TRY
402190792Sgshapiro		s = stab(nbuf, ST_LMAP, ST_ENTER);
402290792Sgshapiro	SM_FINALLY
402390792Sgshapiro		sm_free(nbuf);
402490792Sgshapiro	SM_END_TRY
402564562Sgshapiro	return s;
402664562Sgshapiro}
402738032Speter/*
402864562Sgshapiro**  LDAPMAP_PARSEARGS -- parse ldap map definition args.
402964562Sgshapiro*/
403038032Speter
403190792Sgshapirostatic struct lamvalues LDAPAuthMethods[] =
403264562Sgshapiro{
403364562Sgshapiro	{	"none",		LDAP_AUTH_NONE		},
403464562Sgshapiro	{	"simple",	LDAP_AUTH_SIMPLE	},
403564562Sgshapiro# ifdef LDAP_AUTH_KRBV4
403664562Sgshapiro	{	"krbv4",	LDAP_AUTH_KRBV4		},
403764562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
403864562Sgshapiro	{	NULL,		0			}
403964562Sgshapiro};
404038032Speter
404190792Sgshapirostatic struct ladvalues LDAPAliasDereference[] =
404264562Sgshapiro{
404364562Sgshapiro	{	"never",	LDAP_DEREF_NEVER	},
404464562Sgshapiro	{	"always",	LDAP_DEREF_ALWAYS	},
404564562Sgshapiro	{	"search",	LDAP_DEREF_SEARCHING	},
404664562Sgshapiro	{	"find",		LDAP_DEREF_FINDING	},
404764562Sgshapiro	{	NULL,		0			}
404864562Sgshapiro};
404938032Speter
405090792Sgshapirostatic struct lssvalues LDAPSearchScope[] =
405164562Sgshapiro{
405264562Sgshapiro	{	"base",		LDAP_SCOPE_BASE		},
405364562Sgshapiro	{	"one",		LDAP_SCOPE_ONELEVEL	},
405464562Sgshapiro	{	"sub",		LDAP_SCOPE_SUBTREE	},
405564562Sgshapiro	{	NULL,		0			}
405664562Sgshapiro};
405738032Speter
405864562Sgshapirobool
405964562Sgshapiroldapmap_parseargs(map, args)
406064562Sgshapiro	MAP *map;
406164562Sgshapiro	char *args;
406264562Sgshapiro{
406390792Sgshapiro	bool secretread = true;
406494334Sgshapiro# if _FFR_LDAP_URI
406594334Sgshapiro	bool ldaphost = false;
406694334Sgshapiro# endif /* _FFR_LDAP_URI */
406764562Sgshapiro	int i;
406864562Sgshapiro	register char *p = args;
406990792Sgshapiro	SM_LDAP_STRUCT *lmap;
407064562Sgshapiro	struct lamvalues *lam;
407164562Sgshapiro	struct ladvalues *lad;
407264562Sgshapiro	struct lssvalues *lss;
407390792Sgshapiro	char ldapfilt[MAXLINE];
407464562Sgshapiro	char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
407564562Sgshapiro
407664562Sgshapiro	/* Get ldap struct pointer from map */
407790792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
407864562Sgshapiro
407964562Sgshapiro	/* Check if setting the initial LDAP defaults */
408064562Sgshapiro	if (lmap == NULL || lmap != LDAPDefaults)
408164562Sgshapiro	{
408290792Sgshapiro		/* We need to alloc an SM_LDAP_STRUCT struct */
408390792Sgshapiro		lmap = (SM_LDAP_STRUCT *) xalloc(sizeof *lmap);
408464562Sgshapiro		if (LDAPDefaults == NULL)
408590792Sgshapiro			sm_ldap_clear(lmap);
408664562Sgshapiro		else
408764562Sgshapiro			STRUCTCOPY(*LDAPDefaults, *lmap);
408864562Sgshapiro	}
408964562Sgshapiro
409064562Sgshapiro	/* there is no check whether there is really an argument */
409164562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
409264562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
409390792Sgshapiro
409490792Sgshapiro	/* Check if setting up an alias or file class LDAP map */
409590792Sgshapiro	if (bitset(MF_ALIAS, map->map_mflags))
409690792Sgshapiro	{
409790792Sgshapiro		/* Comma separate if used as an alias file */
409890792Sgshapiro		map->map_coldelim = ',';
409990792Sgshapiro		if (*args == '\0')
410090792Sgshapiro		{
410190792Sgshapiro			int n;
410290792Sgshapiro			char *lc;
410390792Sgshapiro			char jbuf[MAXHOSTNAMELEN];
410490792Sgshapiro			char lcbuf[MAXLINE];
410590792Sgshapiro
410690792Sgshapiro			/* Get $j */
410790792Sgshapiro			expand("\201j", jbuf, sizeof jbuf, &BlankEnvelope);
410890792Sgshapiro			if (jbuf[0] == '\0')
410990792Sgshapiro			{
411090792Sgshapiro				(void) sm_strlcpy(jbuf, "localhost",
411190792Sgshapiro						  sizeof jbuf);
411290792Sgshapiro			}
411390792Sgshapiro
411490792Sgshapiro			lc = macvalue(macid("{sendmailMTACluster}"), CurEnv);
411590792Sgshapiro			if (lc == NULL)
411690792Sgshapiro				lc = "";
411790792Sgshapiro			else
411890792Sgshapiro			{
411990792Sgshapiro				expand(lc, lcbuf, sizeof lcbuf, CurEnv);
412090792Sgshapiro				lc = lcbuf;
412190792Sgshapiro			}
412290792Sgshapiro
412390792Sgshapiro			n = sm_snprintf(ldapfilt, sizeof ldapfilt,
412490792Sgshapiro					"(&(objectClass=sendmailMTAAliasObject)(sendmailMTAAliasGrouping=aliases)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))(sendmailMTAKey=%%0))",
412590792Sgshapiro					lc, jbuf);
412690792Sgshapiro			if (n >= sizeof ldapfilt)
412790792Sgshapiro			{
412890792Sgshapiro				syserr("%s: Default LDAP string too long",
412990792Sgshapiro				       map->map_mname);
413090792Sgshapiro				return false;
413190792Sgshapiro			}
413290792Sgshapiro
413390792Sgshapiro			/* default args for an alias LDAP entry */
413490792Sgshapiro			lmap->ldap_filter = ldapfilt;
413590792Sgshapiro			lmap->ldap_attr[0] = "sendmailMTAAliasValue";
413690792Sgshapiro			lmap->ldap_attr[1] = NULL;
413790792Sgshapiro		}
413890792Sgshapiro	}
413990792Sgshapiro	else if (bitset(MF_FILECLASS, map->map_mflags))
414090792Sgshapiro	{
414190792Sgshapiro		/* Space separate if used as a file class file */
414290792Sgshapiro		map->map_coldelim = ' ';
414390792Sgshapiro	}
414490792Sgshapiro
414538032Speter	for (;;)
414638032Speter	{
414738032Speter		while (isascii(*p) && isspace(*p))
414838032Speter			p++;
414938032Speter		if (*p != '-')
415038032Speter			break;
415138032Speter		switch (*++p)
415238032Speter		{
415338032Speter		  case 'N':
415438032Speter			map->map_mflags |= MF_INCLNULL;
415538032Speter			map->map_mflags &= ~MF_TRY0NULL;
415638032Speter			break;
415738032Speter
415838032Speter		  case 'O':
415938032Speter			map->map_mflags &= ~MF_TRY1NULL;
416038032Speter			break;
416138032Speter
416238032Speter		  case 'o':
416338032Speter			map->map_mflags |= MF_OPTIONAL;
416438032Speter			break;
416538032Speter
416638032Speter		  case 'f':
416738032Speter			map->map_mflags |= MF_NOFOLDCASE;
416838032Speter			break;
416938032Speter
417038032Speter		  case 'm':
417138032Speter			map->map_mflags |= MF_MATCHONLY;
417238032Speter			break;
417338032Speter
417438032Speter		  case 'A':
417538032Speter			map->map_mflags |= MF_APPEND;
417638032Speter			break;
417738032Speter
417838032Speter		  case 'q':
417938032Speter			map->map_mflags |= MF_KEEPQUOTES;
418038032Speter			break;
418138032Speter
418238032Speter		  case 'a':
418338032Speter			map->map_app = ++p;
418438032Speter			break;
418538032Speter
418638032Speter		  case 'T':
418738032Speter			map->map_tapp = ++p;
418838032Speter			break;
418938032Speter
419064562Sgshapiro		  case 't':
419164562Sgshapiro			map->map_mflags |= MF_NODEFER;
419264562Sgshapiro			break;
419364562Sgshapiro
419464562Sgshapiro		  case 'S':
419564562Sgshapiro			map->map_spacesub = *++p;
419664562Sgshapiro			break;
419764562Sgshapiro
419864562Sgshapiro		  case 'D':
419964562Sgshapiro			map->map_mflags |= MF_DEFER;
420064562Sgshapiro			break;
420164562Sgshapiro
420264562Sgshapiro		  case 'z':
420364562Sgshapiro			if (*++p != '\\')
420464562Sgshapiro				map->map_coldelim = *p;
420564562Sgshapiro			else
420664562Sgshapiro			{
420764562Sgshapiro				switch (*++p)
420864562Sgshapiro				{
420964562Sgshapiro				  case 'n':
421064562Sgshapiro					map->map_coldelim = '\n';
421164562Sgshapiro					break;
421264562Sgshapiro
421364562Sgshapiro				  case 't':
421464562Sgshapiro					map->map_coldelim = '\t';
421564562Sgshapiro					break;
421664562Sgshapiro
421764562Sgshapiro				  default:
421864562Sgshapiro					map->map_coldelim = '\\';
421964562Sgshapiro				}
422064562Sgshapiro			}
422164562Sgshapiro			break;
422264562Sgshapiro
422364562Sgshapiro			/* Start of ldapmap specific args */
422490792Sgshapiro		  case 'V':
422590792Sgshapiro			if (*++p != '\\')
422690792Sgshapiro				lmap->ldap_attrsep = *p;
422790792Sgshapiro			else
422890792Sgshapiro			{
422990792Sgshapiro				switch (*++p)
423090792Sgshapiro				{
423190792Sgshapiro				  case 'n':
423290792Sgshapiro					lmap->ldap_attrsep = '\n';
423390792Sgshapiro					break;
423490792Sgshapiro
423590792Sgshapiro				  case 't':
423690792Sgshapiro					lmap->ldap_attrsep = '\t';
423790792Sgshapiro					break;
423890792Sgshapiro
423990792Sgshapiro				  default:
424090792Sgshapiro					lmap->ldap_attrsep = '\\';
424190792Sgshapiro				}
424290792Sgshapiro			}
424390792Sgshapiro			break;
424490792Sgshapiro
424538032Speter		  case 'k':		/* search field */
424638032Speter			while (isascii(*++p) && isspace(*p))
424738032Speter				continue;
424864562Sgshapiro			lmap->ldap_filter = p;
424938032Speter			break;
425038032Speter
425138032Speter		  case 'v':		/* attr to return */
425238032Speter			while (isascii(*++p) && isspace(*p))
425338032Speter				continue;
425464562Sgshapiro			lmap->ldap_attr[0] = p;
425564562Sgshapiro			lmap->ldap_attr[1] = NULL;
425638032Speter			break;
425738032Speter
425864562Sgshapiro		  case '1':
425964562Sgshapiro			map->map_mflags |= MF_SINGLEMATCH;
426064562Sgshapiro			break;
426164562Sgshapiro
426238032Speter			/* args stolen from ldapsearch.c */
426338032Speter		  case 'R':		/* don't auto chase referrals */
426464562Sgshapiro# ifdef LDAP_REFERRALS
426538032Speter			lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
426664562Sgshapiro# else /* LDAP_REFERRALS */
426790792Sgshapiro			syserr("compile with -DLDAP_REFERRALS for referral support");
426864562Sgshapiro# endif /* LDAP_REFERRALS */
426938032Speter			break;
427038032Speter
427164562Sgshapiro		  case 'n':		/* retrieve attribute names only */
427264562Sgshapiro			lmap->ldap_attrsonly = LDAPMAP_TRUE;
427338032Speter			break;
427438032Speter
427564562Sgshapiro		  case 'r':		/* alias dereferencing */
427664562Sgshapiro			while (isascii(*++p) && isspace(*p))
427764562Sgshapiro				continue;
427864562Sgshapiro
427990792Sgshapiro			if (sm_strncasecmp(p, "LDAP_DEREF_", 11) == 0)
428064562Sgshapiro				p += 11;
428164562Sgshapiro
428264562Sgshapiro			for (lad = LDAPAliasDereference;
428364562Sgshapiro			     lad != NULL && lad->lad_name != NULL; lad++)
428438032Speter			{
428590792Sgshapiro				if (sm_strncasecmp(p, lad->lad_name,
428690792Sgshapiro						   strlen(lad->lad_name)) == 0)
428764562Sgshapiro					break;
428838032Speter			}
428964562Sgshapiro			if (lad->lad_name != NULL)
429064562Sgshapiro				lmap->ldap_deref = lad->lad_code;
429164562Sgshapiro			else
429238032Speter			{
429364562Sgshapiro				/* bad config line */
429464562Sgshapiro				if (!bitset(MCF_OPTFILE,
429564562Sgshapiro					    map->map_class->map_cflags))
429664562Sgshapiro				{
429764562Sgshapiro					char *ptr;
429864562Sgshapiro
429964562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
430064562Sgshapiro						*ptr = '\0';
430173188Sgshapiro					syserr("Deref must be [never|always|search|find] (not %s) in map %s",
430264562Sgshapiro						p, map->map_mname);
430364562Sgshapiro					if (ptr != NULL)
430464562Sgshapiro						*ptr = ' ';
430590792Sgshapiro					return false;
430664562Sgshapiro				}
430738032Speter			}
430864562Sgshapiro			break;
430964562Sgshapiro
431064562Sgshapiro		  case 's':		/* search scope */
431164562Sgshapiro			while (isascii(*++p) && isspace(*p))
431264562Sgshapiro				continue;
431364562Sgshapiro
431490792Sgshapiro			if (sm_strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
431564562Sgshapiro				p += 11;
431664562Sgshapiro
431764562Sgshapiro			for (lss = LDAPSearchScope;
431864562Sgshapiro			     lss != NULL && lss->lss_name != NULL; lss++)
431938032Speter			{
432090792Sgshapiro				if (sm_strncasecmp(p, lss->lss_name,
432190792Sgshapiro						   strlen(lss->lss_name)) == 0)
432264562Sgshapiro					break;
432338032Speter			}
432464562Sgshapiro			if (lss->lss_name != NULL)
432564562Sgshapiro				lmap->ldap_scope = lss->lss_code;
432638032Speter			else
432764562Sgshapiro			{
432864562Sgshapiro				/* bad config line */
432964562Sgshapiro				if (!bitset(MCF_OPTFILE,
433064562Sgshapiro					    map->map_class->map_cflags))
433138032Speter				{
433238032Speter					char *ptr;
433338032Speter
433438032Speter					if ((ptr = strchr(p, ' ')) != NULL)
433538032Speter						*ptr = '\0';
433673188Sgshapiro					syserr("Scope must be [base|one|sub] (not %s) in map %s",
433738032Speter						p, map->map_mname);
433838032Speter					if (ptr != NULL)
433938032Speter						*ptr = ' ';
434090792Sgshapiro					return false;
434138032Speter				}
434238032Speter			}
434338032Speter			break;
434438032Speter
434538032Speter		  case 'h':		/* ldap host */
434638032Speter			while (isascii(*++p) && isspace(*p))
434738032Speter				continue;
434894334Sgshapiro# if _FFR_LDAP_URI
434994334Sgshapiro			if (lmap->ldap_uri)
435094334Sgshapiro			{
435194334Sgshapiro				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
435294334Sgshapiro				       map->map_mname);
435394334Sgshapiro				return false;
435494334Sgshapiro			}
435594334Sgshapiro			ldaphost = true;
435694334Sgshapiro# endif /* _FFR_LDAP_URI */
435794334Sgshapiro			lmap->ldap_target = p;
435838032Speter			break;
435938032Speter
436038032Speter		  case 'b':		/* search base */
436138032Speter			while (isascii(*++p) && isspace(*p))
436238032Speter				continue;
436364562Sgshapiro			lmap->ldap_base = p;
436438032Speter			break;
436538032Speter
436638032Speter		  case 'p':		/* ldap port */
436738032Speter			while (isascii(*++p) && isspace(*p))
436838032Speter				continue;
436964562Sgshapiro			lmap->ldap_port = atoi(p);
437038032Speter			break;
437138032Speter
437238032Speter		  case 'l':		/* time limit */
437338032Speter			while (isascii(*++p) && isspace(*p))
437438032Speter				continue;
437564562Sgshapiro			lmap->ldap_timelimit = atoi(p);
437664562Sgshapiro			lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit;
437738032Speter			break;
437838032Speter
437964562Sgshapiro		  case 'Z':
438064562Sgshapiro			while (isascii(*++p) && isspace(*p))
438164562Sgshapiro				continue;
438264562Sgshapiro			lmap->ldap_sizelimit = atoi(p);
438364562Sgshapiro			break;
438464562Sgshapiro
438564562Sgshapiro		  case 'd':		/* Dn to bind to server as */
438664562Sgshapiro			while (isascii(*++p) && isspace(*p))
438764562Sgshapiro				continue;
438864562Sgshapiro			lmap->ldap_binddn = p;
438964562Sgshapiro			break;
439064562Sgshapiro
439164562Sgshapiro		  case 'M':		/* Method for binding */
439264562Sgshapiro			while (isascii(*++p) && isspace(*p))
439364562Sgshapiro				continue;
439464562Sgshapiro
439590792Sgshapiro			if (sm_strncasecmp(p, "LDAP_AUTH_", 10) == 0)
439664562Sgshapiro				p += 10;
439764562Sgshapiro
439864562Sgshapiro			for (lam = LDAPAuthMethods;
439964562Sgshapiro			     lam != NULL && lam->lam_name != NULL; lam++)
440064562Sgshapiro			{
440190792Sgshapiro				if (sm_strncasecmp(p, lam->lam_name,
440290792Sgshapiro						   strlen(lam->lam_name)) == 0)
440364562Sgshapiro					break;
440464562Sgshapiro			}
440564562Sgshapiro			if (lam->lam_name != NULL)
440664562Sgshapiro				lmap->ldap_method = lam->lam_code;
440764562Sgshapiro			else
440864562Sgshapiro			{
440964562Sgshapiro				/* bad config line */
441064562Sgshapiro				if (!bitset(MCF_OPTFILE,
441164562Sgshapiro					    map->map_class->map_cflags))
441264562Sgshapiro				{
441364562Sgshapiro					char *ptr;
441464562Sgshapiro
441564562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
441664562Sgshapiro						*ptr = '\0';
441773188Sgshapiro					syserr("Method for binding must be [none|simple|krbv4] (not %s) in map %s",
441864562Sgshapiro						p, map->map_mname);
441964562Sgshapiro					if (ptr != NULL)
442064562Sgshapiro						*ptr = ' ';
442190792Sgshapiro					return false;
442264562Sgshapiro				}
442364562Sgshapiro			}
442464562Sgshapiro
442564562Sgshapiro			break;
442664562Sgshapiro
442764562Sgshapiro			/*
442864562Sgshapiro			**  This is a string that is dependent on the
442964562Sgshapiro			**  method used defined above.
443064562Sgshapiro			*/
443164562Sgshapiro
443264562Sgshapiro		  case 'P':		/* Secret password for binding */
443364562Sgshapiro			 while (isascii(*++p) && isspace(*p))
443464562Sgshapiro				continue;
443564562Sgshapiro			lmap->ldap_secret = p;
443690792Sgshapiro			secretread = false;
443764562Sgshapiro			break;
443864562Sgshapiro
443994334Sgshapiro# if _FFR_LDAP_URI
444094334Sgshapiro		  case 'H':		/* Use LDAP URI */
444194334Sgshapiro#  if !USE_LDAP_INIT
444294334Sgshapiro			syserr("Must compile with -DUSE_LDAP_INIT to use LDAP URIs (-H) in map %s",
444394334Sgshapiro			       map->map_mname);
444494334Sgshapiro			return false;
444594334Sgshapiro#  else /* !USE_LDAP_INIT */
444694334Sgshapiro			if (ldaphost)
444794334Sgshapiro			{
444894334Sgshapiro				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
444994334Sgshapiro				       map->map_mname);
445094334Sgshapiro				return false;
445194334Sgshapiro			}
445294334Sgshapiro			while (isascii(*++p) && isspace(*p))
445394334Sgshapiro				continue;
445494334Sgshapiro			lmap->ldap_target = p;
445594334Sgshapiro			lmap->ldap_uri = true;
445694334Sgshapiro			break;
445794334Sgshapiro#  endif /* !USE_LDAP_INIT */
445894334Sgshapiro# endif /* _FFR_LDAP_URI */
445994334Sgshapiro
446094334Sgshapiro# if _FFR_LDAP_SETVERSION
446194334Sgshapiro		  case 'w':
446294334Sgshapiro			/* -w should be for passwd, -P should be for version */
446394334Sgshapiro			while (isascii(*++p) && isspace(*p))
446494334Sgshapiro				continue;
446594334Sgshapiro			lmap->ldap_version = atoi(p);
446694334Sgshapiro#  ifdef LDAP_VERSION_MAX
446794334Sgshapiro			if (lmap->ldap_version > LDAP_VERSION_MAX)
446894334Sgshapiro			{
446994334Sgshapiro				syserr("LDAP version %d exceeds max of %d in map %s",
447094334Sgshapiro				       lmap->ldap_version, LDAP_VERSION_MAX,
447194334Sgshapiro				       map->map_mname);
447294334Sgshapiro				return false;
447394334Sgshapiro			}
447494334Sgshapiro#  endif /* LDAP_VERSION_MAX */
447594334Sgshapiro#  ifdef LDAP_VERSION_MIN
447694334Sgshapiro			if (lmap->ldap_version < LDAP_VERSION_MIN)
447794334Sgshapiro			{
447894334Sgshapiro				syserr("LDAP version %d is lower than min of %d in map %s",
447994334Sgshapiro				       lmap->ldap_version, LDAP_VERSION_MIN,
448094334Sgshapiro				       map->map_mname);
448194334Sgshapiro				return false;
448294334Sgshapiro			}
448394334Sgshapiro#  endif /* LDAP_VERSION_MIN */
448494334Sgshapiro			break;
448594334Sgshapiro# endif /* _FFR_LDAP_SETVERSION */
448694334Sgshapiro
448764562Sgshapiro		  default:
448864562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
448964562Sgshapiro			break;
449038032Speter		}
449138032Speter
449264562Sgshapiro		/* need to account for quoted strings here */
449364562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
449438032Speter		{
449538032Speter			if (*p == '"')
449638032Speter			{
449738032Speter				while (*++p != '"' && *p != '\0')
449838032Speter					continue;
449938032Speter				if (*p != '\0')
450038032Speter					p++;
450138032Speter			}
450238032Speter			else
450338032Speter				p++;
450438032Speter		}
450538032Speter
450638032Speter		if (*p != '\0')
450738032Speter			*p++ = '\0';
450838032Speter	}
450938032Speter
451038032Speter	if (map->map_app != NULL)
451164562Sgshapiro		map->map_app = newstr(ldapmap_dequote(map->map_app));
451238032Speter	if (map->map_tapp != NULL)
451364562Sgshapiro		map->map_tapp = newstr(ldapmap_dequote(map->map_tapp));
451438032Speter
451538032Speter	/*
451642575Speter	**  We need to swallow up all the stuff into a struct
451742575Speter	**  and dump it into map->map_dbptr1
451838032Speter	*/
451938032Speter
452094334Sgshapiro	if (lmap->ldap_target != NULL &&
452164562Sgshapiro	    (LDAPDefaults == NULL ||
452264562Sgshapiro	     LDAPDefaults == lmap ||
452394334Sgshapiro	     LDAPDefaults->ldap_target != lmap->ldap_target))
452494334Sgshapiro		lmap->ldap_target = newstr(ldapmap_dequote(lmap->ldap_target));
452594334Sgshapiro	map->map_domain = lmap->ldap_target;
452664562Sgshapiro
452764562Sgshapiro	if (lmap->ldap_binddn != NULL &&
452864562Sgshapiro	    (LDAPDefaults == NULL ||
452964562Sgshapiro	     LDAPDefaults == lmap ||
453064562Sgshapiro	     LDAPDefaults->ldap_binddn != lmap->ldap_binddn))
453164562Sgshapiro		lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn));
453264562Sgshapiro
453364562Sgshapiro	if (lmap->ldap_secret != NULL &&
453464562Sgshapiro	    (LDAPDefaults == NULL ||
453564562Sgshapiro	     LDAPDefaults == lmap ||
453664562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
453738032Speter	{
453890792Sgshapiro		SM_FILE_T *sfd;
453964562Sgshapiro		long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
454038032Speter
454164562Sgshapiro		if (DontLockReadFiles)
454264562Sgshapiro			sff |= SFF_NOLOCK;
454338032Speter
454464562Sgshapiro		/* need to use method to map secret to passwd string */
454564562Sgshapiro		switch (lmap->ldap_method)
454664562Sgshapiro		{
454764562Sgshapiro		  case LDAP_AUTH_NONE:
454864562Sgshapiro			/* Do nothing */
454964562Sgshapiro			break;
455038032Speter
455164562Sgshapiro		  case LDAP_AUTH_SIMPLE:
455238032Speter
455364562Sgshapiro			/*
455464562Sgshapiro			**  Secret is the name of a file with
455564562Sgshapiro			**  the first line as the password.
455664562Sgshapiro			*/
455764562Sgshapiro
455864562Sgshapiro			/* Already read in the secret? */
455964562Sgshapiro			if (secretread)
456064562Sgshapiro				break;
456164562Sgshapiro
456264562Sgshapiro			sfd = safefopen(ldapmap_dequote(lmap->ldap_secret),
456364562Sgshapiro					O_RDONLY, 0, sff);
456464562Sgshapiro			if (sfd == NULL)
456564562Sgshapiro			{
456664562Sgshapiro				syserr("LDAP map: cannot open secret %s",
456764562Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
456890792Sgshapiro				return false;
456964562Sgshapiro			}
457098121Sgshapiro			lmap->ldap_secret = sfgets(m_tmp, sizeof m_tmp,
457166494Sgshapiro						   sfd, TimeOuts.to_fileopen,
457266494Sgshapiro						   "ldapmap_parseargs");
457390792Sgshapiro			(void) sm_io_close(sfd, SM_TIME_DEFAULT);
457498121Sgshapiro			if (strlen(m_tmp) > LDAPMAP_MAX_PASSWD)
457598121Sgshapiro			{
457698121Sgshapiro				syserr("LDAP map: secret in %s too long",
457798121Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
457898121Sgshapiro				return false;
457998121Sgshapiro			}
458064562Sgshapiro			if (lmap->ldap_secret != NULL &&
458164562Sgshapiro			    strlen(m_tmp) > 0)
458264562Sgshapiro			{
458364562Sgshapiro				/* chomp newline */
458464562Sgshapiro				if (m_tmp[strlen(m_tmp) - 1] == '\n')
458564562Sgshapiro					m_tmp[strlen(m_tmp) - 1] = '\0';
458664562Sgshapiro
458764562Sgshapiro				lmap->ldap_secret = m_tmp;
458864562Sgshapiro			}
458964562Sgshapiro			break;
459064562Sgshapiro
459164562Sgshapiro# ifdef LDAP_AUTH_KRBV4
459264562Sgshapiro		  case LDAP_AUTH_KRBV4:
459364562Sgshapiro
459464562Sgshapiro			/*
459564562Sgshapiro			**  Secret is where the ticket file is
459664562Sgshapiro			**  stashed
459764562Sgshapiro			*/
459864562Sgshapiro
459998121Sgshapiro			(void) sm_snprintf(m_tmp, sizeof m_tmp,
460090792Sgshapiro				"KRBTKFILE=%s",
460190792Sgshapiro				ldapmap_dequote(lmap->ldap_secret));
460264562Sgshapiro			lmap->ldap_secret = m_tmp;
460364562Sgshapiro			break;
460464562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
460564562Sgshapiro
460664562Sgshapiro		  default:	       /* Should NEVER get here */
460764562Sgshapiro			syserr("LDAP map: Illegal value in lmap method");
460890792Sgshapiro			return false;
460990792Sgshapiro			/* NOTREACHED */
461064562Sgshapiro			break;
461164562Sgshapiro		}
461238032Speter	}
461338032Speter
461464562Sgshapiro	if (lmap->ldap_secret != NULL &&
461564562Sgshapiro	    (LDAPDefaults == NULL ||
461664562Sgshapiro	     LDAPDefaults == lmap ||
461764562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
461864562Sgshapiro		lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret));
461938032Speter
462064562Sgshapiro	if (lmap->ldap_base != NULL &&
462164562Sgshapiro	    (LDAPDefaults == NULL ||
462264562Sgshapiro	     LDAPDefaults == lmap ||
462364562Sgshapiro	     LDAPDefaults->ldap_base != lmap->ldap_base))
462464562Sgshapiro		lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base));
462564562Sgshapiro
462664562Sgshapiro	/*
462764562Sgshapiro	**  Save the server from extra work.  If request is for a single
462864562Sgshapiro	**  match, tell the server to only return enough records to
462964562Sgshapiro	**  determine if there is a single match or not.  This can not
463064562Sgshapiro	**  be one since the server would only return one and we wouldn't
463164562Sgshapiro	**  know if there were others available.
463264562Sgshapiro	*/
463364562Sgshapiro
463464562Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
463564562Sgshapiro		lmap->ldap_sizelimit = 2;
463664562Sgshapiro
463764562Sgshapiro	/* If setting defaults, don't process ldap_filter and ldap_attr */
463864562Sgshapiro	if (lmap == LDAPDefaults)
463990792Sgshapiro		return true;
464064562Sgshapiro
464164562Sgshapiro	if (lmap->ldap_filter != NULL)
464264562Sgshapiro		lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
464338032Speter	else
464438032Speter	{
464538032Speter		if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
464638032Speter		{
464738032Speter			syserr("No filter given in map %s", map->map_mname);
464890792Sgshapiro			return false;
464938032Speter		}
465038032Speter	}
465164562Sgshapiro
465264562Sgshapiro	if (lmap->ldap_attr[0] != NULL)
465338032Speter	{
465494334Sgshapiro# if _FFR_LDAP_RECURSION
465590792Sgshapiro		bool recurse = false;
465694334Sgshapiro		bool normalseen = false;
465794334Sgshapiro# endif /* _FFR_LDAP_RECURSION */
465890792Sgshapiro
465964562Sgshapiro		i = 0;
466064562Sgshapiro		p = ldapmap_dequote(lmap->ldap_attr[0]);
466164562Sgshapiro		lmap->ldap_attr[0] = NULL;
466264562Sgshapiro
466394334Sgshapiro# if _FFR_LDAP_RECURSION
466494334Sgshapiro		/* Prime the attr list with the objectClass attribute */
466594334Sgshapiro		lmap->ldap_attr[i] = "objectClass";
466694334Sgshapiro		lmap->ldap_attr_type[i] = SM_LDAP_ATTR_OBJCLASS;
466794334Sgshapiro		lmap->ldap_attr_needobjclass[i] = NULL;
466894334Sgshapiro		i++;
466994334Sgshapiro# endif /* _FFR_LDAP_RECURSION */
467094334Sgshapiro
467164562Sgshapiro		while (p != NULL)
467238032Speter		{
467364562Sgshapiro			char *v;
467464562Sgshapiro
467564562Sgshapiro			while (isascii(*p) && isspace(*p))
467664562Sgshapiro				p++;
467764562Sgshapiro			if (*p == '\0')
467864562Sgshapiro				break;
467964562Sgshapiro			v = p;
468064562Sgshapiro			p = strchr(v, ',');
468164562Sgshapiro			if (p != NULL)
468264562Sgshapiro				*p++ = '\0';
468364562Sgshapiro
468471345Sgshapiro			if (i >= LDAPMAP_MAX_ATTR)
468564562Sgshapiro			{
468664562Sgshapiro				syserr("Too many return attributes in %s (max %d)",
468764562Sgshapiro				       map->map_mname, LDAPMAP_MAX_ATTR);
468890792Sgshapiro				return false;
468964562Sgshapiro			}
469064562Sgshapiro			if (*v != '\0')
469190792Sgshapiro			{
469294334Sgshapiro# if _FFR_LDAP_RECURSION
469394334Sgshapiro				int j;
469494334Sgshapiro				int use;
469590792Sgshapiro				char *type;
469694334Sgshapiro				char *needobjclass;
469790792Sgshapiro
469890792Sgshapiro				type = strchr(v, ':');
469990792Sgshapiro				if (type != NULL)
470094334Sgshapiro				{
470190792Sgshapiro					*type++ = '\0';
470294334Sgshapiro					needobjclass = strchr(type, ':');
470394334Sgshapiro					if (needobjclass != NULL)
470494334Sgshapiro						*needobjclass++ = '\0';
470594334Sgshapiro				}
470694334Sgshapiro				else
470794334Sgshapiro				{
470894334Sgshapiro					needobjclass = NULL;
470994334Sgshapiro				}
471090792Sgshapiro
471194334Sgshapiro				use = i;
471290792Sgshapiro
471394334Sgshapiro				/* allow override on "objectClass" type */
471494334Sgshapiro				if (sm_strcasecmp(v, "objectClass") == 0 &&
471594334Sgshapiro				    lmap->ldap_attr_type[0] == SM_LDAP_ATTR_OBJCLASS)
471690792Sgshapiro				{
471794334Sgshapiro					use = 0;
471894334Sgshapiro				}
471994334Sgshapiro				else
472094334Sgshapiro				{
472194334Sgshapiro					/*
472294334Sgshapiro					**  Don't add something to attribute
472394334Sgshapiro					**  list twice.
472494334Sgshapiro					*/
472594334Sgshapiro
472694334Sgshapiro					for (j = 1; j < i; j++)
472790792Sgshapiro					{
472894334Sgshapiro						if (sm_strcasecmp(v, lmap->ldap_attr[j]) == 0)
472994334Sgshapiro						{
473094334Sgshapiro							syserr("Duplicate attribute (%s) in %s",
473194334Sgshapiro							       v, map->map_mname);
473294334Sgshapiro							return false;
473394334Sgshapiro						}
473490792Sgshapiro					}
473594334Sgshapiro
473694334Sgshapiro					lmap->ldap_attr[use] = newstr(v);
473794334Sgshapiro					if (needobjclass != NULL &&
473894334Sgshapiro					    *needobjclass != '\0' &&
473994334Sgshapiro					    *needobjclass != '*')
474090792Sgshapiro					{
474194334Sgshapiro						lmap->ldap_attr_needobjclass[use] = newstr(needobjclass);
474294334Sgshapiro					}
474394334Sgshapiro					else
474494334Sgshapiro					{
474594334Sgshapiro						lmap->ldap_attr_needobjclass[use] = NULL;
474694334Sgshapiro					}
474794334Sgshapiro
474894334Sgshapiro				}
474994334Sgshapiro
475094334Sgshapiro				if (type != NULL && *type != '\0')
475194334Sgshapiro				{
475294334Sgshapiro					if (sm_strcasecmp(type, "dn") == 0)
475394334Sgshapiro					{
475490792Sgshapiro						recurse = true;
475594334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_DN;
475690792Sgshapiro					}
475790792Sgshapiro					else if (sm_strcasecmp(type, "filter") == 0)
475890792Sgshapiro					{
475990792Sgshapiro						recurse = true;
476094334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_FILTER;
476190792Sgshapiro					}
476290792Sgshapiro					else if (sm_strcasecmp(type, "url") == 0)
476390792Sgshapiro					{
476490792Sgshapiro						recurse = true;
476594334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_URL;
476690792Sgshapiro					}
476794334Sgshapiro					else if (sm_strcasecmp(type, "normal") == 0)
476890792Sgshapiro					{
476994334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
477094334Sgshapiro						normalseen = true;
477190792Sgshapiro					}
477290792Sgshapiro					else
477390792Sgshapiro					{
477490792Sgshapiro						syserr("Unknown attribute type (%s) in %s",
477590792Sgshapiro						       type, map->map_mname);
477690792Sgshapiro						return false;
477790792Sgshapiro					}
477890792Sgshapiro				}
477990792Sgshapiro				else
478094334Sgshapiro				{
478194334Sgshapiro					lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
478294334Sgshapiro					normalseen = true;
478394334Sgshapiro				}
478494334Sgshapiro# else /* _FFR_LDAP_RECURSION */
478594334Sgshapiro				lmap->ldap_attr[i] = newstr(v);
478694334Sgshapiro# endif /* _FFR_LDAP_RECURSION */
478790792Sgshapiro				i++;
478890792Sgshapiro			}
478938032Speter		}
479064562Sgshapiro		lmap->ldap_attr[i] = NULL;
479194334Sgshapiro# if _FFR_LDAP_RECURSION
479294334Sgshapiro		if (recurse && !normalseen)
479390792Sgshapiro		{
479494334Sgshapiro			syserr("LDAP recursion requested in %s but no returnable attribute given",
479590792Sgshapiro			       map->map_mname);
479690792Sgshapiro			return false;
479790792Sgshapiro		}
479890792Sgshapiro		if (recurse && lmap->ldap_attrsonly == LDAPMAP_TRUE)
479990792Sgshapiro		{
480090792Sgshapiro			syserr("LDAP recursion requested in %s can not be used with -n",
480190792Sgshapiro			       map->map_mname);
480290792Sgshapiro			return false;
480390792Sgshapiro		}
480494334Sgshapiro# endif /* _FFR_LDAP_RECURSION */
480538032Speter	}
480638032Speter	map->map_db1 = (ARBPTR_T) lmap;
480790792Sgshapiro	return true;
480838032Speter}
480938032Speter
481064562Sgshapiro/*
481164562Sgshapiro**  LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
481264562Sgshapiro**
481364562Sgshapiro**	Parameters:
481464562Sgshapiro**		spec -- map argument string from LDAPDefaults option
481564562Sgshapiro**
481664562Sgshapiro**	Returns:
481764562Sgshapiro**		None.
481864562Sgshapiro*/
481964562Sgshapiro
482064562Sgshapirovoid
482164562Sgshapiroldapmap_set_defaults(spec)
482264562Sgshapiro	char *spec;
482364562Sgshapiro{
482473188Sgshapiro	STAB *class;
482564562Sgshapiro	MAP map;
482664562Sgshapiro
482764562Sgshapiro	/* Allocate and set the default values */
482864562Sgshapiro	if (LDAPDefaults == NULL)
482990792Sgshapiro		LDAPDefaults = (SM_LDAP_STRUCT *) xalloc(sizeof *LDAPDefaults);
483090792Sgshapiro	sm_ldap_clear(LDAPDefaults);
483164562Sgshapiro
483264562Sgshapiro	memset(&map, '\0', sizeof map);
483373188Sgshapiro
483473188Sgshapiro	/* look up the class */
483573188Sgshapiro	class = stab("ldap", ST_MAPCLASS, ST_FIND);
483673188Sgshapiro	if (class == NULL)
483773188Sgshapiro	{
483873188Sgshapiro		syserr("readcf: LDAPDefaultSpec: class ldap not available");
483973188Sgshapiro		return;
484073188Sgshapiro	}
484173188Sgshapiro	map.map_class = &class->s_mapclass;
484264562Sgshapiro	map.map_db1 = (ARBPTR_T) LDAPDefaults;
484373188Sgshapiro	map.map_mname = "O LDAPDefaultSpec";
484464562Sgshapiro
484564562Sgshapiro	(void) ldapmap_parseargs(&map, spec);
484664562Sgshapiro
484764562Sgshapiro	/* These should never be set in LDAPDefaults */
484864562Sgshapiro	if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) ||
484964562Sgshapiro	    map.map_spacesub != SpaceSub ||
485064562Sgshapiro	    map.map_app != NULL ||
485164562Sgshapiro	    map.map_tapp != NULL)
485264562Sgshapiro	{
485364562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
485490792Sgshapiro		SM_FREE_CLR(map.map_app);
485590792Sgshapiro		SM_FREE_CLR(map.map_tapp);
485664562Sgshapiro	}
485764562Sgshapiro
485864562Sgshapiro	if (LDAPDefaults->ldap_filter != NULL)
485964562Sgshapiro	{
486064562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
486194334Sgshapiro
486264562Sgshapiro		/* don't free, it isn't malloc'ed in parseargs */
486364562Sgshapiro		LDAPDefaults->ldap_filter = NULL;
486464562Sgshapiro	}
486564562Sgshapiro
486664562Sgshapiro	if (LDAPDefaults->ldap_attr[0] != NULL)
486764562Sgshapiro	{
486864562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes");
486964562Sgshapiro		/* don't free, they aren't malloc'ed in parseargs */
487064562Sgshapiro		LDAPDefaults->ldap_attr[0] = NULL;
487164562Sgshapiro	}
487264562Sgshapiro}
487364562Sgshapiro#endif /* LDAPMAP */
487490792Sgshapiro/*
487564562Sgshapiro**  PH map
487664562Sgshapiro*/
487764562Sgshapiro
487890792Sgshapiro#if PH_MAP
487964562Sgshapiro
488064562Sgshapiro/*
488164562Sgshapiro**  Support for the CCSO Nameserver (ph/qi).
488264562Sgshapiro**  This code is intended to replace the so-called "ph mailer".
488364562Sgshapiro**  Contributed by Mark D. Roth <roth@uiuc.edu>.  Contact him for support.
488464562Sgshapiro*/
488564562Sgshapiro
488690792Sgshapiro/* what version of the ph map code we're running */
4887110560Sgshapirostatic char phmap_id[128];
488864562Sgshapiro
488990792Sgshapiro/* sendmail version for phmap id string */
489090792Sgshapiroextern const char Version[];
489190792Sgshapiro
4892110560Sgshapiro/* assume we're using nph-1.1.x if not specified */
4893110560Sgshapiro# ifndef NPH_VERSION
4894110560Sgshapiro#  define NPH_VERSION		10100
4895110560Sgshapiro# endif
4896110560Sgshapiro
4897110560Sgshapiro/* compatibility for versions older than nph-1.2.0 */
4898110560Sgshapiro# if NPH_VERSION < 10200
4899110560Sgshapiro#  define PH_OPEN_ROUNDROBIN	PH_ROUNDROBIN
4900110560Sgshapiro#  define PH_OPEN_DONTID	PH_DONTID
4901110560Sgshapiro#  define PH_CLOSE_FAST		PH_FASTCLOSE
4902110560Sgshapiro#  define PH_ERR_DATAERR	PH_DATAERR
4903110560Sgshapiro#  define PH_ERR_NOMATCH	PH_NOMATCH
4904110560Sgshapiro# endif /* NPH_VERSION < 10200 */
4905110560Sgshapiro
490664562Sgshapiro/*
490764562Sgshapiro**  PH_MAP_PARSEARGS -- parse ph map definition args.
490864562Sgshapiro*/
490964562Sgshapiro
491064562Sgshapirobool
491164562Sgshapiroph_map_parseargs(map, args)
491264562Sgshapiro	MAP *map;
491364562Sgshapiro	char *args;
491464562Sgshapiro{
491590792Sgshapiro	register bool done;
491690792Sgshapiro	register char *p = args;
491764562Sgshapiro	PH_MAP_STRUCT *pmap = NULL;
491864562Sgshapiro
491990792Sgshapiro	/* initialize version string */
492090792Sgshapiro	(void) sm_snprintf(phmap_id, sizeof phmap_id,
492190792Sgshapiro			   "sendmail-%s phmap-20010529 libphclient-%s",
492290792Sgshapiro			   Version, libphclient_version);
492390792Sgshapiro
492464562Sgshapiro	pmap = (PH_MAP_STRUCT *) xalloc(sizeof *pmap);
492564562Sgshapiro
492664562Sgshapiro	/* defaults */
492764562Sgshapiro	pmap->ph_servers = NULL;
492864562Sgshapiro	pmap->ph_field_list = NULL;
492990792Sgshapiro	pmap->ph = NULL;
493064562Sgshapiro	pmap->ph_timeout = 0;
493190792Sgshapiro	pmap->ph_fastclose = 0;
493264562Sgshapiro
493364562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
493464562Sgshapiro	for (;;)
493564562Sgshapiro	{
493664562Sgshapiro		while (isascii(*p) && isspace(*p))
493764562Sgshapiro			p++;
493864562Sgshapiro		if (*p != '-')
493964562Sgshapiro			break;
494064562Sgshapiro		switch (*++p)
494164562Sgshapiro		{
494264562Sgshapiro		  case 'N':
494364562Sgshapiro			map->map_mflags |= MF_INCLNULL;
494464562Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
494564562Sgshapiro			break;
494664562Sgshapiro
494764562Sgshapiro		  case 'O':
494864562Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
494964562Sgshapiro			break;
495064562Sgshapiro
495164562Sgshapiro		  case 'o':
495264562Sgshapiro			map->map_mflags |= MF_OPTIONAL;
495364562Sgshapiro			break;
495464562Sgshapiro
495564562Sgshapiro		  case 'f':
495664562Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
495764562Sgshapiro			break;
495864562Sgshapiro
495964562Sgshapiro		  case 'm':
496064562Sgshapiro			map->map_mflags |= MF_MATCHONLY;
496164562Sgshapiro			break;
496264562Sgshapiro
496364562Sgshapiro		  case 'A':
496464562Sgshapiro			map->map_mflags |= MF_APPEND;
496564562Sgshapiro			break;
496664562Sgshapiro
496764562Sgshapiro		  case 'q':
496864562Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
496964562Sgshapiro			break;
497064562Sgshapiro
497164562Sgshapiro		  case 't':
497264562Sgshapiro			map->map_mflags |= MF_NODEFER;
497364562Sgshapiro			break;
497464562Sgshapiro
497564562Sgshapiro		  case 'a':
497664562Sgshapiro			map->map_app = ++p;
497764562Sgshapiro			break;
497864562Sgshapiro
497964562Sgshapiro		  case 'T':
498064562Sgshapiro			map->map_tapp = ++p;
498164562Sgshapiro			break;
498264562Sgshapiro
498364562Sgshapiro		  case 'l':
498464562Sgshapiro			while (isascii(*++p) && isspace(*p))
498564562Sgshapiro				continue;
498664562Sgshapiro			pmap->ph_timeout = atoi(p);
498764562Sgshapiro			break;
498864562Sgshapiro
498964562Sgshapiro		  case 'S':
499064562Sgshapiro			map->map_spacesub = *++p;
499164562Sgshapiro			break;
499264562Sgshapiro
499364562Sgshapiro		  case 'D':
499464562Sgshapiro			map->map_mflags |= MF_DEFER;
499564562Sgshapiro			break;
499664562Sgshapiro
499764562Sgshapiro		  case 'h':		/* PH server list */
499864562Sgshapiro			while (isascii(*++p) && isspace(*p))
499964562Sgshapiro				continue;
500064562Sgshapiro			pmap->ph_servers = p;
500164562Sgshapiro			break;
500264562Sgshapiro
500390792Sgshapiro		  case 'v':
500490792Sgshapiro			sm_syslog(LOG_WARNING, NULL,
500590792Sgshapiro				  "ph_map_parseargs: WARNING: -v option will be removed in a future release - please use -k instead");
500690792Sgshapiro			/* intentional fallthrough for backward compatibility */
500790792Sgshapiro			/* FALLTHROUGH */
500890792Sgshapiro
500990792Sgshapiro		  case 'k':		/* fields to search for */
501064562Sgshapiro			while (isascii(*++p) && isspace(*p))
501164562Sgshapiro				continue;
501264562Sgshapiro			pmap->ph_field_list = p;
501364562Sgshapiro			break;
501464562Sgshapiro
501564562Sgshapiro		  default:
501690792Sgshapiro			syserr("ph_map_parseargs: unknown option -%c", *p);
501764562Sgshapiro		}
501864562Sgshapiro
501964562Sgshapiro		/* try to account for quoted strings */
502064562Sgshapiro		done = isascii(*p) && isspace(*p);
502164562Sgshapiro		while (*p != '\0' && !done)
502264562Sgshapiro		{
502364562Sgshapiro			if (*p == '"')
502464562Sgshapiro			{
502564562Sgshapiro				while (*++p != '"' && *p != '\0')
502664562Sgshapiro					continue;
502764562Sgshapiro				if (*p != '\0')
502864562Sgshapiro					p++;
502964562Sgshapiro			}
503064562Sgshapiro			else
503164562Sgshapiro				p++;
503264562Sgshapiro			done = isascii(*p) && isspace(*p);
503364562Sgshapiro		}
503464562Sgshapiro
503564562Sgshapiro		if (*p != '\0')
503664562Sgshapiro			*p++ = '\0';
503764562Sgshapiro	}
503864562Sgshapiro
503964562Sgshapiro	if (map->map_app != NULL)
504064562Sgshapiro		map->map_app = newstr(ph_map_dequote(map->map_app));
504164562Sgshapiro	if (map->map_tapp != NULL)
504264562Sgshapiro		map->map_tapp = newstr(ph_map_dequote(map->map_tapp));
504364562Sgshapiro
504464562Sgshapiro	if (pmap->ph_field_list != NULL)
504564562Sgshapiro		pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
504664562Sgshapiro
504764562Sgshapiro	if (pmap->ph_servers != NULL)
504864562Sgshapiro		pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
504964562Sgshapiro	else
505064562Sgshapiro	{
505164562Sgshapiro		syserr("ph_map_parseargs: -h flag is required");
505290792Sgshapiro		return false;
505364562Sgshapiro	}
505464562Sgshapiro
505564562Sgshapiro	map->map_db1 = (ARBPTR_T) pmap;
505690792Sgshapiro	return true;
505764562Sgshapiro}
505864562Sgshapiro
505964562Sgshapiro/*
506064562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
506164562Sgshapiro*/
506264562Sgshapiro
506390792Sgshapirovoid
506490792Sgshapiroph_map_close(map)
506564562Sgshapiro	MAP *map;
506664562Sgshapiro{
506764562Sgshapiro	PH_MAP_STRUCT *pmap;
506864562Sgshapiro
506964562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
507090792Sgshapiro	if (tTd(38, 9))
507194334Sgshapiro		sm_dprintf("ph_map_close(%s): pmap->ph_fastclose=%d\n",
507290792Sgshapiro			   map->map_mname, pmap->ph_fastclose);
507364562Sgshapiro
507490792Sgshapiro
507590792Sgshapiro	if (pmap->ph != NULL)
507664562Sgshapiro	{
507790792Sgshapiro		ph_set_sendhook(pmap->ph, NULL);
507890792Sgshapiro		ph_set_recvhook(pmap->ph, NULL);
507990792Sgshapiro		ph_close(pmap->ph, pmap->ph_fastclose);
508064562Sgshapiro	}
508190792Sgshapiro
508264562Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
508364562Sgshapiro}
508464562Sgshapiro
508564562Sgshapirostatic jmp_buf  PHTimeout;
508664562Sgshapiro
508764562Sgshapiro/* ARGSUSED */
508864562Sgshapirostatic void
508990792Sgshapiroph_timeout(unused)
509090792Sgshapiro	int unused;
509164562Sgshapiro{
509277349Sgshapiro	/*
509377349Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
509477349Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
509577349Sgshapiro	**	DOING.
509677349Sgshapiro	*/
509777349Sgshapiro
509877349Sgshapiro	errno = ETIMEDOUT;
509964562Sgshapiro	longjmp(PHTimeout, 1);
510064562Sgshapiro}
510164562Sgshapiro
510290792Sgshapirostatic void
5103110560Sgshapiro#if NPH_VERSION >= 10200
5104110560Sgshapiroph_map_send_debug(appdata, text)
5105110560Sgshapiro	void *appdata;
5106110560Sgshapiro#else
510790792Sgshapiroph_map_send_debug(text)
5108110560Sgshapiro#endif
510990792Sgshapiro	char *text;
511064562Sgshapiro{
511190792Sgshapiro	if (LogLevel > 9)
511290792Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
511390792Sgshapiro			  "ph_map_send_debug: ==> %s", text);
511490792Sgshapiro	if (tTd(38, 20))
511590792Sgshapiro		sm_dprintf("ph_map_send_debug: ==> %s\n", text);
511690792Sgshapiro}
511764562Sgshapiro
511890792Sgshapirostatic void
5119110560Sgshapiro#if NPH_VERSION >= 10200
5120110560Sgshapiroph_map_recv_debug(appdata, text)
5121110560Sgshapiro	void *appdata;
5122110560Sgshapiro#else
512390792Sgshapiroph_map_recv_debug(text)
5124110560Sgshapiro#endif
512590792Sgshapiro	char *text;
512690792Sgshapiro{
512790792Sgshapiro	if (LogLevel > 10)
512890792Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
512990792Sgshapiro			  "ph_map_recv_debug: <== %s", text);
513090792Sgshapiro	if (tTd(38, 21))
513190792Sgshapiro		sm_dprintf("ph_map_recv_debug: <== %s\n", text);
513264562Sgshapiro}
513364562Sgshapiro
513490792Sgshapiro/*
513564562Sgshapiro**  PH_MAP_OPEN -- sub for opening PH map
513664562Sgshapiro*/
513764562Sgshapirobool
513864562Sgshapiroph_map_open(map, mode)
513964562Sgshapiro	MAP *map;
514064562Sgshapiro	int mode;
514164562Sgshapiro{
514290792Sgshapiro	PH_MAP_STRUCT *pmap;
514390792Sgshapiro	register SM_EVENT *ev = NULL;
514464562Sgshapiro	int save_errno = 0;
514590792Sgshapiro	char *hostlist, *host;
514664562Sgshapiro
514764562Sgshapiro	if (tTd(38, 2))
514890792Sgshapiro		sm_dprintf("ph_map_open(%s)\n", map->map_mname);
514964562Sgshapiro
515064562Sgshapiro	mode &= O_ACCMODE;
515164562Sgshapiro	if (mode != O_RDONLY)
515264562Sgshapiro	{
515364562Sgshapiro		/* issue a pseudo-error message */
515490792Sgshapiro		errno = SM_EMAPCANTWRITE;
515590792Sgshapiro		return false;
515664562Sgshapiro	}
515764562Sgshapiro
515866494Sgshapiro	if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER &&
515966494Sgshapiro	    bitset(MF_DEFER, map->map_mflags))
516066494Sgshapiro	{
516166494Sgshapiro		if (tTd(9, 1))
516290792Sgshapiro			sm_dprintf("ph_map_open(%s) => DEFERRED\n",
516390792Sgshapiro				   map->map_mname);
516466494Sgshapiro
516566494Sgshapiro		/*
516690792Sgshapiro		**  Unset MF_DEFER here so that map_lookup() returns
516790792Sgshapiro		**  a temporary failure using the bogus map and
516890792Sgshapiro		**  map->map_tapp instead of the default permanent error.
516966494Sgshapiro		*/
517066494Sgshapiro
517166494Sgshapiro		map->map_mflags &= ~MF_DEFER;
517290792Sgshapiro		return false;
517366494Sgshapiro	}
517466494Sgshapiro
517564562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
517690792Sgshapiro	pmap->ph_fastclose = 0;		/* refresh field for reopen */
517764562Sgshapiro
517890792Sgshapiro	/* try each host in the list */
517964562Sgshapiro	hostlist = newstr(pmap->ph_servers);
518090792Sgshapiro	for (host = strtok(hostlist, " ");
518190792Sgshapiro	     host != NULL;
518290792Sgshapiro	     host = strtok(NULL, " "))
518364562Sgshapiro	{
518490792Sgshapiro		/* set timeout */
518564562Sgshapiro		if (pmap->ph_timeout != 0)
518664562Sgshapiro		{
518764562Sgshapiro			if (setjmp(PHTimeout) != 0)
518864562Sgshapiro			{
518964562Sgshapiro				ev = NULL;
519064562Sgshapiro				if (LogLevel > 1)
519164562Sgshapiro					sm_syslog(LOG_NOTICE, CurEnv->e_id,
519264562Sgshapiro						  "timeout connecting to PH server %.100s",
519390792Sgshapiro						  host);
519464562Sgshapiro				errno = ETIMEDOUT;
519564562Sgshapiro				goto ph_map_open_abort;
519664562Sgshapiro			}
519790792Sgshapiro			ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
519864562Sgshapiro		}
519990792Sgshapiro
520090792Sgshapiro		/* open connection to server */
5201110560Sgshapiro		if (ph_open(&(pmap->ph), host,
5202110560Sgshapiro			    PH_OPEN_ROUNDROBIN|PH_OPEN_DONTID,
5203110560Sgshapiro			    ph_map_send_debug, ph_map_recv_debug
5204110560Sgshapiro#if NPH_VERSION >= 10200
5205110560Sgshapiro			    , NULL
5206110560Sgshapiro#endif
5207110560Sgshapiro			    ) == 0
5208110560Sgshapiro		    && ph_id(pmap->ph, phmap_id) == 0)
520964562Sgshapiro		{
521064562Sgshapiro			if (ev != NULL)
521190792Sgshapiro				sm_clrevent(ev);
521290792Sgshapiro			sm_free(hostlist); /* XXX */
521390792Sgshapiro			return true;
521464562Sgshapiro		}
521590792Sgshapiro
521664562Sgshapiro  ph_map_open_abort:
521790792Sgshapiro		save_errno = errno;
521864562Sgshapiro		if (ev != NULL)
521990792Sgshapiro			sm_clrevent(ev);
5220110560Sgshapiro		pmap->ph_fastclose = PH_CLOSE_FAST;
522190792Sgshapiro		ph_map_close(map);
522290792Sgshapiro		errno = save_errno;
522390792Sgshapiro	}
522464562Sgshapiro
522566494Sgshapiro	if (bitset(MF_NODEFER, map->map_mflags))
522664562Sgshapiro	{
522766494Sgshapiro		if (errno == 0)
522864562Sgshapiro			errno = EAGAIN;
522966494Sgshapiro		syserr("ph_map_open: %s: cannot connect to PH server",
523066494Sgshapiro		       map->map_mname);
523164562Sgshapiro	}
523266494Sgshapiro	else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1)
523364562Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
523466494Sgshapiro			  "ph_map_open: %s: cannot connect to PH server",
523566494Sgshapiro			  map->map_mname);
523690792Sgshapiro	sm_free(hostlist); /* XXX */
523790792Sgshapiro	return false;
523864562Sgshapiro}
523964562Sgshapiro
524064562Sgshapiro/*
524164562Sgshapiro**  PH_MAP_LOOKUP -- look up key from ph server
524264562Sgshapiro*/
524364562Sgshapiro
524464562Sgshapirochar *
524564562Sgshapiroph_map_lookup(map, key, args, pstat)
524664562Sgshapiro	MAP *map;
524764562Sgshapiro	char *key;
524864562Sgshapiro	char **args;
524964562Sgshapiro	int *pstat;
525064562Sgshapiro{
525190792Sgshapiro	int i, save_errno = 0;
525290792Sgshapiro	register SM_EVENT *ev = NULL;
525364562Sgshapiro	PH_MAP_STRUCT *pmap;
525490792Sgshapiro	char *value = NULL;
525564562Sgshapiro
525664562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
525764562Sgshapiro
525864562Sgshapiro	*pstat = EX_OK;
525964562Sgshapiro
526090792Sgshapiro	/* set timeout */
526164562Sgshapiro	if (pmap->ph_timeout != 0)
526264562Sgshapiro	{
526364562Sgshapiro		if (setjmp(PHTimeout) != 0)
526464562Sgshapiro		{
526564562Sgshapiro			ev = NULL;
526664562Sgshapiro			if (LogLevel > 1)
526764562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
526864562Sgshapiro					  "timeout during PH lookup of %.100s",
526964562Sgshapiro					  key);
527064562Sgshapiro			errno = ETIMEDOUT;
527164562Sgshapiro			*pstat = EX_TEMPFAIL;
527264562Sgshapiro			goto ph_map_lookup_abort;
527364562Sgshapiro		}
527490792Sgshapiro		ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
527564562Sgshapiro	}
527664562Sgshapiro
527790792Sgshapiro	/* perform lookup */
527890792Sgshapiro	i = ph_email_resolve(pmap->ph, key, pmap->ph_field_list, &value);
527990792Sgshapiro	if (i == -1)
528090792Sgshapiro		*pstat = EX_TEMPFAIL;
5281110560Sgshapiro	else if (i == PH_ERR_NOMATCH || i == PH_ERR_DATAERR)
528290792Sgshapiro		*pstat = EX_UNAVAILABLE;
528364562Sgshapiro
528464562Sgshapiro  ph_map_lookup_abort:
528564562Sgshapiro	if (ev != NULL)
528690792Sgshapiro		sm_clrevent(ev);
528764562Sgshapiro
528864562Sgshapiro	/*
528990792Sgshapiro	**  Close the connection if the timer popped
529064562Sgshapiro	**  or we got a temporary PH error
529164562Sgshapiro	*/
529264562Sgshapiro
529364562Sgshapiro	if (*pstat == EX_TEMPFAIL)
529490792Sgshapiro	{
529590792Sgshapiro		save_errno = errno;
5296110560Sgshapiro		pmap->ph_fastclose = PH_CLOSE_FAST;
529790792Sgshapiro		ph_map_close(map);
529890792Sgshapiro		errno = save_errno;
529990792Sgshapiro	}
530064562Sgshapiro
530164562Sgshapiro	if (*pstat == EX_OK)
530264562Sgshapiro	{
530364562Sgshapiro		if (tTd(38,20))
530490792Sgshapiro			sm_dprintf("ph_map_lookup: %s => %s\n", key, value);
530564562Sgshapiro
530664562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
530790792Sgshapiro			return map_rewrite(map, key, strlen(key), NULL);
530864562Sgshapiro		else
530990792Sgshapiro			return map_rewrite(map, value, strlen(value), args);
531064562Sgshapiro	}
531164562Sgshapiro
531264562Sgshapiro	return NULL;
531364562Sgshapiro}
531464562Sgshapiro#endif /* PH_MAP */
531590792Sgshapiro/*
531642575Speter**  syslog map
531738032Speter*/
531838032Speter
531938032Speter#define map_prio	map_lockfd	/* overload field */
532038032Speter
532138032Speter/*
532242575Speter**  SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
532338032Speter*/
532438032Speter
532538032Speterbool
532638032Spetersyslog_map_parseargs(map, args)
532738032Speter	MAP *map;
532838032Speter	char *args;
532938032Speter{
533038032Speter	char *p = args;
533138032Speter	char *priority = NULL;
533238032Speter
533364562Sgshapiro	/* there is no check whether there is really an argument */
533464562Sgshapiro	while (*p != '\0')
533538032Speter	{
533638032Speter		while (isascii(*p) && isspace(*p))
533738032Speter			p++;
533838032Speter		if (*p != '-')
533938032Speter			break;
534064562Sgshapiro		++p;
534164562Sgshapiro		if (*p == 'D')
534264562Sgshapiro		{
534364562Sgshapiro			map->map_mflags |= MF_DEFER;
534464562Sgshapiro			++p;
534564562Sgshapiro		}
534664562Sgshapiro		else if (*p == 'S')
534764562Sgshapiro		{
534864562Sgshapiro			map->map_spacesub = *++p;
534964562Sgshapiro			if (*p != '\0')
535064562Sgshapiro				p++;
535164562Sgshapiro		}
535264562Sgshapiro		else if (*p == 'L')
535364562Sgshapiro		{
535464562Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p))
535564562Sgshapiro				continue;
535664562Sgshapiro			if (*p == '\0')
535764562Sgshapiro				break;
535864562Sgshapiro			priority = p;
535964562Sgshapiro			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
536064562Sgshapiro				p++;
536164562Sgshapiro			if (*p != '\0')
536264562Sgshapiro				*p++ = '\0';
536364562Sgshapiro		}
536464562Sgshapiro		else
536564562Sgshapiro		{
536664562Sgshapiro			syserr("Illegal option %c map syslog", *p);
536764562Sgshapiro			++p;
536864562Sgshapiro		}
536938032Speter	}
537038032Speter
537138032Speter	if (priority == NULL)
537238032Speter		map->map_prio = LOG_INFO;
537338032Speter	else
537438032Speter	{
537590792Sgshapiro		if (sm_strncasecmp("LOG_", priority, 4) == 0)
537638032Speter			priority += 4;
537738032Speter
537838032Speter#ifdef LOG_EMERG
537990792Sgshapiro		if (sm_strcasecmp("EMERG", priority) == 0)
538038032Speter			map->map_prio = LOG_EMERG;
538138032Speter		else
538264562Sgshapiro#endif /* LOG_EMERG */
538338032Speter#ifdef LOG_ALERT
538490792Sgshapiro		if (sm_strcasecmp("ALERT", priority) == 0)
538538032Speter			map->map_prio = LOG_ALERT;
538638032Speter		else
538764562Sgshapiro#endif /* LOG_ALERT */
538838032Speter#ifdef LOG_CRIT
538990792Sgshapiro		if (sm_strcasecmp("CRIT", priority) == 0)
539038032Speter			map->map_prio = LOG_CRIT;
539138032Speter		else
539264562Sgshapiro#endif /* LOG_CRIT */
539338032Speter#ifdef LOG_ERR
539490792Sgshapiro		if (sm_strcasecmp("ERR", priority) == 0)
539538032Speter			map->map_prio = LOG_ERR;
539638032Speter		else
539764562Sgshapiro#endif /* LOG_ERR */
539838032Speter#ifdef LOG_WARNING
539990792Sgshapiro		if (sm_strcasecmp("WARNING", priority) == 0)
540038032Speter			map->map_prio = LOG_WARNING;
540138032Speter		else
540264562Sgshapiro#endif /* LOG_WARNING */
540338032Speter#ifdef LOG_NOTICE
540490792Sgshapiro		if (sm_strcasecmp("NOTICE", priority) == 0)
540538032Speter			map->map_prio = LOG_NOTICE;
540638032Speter		else
540764562Sgshapiro#endif /* LOG_NOTICE */
540838032Speter#ifdef LOG_INFO
540990792Sgshapiro		if (sm_strcasecmp("INFO", priority) == 0)
541038032Speter			map->map_prio = LOG_INFO;
541138032Speter		else
541264562Sgshapiro#endif /* LOG_INFO */
541338032Speter#ifdef LOG_DEBUG
541490792Sgshapiro		if (sm_strcasecmp("DEBUG", priority) == 0)
541538032Speter			map->map_prio = LOG_DEBUG;
541638032Speter		else
541764562Sgshapiro#endif /* LOG_DEBUG */
541838032Speter		{
541990792Sgshapiro			syserr("syslog_map_parseargs: Unknown priority %s",
542038032Speter			       priority);
542190792Sgshapiro			return false;
542238032Speter		}
542338032Speter	}
542490792Sgshapiro	return true;
542538032Speter}
542638032Speter
542738032Speter/*
542842575Speter**  SYSLOG_MAP_LOOKUP -- rewrite and syslog message.  Always return empty string
542938032Speter*/
543038032Speter
543138032Speterchar *
543238032Spetersyslog_map_lookup(map, string, args, statp)
543338032Speter	MAP *map;
543438032Speter	char *string;
543538032Speter	char **args;
543638032Speter	int *statp;
543738032Speter{
543838032Speter	char *ptr = map_rewrite(map, string, strlen(string), args);
543938032Speter
544038032Speter	if (ptr != NULL)
544138032Speter	{
544238032Speter		if (tTd(38, 20))
544390792Sgshapiro			sm_dprintf("syslog_map_lookup(%s (priority %d): %s\n",
544464562Sgshapiro				map->map_mname, map->map_prio, ptr);
544538032Speter
544638032Speter		sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
544738032Speter	}
544838032Speter
544938032Speter	*statp = EX_OK;
545038032Speter	return "";
545138032Speter}
545238032Speter
545390792Sgshapiro/*
545438032Speter**  HESIOD Modules
545538032Speter*/
545638032Speter
545790792Sgshapiro#if HESIOD
545838032Speter
545938032Speterbool
546038032Speterhes_map_open(map, mode)
546138032Speter	MAP *map;
546238032Speter	int mode;
546338032Speter{
546438032Speter	if (tTd(38, 2))
546590792Sgshapiro		sm_dprintf("hes_map_open(%s, %s, %d)\n",
546638032Speter			map->map_mname, map->map_file, mode);
546738032Speter
546838032Speter	if (mode != O_RDONLY)
546938032Speter	{
547038032Speter		/* issue a pseudo-error message */
547190792Sgshapiro		errno = SM_EMAPCANTWRITE;
547290792Sgshapiro		return false;
547338032Speter	}
547438032Speter
547564562Sgshapiro# ifdef HESIOD_INIT
547638032Speter	if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
547790792Sgshapiro		return true;
547838032Speter
547938032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
548094334Sgshapiro		syserr("451 4.3.5 cannot initialize Hesiod map (%s)",
548190792Sgshapiro			sm_errstring(errno));
548290792Sgshapiro	return false;
548364562Sgshapiro# else /* HESIOD_INIT */
548438032Speter	if (hes_error() == HES_ER_UNINIT)
548538032Speter		hes_init();
548638032Speter	switch (hes_error())
548738032Speter	{
548838032Speter	  case HES_ER_OK:
548938032Speter	  case HES_ER_NOTFOUND:
549090792Sgshapiro		return true;
549138032Speter	}
549238032Speter
549338032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
549494334Sgshapiro		syserr("451 4.3.5 cannot initialize Hesiod map (%d)", hes_error());
549538032Speter
549690792Sgshapiro	return false;
549764562Sgshapiro# endif /* HESIOD_INIT */
549838032Speter}
549938032Speter
550038032Speterchar *
550138032Speterhes_map_lookup(map, name, av, statp)
550238032Speter	MAP *map;
550338032Speter	char *name;
550438032Speter	char **av;
550538032Speter	int *statp;
550638032Speter{
550738032Speter	char **hp;
550838032Speter
550938032Speter	if (tTd(38, 20))
551090792Sgshapiro		sm_dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
551138032Speter
551238032Speter	if (name[0] == '\\')
551338032Speter	{
551438032Speter		char *np;
551538032Speter		int nl;
551677349Sgshapiro		int save_errno;
551738032Speter		char nbuf[MAXNAME];
551838032Speter
551938032Speter		nl = strlen(name);
552038032Speter		if (nl < sizeof nbuf - 1)
552138032Speter			np = nbuf;
552238032Speter		else
552338032Speter			np = xalloc(strlen(name) + 2);
552438032Speter		np[0] = '\\';
552590792Sgshapiro		(void) sm_strlcpy(&np[1], name, (sizeof nbuf) - 1);
552664562Sgshapiro# ifdef HESIOD_INIT
552738032Speter		hp = hesiod_resolve(HesiodContext, np, map->map_file);
552864562Sgshapiro# else /* HESIOD_INIT */
552938032Speter		hp = hes_resolve(np, map->map_file);
553064562Sgshapiro# endif /* HESIOD_INIT */
553177349Sgshapiro		save_errno = errno;
553238032Speter		if (np != nbuf)
553390792Sgshapiro			sm_free(np); /* XXX */
553477349Sgshapiro		errno = save_errno;
553538032Speter	}
553638032Speter	else
553738032Speter	{
553864562Sgshapiro# ifdef HESIOD_INIT
553938032Speter		hp = hesiod_resolve(HesiodContext, name, map->map_file);
554064562Sgshapiro# else /* HESIOD_INIT */
554138032Speter		hp = hes_resolve(name, map->map_file);
554264562Sgshapiro# endif /* HESIOD_INIT */
554338032Speter	}
554464562Sgshapiro# ifdef HESIOD_INIT
554577349Sgshapiro	if (hp == NULL || *hp == NULL)
554638032Speter	{
554738032Speter		switch (errno)
554838032Speter		{
554938032Speter		  case ENOENT:
555038032Speter			  *statp = EX_NOTFOUND;
555138032Speter			  break;
555238032Speter		  case ECONNREFUSED:
555338032Speter			  *statp = EX_TEMPFAIL;
555438032Speter			  break;
555590792Sgshapiro		  case EMSGSIZE:
555638032Speter		  case ENOMEM:
555738032Speter		  default:
555838032Speter			  *statp = EX_UNAVAILABLE;
555938032Speter			  break;
556038032Speter		}
556182017Sgshapiro		if (hp != NULL)
556282017Sgshapiro			hesiod_free_list(HesiodContext, hp);
556338032Speter		return NULL;
556438032Speter	}
556564562Sgshapiro# else /* HESIOD_INIT */
556638032Speter	if (hp == NULL || hp[0] == NULL)
556738032Speter	{
556838032Speter		switch (hes_error())
556938032Speter		{
557038032Speter		  case HES_ER_OK:
557138032Speter			*statp = EX_OK;
557238032Speter			break;
557338032Speter
557438032Speter		  case HES_ER_NOTFOUND:
557538032Speter			*statp = EX_NOTFOUND;
557638032Speter			break;
557738032Speter
557838032Speter		  case HES_ER_CONFIG:
557938032Speter			*statp = EX_UNAVAILABLE;
558038032Speter			break;
558138032Speter
558238032Speter		  case HES_ER_NET:
558338032Speter			*statp = EX_TEMPFAIL;
558438032Speter			break;
558538032Speter		}
558638032Speter		return NULL;
558738032Speter	}
558864562Sgshapiro# endif /* HESIOD_INIT */
558938032Speter
559038032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
559138032Speter		return map_rewrite(map, name, strlen(name), NULL);
559238032Speter	else
559338032Speter		return map_rewrite(map, hp[0], strlen(hp[0]), av);
559438032Speter}
559538032Speter
559690792Sgshapiro/*
559790792Sgshapiro**  HES_MAP_CLOSE -- free the Hesiod context
559890792Sgshapiro*/
559990792Sgshapiro
560090792Sgshapirovoid
560190792Sgshapirohes_map_close(map)
560290792Sgshapiro	MAP *map;
560390792Sgshapiro{
560490792Sgshapiro	if (tTd(38, 20))
560590792Sgshapiro		sm_dprintf("hes_map_close(%s)\n", map->map_file);
560690792Sgshapiro
560790792Sgshapiro# ifdef HESIOD_INIT
560890792Sgshapiro	/* Free the hesiod context */
560990792Sgshapiro	if (HesiodContext != NULL)
561090792Sgshapiro	{
561190792Sgshapiro		hesiod_end(HesiodContext);
561290792Sgshapiro		HesiodContext = NULL;
561390792Sgshapiro	}
561490792Sgshapiro# endif /* HESIOD_INIT */
561590792Sgshapiro}
561690792Sgshapiro
561764562Sgshapiro#endif /* HESIOD */
561890792Sgshapiro/*
561938032Speter**  NeXT NETINFO Modules
562038032Speter*/
562138032Speter
562238032Speter#if NETINFO
562338032Speter
562438032Speter# define NETINFO_DEFAULT_DIR		"/aliases"
562538032Speter# define NETINFO_DEFAULT_PROPERTY	"members"
562638032Speter
562738032Speter/*
562838032Speter**  NI_MAP_OPEN -- open NetInfo Aliases
562938032Speter*/
563038032Speter
563138032Speterbool
563238032Speterni_map_open(map, mode)
563338032Speter	MAP *map;
563438032Speter	int mode;
563538032Speter{
563638032Speter	if (tTd(38, 2))
563790792Sgshapiro		sm_dprintf("ni_map_open(%s, %s, %d)\n",
563838032Speter			map->map_mname, map->map_file, mode);
563938032Speter	mode &= O_ACCMODE;
564038032Speter
564138032Speter	if (*map->map_file == '\0')
564238032Speter		map->map_file = NETINFO_DEFAULT_DIR;
564338032Speter
564438032Speter	if (map->map_valcolnm == NULL)
564538032Speter		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
564638032Speter
564790792Sgshapiro	if (map->map_coldelim == '\0')
564890792Sgshapiro	{
564990792Sgshapiro		if (bitset(MF_ALIAS, map->map_mflags))
565090792Sgshapiro			map->map_coldelim = ',';
565190792Sgshapiro		else if (bitset(MF_FILECLASS, map->map_mflags))
565290792Sgshapiro			map->map_coldelim = ' ';
565390792Sgshapiro	}
565490792Sgshapiro	return true;
565538032Speter}
565638032Speter
565738032Speter
565838032Speter/*
565938032Speter**  NI_MAP_LOOKUP -- look up a datum in NetInfo
566038032Speter*/
566138032Speter
566238032Speterchar *
566338032Speterni_map_lookup(map, name, av, statp)
566438032Speter	MAP *map;
566538032Speter	char *name;
566638032Speter	char **av;
566738032Speter	int *statp;
566838032Speter{
566938032Speter	char *res;
567038032Speter	char *propval;
567138032Speter
567238032Speter	if (tTd(38, 20))
567390792Sgshapiro		sm_dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
567438032Speter
567538032Speter	propval = ni_propval(map->map_file, map->map_keycolnm, name,
567638032Speter			     map->map_valcolnm, map->map_coldelim);
567738032Speter
567838032Speter	if (propval == NULL)
567938032Speter		return NULL;
568038032Speter
568190792Sgshapiro	SM_TRY
568290792Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
568390792Sgshapiro			res = map_rewrite(map, name, strlen(name), NULL);
568490792Sgshapiro		else
568590792Sgshapiro			res = map_rewrite(map, propval, strlen(propval), av);
568690792Sgshapiro	SM_FINALLY
568790792Sgshapiro		sm_free(propval);
568890792Sgshapiro	SM_END_TRY
568938032Speter	return res;
569038032Speter}
569138032Speter
569238032Speter
569364562Sgshapirostatic bool
569438032Speterni_getcanonname(name, hbsize, statp)
569538032Speter	char *name;
569638032Speter	int hbsize;
569738032Speter	int *statp;
569838032Speter{
569938032Speter	char *vptr;
570038032Speter	char *ptr;
570138032Speter	char nbuf[MAXNAME + 1];
570238032Speter
570338032Speter	if (tTd(38, 20))
570490792Sgshapiro		sm_dprintf("ni_getcanonname(%s)\n", name);
570538032Speter
570690792Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
570738032Speter	{
570838032Speter		*statp = EX_UNAVAILABLE;
570990792Sgshapiro		return false;
571038032Speter	}
571173188Sgshapiro	(void) shorten_hostname(nbuf);
571238032Speter
571338032Speter	/* we only accept single token search key */
571438032Speter	if (strchr(nbuf, '.'))
571538032Speter	{
571638032Speter		*statp = EX_NOHOST;
571790792Sgshapiro		return false;
571838032Speter	}
571938032Speter
572038032Speter	/* Do the search */
572138032Speter	vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
572238032Speter
572338032Speter	if (vptr == NULL)
572438032Speter	{
572538032Speter		*statp = EX_NOHOST;
572690792Sgshapiro		return false;
572738032Speter	}
572838032Speter
572938032Speter	/* Only want the first machine name */
573038032Speter	if ((ptr = strchr(vptr, '\n')) != NULL)
573138032Speter		*ptr = '\0';
573238032Speter
573390792Sgshapiro	if (sm_strlcpy(name, vptr, hbsize) >= hbsize)
573438032Speter	{
573577349Sgshapiro		sm_free(vptr);
573690792Sgshapiro		*statp = EX_UNAVAILABLE;
573790792Sgshapiro		return true;
573838032Speter	}
573977349Sgshapiro	sm_free(vptr);
574090792Sgshapiro	*statp = EX_OK;
574190792Sgshapiro	return false;
574238032Speter}
574390792Sgshapiro#endif /* NETINFO */
574438032Speter/*
574538032Speter**  TEXT (unindexed text file) Modules
574638032Speter**
574738032Speter**	This code donated by Sun Microsystems.
574838032Speter*/
574938032Speter
575038032Speter#define map_sff		map_lockfd	/* overload field */
575138032Speter
575238032Speter
575338032Speter/*
575438032Speter**  TEXT_MAP_OPEN -- open text table
575538032Speter*/
575638032Speter
575738032Speterbool
575838032Spetertext_map_open(map, mode)
575938032Speter	MAP *map;
576038032Speter	int mode;
576138032Speter{
576264562Sgshapiro	long sff;
576338032Speter	int i;
576438032Speter
576538032Speter	if (tTd(38, 2))
576690792Sgshapiro		sm_dprintf("text_map_open(%s, %s, %d)\n",
576738032Speter			map->map_mname, map->map_file, mode);
576838032Speter
576938032Speter	mode &= O_ACCMODE;
577038032Speter	if (mode != O_RDONLY)
577138032Speter	{
577238032Speter		errno = EPERM;
577390792Sgshapiro		return false;
577438032Speter	}
577538032Speter
577638032Speter	if (*map->map_file == '\0')
577738032Speter	{
577838032Speter		syserr("text map \"%s\": file name required",
577938032Speter			map->map_mname);
578090792Sgshapiro		return false;
578138032Speter	}
578238032Speter
578338032Speter	if (map->map_file[0] != '/')
578438032Speter	{
578538032Speter		syserr("text map \"%s\": file name must be fully qualified",
578638032Speter			map->map_mname);
578790792Sgshapiro		return false;
578838032Speter	}
578938032Speter
579038032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
579164562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
579238032Speter		sff |= SFF_NOWLINK;
579364562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
579438032Speter		sff |= SFF_SAFEDIRPATH;
579538032Speter	if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
579638032Speter			  sff, S_IRUSR, NULL)) != 0)
579738032Speter	{
579864562Sgshapiro		int save_errno = errno;
579964562Sgshapiro
580038032Speter		/* cannot open this map */
580138032Speter		if (tTd(38, 2))
580290792Sgshapiro			sm_dprintf("\tunsafe map file: %d\n", i);
580364562Sgshapiro		errno = save_errno;
580438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
580538032Speter			syserr("text map \"%s\": unsafe map file %s",
580638032Speter				map->map_mname, map->map_file);
580790792Sgshapiro		return false;
580838032Speter	}
580938032Speter
581038032Speter	if (map->map_keycolnm == NULL)
581138032Speter		map->map_keycolno = 0;
581238032Speter	else
581338032Speter	{
581438032Speter		if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
581538032Speter		{
581638032Speter			syserr("text map \"%s\", file %s: -k should specify a number, not %s",
581738032Speter				map->map_mname, map->map_file,
581838032Speter				map->map_keycolnm);
581990792Sgshapiro			return false;
582038032Speter		}
582138032Speter		map->map_keycolno = atoi(map->map_keycolnm);
582238032Speter	}
582338032Speter
582438032Speter	if (map->map_valcolnm == NULL)
582538032Speter		map->map_valcolno = 0;
582638032Speter	else
582738032Speter	{
582838032Speter		if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
582938032Speter		{
583038032Speter			syserr("text map \"%s\", file %s: -v should specify a number, not %s",
583138032Speter					map->map_mname, map->map_file,
583238032Speter					map->map_valcolnm);
583390792Sgshapiro			return false;
583438032Speter		}
583538032Speter		map->map_valcolno = atoi(map->map_valcolnm);
583638032Speter	}
583738032Speter
583838032Speter	if (tTd(38, 2))
583938032Speter	{
584090792Sgshapiro		sm_dprintf("text_map_open(%s, %s): delimiter = ",
584138032Speter			map->map_mname, map->map_file);
584238032Speter		if (map->map_coldelim == '\0')
584390792Sgshapiro			sm_dprintf("(white space)\n");
584438032Speter		else
584590792Sgshapiro			sm_dprintf("%c\n", map->map_coldelim);
584638032Speter	}
584738032Speter
584838032Speter	map->map_sff = sff;
584990792Sgshapiro	return true;
585038032Speter}
585138032Speter
585238032Speter
585338032Speter/*
585438032Speter**  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
585538032Speter*/
585638032Speter
585738032Speterchar *
585838032Spetertext_map_lookup(map, name, av, statp)
585938032Speter	MAP *map;
586038032Speter	char *name;
586138032Speter	char **av;
586238032Speter	int *statp;
586338032Speter{
586438032Speter	char *vp;
586538032Speter	auto int vsize;
586638032Speter	int buflen;
586790792Sgshapiro	SM_FILE_T *f;
586838032Speter	char delim;
586938032Speter	int key_idx;
587038032Speter	bool found_it;
587164562Sgshapiro	long sff = map->map_sff;
587238032Speter	char search_key[MAXNAME + 1];
587338032Speter	char linebuf[MAXLINE];
587438032Speter	char buf[MAXNAME + 1];
587538032Speter
587690792Sgshapiro	found_it = false;
587738032Speter	if (tTd(38, 20))
587890792Sgshapiro		sm_dprintf("text_map_lookup(%s, %s)\n", map->map_mname,  name);
587938032Speter
588038032Speter	buflen = strlen(name);
588138032Speter	if (buflen > sizeof search_key - 1)
588290792Sgshapiro		buflen = sizeof search_key - 1;	/* XXX just cut if off? */
588364562Sgshapiro	memmove(search_key, name, buflen);
588438032Speter	search_key[buflen] = '\0';
588538032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
588638032Speter		makelower(search_key);
588738032Speter
588838032Speter	f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
588938032Speter	if (f == NULL)
589038032Speter	{
589138032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
589238032Speter		*statp = EX_UNAVAILABLE;
589338032Speter		return NULL;
589438032Speter	}
589538032Speter	key_idx = map->map_keycolno;
589638032Speter	delim = map->map_coldelim;
589798121Sgshapiro	while (sm_io_fgets(f, SM_TIME_DEFAULT,
589898121Sgshapiro			   linebuf, sizeof linebuf) != NULL)
589938032Speter	{
590038032Speter		char *p;
590138032Speter
590238032Speter		/* skip comment line */
590338032Speter		if (linebuf[0] == '#')
590438032Speter			continue;
590538032Speter		p = strchr(linebuf, '\n');
590638032Speter		if (p != NULL)
590738032Speter			*p = '\0';
590838032Speter		p = get_column(linebuf, key_idx, delim, buf, sizeof buf);
590990792Sgshapiro		if (p != NULL && sm_strcasecmp(search_key, p) == 0)
591038032Speter		{
591190792Sgshapiro			found_it = true;
591238032Speter			break;
591338032Speter		}
591438032Speter	}
591590792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
591638032Speter	if (!found_it)
591738032Speter	{
591838032Speter		*statp = EX_NOTFOUND;
591938032Speter		return NULL;
592038032Speter	}
592138032Speter	vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof buf);
592242575Speter	if (vp == NULL)
592342575Speter	{
592442575Speter		*statp = EX_NOTFOUND;
592542575Speter		return NULL;
592642575Speter	}
592738032Speter	vsize = strlen(vp);
592838032Speter	*statp = EX_OK;
592938032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
593038032Speter		return map_rewrite(map, name, strlen(name), NULL);
593138032Speter	else
593238032Speter		return map_rewrite(map, vp, vsize, av);
593338032Speter}
593438032Speter
593538032Speter/*
593638032Speter**  TEXT_GETCANONNAME -- look up canonical name in hosts file
593738032Speter*/
593838032Speter
593964562Sgshapirostatic bool
594038032Spetertext_getcanonname(name, hbsize, statp)
594138032Speter	char *name;
594238032Speter	int hbsize;
594338032Speter	int *statp;
594438032Speter{
594538032Speter	bool found;
594673188Sgshapiro	char *dot;
594790792Sgshapiro	SM_FILE_T *f;
594838032Speter	char linebuf[MAXLINE];
594938032Speter	char cbuf[MAXNAME + 1];
595038032Speter	char nbuf[MAXNAME + 1];
595138032Speter
595238032Speter	if (tTd(38, 20))
595390792Sgshapiro		sm_dprintf("text_getcanonname(%s)\n", name);
595438032Speter
595590792Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
595638032Speter	{
595738032Speter		*statp = EX_UNAVAILABLE;
595890792Sgshapiro		return false;
595938032Speter	}
596073188Sgshapiro	dot = shorten_hostname(nbuf);
596138032Speter
596290792Sgshapiro	f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, HostsFile, SM_IO_RDONLY,
596390792Sgshapiro		       NULL);
596438032Speter	if (f == NULL)
596538032Speter	{
596638032Speter		*statp = EX_UNAVAILABLE;
596790792Sgshapiro		return false;
596838032Speter	}
596990792Sgshapiro	found = false;
597090792Sgshapiro	while (!found &&
597198121Sgshapiro		sm_io_fgets(f, SM_TIME_DEFAULT,
597298121Sgshapiro			    linebuf, sizeof linebuf) != NULL)
597338032Speter	{
597438032Speter		char *p = strpbrk(linebuf, "#\n");
597538032Speter
597638032Speter		if (p != NULL)
597738032Speter			*p = '\0';
597838032Speter		if (linebuf[0] != '\0')
597973188Sgshapiro			found = extract_canonname(nbuf, dot, linebuf,
598073188Sgshapiro						  cbuf, sizeof cbuf);
598138032Speter	}
598290792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
598338032Speter	if (!found)
598438032Speter	{
598538032Speter		*statp = EX_NOHOST;
598690792Sgshapiro		return false;
598738032Speter	}
598838032Speter
598990792Sgshapiro	if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
599038032Speter	{
599190792Sgshapiro		*statp = EX_UNAVAILABLE;
599290792Sgshapiro		return false;
599338032Speter	}
599490792Sgshapiro	*statp = EX_OK;
599590792Sgshapiro	return true;
599638032Speter}
599790792Sgshapiro/*
599838032Speter**  STAB (Symbol Table) Modules
599938032Speter*/
600038032Speter
600138032Speter
600238032Speter/*
600338032Speter**  STAB_MAP_LOOKUP -- look up alias in symbol table
600438032Speter*/
600538032Speter
600638032Speter/* ARGSUSED2 */
600738032Speterchar *
600838032Speterstab_map_lookup(map, name, av, pstat)
600938032Speter	register MAP *map;
601038032Speter	char *name;
601138032Speter	char **av;
601238032Speter	int *pstat;
601338032Speter{
601438032Speter	register STAB *s;
601538032Speter
601638032Speter	if (tTd(38, 20))
601790792Sgshapiro		sm_dprintf("stab_lookup(%s, %s)\n",
601838032Speter			map->map_mname, name);
601938032Speter
602038032Speter	s = stab(name, ST_ALIAS, ST_FIND);
602138032Speter	if (s != NULL)
602264562Sgshapiro		return s->s_alias;
602364562Sgshapiro	return NULL;
602438032Speter}
602538032Speter
602638032Speter
602738032Speter/*
602838032Speter**  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
602938032Speter*/
603038032Speter
603138032Spetervoid
603238032Speterstab_map_store(map, lhs, rhs)
603338032Speter	register MAP *map;
603438032Speter	char *lhs;
603538032Speter	char *rhs;
603638032Speter{
603738032Speter	register STAB *s;
603838032Speter
603938032Speter	s = stab(lhs, ST_ALIAS, ST_ENTER);
604038032Speter	s->s_alias = newstr(rhs);
604138032Speter}
604238032Speter
604338032Speter
604438032Speter/*
604538032Speter**  STAB_MAP_OPEN -- initialize (reads data file)
604638032Speter**
604738032Speter**	This is a wierd case -- it is only intended as a fallback for
604838032Speter**	aliases.  For this reason, opens for write (only during a
604938032Speter**	"newaliases") always fails, and opens for read open the
605038032Speter**	actual underlying text file instead of the database.
605138032Speter*/
605238032Speter
605338032Speterbool
605438032Speterstab_map_open(map, mode)
605538032Speter	register MAP *map;
605638032Speter	int mode;
605738032Speter{
605890792Sgshapiro	SM_FILE_T *af;
605964562Sgshapiro	long sff;
606038032Speter	struct stat st;
606138032Speter
606238032Speter	if (tTd(38, 2))
606390792Sgshapiro		sm_dprintf("stab_map_open(%s, %s, %d)\n",
606438032Speter			map->map_mname, map->map_file, mode);
606538032Speter
606638032Speter	mode &= O_ACCMODE;
606738032Speter	if (mode != O_RDONLY)
606838032Speter	{
606938032Speter		errno = EPERM;
607090792Sgshapiro		return false;
607138032Speter	}
607238032Speter
607338032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
607464562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
607538032Speter		sff |= SFF_NOWLINK;
607664562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
607738032Speter		sff |= SFF_SAFEDIRPATH;
607838032Speter	af = safefopen(map->map_file, O_RDONLY, 0444, sff);
607938032Speter	if (af == NULL)
608090792Sgshapiro		return false;
608190792Sgshapiro	readaliases(map, af, false, false);
608238032Speter
608390792Sgshapiro	if (fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &st) >= 0)
608438032Speter		map->map_mtime = st.st_mtime;
608590792Sgshapiro	(void) sm_io_close(af, SM_TIME_DEFAULT);
608638032Speter
608790792Sgshapiro	return true;
608838032Speter}
608990792Sgshapiro/*
609038032Speter**  Implicit Modules
609138032Speter**
609238032Speter**	Tries several types.  For back compatibility of aliases.
609338032Speter*/
609438032Speter
609538032Speter
609638032Speter/*
609738032Speter**  IMPL_MAP_LOOKUP -- lookup in best open database
609838032Speter*/
609938032Speter
610038032Speterchar *
610138032Speterimpl_map_lookup(map, name, av, pstat)
610238032Speter	MAP *map;
610338032Speter	char *name;
610438032Speter	char **av;
610538032Speter	int *pstat;
610638032Speter{
610738032Speter	if (tTd(38, 20))
610890792Sgshapiro		sm_dprintf("impl_map_lookup(%s, %s)\n",
610938032Speter			map->map_mname, name);
611038032Speter
611190792Sgshapiro#if NEWDB
611238032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
611338032Speter		return db_map_lookup(map, name, av, pstat);
611464562Sgshapiro#endif /* NEWDB */
611590792Sgshapiro#if NDBM
611638032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
611738032Speter		return ndbm_map_lookup(map, name, av, pstat);
611864562Sgshapiro#endif /* NDBM */
611938032Speter	return stab_map_lookup(map, name, av, pstat);
612038032Speter}
612138032Speter
612238032Speter/*
612338032Speter**  IMPL_MAP_STORE -- store in open databases
612438032Speter*/
612538032Speter
612638032Spetervoid
612738032Speterimpl_map_store(map, lhs, rhs)
612838032Speter	MAP *map;
612938032Speter	char *lhs;
613038032Speter	char *rhs;
613138032Speter{
613238032Speter	if (tTd(38, 12))
613390792Sgshapiro		sm_dprintf("impl_map_store(%s, %s, %s)\n",
613438032Speter			map->map_mname, lhs, rhs);
613590792Sgshapiro#if NEWDB
613638032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
613738032Speter		db_map_store(map, lhs, rhs);
613864562Sgshapiro#endif /* NEWDB */
613990792Sgshapiro#if NDBM
614038032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
614138032Speter		ndbm_map_store(map, lhs, rhs);
614264562Sgshapiro#endif /* NDBM */
614338032Speter	stab_map_store(map, lhs, rhs);
614438032Speter}
614538032Speter
614638032Speter/*
614738032Speter**  IMPL_MAP_OPEN -- implicit database open
614838032Speter*/
614938032Speter
615038032Speterbool
615138032Speterimpl_map_open(map, mode)
615238032Speter	MAP *map;
615338032Speter	int mode;
615438032Speter{
615538032Speter	if (tTd(38, 2))
615690792Sgshapiro		sm_dprintf("impl_map_open(%s, %s, %d)\n",
615738032Speter			map->map_mname, map->map_file, mode);
615838032Speter
615938032Speter	mode &= O_ACCMODE;
616090792Sgshapiro#if NEWDB
616138032Speter	map->map_mflags |= MF_IMPL_HASH;
616238032Speter	if (hash_map_open(map, mode))
616338032Speter	{
616438032Speter# ifdef NDBM_YP_COMPAT
616538032Speter		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
616664562Sgshapiro# endif /* NDBM_YP_COMPAT */
616790792Sgshapiro			return true;
616838032Speter	}
616938032Speter	else
617038032Speter		map->map_mflags &= ~MF_IMPL_HASH;
617164562Sgshapiro#endif /* NEWDB */
617290792Sgshapiro#if NDBM
617338032Speter	map->map_mflags |= MF_IMPL_NDBM;
617438032Speter	if (ndbm_map_open(map, mode))
617538032Speter	{
617690792Sgshapiro		return true;
617738032Speter	}
617838032Speter	else
617938032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
618064562Sgshapiro#endif /* NDBM */
618138032Speter
618238032Speter#if defined(NEWDB) || defined(NDBM)
618338032Speter	if (Verbose)
618438032Speter		message("WARNING: cannot open alias database %s%s",
618538032Speter			map->map_file,
618638032Speter			mode == O_RDONLY ? "; reading text version" : "");
618764562Sgshapiro#else /* defined(NEWDB) || defined(NDBM) */
618838032Speter	if (mode != O_RDONLY)
618938032Speter		usrerr("Cannot rebuild aliases: no database format defined");
619064562Sgshapiro#endif /* defined(NEWDB) || defined(NDBM) */
619138032Speter
619238032Speter	if (mode == O_RDONLY)
619338032Speter		return stab_map_open(map, mode);
619438032Speter	else
619590792Sgshapiro		return false;
619638032Speter}
619738032Speter
619838032Speter
619938032Speter/*
620038032Speter**  IMPL_MAP_CLOSE -- close any open database(s)
620138032Speter*/
620238032Speter
620338032Spetervoid
620438032Speterimpl_map_close(map)
620538032Speter	MAP *map;
620638032Speter{
620738032Speter	if (tTd(38, 9))
620890792Sgshapiro		sm_dprintf("impl_map_close(%s, %s, %lx)\n",
620938032Speter			map->map_mname, map->map_file, map->map_mflags);
621090792Sgshapiro#if NEWDB
621138032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
621238032Speter	{
621338032Speter		db_map_close(map);
621438032Speter		map->map_mflags &= ~MF_IMPL_HASH;
621538032Speter	}
621664562Sgshapiro#endif /* NEWDB */
621738032Speter
621890792Sgshapiro#if NDBM
621938032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
622038032Speter	{
622138032Speter		ndbm_map_close(map);
622238032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
622338032Speter	}
622464562Sgshapiro#endif /* NDBM */
622538032Speter}
622690792Sgshapiro/*
622738032Speter**  User map class.
622838032Speter**
622938032Speter**	Provides access to the system password file.
623038032Speter*/
623138032Speter
623238032Speter/*
623338032Speter**  USER_MAP_OPEN -- open user map
623438032Speter**
623538032Speter**	Really just binds field names to field numbers.
623638032Speter*/
623738032Speter
623838032Speterbool
623938032Speteruser_map_open(map, mode)
624038032Speter	MAP *map;
624138032Speter	int mode;
624238032Speter{
624338032Speter	if (tTd(38, 2))
624490792Sgshapiro		sm_dprintf("user_map_open(%s, %d)\n",
624538032Speter			map->map_mname, mode);
624638032Speter
624738032Speter	mode &= O_ACCMODE;
624838032Speter	if (mode != O_RDONLY)
624938032Speter	{
625038032Speter		/* issue a pseudo-error message */
625190792Sgshapiro		errno = SM_EMAPCANTWRITE;
625290792Sgshapiro		return false;
625338032Speter	}
625438032Speter	if (map->map_valcolnm == NULL)
625564562Sgshapiro		/* EMPTY */
625638032Speter		/* nothing */ ;
625790792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "name") == 0)
625838032Speter		map->map_valcolno = 1;
625990792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "passwd") == 0)
626038032Speter		map->map_valcolno = 2;
626190792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "uid") == 0)
626238032Speter		map->map_valcolno = 3;
626390792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "gid") == 0)
626438032Speter		map->map_valcolno = 4;
626590792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "gecos") == 0)
626638032Speter		map->map_valcolno = 5;
626790792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "dir") == 0)
626838032Speter		map->map_valcolno = 6;
626990792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "shell") == 0)
627038032Speter		map->map_valcolno = 7;
627138032Speter	else
627238032Speter	{
627338032Speter		syserr("User map %s: unknown column name %s",
627438032Speter			map->map_mname, map->map_valcolnm);
627590792Sgshapiro		return false;
627638032Speter	}
627790792Sgshapiro	return true;
627838032Speter}
627938032Speter
628038032Speter
628138032Speter/*
628238032Speter**  USER_MAP_LOOKUP -- look up a user in the passwd file.
628338032Speter*/
628438032Speter
628538032Speter/* ARGSUSED3 */
628638032Speterchar *
628738032Speteruser_map_lookup(map, key, av, statp)
628838032Speter	MAP *map;
628938032Speter	char *key;
629038032Speter	char **av;
629138032Speter	int *statp;
629238032Speter{
629338032Speter	auto bool fuzzy;
629490792Sgshapiro	SM_MBDB_T user;
629538032Speter
629638032Speter	if (tTd(38, 20))
629790792Sgshapiro		sm_dprintf("user_map_lookup(%s, %s)\n",
629838032Speter			map->map_mname, key);
629938032Speter
630090792Sgshapiro	*statp = finduser(key, &fuzzy, &user);
630190792Sgshapiro	if (*statp != EX_OK)
630238032Speter		return NULL;
630338032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
630438032Speter		return map_rewrite(map, key, strlen(key), NULL);
630538032Speter	else
630638032Speter	{
630738032Speter		char *rwval = NULL;
630838032Speter		char buf[30];
630938032Speter
631038032Speter		switch (map->map_valcolno)
631138032Speter		{
631238032Speter		  case 0:
631338032Speter		  case 1:
631490792Sgshapiro			rwval = user.mbdb_name;
631538032Speter			break;
631638032Speter
631738032Speter		  case 2:
631890792Sgshapiro			rwval = "x";	/* passwd no longer supported */
631938032Speter			break;
632038032Speter
632138032Speter		  case 3:
632290792Sgshapiro			(void) sm_snprintf(buf, sizeof buf, "%d",
632390792Sgshapiro					   (int) user.mbdb_uid);
632438032Speter			rwval = buf;
632538032Speter			break;
632638032Speter
632738032Speter		  case 4:
632890792Sgshapiro			(void) sm_snprintf(buf, sizeof buf, "%d",
632990792Sgshapiro					   (int) user.mbdb_gid);
633038032Speter			rwval = buf;
633138032Speter			break;
633238032Speter
633338032Speter		  case 5:
633490792Sgshapiro			rwval = user.mbdb_fullname;
633538032Speter			break;
633638032Speter
633738032Speter		  case 6:
633890792Sgshapiro			rwval = user.mbdb_homedir;
633938032Speter			break;
634038032Speter
634138032Speter		  case 7:
634290792Sgshapiro			rwval = user.mbdb_shell;
634338032Speter			break;
634438032Speter		}
634538032Speter		return map_rewrite(map, rwval, strlen(rwval), av);
634638032Speter	}
634738032Speter}
634890792Sgshapiro/*
634938032Speter**  Program map type.
635038032Speter**
635138032Speter**	This provides access to arbitrary programs.  It should be used
635238032Speter**	only very sparingly, since there is no way to bound the cost
635338032Speter**	of invoking an arbitrary program.
635438032Speter*/
635538032Speter
635638032Speterchar *
635738032Speterprog_map_lookup(map, name, av, statp)
635838032Speter	MAP *map;
635938032Speter	char *name;
636038032Speter	char **av;
636138032Speter	int *statp;
636238032Speter{
636338032Speter	int i;
636464562Sgshapiro	int save_errno;
636538032Speter	int fd;
636664562Sgshapiro	int status;
636738032Speter	auto pid_t pid;
636864562Sgshapiro	register char *p;
636938032Speter	char *rval;
637038032Speter	char *argv[MAXPV + 1];
637138032Speter	char buf[MAXLINE];
637238032Speter
637338032Speter	if (tTd(38, 20))
637490792Sgshapiro		sm_dprintf("prog_map_lookup(%s, %s) %s\n",
637538032Speter			map->map_mname, name, map->map_file);
637638032Speter
637738032Speter	i = 0;
637838032Speter	argv[i++] = map->map_file;
637938032Speter	if (map->map_rebuild != NULL)
638038032Speter	{
638190792Sgshapiro		(void) sm_strlcpy(buf, map->map_rebuild, sizeof buf);
638238032Speter		for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
638338032Speter		{
638438032Speter			if (i >= MAXPV - 1)
638538032Speter				break;
638638032Speter			argv[i++] = p;
638738032Speter		}
638838032Speter	}
638938032Speter	argv[i++] = name;
639038032Speter	argv[i] = NULL;
639138032Speter	if (tTd(38, 21))
639238032Speter	{
639390792Sgshapiro		sm_dprintf("prog_open:");
639438032Speter		for (i = 0; argv[i] != NULL; i++)
639590792Sgshapiro			sm_dprintf(" %s", argv[i]);
639690792Sgshapiro		sm_dprintf("\n");
639738032Speter	}
639890792Sgshapiro	(void) sm_blocksignal(SIGCHLD);
639938032Speter	pid = prog_open(argv, &fd, CurEnv);
640038032Speter	if (pid < 0)
640138032Speter	{
640238032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
640338032Speter			syserr("prog_map_lookup(%s) failed (%s) -- closing",
640490792Sgshapiro			       map->map_mname, sm_errstring(errno));
640538032Speter		else if (tTd(38, 9))
640690792Sgshapiro			sm_dprintf("prog_map_lookup(%s) failed (%s) -- closing",
640790792Sgshapiro				   map->map_mname, sm_errstring(errno));
640838032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
640938032Speter		*statp = EX_OSFILE;
641038032Speter		return NULL;
641138032Speter	}
641238032Speter	i = read(fd, buf, sizeof buf - 1);
641338032Speter	if (i < 0)
641438032Speter	{
641590792Sgshapiro		syserr("prog_map_lookup(%s): read error %s",
641690792Sgshapiro		       map->map_mname, sm_errstring(errno));
641738032Speter		rval = NULL;
641838032Speter	}
641938032Speter	else if (i == 0)
642038032Speter	{
642138032Speter		if (tTd(38, 20))
642290792Sgshapiro			sm_dprintf("prog_map_lookup(%s): empty answer\n",
642390792Sgshapiro				   map->map_mname);
642438032Speter		rval = NULL;
642538032Speter	}
642638032Speter	else
642738032Speter	{
642838032Speter		buf[i] = '\0';
642938032Speter		p = strchr(buf, '\n');
643038032Speter		if (p != NULL)
643138032Speter			*p = '\0';
643238032Speter
643338032Speter		/* collect the return value */
643438032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
643538032Speter			rval = map_rewrite(map, name, strlen(name), NULL);
643638032Speter		else
643777349Sgshapiro			rval = map_rewrite(map, buf, strlen(buf), av);
643838032Speter
643938032Speter		/* now flush any additional output */
644038032Speter		while ((i = read(fd, buf, sizeof buf)) > 0)
644138032Speter			continue;
644238032Speter	}
644338032Speter
644438032Speter	/* wait for the process to terminate */
644564562Sgshapiro	(void) close(fd);
644664562Sgshapiro	status = waitfor(pid);
644764562Sgshapiro	save_errno = errno;
644890792Sgshapiro	(void) sm_releasesignal(SIGCHLD);
644964562Sgshapiro	errno = save_errno;
645038032Speter
645164562Sgshapiro	if (status == -1)
645238032Speter	{
645390792Sgshapiro		syserr("prog_map_lookup(%s): wait error %s",
645490792Sgshapiro		       map->map_mname, sm_errstring(errno));
645538032Speter		*statp = EX_SOFTWARE;
645638032Speter		rval = NULL;
645738032Speter	}
645864562Sgshapiro	else if (WIFEXITED(status))
645938032Speter	{
646064562Sgshapiro		if ((*statp = WEXITSTATUS(status)) != EX_OK)
646138032Speter			rval = NULL;
646238032Speter	}
646338032Speter	else
646438032Speter	{
646538032Speter		syserr("prog_map_lookup(%s): child died on signal %d",
646690792Sgshapiro		       map->map_mname, status);
646738032Speter		*statp = EX_UNAVAILABLE;
646838032Speter		rval = NULL;
646938032Speter	}
647038032Speter	return rval;
647138032Speter}
647290792Sgshapiro/*
647338032Speter**  Sequenced map type.
647438032Speter**
647538032Speter**	Tries each map in order until something matches, much like
647638032Speter**	implicit.  Stores go to the first map in the list that can
647738032Speter**	support storing.
647838032Speter**
647938032Speter**	This is slightly unusual in that there are two interfaces.
648038032Speter**	The "sequence" interface lets you stack maps arbitrarily.
648138032Speter**	The "switch" interface builds a sequence map by looking
648238032Speter**	at a system-dependent configuration file such as
648338032Speter**	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
648438032Speter**
648538032Speter**	We don't need an explicit open, since all maps are
648690792Sgshapiro**	opened on demand.
648738032Speter*/
648838032Speter
648938032Speter/*
649038032Speter**  SEQ_MAP_PARSE -- Sequenced map parsing
649138032Speter*/
649238032Speter
649338032Speterbool
649438032Speterseq_map_parse(map, ap)
649538032Speter	MAP *map;
649638032Speter	char *ap;
649738032Speter{
649838032Speter	int maxmap;
649938032Speter
650038032Speter	if (tTd(38, 2))
650190792Sgshapiro		sm_dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
650238032Speter	maxmap = 0;
650338032Speter	while (*ap != '\0')
650438032Speter	{
650538032Speter		register char *p;
650638032Speter		STAB *s;
650738032Speter
650838032Speter		/* find beginning of map name */
650938032Speter		while (isascii(*ap) && isspace(*ap))
651038032Speter			ap++;
651164562Sgshapiro		for (p = ap;
651264562Sgshapiro		     (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.';
651364562Sgshapiro		     p++)
651438032Speter			continue;
651538032Speter		if (*p != '\0')
651638032Speter			*p++ = '\0';
651738032Speter		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
651838032Speter			p++;
651938032Speter		if (*ap == '\0')
652038032Speter		{
652138032Speter			ap = p;
652238032Speter			continue;
652338032Speter		}
652438032Speter		s = stab(ap, ST_MAP, ST_FIND);
652538032Speter		if (s == NULL)
652638032Speter		{
652738032Speter			syserr("Sequence map %s: unknown member map %s",
652838032Speter				map->map_mname, ap);
652938032Speter		}
653090792Sgshapiro		else if (maxmap >= MAXMAPSTACK)
653138032Speter		{
653238032Speter			syserr("Sequence map %s: too many member maps (%d max)",
653338032Speter				map->map_mname, MAXMAPSTACK);
653438032Speter			maxmap++;
653538032Speter		}
653638032Speter		else if (maxmap < MAXMAPSTACK)
653738032Speter		{
653838032Speter			map->map_stack[maxmap++] = &s->s_map;
653938032Speter		}
654038032Speter		ap = p;
654138032Speter	}
654290792Sgshapiro	return true;
654338032Speter}
654438032Speter
654538032Speter/*
654638032Speter**  SWITCH_MAP_OPEN -- open a switched map
654738032Speter**
654838032Speter**	This looks at the system-dependent configuration and builds
654938032Speter**	a sequence map that does the same thing.
655038032Speter**
655138032Speter**	Every system must define a switch_map_find routine in conf.c
655238032Speter**	that will return the list of service types associated with a
655338032Speter**	given service class.
655438032Speter*/
655538032Speter
655638032Speterbool
655738032Speterswitch_map_open(map, mode)
655838032Speter	MAP *map;
655938032Speter	int mode;
656038032Speter{
656138032Speter	int mapno;
656238032Speter	int nmaps;
656338032Speter	char *maptype[MAXMAPSTACK];
656438032Speter
656538032Speter	if (tTd(38, 2))
656690792Sgshapiro		sm_dprintf("switch_map_open(%s, %s, %d)\n",
656738032Speter			map->map_mname, map->map_file, mode);
656838032Speter
656938032Speter	mode &= O_ACCMODE;
657038032Speter	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
657138032Speter	if (tTd(38, 19))
657238032Speter	{
657390792Sgshapiro		sm_dprintf("\tswitch_map_find => %d\n", nmaps);
657438032Speter		for (mapno = 0; mapno < nmaps; mapno++)
657590792Sgshapiro			sm_dprintf("\t\t%s\n", maptype[mapno]);
657638032Speter	}
657738032Speter	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
657890792Sgshapiro		return false;
657938032Speter
658038032Speter	for (mapno = 0; mapno < nmaps; mapno++)
658138032Speter	{
658238032Speter		register STAB *s;
658338032Speter		char nbuf[MAXNAME + 1];
658438032Speter
658538032Speter		if (maptype[mapno] == NULL)
658638032Speter			continue;
658790792Sgshapiro		(void) sm_strlcpyn(nbuf, sizeof nbuf, 3,
658890792Sgshapiro				   map->map_mname, ".", maptype[mapno]);
658938032Speter		s = stab(nbuf, ST_MAP, ST_FIND);
659038032Speter		if (s == NULL)
659138032Speter		{
659238032Speter			syserr("Switch map %s: unknown member map %s",
659338032Speter				map->map_mname, nbuf);
659438032Speter		}
659538032Speter		else
659638032Speter		{
659738032Speter			map->map_stack[mapno] = &s->s_map;
659838032Speter			if (tTd(38, 4))
659990792Sgshapiro				sm_dprintf("\tmap_stack[%d] = %s:%s\n",
660090792Sgshapiro					   mapno,
660190792Sgshapiro					   s->s_map.map_class->map_cname,
660290792Sgshapiro					   nbuf);
660338032Speter		}
660438032Speter	}
660590792Sgshapiro	return true;
660638032Speter}
660738032Speter
660890792Sgshapiro#if 0
660938032Speter/*
661038032Speter**  SEQ_MAP_CLOSE -- close all underlying maps
661138032Speter*/
661238032Speter
661338032Spetervoid
661438032Speterseq_map_close(map)
661538032Speter	MAP *map;
661638032Speter{
661738032Speter	int mapno;
661838032Speter
661938032Speter	if (tTd(38, 9))
662090792Sgshapiro		sm_dprintf("seq_map_close(%s)\n", map->map_mname);
662138032Speter
662238032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
662338032Speter	{
662438032Speter		MAP *mm = map->map_stack[mapno];
662538032Speter
662638032Speter		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
662738032Speter			continue;
662877349Sgshapiro		mm->map_mflags |= MF_CLOSING;
662938032Speter		mm->map_class->map_close(mm);
663077349Sgshapiro		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
663138032Speter	}
663238032Speter}
663390792Sgshapiro#endif /* 0 */
663438032Speter
663538032Speter/*
663638032Speter**  SEQ_MAP_LOOKUP -- sequenced map lookup
663738032Speter*/
663838032Speter
663938032Speterchar *
664038032Speterseq_map_lookup(map, key, args, pstat)
664138032Speter	MAP *map;
664238032Speter	char *key;
664338032Speter	char **args;
664438032Speter	int *pstat;
664538032Speter{
664638032Speter	int mapno;
664738032Speter	int mapbit = 0x01;
664890792Sgshapiro	bool tempfail = false;
664938032Speter
665038032Speter	if (tTd(38, 20))
665190792Sgshapiro		sm_dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
665238032Speter
665338032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
665438032Speter	{
665538032Speter		MAP *mm = map->map_stack[mapno];
665638032Speter		char *rv;
665738032Speter
665838032Speter		if (mm == NULL)
665938032Speter			continue;
666064562Sgshapiro		if (!bitset(MF_OPEN, mm->map_mflags) &&
666164562Sgshapiro		    !openmap(mm))
666238032Speter		{
666338032Speter			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
666438032Speter			{
666538032Speter				*pstat = EX_UNAVAILABLE;
666638032Speter				return NULL;
666738032Speter			}
666838032Speter			continue;
666938032Speter		}
667038032Speter		*pstat = EX_OK;
667138032Speter		rv = mm->map_class->map_lookup(mm, key, args, pstat);
667238032Speter		if (rv != NULL)
667338032Speter			return rv;
667438032Speter		if (*pstat == EX_TEMPFAIL)
667538032Speter		{
667638032Speter			if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
667738032Speter				return NULL;
667890792Sgshapiro			tempfail = true;
667938032Speter		}
668038032Speter		else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
668138032Speter			break;
668238032Speter	}
668338032Speter	if (tempfail)
668438032Speter		*pstat = EX_TEMPFAIL;
668538032Speter	else if (*pstat == EX_OK)
668638032Speter		*pstat = EX_NOTFOUND;
668738032Speter	return NULL;
668838032Speter}
668938032Speter
669038032Speter/*
669138032Speter**  SEQ_MAP_STORE -- sequenced map store
669238032Speter*/
669338032Speter
669438032Spetervoid
669538032Speterseq_map_store(map, key, val)
669638032Speter	MAP *map;
669738032Speter	char *key;
669838032Speter	char *val;
669938032Speter{
670038032Speter	int mapno;
670138032Speter
670238032Speter	if (tTd(38, 12))
670390792Sgshapiro		sm_dprintf("seq_map_store(%s, %s, %s)\n",
670438032Speter			map->map_mname, key, val);
670538032Speter
670638032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
670738032Speter	{
670838032Speter		MAP *mm = map->map_stack[mapno];
670938032Speter
671038032Speter		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
671138032Speter			continue;
671238032Speter
671338032Speter		mm->map_class->map_store(mm, key, val);
671438032Speter		return;
671538032Speter	}
671638032Speter	syserr("seq_map_store(%s, %s, %s): no writable map",
671738032Speter		map->map_mname, key, val);
671838032Speter}
671990792Sgshapiro/*
672038032Speter**  NULL stubs
672138032Speter*/
672238032Speter
672338032Speter/* ARGSUSED */
672438032Speterbool
672538032Speternull_map_open(map, mode)
672638032Speter	MAP *map;
672738032Speter	int mode;
672838032Speter{
672990792Sgshapiro	return true;
673038032Speter}
673138032Speter
673238032Speter/* ARGSUSED */
673338032Spetervoid
673438032Speternull_map_close(map)
673538032Speter	MAP *map;
673638032Speter{
673738032Speter	return;
673838032Speter}
673938032Speter
674038032Speterchar *
674138032Speternull_map_lookup(map, key, args, pstat)
674238032Speter	MAP *map;
674338032Speter	char *key;
674438032Speter	char **args;
674538032Speter	int *pstat;
674638032Speter{
674738032Speter	*pstat = EX_NOTFOUND;
674838032Speter	return NULL;
674938032Speter}
675038032Speter
675138032Speter/* ARGSUSED */
675238032Spetervoid
675338032Speternull_map_store(map, key, val)
675438032Speter	MAP *map;
675538032Speter	char *key;
675638032Speter	char *val;
675738032Speter{
675838032Speter	return;
675938032Speter}
676038032Speter
676138032Speter/*
676238032Speter**  BOGUS stubs
676338032Speter*/
676438032Speter
676538032Speterchar *
676638032Speterbogus_map_lookup(map, key, args, pstat)
676738032Speter	MAP *map;
676838032Speter	char *key;
676938032Speter	char **args;
677038032Speter	int *pstat;
677138032Speter{
677238032Speter	*pstat = EX_TEMPFAIL;
677338032Speter	return NULL;
677438032Speter}
677538032Speter
677638032SpeterMAPCLASS	BogusMapClass =
677738032Speter{
677890792Sgshapiro	"bogus-map",		NULL,			0,
677990792Sgshapiro	NULL,			bogus_map_lookup,	null_map_store,
678090792Sgshapiro	null_map_open,		null_map_close,
678138032Speter};
678290792Sgshapiro/*
678364562Sgshapiro**  MACRO modules
678464562Sgshapiro*/
678564562Sgshapiro
678664562Sgshapirochar *
678764562Sgshapiromacro_map_lookup(map, name, av, statp)
678864562Sgshapiro	MAP *map;
678964562Sgshapiro	char *name;
679064562Sgshapiro	char **av;
679164562Sgshapiro	int *statp;
679264562Sgshapiro{
679364562Sgshapiro	int mid;
679464562Sgshapiro
679564562Sgshapiro	if (tTd(38, 20))
679690792Sgshapiro		sm_dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
679764562Sgshapiro			name == NULL ? "NULL" : name);
679864562Sgshapiro
679964562Sgshapiro	if (name == NULL ||
680064562Sgshapiro	    *name == '\0' ||
680190792Sgshapiro	    (mid = macid(name)) == 0)
680264562Sgshapiro	{
680364562Sgshapiro		*statp = EX_CONFIG;
680464562Sgshapiro		return NULL;
680564562Sgshapiro	}
680664562Sgshapiro
680764562Sgshapiro	if (av[1] == NULL)
680890792Sgshapiro		macdefine(&CurEnv->e_macro, A_PERM, mid, NULL);
680964562Sgshapiro	else
681090792Sgshapiro		macdefine(&CurEnv->e_macro, A_TEMP, mid, av[1]);
681164562Sgshapiro
681264562Sgshapiro	*statp = EX_OK;
681364562Sgshapiro	return "";
681464562Sgshapiro}
681590792Sgshapiro/*
681638032Speter**  REGEX modules
681738032Speter*/
681838032Speter
681990792Sgshapiro#if MAP_REGEX
682038032Speter
682138032Speter# include <regex.h>
682238032Speter
682338032Speter# define DEFAULT_DELIM	CONDELSE
682438032Speter# define END_OF_FIELDS	-1
682538032Speter# define ERRBUF_SIZE	80
682638032Speter# define MAX_MATCH	32
682738032Speter
682864562Sgshapiro# define xnalloc(s)	memset(xalloc(s), '\0', s);
682938032Speter
683038032Speterstruct regex_map
683138032Speter{
683271345Sgshapiro	regex_t	*regex_pattern_buf;	/* xalloc it */
683338032Speter	int	*regex_subfields;	/* move to type MAP */
683464562Sgshapiro	char	*regex_delim;		/* move to type MAP */
683538032Speter};
683638032Speter
683738032Speterstatic int
683838032Speterparse_fields(s, ibuf, blen, nr_substrings)
683938032Speter	char *s;
684038032Speter	int *ibuf;		/* array */
684138032Speter	int blen;		/* number of elements in ibuf */
684238032Speter	int nr_substrings;	/* number of substrings in the pattern */
684338032Speter{
684438032Speter	register char *cp;
684538032Speter	int i = 0;
684690792Sgshapiro	bool lastone = false;
684738032Speter
684838032Speter	blen--;		/* for terminating END_OF_FIELDS */
684938032Speter	cp = s;
685038032Speter	do
685138032Speter	{
685238032Speter		for (;; cp++)
685338032Speter		{
685438032Speter			if (*cp == ',')
685538032Speter			{
685638032Speter				*cp = '\0';
685738032Speter				break;
685838032Speter			}
685938032Speter			if (*cp == '\0')
686038032Speter			{
686190792Sgshapiro				lastone = true;
686238032Speter				break;
686338032Speter			}
686438032Speter		}
686538032Speter		if (i < blen)
686638032Speter		{
686738032Speter			int val = atoi(s);
686838032Speter
686938032Speter			if (val < 0 || val >= nr_substrings)
687038032Speter			{
687138032Speter				syserr("field (%d) out of range, only %d substrings in pattern",
687238032Speter				       val, nr_substrings);
687338032Speter				return -1;
687438032Speter			}
687538032Speter			ibuf[i++] = val;
687638032Speter		}
687738032Speter		else
687838032Speter		{
687990792Sgshapiro			syserr("too many fields, %d max", blen);
688038032Speter			return -1;
688138032Speter		}
688238032Speter		s = ++cp;
688338032Speter	} while (!lastone);
688438032Speter	ibuf[i] = END_OF_FIELDS;
688538032Speter	return i;
688638032Speter}
688738032Speter
688838032Speterbool
688938032Speterregex_map_init(map, ap)
689038032Speter	MAP *map;
689138032Speter	char *ap;
689238032Speter{
689338032Speter	int regerr;
689438032Speter	struct regex_map *map_p;
689538032Speter	register char *p;
689638032Speter	char *sub_param = NULL;
689738032Speter	int pflags;
689890792Sgshapiro	static char defdstr[] = { (char) DEFAULT_DELIM, '\0' };
689938032Speter
690038032Speter	if (tTd(38, 2))
690190792Sgshapiro		sm_dprintf("regex_map_init: mapname '%s', args '%s'\n",
690264562Sgshapiro			map->map_mname, ap);
690338032Speter
690438032Speter	pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
690538032Speter	p = ap;
690664562Sgshapiro	map_p = (struct regex_map *) xnalloc(sizeof *map_p);
690771345Sgshapiro	map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t));
690838032Speter
690938032Speter	for (;;)
691064562Sgshapiro	{
691138032Speter		while (isascii(*p) && isspace(*p))
691238032Speter			p++;
691338032Speter		if (*p != '-')
691438032Speter			break;
691538032Speter		switch (*++p)
691638032Speter		{
691738032Speter		  case 'n':	/* not */
691838032Speter			map->map_mflags |= MF_REGEX_NOT;
691938032Speter			break;
692038032Speter
692138032Speter		  case 'f':	/* case sensitive */
692238032Speter			map->map_mflags |= MF_NOFOLDCASE;
692338032Speter			pflags &= ~REG_ICASE;
692438032Speter			break;
692538032Speter
692638032Speter		  case 'b':	/* basic regular expressions */
692738032Speter			pflags &= ~REG_EXTENDED;
692838032Speter			break;
692938032Speter
693038032Speter		  case 's':	/* substring match () syntax */
693138032Speter			sub_param = ++p;
693238032Speter			pflags &= ~REG_NOSUB;
693338032Speter			break;
693438032Speter
693538032Speter		  case 'd':	/* delimiter */
693664562Sgshapiro			map_p->regex_delim = ++p;
693738032Speter			break;
693838032Speter
693938032Speter		  case 'a':	/* map append */
694038032Speter			map->map_app = ++p;
694138032Speter			break;
694238032Speter
694338032Speter		  case 'm':	/* matchonly */
694438032Speter			map->map_mflags |= MF_MATCHONLY;
694538032Speter			break;
694638032Speter
6947120256Sgshapiro		  case 'q':
6948120256Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
6949120256Sgshapiro			break;
6950120256Sgshapiro
695164562Sgshapiro		  case 'S':
695264562Sgshapiro			map->map_spacesub = *++p;
695364562Sgshapiro			break;
695464562Sgshapiro
695564562Sgshapiro		  case 'D':
695664562Sgshapiro			map->map_mflags |= MF_DEFER;
695764562Sgshapiro			break;
695864562Sgshapiro
695938032Speter		}
696064562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
696164562Sgshapiro			p++;
696264562Sgshapiro		if (*p != '\0')
696364562Sgshapiro			*p++ = '\0';
696438032Speter	}
696538032Speter	if (tTd(38, 3))
696690792Sgshapiro		sm_dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
696738032Speter
696871345Sgshapiro	if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0)
696938032Speter	{
697038032Speter		/* Errorhandling */
697138032Speter		char errbuf[ERRBUF_SIZE];
697238032Speter
697371345Sgshapiro		(void) regerror(regerr, map_p->regex_pattern_buf,
697490792Sgshapiro			 errbuf, sizeof errbuf);
697590792Sgshapiro		syserr("pattern-compile-error: %s", errbuf);
697690792Sgshapiro		sm_free(map_p->regex_pattern_buf); /* XXX */
697790792Sgshapiro		sm_free(map_p); /* XXX */
697890792Sgshapiro		return false;
697938032Speter	}
698038032Speter
698138032Speter	if (map->map_app != NULL)
698238032Speter		map->map_app = newstr(map->map_app);
698364562Sgshapiro	if (map_p->regex_delim != NULL)
698464562Sgshapiro		map_p->regex_delim = newstr(map_p->regex_delim);
698538032Speter	else
698664562Sgshapiro		map_p->regex_delim = defdstr;
698738032Speter
698838032Speter	if (!bitset(REG_NOSUB, pflags))
698938032Speter	{
699038032Speter		/* substring matching */
699138032Speter		int substrings;
699264562Sgshapiro		int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1));
699338032Speter
699471345Sgshapiro		substrings = map_p->regex_pattern_buf->re_nsub + 1;
699538032Speter
699638032Speter		if (tTd(38, 3))
699790792Sgshapiro			sm_dprintf("regex_map_init: nr of substrings %d\n",
699864562Sgshapiro				substrings);
699938032Speter
700038032Speter		if (substrings >= MAX_MATCH)
700138032Speter		{
700290792Sgshapiro			syserr("too many substrings, %d max", MAX_MATCH);
700390792Sgshapiro			sm_free(map_p->regex_pattern_buf); /* XXX */
700490792Sgshapiro			sm_free(map_p); /* XXX */
700590792Sgshapiro			return false;
700638032Speter		}
700738032Speter		if (sub_param != NULL && sub_param[0] != '\0')
700838032Speter		{
700938032Speter			/* optional parameter -sfields */
701038032Speter			if (parse_fields(sub_param, fields,
701138032Speter					 MAX_MATCH + 1, substrings) == -1)
701290792Sgshapiro				return false;
701338032Speter		}
701438032Speter		else
701538032Speter		{
701638032Speter			int i;
701738032Speter
701890792Sgshapiro			/* set default fields */
701938032Speter			for (i = 0; i < substrings; i++)
702038032Speter				fields[i] = i;
702138032Speter			fields[i] = END_OF_FIELDS;
702238032Speter		}
702338032Speter		map_p->regex_subfields = fields;
702438032Speter		if (tTd(38, 3))
702538032Speter		{
702638032Speter			int *ip;
702738032Speter
702890792Sgshapiro			sm_dprintf("regex_map_init: subfields");
702938032Speter			for (ip = fields; *ip != END_OF_FIELDS; ip++)
703090792Sgshapiro				sm_dprintf(" %d", *ip);
703190792Sgshapiro			sm_dprintf("\n");
703238032Speter		}
703338032Speter	}
703490792Sgshapiro	map->map_db1 = (ARBPTR_T) map_p;	/* dirty hack */
703590792Sgshapiro	return true;
703638032Speter}
703738032Speter
703838032Speterstatic char *
703938032Speterregex_map_rewrite(map, s, slen, av)
704038032Speter	MAP *map;
704138032Speter	const char *s;
704238032Speter	size_t slen;
704338032Speter	char **av;
704438032Speter{
704538032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
704638032Speter		return map_rewrite(map, av[0], strlen(av[0]), NULL);
704738032Speter	else
704877349Sgshapiro		return map_rewrite(map, s, slen, av);
704938032Speter}
705038032Speter
705138032Speterchar *
705238032Speterregex_map_lookup(map, name, av, statp)
705338032Speter	MAP *map;
705438032Speter	char *name;
705538032Speter	char **av;
705638032Speter	int *statp;
705738032Speter{
705838032Speter	int reg_res;
705938032Speter	struct regex_map *map_p;
706038032Speter	regmatch_t pmatch[MAX_MATCH];
706138032Speter
706238032Speter	if (tTd(38, 20))
706338032Speter	{
706438032Speter		char **cpp;
706538032Speter
706690792Sgshapiro		sm_dprintf("regex_map_lookup: key '%s'\n", name);
706764562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
706890792Sgshapiro			sm_dprintf("regex_map_lookup: arg '%s'\n", *cpp);
706938032Speter	}
707038032Speter
707138032Speter	map_p = (struct regex_map *)(map->map_db1);
707271345Sgshapiro	reg_res = regexec(map_p->regex_pattern_buf,
707364562Sgshapiro			  name, MAX_MATCH, pmatch, 0);
707438032Speter
707538032Speter	if (bitset(MF_REGEX_NOT, map->map_mflags))
707638032Speter	{
707738032Speter		/* option -n */
707838032Speter		if (reg_res == REG_NOMATCH)
707990792Sgshapiro			return regex_map_rewrite(map, "", (size_t) 0, av);
708038032Speter		else
708138032Speter			return NULL;
708238032Speter	}
708338032Speter	if (reg_res == REG_NOMATCH)
708438032Speter		return NULL;
708538032Speter
708638032Speter	if (map_p->regex_subfields != NULL)
708738032Speter	{
708838032Speter		/* option -s */
708938032Speter		static char retbuf[MAXNAME];
709038032Speter		int fields[MAX_MATCH + 1];
709190792Sgshapiro		bool first = true;
709238032Speter		int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
709390792Sgshapiro		bool quotemode = false, bslashmode = false;
709438032Speter		register char *dp, *sp;
709538032Speter		char *endp, *ldp;
709638032Speter		int *ip;
709738032Speter
709838032Speter		dp = retbuf;
709938032Speter		ldp = retbuf + sizeof(retbuf) - 1;
710038032Speter
710138032Speter		if (av[1] != NULL)
710238032Speter		{
710338032Speter			if (parse_fields(av[1], fields, MAX_MATCH + 1,
710471345Sgshapiro					 (int) map_p->regex_pattern_buf->re_nsub + 1) == -1)
710538032Speter			{
710638032Speter				*statp = EX_CONFIG;
710738032Speter				return NULL;
710838032Speter			}
710938032Speter			ip = fields;
711038032Speter		}
711138032Speter		else
711238032Speter			ip = map_p->regex_subfields;
711338032Speter
711438032Speter		for ( ; *ip != END_OF_FIELDS; ip++)
711538032Speter		{
711638032Speter			if (!first)
711738032Speter			{
711864562Sgshapiro				for (sp = map_p->regex_delim; *sp; sp++)
711938032Speter				{
712038032Speter					if (dp < ldp)
712138032Speter						*dp++ = *sp;
712238032Speter				}
712338032Speter			}
712438032Speter			else
712590792Sgshapiro				first = false;
712638032Speter
712771345Sgshapiro			if (*ip >= MAX_MATCH ||
712871345Sgshapiro			    pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
712938032Speter				continue;
713038032Speter
713138032Speter			sp = name + pmatch[*ip].rm_so;
713238032Speter			endp = name + pmatch[*ip].rm_eo;
713338032Speter			for (; endp > sp; sp++)
713438032Speter			{
713538032Speter				if (dp < ldp)
713638032Speter				{
713764562Sgshapiro					if (bslashmode)
713864562Sgshapiro					{
713938032Speter						*dp++ = *sp;
714090792Sgshapiro						bslashmode = false;
714138032Speter					}
714264562Sgshapiro					else if (quotemode && *sp != '"' &&
714338032Speter						*sp != '\\')
714438032Speter					{
714538032Speter						*dp++ = *sp;
714638032Speter					}
714790792Sgshapiro					else switch (*dp++ = *sp)
714838032Speter					{
714990792Sgshapiro					  case '\\':
715090792Sgshapiro						bslashmode = true;
715138032Speter						break;
715238032Speter
715390792Sgshapiro					  case '(':
715438032Speter						cmntcnt++;
715538032Speter						break;
715638032Speter
715790792Sgshapiro					  case ')':
715838032Speter						cmntcnt--;
715938032Speter						break;
716038032Speter
716190792Sgshapiro					  case '<':
716238032Speter						anglecnt++;
716338032Speter						break;
716438032Speter
716590792Sgshapiro					  case '>':
716638032Speter						anglecnt--;
716738032Speter						break;
716838032Speter
716990792Sgshapiro					  case ' ':
717038032Speter						spacecnt++;
717138032Speter						break;
717238032Speter
717390792Sgshapiro					  case '"':
717438032Speter						quotemode = !quotemode;
717538032Speter						break;
717638032Speter					}
717738032Speter				}
717838032Speter			}
717938032Speter		}
718038032Speter		if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
718138032Speter		    bslashmode || spacecnt != 0)
718238032Speter		{
718364562Sgshapiro			sm_syslog(LOG_WARNING, NOQID,
718464562Sgshapiro				  "Warning: regex may cause prescan() failure map=%s lookup=%s",
718564562Sgshapiro				  map->map_mname, name);
718638032Speter			return NULL;
718738032Speter		}
718838032Speter
718938032Speter		*dp = '\0';
719038032Speter
719138032Speter		return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
719238032Speter	}
719338032Speter	return regex_map_rewrite(map, "", (size_t)0, av);
719438032Speter}
719538032Speter#endif /* MAP_REGEX */
719690792Sgshapiro/*
719764562Sgshapiro**  NSD modules
719864562Sgshapiro*/
719990792Sgshapiro#if MAP_NSD
720064562Sgshapiro
720164562Sgshapiro# include <ndbm.h>
720264562Sgshapiro# define _DATUM_DEFINED
720364562Sgshapiro# include <ns_api.h>
720464562Sgshapiro
720564562Sgshapirotypedef struct ns_map_list
720664562Sgshapiro{
720790792Sgshapiro	ns_map_t		*map;		/* XXX ns_ ? */
720890792Sgshapiro	char			*mapname;
720990792Sgshapiro	struct ns_map_list	*next;
721064562Sgshapiro} ns_map_list_t;
721164562Sgshapiro
721264562Sgshapirostatic ns_map_t *
721364562Sgshapirons_map_t_find(mapname)
721464562Sgshapiro	char *mapname;
721564562Sgshapiro{
721664562Sgshapiro	static ns_map_list_t *ns_maps = NULL;
721764562Sgshapiro	ns_map_list_t *ns_map;
721864562Sgshapiro
721964562Sgshapiro	/* walk the list of maps looking for the correctly named map */
722064562Sgshapiro	for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next)
722164562Sgshapiro	{
722264562Sgshapiro		if (strcmp(ns_map->mapname, mapname) == 0)
722364562Sgshapiro			break;
722464562Sgshapiro	}
722564562Sgshapiro
722664562Sgshapiro	/* if we are looking at a NULL ns_map_list_t, then create a new one */
722764562Sgshapiro	if (ns_map == NULL)
722864562Sgshapiro	{
722964562Sgshapiro		ns_map = (ns_map_list_t *) xalloc(sizeof *ns_map);
723064562Sgshapiro		ns_map->mapname = newstr(mapname);
723164562Sgshapiro		ns_map->map = (ns_map_t *) xalloc(sizeof *ns_map->map);
7232102528Sgshapiro		memset(ns_map->map, '\0', sizeof *ns_map->map);
723364562Sgshapiro		ns_map->next = ns_maps;
723464562Sgshapiro		ns_maps = ns_map;
723564562Sgshapiro	}
723664562Sgshapiro	return ns_map->map;
723764562Sgshapiro}
723864562Sgshapiro
723964562Sgshapirochar *
724064562Sgshapironsd_map_lookup(map, name, av, statp)
724164562Sgshapiro	MAP *map;
724264562Sgshapiro	char *name;
724364562Sgshapiro	char **av;
724464562Sgshapiro	int *statp;
724564562Sgshapiro{
724671345Sgshapiro	int buflen, r;
724764562Sgshapiro	char *p;
724864562Sgshapiro	ns_map_t *ns_map;
724964562Sgshapiro	char keybuf[MAXNAME + 1];
725064562Sgshapiro	char buf[MAXLINE];
725164562Sgshapiro
725264562Sgshapiro	if (tTd(38, 20))
725390792Sgshapiro		sm_dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
725464562Sgshapiro
725564562Sgshapiro	buflen = strlen(name);
725664562Sgshapiro	if (buflen > sizeof keybuf - 1)
725790792Sgshapiro		buflen = sizeof keybuf - 1;	/* XXX simply cut off? */
725864562Sgshapiro	memmove(keybuf, name, buflen);
725964562Sgshapiro	keybuf[buflen] = '\0';
726064562Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
726164562Sgshapiro		makelower(keybuf);
726264562Sgshapiro
726364562Sgshapiro	ns_map = ns_map_t_find(map->map_file);
726464562Sgshapiro	if (ns_map == NULL)
726564562Sgshapiro	{
726664562Sgshapiro		if (tTd(38, 20))
726790792Sgshapiro			sm_dprintf("nsd_map_t_find failed\n");
726871345Sgshapiro		*statp = EX_UNAVAILABLE;
726964562Sgshapiro		return NULL;
727064562Sgshapiro	}
727198121Sgshapiro	r = ns_lookup(ns_map, NULL, map->map_file, keybuf, NULL,
727298121Sgshapiro		      buf, sizeof buf);
727371345Sgshapiro	if (r == NS_UNAVAIL || r == NS_TRYAGAIN)
727471345Sgshapiro	{
727571345Sgshapiro		*statp = EX_TEMPFAIL;
727664562Sgshapiro		return NULL;
727771345Sgshapiro	}
727877349Sgshapiro	if (r == NS_BADREQ
727977349Sgshapiro# ifdef NS_NOPERM
728077349Sgshapiro	    || r == NS_NOPERM
728177349Sgshapiro# endif /* NS_NOPERM */
728277349Sgshapiro	    )
728371345Sgshapiro	{
728471345Sgshapiro		*statp = EX_CONFIG;
728571345Sgshapiro		return NULL;
728671345Sgshapiro	}
728771345Sgshapiro	if (r != NS_SUCCESS)
728871345Sgshapiro	{
728971345Sgshapiro		*statp = EX_NOTFOUND;
729071345Sgshapiro		return NULL;
729171345Sgshapiro	}
729264562Sgshapiro
729371345Sgshapiro	*statp = EX_OK;
729471345Sgshapiro
729564562Sgshapiro	/* Null out trailing \n */
729664562Sgshapiro	if ((p = strchr(buf, '\n')) != NULL)
729764562Sgshapiro		*p = '\0';
729864562Sgshapiro
729964562Sgshapiro	return map_rewrite(map, buf, strlen(buf), av);
730064562Sgshapiro}
730164562Sgshapiro#endif /* MAP_NSD */
730264562Sgshapiro
730364562Sgshapirochar *
730464562Sgshapiroarith_map_lookup(map, name, av, statp)
730564562Sgshapiro	MAP *map;
730664562Sgshapiro	char *name;
730764562Sgshapiro	char **av;
730864562Sgshapiro	int *statp;
730964562Sgshapiro{
731064562Sgshapiro	long r;
731164562Sgshapiro	long v[2];
731290792Sgshapiro	bool res = false;
731364562Sgshapiro	bool boolres;
731464562Sgshapiro	static char result[16];
731564562Sgshapiro	char **cpp;
731664562Sgshapiro
731764562Sgshapiro	if (tTd(38, 2))
731864562Sgshapiro	{
731990792Sgshapiro		sm_dprintf("arith_map_lookup: key '%s'\n", name);
732064562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
732190792Sgshapiro			sm_dprintf("arith_map_lookup: arg '%s'\n", *cpp);
732264562Sgshapiro	}
732364562Sgshapiro	r = 0;
732490792Sgshapiro	boolres = false;
732564562Sgshapiro	cpp = av;
732664562Sgshapiro	*statp = EX_OK;
732764562Sgshapiro
732864562Sgshapiro	/*
732964562Sgshapiro	**  read arguments for arith map
733064562Sgshapiro	**  - no check is made whether they are really numbers
733164562Sgshapiro	**  - just ignores args after the second
733264562Sgshapiro	*/
733390792Sgshapiro
733464562Sgshapiro	for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
733564562Sgshapiro		v[r++] = strtol(*cpp, NULL, 0);
733664562Sgshapiro
733764562Sgshapiro	/* operator and (at least) two operands given? */
733864562Sgshapiro	if (name != NULL && r == 2)
733964562Sgshapiro	{
734090792Sgshapiro		switch (*name)
734164562Sgshapiro		{
734264562Sgshapiro		  case '|':
734364562Sgshapiro			r = v[0] | v[1];
734464562Sgshapiro			break;
734564562Sgshapiro
734664562Sgshapiro		  case '&':
734764562Sgshapiro			r = v[0] & v[1];
734864562Sgshapiro			break;
734964562Sgshapiro
735064562Sgshapiro		  case '%':
735164562Sgshapiro			if (v[1] == 0)
735264562Sgshapiro				return NULL;
735364562Sgshapiro			r = v[0] % v[1];
735464562Sgshapiro			break;
735564562Sgshapiro		  case '+':
735664562Sgshapiro			r = v[0] + v[1];
735764562Sgshapiro			break;
735864562Sgshapiro
735964562Sgshapiro		  case '-':
736064562Sgshapiro			r = v[0] - v[1];
736164562Sgshapiro			break;
736264562Sgshapiro
736364562Sgshapiro		  case '*':
736464562Sgshapiro			r = v[0] * v[1];
736564562Sgshapiro			break;
736664562Sgshapiro
736764562Sgshapiro		  case '/':
736864562Sgshapiro			if (v[1] == 0)
736964562Sgshapiro				return NULL;
737064562Sgshapiro			r = v[0] / v[1];
737164562Sgshapiro			break;
737264562Sgshapiro
737364562Sgshapiro		  case 'l':
737464562Sgshapiro			res = v[0] < v[1];
737590792Sgshapiro			boolres = true;
737664562Sgshapiro			break;
737764562Sgshapiro
737864562Sgshapiro		  case '=':
737964562Sgshapiro			res = v[0] == v[1];
738090792Sgshapiro			boolres = true;
738164562Sgshapiro			break;
738264562Sgshapiro
738364562Sgshapiro		  default:
738464562Sgshapiro			/* XXX */
738564562Sgshapiro			*statp = EX_CONFIG;
738664562Sgshapiro			if (LogLevel > 10)
738764562Sgshapiro				sm_syslog(LOG_WARNING, NOQID,
738864562Sgshapiro					  "arith_map: unknown operator %c",
738964562Sgshapiro					  isprint(*name) ? *name : '?');
739064562Sgshapiro			return NULL;
739164562Sgshapiro		}
739264562Sgshapiro		if (boolres)
739390792Sgshapiro			(void) sm_snprintf(result, sizeof result,
739490792Sgshapiro				res ? "TRUE" : "FALSE");
739564562Sgshapiro		else
739690792Sgshapiro			(void) sm_snprintf(result, sizeof result, "%ld", r);
739764562Sgshapiro		return result;
739864562Sgshapiro	}
739964562Sgshapiro	*statp = EX_CONFIG;
740064562Sgshapiro	return NULL;
740164562Sgshapiro}
7402