map.c revision 168515
138032Speter/*
2168515Sgshapiro * Copyright (c) 1998-2006 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
16168515SgshapiroSM_RCSID("@(#)$Id: map.c,v 8.696 2007/04/03 21:33:14 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
42168515Sgshapiro#include "map.h"
43168515Sgshapiro
4490792Sgshapiro#if NEWDB
4564562Sgshapiro# if DB_VERSION_MAJOR < 2
4664562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
4764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
4864562Sgshapiro# if DB_VERSION_MAJOR == 2
4964562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
5064562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
5164562Sgshapiro# if DB_VERSION_MAJOR > 2
5264562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, void **));
5364562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
5464562Sgshapiro#endif /* NEWDB */
5573188Sgshapirostatic bool	extract_canonname __P((char *, char *, char *, char[], int));
5690792Sgshapirostatic void	map_close __P((STAB *, int));
5790792Sgshapirostatic void	map_init __P((STAB *, int));
5864562Sgshapiro#ifdef LDAPMAP
5990792Sgshapirostatic STAB *	ldapmap_findconn __P((SM_LDAP_STRUCT *));
6064562Sgshapiro#endif /* LDAPMAP */
6190792Sgshapiro#if NISPLUS
6264562Sgshapirostatic bool	nisplus_getcanonname __P((char *, int, int *));
6364562Sgshapiro#endif /* NISPLUS */
6490792Sgshapiro#if NIS
6564562Sgshapirostatic bool	nis_getcanonname __P((char *, int, int *));
6664562Sgshapiro#endif /* NIS */
6764562Sgshapiro#if NETINFO
6864562Sgshapirostatic bool	ni_getcanonname __P((char *, int, int *));
6964562Sgshapiro#endif /* NETINFO */
7064562Sgshapirostatic bool	text_getcanonname __P((char *, int, int *));
71132943Sgshapiro#if SOCKETMAP
72132943Sgshapirostatic STAB	*socket_map_findconn __P((const char*));
7364562Sgshapiro
74132943Sgshapiro/* XXX arbitrary limit for sanity */
75132943Sgshapiro# define SOCKETMAP_MAXL 1000000
76132943Sgshapiro#endif /* SOCKETMAP */
77132943Sgshapiro
7890792Sgshapiro/* default error message for trying to open a map in write mode */
7990792Sgshapiro#ifdef ENOSYS
8090792Sgshapiro# define SM_EMAPCANTWRITE	ENOSYS
8190792Sgshapiro#else /* ENOSYS */
8290792Sgshapiro# ifdef EFTYPE
8390792Sgshapiro#  define SM_EMAPCANTWRITE	EFTYPE
8490792Sgshapiro# else /* EFTYPE */
8590792Sgshapiro#  define SM_EMAPCANTWRITE	ENXIO
8690792Sgshapiro# endif /* EFTYPE */
8790792Sgshapiro#endif /* ENOSYS */
8890792Sgshapiro
8938032Speter/*
9038032Speter**  MAP.C -- implementations for various map classes.
9138032Speter**
9238032Speter**	Each map class implements a series of functions:
9338032Speter**
9438032Speter**	bool map_parse(MAP *map, char *args)
9590792Sgshapiro**		Parse the arguments from the config file.  Return true
9690792Sgshapiro**		if they were ok, false otherwise.  Fill in map with the
9738032Speter**		values.
9838032Speter**
9938032Speter**	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
10038032Speter**		Look up the key in the given map.  If found, do any
10138032Speter**		rewriting the map wants (including "args" if desired)
10238032Speter**		and return the value.  Set *pstat to the appropriate status
10338032Speter**		on error and return NULL.  Args will be NULL if called
10438032Speter**		from the alias routines, although this should probably
10538032Speter**		not be relied upon.  It is suggested you call map_rewrite
10638032Speter**		to return the results -- it takes care of null termination
10738032Speter**		and uses a dynamically expanded buffer as needed.
10838032Speter**
10938032Speter**	void map_store(MAP *map, char *key, char *value)
11038032Speter**		Store the key:value pair in the map.
11138032Speter**
11238032Speter**	bool map_open(MAP *map, int mode)
11338032Speter**		Open the map for the indicated mode.  Mode should
11490792Sgshapiro**		be either O_RDONLY or O_RDWR.  Return true if it
11590792Sgshapiro**		was opened successfully, false otherwise.  If the open
11690792Sgshapiro**		failed and the MF_OPTIONAL flag is not set, it should
11738032Speter**		also print an error.  If the MF_ALIAS bit is set
11838032Speter**		and this map class understands the @:@ convention, it
11938032Speter**		should call aliaswait() before returning.
12038032Speter**
12138032Speter**	void map_close(MAP *map)
12238032Speter**		Close the map.
12338032Speter**
12438032Speter**	This file also includes the implementation for getcanonname.
12538032Speter**	It is currently implemented in a pretty ad-hoc manner; it ought
12638032Speter**	to be more properly integrated into the map structure.
12738032Speter*/
12838032Speter
12938032Speter#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
13038032Speter# define LOCK_ON_OPEN	1	/* we can open/create a locked file */
13164562Sgshapiro#else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
13238032Speter# define LOCK_ON_OPEN	0	/* no such luck -- bend over backwards */
13364562Sgshapiro#endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
13438032Speter
13590792Sgshapiro/*
13638032Speter**  MAP_PARSEARGS -- parse config line arguments for database lookup
13738032Speter**
13838032Speter**	This is a generic version of the map_parse method.
13938032Speter**
14038032Speter**	Parameters:
14138032Speter**		map -- the map being initialized.
14238032Speter**		ap -- a pointer to the args on the config line.
14338032Speter**
14438032Speter**	Returns:
14590792Sgshapiro**		true -- if everything parsed OK.
14690792Sgshapiro**		false -- otherwise.
14738032Speter**
14838032Speter**	Side Effects:
14938032Speter**		null terminates the filename; stores it in map
15038032Speter*/
15138032Speter
15238032Speterbool
15338032Spetermap_parseargs(map, ap)
15438032Speter	MAP *map;
15538032Speter	char *ap;
15638032Speter{
15738032Speter	register char *p = ap;
15838032Speter
15964562Sgshapiro	/*
16090792Sgshapiro	**  There is no check whether there is really an argument,
16190792Sgshapiro	**  but that's not important enough to warrant extra code.
16264562Sgshapiro	*/
16390792Sgshapiro
16490792Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
16564562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
16638032Speter	for (;;)
16738032Speter	{
16838032Speter		while (isascii(*p) && isspace(*p))
16938032Speter			p++;
17038032Speter		if (*p != '-')
17138032Speter			break;
17238032Speter		switch (*++p)
17338032Speter		{
17438032Speter		  case 'N':
17538032Speter			map->map_mflags |= MF_INCLNULL;
17638032Speter			map->map_mflags &= ~MF_TRY0NULL;
17738032Speter			break;
17838032Speter
17938032Speter		  case 'O':
18038032Speter			map->map_mflags &= ~MF_TRY1NULL;
18138032Speter			break;
18238032Speter
18338032Speter		  case 'o':
18438032Speter			map->map_mflags |= MF_OPTIONAL;
18538032Speter			break;
18638032Speter
18738032Speter		  case 'f':
18838032Speter			map->map_mflags |= MF_NOFOLDCASE;
18938032Speter			break;
19038032Speter
19138032Speter		  case 'm':
19238032Speter			map->map_mflags |= MF_MATCHONLY;
19338032Speter			break;
19438032Speter
19538032Speter		  case 'A':
19638032Speter			map->map_mflags |= MF_APPEND;
19738032Speter			break;
19838032Speter
19938032Speter		  case 'q':
20038032Speter			map->map_mflags |= MF_KEEPQUOTES;
20138032Speter			break;
20238032Speter
20338032Speter		  case 'a':
20438032Speter			map->map_app = ++p;
20538032Speter			break;
20638032Speter
20738032Speter		  case 'T':
20838032Speter			map->map_tapp = ++p;
20938032Speter			break;
21038032Speter
21138032Speter		  case 'k':
21238032Speter			while (isascii(*++p) && isspace(*p))
21338032Speter				continue;
21438032Speter			map->map_keycolnm = p;
21538032Speter			break;
21638032Speter
21738032Speter		  case 'v':
21838032Speter			while (isascii(*++p) && isspace(*p))
21938032Speter				continue;
22038032Speter			map->map_valcolnm = p;
22138032Speter			break;
22238032Speter
22338032Speter		  case 'z':
22438032Speter			if (*++p != '\\')
22538032Speter				map->map_coldelim = *p;
22638032Speter			else
22738032Speter			{
22838032Speter				switch (*++p)
22938032Speter				{
23038032Speter				  case 'n':
23138032Speter					map->map_coldelim = '\n';
23238032Speter					break;
23338032Speter
23438032Speter				  case 't':
23538032Speter					map->map_coldelim = '\t';
23638032Speter					break;
23738032Speter
23838032Speter				  default:
23938032Speter					map->map_coldelim = '\\';
24038032Speter				}
24138032Speter			}
24238032Speter			break;
24338032Speter
24438032Speter		  case 't':
24538032Speter			map->map_mflags |= MF_NODEFER;
24638032Speter			break;
24738032Speter
24864562Sgshapiro
24964562Sgshapiro		  case 'S':
25064562Sgshapiro			map->map_spacesub = *++p;
25138032Speter			break;
25238032Speter
25364562Sgshapiro		  case 'D':
25464562Sgshapiro			map->map_mflags |= MF_DEFER;
25538032Speter			break;
25664562Sgshapiro
25764562Sgshapiro		  default:
25864562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
25964562Sgshapiro			break;
26038032Speter		}
26138032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
26238032Speter			p++;
26338032Speter		if (*p != '\0')
26438032Speter			*p++ = '\0';
26538032Speter	}
26638032Speter	if (map->map_app != NULL)
26738032Speter		map->map_app = newstr(map->map_app);
26838032Speter	if (map->map_tapp != NULL)
26938032Speter		map->map_tapp = newstr(map->map_tapp);
27038032Speter	if (map->map_keycolnm != NULL)
27138032Speter		map->map_keycolnm = newstr(map->map_keycolnm);
27238032Speter	if (map->map_valcolnm != NULL)
27338032Speter		map->map_valcolnm = newstr(map->map_valcolnm);
27438032Speter
27538032Speter	if (*p != '\0')
27638032Speter	{
27738032Speter		map->map_file = p;
27838032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
27938032Speter			p++;
28038032Speter		if (*p != '\0')
28138032Speter			*p++ = '\0';
28238032Speter		map->map_file = newstr(map->map_file);
28338032Speter	}
28438032Speter
28538032Speter	while (*p != '\0' && isascii(*p) && isspace(*p))
28638032Speter		p++;
28738032Speter	if (*p != '\0')
28838032Speter		map->map_rebuild = newstr(p);
28938032Speter
29038032Speter	if (map->map_file == NULL &&
29138032Speter	    !bitset(MCF_OPTFILE, map->map_class->map_cflags))
29238032Speter	{
29338032Speter		syserr("No file name for %s map %s",
29438032Speter			map->map_class->map_cname, map->map_mname);
29590792Sgshapiro		return false;
29638032Speter	}
29790792Sgshapiro	return true;
29838032Speter}
29990792Sgshapiro/*
30038032Speter**  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
30138032Speter**
30238032Speter**	It also adds the map_app string.  It can be used as a utility
30338032Speter**	in the map_lookup method.
30438032Speter**
30538032Speter**	Parameters:
30638032Speter**		map -- the map that causes this.
30738032Speter**		s -- the string to rewrite, NOT necessarily null terminated.
30838032Speter**		slen -- the length of s.
30938032Speter**		av -- arguments to interpolate into buf.
31038032Speter**
31138032Speter**	Returns:
31238032Speter**		Pointer to rewritten result.  This is static data that
31338032Speter**		should be copied if it is to be saved!
31438032Speter*/
31538032Speter
31638032Speterchar *
31738032Spetermap_rewrite(map, s, slen, av)
31838032Speter	register MAP *map;
31938032Speter	register const char *s;
32038032Speter	size_t slen;
32138032Speter	char **av;
32238032Speter{
32338032Speter	register char *bp;
32438032Speter	register char c;
32538032Speter	char **avp;
32638032Speter	register char *ap;
32738032Speter	size_t l;
32838032Speter	size_t len;
32938032Speter	static size_t buflen = 0;
33038032Speter	static char *buf = NULL;
33138032Speter
33238032Speter	if (tTd(39, 1))
33338032Speter	{
33490792Sgshapiro		sm_dprintf("map_rewrite(%.*s), av =", (int) slen, s);
33538032Speter		if (av == NULL)
33690792Sgshapiro			sm_dprintf(" (nullv)");
33738032Speter		else
33838032Speter		{
33938032Speter			for (avp = av; *avp != NULL; avp++)
34090792Sgshapiro				sm_dprintf("\n\t%s", *avp);
34138032Speter		}
34290792Sgshapiro		sm_dprintf("\n");
34338032Speter	}
34438032Speter
34538032Speter	/* count expected size of output (can safely overestimate) */
34638032Speter	l = len = slen;
34738032Speter	if (av != NULL)
34838032Speter	{
34938032Speter		const char *sp = s;
35038032Speter
35138032Speter		while (l-- > 0 && (c = *sp++) != '\0')
35238032Speter		{
35338032Speter			if (c != '%')
35438032Speter				continue;
35538032Speter			if (l-- <= 0)
35638032Speter				break;
35738032Speter			c = *sp++;
35838032Speter			if (!(isascii(c) && isdigit(c)))
35938032Speter				continue;
36038032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
36138032Speter				continue;
36238032Speter			if (*avp == NULL)
36338032Speter				continue;
36438032Speter			len += strlen(*avp);
36538032Speter		}
36638032Speter	}
36738032Speter	if (map->map_app != NULL)
36838032Speter		len += strlen(map->map_app);
36938032Speter	if (buflen < ++len)
37038032Speter	{
37138032Speter		/* need to malloc additional space */
37238032Speter		buflen = len;
37338032Speter		if (buf != NULL)
37477349Sgshapiro			sm_free(buf);
37590792Sgshapiro		buf = sm_pmalloc_x(buflen);
37638032Speter	}
37738032Speter
37838032Speter	bp = buf;
37938032Speter	if (av == NULL)
38038032Speter	{
38164562Sgshapiro		memmove(bp, s, slen);
38238032Speter		bp += slen;
38364562Sgshapiro
38464562Sgshapiro		/* assert(len > slen); */
38564562Sgshapiro		len -= slen;
38638032Speter	}
38738032Speter	else
38838032Speter	{
38938032Speter		while (slen-- > 0 && (c = *s++) != '\0')
39038032Speter		{
39138032Speter			if (c != '%')
39238032Speter			{
39338032Speter  pushc:
394120256Sgshapiro				if (len-- <= 1)
39590792Sgshapiro				     break;
39638032Speter				*bp++ = c;
39738032Speter				continue;
39838032Speter			}
39938032Speter			if (slen-- <= 0 || (c = *s++) == '\0')
40038032Speter				c = '%';
40138032Speter			if (c == '%')
40238032Speter				goto pushc;
40338032Speter			if (!(isascii(c) && isdigit(c)))
40438032Speter			{
405120256Sgshapiro				if (len-- <= 1)
406120256Sgshapiro				     break;
40738032Speter				*bp++ = '%';
40838032Speter				goto pushc;
40938032Speter			}
41038032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
41138032Speter				continue;
41238032Speter			if (*avp == NULL)
41338032Speter				continue;
41438032Speter
41538032Speter			/* transliterate argument into output string */
41664562Sgshapiro			for (ap = *avp; (c = *ap++) != '\0' && len > 0; --len)
41738032Speter				*bp++ = c;
41838032Speter		}
41938032Speter	}
42064562Sgshapiro	if (map->map_app != NULL && len > 0)
42190792Sgshapiro		(void) sm_strlcpy(bp, map->map_app, len);
42238032Speter	else
42338032Speter		*bp = '\0';
42438032Speter	if (tTd(39, 1))
42590792Sgshapiro		sm_dprintf("map_rewrite => %s\n", buf);
42638032Speter	return buf;
42738032Speter}
42890792Sgshapiro/*
42964562Sgshapiro**  INITMAPS -- rebuild alias maps
43038032Speter**
43138032Speter**	Parameters:
43264562Sgshapiro**		none.
43338032Speter**
43438032Speter**	Returns:
43538032Speter**		none.
43638032Speter*/
43738032Speter
43838032Spetervoid
43964562Sgshapiroinitmaps()
44038032Speter{
44138032Speter#if XDEBUG
44238032Speter	checkfd012("entering initmaps");
44364562Sgshapiro#endif /* XDEBUG */
44438032Speter	stabapply(map_init, 0);
44538032Speter#if XDEBUG
44638032Speter	checkfd012("exiting initmaps");
44764562Sgshapiro#endif /* XDEBUG */
44838032Speter}
44990792Sgshapiro/*
45064562Sgshapiro**  MAP_INIT -- rebuild a map
45164562Sgshapiro**
45264562Sgshapiro**	Parameters:
45364562Sgshapiro**		s -- STAB entry: if map: try to rebuild
45464562Sgshapiro**		unused -- unused variable
45564562Sgshapiro**
45664562Sgshapiro**	Returns:
45764562Sgshapiro**		none.
45864562Sgshapiro**
45964562Sgshapiro**	Side Effects:
46064562Sgshapiro**		will close already open rebuildable map.
46164562Sgshapiro*/
46238032Speter
46364562Sgshapiro/* ARGSUSED1 */
46464562Sgshapirostatic void
46564562Sgshapiromap_init(s, unused)
46638032Speter	register STAB *s;
46764562Sgshapiro	int unused;
46838032Speter{
46938032Speter	register MAP *map;
47038032Speter
47138032Speter	/* has to be a map */
47290792Sgshapiro	if (s->s_symtype != ST_MAP)
47338032Speter		return;
47438032Speter
47538032Speter	map = &s->s_map;
47638032Speter	if (!bitset(MF_VALID, map->map_mflags))
47738032Speter		return;
47838032Speter
47938032Speter	if (tTd(38, 2))
48090792Sgshapiro		sm_dprintf("map_init(%s:%s, %s)\n",
48138032Speter			map->map_class->map_cname == NULL ? "NULL" :
48238032Speter				map->map_class->map_cname,
48338032Speter			map->map_mname == NULL ? "NULL" : map->map_mname,
48464562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
48538032Speter
48664562Sgshapiro	if (!bitset(MF_ALIAS, map->map_mflags) ||
48764562Sgshapiro	    !bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
48838032Speter	{
48938032Speter		if (tTd(38, 3))
49090792Sgshapiro			sm_dprintf("\tnot rebuildable\n");
49138032Speter		return;
49238032Speter	}
49338032Speter
49438032Speter	/* if already open, close it (for nested open) */
49538032Speter	if (bitset(MF_OPEN, map->map_mflags))
49638032Speter	{
49777349Sgshapiro		map->map_mflags |= MF_CLOSING;
49838032Speter		map->map_class->map_close(map);
49977349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
50038032Speter	}
50138032Speter
50290792Sgshapiro	(void) rebuildaliases(map, false);
50364562Sgshapiro	return;
50464562Sgshapiro}
50590792Sgshapiro/*
50664562Sgshapiro**  OPENMAP -- open a map
50764562Sgshapiro**
50864562Sgshapiro**	Parameters:
50964562Sgshapiro**		map -- map to open (it must not be open).
51064562Sgshapiro**
51164562Sgshapiro**	Returns:
51264562Sgshapiro**		whether open succeeded.
51364562Sgshapiro*/
51464562Sgshapiro
51564562Sgshapirobool
51664562Sgshapiroopenmap(map)
51764562Sgshapiro	MAP *map;
51864562Sgshapiro{
51990792Sgshapiro	bool restore = false;
52064562Sgshapiro	bool savehold = HoldErrs;
52164562Sgshapiro	bool savequick = QuickAbort;
52264562Sgshapiro	int saveerrors = Errors;
52364562Sgshapiro
52464562Sgshapiro	if (!bitset(MF_VALID, map->map_mflags))
52590792Sgshapiro		return false;
52664562Sgshapiro
52764562Sgshapiro	/* better safe than sorry... */
52864562Sgshapiro	if (bitset(MF_OPEN, map->map_mflags))
52990792Sgshapiro		return true;
53064562Sgshapiro
53164562Sgshapiro	/* Don't send a map open error out via SMTP */
53264562Sgshapiro	if ((OnlyOneError || QuickAbort) &&
53364562Sgshapiro	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))
53438032Speter	{
53590792Sgshapiro		restore = true;
53690792Sgshapiro		HoldErrs = true;
53790792Sgshapiro		QuickAbort = false;
53838032Speter	}
53938032Speter
54064562Sgshapiro	errno = 0;
54138032Speter	if (map->map_class->map_open(map, O_RDONLY))
54238032Speter	{
54338032Speter		if (tTd(38, 4))
54490792Sgshapiro			sm_dprintf("openmap()\t%s:%s %s: valid\n",
54538032Speter				map->map_class->map_cname == NULL ? "NULL" :
54638032Speter					map->map_class->map_cname,
54738032Speter				map->map_mname == NULL ? "NULL" :
54838032Speter					map->map_mname,
54938032Speter				map->map_file == NULL ? "NULL" :
55038032Speter					map->map_file);
55138032Speter		map->map_mflags |= MF_OPEN;
55290792Sgshapiro		map->map_pid = CurrentPid;
55338032Speter	}
55438032Speter	else
55538032Speter	{
55638032Speter		if (tTd(38, 4))
55790792Sgshapiro			sm_dprintf("openmap()\t%s:%s %s: invalid%s%s\n",
55838032Speter				map->map_class->map_cname == NULL ? "NULL" :
55938032Speter					map->map_class->map_cname,
56038032Speter				map->map_mname == NULL ? "NULL" :
56138032Speter					map->map_mname,
56238032Speter				map->map_file == NULL ? "NULL" :
56338032Speter					map->map_file,
56464562Sgshapiro				errno == 0 ? "" : ": ",
56590792Sgshapiro				errno == 0 ? "" : sm_errstring(errno));
56638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
56738032Speter		{
56838032Speter			extern MAPCLASS BogusMapClass;
56938032Speter
57090792Sgshapiro			map->map_orgclass = map->map_class;
57138032Speter			map->map_class = &BogusMapClass;
57290792Sgshapiro			map->map_mflags |= MF_OPEN|MF_OPENBOGUS;
57390792Sgshapiro			map->map_pid = CurrentPid;
57438032Speter		}
57564562Sgshapiro		else
57664562Sgshapiro		{
57764562Sgshapiro			/* don't try again */
57864562Sgshapiro			map->map_mflags &= ~MF_VALID;
57964562Sgshapiro		}
58038032Speter	}
58164562Sgshapiro
58264562Sgshapiro	if (restore)
58364562Sgshapiro	{
58464562Sgshapiro		Errors = saveerrors;
58564562Sgshapiro		HoldErrs = savehold;
58664562Sgshapiro		QuickAbort = savequick;
58764562Sgshapiro	}
58864562Sgshapiro
58964562Sgshapiro	return bitset(MF_OPEN, map->map_mflags);
59038032Speter}
59190792Sgshapiro/*
59242575Speter**  CLOSEMAPS -- close all open maps opened by the current pid.
59342575Speter**
59442575Speter**	Parameters:
59590792Sgshapiro**		bogus -- only close bogus maps.
59642575Speter**
59742575Speter**	Returns:
59842575Speter**		none.
59942575Speter*/
60042575Speter
60142575Spetervoid
60290792Sgshapiroclosemaps(bogus)
60390792Sgshapiro	bool bogus;
60442575Speter{
60590792Sgshapiro	stabapply(map_close, bogus);
60642575Speter}
60790792Sgshapiro/*
60864562Sgshapiro**  MAP_CLOSE -- close a map opened by the current pid.
60964562Sgshapiro**
61064562Sgshapiro**	Parameters:
61190792Sgshapiro**		s -- STAB entry: if map: try to close
61290792Sgshapiro**		bogus -- only close bogus maps or MCF_NOTPERSIST maps.
61364562Sgshapiro**
61464562Sgshapiro**	Returns:
61564562Sgshapiro**		none.
61664562Sgshapiro*/
61742575Speter
61842575Speter/* ARGSUSED1 */
61964562Sgshapirostatic void
62090792Sgshapiromap_close(s, bogus)
62142575Speter	register STAB *s;
62290792Sgshapiro	int bogus;	/* int because of stabapply(), used as bool */
62342575Speter{
62442575Speter	MAP *map;
62590792Sgshapiro	extern MAPCLASS BogusMapClass;
62642575Speter
62790792Sgshapiro	if (s->s_symtype != ST_MAP)
62842575Speter		return;
62964562Sgshapiro
63042575Speter	map = &s->s_map;
63142575Speter
63290792Sgshapiro	/*
63390792Sgshapiro	**  close the map iff:
63490792Sgshapiro	**  it is valid and open and opened by this process
63590792Sgshapiro	**  and (!bogus or it's a bogus map or it is not persistent)
63690792Sgshapiro	**  negate this: return iff
63790792Sgshapiro	**  it is not valid or it is not open or not opened by this process
63890792Sgshapiro	**  or (bogus and it's not a bogus map and it's not not-persistent)
63990792Sgshapiro	*/
64090792Sgshapiro
64142575Speter	if (!bitset(MF_VALID, map->map_mflags) ||
64242575Speter	    !bitset(MF_OPEN, map->map_mflags) ||
64377349Sgshapiro	    bitset(MF_CLOSING, map->map_mflags) ||
64490792Sgshapiro	    map->map_pid != CurrentPid ||
64590792Sgshapiro	    (bogus && map->map_class != &BogusMapClass &&
64690792Sgshapiro	     !bitset(MCF_NOTPERSIST, map->map_class->map_cflags)))
64742575Speter		return;
64864562Sgshapiro
64990792Sgshapiro	if (map->map_class == &BogusMapClass && map->map_orgclass != NULL &&
65090792Sgshapiro	    map->map_orgclass != &BogusMapClass)
65190792Sgshapiro		map->map_class = map->map_orgclass;
65242575Speter	if (tTd(38, 5))
65390792Sgshapiro		sm_dprintf("closemaps: closing %s (%s)\n",
65464562Sgshapiro			map->map_mname == NULL ? "NULL" : map->map_mname,
65564562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
65664562Sgshapiro
65790792Sgshapiro	if (!bitset(MF_OPENBOGUS, map->map_mflags))
65890792Sgshapiro	{
65990792Sgshapiro		map->map_mflags |= MF_CLOSING;
66090792Sgshapiro		map->map_class->map_close(map);
66190792Sgshapiro	}
66290792Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_OPENBOGUS|MF_CLOSING);
66342575Speter}
664168515Sgshapiro
665168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
666168515Sgshapiroextern int getdomainname();
667168515Sgshapiro
668168515Sgshapiro/* this is mainly for backward compatibility in Sun environment */
669168515Sgshapirostatic char *
670168515Sgshapirosun_init_domain()
671168515Sgshapiro{
672168515Sgshapiro	/*
673168515Sgshapiro	**  Get the domain name from the kernel.
674168515Sgshapiro	**  If it does not start with a leading dot, then remove
675168515Sgshapiro	**  the first component.  Since leading dots are funny Unix
676168515Sgshapiro	**  files, we treat a leading "+" the same as a leading dot.
677168515Sgshapiro	**  Finally, force there to be at least one dot in the domain name
678168515Sgshapiro	**  (i.e. top-level domains are not allowed, like "com", must be
679168515Sgshapiro	**  something like "sun.com").
680168515Sgshapiro	*/
681168515Sgshapiro
682168515Sgshapiro	char buf[MAXNAME];
683168515Sgshapiro	char *period, *autodomain;
684168515Sgshapiro
685168515Sgshapiro	if (getdomainname(buf, sizeof buf) < 0)
686168515Sgshapiro		return NULL;
687168515Sgshapiro
688168515Sgshapiro	if (buf[0] == '\0')
689168515Sgshapiro		return NULL;
690168515Sgshapiro
691168515Sgshapiro	if (tTd(0, 20))
692168515Sgshapiro		printf("domainname = %s\n", buf);
693168515Sgshapiro
694168515Sgshapiro	if (buf[0] == '+')
695168515Sgshapiro		buf[0] = '.';
696168515Sgshapiro	period = strchr(buf, '.');
697168515Sgshapiro	if (period == NULL)
698168515Sgshapiro		autodomain = buf;
699168515Sgshapiro	else
700168515Sgshapiro		autodomain = period + 1;
701168515Sgshapiro	if (strchr(autodomain, '.') == NULL)
702168515Sgshapiro		return newstr(buf);
703168515Sgshapiro	else
704168515Sgshapiro		return newstr(autodomain);
705168515Sgshapiro}
706168515Sgshapiro#endif /* SUN_EXTENSIONS && SUN_INIT_DOMAIN */
707168515Sgshapiro
70890792Sgshapiro/*
70938032Speter**  GETCANONNAME -- look up name using service switch
71038032Speter**
71138032Speter**	Parameters:
71238032Speter**		host -- the host name to look up.
71338032Speter**		hbsize -- the size of the host buffer.
71438032Speter**		trymx -- if set, try MX records.
71590792Sgshapiro**		pttl -- pointer to return TTL (can be NULL).
71638032Speter**
71738032Speter**	Returns:
71890792Sgshapiro**		true -- if the host was found.
71990792Sgshapiro**		false -- otherwise.
72038032Speter*/
72138032Speter
72238032Speterbool
72390792Sgshapirogetcanonname(host, hbsize, trymx, pttl)
72438032Speter	char *host;
72538032Speter	int hbsize;
72638032Speter	bool trymx;
72790792Sgshapiro	int *pttl;
72838032Speter{
72938032Speter	int nmaps;
73038032Speter	int mapno;
73190792Sgshapiro	bool found = false;
73290792Sgshapiro	bool got_tempfail = false;
73364562Sgshapiro	auto int status;
73438032Speter	char *maptype[MAXMAPSTACK];
73538032Speter	short mapreturn[MAXMAPACTIONS];
736168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
737168515Sgshapiro	bool should_try_nis_domain = false;
738168515Sgshapiro	static char *nis_domain = NULL;
739168515Sgshapiro#endif
74038032Speter
74138032Speter	nmaps = switch_map_find("hosts", maptype, mapreturn);
74290792Sgshapiro	if (pttl != 0)
74390792Sgshapiro		*pttl = SM_DEFAULT_TTL;
74438032Speter	for (mapno = 0; mapno < nmaps; mapno++)
74538032Speter	{
74638032Speter		int i;
74738032Speter
74838032Speter		if (tTd(38, 20))
74990792Sgshapiro			sm_dprintf("getcanonname(%s), trying %s\n",
75038032Speter				host, maptype[mapno]);
75138032Speter		if (strcmp("files", maptype[mapno]) == 0)
75238032Speter		{
75364562Sgshapiro			found = text_getcanonname(host, hbsize, &status);
75438032Speter		}
75590792Sgshapiro#if NIS
75638032Speter		else if (strcmp("nis", maptype[mapno]) == 0)
75738032Speter		{
75864562Sgshapiro			found = nis_getcanonname(host, hbsize, &status);
759168515Sgshapiro# if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
760168515Sgshapiro			if (nis_domain == NULL)
761168515Sgshapiro				nis_domain = sun_init_domain();
762168515Sgshapiro# endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
76338032Speter		}
76464562Sgshapiro#endif /* NIS */
76590792Sgshapiro#if NISPLUS
76638032Speter		else if (strcmp("nisplus", maptype[mapno]) == 0)
76738032Speter		{
76864562Sgshapiro			found = nisplus_getcanonname(host, hbsize, &status);
769168515Sgshapiro# if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
770168515Sgshapiro			if (nis_domain == NULL)
771168515Sgshapiro				nis_domain = sun_init_domain();
772168515Sgshapiro# endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
77338032Speter		}
77464562Sgshapiro#endif /* NISPLUS */
77538032Speter#if NAMED_BIND
77638032Speter		else if (strcmp("dns", maptype[mapno]) == 0)
77738032Speter		{
77890792Sgshapiro			found = dns_getcanonname(host, hbsize, trymx, &status,							 pttl);
77938032Speter		}
78064562Sgshapiro#endif /* NAMED_BIND */
78138032Speter#if NETINFO
78238032Speter		else if (strcmp("netinfo", maptype[mapno]) == 0)
78338032Speter		{
78464562Sgshapiro			found = ni_getcanonname(host, hbsize, &status);
78538032Speter		}
78664562Sgshapiro#endif /* NETINFO */
78738032Speter		else
78838032Speter		{
78990792Sgshapiro			found = false;
79064562Sgshapiro			status = EX_UNAVAILABLE;
79138032Speter		}
79238032Speter
79338032Speter		/*
79438032Speter		**  Heuristic: if $m is not set, we are running during system
79538032Speter		**  startup.  In this case, when a name is apparently found
79638032Speter		**  but has no dot, treat is as not found.  This avoids
79738032Speter		**  problems if /etc/hosts has no FQDN but is listed first
79838032Speter		**  in the service switch.
79938032Speter		*/
80038032Speter
80138032Speter		if (found &&
80238032Speter		    (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
80338032Speter			break;
80438032Speter
805168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
806168515Sgshapiro		if (found)
807168515Sgshapiro			should_try_nis_domain = true;
808168515Sgshapiro		/* but don't break, as we need to try all methods first */
809168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
810168515Sgshapiro
81138032Speter		/* see if we should continue */
81264562Sgshapiro		if (status == EX_TEMPFAIL)
81338032Speter		{
81438032Speter			i = MA_TRYAGAIN;
81590792Sgshapiro			got_tempfail = true;
81638032Speter		}
81764562Sgshapiro		else if (status == EX_NOTFOUND)
81838032Speter			i = MA_NOTFOUND;
81938032Speter		else
82038032Speter			i = MA_UNAVAIL;
82138032Speter		if (bitset(1 << mapno, mapreturn[i]))
82238032Speter			break;
82338032Speter	}
82438032Speter
82538032Speter	if (found)
82638032Speter	{
82738032Speter		char *d;
82838032Speter
82938032Speter		if (tTd(38, 20))
83090792Sgshapiro			sm_dprintf("getcanonname(%s), found\n", host);
83138032Speter
83238032Speter		/*
83338032Speter		**  If returned name is still single token, compensate
83438032Speter		**  by tagging on $m.  This is because some sites set
83538032Speter		**  up their DNS or NIS databases wrong.
83638032Speter		*/
83738032Speter
83838032Speter		if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
83938032Speter		{
84038032Speter			d = macvalue('m', CurEnv);
84138032Speter			if (d != NULL &&
84238032Speter			    hbsize > (int) (strlen(host) + strlen(d) + 1))
84338032Speter			{
84438032Speter				if (host[strlen(host) - 1] != '.')
84590792Sgshapiro					(void) sm_strlcat2(host, ".", d,
84690792Sgshapiro							   hbsize);
84790792Sgshapiro				else
84890792Sgshapiro					(void) sm_strlcat(host, d, hbsize);
84938032Speter			}
85038032Speter			else
851168515Sgshapiro			{
852168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
853168515Sgshapiro				if (VendorCode == VENDOR_SUN &&
854168515Sgshapiro				    should_try_nis_domain)
855168515Sgshapiro				{
856168515Sgshapiro					goto try_nis_domain;
857168515Sgshapiro				}
858168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
85990792Sgshapiro				return false;
860168515Sgshapiro			}
86138032Speter		}
86290792Sgshapiro		return true;
86338032Speter	}
86438032Speter
865168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
866168515Sgshapiro	if (VendorCode == VENDOR_SUN && should_try_nis_domain)
867168515Sgshapiro	{
868168515Sgshapiro  try_nis_domain:
869168515Sgshapiro		if (nis_domain != NULL &&
870168515Sgshapiro		    strlen(nis_domain) + strlen(host) + 1 < hbsize)
871168515Sgshapiro		{
872168515Sgshapiro			(void) sm_strlcat2(host, ".", nis_domain, hbsize);
873168515Sgshapiro			return true;
874168515Sgshapiro		}
875168515Sgshapiro	}
876168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
877168515Sgshapiro
87838032Speter	if (tTd(38, 20))
87990792Sgshapiro		sm_dprintf("getcanonname(%s), failed, status=%d\n", host,
88090792Sgshapiro			status);
88138032Speter
88238032Speter	if (got_tempfail)
88373188Sgshapiro		SM_SET_H_ERRNO(TRY_AGAIN);
88438032Speter	else
88573188Sgshapiro		SM_SET_H_ERRNO(HOST_NOT_FOUND);
88690792Sgshapiro
88790792Sgshapiro	return false;
88838032Speter}
88990792Sgshapiro/*
89038032Speter**  EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
89138032Speter**
89238032Speter**	Parameters:
89338032Speter**		name -- the name against which to match.
89473188Sgshapiro**		dot -- where to reinsert '.' to get FQDN
89538032Speter**		line -- the /etc/hosts line.
89638032Speter**		cbuf -- the location to store the result.
89738032Speter**		cbuflen -- the size of cbuf.
89838032Speter**
89938032Speter**	Returns:
90090792Sgshapiro**		true -- if the line matched the desired name.
90190792Sgshapiro**		false -- otherwise.
90238032Speter*/
90338032Speter
90464562Sgshapirostatic bool
90573188Sgshapiroextract_canonname(name, dot, line, cbuf, cbuflen)
90638032Speter	char *name;
90773188Sgshapiro	char *dot;
90838032Speter	char *line;
90938032Speter	char cbuf[];
91038032Speter	int cbuflen;
91138032Speter{
91238032Speter	int i;
91338032Speter	char *p;
91490792Sgshapiro	bool found = false;
91538032Speter
91638032Speter	cbuf[0] = '\0';
91738032Speter	if (line[0] == '#')
91890792Sgshapiro		return false;
91938032Speter
92038032Speter	for (i = 1; ; i++)
92138032Speter	{
92238032Speter		char nbuf[MAXNAME + 1];
92338032Speter
924168515Sgshapiro		p = get_column(line, i, '\0', nbuf, sizeof(nbuf));
92538032Speter		if (p == NULL)
92638032Speter			break;
92738032Speter		if (*p == '\0')
92838032Speter			continue;
92938032Speter		if (cbuf[0] == '\0' ||
93038032Speter		    (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
93138032Speter		{
93290792Sgshapiro			(void) sm_strlcpy(cbuf, p, cbuflen);
93338032Speter		}
93490792Sgshapiro		if (sm_strcasecmp(name, p) == 0)
93590792Sgshapiro			found = true;
93673188Sgshapiro		else if (dot != NULL)
93773188Sgshapiro		{
93873188Sgshapiro			/* try looking for the FQDN as well */
93973188Sgshapiro			*dot = '.';
94090792Sgshapiro			if (sm_strcasecmp(name, p) == 0)
94190792Sgshapiro				found = true;
94273188Sgshapiro			*dot = '\0';
94373188Sgshapiro		}
94438032Speter	}
94538032Speter	if (found && strchr(cbuf, '.') == NULL)
94638032Speter	{
94738032Speter		/* try to add a domain on the end of the name */
94838032Speter		char *domain = macvalue('m', CurEnv);
94938032Speter
95038032Speter		if (domain != NULL &&
95164562Sgshapiro		    strlen(domain) + (i = strlen(cbuf)) + 1 < (size_t) cbuflen)
95238032Speter		{
95364562Sgshapiro			p = &cbuf[i];
95438032Speter			*p++ = '.';
95590792Sgshapiro			(void) sm_strlcpy(p, domain, cbuflen - i - 1);
95638032Speter		}
95738032Speter	}
95838032Speter	return found;
95938032Speter}
96090792Sgshapiro
96190792Sgshapiro/*
96290792Sgshapiro**  DNS modules
96390792Sgshapiro*/
96490792Sgshapiro
96590792Sgshapiro#if NAMED_BIND
96690792Sgshapiro# if DNSMAP
96790792Sgshapiro
96890792Sgshapiro#  include "sm_resolve.h"
96990792Sgshapiro#  if NETINET || NETINET6
97090792Sgshapiro#   include <arpa/inet.h>
97190792Sgshapiro#  endif /* NETINET || NETINET6 */
97290792Sgshapiro
97390792Sgshapiro/*
97490792Sgshapiro**  DNS_MAP_OPEN -- stub to check proper value for dns map type
97590792Sgshapiro*/
97690792Sgshapiro
97790792Sgshapirobool
97890792Sgshapirodns_map_open(map, mode)
97990792Sgshapiro	MAP *map;
98090792Sgshapiro	int mode;
98190792Sgshapiro{
98290792Sgshapiro	if (tTd(38,2))
98390792Sgshapiro		sm_dprintf("dns_map_open(%s, %d)\n", map->map_mname, mode);
98490792Sgshapiro
98590792Sgshapiro	mode &= O_ACCMODE;
98690792Sgshapiro	if (mode != O_RDONLY)
98790792Sgshapiro	{
98890792Sgshapiro		/* issue a pseudo-error message */
98990792Sgshapiro		errno = SM_EMAPCANTWRITE;
99090792Sgshapiro		return false;
99190792Sgshapiro	}
99290792Sgshapiro	return true;
99390792Sgshapiro}
99490792Sgshapiro
99590792Sgshapiro/*
99690792Sgshapiro**  DNS_MAP_PARSEARGS -- parse dns map definition args.
99790792Sgshapiro**
99890792Sgshapiro**	Parameters:
99990792Sgshapiro**		map -- pointer to MAP
100090792Sgshapiro**		args -- pointer to the args on the config line.
100190792Sgshapiro**
100290792Sgshapiro**	Returns:
100390792Sgshapiro**		true -- if everything parsed OK.
100490792Sgshapiro**		false -- otherwise.
100590792Sgshapiro*/
100690792Sgshapiro
1007168515Sgshapiro#define map_sizelimit	map_lockfd	/* overload field */
100890792Sgshapiro
100990792Sgshapirostruct dns_map
101090792Sgshapiro{
101190792Sgshapiro	int dns_m_type;
101290792Sgshapiro};
101390792Sgshapiro
101490792Sgshapirobool
101590792Sgshapirodns_map_parseargs(map,args)
101690792Sgshapiro	MAP *map;
101790792Sgshapiro	char *args;
101890792Sgshapiro{
101990792Sgshapiro	register char *p = args;
102090792Sgshapiro	struct dns_map *map_p;
102190792Sgshapiro
1022168515Sgshapiro	map_p = (struct dns_map *) xalloc(sizeof(*map_p));
102390792Sgshapiro	map_p->dns_m_type = -1;
102490792Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
102590792Sgshapiro
102690792Sgshapiro	for (;;)
102790792Sgshapiro	{
102890792Sgshapiro		while (isascii(*p) && isspace(*p))
102990792Sgshapiro			p++;
103090792Sgshapiro		if (*p != '-')
103190792Sgshapiro			break;
103290792Sgshapiro		switch (*++p)
103390792Sgshapiro		{
103490792Sgshapiro		  case 'N':
103590792Sgshapiro			map->map_mflags |= MF_INCLNULL;
103690792Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
103790792Sgshapiro			break;
103890792Sgshapiro
103990792Sgshapiro		  case 'O':
104090792Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
104190792Sgshapiro			break;
104290792Sgshapiro
104390792Sgshapiro		  case 'o':
104490792Sgshapiro			map->map_mflags |= MF_OPTIONAL;
104590792Sgshapiro			break;
104690792Sgshapiro
104790792Sgshapiro		  case 'f':
104890792Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
104990792Sgshapiro			break;
105090792Sgshapiro
105190792Sgshapiro		  case 'm':
105290792Sgshapiro			map->map_mflags |= MF_MATCHONLY;
105390792Sgshapiro			break;
105490792Sgshapiro
105590792Sgshapiro		  case 'A':
105690792Sgshapiro			map->map_mflags |= MF_APPEND;
105790792Sgshapiro			break;
105890792Sgshapiro
105990792Sgshapiro		  case 'q':
106090792Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
106190792Sgshapiro			break;
106290792Sgshapiro
106390792Sgshapiro		  case 't':
106490792Sgshapiro			map->map_mflags |= MF_NODEFER;
106590792Sgshapiro			break;
106690792Sgshapiro
106790792Sgshapiro		  case 'a':
106890792Sgshapiro			map->map_app = ++p;
106990792Sgshapiro			break;
107090792Sgshapiro
107190792Sgshapiro		  case 'T':
107290792Sgshapiro			map->map_tapp = ++p;
107390792Sgshapiro			break;
107490792Sgshapiro
107590792Sgshapiro		  case 'd':
107690792Sgshapiro			{
107790792Sgshapiro				char *h;
107890792Sgshapiro
107990792Sgshapiro				++p;
108090792Sgshapiro				h = strchr(p, ' ');
108190792Sgshapiro				if (h != NULL)
108290792Sgshapiro					*h = '\0';
108390792Sgshapiro				map->map_timeout = convtime(p, 's');
108490792Sgshapiro				if (h != NULL)
108590792Sgshapiro					*h = ' ';
108690792Sgshapiro			}
108790792Sgshapiro			break;
108890792Sgshapiro
108990792Sgshapiro		  case 'r':
109090792Sgshapiro			while (isascii(*++p) && isspace(*p))
109190792Sgshapiro				continue;
109290792Sgshapiro			map->map_retry = atoi(p);
109390792Sgshapiro			break;
109490792Sgshapiro
109590792Sgshapiro		  case 'z':
109690792Sgshapiro			if (*++p != '\\')
109790792Sgshapiro				map->map_coldelim = *p;
109890792Sgshapiro			else
109990792Sgshapiro			{
110090792Sgshapiro				switch (*++p)
110190792Sgshapiro				{
110290792Sgshapiro				  case 'n':
110390792Sgshapiro					map->map_coldelim = '\n';
110490792Sgshapiro					break;
110590792Sgshapiro
110690792Sgshapiro				  case 't':
110790792Sgshapiro					map->map_coldelim = '\t';
110890792Sgshapiro					break;
110990792Sgshapiro
111090792Sgshapiro				  default:
111190792Sgshapiro					map->map_coldelim = '\\';
111290792Sgshapiro				}
111390792Sgshapiro			}
111490792Sgshapiro			break;
111590792Sgshapiro
111690792Sgshapiro		  case 'Z':
111790792Sgshapiro			while (isascii(*++p) && isspace(*p))
111890792Sgshapiro				continue;
111990792Sgshapiro			map->map_sizelimit = atoi(p);
112090792Sgshapiro			break;
112190792Sgshapiro
112290792Sgshapiro			/* Start of dns_map specific args */
112390792Sgshapiro		  case 'R':		/* search field */
112490792Sgshapiro			{
112590792Sgshapiro				char *h;
112690792Sgshapiro
112790792Sgshapiro				while (isascii(*++p) && isspace(*p))
112890792Sgshapiro					continue;
112990792Sgshapiro				h = strchr(p, ' ');
113090792Sgshapiro				if (h != NULL)
113190792Sgshapiro					*h = '\0';
113290792Sgshapiro				map_p->dns_m_type = dns_string_to_type(p);
113390792Sgshapiro				if (h != NULL)
113490792Sgshapiro					*h = ' ';
113590792Sgshapiro				if (map_p->dns_m_type < 0)
113690792Sgshapiro					syserr("dns map %s: wrong type %s",
113790792Sgshapiro						map->map_mname, p);
113890792Sgshapiro			}
113990792Sgshapiro			break;
114090792Sgshapiro
114190792Sgshapiro		  case 'B':		/* base domain */
114290792Sgshapiro			{
114390792Sgshapiro				char *h;
114490792Sgshapiro
114590792Sgshapiro				while (isascii(*++p) && isspace(*p))
114690792Sgshapiro					continue;
114790792Sgshapiro				h = strchr(p, ' ');
114890792Sgshapiro				if (h != NULL)
114990792Sgshapiro					*h = '\0';
115090792Sgshapiro
115190792Sgshapiro				/*
115290792Sgshapiro				**  slight abuse of map->map_file; it isn't
115390792Sgshapiro				**	used otherwise in this map type.
115490792Sgshapiro				*/
115590792Sgshapiro
115690792Sgshapiro				map->map_file = newstr(p);
115790792Sgshapiro				if (h != NULL)
115890792Sgshapiro					*h = ' ';
115990792Sgshapiro			}
116090792Sgshapiro			break;
116190792Sgshapiro		}
116290792Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
116390792Sgshapiro			p++;
116490792Sgshapiro		if (*p != '\0')
116590792Sgshapiro			*p++ = '\0';
116690792Sgshapiro	}
116790792Sgshapiro	if (map_p->dns_m_type < 0)
116890792Sgshapiro		syserr("dns map %s: missing -R type", map->map_mname);
116990792Sgshapiro	if (map->map_app != NULL)
117090792Sgshapiro		map->map_app = newstr(map->map_app);
117190792Sgshapiro	if (map->map_tapp != NULL)
117290792Sgshapiro		map->map_tapp = newstr(map->map_tapp);
117390792Sgshapiro
117490792Sgshapiro	/*
1175168515Sgshapiro	**  Assumption: assert(sizeof(int) <= sizeof(ARBPTR_T));
117690792Sgshapiro	**  Even if this assumption is wrong, we use only one byte,
117790792Sgshapiro	**  so it doesn't really matter.
117890792Sgshapiro	*/
117990792Sgshapiro
118090792Sgshapiro	map->map_db1 = (ARBPTR_T) map_p;
118190792Sgshapiro	return true;
118290792Sgshapiro}
118390792Sgshapiro
118490792Sgshapiro/*
118590792Sgshapiro**  DNS_MAP_LOOKUP -- perform dns map lookup.
118690792Sgshapiro**
118790792Sgshapiro**	Parameters:
118890792Sgshapiro**		map -- pointer to MAP
118990792Sgshapiro**		name -- name to lookup
119090792Sgshapiro**		av -- arguments to interpolate into buf.
119190792Sgshapiro**		statp -- pointer to status (EX_)
119290792Sgshapiro**
119390792Sgshapiro**	Returns:
119490792Sgshapiro**		result of lookup if succeeded.
119590792Sgshapiro**		NULL -- otherwise.
119690792Sgshapiro*/
119790792Sgshapiro
119890792Sgshapirochar *
119990792Sgshapirodns_map_lookup(map, name, av, statp)
120090792Sgshapiro	MAP *map;
120190792Sgshapiro	char *name;
120290792Sgshapiro	char **av;
120390792Sgshapiro	int *statp;
120490792Sgshapiro{
120590792Sgshapiro	int resnum = 0;
120690792Sgshapiro	char *vp = NULL, *result = NULL;
120790792Sgshapiro	size_t vsize;
120890792Sgshapiro	struct dns_map *map_p;
120990792Sgshapiro	RESOURCE_RECORD_T *rr = NULL;
121090792Sgshapiro	DNS_REPLY_T *r = NULL;
121190792Sgshapiro#  if NETINET6
121290792Sgshapiro	static char buf6[INET6_ADDRSTRLEN];
121390792Sgshapiro#  endif /* NETINET6 */
121490792Sgshapiro
121590792Sgshapiro	if (tTd(38, 20))
121690792Sgshapiro		sm_dprintf("dns_map_lookup(%s, %s)\n",
121790792Sgshapiro			   map->map_mname, name);
121890792Sgshapiro
121990792Sgshapiro	map_p = (struct dns_map *)(map->map_db1);
122090792Sgshapiro	if (map->map_file != NULL && *map->map_file != '\0')
122190792Sgshapiro	{
122290792Sgshapiro		size_t len;
122390792Sgshapiro		char *appdomain;
122490792Sgshapiro
122590792Sgshapiro		len = strlen(map->map_file) + strlen(name) + 2;
122690792Sgshapiro		appdomain = (char *) sm_malloc(len);
122790792Sgshapiro		if (appdomain == NULL)
122890792Sgshapiro		{
122990792Sgshapiro			*statp = EX_UNAVAILABLE;
123090792Sgshapiro			return NULL;
123190792Sgshapiro		}
123290792Sgshapiro		(void) sm_strlcpyn(appdomain, len, 3, name, ".", map->map_file);
123390792Sgshapiro		r = dns_lookup_int(appdomain, C_IN, map_p->dns_m_type,
123490792Sgshapiro				   map->map_timeout, map->map_retry);
123590792Sgshapiro		sm_free(appdomain);
123690792Sgshapiro	}
123790792Sgshapiro	else
123890792Sgshapiro	{
123990792Sgshapiro		r = dns_lookup_int(name, C_IN, map_p->dns_m_type,
124090792Sgshapiro				   map->map_timeout, map->map_retry);
124190792Sgshapiro	}
124290792Sgshapiro
124390792Sgshapiro	if (r == NULL)
124490792Sgshapiro	{
124590792Sgshapiro		result = NULL;
1246120256Sgshapiro		if (h_errno == TRY_AGAIN || transienterror(errno))
124790792Sgshapiro			*statp = EX_TEMPFAIL;
124890792Sgshapiro		else
124990792Sgshapiro			*statp = EX_NOTFOUND;
125090792Sgshapiro		goto cleanup;
125190792Sgshapiro	}
125290792Sgshapiro	*statp = EX_OK;
125390792Sgshapiro	for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next)
125490792Sgshapiro	{
125590792Sgshapiro		char *type = NULL;
125690792Sgshapiro		char *value = NULL;
125790792Sgshapiro
125890792Sgshapiro		switch (rr->rr_type)
125990792Sgshapiro		{
126090792Sgshapiro		  case T_NS:
126190792Sgshapiro			type = "T_NS";
126290792Sgshapiro			value = rr->rr_u.rr_txt;
126390792Sgshapiro			break;
126490792Sgshapiro		  case T_CNAME:
126590792Sgshapiro			type = "T_CNAME";
126690792Sgshapiro			value = rr->rr_u.rr_txt;
126790792Sgshapiro			break;
126890792Sgshapiro		  case T_AFSDB:
126990792Sgshapiro			type = "T_AFSDB";
127090792Sgshapiro			value = rr->rr_u.rr_mx->mx_r_domain;
127190792Sgshapiro			break;
127290792Sgshapiro		  case T_SRV:
127390792Sgshapiro			type = "T_SRV";
127490792Sgshapiro			value = rr->rr_u.rr_srv->srv_r_target;
127590792Sgshapiro			break;
127690792Sgshapiro		  case T_PTR:
127790792Sgshapiro			type = "T_PTR";
127890792Sgshapiro			value = rr->rr_u.rr_txt;
127990792Sgshapiro			break;
128090792Sgshapiro		  case T_TXT:
128190792Sgshapiro			type = "T_TXT";
128290792Sgshapiro			value = rr->rr_u.rr_txt;
128390792Sgshapiro			break;
128490792Sgshapiro		  case T_MX:
128590792Sgshapiro			type = "T_MX";
128690792Sgshapiro			value = rr->rr_u.rr_mx->mx_r_domain;
128790792Sgshapiro			break;
128890792Sgshapiro#  if NETINET
128990792Sgshapiro		  case T_A:
129090792Sgshapiro			type = "T_A";
129190792Sgshapiro			value = inet_ntoa(*(rr->rr_u.rr_a));
129290792Sgshapiro			break;
129390792Sgshapiro#  endif /* NETINET */
129490792Sgshapiro#  if NETINET6
129590792Sgshapiro		  case T_AAAA:
129690792Sgshapiro			type = "T_AAAA";
129790792Sgshapiro			value = anynet_ntop(rr->rr_u.rr_aaaa, buf6,
1298168515Sgshapiro					    sizeof(buf6));
129990792Sgshapiro			break;
130090792Sgshapiro#  endif /* NETINET6 */
130190792Sgshapiro		}
130290792Sgshapiro
130398841Sgshapiro		(void) strreplnonprt(value, 'X');
130490792Sgshapiro		if (map_p->dns_m_type != rr->rr_type)
130590792Sgshapiro		{
130690792Sgshapiro			if (tTd(38, 40))
130790792Sgshapiro				sm_dprintf("\tskipping type %s (%d) value %s\n",
130890792Sgshapiro					   type != NULL ? type : "<UNKNOWN>",
130990792Sgshapiro					   rr->rr_type,
131090792Sgshapiro					   value != NULL ? value : "<NO VALUE>");
131190792Sgshapiro			continue;
131290792Sgshapiro		}
131390792Sgshapiro
131490792Sgshapiro#  if NETINET6
131590792Sgshapiro		if (rr->rr_type == T_AAAA && value == NULL)
131690792Sgshapiro		{
131790792Sgshapiro			result = NULL;
131890792Sgshapiro			*statp = EX_DATAERR;
131990792Sgshapiro			if (tTd(38, 40))
132090792Sgshapiro				sm_dprintf("\tbad T_AAAA conversion\n");
132190792Sgshapiro			goto cleanup;
132290792Sgshapiro		}
132390792Sgshapiro#  endif /* NETINET6 */
132490792Sgshapiro		if (tTd(38, 40))
132590792Sgshapiro			sm_dprintf("\tfound type %s (%d) value %s\n",
132690792Sgshapiro				   type != NULL ? type : "<UNKNOWN>",
132790792Sgshapiro				   rr->rr_type,
132890792Sgshapiro				   value != NULL ? value : "<NO VALUE>");
132990792Sgshapiro		if (value != NULL &&
133090792Sgshapiro		    (map->map_coldelim == '\0' ||
133190792Sgshapiro		     map->map_sizelimit == 1 ||
133290792Sgshapiro		     bitset(MF_MATCHONLY, map->map_mflags)))
133390792Sgshapiro		{
133490792Sgshapiro			/* Only care about the first match */
133590792Sgshapiro			vp = newstr(value);
133690792Sgshapiro			break;
133790792Sgshapiro		}
133890792Sgshapiro		else if (vp == NULL)
133990792Sgshapiro		{
134090792Sgshapiro			/* First result */
134190792Sgshapiro			vp = newstr(value);
134290792Sgshapiro		}
134390792Sgshapiro		else
134490792Sgshapiro		{
134590792Sgshapiro			/* concatenate the results */
134690792Sgshapiro			int sz;
134790792Sgshapiro			char *new;
134890792Sgshapiro
134990792Sgshapiro			sz = strlen(vp) + strlen(value) + 2;
135090792Sgshapiro			new = xalloc(sz);
135190792Sgshapiro			(void) sm_snprintf(new, sz, "%s%c%s",
135290792Sgshapiro					   vp, map->map_coldelim, value);
135390792Sgshapiro			sm_free(vp);
135490792Sgshapiro			vp = new;
135590792Sgshapiro			if (map->map_sizelimit > 0 &&
135690792Sgshapiro			    ++resnum >= map->map_sizelimit)
135790792Sgshapiro				break;
135890792Sgshapiro		}
135990792Sgshapiro	}
136090792Sgshapiro	if (vp == NULL)
136190792Sgshapiro	{
136290792Sgshapiro		result = NULL;
136390792Sgshapiro		*statp = EX_NOTFOUND;
136490792Sgshapiro		if (tTd(38, 40))
136590792Sgshapiro			sm_dprintf("\tno match found\n");
136690792Sgshapiro		goto cleanup;
136790792Sgshapiro	}
136890792Sgshapiro
136990792Sgshapiro	/* Cleanly truncate for rulesets */
137090792Sgshapiro	truncate_at_delim(vp, PSBUFSIZE / 2, map->map_coldelim);
137190792Sgshapiro
137290792Sgshapiro	vsize = strlen(vp);
137390792Sgshapiro
137490792Sgshapiro	if (LogLevel > 9)
137590792Sgshapiro		sm_syslog(LOG_INFO, CurEnv->e_id, "dns %.100s => %s",
137690792Sgshapiro			  name, vp);
137790792Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
137890792Sgshapiro		result = map_rewrite(map, name, strlen(name), NULL);
137990792Sgshapiro	else
138090792Sgshapiro		result = map_rewrite(map, vp, vsize, av);
138190792Sgshapiro
138290792Sgshapiro  cleanup:
138390792Sgshapiro	if (vp != NULL)
138490792Sgshapiro		sm_free(vp);
138590792Sgshapiro	if (r != NULL)
138690792Sgshapiro		dns_free_data(r);
138790792Sgshapiro	return result;
138890792Sgshapiro}
138990792Sgshapiro# endif /* DNSMAP */
139090792Sgshapiro#endif /* NAMED_BIND */
139190792Sgshapiro
139290792Sgshapiro/*
139338032Speter**  NDBM modules
139438032Speter*/
139538032Speter
139690792Sgshapiro#if NDBM
139738032Speter
139838032Speter/*
139938032Speter**  NDBM_MAP_OPEN -- DBM-style map open
140038032Speter*/
140138032Speter
140238032Speterbool
140338032Speterndbm_map_open(map, mode)
140438032Speter	MAP *map;
140538032Speter	int mode;
140638032Speter{
140738032Speter	register DBM *dbm;
140864562Sgshapiro	int save_errno;
140938032Speter	int dfd;
141038032Speter	int pfd;
141164562Sgshapiro	long sff;
141238032Speter	int ret;
141338032Speter	int smode = S_IREAD;
141498121Sgshapiro	char dirfile[MAXPATHLEN];
141598121Sgshapiro	char pagfile[MAXPATHLEN];
141664562Sgshapiro	struct stat st;
141738032Speter	struct stat std, stp;
141838032Speter
141938032Speter	if (tTd(38, 2))
142090792Sgshapiro		sm_dprintf("ndbm_map_open(%s, %s, %d)\n",
142138032Speter			map->map_mname, map->map_file, mode);
142238032Speter	map->map_lockfd = -1;
142338032Speter	mode &= O_ACCMODE;
142438032Speter
142538032Speter	/* do initial file and directory checks */
1426168515Sgshapiro	if (sm_strlcpyn(dirfile, sizeof(dirfile), 2,
1427168515Sgshapiro			map->map_file, ".dir") >= sizeof(dirfile) ||
1428168515Sgshapiro	    sm_strlcpyn(pagfile, sizeof(pagfile), 2,
1429168515Sgshapiro			map->map_file, ".pag") >= sizeof(pagfile))
143098121Sgshapiro	{
143198121Sgshapiro		errno = 0;
143298121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
143398121Sgshapiro			syserr("dbm map \"%s\": map file %s name too long",
143498121Sgshapiro				map->map_mname, map->map_file);
143598121Sgshapiro		return false;
143698121Sgshapiro	}
143738032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
143838032Speter	if (mode == O_RDWR)
143938032Speter	{
144038032Speter		sff |= SFF_CREAT;
144164562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
144238032Speter			sff |= SFF_NOSLINK;
144364562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
144438032Speter			sff |= SFF_NOHLINK;
144538032Speter		smode = S_IWRITE;
144638032Speter	}
144738032Speter	else
144838032Speter	{
144964562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
145038032Speter			sff |= SFF_NOWLINK;
145138032Speter	}
145264562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
145338032Speter		sff |= SFF_SAFEDIRPATH;
145438032Speter	ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
145590792Sgshapiro		       sff, smode, &std);
145638032Speter	if (ret == 0)
145738032Speter		ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
145838032Speter			       sff, smode, &stp);
145964562Sgshapiro
146038032Speter	if (ret != 0)
146138032Speter	{
146238032Speter		char *prob = "unsafe";
146338032Speter
146438032Speter		/* cannot open this map */
146538032Speter		if (ret == ENOENT)
146638032Speter			prob = "missing";
146738032Speter		if (tTd(38, 2))
146890792Sgshapiro			sm_dprintf("\t%s map file: %d\n", prob, ret);
146938032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
147038032Speter			syserr("dbm map \"%s\": %s map file %s",
147138032Speter				map->map_mname, prob, map->map_file);
147290792Sgshapiro		return false;
147338032Speter	}
147438032Speter	if (std.st_mode == ST_MODE_NOFILE)
147538032Speter		mode |= O_CREAT|O_EXCL;
147638032Speter
147764562Sgshapiro# if LOCK_ON_OPEN
147838032Speter	if (mode == O_RDONLY)
147938032Speter		mode |= O_SHLOCK;
148038032Speter	else
148138032Speter		mode |= O_TRUNC|O_EXLOCK;
148264562Sgshapiro# else /* LOCK_ON_OPEN */
148338032Speter	if ((mode & O_ACCMODE) == O_RDWR)
148438032Speter	{
148564562Sgshapiro#  if NOFTRUNCATE
148638032Speter		/*
148738032Speter		**  Warning: race condition.  Try to lock the file as
148838032Speter		**  quickly as possible after opening it.
148938032Speter		**	This may also have security problems on some systems,
149038032Speter		**	but there isn't anything we can do about it.
149138032Speter		*/
149238032Speter
149338032Speter		mode |= O_TRUNC;
149464562Sgshapiro#  else /* NOFTRUNCATE */
149538032Speter		/*
149638032Speter		**  This ugly code opens the map without truncating it,
149738032Speter		**  locks the file, then truncates it.  Necessary to
149838032Speter		**  avoid race conditions.
149938032Speter		*/
150038032Speter
150138032Speter		int dirfd;
150238032Speter		int pagfd;
150364562Sgshapiro		long sff = SFF_CREAT|SFF_OPENASROOT;
150438032Speter
150564562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
150638032Speter			sff |= SFF_NOSLINK;
150764562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
150838032Speter			sff |= SFF_NOHLINK;
150938032Speter
151038032Speter		dirfd = safeopen(dirfile, mode, DBMMODE, sff);
151138032Speter		pagfd = safeopen(pagfile, mode, DBMMODE, sff);
151238032Speter
151338032Speter		if (dirfd < 0 || pagfd < 0)
151438032Speter		{
151564562Sgshapiro			save_errno = errno;
151638032Speter			if (dirfd >= 0)
151738032Speter				(void) close(dirfd);
151838032Speter			if (pagfd >= 0)
151938032Speter				(void) close(pagfd);
152038032Speter			errno = save_errno;
152138032Speter			syserr("ndbm_map_open: cannot create database %s",
152238032Speter				map->map_file);
152390792Sgshapiro			return false;
152438032Speter		}
152538032Speter		if (ftruncate(dirfd, (off_t) 0) < 0 ||
152638032Speter		    ftruncate(pagfd, (off_t) 0) < 0)
152738032Speter		{
152864562Sgshapiro			save_errno = errno;
152938032Speter			(void) close(dirfd);
153038032Speter			(void) close(pagfd);
153138032Speter			errno = save_errno;
153238032Speter			syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
153338032Speter				map->map_file);
153490792Sgshapiro			return false;
153538032Speter		}
153638032Speter
153738032Speter		/* if new file, get "before" bits for later filechanged check */
153838032Speter		if (std.st_mode == ST_MODE_NOFILE &&
153938032Speter		    (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
154038032Speter		{
154164562Sgshapiro			save_errno = errno;
154238032Speter			(void) close(dirfd);
154338032Speter			(void) close(pagfd);
154438032Speter			errno = save_errno;
154538032Speter			syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
154638032Speter				map->map_file);
154790792Sgshapiro			return false;
154838032Speter		}
154938032Speter
155038032Speter		/* have to save the lock for the duration (bletch) */
155138032Speter		map->map_lockfd = dirfd;
155264562Sgshapiro		(void) close(pagfd);
155338032Speter
155438032Speter		/* twiddle bits for dbm_open */
155538032Speter		mode &= ~(O_CREAT|O_EXCL);
155664562Sgshapiro#  endif /* NOFTRUNCATE */
155738032Speter	}
155864562Sgshapiro# endif /* LOCK_ON_OPEN */
155938032Speter
156038032Speter	/* open the database */
156138032Speter	dbm = dbm_open(map->map_file, mode, DBMMODE);
156238032Speter	if (dbm == NULL)
156338032Speter	{
156464562Sgshapiro		save_errno = errno;
156538032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
156690792Sgshapiro		    aliaswait(map, ".pag", false))
156790792Sgshapiro			return true;
156864562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
156938032Speter		if (map->map_lockfd >= 0)
157064562Sgshapiro			(void) close(map->map_lockfd);
157164562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
157238032Speter		errno = save_errno;
157338032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
157438032Speter			syserr("Cannot open DBM database %s", map->map_file);
157590792Sgshapiro		return false;
157638032Speter	}
157738032Speter	dfd = dbm_dirfno(dbm);
157838032Speter	pfd = dbm_pagfno(dbm);
157938032Speter	if (dfd == pfd)
158038032Speter	{
158138032Speter		/* heuristic: if files are linked, this is actually gdbm */
158238032Speter		dbm_close(dbm);
158364562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
158438032Speter		if (map->map_lockfd >= 0)
158564562Sgshapiro			(void) close(map->map_lockfd);
158664562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
158738032Speter		errno = 0;
158838032Speter		syserr("dbm map \"%s\": cannot support GDBM",
158938032Speter			map->map_mname);
159090792Sgshapiro		return false;
159138032Speter	}
159238032Speter
159338032Speter	if (filechanged(dirfile, dfd, &std) ||
159438032Speter	    filechanged(pagfile, pfd, &stp))
159538032Speter	{
159664562Sgshapiro		save_errno = errno;
159738032Speter		dbm_close(dbm);
159864562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
159938032Speter		if (map->map_lockfd >= 0)
160064562Sgshapiro			(void) close(map->map_lockfd);
160164562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
160238032Speter		errno = save_errno;
160338032Speter		syserr("ndbm_map_open(%s): file changed after open",
160438032Speter			map->map_file);
160590792Sgshapiro		return false;
160638032Speter	}
160738032Speter
160838032Speter	map->map_db1 = (ARBPTR_T) dbm;
160964562Sgshapiro
161064562Sgshapiro	/*
161164562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
161264562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
161364562Sgshapiro	**  map_mtime to be set
161464562Sgshapiro	*/
161564562Sgshapiro
161677349Sgshapiro	if (fstat(pfd, &st) >= 0)
161764562Sgshapiro		map->map_mtime = st.st_mtime;
161864562Sgshapiro
161938032Speter	if (mode == O_RDONLY)
162038032Speter	{
162164562Sgshapiro# if LOCK_ON_OPEN
162238032Speter		if (dfd >= 0)
162338032Speter			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
162438032Speter		if (pfd >= 0)
162538032Speter			(void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
162664562Sgshapiro# endif /* LOCK_ON_OPEN */
162738032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
162890792Sgshapiro		    !aliaswait(map, ".pag", true))
162990792Sgshapiro			return false;
163038032Speter	}
163138032Speter	else
163238032Speter	{
163338032Speter		map->map_mflags |= MF_LOCKED;
163442575Speter		if (geteuid() == 0 && TrustedUid != 0)
163538032Speter		{
163664562Sgshapiro#  if HASFCHOWN
163742575Speter			if (fchown(dfd, TrustedUid, -1) < 0 ||
163842575Speter			    fchown(pfd, TrustedUid, -1) < 0)
163938032Speter			{
164038032Speter				int err = errno;
164138032Speter
164238032Speter				sm_syslog(LOG_ALERT, NOQID,
164338032Speter					  "ownership change on %s failed: %s",
164490792Sgshapiro					  map->map_file, sm_errstring(err));
164538032Speter				message("050 ownership change on %s failed: %s",
164690792Sgshapiro					map->map_file, sm_errstring(err));
164738032Speter			}
164890792Sgshapiro#  else /* HASFCHOWN */
164990792Sgshapiro			sm_syslog(LOG_ALERT, NOQID,
165090792Sgshapiro				  "no fchown(): cannot change ownership on %s",
165190792Sgshapiro				  map->map_file);
165290792Sgshapiro			message("050 no fchown(): cannot change ownership on %s",
165390792Sgshapiro				map->map_file);
165464562Sgshapiro#  endif /* HASFCHOWN */
165538032Speter		}
165638032Speter	}
165790792Sgshapiro	return true;
165838032Speter}
165938032Speter
166038032Speter
166138032Speter/*
166238032Speter**  NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
166338032Speter*/
166438032Speter
166538032Speterchar *
166638032Speterndbm_map_lookup(map, name, av, statp)
166738032Speter	MAP *map;
166838032Speter	char *name;
166938032Speter	char **av;
167038032Speter	int *statp;
167138032Speter{
167238032Speter	datum key, val;
167377349Sgshapiro	int dfd, pfd;
167438032Speter	char keybuf[MAXNAME + 1];
167538032Speter	struct stat stbuf;
167638032Speter
167738032Speter	if (tTd(38, 20))
167890792Sgshapiro		sm_dprintf("ndbm_map_lookup(%s, %s)\n",
167938032Speter			map->map_mname, name);
168038032Speter
168138032Speter	key.dptr = name;
168238032Speter	key.dsize = strlen(name);
168338032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
168438032Speter	{
1685168515Sgshapiro		if (key.dsize > sizeof(keybuf) - 1)
1686168515Sgshapiro			key.dsize = sizeof(keybuf) - 1;
168764562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
168838032Speter		keybuf[key.dsize] = '\0';
168938032Speter		makelower(keybuf);
169038032Speter		key.dptr = keybuf;
169138032Speter	}
169238032Speterlockdbm:
169377349Sgshapiro	dfd = dbm_dirfno((DBM *) map->map_db1);
169477349Sgshapiro	if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
169577349Sgshapiro		(void) lockfile(dfd, map->map_file, ".dir", LOCK_SH);
169677349Sgshapiro	pfd = dbm_pagfno((DBM *) map->map_db1);
169777349Sgshapiro	if (pfd < 0 || fstat(pfd, &stbuf) < 0 ||
169877349Sgshapiro	    stbuf.st_mtime > map->map_mtime)
169938032Speter	{
170038032Speter		/* Reopen the database to sync the cache */
170138032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
170238032Speter								 : O_RDONLY;
170338032Speter
170477349Sgshapiro		if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
170577349Sgshapiro			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
170677349Sgshapiro		map->map_mflags |= MF_CLOSING;
170738032Speter		map->map_class->map_close(map);
170877349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
170938032Speter		if (map->map_class->map_open(map, omode))
171038032Speter		{
171138032Speter			map->map_mflags |= MF_OPEN;
171290792Sgshapiro			map->map_pid = CurrentPid;
171338032Speter			if ((omode && O_ACCMODE) == O_RDWR)
171438032Speter				map->map_mflags |= MF_WRITABLE;
171538032Speter			goto lockdbm;
171638032Speter		}
171738032Speter		else
171838032Speter		{
171938032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
172038032Speter			{
172138032Speter				extern MAPCLASS BogusMapClass;
172238032Speter
172338032Speter				*statp = EX_TEMPFAIL;
172490792Sgshapiro				map->map_orgclass = map->map_class;
172538032Speter				map->map_class = &BogusMapClass;
172638032Speter				map->map_mflags |= MF_OPEN;
172790792Sgshapiro				map->map_pid = CurrentPid;
172838032Speter				syserr("Cannot reopen NDBM database %s",
172938032Speter					map->map_file);
173038032Speter			}
173138032Speter			return NULL;
173238032Speter		}
173338032Speter	}
173438032Speter	val.dptr = NULL;
173538032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
173638032Speter	{
173738032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
173838032Speter		if (val.dptr != NULL)
173938032Speter			map->map_mflags &= ~MF_TRY1NULL;
174038032Speter	}
174138032Speter	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
174238032Speter	{
174338032Speter		key.dsize++;
174438032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
174538032Speter		if (val.dptr != NULL)
174638032Speter			map->map_mflags &= ~MF_TRY0NULL;
174738032Speter	}
174877349Sgshapiro	if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
174977349Sgshapiro		(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
175038032Speter	if (val.dptr == NULL)
175138032Speter		return NULL;
175238032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
175338032Speter		return map_rewrite(map, name, strlen(name), NULL);
175438032Speter	else
175538032Speter		return map_rewrite(map, val.dptr, val.dsize, av);
175638032Speter}
175738032Speter
175838032Speter
175938032Speter/*
176038032Speter**  NDBM_MAP_STORE -- store a datum in the database
176138032Speter*/
176238032Speter
176338032Spetervoid
176438032Speterndbm_map_store(map, lhs, rhs)
176538032Speter	register MAP *map;
176638032Speter	char *lhs;
176738032Speter	char *rhs;
176838032Speter{
176938032Speter	datum key;
177038032Speter	datum data;
177164562Sgshapiro	int status;
177238032Speter	char keybuf[MAXNAME + 1];
177338032Speter
177438032Speter	if (tTd(38, 12))
177590792Sgshapiro		sm_dprintf("ndbm_map_store(%s, %s, %s)\n",
177638032Speter			map->map_mname, lhs, rhs);
177738032Speter
177838032Speter	key.dsize = strlen(lhs);
177938032Speter	key.dptr = lhs;
178038032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
178138032Speter	{
1782168515Sgshapiro		if (key.dsize > sizeof(keybuf) - 1)
1783168515Sgshapiro			key.dsize = sizeof(keybuf) - 1;
178464562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
178538032Speter		keybuf[key.dsize] = '\0';
178638032Speter		makelower(keybuf);
178738032Speter		key.dptr = keybuf;
178838032Speter	}
178938032Speter
179038032Speter	data.dsize = strlen(rhs);
179138032Speter	data.dptr = rhs;
179238032Speter
179338032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
179438032Speter	{
179538032Speter		key.dsize++;
179638032Speter		data.dsize++;
179738032Speter	}
179838032Speter
179964562Sgshapiro	status = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
180064562Sgshapiro	if (status > 0)
180138032Speter	{
180238032Speter		if (!bitset(MF_APPEND, map->map_mflags))
180338032Speter			message("050 Warning: duplicate alias name %s", lhs);
180438032Speter		else
180538032Speter		{
180638032Speter			static char *buf = NULL;
180738032Speter			static int bufsiz = 0;
180838032Speter			auto int xstat;
180938032Speter			datum old;
181038032Speter
181138032Speter			old.dptr = ndbm_map_lookup(map, key.dptr,
181290792Sgshapiro						   (char **) NULL, &xstat);
181338032Speter			if (old.dptr != NULL && *(char *) old.dptr != '\0')
181438032Speter			{
181538032Speter				old.dsize = strlen(old.dptr);
181638032Speter				if (data.dsize + old.dsize + 2 > bufsiz)
181738032Speter				{
181838032Speter					if (buf != NULL)
181990792Sgshapiro						(void) sm_free(buf);
182038032Speter					bufsiz = data.dsize + old.dsize + 2;
182190792Sgshapiro					buf = sm_pmalloc_x(bufsiz);
182238032Speter				}
182390792Sgshapiro				(void) sm_strlcpyn(buf, bufsiz, 3,
182490792Sgshapiro					data.dptr, ",", old.dptr);
182538032Speter				data.dsize = data.dsize + old.dsize + 1;
182638032Speter				data.dptr = buf;
182738032Speter				if (tTd(38, 9))
182890792Sgshapiro					sm_dprintf("ndbm_map_store append=%s\n",
182964562Sgshapiro						data.dptr);
183038032Speter			}
183138032Speter		}
183264562Sgshapiro		status = dbm_store((DBM *) map->map_db1,
183364562Sgshapiro				   key, data, DBM_REPLACE);
183438032Speter	}
183564562Sgshapiro	if (status != 0)
183664562Sgshapiro		syserr("readaliases: dbm put (%s): %d", lhs, status);
183738032Speter}
183838032Speter
183938032Speter
184038032Speter/*
184138032Speter**  NDBM_MAP_CLOSE -- close the database
184238032Speter*/
184338032Speter
184438032Spetervoid
184538032Speterndbm_map_close(map)
184638032Speter	register MAP  *map;
184738032Speter{
184838032Speter	if (tTd(38, 9))
184990792Sgshapiro		sm_dprintf("ndbm_map_close(%s, %s, %lx)\n",
185038032Speter			map->map_mname, map->map_file, map->map_mflags);
185138032Speter
185238032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
185338032Speter	{
185464562Sgshapiro# ifdef NDBM_YP_COMPAT
185538032Speter		bool inclnull;
185642575Speter		char buf[MAXHOSTNAMELEN];
185738032Speter
185838032Speter		inclnull = bitset(MF_INCLNULL, map->map_mflags);
185938032Speter		map->map_mflags &= ~MF_INCLNULL;
186038032Speter
186138032Speter		if (strstr(map->map_file, "/yp/") != NULL)
186238032Speter		{
186338032Speter			long save_mflags = map->map_mflags;
186438032Speter
186538032Speter			map->map_mflags |= MF_NOFOLDCASE;
186638032Speter
1867168515Sgshapiro			(void) sm_snprintf(buf, sizeof(buf), "%010ld", curtime());
186838032Speter			ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
186938032Speter
1870168515Sgshapiro			(void) gethostname(buf, sizeof(buf));
187138032Speter			ndbm_map_store(map, "YP_MASTER_NAME", buf);
187238032Speter
187338032Speter			map->map_mflags = save_mflags;
187438032Speter		}
187538032Speter
187638032Speter		if (inclnull)
187738032Speter			map->map_mflags |= MF_INCLNULL;
187864562Sgshapiro# endif /* NDBM_YP_COMPAT */
187938032Speter
188038032Speter		/* write out the distinguished alias */
188138032Speter		ndbm_map_store(map, "@", "@");
188238032Speter	}
188338032Speter	dbm_close((DBM *) map->map_db1);
188438032Speter
188538032Speter	/* release lock (if needed) */
188664562Sgshapiro# if !LOCK_ON_OPEN
188738032Speter	if (map->map_lockfd >= 0)
188838032Speter		(void) close(map->map_lockfd);
188964562Sgshapiro# endif /* !LOCK_ON_OPEN */
189038032Speter}
189138032Speter
189264562Sgshapiro#endif /* NDBM */
189390792Sgshapiro/*
189438032Speter**  NEWDB (Hash and BTree) Modules
189538032Speter*/
189638032Speter
189790792Sgshapiro#if NEWDB
189838032Speter
189938032Speter/*
190038032Speter**  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
190138032Speter**
190238032Speter**	These do rather bizarre locking.  If you can lock on open,
190338032Speter**	do that to avoid the condition of opening a database that
190438032Speter**	is being rebuilt.  If you don't, we'll try to fake it, but
190538032Speter**	there will be a race condition.  If opening for read-only,
190638032Speter**	we immediately release the lock to avoid freezing things up.
190738032Speter**	We really ought to hold the lock, but guarantee that we won't
190838032Speter**	be pokey about it.  That's hard to do.
190938032Speter*/
191038032Speter
191138032Speter/* these should be K line arguments */
191264562Sgshapiro# if DB_VERSION_MAJOR < 2
191364562Sgshapiro#  define db_cachesize	cachesize
191464562Sgshapiro#  define h_nelem	nelem
191564562Sgshapiro#  ifndef DB_CACHE_SIZE
191664562Sgshapiro#   define DB_CACHE_SIZE	(1024 * 1024)	/* database memory cache size */
191764562Sgshapiro#  endif /* ! DB_CACHE_SIZE */
191864562Sgshapiro#  ifndef DB_HASH_NELEM
191964562Sgshapiro#   define DB_HASH_NELEM	4096		/* (starting) size of hash table */
192064562Sgshapiro#  endif /* ! DB_HASH_NELEM */
192164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
192238032Speter
192338032Speterbool
192438032Speterbt_map_open(map, mode)
192538032Speter	MAP *map;
192638032Speter	int mode;
192738032Speter{
192864562Sgshapiro# if DB_VERSION_MAJOR < 2
192938032Speter	BTREEINFO btinfo;
193064562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
193164562Sgshapiro# if DB_VERSION_MAJOR == 2
193238032Speter	DB_INFO btinfo;
193364562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
193464562Sgshapiro# if DB_VERSION_MAJOR > 2
193564562Sgshapiro	void *btinfo = NULL;
193664562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
193738032Speter
193838032Speter	if (tTd(38, 2))
193990792Sgshapiro		sm_dprintf("bt_map_open(%s, %s, %d)\n",
194038032Speter			map->map_mname, map->map_file, mode);
194138032Speter
194264562Sgshapiro# if DB_VERSION_MAJOR < 3
1943168515Sgshapiro	memset(&btinfo, '\0', sizeof(btinfo));
194464562Sgshapiro#  ifdef DB_CACHE_SIZE
194538032Speter	btinfo.db_cachesize = DB_CACHE_SIZE;
194664562Sgshapiro#  endif /* DB_CACHE_SIZE */
194764562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
194864562Sgshapiro
194938032Speter	return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
195038032Speter}
195138032Speter
195238032Speterbool
195338032Speterhash_map_open(map, mode)
195438032Speter	MAP *map;
195538032Speter	int mode;
195638032Speter{
195764562Sgshapiro# if DB_VERSION_MAJOR < 2
195838032Speter	HASHINFO hinfo;
195964562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
196064562Sgshapiro# if DB_VERSION_MAJOR == 2
196138032Speter	DB_INFO hinfo;
196264562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
196364562Sgshapiro# if DB_VERSION_MAJOR > 2
196464562Sgshapiro	void *hinfo = NULL;
196564562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
196638032Speter
196738032Speter	if (tTd(38, 2))
196890792Sgshapiro		sm_dprintf("hash_map_open(%s, %s, %d)\n",
196938032Speter			map->map_mname, map->map_file, mode);
197038032Speter
197164562Sgshapiro# if DB_VERSION_MAJOR < 3
1972168515Sgshapiro	memset(&hinfo, '\0', sizeof(hinfo));
197364562Sgshapiro#  ifdef DB_HASH_NELEM
197438032Speter	hinfo.h_nelem = DB_HASH_NELEM;
197564562Sgshapiro#  endif /* DB_HASH_NELEM */
197664562Sgshapiro#  ifdef DB_CACHE_SIZE
197738032Speter	hinfo.db_cachesize = DB_CACHE_SIZE;
197864562Sgshapiro#  endif /* DB_CACHE_SIZE */
197964562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
198064562Sgshapiro
198138032Speter	return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
198238032Speter}
198338032Speter
198464562Sgshapirostatic bool
198538032Speterdb_map_open(map, mode, mapclassname, dbtype, openinfo)
198638032Speter	MAP *map;
198738032Speter	int mode;
198838032Speter	char *mapclassname;
198938032Speter	DBTYPE dbtype;
199064562Sgshapiro# if DB_VERSION_MAJOR < 2
199138032Speter	const void *openinfo;
199264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
199364562Sgshapiro# if DB_VERSION_MAJOR == 2
199438032Speter	DB_INFO *openinfo;
199564562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
199664562Sgshapiro# if DB_VERSION_MAJOR > 2
199764562Sgshapiro	void **openinfo;
199864562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
199938032Speter{
200038032Speter	DB *db = NULL;
200138032Speter	int i;
200238032Speter	int omode;
200338032Speter	int smode = S_IREAD;
200438032Speter	int fd;
200564562Sgshapiro	long sff;
200664562Sgshapiro	int save_errno;
200738032Speter	struct stat st;
200898121Sgshapiro	char buf[MAXPATHLEN];
200938032Speter
201038032Speter	/* do initial file and directory checks */
2011168515Sgshapiro	if (sm_strlcpy(buf, map->map_file, sizeof(buf)) >= sizeof(buf))
201298121Sgshapiro	{
201398121Sgshapiro		errno = 0;
201498121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
201598121Sgshapiro			syserr("map \"%s\": map file %s name too long",
201698121Sgshapiro				map->map_mname, map->map_file);
201798121Sgshapiro		return false;
201898121Sgshapiro	}
201938032Speter	i = strlen(buf);
202038032Speter	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
202198121Sgshapiro	{
2022168515Sgshapiro		if (sm_strlcat(buf, ".db", sizeof(buf)) >= sizeof(buf))
202398121Sgshapiro		{
202498121Sgshapiro			errno = 0;
202598121Sgshapiro			if (!bitset(MF_OPTIONAL, map->map_mflags))
202698121Sgshapiro				syserr("map \"%s\": map file %s name too long",
202798121Sgshapiro					map->map_mname, map->map_file);
202898121Sgshapiro			return false;
202998121Sgshapiro		}
203098121Sgshapiro	}
203138032Speter
203238032Speter	mode &= O_ACCMODE;
203338032Speter	omode = mode;
203438032Speter
203538032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
203638032Speter	if (mode == O_RDWR)
203738032Speter	{
203838032Speter		sff |= SFF_CREAT;
203964562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
204038032Speter			sff |= SFF_NOSLINK;
204164562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
204238032Speter			sff |= SFF_NOHLINK;
204338032Speter		smode = S_IWRITE;
204438032Speter	}
204538032Speter	else
204638032Speter	{
204764562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
204838032Speter			sff |= SFF_NOWLINK;
204938032Speter	}
205064562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
205138032Speter		sff |= SFF_SAFEDIRPATH;
205238032Speter	i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
205364562Sgshapiro
205438032Speter	if (i != 0)
205538032Speter	{
205638032Speter		char *prob = "unsafe";
205738032Speter
205838032Speter		/* cannot open this map */
205938032Speter		if (i == ENOENT)
206038032Speter			prob = "missing";
206138032Speter		if (tTd(38, 2))
206290792Sgshapiro			sm_dprintf("\t%s map file: %s\n", prob, sm_errstring(i));
206338032Speter		errno = i;
206438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
206538032Speter			syserr("%s map \"%s\": %s map file %s",
206638032Speter				mapclassname, map->map_mname, prob, buf);
206790792Sgshapiro		return false;
206838032Speter	}
206938032Speter	if (st.st_mode == ST_MODE_NOFILE)
207038032Speter		omode |= O_CREAT|O_EXCL;
207138032Speter
207238032Speter	map->map_lockfd = -1;
207338032Speter
207464562Sgshapiro# if LOCK_ON_OPEN
207538032Speter	if (mode == O_RDWR)
207638032Speter		omode |= O_TRUNC|O_EXLOCK;
207738032Speter	else
207838032Speter		omode |= O_SHLOCK;
207964562Sgshapiro# else /* LOCK_ON_OPEN */
208038032Speter	/*
208138032Speter	**  Pre-lock the file to avoid race conditions.  In particular,
208238032Speter	**  since dbopen returns NULL if the file is zero length, we
208338032Speter	**  must have a locked instance around the dbopen.
208438032Speter	*/
208538032Speter
208638032Speter	fd = open(buf, omode, DBMMODE);
208738032Speter	if (fd < 0)
208838032Speter	{
208938032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
209038032Speter			syserr("db_map_open: cannot pre-open database %s", buf);
209190792Sgshapiro		return false;
209238032Speter	}
209338032Speter
209438032Speter	/* make sure no baddies slipped in just before the open... */
209538032Speter	if (filechanged(buf, fd, &st))
209638032Speter	{
209764562Sgshapiro		save_errno = errno;
209838032Speter		(void) close(fd);
209938032Speter		errno = save_errno;
210038032Speter		syserr("db_map_open(%s): file changed after pre-open", buf);
210190792Sgshapiro		return false;
210238032Speter	}
210338032Speter
210438032Speter	/* if new file, get the "before" bits for later filechanged check */
210538032Speter	if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
210638032Speter	{
210764562Sgshapiro		save_errno = errno;
210838032Speter		(void) close(fd);
210938032Speter		errno = save_errno;
211038032Speter		syserr("db_map_open(%s): cannot fstat pre-opened file",
211138032Speter			buf);
211290792Sgshapiro		return false;
211338032Speter	}
211438032Speter
211538032Speter	/* actually lock the pre-opened file */
211638032Speter	if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
211738032Speter		syserr("db_map_open: cannot lock %s", buf);
211838032Speter
211938032Speter	/* set up mode bits for dbopen */
212038032Speter	if (mode == O_RDWR)
212138032Speter		omode |= O_TRUNC;
212238032Speter	omode &= ~(O_EXCL|O_CREAT);
212364562Sgshapiro# endif /* LOCK_ON_OPEN */
212438032Speter
212564562Sgshapiro# if DB_VERSION_MAJOR < 2
212638032Speter	db = dbopen(buf, omode, DBMMODE, dbtype, openinfo);
212764562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
212838032Speter	{
212938032Speter		int flags = 0;
213064562Sgshapiro#  if DB_VERSION_MAJOR > 2
213164562Sgshapiro		int ret;
213264562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
213338032Speter
213438032Speter		if (mode == O_RDONLY)
213538032Speter			flags |= DB_RDONLY;
213638032Speter		if (bitset(O_CREAT, omode))
213738032Speter			flags |= DB_CREATE;
213838032Speter		if (bitset(O_TRUNC, omode))
213938032Speter			flags |= DB_TRUNCATE;
2140110560Sgshapiro		SM_DB_FLAG_ADD(flags);
214138032Speter
214264562Sgshapiro#  if DB_VERSION_MAJOR > 2
214364562Sgshapiro		ret = db_create(&db, NULL, 0);
214464562Sgshapiro#  ifdef DB_CACHE_SIZE
214564562Sgshapiro		if (ret == 0 && db != NULL)
214664562Sgshapiro		{
214764562Sgshapiro			ret = db->set_cachesize(db, 0, DB_CACHE_SIZE, 0);
214864562Sgshapiro			if (ret != 0)
214964562Sgshapiro			{
215064562Sgshapiro				(void) db->close(db, 0);
215164562Sgshapiro				db = NULL;
215264562Sgshapiro			}
215364562Sgshapiro		}
215464562Sgshapiro#  endif /* DB_CACHE_SIZE */
215564562Sgshapiro#  ifdef DB_HASH_NELEM
215664562Sgshapiro		if (dbtype == DB_HASH && ret == 0 && db != NULL)
215764562Sgshapiro		{
215864562Sgshapiro			ret = db->set_h_nelem(db, DB_HASH_NELEM);
215964562Sgshapiro			if (ret != 0)
216064562Sgshapiro			{
216164562Sgshapiro				(void) db->close(db, 0);
216264562Sgshapiro				db = NULL;
216364562Sgshapiro			}
216464562Sgshapiro		}
216564562Sgshapiro#  endif /* DB_HASH_NELEM */
216664562Sgshapiro		if (ret == 0 && db != NULL)
216764562Sgshapiro		{
2168110560Sgshapiro			ret = db->open(db,
2169110560Sgshapiro					DBTXN	/* transaction for DB 4.1 */
2170110560Sgshapiro					buf, NULL, dbtype, flags, DBMMODE);
217164562Sgshapiro			if (ret != 0)
217264562Sgshapiro			{
217373188Sgshapiro#ifdef DB_OLD_VERSION
217473188Sgshapiro				if (ret == DB_OLD_VERSION)
217573188Sgshapiro					ret = EINVAL;
217673188Sgshapiro#endif /* DB_OLD_VERSION */
217764562Sgshapiro				(void) db->close(db, 0);
217864562Sgshapiro				db = NULL;
217964562Sgshapiro			}
218064562Sgshapiro		}
218164562Sgshapiro		errno = ret;
218264562Sgshapiro#  else /* DB_VERSION_MAJOR > 2 */
218338032Speter		errno = db_open(buf, dbtype, flags, DBMMODE,
218438032Speter				NULL, openinfo, &db);
218564562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
218638032Speter	}
218764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
218864562Sgshapiro	save_errno = errno;
218938032Speter
219064562Sgshapiro# if !LOCK_ON_OPEN
219138032Speter	if (mode == O_RDWR)
219238032Speter		map->map_lockfd = fd;
219338032Speter	else
219438032Speter		(void) close(fd);
219564562Sgshapiro# endif /* !LOCK_ON_OPEN */
219638032Speter
219738032Speter	if (db == NULL)
219838032Speter	{
219938032Speter		if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
220090792Sgshapiro		    aliaswait(map, ".db", false))
220190792Sgshapiro			return true;
220264562Sgshapiro# if !LOCK_ON_OPEN
220338032Speter		if (map->map_lockfd >= 0)
220438032Speter			(void) close(map->map_lockfd);
220564562Sgshapiro# endif /* !LOCK_ON_OPEN */
220664562Sgshapiro		errno = save_errno;
220738032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
220838032Speter			syserr("Cannot open %s database %s",
220938032Speter				mapclassname, buf);
221090792Sgshapiro		return false;
221138032Speter	}
221238032Speter
221364562Sgshapiro# if DB_VERSION_MAJOR < 2
221438032Speter	fd = db->fd(db);
221564562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
221638032Speter	fd = -1;
221738032Speter	errno = db->fd(db, &fd);
221864562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
221938032Speter	if (filechanged(buf, fd, &st))
222038032Speter	{
222164562Sgshapiro		save_errno = errno;
222264562Sgshapiro# if DB_VERSION_MAJOR < 2
222364562Sgshapiro		(void) db->close(db);
222464562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
222538032Speter		errno = db->close(db, 0);
222664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
222764562Sgshapiro# if !LOCK_ON_OPEN
222838032Speter		if (map->map_lockfd >= 0)
222964562Sgshapiro			(void) close(map->map_lockfd);
223064562Sgshapiro# endif /* !LOCK_ON_OPEN */
223138032Speter		errno = save_errno;
223238032Speter		syserr("db_map_open(%s): file changed after open", buf);
223390792Sgshapiro		return false;
223438032Speter	}
223538032Speter
223638032Speter	if (mode == O_RDWR)
223738032Speter		map->map_mflags |= MF_LOCKED;
223864562Sgshapiro# if LOCK_ON_OPEN
223938032Speter	if (fd >= 0 && mode == O_RDONLY)
224038032Speter	{
224138032Speter		(void) lockfile(fd, buf, NULL, LOCK_UN);
224238032Speter	}
224364562Sgshapiro# endif /* LOCK_ON_OPEN */
224438032Speter
224538032Speter	/* try to make sure that at least the database header is on disk */
224638032Speter	if (mode == O_RDWR)
224738032Speter	{
224838032Speter		(void) db->sync(db, 0);
224942575Speter		if (geteuid() == 0 && TrustedUid != 0)
225038032Speter		{
225164562Sgshapiro#  if HASFCHOWN
225242575Speter			if (fchown(fd, TrustedUid, -1) < 0)
225338032Speter			{
225438032Speter				int err = errno;
225538032Speter
225638032Speter				sm_syslog(LOG_ALERT, NOQID,
225738032Speter					  "ownership change on %s failed: %s",
225890792Sgshapiro					  buf, sm_errstring(err));
225938032Speter				message("050 ownership change on %s failed: %s",
226090792Sgshapiro					buf, sm_errstring(err));
226138032Speter			}
226290792Sgshapiro#  else /* HASFCHOWN */
226390792Sgshapiro			sm_syslog(LOG_ALERT, NOQID,
226490792Sgshapiro				  "no fchown(): cannot change ownership on %s",
226590792Sgshapiro				  map->map_file);
226690792Sgshapiro			message("050 no fchown(): cannot change ownership on %s",
226790792Sgshapiro				map->map_file);
226864562Sgshapiro#  endif /* HASFCHOWN */
226938032Speter		}
227038032Speter	}
227138032Speter
227264562Sgshapiro	map->map_db2 = (ARBPTR_T) db;
227364562Sgshapiro
227464562Sgshapiro	/*
227564562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
227664562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
227764562Sgshapiro	**  map_mtime to be set
227864562Sgshapiro	*/
227964562Sgshapiro
228038032Speter	if (fd >= 0 && fstat(fd, &st) >= 0)
228138032Speter		map->map_mtime = st.st_mtime;
228238032Speter
228338032Speter	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
228490792Sgshapiro	    !aliaswait(map, ".db", true))
228590792Sgshapiro		return false;
228690792Sgshapiro	return true;
228738032Speter}
228838032Speter
228938032Speter
229038032Speter/*
229138032Speter**  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
229238032Speter*/
229338032Speter
229438032Speterchar *
229538032Speterdb_map_lookup(map, name, av, statp)
229638032Speter	MAP *map;
229738032Speter	char *name;
229838032Speter	char **av;
229938032Speter	int *statp;
230038032Speter{
230138032Speter	DBT key, val;
230238032Speter	register DB *db = (DB *) map->map_db2;
230338032Speter	int i;
230438032Speter	int st;
230564562Sgshapiro	int save_errno;
230638032Speter	int fd;
230738032Speter	struct stat stbuf;
230838032Speter	char keybuf[MAXNAME + 1];
230998121Sgshapiro	char buf[MAXPATHLEN];
231038032Speter
2311168515Sgshapiro	memset(&key, '\0', sizeof(key));
2312168515Sgshapiro	memset(&val, '\0', sizeof(val));
231338032Speter
231438032Speter	if (tTd(38, 20))
231590792Sgshapiro		sm_dprintf("db_map_lookup(%s, %s)\n",
231638032Speter			map->map_mname, name);
231738032Speter
2318168515Sgshapiro	if (sm_strlcpy(buf, map->map_file, sizeof(buf)) >= sizeof(buf))
231998121Sgshapiro	{
232098121Sgshapiro		errno = 0;
232198121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
232298121Sgshapiro			syserr("map \"%s\": map file %s name too long",
232398121Sgshapiro				map->map_mname, map->map_file);
232498121Sgshapiro		return NULL;
232598121Sgshapiro	}
232698121Sgshapiro	i = strlen(buf);
232738032Speter	if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
232838032Speter		buf[i - 3] = '\0';
232938032Speter
233038032Speter	key.size = strlen(name);
2331168515Sgshapiro	if (key.size > sizeof(keybuf) - 1)
2332168515Sgshapiro		key.size = sizeof(keybuf) - 1;
233338032Speter	key.data = keybuf;
233464562Sgshapiro	memmove(keybuf, name, key.size);
233538032Speter	keybuf[key.size] = '\0';
233638032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
233738032Speter		makelower(keybuf);
233838032Speter  lockdb:
233964562Sgshapiro# if DB_VERSION_MAJOR < 2
234038032Speter	fd = db->fd(db);
234164562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
234238032Speter	fd = -1;
234338032Speter	errno = db->fd(db, &fd);
234464562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
234538032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
234638032Speter		(void) lockfile(fd, buf, ".db", LOCK_SH);
234738032Speter	if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
234838032Speter	{
234938032Speter		/* Reopen the database to sync the cache */
235038032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
235138032Speter								 : O_RDONLY;
235238032Speter
235364562Sgshapiro		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
235464562Sgshapiro			(void) lockfile(fd, buf, ".db", LOCK_UN);
235577349Sgshapiro		map->map_mflags |= MF_CLOSING;
235638032Speter		map->map_class->map_close(map);
235777349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
235838032Speter		if (map->map_class->map_open(map, omode))
235938032Speter		{
236038032Speter			map->map_mflags |= MF_OPEN;
236190792Sgshapiro			map->map_pid = CurrentPid;
236238032Speter			if ((omode && O_ACCMODE) == O_RDWR)
236338032Speter				map->map_mflags |= MF_WRITABLE;
236438032Speter			db = (DB *) map->map_db2;
236538032Speter			goto lockdb;
236638032Speter		}
236738032Speter		else
236838032Speter		{
236938032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
237038032Speter			{
237138032Speter				extern MAPCLASS BogusMapClass;
237238032Speter
237338032Speter				*statp = EX_TEMPFAIL;
237490792Sgshapiro				map->map_orgclass = map->map_class;
237538032Speter				map->map_class = &BogusMapClass;
237638032Speter				map->map_mflags |= MF_OPEN;
237790792Sgshapiro				map->map_pid = CurrentPid;
237838032Speter				syserr("Cannot reopen DB database %s",
237938032Speter					map->map_file);
238038032Speter			}
238138032Speter			return NULL;
238238032Speter		}
238338032Speter	}
238438032Speter
238538032Speter	st = 1;
238638032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
238738032Speter	{
238864562Sgshapiro# if DB_VERSION_MAJOR < 2
238938032Speter		st = db->get(db, &key, &val, 0);
239064562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
239138032Speter		errno = db->get(db, NULL, &key, &val, 0);
239238032Speter		switch (errno)
239338032Speter		{
239438032Speter		  case DB_NOTFOUND:
239538032Speter		  case DB_KEYEMPTY:
239638032Speter			st = 1;
239738032Speter			break;
239838032Speter
239938032Speter		  case 0:
240038032Speter			st = 0;
240138032Speter			break;
240238032Speter
240338032Speter		  default:
240438032Speter			st = -1;
240538032Speter			break;
240638032Speter		}
240764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
240838032Speter		if (st == 0)
240938032Speter			map->map_mflags &= ~MF_TRY1NULL;
241038032Speter	}
241138032Speter	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
241238032Speter	{
241338032Speter		key.size++;
241464562Sgshapiro# if DB_VERSION_MAJOR < 2
241538032Speter		st = db->get(db, &key, &val, 0);
241664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
241738032Speter		errno = db->get(db, NULL, &key, &val, 0);
241838032Speter		switch (errno)
241938032Speter		{
242038032Speter		  case DB_NOTFOUND:
242138032Speter		  case DB_KEYEMPTY:
242238032Speter			st = 1;
242338032Speter			break;
242438032Speter
242538032Speter		  case 0:
242638032Speter			st = 0;
242738032Speter			break;
242838032Speter
242938032Speter		  default:
243038032Speter			st = -1;
243138032Speter			break;
243238032Speter		}
243364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
243438032Speter		if (st == 0)
243538032Speter			map->map_mflags &= ~MF_TRY0NULL;
243638032Speter	}
243764562Sgshapiro	save_errno = errno;
243838032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
243938032Speter		(void) lockfile(fd, buf, ".db", LOCK_UN);
244038032Speter	if (st != 0)
244138032Speter	{
244264562Sgshapiro		errno = save_errno;
244338032Speter		if (st < 0)
244438032Speter			syserr("db_map_lookup: get (%s)", name);
244538032Speter		return NULL;
244638032Speter	}
244738032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
244838032Speter		return map_rewrite(map, name, strlen(name), NULL);
244938032Speter	else
245038032Speter		return map_rewrite(map, val.data, val.size, av);
245138032Speter}
245238032Speter
245338032Speter
245438032Speter/*
245538032Speter**  DB_MAP_STORE -- store a datum in the NEWDB database
245638032Speter*/
245738032Speter
245838032Spetervoid
245938032Speterdb_map_store(map, lhs, rhs)
246038032Speter	register MAP *map;
246138032Speter	char *lhs;
246238032Speter	char *rhs;
246338032Speter{
246464562Sgshapiro	int status;
246538032Speter	DBT key;
246638032Speter	DBT data;
246738032Speter	register DB *db = map->map_db2;
246838032Speter	char keybuf[MAXNAME + 1];
246938032Speter
2470168515Sgshapiro	memset(&key, '\0', sizeof(key));
2471168515Sgshapiro	memset(&data, '\0', sizeof(data));
247238032Speter
247338032Speter	if (tTd(38, 12))
247490792Sgshapiro		sm_dprintf("db_map_store(%s, %s, %s)\n",
247538032Speter			map->map_mname, lhs, rhs);
247638032Speter
247738032Speter	key.size = strlen(lhs);
247838032Speter	key.data = lhs;
247938032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
248038032Speter	{
2481168515Sgshapiro		if (key.size > sizeof(keybuf) - 1)
2482168515Sgshapiro			key.size = sizeof(keybuf) - 1;
248364562Sgshapiro		memmove(keybuf, key.data, key.size);
248438032Speter		keybuf[key.size] = '\0';
248538032Speter		makelower(keybuf);
248638032Speter		key.data = keybuf;
248738032Speter	}
248838032Speter
248938032Speter	data.size = strlen(rhs);
249038032Speter	data.data = rhs;
249138032Speter
249238032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
249338032Speter	{
249438032Speter		key.size++;
249538032Speter		data.size++;
249638032Speter	}
249738032Speter
249864562Sgshapiro# if DB_VERSION_MAJOR < 2
249964562Sgshapiro	status = db->put(db, &key, &data, R_NOOVERWRITE);
250064562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
250138032Speter	errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE);
250238032Speter	switch (errno)
250338032Speter	{
250438032Speter	  case DB_KEYEXIST:
250564562Sgshapiro		status = 1;
250638032Speter		break;
250738032Speter
250838032Speter	  case 0:
250964562Sgshapiro		status = 0;
251038032Speter		break;
251138032Speter
251238032Speter	  default:
251364562Sgshapiro		status = -1;
251438032Speter		break;
251538032Speter	}
251664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
251764562Sgshapiro	if (status > 0)
251838032Speter	{
251938032Speter		if (!bitset(MF_APPEND, map->map_mflags))
252038032Speter			message("050 Warning: duplicate alias name %s", lhs);
252138032Speter		else
252238032Speter		{
252338032Speter			static char *buf = NULL;
252438032Speter			static int bufsiz = 0;
252538032Speter			DBT old;
252638032Speter
2527168515Sgshapiro			memset(&old, '\0', sizeof(old));
252838032Speter
252964562Sgshapiro			old.data = db_map_lookup(map, key.data,
253090792Sgshapiro						 (char **) NULL, &status);
253138032Speter			if (old.data != NULL)
253238032Speter			{
253338032Speter				old.size = strlen(old.data);
253490792Sgshapiro				if (data.size + old.size + 2 > (size_t) bufsiz)
253538032Speter				{
253638032Speter					if (buf != NULL)
253777349Sgshapiro						sm_free(buf);
253838032Speter					bufsiz = data.size + old.size + 2;
253990792Sgshapiro					buf = sm_pmalloc_x(bufsiz);
254038032Speter				}
254190792Sgshapiro				(void) sm_strlcpyn(buf, bufsiz, 3,
254290792Sgshapiro					(char *) data.data, ",",
254390792Sgshapiro					(char *) old.data);
254438032Speter				data.size = data.size + old.size + 1;
254538032Speter				data.data = buf;
254638032Speter				if (tTd(38, 9))
254790792Sgshapiro					sm_dprintf("db_map_store append=%s\n",
254864562Sgshapiro						(char *) data.data);
254938032Speter			}
255038032Speter		}
255164562Sgshapiro# if DB_VERSION_MAJOR < 2
255264562Sgshapiro		status = db->put(db, &key, &data, 0);
255364562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
255464562Sgshapiro		status = errno = db->put(db, NULL, &key, &data, 0);
255564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
255638032Speter	}
255764562Sgshapiro	if (status != 0)
255838032Speter		syserr("readaliases: db put (%s)", lhs);
255938032Speter}
256038032Speter
256138032Speter
256238032Speter/*
256338032Speter**  DB_MAP_CLOSE -- add distinguished entries and close the database
256438032Speter*/
256538032Speter
256638032Spetervoid
256738032Speterdb_map_close(map)
256838032Speter	MAP *map;
256938032Speter{
257038032Speter	register DB *db = map->map_db2;
257138032Speter
257238032Speter	if (tTd(38, 9))
257390792Sgshapiro		sm_dprintf("db_map_close(%s, %s, %lx)\n",
257438032Speter			map->map_mname, map->map_file, map->map_mflags);
257538032Speter
257638032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
257738032Speter	{
257838032Speter		/* write out the distinguished alias */
257938032Speter		db_map_store(map, "@", "@");
258038032Speter	}
258138032Speter
258238032Speter	(void) db->sync(db, 0);
258338032Speter
258464562Sgshapiro# if !LOCK_ON_OPEN
258538032Speter	if (map->map_lockfd >= 0)
258638032Speter		(void) close(map->map_lockfd);
258764562Sgshapiro# endif /* !LOCK_ON_OPEN */
258838032Speter
258964562Sgshapiro# if DB_VERSION_MAJOR < 2
259038032Speter	if (db->close(db) != 0)
259164562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
259242575Speter	/*
259342575Speter	**  Berkeley DB can use internal shared memory
259442575Speter	**  locking for its memory pool.  Closing a map
259542575Speter	**  opened by another process will interfere
259642575Speter	**  with the shared memory and locks of the parent
259742575Speter	**  process leaving things in a bad state.
259843730Speter	*/
259943730Speter
260043730Speter	/*
260142575Speter	**  If this map was not opened by the current
260243730Speter	**  process, do not close the map but recover
260342575Speter	**  the file descriptor.
260442575Speter	*/
260590792Sgshapiro
260690792Sgshapiro	if (map->map_pid != CurrentPid)
260742575Speter	{
260842575Speter		int fd = -1;
260942575Speter
261042575Speter		errno = db->fd(db, &fd);
261142575Speter		if (fd >= 0)
261242575Speter			(void) close(fd);
261342575Speter		return;
261442575Speter	}
261542575Speter
261638032Speter	if ((errno = db->close(db, 0)) != 0)
261764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
261842575Speter		syserr("db_map_close(%s, %s, %lx): db close failure",
261942575Speter			map->map_mname, map->map_file, map->map_mflags);
262038032Speter}
262164562Sgshapiro#endif /* NEWDB */
262290792Sgshapiro/*
262338032Speter**  NIS Modules
262438032Speter*/
262538032Speter
262690792Sgshapiro#if NIS
262738032Speter
262838032Speter# ifndef YPERR_BUSY
262938032Speter#  define YPERR_BUSY	16
263064562Sgshapiro# endif /* ! YPERR_BUSY */
263138032Speter
263238032Speter/*
263338032Speter**  NIS_MAP_OPEN -- open DBM map
263438032Speter*/
263538032Speter
263638032Speterbool
263738032Speternis_map_open(map, mode)
263838032Speter	MAP *map;
263938032Speter	int mode;
264038032Speter{
264138032Speter	int yperr;
264238032Speter	register char *p;
264338032Speter	auto char *vp;
264438032Speter	auto int vsize;
264538032Speter
264638032Speter	if (tTd(38, 2))
264790792Sgshapiro		sm_dprintf("nis_map_open(%s, %s, %d)\n",
264838032Speter			map->map_mname, map->map_file, mode);
264938032Speter
265038032Speter	mode &= O_ACCMODE;
265138032Speter	if (mode != O_RDONLY)
265238032Speter	{
265338032Speter		/* issue a pseudo-error message */
265490792Sgshapiro		errno = SM_EMAPCANTWRITE;
265590792Sgshapiro		return false;
265638032Speter	}
265738032Speter
265838032Speter	p = strchr(map->map_file, '@');
265938032Speter	if (p != NULL)
266038032Speter	{
266138032Speter		*p++ = '\0';
266238032Speter		if (*p != '\0')
266338032Speter			map->map_domain = p;
266438032Speter	}
266538032Speter
266638032Speter	if (*map->map_file == '\0')
266738032Speter		map->map_file = "mail.aliases";
266838032Speter
266938032Speter	if (map->map_domain == NULL)
267038032Speter	{
267138032Speter		yperr = yp_get_default_domain(&map->map_domain);
267238032Speter		if (yperr != 0)
267338032Speter		{
267438032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
267594334Sgshapiro				syserr("451 4.3.5 NIS map %s specified, but NIS not running",
267664562Sgshapiro				       map->map_file);
267790792Sgshapiro			return false;
267838032Speter		}
267938032Speter	}
268038032Speter
268138032Speter	/* check to see if this map actually exists */
268264562Sgshapiro	vp = NULL;
268338032Speter	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
268438032Speter			&vp, &vsize);
268538032Speter	if (tTd(38, 10))
268690792Sgshapiro		sm_dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n",
268738032Speter			map->map_domain, map->map_file, yperr_string(yperr));
268864562Sgshapiro	if (vp != NULL)
268977349Sgshapiro		sm_free(vp);
269064562Sgshapiro
269138032Speter	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
269238032Speter	{
269338032Speter		/*
269438032Speter		**  We ought to be calling aliaswait() here if this is an
269538032Speter		**  alias file, but powerful HP-UX NIS servers  apparently
269638032Speter		**  don't insert the @:@ token into the alias map when it
269738032Speter		**  is rebuilt, so aliaswait() just hangs.  I hate HP-UX.
269838032Speter		*/
269938032Speter
270064562Sgshapiro# if 0
270138032Speter		if (!bitset(MF_ALIAS, map->map_mflags) ||
270290792Sgshapiro		    aliaswait(map, NULL, true))
270364562Sgshapiro# endif /* 0 */
270490792Sgshapiro			return true;
270538032Speter	}
270638032Speter
270738032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
270838032Speter	{
270994334Sgshapiro		syserr("451 4.3.5 Cannot bind to map %s in domain %s: %s",
271038032Speter			map->map_file, map->map_domain, yperr_string(yperr));
271138032Speter	}
271238032Speter
271390792Sgshapiro	return false;
271438032Speter}
271538032Speter
271638032Speter
271738032Speter/*
271838032Speter**  NIS_MAP_LOOKUP -- look up a datum in a NIS map
271938032Speter*/
272038032Speter
272138032Speter/* ARGSUSED3 */
272238032Speterchar *
272338032Speternis_map_lookup(map, name, av, statp)
272438032Speter	MAP *map;
272538032Speter	char *name;
272638032Speter	char **av;
272738032Speter	int *statp;
272838032Speter{
272938032Speter	char *vp;
273038032Speter	auto int vsize;
273138032Speter	int buflen;
273238032Speter	int yperr;
273338032Speter	char keybuf[MAXNAME + 1];
273490792Sgshapiro	char *SM_NONVOLATILE result = NULL;
273538032Speter
273638032Speter	if (tTd(38, 20))
273790792Sgshapiro		sm_dprintf("nis_map_lookup(%s, %s)\n",
273838032Speter			map->map_mname, name);
273938032Speter
274038032Speter	buflen = strlen(name);
2741168515Sgshapiro	if (buflen > sizeof(keybuf) - 1)
2742168515Sgshapiro		buflen = sizeof(keybuf) - 1;
274364562Sgshapiro	memmove(keybuf, name, buflen);
274438032Speter	keybuf[buflen] = '\0';
274538032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
274638032Speter		makelower(keybuf);
274738032Speter	yperr = YPERR_KEY;
274864562Sgshapiro	vp = NULL;
274938032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
275038032Speter	{
275138032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
275238032Speter			     &vp, &vsize);
275338032Speter		if (yperr == 0)
275438032Speter			map->map_mflags &= ~MF_TRY1NULL;
275538032Speter	}
275638032Speter	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
275738032Speter	{
275890792Sgshapiro		SM_FREE_CLR(vp);
275938032Speter		buflen++;
276038032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
276138032Speter			     &vp, &vsize);
276238032Speter		if (yperr == 0)
276338032Speter			map->map_mflags &= ~MF_TRY0NULL;
276438032Speter	}
276538032Speter	if (yperr != 0)
276638032Speter	{
276738032Speter		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
276838032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
276964562Sgshapiro		if (vp != NULL)
277077349Sgshapiro			sm_free(vp);
277138032Speter		return NULL;
277238032Speter	}
277390792Sgshapiro	SM_TRY
277490792Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
277590792Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
277690792Sgshapiro		else
277790792Sgshapiro			result = map_rewrite(map, vp, vsize, av);
277890792Sgshapiro	SM_FINALLY
277964562Sgshapiro		if (vp != NULL)
278077349Sgshapiro			sm_free(vp);
278190792Sgshapiro	SM_END_TRY
278290792Sgshapiro	return result;
278338032Speter}
278438032Speter
278538032Speter
278638032Speter/*
278738032Speter**  NIS_GETCANONNAME -- look up canonical name in NIS
278838032Speter*/
278938032Speter
279064562Sgshapirostatic bool
279138032Speternis_getcanonname(name, hbsize, statp)
279238032Speter	char *name;
279338032Speter	int hbsize;
279438032Speter	int *statp;
279538032Speter{
279638032Speter	char *vp;
279738032Speter	auto int vsize;
279838032Speter	int keylen;
279938032Speter	int yperr;
280090792Sgshapiro	static bool try0null = true;
280190792Sgshapiro	static bool try1null = true;
280238032Speter	static char *yp_domain = NULL;
280338032Speter	char host_record[MAXLINE];
280438032Speter	char cbuf[MAXNAME];
280538032Speter	char nbuf[MAXNAME + 1];
280638032Speter
280738032Speter	if (tTd(38, 20))
280890792Sgshapiro		sm_dprintf("nis_getcanonname(%s)\n", name);
280938032Speter
2810168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
281138032Speter	{
281238032Speter		*statp = EX_UNAVAILABLE;
281390792Sgshapiro		return false;
281438032Speter	}
281573188Sgshapiro	(void) shorten_hostname(nbuf);
281638032Speter	keylen = strlen(nbuf);
281738032Speter
281838032Speter	if (yp_domain == NULL)
281964562Sgshapiro		(void) yp_get_default_domain(&yp_domain);
282038032Speter	makelower(nbuf);
282138032Speter	yperr = YPERR_KEY;
282264562Sgshapiro	vp = NULL;
282338032Speter	if (try0null)
282438032Speter	{
282538032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
282638032Speter			     &vp, &vsize);
282738032Speter		if (yperr == 0)
282890792Sgshapiro			try1null = false;
282938032Speter	}
283038032Speter	if (yperr == YPERR_KEY && try1null)
283138032Speter	{
283290792Sgshapiro		SM_FREE_CLR(vp);
283338032Speter		keylen++;
283438032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
283538032Speter			     &vp, &vsize);
283638032Speter		if (yperr == 0)
283790792Sgshapiro			try0null = false;
283838032Speter	}
283938032Speter	if (yperr != 0)
284038032Speter	{
284138032Speter		if (yperr == YPERR_KEY)
284238032Speter			*statp = EX_NOHOST;
284338032Speter		else if (yperr == YPERR_BUSY)
284438032Speter			*statp = EX_TEMPFAIL;
284538032Speter		else
284638032Speter			*statp = EX_UNAVAILABLE;
284764562Sgshapiro		if (vp != NULL)
284877349Sgshapiro			sm_free(vp);
284990792Sgshapiro		return false;
285038032Speter	}
2851168515Sgshapiro	(void) sm_strlcpy(host_record, vp, sizeof(host_record));
285277349Sgshapiro	sm_free(vp);
285338032Speter	if (tTd(38, 44))
285490792Sgshapiro		sm_dprintf("got record `%s'\n", host_record);
285590792Sgshapiro	vp = strpbrk(host_record, "#\n");
285690792Sgshapiro	if (vp != NULL)
285790792Sgshapiro		*vp = '\0';
2858168515Sgshapiro	if (!extract_canonname(nbuf, NULL, host_record, cbuf, sizeof(cbuf)))
285938032Speter	{
286038032Speter		/* this should not happen, but.... */
286138032Speter		*statp = EX_NOHOST;
286290792Sgshapiro		return false;
286338032Speter	}
286490792Sgshapiro	if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
286538032Speter	{
286638032Speter		*statp = EX_UNAVAILABLE;
286790792Sgshapiro		return false;
286838032Speter	}
286938032Speter	*statp = EX_OK;
287090792Sgshapiro	return true;
287138032Speter}
287238032Speter
287364562Sgshapiro#endif /* NIS */
287490792Sgshapiro/*
287538032Speter**  NISPLUS Modules
287638032Speter**
287738032Speter**	This code donated by Sun Microsystems.
287838032Speter*/
287938032Speter
288090792Sgshapiro#if NISPLUS
288138032Speter
288264562Sgshapiro# undef NIS		/* symbol conflict in nis.h */
288364562Sgshapiro# undef T_UNSPEC	/* symbol conflict in nis.h -> ... -> sys/tiuser.h */
288464562Sgshapiro# include <rpcsvc/nis.h>
288564562Sgshapiro# include <rpcsvc/nislib.h>
288638032Speter
288764562Sgshapiro# define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
288864562Sgshapiro# define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
288964562Sgshapiro# define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
289064562Sgshapiro# define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
289138032Speter
289238032Speter/*
289338032Speter**  NISPLUS_MAP_OPEN -- open nisplus table
289438032Speter*/
289538032Speter
289638032Speterbool
289738032Speternisplus_map_open(map, mode)
289838032Speter	MAP *map;
289938032Speter	int mode;
290038032Speter{
290138032Speter	nis_result *res = NULL;
290238032Speter	int retry_cnt, max_col, i;
290338032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
290438032Speter
290538032Speter	if (tTd(38, 2))
290690792Sgshapiro		sm_dprintf("nisplus_map_open(%s, %s, %d)\n",
290738032Speter			map->map_mname, map->map_file, mode);
290838032Speter
290938032Speter	mode &= O_ACCMODE;
291038032Speter	if (mode != O_RDONLY)
291138032Speter	{
291238032Speter		errno = EPERM;
291390792Sgshapiro		return false;
291438032Speter	}
291538032Speter
291638032Speter	if (*map->map_file == '\0')
291738032Speter		map->map_file = "mail_aliases.org_dir";
291838032Speter
291938032Speter	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
292038032Speter	{
292138032Speter		/* set default NISPLUS Domain to $m */
292238032Speter		map->map_domain = newstr(nisplus_default_domain());
292338032Speter		if (tTd(38, 2))
292490792Sgshapiro			sm_dprintf("nisplus_map_open(%s): using domain %s\n",
292564562Sgshapiro				map->map_file, map->map_domain);
292638032Speter	}
292738032Speter	if (!PARTIAL_NAME(map->map_file))
292838032Speter	{
292938032Speter		map->map_domain = newstr("");
2930168515Sgshapiro		(void) sm_strlcpy(qbuf, map->map_file, sizeof(qbuf));
293138032Speter	}
293238032Speter	else
293338032Speter	{
293438032Speter		/* check to see if this map actually exists */
2935168515Sgshapiro		(void) sm_strlcpyn(qbuf, sizeof(qbuf), 3,
293690792Sgshapiro				   map->map_file, ".", map->map_domain);
293738032Speter	}
293838032Speter
293938032Speter	retry_cnt = 0;
294038032Speter	while (res == NULL || res->status != NIS_SUCCESS)
294138032Speter	{
294238032Speter		res = nis_lookup(qbuf, FOLLOW_LINKS);
294338032Speter		switch (res->status)
294438032Speter		{
294538032Speter		  case NIS_SUCCESS:
294638032Speter			break;
294738032Speter
294838032Speter		  case NIS_TRYAGAIN:
294938032Speter		  case NIS_RPCERROR:
295038032Speter		  case NIS_NAMEUNREACHABLE:
295138032Speter			if (retry_cnt++ > 4)
295238032Speter			{
295338032Speter				errno = EAGAIN;
295490792Sgshapiro				return false;
295538032Speter			}
295638032Speter			/* try not to overwhelm hosed server */
295738032Speter			sleep(2);
295838032Speter			break;
295938032Speter
296038032Speter		  default:		/* all other nisplus errors */
296164562Sgshapiro# if 0
296238032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
296394334Sgshapiro				syserr("451 4.3.5 Cannot find table %s.%s: %s",
296438032Speter					map->map_file, map->map_domain,
296538032Speter					nis_sperrno(res->status));
296664562Sgshapiro# endif /* 0 */
296738032Speter			errno = EAGAIN;
296890792Sgshapiro			return false;
296938032Speter		}
297038032Speter	}
297138032Speter
297238032Speter	if (NIS_RES_NUMOBJ(res) != 1 ||
297338032Speter	    (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
297438032Speter	{
297538032Speter		if (tTd(38, 10))
297690792Sgshapiro			sm_dprintf("nisplus_map_open: %s is not a table\n", qbuf);
297764562Sgshapiro# if 0
297838032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
297994334Sgshapiro			syserr("451 4.3.5 %s.%s: %s is not a table",
298038032Speter				map->map_file, map->map_domain,
298138032Speter				nis_sperrno(res->status));
298264562Sgshapiro# endif /* 0 */
298338032Speter		errno = EBADF;
298490792Sgshapiro		return false;
298538032Speter	}
298638032Speter	/* default key column is column 0 */
298738032Speter	if (map->map_keycolnm == NULL)
298838032Speter		map->map_keycolnm = newstr(COL_NAME(res,0));
298938032Speter
299038032Speter	max_col = COL_MAX(res);
299138032Speter
299238032Speter	/* verify the key column exist */
299390792Sgshapiro	for (i = 0; i < max_col; i++)
299438032Speter	{
299564562Sgshapiro		if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0)
299638032Speter			break;
299738032Speter	}
299838032Speter	if (i == max_col)
299938032Speter	{
300038032Speter		if (tTd(38, 2))
300190792Sgshapiro			sm_dprintf("nisplus_map_open(%s): can not find key column %s\n",
300238032Speter				map->map_file, map->map_keycolnm);
300338032Speter		errno = ENOENT;
300490792Sgshapiro		return false;
300538032Speter	}
300638032Speter
300738032Speter	/* default value column is the last column */
300838032Speter	if (map->map_valcolnm == NULL)
300938032Speter	{
301038032Speter		map->map_valcolno = max_col - 1;
301190792Sgshapiro		return true;
301238032Speter	}
301338032Speter
301464562Sgshapiro	for (i = 0; i< max_col; i++)
301538032Speter	{
301638032Speter		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
301738032Speter		{
301838032Speter			map->map_valcolno = i;
301990792Sgshapiro			return true;
302038032Speter		}
302138032Speter	}
302238032Speter
302338032Speter	if (tTd(38, 2))
302490792Sgshapiro		sm_dprintf("nisplus_map_open(%s): can not find column %s\n",
302564562Sgshapiro			map->map_file, map->map_keycolnm);
302638032Speter	errno = ENOENT;
302790792Sgshapiro	return false;
302838032Speter}
302938032Speter
303038032Speter
303138032Speter/*
303238032Speter**  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
303338032Speter*/
303438032Speter
303538032Speterchar *
303638032Speternisplus_map_lookup(map, name, av, statp)
303738032Speter	MAP *map;
303838032Speter	char *name;
303938032Speter	char **av;
304038032Speter	int *statp;
304138032Speter{
304238032Speter	char *p;
304338032Speter	auto int vsize;
304438032Speter	char *skp;
304538032Speter	int skleft;
304638032Speter	char search_key[MAXNAME + 4];
304738032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
304838032Speter	nis_result *result;
304938032Speter
305038032Speter	if (tTd(38, 20))
305190792Sgshapiro		sm_dprintf("nisplus_map_lookup(%s, %s)\n",
305238032Speter			map->map_mname, name);
305338032Speter
305438032Speter	if (!bitset(MF_OPEN, map->map_mflags))
305538032Speter	{
305638032Speter		if (nisplus_map_open(map, O_RDONLY))
305742575Speter		{
305838032Speter			map->map_mflags |= MF_OPEN;
305990792Sgshapiro			map->map_pid = CurrentPid;
306042575Speter		}
306138032Speter		else
306238032Speter		{
306338032Speter			*statp = EX_UNAVAILABLE;
306438032Speter			return NULL;
306538032Speter		}
306638032Speter	}
306738032Speter
306838032Speter	/*
306938032Speter	**  Copy the name to the key buffer, escaping double quote characters
307038032Speter	**  by doubling them and quoting "]" and "," to avoid having the
307138032Speter	**  NIS+ parser choke on them.
307238032Speter	*/
307338032Speter
3074168515Sgshapiro	skleft = sizeof(search_key) - 4;
307538032Speter	skp = search_key;
307638032Speter	for (p = name; *p != '\0' && skleft > 0; p++)
307738032Speter	{
307838032Speter		switch (*p)
307938032Speter		{
308038032Speter		  case ']':
308138032Speter		  case ',':
308238032Speter			/* quote the character */
308338032Speter			*skp++ = '"';
308438032Speter			*skp++ = *p;
308538032Speter			*skp++ = '"';
308638032Speter			skleft -= 3;
308738032Speter			break;
308838032Speter
308938032Speter		  case '"':
309038032Speter			/* double the quote */
309138032Speter			*skp++ = '"';
309238032Speter			skleft--;
309364562Sgshapiro			/* FALLTHROUGH */
309438032Speter
309538032Speter		  default:
309638032Speter			*skp++ = *p;
309738032Speter			skleft--;
309838032Speter			break;
309938032Speter		}
310038032Speter	}
310138032Speter	*skp = '\0';
310238032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
310338032Speter		makelower(search_key);
310438032Speter
310538032Speter	/* construct the query */
310638032Speter	if (PARTIAL_NAME(map->map_file))
3107168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf), "[%s=%s],%s.%s",
310838032Speter			map->map_keycolnm, search_key, map->map_file,
310938032Speter			map->map_domain);
311038032Speter	else
3111168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf), "[%s=%s],%s",
311238032Speter			map->map_keycolnm, search_key, map->map_file);
311338032Speter
311438032Speter	if (tTd(38, 20))
311590792Sgshapiro		sm_dprintf("qbuf=%s\n", qbuf);
311638032Speter	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
311738032Speter	if (result->status == NIS_SUCCESS)
311838032Speter	{
311938032Speter		int count;
312038032Speter		char *str;
312138032Speter
312238032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
312338032Speter		{
312438032Speter			if (LogLevel > 10)
312538032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
312664562Sgshapiro					  "%s: lookup error, expected 1 entry, got %d",
312764562Sgshapiro					  map->map_file, count);
312838032Speter
312938032Speter			/* ignore second entry */
313038032Speter			if (tTd(38, 20))
313190792Sgshapiro				sm_dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
313238032Speter					name, count);
313338032Speter		}
313438032Speter
313538032Speter		p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
313638032Speter		/* set the length of the result */
313738032Speter		if (p == NULL)
313838032Speter			p = "";
313938032Speter		vsize = strlen(p);
314038032Speter		if (tTd(38, 20))
314190792Sgshapiro			sm_dprintf("nisplus_map_lookup(%s), found %s\n",
314238032Speter				name, p);
314338032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
314438032Speter			str = map_rewrite(map, name, strlen(name), NULL);
314538032Speter		else
314638032Speter			str = map_rewrite(map, p, vsize, av);
314738032Speter		nis_freeresult(result);
314838032Speter		*statp = EX_OK;
314938032Speter		return str;
315038032Speter	}
315138032Speter	else
315238032Speter	{
315338032Speter		if (result->status == NIS_NOTFOUND)
315438032Speter			*statp = EX_NOTFOUND;
315538032Speter		else if (result->status == NIS_TRYAGAIN)
315638032Speter			*statp = EX_TEMPFAIL;
315738032Speter		else
315838032Speter		{
315938032Speter			*statp = EX_UNAVAILABLE;
316038032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
316138032Speter		}
316238032Speter	}
316338032Speter	if (tTd(38, 20))
316490792Sgshapiro		sm_dprintf("nisplus_map_lookup(%s), failed\n", name);
316538032Speter	nis_freeresult(result);
316638032Speter	return NULL;
316738032Speter}
316838032Speter
316938032Speter
317038032Speter
317138032Speter/*
317238032Speter**  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
317338032Speter*/
317438032Speter
317564562Sgshapirostatic bool
317638032Speternisplus_getcanonname(name, hbsize, statp)
317738032Speter	char *name;
317838032Speter	int hbsize;
317938032Speter	int *statp;
318038032Speter{
318138032Speter	char *vp;
318238032Speter	auto int vsize;
318338032Speter	nis_result *result;
318438032Speter	char *p;
318538032Speter	char nbuf[MAXNAME + 1];
318638032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
318738032Speter
3188168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
318938032Speter	{
319038032Speter		*statp = EX_UNAVAILABLE;
319190792Sgshapiro		return false;
319238032Speter	}
319373188Sgshapiro	(void) shorten_hostname(nbuf);
319438032Speter
319538032Speter	p = strchr(nbuf, '.');
319638032Speter	if (p == NULL)
319738032Speter	{
319838032Speter		/* single token */
3199168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf),
320090792Sgshapiro			"[name=%s],hosts.org_dir", nbuf);
320138032Speter	}
320238032Speter	else if (p[1] != '\0')
320338032Speter	{
320438032Speter		/* multi token -- take only first token in nbuf */
320538032Speter		*p = '\0';
3206168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf),
320790792Sgshapiro				   "[name=%s],hosts.org_dir.%s", nbuf, &p[1]);
320838032Speter	}
320938032Speter	else
321038032Speter	{
321138032Speter		*statp = EX_NOHOST;
321290792Sgshapiro		return false;
321338032Speter	}
321438032Speter
321538032Speter	if (tTd(38, 20))
321694334Sgshapiro		sm_dprintf("\nnisplus_getcanonname(%s), qbuf=%s\n",
321790792Sgshapiro			   name, qbuf);
321838032Speter
321938032Speter	result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
322090792Sgshapiro			  NULL, NULL);
322138032Speter
322238032Speter	if (result->status == NIS_SUCCESS)
322338032Speter	{
322438032Speter		int count;
322538032Speter		char *domain;
322638032Speter
322738032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
322838032Speter		{
322938032Speter			if (LogLevel > 10)
323038032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
323164562Sgshapiro					  "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
323264562Sgshapiro					  count);
323338032Speter
323438032Speter			/* ignore second entry */
323538032Speter			if (tTd(38, 20))
323694334Sgshapiro				sm_dprintf("nisplus_getcanonname(%s), got %d entries, all but first ignored\n",
323790792Sgshapiro					   name, count);
323838032Speter		}
323938032Speter
324038032Speter		if (tTd(38, 20))
324194334Sgshapiro			sm_dprintf("nisplus_getcanonname(%s), found in directory \"%s\"\n",
324290792Sgshapiro				   name, (NIS_RES_OBJECT(result))->zo_domain);
324338032Speter
324438032Speter
324538032Speter		vp = ((NIS_RES_OBJECT(result))->EN_col(0));
324638032Speter		vsize = strlen(vp);
324738032Speter		if (tTd(38, 20))
324890792Sgshapiro			sm_dprintf("nisplus_getcanonname(%s), found %s\n",
324990792Sgshapiro				   name, vp);
325038032Speter		if (strchr(vp, '.') != NULL)
325138032Speter		{
325238032Speter			domain = "";
325338032Speter		}
325438032Speter		else
325538032Speter		{
325638032Speter			domain = macvalue('m', CurEnv);
325738032Speter			if (domain == NULL)
325838032Speter				domain = "";
325938032Speter		}
326038032Speter		if (hbsize > vsize + (int) strlen(domain) + 1)
326138032Speter		{
326238032Speter			if (domain[0] == '\0')
326390792Sgshapiro				(void) sm_strlcpy(name, vp, hbsize);
326438032Speter			else
326590792Sgshapiro				(void) sm_snprintf(name, hbsize,
326690792Sgshapiro						   "%s.%s", vp, domain);
326738032Speter			*statp = EX_OK;
326838032Speter		}
326938032Speter		else
327038032Speter			*statp = EX_NOHOST;
327138032Speter		nis_freeresult(result);
327290792Sgshapiro		return true;
327338032Speter	}
327438032Speter	else
327538032Speter	{
327638032Speter		if (result->status == NIS_NOTFOUND)
327738032Speter			*statp = EX_NOHOST;
327838032Speter		else if (result->status == NIS_TRYAGAIN)
327938032Speter			*statp = EX_TEMPFAIL;
328038032Speter		else
328138032Speter			*statp = EX_UNAVAILABLE;
328238032Speter	}
328338032Speter	if (tTd(38, 20))
328490792Sgshapiro		sm_dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
328590792Sgshapiro			   name, result->status, *statp);
328638032Speter	nis_freeresult(result);
328790792Sgshapiro	return false;
328838032Speter}
328938032Speter
329038032Speterchar *
329138032Speternisplus_default_domain()
329238032Speter{
329338032Speter	static char default_domain[MAXNAME + 1] = "";
329438032Speter	char *p;
329538032Speter
329638032Speter	if (default_domain[0] != '\0')
329764562Sgshapiro		return default_domain;
329838032Speter
329938032Speter	p = nis_local_directory();
3300168515Sgshapiro	(void) sm_strlcpy(default_domain, p, sizeof(default_domain));
330138032Speter	return default_domain;
330238032Speter}
330338032Speter
330438032Speter#endif /* NISPLUS */
330590792Sgshapiro/*
330638032Speter**  LDAP Modules
330738032Speter*/
330838032Speter
330964562Sgshapiro/*
331064562Sgshapiro**  LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs
331164562Sgshapiro*/
331264562Sgshapiro
331364562Sgshapiro#if defined(LDAPMAP) || defined(PH_MAP)
331464562Sgshapiro
331590792Sgshapiro# if PH_MAP
331664562Sgshapiro#  define ph_map_dequote ldapmap_dequote
331764562Sgshapiro# endif /* PH_MAP */
331864562Sgshapiro
331990792Sgshapirostatic char *ldapmap_dequote __P((char *));
332090792Sgshapiro
332190792Sgshapirostatic char *
332264562Sgshapiroldapmap_dequote(str)
332364562Sgshapiro	char *str;
332464562Sgshapiro{
332564562Sgshapiro	char *p;
332664562Sgshapiro	char *start;
332764562Sgshapiro
332864562Sgshapiro	if (str == NULL)
332964562Sgshapiro		return NULL;
333064562Sgshapiro
333164562Sgshapiro	p = str;
333264562Sgshapiro	if (*p == '"')
333364562Sgshapiro	{
333464562Sgshapiro		/* Should probably swallow initial whitespace here */
333564562Sgshapiro		start = ++p;
333664562Sgshapiro	}
333764562Sgshapiro	else
333864562Sgshapiro		return str;
333964562Sgshapiro	while (*p != '"' && *p != '\0')
334064562Sgshapiro		p++;
334164562Sgshapiro	if (*p != '\0')
334264562Sgshapiro		*p = '\0';
334364562Sgshapiro	return start;
334464562Sgshapiro}
334564562Sgshapiro#endif /* defined(LDAPMAP) || defined(PH_MAP) */
334664562Sgshapiro
334790792Sgshapiro#if LDAPMAP
334838032Speter
334990792Sgshapirostatic SM_LDAP_STRUCT *LDAPDefaults = NULL;
335038032Speter
335138032Speter/*
335264562Sgshapiro**  LDAPMAP_OPEN -- open LDAP map
335338032Speter**
335464562Sgshapiro**	Connect to the LDAP server.  Re-use existing connections since a
335564562Sgshapiro**	single server connection to a host (with the same host, port,
335664562Sgshapiro**	bind DN, and secret) can answer queries for multiple maps.
335738032Speter*/
335838032Speter
335938032Speterbool
336064562Sgshapiroldapmap_open(map, mode)
336138032Speter	MAP *map;
336238032Speter	int mode;
336338032Speter{
336490792Sgshapiro	SM_LDAP_STRUCT *lmap;
336564562Sgshapiro	STAB *s;
3366132943Sgshapiro	char *id;
336764562Sgshapiro
336838032Speter	if (tTd(38, 2))
336990792Sgshapiro		sm_dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode);
337038032Speter
3371168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && \
3372168515Sgshapiro    HASLDAPGETALIASBYNAME
3373168515Sgshapiro	if (VendorCode == VENDOR_SUN &&
3374168515Sgshapiro	    strcmp(map->map_mname, "aliases.ldap") == 0)
3375168515Sgshapiro	{
3376168515Sgshapiro		return true;
3377168515Sgshapiro	}
3378168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && ... */
3379168515Sgshapiro
338038032Speter	mode &= O_ACCMODE;
338164562Sgshapiro
338264562Sgshapiro	/* sendmail doesn't have the ability to write to LDAP (yet) */
338338032Speter	if (mode != O_RDONLY)
338438032Speter	{
338538032Speter		/* issue a pseudo-error message */
338690792Sgshapiro		errno = SM_EMAPCANTWRITE;
338790792Sgshapiro		return false;
338838032Speter	}
338964562Sgshapiro
339090792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
339164562Sgshapiro
339264562Sgshapiro	s = ldapmap_findconn(lmap);
339377349Sgshapiro	if (s->s_lmap != NULL)
339464562Sgshapiro	{
339564562Sgshapiro		/* Already have a connection open to this LDAP server */
339690792Sgshapiro		lmap->ldap_ld = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_ld;
339790792Sgshapiro		lmap->ldap_pid = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_pid;
339877349Sgshapiro
339977349Sgshapiro		/* Add this map as head of linked list */
340077349Sgshapiro		lmap->ldap_next = s->s_lmap;
340177349Sgshapiro		s->s_lmap = map;
340277349Sgshapiro
340366494Sgshapiro		if (tTd(38, 2))
340490792Sgshapiro			sm_dprintf("using cached connection\n");
340590792Sgshapiro		return true;
340664562Sgshapiro	}
340764562Sgshapiro
340866494Sgshapiro	if (tTd(38, 2))
340990792Sgshapiro		sm_dprintf("opening new connection\n");
341066494Sgshapiro
3411132943Sgshapiro	if (lmap->ldap_host != NULL)
3412132943Sgshapiro		id = lmap->ldap_host;
3413132943Sgshapiro	else if (lmap->ldap_uri != NULL)
3414132943Sgshapiro		id = lmap->ldap_uri;
3415132943Sgshapiro	else
3416132943Sgshapiro		id = "localhost";
3417132943Sgshapiro
341864562Sgshapiro	/* No connection yet, connect */
341990792Sgshapiro	if (!sm_ldap_start(map->map_mname, lmap))
342038032Speter	{
342190792Sgshapiro		if (errno == ETIMEDOUT)
342238032Speter		{
342338032Speter			if (LogLevel > 1)
342438032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
342564562Sgshapiro					  "timeout conning to LDAP server %.100s",
3426132943Sgshapiro					  id);
342738032Speter		}
342838032Speter
342938032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
343038032Speter		{
343164562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
3432132943Sgshapiro			{
343364562Sgshapiro				syserr("%s failed to %s in map %s",
343464562Sgshapiro# if USE_LDAP_INIT
343590792Sgshapiro				       "ldap_init/ldap_bind",
343664562Sgshapiro# else /* USE_LDAP_INIT */
343764562Sgshapiro				       "ldap_open",
343864562Sgshapiro# endif /* USE_LDAP_INIT */
3439132943Sgshapiro				       id, map->map_mname);
3440132943Sgshapiro			}
344164562Sgshapiro			else
3442132943Sgshapiro			{
344394334Sgshapiro				syserr("451 4.3.5 %s failed to %s in map %s",
344464562Sgshapiro# if USE_LDAP_INIT
344590792Sgshapiro				       "ldap_init/ldap_bind",
344664562Sgshapiro# else /* USE_LDAP_INIT */
344764562Sgshapiro				       "ldap_open",
344864562Sgshapiro# endif /* USE_LDAP_INIT */
3449132943Sgshapiro				       id, map->map_mname);
3450132943Sgshapiro			}
345138032Speter		}
345290792Sgshapiro		return false;
345338032Speter	}
345438032Speter
345590792Sgshapiro	/* Save connection for reuse */
345690792Sgshapiro	s->s_lmap = map;
345790792Sgshapiro	return true;
345838032Speter}
345938032Speter
346038032Speter/*
346164562Sgshapiro**  LDAPMAP_CLOSE -- close ldap map
346238032Speter*/
346338032Speter
346438032Spetervoid
346564562Sgshapiroldapmap_close(map)
346638032Speter	MAP *map;
346738032Speter{
346890792Sgshapiro	SM_LDAP_STRUCT *lmap;
346964562Sgshapiro	STAB *s;
347043730Speter
347164562Sgshapiro	if (tTd(38, 2))
347290792Sgshapiro		sm_dprintf("ldapmap_close(%s)\n", map->map_mname);
347364562Sgshapiro
347490792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
347564562Sgshapiro
347664562Sgshapiro	/* Check if already closed */
347764562Sgshapiro	if (lmap->ldap_ld == NULL)
347864562Sgshapiro		return;
347964562Sgshapiro
348077349Sgshapiro	/* Close the LDAP connection */
348190792Sgshapiro	sm_ldap_close(lmap);
348277349Sgshapiro
348377349Sgshapiro	/* Mark all the maps that share the connection as closed */
348464562Sgshapiro	s = ldapmap_findconn(lmap);
348564562Sgshapiro
348677349Sgshapiro	while (s->s_lmap != NULL)
348777349Sgshapiro	{
348877349Sgshapiro		MAP *smap = s->s_lmap;
348964562Sgshapiro
349077349Sgshapiro		if (tTd(38, 2) && smap != map)
349190792Sgshapiro			sm_dprintf("ldapmap_close(%s): closed %s (shared LDAP connection)\n",
349290792Sgshapiro				   map->map_mname, smap->map_mname);
349377349Sgshapiro		smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
349490792Sgshapiro		lmap = (SM_LDAP_STRUCT *) smap->map_db1;
349564562Sgshapiro		lmap->ldap_ld = NULL;
349677349Sgshapiro		s->s_lmap = lmap->ldap_next;
349777349Sgshapiro		lmap->ldap_next = NULL;
349843730Speter	}
349938032Speter}
350038032Speter
350164562Sgshapiro# ifdef SUNET_ID
350243730Speter/*
350390792Sgshapiro**  SUNET_ID_HASH -- Convert a string to its Sunet_id canonical form
350442575Speter**  This only makes sense at Stanford University.
350538032Speter*/
350638032Speter
350790792Sgshapirostatic char *
350838032Spetersunet_id_hash(str)
350938032Speter	char *str;
351038032Speter{
351138032Speter	char *p, *p_last;
351238032Speter
351338032Speter	p = str;
351438032Speter	p_last = p;
351538032Speter	while (*p != '\0')
351638032Speter	{
351738032Speter		if (islower(*p) || isdigit(*p))
351838032Speter		{
351938032Speter			*p_last = *p;
352038032Speter			p_last++;
352138032Speter		}
352238032Speter		else if (isupper(*p))
352338032Speter		{
352438032Speter			*p_last = tolower(*p);
352538032Speter			p_last++;
352638032Speter		}
352738032Speter		++p;
352838032Speter	}
352938032Speter	if (*p_last != '\0')
353038032Speter		*p_last = '\0';
353164562Sgshapiro	return str;
353238032Speter}
3533168515Sgshapiro#  define SM_CONVERT_ID(str)	sunet_id_hash(str)
3534168515Sgshapiro# else /* SUNET_ID */
3535168515Sgshapiro#  define SM_CONVERT_ID(str)	makelower(str)
353664562Sgshapiro# endif /* SUNET_ID */
353738032Speter
353838032Speter/*
353964562Sgshapiro**  LDAPMAP_LOOKUP -- look up a datum in a LDAP map
354038032Speter*/
354138032Speter
354238032Speterchar *
354364562Sgshapiroldapmap_lookup(map, name, av, statp)
354438032Speter	MAP *map;
354538032Speter	char *name;
354638032Speter	char **av;
354738032Speter	int *statp;
354838032Speter{
3549132943Sgshapiro	int flags;
3550168515Sgshapiro	int i;
355194334Sgshapiro	int plen = 0;
355294334Sgshapiro	int psize = 0;
355364562Sgshapiro	int msgid;
355490792Sgshapiro	int save_errno;
355590792Sgshapiro	char *vp, *p;
355664562Sgshapiro	char *result = NULL;
3557132943Sgshapiro	SM_RPOOL_T *rpool;
355890792Sgshapiro	SM_LDAP_STRUCT *lmap = NULL;
3559168515Sgshapiro	char *argv[SM_LDAP_ARGS];
3560157001Sgshapiro	char keybuf[MAXKEY];
3561168515Sgshapiro#if SM_LDAP_ARGS != MAX_MAP_ARGS
3562168515Sgshapiro# ERROR _SM_LDAP_ARGS must be the same as _MAX_MAP_ARGS
3563168515Sgshapiro#endif /* SM_LDAP_ARGS != MAX_MAP_ARGS */
356438032Speter
3565168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && \
3566168515Sgshapiro    HASLDAPGETALIASBYNAME
3567168515Sgshapiro	if (VendorCode == VENDOR_SUN &&
3568168515Sgshapiro	    strcmp(map->map_mname, "aliases.ldap") == 0)
3569168515Sgshapiro	{
3570168515Sgshapiro		char answer[MAXNAME + 1];
3571168515Sgshapiro		int rc;
357238032Speter
3573168515Sgshapiro		rc = __getldapaliasbyname(name, answer, sizeof(answer));
3574168515Sgshapiro		if (rc != 0)
3575168515Sgshapiro		{
3576168515Sgshapiro			if (tTd(38, 20))
3577168515Sgshapiro				sm_dprintf("getldapaliasbyname(%.100s) failed, errno=%d\n",
3578168515Sgshapiro					   name, errno);
3579168515Sgshapiro			*statp = EX_NOTFOUND;
3580168515Sgshapiro			return NULL;
3581168515Sgshapiro		}
3582168515Sgshapiro		*statp = EX_OK;
3583168515Sgshapiro		if (tTd(38, 20))
3584168515Sgshapiro			sm_dprintf("getldapaliasbyname(%.100s) => %s\n", name,
3585168515Sgshapiro				   answer);
3586168515Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
3587168515Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
3588168515Sgshapiro		else
3589168515Sgshapiro			result = map_rewrite(map, answer, strlen(answer), av);
3590168515Sgshapiro		return result;
3591168515Sgshapiro	}
3592168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && ... */
3593168515Sgshapiro
359438032Speter	/* Get ldap struct pointer from map */
359590792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
359690792Sgshapiro	sm_ldap_setopts(lmap->ldap_ld, lmap);
359738032Speter
3598168515Sgshapiro	if (lmap->ldap_multi_args)
3599168515Sgshapiro	{
3600168515Sgshapiro		SM_REQUIRE(av != NULL);
3601168515Sgshapiro		memset(argv, '\0', sizeof(argv));
3602168515Sgshapiro		for (i = 0; i < SM_LDAP_ARGS && av[i] != NULL; i++)
3603168515Sgshapiro		{
3604168515Sgshapiro			argv[i] = sm_strdup(av[i]);
3605168515Sgshapiro			if (argv[i] == NULL)
3606168515Sgshapiro			{
3607168515Sgshapiro				int save_errno, j;
360838032Speter
3609168515Sgshapiro				save_errno = errno;
3610168515Sgshapiro				for (j = 0; j < i && argv[j] != NULL; j++)
3611168515Sgshapiro					SM_FREE(argv[j]);
3612168515Sgshapiro				*statp = EX_TEMPFAIL;
3613168515Sgshapiro				errno = save_errno;
3614168515Sgshapiro				return NULL;
3615168515Sgshapiro			}
3616168515Sgshapiro
3617168515Sgshapiro			if (!bitset(MF_NOFOLDCASE, map->map_mflags))
3618168515Sgshapiro				SM_CONVERT_ID(av[i]);
3619168515Sgshapiro		}
3620168515Sgshapiro	}
3621168515Sgshapiro	else
362264562Sgshapiro	{
3623168515Sgshapiro		(void) sm_strlcpy(keybuf, name, sizeof(keybuf));
3624168515Sgshapiro
3625168515Sgshapiro		if (!bitset(MF_NOFOLDCASE, map->map_mflags))
3626168515Sgshapiro			SM_CONVERT_ID(keybuf);
362764562Sgshapiro	}
362838032Speter
3629168515Sgshapiro	if (tTd(38, 20))
363038032Speter	{
3631168515Sgshapiro		if (lmap->ldap_multi_args)
3632168515Sgshapiro		{
3633168515Sgshapiro			sm_dprintf("ldapmap_lookup(%s, argv)\n",
3634168515Sgshapiro				map->map_mname);
3635168515Sgshapiro			for (i = 0; i < SM_LDAP_ARGS; i++)
3636168515Sgshapiro			{
3637168515Sgshapiro				sm_dprintf("   argv[%d] = %s\n", i,
3638168515Sgshapiro					   argv[i] == NULL ? "NULL" : argv[i]);
3639168515Sgshapiro			}
3640168515Sgshapiro		}
3641168515Sgshapiro		else
3642168515Sgshapiro		{
3643168515Sgshapiro			sm_dprintf("ldapmap_lookup(%s, %s)\n",
3644168515Sgshapiro				   map->map_mname, name);
3645168515Sgshapiro		}
3646168515Sgshapiro	}
3647168515Sgshapiro
3648168515Sgshapiro	if (lmap->ldap_multi_args)
3649168515Sgshapiro	{
3650168515Sgshapiro		msgid = sm_ldap_search_m(lmap, argv);
3651168515Sgshapiro
3652168515Sgshapiro		/* free the argv array and its content, no longer needed */
3653168515Sgshapiro		for (i = 0; i < SM_LDAP_ARGS && argv[i] != NULL; i++)
3654168515Sgshapiro			SM_FREE(argv[i]);
3655168515Sgshapiro	}
3656168515Sgshapiro	else
3657168515Sgshapiro		msgid = sm_ldap_search(lmap, keybuf);
3658168515Sgshapiro	if (msgid == SM_LDAP_ERR)
3659168515Sgshapiro	{
366090792Sgshapiro		errno = sm_ldap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
366177349Sgshapiro		save_errno = errno;
366264562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
366338032Speter		{
3664168515Sgshapiro			/*
3665168515Sgshapiro			**  Do not include keybuf as this error may be shown
3666168515Sgshapiro			**  to outsiders.
3667168515Sgshapiro			*/
3668168515Sgshapiro
366964562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
3670168515Sgshapiro				syserr("Error in ldap_search in map %s",
3671168515Sgshapiro				       map->map_mname);
367264562Sgshapiro			else
3673168515Sgshapiro				syserr("451 4.3.5 Error in ldap_search in map %s",
3674168515Sgshapiro				       map->map_mname);
367538032Speter		}
367664562Sgshapiro		*statp = EX_TEMPFAIL;
367790792Sgshapiro		switch (save_errno - E_LDAPBASE)
367890792Sgshapiro		{
367994334Sgshapiro# ifdef LDAP_SERVER_DOWN
368090792Sgshapiro		  case LDAP_SERVER_DOWN:
368194334Sgshapiro# endif /* LDAP_SERVER_DOWN */
368290792Sgshapiro		  case LDAP_TIMEOUT:
368390792Sgshapiro		  case LDAP_UNAVAILABLE:
368466494Sgshapiro			/* server disappeared, try reopen on next search */
368577349Sgshapiro			ldapmap_close(map);
368690792Sgshapiro			break;
368766494Sgshapiro		}
368877349Sgshapiro		errno = save_errno;
368964562Sgshapiro		return NULL;
369064562Sgshapiro	}
3691168515Sgshapiro#if SM_LDAP_ERROR_ON_MISSING_ARGS
3692168515Sgshapiro	else if (msgid == SM_LDAP_ERR_ARG_MISS)
3693168515Sgshapiro	{
3694168515Sgshapiro		if (bitset(MF_NODEFER, map->map_mflags))
3695168515Sgshapiro			syserr("Error in ldap_search in map %s, too few arguments",
3696168515Sgshapiro			       map->map_mname);
3697168515Sgshapiro		else
3698168515Sgshapiro			syserr("554 5.3.5 Error in ldap_search in map %s, too few arguments",
3699168515Sgshapiro			       map->map_mname);
3700168515Sgshapiro		*statp = EX_CONFIG;
3701168515Sgshapiro		return NULL;
3702168515Sgshapiro	}
3703168515Sgshapiro#endif /* SM_LDAP_ERROR_ON_MISSING_ARGS */
370464562Sgshapiro
370564562Sgshapiro	*statp = EX_NOTFOUND;
370664562Sgshapiro	vp = NULL;
370764562Sgshapiro
3708132943Sgshapiro	flags = 0;
3709132943Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
3710132943Sgshapiro		flags |= SM_LDAP_SINGLEMATCH;
3711132943Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
3712132943Sgshapiro		flags |= SM_LDAP_MATCHONLY;
3713157001Sgshapiro# if _FFR_LDAP_SINGLEDN
3714157001Sgshapiro	if (bitset(MF_SINGLEDN, map->map_mflags))
3715157001Sgshapiro		flags |= SM_LDAP_SINGLEDN;
3716157001Sgshapiro# endif /* _FFR_LDAP_SINGLEDN */
371790792Sgshapiro
3718132943Sgshapiro	/* Create an rpool for search related memory usage */
3719132943Sgshapiro	rpool = sm_rpool_new_x(NULL);
372090792Sgshapiro
3721132943Sgshapiro	p = NULL;
3722132943Sgshapiro	*statp = sm_ldap_results(lmap, msgid, flags, map->map_coldelim,
3723132943Sgshapiro				 rpool, &p, &plen, &psize, NULL);
3724132943Sgshapiro	save_errno = errno;
372590792Sgshapiro
3726132943Sgshapiro	/* Copy result so rpool can be freed */
3727132943Sgshapiro	if (*statp == EX_OK && p != NULL)
3728132943Sgshapiro		vp = newstr(p);
3729132943Sgshapiro	sm_rpool_free(rpool);
373090792Sgshapiro
3731132943Sgshapiro	/* need to restart LDAP connection? */
3732132943Sgshapiro	if (*statp == EX_RESTART)
373364562Sgshapiro	{
3734132943Sgshapiro		*statp = EX_TEMPFAIL;
3735132943Sgshapiro		ldapmap_close(map);
373638032Speter	}
373738032Speter
3738132943Sgshapiro	errno = save_errno;
3739132943Sgshapiro	if (*statp != EX_OK && *statp != EX_NOTFOUND)
374038032Speter	{
374164562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
374264562Sgshapiro		{
374364562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
374464562Sgshapiro				syserr("Error getting LDAP results in map %s",
374564562Sgshapiro				       map->map_mname);
374664562Sgshapiro			else
374794334Sgshapiro				syserr("451 4.3.5 Error getting LDAP results in map %s",
374864562Sgshapiro				       map->map_mname);
374964562Sgshapiro		}
375077349Sgshapiro		errno = save_errno;
375164562Sgshapiro		return NULL;
375238032Speter	}
375390792Sgshapiro
375464562Sgshapiro	/* Did we match anything? */
375571345Sgshapiro	if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags))
375664562Sgshapiro		return NULL;
375738032Speter
375864562Sgshapiro	if (*statp == EX_OK)
375964562Sgshapiro	{
376064562Sgshapiro		if (LogLevel > 9)
376164562Sgshapiro			sm_syslog(LOG_INFO, CurEnv->e_id,
376271345Sgshapiro				  "ldap %.100s => %s", name,
376371345Sgshapiro				  vp == NULL ? "<NULL>" : vp);
376464562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
376564562Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
376664562Sgshapiro		else
376771345Sgshapiro		{
376871345Sgshapiro			/* vp != NULL according to test above */
376964562Sgshapiro			result = map_rewrite(map, vp, strlen(vp), av);
377071345Sgshapiro		}
377171345Sgshapiro		if (vp != NULL)
377290792Sgshapiro			sm_free(vp); /* XXX */
377364562Sgshapiro	}
377464562Sgshapiro	return result;
377538032Speter}
377638032Speter
377738032Speter/*
377864562Sgshapiro**  LDAPMAP_FINDCONN -- find an LDAP connection to the server
377964562Sgshapiro**
378064562Sgshapiro**	Cache LDAP connections based on the host, port, bind DN,
378166494Sgshapiro**	secret, and PID so we don't have multiple connections open to
378266494Sgshapiro**	the same server for different maps.  Need a separate connection
378366494Sgshapiro**	per PID since a parent process may close the map before the
378466494Sgshapiro**	child is done with it.
378564562Sgshapiro**
378664562Sgshapiro**	Parameters:
378764562Sgshapiro**		lmap -- LDAP map information
378864562Sgshapiro**
378964562Sgshapiro**	Returns:
379064562Sgshapiro**		Symbol table entry for the LDAP connection.
379138032Speter*/
379238032Speter
379364562Sgshapirostatic STAB *
379464562Sgshapiroldapmap_findconn(lmap)
379590792Sgshapiro	SM_LDAP_STRUCT *lmap;
379638032Speter{
379794334Sgshapiro	char *format;
379864562Sgshapiro	char *nbuf;
3799132943Sgshapiro	char *id;
380090792Sgshapiro	STAB *SM_NONVOLATILE s = NULL;
380138032Speter
3802132943Sgshapiro	if (lmap->ldap_host != NULL)
3803132943Sgshapiro		id = lmap->ldap_host;
3804132943Sgshapiro	else if (lmap->ldap_uri != NULL)
3805132943Sgshapiro		id = lmap->ldap_uri;
3806132943Sgshapiro	else
3807132943Sgshapiro		id = "localhost";
3808132943Sgshapiro
380994334Sgshapiro	format = "%s%c%d%c%d%c%s%c%s%d";
381094334Sgshapiro	nbuf = sm_stringf_x(format,
3811132943Sgshapiro			    id,
381290792Sgshapiro			    CONDELSE,
381390792Sgshapiro			    lmap->ldap_port,
381490792Sgshapiro			    CONDELSE,
381594334Sgshapiro			    lmap->ldap_version,
381694334Sgshapiro			    CONDELSE,
381790792Sgshapiro			    (lmap->ldap_binddn == NULL ? ""
381890792Sgshapiro						       : lmap->ldap_binddn),
381990792Sgshapiro			    CONDELSE,
382090792Sgshapiro			    (lmap->ldap_secret == NULL ? ""
382190792Sgshapiro						       : lmap->ldap_secret),
382290792Sgshapiro			    (int) CurrentPid);
382390792Sgshapiro	SM_TRY
382490792Sgshapiro		s = stab(nbuf, ST_LMAP, ST_ENTER);
382590792Sgshapiro	SM_FINALLY
382690792Sgshapiro		sm_free(nbuf);
382790792Sgshapiro	SM_END_TRY
382864562Sgshapiro	return s;
382964562Sgshapiro}
383038032Speter/*
383164562Sgshapiro**  LDAPMAP_PARSEARGS -- parse ldap map definition args.
383264562Sgshapiro*/
383338032Speter
383490792Sgshapirostatic struct lamvalues LDAPAuthMethods[] =
383564562Sgshapiro{
383664562Sgshapiro	{	"none",		LDAP_AUTH_NONE		},
383764562Sgshapiro	{	"simple",	LDAP_AUTH_SIMPLE	},
383864562Sgshapiro# ifdef LDAP_AUTH_KRBV4
383964562Sgshapiro	{	"krbv4",	LDAP_AUTH_KRBV4		},
384064562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
384164562Sgshapiro	{	NULL,		0			}
384264562Sgshapiro};
384338032Speter
384490792Sgshapirostatic struct ladvalues LDAPAliasDereference[] =
384564562Sgshapiro{
384664562Sgshapiro	{	"never",	LDAP_DEREF_NEVER	},
384764562Sgshapiro	{	"always",	LDAP_DEREF_ALWAYS	},
384864562Sgshapiro	{	"search",	LDAP_DEREF_SEARCHING	},
384964562Sgshapiro	{	"find",		LDAP_DEREF_FINDING	},
385064562Sgshapiro	{	NULL,		0			}
385164562Sgshapiro};
385238032Speter
385390792Sgshapirostatic struct lssvalues LDAPSearchScope[] =
385464562Sgshapiro{
385564562Sgshapiro	{	"base",		LDAP_SCOPE_BASE		},
385664562Sgshapiro	{	"one",		LDAP_SCOPE_ONELEVEL	},
385764562Sgshapiro	{	"sub",		LDAP_SCOPE_SUBTREE	},
385864562Sgshapiro	{	NULL,		0			}
385964562Sgshapiro};
386038032Speter
386164562Sgshapirobool
386264562Sgshapiroldapmap_parseargs(map, args)
386364562Sgshapiro	MAP *map;
386464562Sgshapiro	char *args;
386564562Sgshapiro{
386690792Sgshapiro	bool secretread = true;
3867132943Sgshapiro	bool attrssetup = false;
386864562Sgshapiro	int i;
386964562Sgshapiro	register char *p = args;
387090792Sgshapiro	SM_LDAP_STRUCT *lmap;
387164562Sgshapiro	struct lamvalues *lam;
387264562Sgshapiro	struct ladvalues *lad;
387364562Sgshapiro	struct lssvalues *lss;
387490792Sgshapiro	char ldapfilt[MAXLINE];
387564562Sgshapiro	char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
387664562Sgshapiro
387764562Sgshapiro	/* Get ldap struct pointer from map */
387890792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
387964562Sgshapiro
388064562Sgshapiro	/* Check if setting the initial LDAP defaults */
388164562Sgshapiro	if (lmap == NULL || lmap != LDAPDefaults)
388264562Sgshapiro	{
388390792Sgshapiro		/* We need to alloc an SM_LDAP_STRUCT struct */
3884168515Sgshapiro		lmap = (SM_LDAP_STRUCT *) xalloc(sizeof(*lmap));
388564562Sgshapiro		if (LDAPDefaults == NULL)
388690792Sgshapiro			sm_ldap_clear(lmap);
388764562Sgshapiro		else
388864562Sgshapiro			STRUCTCOPY(*LDAPDefaults, *lmap);
388964562Sgshapiro	}
389064562Sgshapiro
389164562Sgshapiro	/* there is no check whether there is really an argument */
389264562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
389364562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
389490792Sgshapiro
389590792Sgshapiro	/* Check if setting up an alias or file class LDAP map */
389690792Sgshapiro	if (bitset(MF_ALIAS, map->map_mflags))
389790792Sgshapiro	{
389890792Sgshapiro		/* Comma separate if used as an alias file */
389990792Sgshapiro		map->map_coldelim = ',';
390090792Sgshapiro		if (*args == '\0')
390190792Sgshapiro		{
390290792Sgshapiro			int n;
390390792Sgshapiro			char *lc;
390490792Sgshapiro			char jbuf[MAXHOSTNAMELEN];
390590792Sgshapiro			char lcbuf[MAXLINE];
390690792Sgshapiro
390790792Sgshapiro			/* Get $j */
3908168515Sgshapiro			expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope);
390990792Sgshapiro			if (jbuf[0] == '\0')
391090792Sgshapiro			{
391190792Sgshapiro				(void) sm_strlcpy(jbuf, "localhost",
3912168515Sgshapiro						  sizeof(jbuf));
391390792Sgshapiro			}
391490792Sgshapiro
391590792Sgshapiro			lc = macvalue(macid("{sendmailMTACluster}"), CurEnv);
391690792Sgshapiro			if (lc == NULL)
391790792Sgshapiro				lc = "";
391890792Sgshapiro			else
391990792Sgshapiro			{
3920168515Sgshapiro				expand(lc, lcbuf, sizeof(lcbuf), CurEnv);
392190792Sgshapiro				lc = lcbuf;
392290792Sgshapiro			}
392390792Sgshapiro
3924168515Sgshapiro			n = sm_snprintf(ldapfilt, sizeof(ldapfilt),
392590792Sgshapiro					"(&(objectClass=sendmailMTAAliasObject)(sendmailMTAAliasGrouping=aliases)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))(sendmailMTAKey=%%0))",
392690792Sgshapiro					lc, jbuf);
3927168515Sgshapiro			if (n >= sizeof(ldapfilt))
392890792Sgshapiro			{
392990792Sgshapiro				syserr("%s: Default LDAP string too long",
393090792Sgshapiro				       map->map_mname);
393190792Sgshapiro				return false;
393290792Sgshapiro			}
393390792Sgshapiro
393490792Sgshapiro			/* default args for an alias LDAP entry */
393590792Sgshapiro			lmap->ldap_filter = ldapfilt;
3936132943Sgshapiro			lmap->ldap_attr[0] = "objectClass";
3937132943Sgshapiro			lmap->ldap_attr_type[0] = SM_LDAP_ATTR_OBJCLASS;
3938132943Sgshapiro			lmap->ldap_attr_needobjclass[0] = NULL;
3939132943Sgshapiro			lmap->ldap_attr[1] = "sendmailMTAAliasValue";
3940132943Sgshapiro			lmap->ldap_attr_type[1] = SM_LDAP_ATTR_NORMAL;
3941132943Sgshapiro			lmap->ldap_attr_needobjclass[1] = NULL;
3942132943Sgshapiro			lmap->ldap_attr[2] = "sendmailMTAAliasSearch";
3943132943Sgshapiro			lmap->ldap_attr_type[2] = SM_LDAP_ATTR_FILTER;
3944132943Sgshapiro			lmap->ldap_attr_needobjclass[2] = "sendmailMTAMapObject";
3945132943Sgshapiro			lmap->ldap_attr[3] = "sendmailMTAAliasURL";
3946132943Sgshapiro			lmap->ldap_attr_type[3] = SM_LDAP_ATTR_URL;
3947132943Sgshapiro			lmap->ldap_attr_needobjclass[3] = "sendmailMTAMapObject";
3948132943Sgshapiro			lmap->ldap_attr[4] = NULL;
3949132943Sgshapiro			lmap->ldap_attr_type[4] = SM_LDAP_ATTR_NONE;
3950132943Sgshapiro			lmap->ldap_attr_needobjclass[4] = NULL;
3951132943Sgshapiro			attrssetup = true;
395290792Sgshapiro		}
395390792Sgshapiro	}
395490792Sgshapiro	else if (bitset(MF_FILECLASS, map->map_mflags))
395590792Sgshapiro	{
395690792Sgshapiro		/* Space separate if used as a file class file */
395790792Sgshapiro		map->map_coldelim = ' ';
395890792Sgshapiro	}
395990792Sgshapiro
396038032Speter	for (;;)
396138032Speter	{
396238032Speter		while (isascii(*p) && isspace(*p))
396338032Speter			p++;
396438032Speter		if (*p != '-')
396538032Speter			break;
396638032Speter		switch (*++p)
396738032Speter		{
396838032Speter		  case 'N':
396938032Speter			map->map_mflags |= MF_INCLNULL;
397038032Speter			map->map_mflags &= ~MF_TRY0NULL;
397138032Speter			break;
397238032Speter
397338032Speter		  case 'O':
397438032Speter			map->map_mflags &= ~MF_TRY1NULL;
397538032Speter			break;
397638032Speter
397738032Speter		  case 'o':
397838032Speter			map->map_mflags |= MF_OPTIONAL;
397938032Speter			break;
398038032Speter
398138032Speter		  case 'f':
398238032Speter			map->map_mflags |= MF_NOFOLDCASE;
398338032Speter			break;
398438032Speter
398538032Speter		  case 'm':
398638032Speter			map->map_mflags |= MF_MATCHONLY;
398738032Speter			break;
398838032Speter
398938032Speter		  case 'A':
399038032Speter			map->map_mflags |= MF_APPEND;
399138032Speter			break;
399238032Speter
399338032Speter		  case 'q':
399438032Speter			map->map_mflags |= MF_KEEPQUOTES;
399538032Speter			break;
399638032Speter
399738032Speter		  case 'a':
399838032Speter			map->map_app = ++p;
399938032Speter			break;
400038032Speter
400138032Speter		  case 'T':
400238032Speter			map->map_tapp = ++p;
400338032Speter			break;
400438032Speter
400564562Sgshapiro		  case 't':
400664562Sgshapiro			map->map_mflags |= MF_NODEFER;
400764562Sgshapiro			break;
400864562Sgshapiro
400964562Sgshapiro		  case 'S':
401064562Sgshapiro			map->map_spacesub = *++p;
401164562Sgshapiro			break;
401264562Sgshapiro
401364562Sgshapiro		  case 'D':
401464562Sgshapiro			map->map_mflags |= MF_DEFER;
401564562Sgshapiro			break;
401664562Sgshapiro
401764562Sgshapiro		  case 'z':
401864562Sgshapiro			if (*++p != '\\')
401964562Sgshapiro				map->map_coldelim = *p;
402064562Sgshapiro			else
402164562Sgshapiro			{
402264562Sgshapiro				switch (*++p)
402364562Sgshapiro				{
402464562Sgshapiro				  case 'n':
402564562Sgshapiro					map->map_coldelim = '\n';
402664562Sgshapiro					break;
402764562Sgshapiro
402864562Sgshapiro				  case 't':
402964562Sgshapiro					map->map_coldelim = '\t';
403064562Sgshapiro					break;
403164562Sgshapiro
403264562Sgshapiro				  default:
403364562Sgshapiro					map->map_coldelim = '\\';
403464562Sgshapiro				}
403564562Sgshapiro			}
403664562Sgshapiro			break;
403764562Sgshapiro
403864562Sgshapiro			/* Start of ldapmap specific args */
403990792Sgshapiro		  case 'V':
404090792Sgshapiro			if (*++p != '\\')
404190792Sgshapiro				lmap->ldap_attrsep = *p;
404290792Sgshapiro			else
404390792Sgshapiro			{
404490792Sgshapiro				switch (*++p)
404590792Sgshapiro				{
404690792Sgshapiro				  case 'n':
404790792Sgshapiro					lmap->ldap_attrsep = '\n';
404890792Sgshapiro					break;
404990792Sgshapiro
405090792Sgshapiro				  case 't':
405190792Sgshapiro					lmap->ldap_attrsep = '\t';
405290792Sgshapiro					break;
405390792Sgshapiro
405490792Sgshapiro				  default:
405590792Sgshapiro					lmap->ldap_attrsep = '\\';
405690792Sgshapiro				}
405790792Sgshapiro			}
405890792Sgshapiro			break;
405990792Sgshapiro
406038032Speter		  case 'k':		/* search field */
406138032Speter			while (isascii(*++p) && isspace(*p))
406238032Speter				continue;
406364562Sgshapiro			lmap->ldap_filter = p;
406438032Speter			break;
406538032Speter
406638032Speter		  case 'v':		/* attr to return */
406738032Speter			while (isascii(*++p) && isspace(*p))
406838032Speter				continue;
406964562Sgshapiro			lmap->ldap_attr[0] = p;
407064562Sgshapiro			lmap->ldap_attr[1] = NULL;
407138032Speter			break;
407238032Speter
407364562Sgshapiro		  case '1':
407464562Sgshapiro			map->map_mflags |= MF_SINGLEMATCH;
407564562Sgshapiro			break;
407664562Sgshapiro
4077157001Sgshapiro# if _FFR_LDAP_SINGLEDN
4078157001Sgshapiro		  case '2':
4079157001Sgshapiro			map->map_mflags |= MF_SINGLEDN;
4080157001Sgshapiro			break;
4081157001Sgshapiro# endif /* _FFR_LDAP_SINGLEDN */
4082157001Sgshapiro
408338032Speter			/* args stolen from ldapsearch.c */
408438032Speter		  case 'R':		/* don't auto chase referrals */
408564562Sgshapiro# ifdef LDAP_REFERRALS
408638032Speter			lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
408764562Sgshapiro# else /* LDAP_REFERRALS */
408890792Sgshapiro			syserr("compile with -DLDAP_REFERRALS for referral support");
408964562Sgshapiro# endif /* LDAP_REFERRALS */
409038032Speter			break;
409138032Speter
409264562Sgshapiro		  case 'n':		/* retrieve attribute names only */
409364562Sgshapiro			lmap->ldap_attrsonly = LDAPMAP_TRUE;
409438032Speter			break;
409538032Speter
409664562Sgshapiro		  case 'r':		/* alias dereferencing */
409764562Sgshapiro			while (isascii(*++p) && isspace(*p))
409864562Sgshapiro				continue;
409964562Sgshapiro
410090792Sgshapiro			if (sm_strncasecmp(p, "LDAP_DEREF_", 11) == 0)
410164562Sgshapiro				p += 11;
410264562Sgshapiro
410364562Sgshapiro			for (lad = LDAPAliasDereference;
410464562Sgshapiro			     lad != NULL && lad->lad_name != NULL; lad++)
410538032Speter			{
410690792Sgshapiro				if (sm_strncasecmp(p, lad->lad_name,
410790792Sgshapiro						   strlen(lad->lad_name)) == 0)
410864562Sgshapiro					break;
410938032Speter			}
411064562Sgshapiro			if (lad->lad_name != NULL)
411164562Sgshapiro				lmap->ldap_deref = lad->lad_code;
411264562Sgshapiro			else
411338032Speter			{
411464562Sgshapiro				/* bad config line */
411564562Sgshapiro				if (!bitset(MCF_OPTFILE,
411664562Sgshapiro					    map->map_class->map_cflags))
411764562Sgshapiro				{
411864562Sgshapiro					char *ptr;
411964562Sgshapiro
412064562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
412164562Sgshapiro						*ptr = '\0';
412273188Sgshapiro					syserr("Deref must be [never|always|search|find] (not %s) in map %s",
412364562Sgshapiro						p, map->map_mname);
412464562Sgshapiro					if (ptr != NULL)
412564562Sgshapiro						*ptr = ' ';
412690792Sgshapiro					return false;
412764562Sgshapiro				}
412838032Speter			}
412964562Sgshapiro			break;
413064562Sgshapiro
413164562Sgshapiro		  case 's':		/* search scope */
413264562Sgshapiro			while (isascii(*++p) && isspace(*p))
413364562Sgshapiro				continue;
413464562Sgshapiro
413590792Sgshapiro			if (sm_strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
413664562Sgshapiro				p += 11;
413764562Sgshapiro
413864562Sgshapiro			for (lss = LDAPSearchScope;
413964562Sgshapiro			     lss != NULL && lss->lss_name != NULL; lss++)
414038032Speter			{
414190792Sgshapiro				if (sm_strncasecmp(p, lss->lss_name,
414290792Sgshapiro						   strlen(lss->lss_name)) == 0)
414364562Sgshapiro					break;
414438032Speter			}
414564562Sgshapiro			if (lss->lss_name != NULL)
414664562Sgshapiro				lmap->ldap_scope = lss->lss_code;
414738032Speter			else
414864562Sgshapiro			{
414964562Sgshapiro				/* bad config line */
415064562Sgshapiro				if (!bitset(MCF_OPTFILE,
415164562Sgshapiro					    map->map_class->map_cflags))
415238032Speter				{
415338032Speter					char *ptr;
415438032Speter
415538032Speter					if ((ptr = strchr(p, ' ')) != NULL)
415638032Speter						*ptr = '\0';
415773188Sgshapiro					syserr("Scope must be [base|one|sub] (not %s) in map %s",
415838032Speter						p, map->map_mname);
415938032Speter					if (ptr != NULL)
416038032Speter						*ptr = ' ';
416190792Sgshapiro					return false;
416238032Speter				}
416338032Speter			}
416438032Speter			break;
416538032Speter
416638032Speter		  case 'h':		/* ldap host */
416738032Speter			while (isascii(*++p) && isspace(*p))
416838032Speter				continue;
4169132943Sgshapiro			if (lmap->ldap_uri != NULL)
417094334Sgshapiro			{
417194334Sgshapiro				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
417294334Sgshapiro				       map->map_mname);
417394334Sgshapiro				return false;
417494334Sgshapiro			}
4175132943Sgshapiro			lmap->ldap_host = p;
417638032Speter			break;
417738032Speter
417838032Speter		  case 'b':		/* search base */
417938032Speter			while (isascii(*++p) && isspace(*p))
418038032Speter				continue;
418164562Sgshapiro			lmap->ldap_base = p;
418238032Speter			break;
418338032Speter
418438032Speter		  case 'p':		/* ldap port */
418538032Speter			while (isascii(*++p) && isspace(*p))
418638032Speter				continue;
418764562Sgshapiro			lmap->ldap_port = atoi(p);
418838032Speter			break;
418938032Speter
419038032Speter		  case 'l':		/* time limit */
419138032Speter			while (isascii(*++p) && isspace(*p))
419238032Speter				continue;
419364562Sgshapiro			lmap->ldap_timelimit = atoi(p);
419464562Sgshapiro			lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit;
419538032Speter			break;
419638032Speter
419764562Sgshapiro		  case 'Z':
419864562Sgshapiro			while (isascii(*++p) && isspace(*p))
419964562Sgshapiro				continue;
420064562Sgshapiro			lmap->ldap_sizelimit = atoi(p);
420164562Sgshapiro			break;
420264562Sgshapiro
420364562Sgshapiro		  case 'd':		/* Dn to bind to server as */
420464562Sgshapiro			while (isascii(*++p) && isspace(*p))
420564562Sgshapiro				continue;
420664562Sgshapiro			lmap->ldap_binddn = p;
420764562Sgshapiro			break;
420864562Sgshapiro
420964562Sgshapiro		  case 'M':		/* Method for binding */
421064562Sgshapiro			while (isascii(*++p) && isspace(*p))
421164562Sgshapiro				continue;
421264562Sgshapiro
421390792Sgshapiro			if (sm_strncasecmp(p, "LDAP_AUTH_", 10) == 0)
421464562Sgshapiro				p += 10;
421564562Sgshapiro
421664562Sgshapiro			for (lam = LDAPAuthMethods;
421764562Sgshapiro			     lam != NULL && lam->lam_name != NULL; lam++)
421864562Sgshapiro			{
421990792Sgshapiro				if (sm_strncasecmp(p, lam->lam_name,
422090792Sgshapiro						   strlen(lam->lam_name)) == 0)
422164562Sgshapiro					break;
422264562Sgshapiro			}
422364562Sgshapiro			if (lam->lam_name != NULL)
422464562Sgshapiro				lmap->ldap_method = lam->lam_code;
422564562Sgshapiro			else
422664562Sgshapiro			{
422764562Sgshapiro				/* bad config line */
422864562Sgshapiro				if (!bitset(MCF_OPTFILE,
422964562Sgshapiro					    map->map_class->map_cflags))
423064562Sgshapiro				{
423164562Sgshapiro					char *ptr;
423264562Sgshapiro
423364562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
423464562Sgshapiro						*ptr = '\0';
423573188Sgshapiro					syserr("Method for binding must be [none|simple|krbv4] (not %s) in map %s",
423664562Sgshapiro						p, map->map_mname);
423764562Sgshapiro					if (ptr != NULL)
423864562Sgshapiro						*ptr = ' ';
423990792Sgshapiro					return false;
424064562Sgshapiro				}
424164562Sgshapiro			}
424264562Sgshapiro
424364562Sgshapiro			break;
424464562Sgshapiro
424564562Sgshapiro			/*
424664562Sgshapiro			**  This is a string that is dependent on the
424764562Sgshapiro			**  method used defined above.
424864562Sgshapiro			*/
424964562Sgshapiro
425064562Sgshapiro		  case 'P':		/* Secret password for binding */
425164562Sgshapiro			 while (isascii(*++p) && isspace(*p))
425264562Sgshapiro				continue;
425364562Sgshapiro			lmap->ldap_secret = p;
425490792Sgshapiro			secretread = false;
425564562Sgshapiro			break;
425664562Sgshapiro
425794334Sgshapiro		  case 'H':		/* Use LDAP URI */
425894334Sgshapiro#  if !USE_LDAP_INIT
425994334Sgshapiro			syserr("Must compile with -DUSE_LDAP_INIT to use LDAP URIs (-H) in map %s",
426094334Sgshapiro			       map->map_mname);
426194334Sgshapiro			return false;
4262132943Sgshapiro#   else /* !USE_LDAP_INIT */
4263132943Sgshapiro			if (lmap->ldap_host != NULL)
426494334Sgshapiro			{
426594334Sgshapiro				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
426694334Sgshapiro				       map->map_mname);
426794334Sgshapiro				return false;
426894334Sgshapiro			}
426994334Sgshapiro			while (isascii(*++p) && isspace(*p))
427094334Sgshapiro				continue;
4271132943Sgshapiro			lmap->ldap_uri = p;
427294334Sgshapiro			break;
427394334Sgshapiro#  endif /* !USE_LDAP_INIT */
427494334Sgshapiro
427594334Sgshapiro		  case 'w':
427694334Sgshapiro			/* -w should be for passwd, -P should be for version */
427794334Sgshapiro			while (isascii(*++p) && isspace(*p))
427894334Sgshapiro				continue;
427994334Sgshapiro			lmap->ldap_version = atoi(p);
4280132943Sgshapiro# ifdef LDAP_VERSION_MAX
428194334Sgshapiro			if (lmap->ldap_version > LDAP_VERSION_MAX)
428294334Sgshapiro			{
428394334Sgshapiro				syserr("LDAP version %d exceeds max of %d in map %s",
428494334Sgshapiro				       lmap->ldap_version, LDAP_VERSION_MAX,
428594334Sgshapiro				       map->map_mname);
428694334Sgshapiro				return false;
428794334Sgshapiro			}
4288132943Sgshapiro# endif /* LDAP_VERSION_MAX */
4289132943Sgshapiro# ifdef LDAP_VERSION_MIN
429094334Sgshapiro			if (lmap->ldap_version < LDAP_VERSION_MIN)
429194334Sgshapiro			{
429294334Sgshapiro				syserr("LDAP version %d is lower than min of %d in map %s",
429394334Sgshapiro				       lmap->ldap_version, LDAP_VERSION_MIN,
429494334Sgshapiro				       map->map_mname);
429594334Sgshapiro				return false;
429694334Sgshapiro			}
4297132943Sgshapiro# endif /* LDAP_VERSION_MIN */
429894334Sgshapiro			break;
429994334Sgshapiro
4300168515Sgshapiro		  case 'K':
4301168515Sgshapiro			lmap->ldap_multi_args = true;
4302168515Sgshapiro			break;
4303168515Sgshapiro
430464562Sgshapiro		  default:
430564562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
430664562Sgshapiro			break;
430738032Speter		}
430838032Speter
430964562Sgshapiro		/* need to account for quoted strings here */
431064562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
431138032Speter		{
431238032Speter			if (*p == '"')
431338032Speter			{
431438032Speter				while (*++p != '"' && *p != '\0')
431538032Speter					continue;
431638032Speter				if (*p != '\0')
431738032Speter					p++;
431838032Speter			}
431938032Speter			else
432038032Speter				p++;
432138032Speter		}
432238032Speter
432338032Speter		if (*p != '\0')
432438032Speter			*p++ = '\0';
432538032Speter	}
432638032Speter
432738032Speter	if (map->map_app != NULL)
432864562Sgshapiro		map->map_app = newstr(ldapmap_dequote(map->map_app));
432938032Speter	if (map->map_tapp != NULL)
433064562Sgshapiro		map->map_tapp = newstr(ldapmap_dequote(map->map_tapp));
433138032Speter
433238032Speter	/*
433342575Speter	**  We need to swallow up all the stuff into a struct
433442575Speter	**  and dump it into map->map_dbptr1
433538032Speter	*/
433638032Speter
4337132943Sgshapiro	if (lmap->ldap_host != NULL &&
433864562Sgshapiro	    (LDAPDefaults == NULL ||
433964562Sgshapiro	     LDAPDefaults == lmap ||
4340132943Sgshapiro	     LDAPDefaults->ldap_host != lmap->ldap_host))
4341132943Sgshapiro		lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host));
4342132943Sgshapiro	map->map_domain = lmap->ldap_host;
434364562Sgshapiro
4344132943Sgshapiro	if (lmap->ldap_uri != NULL &&
4345132943Sgshapiro	    (LDAPDefaults == NULL ||
4346132943Sgshapiro	     LDAPDefaults == lmap ||
4347132943Sgshapiro	     LDAPDefaults->ldap_uri != lmap->ldap_uri))
4348132943Sgshapiro		lmap->ldap_uri = newstr(ldapmap_dequote(lmap->ldap_uri));
4349132943Sgshapiro	map->map_domain = lmap->ldap_uri;
4350132943Sgshapiro
435164562Sgshapiro	if (lmap->ldap_binddn != NULL &&
435264562Sgshapiro	    (LDAPDefaults == NULL ||
435364562Sgshapiro	     LDAPDefaults == lmap ||
435464562Sgshapiro	     LDAPDefaults->ldap_binddn != lmap->ldap_binddn))
435564562Sgshapiro		lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn));
435664562Sgshapiro
435764562Sgshapiro	if (lmap->ldap_secret != NULL &&
435864562Sgshapiro	    (LDAPDefaults == NULL ||
435964562Sgshapiro	     LDAPDefaults == lmap ||
436064562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
436138032Speter	{
436290792Sgshapiro		SM_FILE_T *sfd;
436364562Sgshapiro		long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
436438032Speter
436564562Sgshapiro		if (DontLockReadFiles)
436664562Sgshapiro			sff |= SFF_NOLOCK;
436738032Speter
436864562Sgshapiro		/* need to use method to map secret to passwd string */
436964562Sgshapiro		switch (lmap->ldap_method)
437064562Sgshapiro		{
437164562Sgshapiro		  case LDAP_AUTH_NONE:
437264562Sgshapiro			/* Do nothing */
437364562Sgshapiro			break;
437438032Speter
437564562Sgshapiro		  case LDAP_AUTH_SIMPLE:
437638032Speter
437764562Sgshapiro			/*
437864562Sgshapiro			**  Secret is the name of a file with
437964562Sgshapiro			**  the first line as the password.
438064562Sgshapiro			*/
438164562Sgshapiro
438264562Sgshapiro			/* Already read in the secret? */
438364562Sgshapiro			if (secretread)
438464562Sgshapiro				break;
438564562Sgshapiro
438664562Sgshapiro			sfd = safefopen(ldapmap_dequote(lmap->ldap_secret),
438764562Sgshapiro					O_RDONLY, 0, sff);
438864562Sgshapiro			if (sfd == NULL)
438964562Sgshapiro			{
439064562Sgshapiro				syserr("LDAP map: cannot open secret %s",
439164562Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
439290792Sgshapiro				return false;
439364562Sgshapiro			}
4394168515Sgshapiro			lmap->ldap_secret = sfgets(m_tmp, sizeof(m_tmp),
439566494Sgshapiro						   sfd, TimeOuts.to_fileopen,
439666494Sgshapiro						   "ldapmap_parseargs");
439790792Sgshapiro			(void) sm_io_close(sfd, SM_TIME_DEFAULT);
439898121Sgshapiro			if (strlen(m_tmp) > LDAPMAP_MAX_PASSWD)
439998121Sgshapiro			{
440098121Sgshapiro				syserr("LDAP map: secret in %s too long",
440198121Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
440298121Sgshapiro				return false;
440398121Sgshapiro			}
440464562Sgshapiro			if (lmap->ldap_secret != NULL &&
440564562Sgshapiro			    strlen(m_tmp) > 0)
440664562Sgshapiro			{
440764562Sgshapiro				/* chomp newline */
440864562Sgshapiro				if (m_tmp[strlen(m_tmp) - 1] == '\n')
440964562Sgshapiro					m_tmp[strlen(m_tmp) - 1] = '\0';
441064562Sgshapiro
441164562Sgshapiro				lmap->ldap_secret = m_tmp;
441264562Sgshapiro			}
441364562Sgshapiro			break;
441464562Sgshapiro
441564562Sgshapiro# ifdef LDAP_AUTH_KRBV4
441664562Sgshapiro		  case LDAP_AUTH_KRBV4:
441764562Sgshapiro
441864562Sgshapiro			/*
441964562Sgshapiro			**  Secret is where the ticket file is
442064562Sgshapiro			**  stashed
442164562Sgshapiro			*/
442264562Sgshapiro
4423168515Sgshapiro			(void) sm_snprintf(m_tmp, sizeof(m_tmp),
442490792Sgshapiro				"KRBTKFILE=%s",
442590792Sgshapiro				ldapmap_dequote(lmap->ldap_secret));
442664562Sgshapiro			lmap->ldap_secret = m_tmp;
442764562Sgshapiro			break;
442864562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
442964562Sgshapiro
443064562Sgshapiro		  default:	       /* Should NEVER get here */
443164562Sgshapiro			syserr("LDAP map: Illegal value in lmap method");
443290792Sgshapiro			return false;
443390792Sgshapiro			/* NOTREACHED */
443464562Sgshapiro			break;
443564562Sgshapiro		}
443638032Speter	}
443738032Speter
443864562Sgshapiro	if (lmap->ldap_secret != NULL &&
443964562Sgshapiro	    (LDAPDefaults == NULL ||
444064562Sgshapiro	     LDAPDefaults == lmap ||
444164562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
444264562Sgshapiro		lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret));
444338032Speter
444464562Sgshapiro	if (lmap->ldap_base != NULL &&
444564562Sgshapiro	    (LDAPDefaults == NULL ||
444664562Sgshapiro	     LDAPDefaults == lmap ||
444764562Sgshapiro	     LDAPDefaults->ldap_base != lmap->ldap_base))
444864562Sgshapiro		lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base));
444964562Sgshapiro
445064562Sgshapiro	/*
445164562Sgshapiro	**  Save the server from extra work.  If request is for a single
445264562Sgshapiro	**  match, tell the server to only return enough records to
445364562Sgshapiro	**  determine if there is a single match or not.  This can not
445464562Sgshapiro	**  be one since the server would only return one and we wouldn't
445564562Sgshapiro	**  know if there were others available.
445664562Sgshapiro	*/
445764562Sgshapiro
445864562Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
445964562Sgshapiro		lmap->ldap_sizelimit = 2;
446064562Sgshapiro
446164562Sgshapiro	/* If setting defaults, don't process ldap_filter and ldap_attr */
446264562Sgshapiro	if (lmap == LDAPDefaults)
446390792Sgshapiro		return true;
446464562Sgshapiro
446564562Sgshapiro	if (lmap->ldap_filter != NULL)
446664562Sgshapiro		lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
446738032Speter	else
446838032Speter	{
446938032Speter		if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
447038032Speter		{
447138032Speter			syserr("No filter given in map %s", map->map_mname);
447290792Sgshapiro			return false;
447338032Speter		}
447438032Speter	}
447564562Sgshapiro
4476132943Sgshapiro	if (!attrssetup && lmap->ldap_attr[0] != NULL)
447738032Speter	{
447890792Sgshapiro		bool recurse = false;
447994334Sgshapiro		bool normalseen = false;
448090792Sgshapiro
448164562Sgshapiro		i = 0;
448264562Sgshapiro		p = ldapmap_dequote(lmap->ldap_attr[0]);
448364562Sgshapiro		lmap->ldap_attr[0] = NULL;
448464562Sgshapiro
448594334Sgshapiro		/* Prime the attr list with the objectClass attribute */
448694334Sgshapiro		lmap->ldap_attr[i] = "objectClass";
448794334Sgshapiro		lmap->ldap_attr_type[i] = SM_LDAP_ATTR_OBJCLASS;
448894334Sgshapiro		lmap->ldap_attr_needobjclass[i] = NULL;
448994334Sgshapiro		i++;
449094334Sgshapiro
449164562Sgshapiro		while (p != NULL)
449238032Speter		{
449364562Sgshapiro			char *v;
449464562Sgshapiro
449564562Sgshapiro			while (isascii(*p) && isspace(*p))
449664562Sgshapiro				p++;
449764562Sgshapiro			if (*p == '\0')
449864562Sgshapiro				break;
449964562Sgshapiro			v = p;
450064562Sgshapiro			p = strchr(v, ',');
450164562Sgshapiro			if (p != NULL)
450264562Sgshapiro				*p++ = '\0';
450364562Sgshapiro
450471345Sgshapiro			if (i >= LDAPMAP_MAX_ATTR)
450564562Sgshapiro			{
450664562Sgshapiro				syserr("Too many return attributes in %s (max %d)",
450764562Sgshapiro				       map->map_mname, LDAPMAP_MAX_ATTR);
450890792Sgshapiro				return false;
450964562Sgshapiro			}
451064562Sgshapiro			if (*v != '\0')
451190792Sgshapiro			{
451294334Sgshapiro				int j;
451394334Sgshapiro				int use;
451490792Sgshapiro				char *type;
451594334Sgshapiro				char *needobjclass;
451690792Sgshapiro
451790792Sgshapiro				type = strchr(v, ':');
451890792Sgshapiro				if (type != NULL)
451994334Sgshapiro				{
452090792Sgshapiro					*type++ = '\0';
452194334Sgshapiro					needobjclass = strchr(type, ':');
452294334Sgshapiro					if (needobjclass != NULL)
452394334Sgshapiro						*needobjclass++ = '\0';
452494334Sgshapiro				}
452594334Sgshapiro				else
452694334Sgshapiro				{
452794334Sgshapiro					needobjclass = NULL;
452894334Sgshapiro				}
452990792Sgshapiro
453094334Sgshapiro				use = i;
453190792Sgshapiro
453294334Sgshapiro				/* allow override on "objectClass" type */
453394334Sgshapiro				if (sm_strcasecmp(v, "objectClass") == 0 &&
453494334Sgshapiro				    lmap->ldap_attr_type[0] == SM_LDAP_ATTR_OBJCLASS)
453590792Sgshapiro				{
453694334Sgshapiro					use = 0;
453794334Sgshapiro				}
453894334Sgshapiro				else
453994334Sgshapiro				{
454094334Sgshapiro					/*
454194334Sgshapiro					**  Don't add something to attribute
454294334Sgshapiro					**  list twice.
454394334Sgshapiro					*/
454494334Sgshapiro
454594334Sgshapiro					for (j = 1; j < i; j++)
454690792Sgshapiro					{
454794334Sgshapiro						if (sm_strcasecmp(v, lmap->ldap_attr[j]) == 0)
454894334Sgshapiro						{
454994334Sgshapiro							syserr("Duplicate attribute (%s) in %s",
455094334Sgshapiro							       v, map->map_mname);
455194334Sgshapiro							return false;
455294334Sgshapiro						}
455390792Sgshapiro					}
455494334Sgshapiro
455594334Sgshapiro					lmap->ldap_attr[use] = newstr(v);
455694334Sgshapiro					if (needobjclass != NULL &&
455794334Sgshapiro					    *needobjclass != '\0' &&
455894334Sgshapiro					    *needobjclass != '*')
455990792Sgshapiro					{
456094334Sgshapiro						lmap->ldap_attr_needobjclass[use] = newstr(needobjclass);
456194334Sgshapiro					}
456294334Sgshapiro					else
456394334Sgshapiro					{
456494334Sgshapiro						lmap->ldap_attr_needobjclass[use] = NULL;
456594334Sgshapiro					}
456694334Sgshapiro
456794334Sgshapiro				}
456894334Sgshapiro
456994334Sgshapiro				if (type != NULL && *type != '\0')
457094334Sgshapiro				{
457194334Sgshapiro					if (sm_strcasecmp(type, "dn") == 0)
457294334Sgshapiro					{
457390792Sgshapiro						recurse = true;
457494334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_DN;
457590792Sgshapiro					}
457690792Sgshapiro					else if (sm_strcasecmp(type, "filter") == 0)
457790792Sgshapiro					{
457890792Sgshapiro						recurse = true;
457994334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_FILTER;
458090792Sgshapiro					}
458190792Sgshapiro					else if (sm_strcasecmp(type, "url") == 0)
458290792Sgshapiro					{
458390792Sgshapiro						recurse = true;
458494334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_URL;
458590792Sgshapiro					}
458694334Sgshapiro					else if (sm_strcasecmp(type, "normal") == 0)
458790792Sgshapiro					{
458894334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
458994334Sgshapiro						normalseen = true;
459090792Sgshapiro					}
459190792Sgshapiro					else
459290792Sgshapiro					{
459390792Sgshapiro						syserr("Unknown attribute type (%s) in %s",
459490792Sgshapiro						       type, map->map_mname);
459590792Sgshapiro						return false;
459690792Sgshapiro					}
459790792Sgshapiro				}
459890792Sgshapiro				else
459994334Sgshapiro				{
460094334Sgshapiro					lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
460194334Sgshapiro					normalseen = true;
460294334Sgshapiro				}
460390792Sgshapiro				i++;
460490792Sgshapiro			}
460538032Speter		}
460664562Sgshapiro		lmap->ldap_attr[i] = NULL;
4607141858Sgshapiro
4608141858Sgshapiro		/* Set in case needed in future code */
4609132943Sgshapiro		attrssetup = true;
4610141858Sgshapiro
461194334Sgshapiro		if (recurse && !normalseen)
461290792Sgshapiro		{
461394334Sgshapiro			syserr("LDAP recursion requested in %s but no returnable attribute given",
461490792Sgshapiro			       map->map_mname);
461590792Sgshapiro			return false;
461690792Sgshapiro		}
461790792Sgshapiro		if (recurse && lmap->ldap_attrsonly == LDAPMAP_TRUE)
461890792Sgshapiro		{
461990792Sgshapiro			syserr("LDAP recursion requested in %s can not be used with -n",
462090792Sgshapiro			       map->map_mname);
462190792Sgshapiro			return false;
462290792Sgshapiro		}
462338032Speter	}
462438032Speter	map->map_db1 = (ARBPTR_T) lmap;
462590792Sgshapiro	return true;
462638032Speter}
462738032Speter
462864562Sgshapiro/*
462964562Sgshapiro**  LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
463064562Sgshapiro**
463164562Sgshapiro**	Parameters:
463264562Sgshapiro**		spec -- map argument string from LDAPDefaults option
463364562Sgshapiro**
463464562Sgshapiro**	Returns:
463564562Sgshapiro**		None.
463664562Sgshapiro*/
463764562Sgshapiro
463864562Sgshapirovoid
463964562Sgshapiroldapmap_set_defaults(spec)
464064562Sgshapiro	char *spec;
464164562Sgshapiro{
464273188Sgshapiro	STAB *class;
464364562Sgshapiro	MAP map;
464464562Sgshapiro
464564562Sgshapiro	/* Allocate and set the default values */
464664562Sgshapiro	if (LDAPDefaults == NULL)
4647168515Sgshapiro		LDAPDefaults = (SM_LDAP_STRUCT *) xalloc(sizeof(*LDAPDefaults));
464890792Sgshapiro	sm_ldap_clear(LDAPDefaults);
464964562Sgshapiro
4650168515Sgshapiro	memset(&map, '\0', sizeof(map));
465173188Sgshapiro
465273188Sgshapiro	/* look up the class */
465373188Sgshapiro	class = stab("ldap", ST_MAPCLASS, ST_FIND);
465473188Sgshapiro	if (class == NULL)
465573188Sgshapiro	{
465673188Sgshapiro		syserr("readcf: LDAPDefaultSpec: class ldap not available");
465773188Sgshapiro		return;
465873188Sgshapiro	}
465973188Sgshapiro	map.map_class = &class->s_mapclass;
466064562Sgshapiro	map.map_db1 = (ARBPTR_T) LDAPDefaults;
466173188Sgshapiro	map.map_mname = "O LDAPDefaultSpec";
466264562Sgshapiro
466364562Sgshapiro	(void) ldapmap_parseargs(&map, spec);
466464562Sgshapiro
466564562Sgshapiro	/* These should never be set in LDAPDefaults */
466664562Sgshapiro	if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) ||
466764562Sgshapiro	    map.map_spacesub != SpaceSub ||
466864562Sgshapiro	    map.map_app != NULL ||
466964562Sgshapiro	    map.map_tapp != NULL)
467064562Sgshapiro	{
467164562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
467290792Sgshapiro		SM_FREE_CLR(map.map_app);
467390792Sgshapiro		SM_FREE_CLR(map.map_tapp);
467464562Sgshapiro	}
467564562Sgshapiro
467664562Sgshapiro	if (LDAPDefaults->ldap_filter != NULL)
467764562Sgshapiro	{
467864562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
467994334Sgshapiro
468064562Sgshapiro		/* don't free, it isn't malloc'ed in parseargs */
468164562Sgshapiro		LDAPDefaults->ldap_filter = NULL;
468264562Sgshapiro	}
468364562Sgshapiro
468464562Sgshapiro	if (LDAPDefaults->ldap_attr[0] != NULL)
468564562Sgshapiro	{
468664562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes");
468764562Sgshapiro		/* don't free, they aren't malloc'ed in parseargs */
468864562Sgshapiro		LDAPDefaults->ldap_attr[0] = NULL;
468964562Sgshapiro	}
469064562Sgshapiro}
469164562Sgshapiro#endif /* LDAPMAP */
469290792Sgshapiro/*
469364562Sgshapiro**  PH map
469464562Sgshapiro*/
469564562Sgshapiro
469690792Sgshapiro#if PH_MAP
469764562Sgshapiro
469864562Sgshapiro/*
469964562Sgshapiro**  Support for the CCSO Nameserver (ph/qi).
470064562Sgshapiro**  This code is intended to replace the so-called "ph mailer".
4701168515Sgshapiro**  Contributed by Mark D. Roth.  Contact him for support.
470264562Sgshapiro*/
470364562Sgshapiro
470490792Sgshapiro/* what version of the ph map code we're running */
4705110560Sgshapirostatic char phmap_id[128];
470664562Sgshapiro
470790792Sgshapiro/* sendmail version for phmap id string */
470890792Sgshapiroextern const char Version[];
470990792Sgshapiro
4710132943Sgshapiro/* assume we're using nph-1.2.x if not specified */
4711110560Sgshapiro# ifndef NPH_VERSION
4712132943Sgshapiro#  define NPH_VERSION		10200
4713110560Sgshapiro# endif
4714110560Sgshapiro
4715110560Sgshapiro/* compatibility for versions older than nph-1.2.0 */
4716110560Sgshapiro# if NPH_VERSION < 10200
4717110560Sgshapiro#  define PH_OPEN_ROUNDROBIN	PH_ROUNDROBIN
4718110560Sgshapiro#  define PH_OPEN_DONTID	PH_DONTID
4719110560Sgshapiro#  define PH_CLOSE_FAST		PH_FASTCLOSE
4720110560Sgshapiro#  define PH_ERR_DATAERR	PH_DATAERR
4721110560Sgshapiro#  define PH_ERR_NOMATCH	PH_NOMATCH
4722110560Sgshapiro# endif /* NPH_VERSION < 10200 */
4723110560Sgshapiro
472464562Sgshapiro/*
472564562Sgshapiro**  PH_MAP_PARSEARGS -- parse ph map definition args.
472664562Sgshapiro*/
472764562Sgshapiro
472864562Sgshapirobool
472964562Sgshapiroph_map_parseargs(map, args)
473064562Sgshapiro	MAP *map;
473164562Sgshapiro	char *args;
473264562Sgshapiro{
473390792Sgshapiro	register bool done;
473490792Sgshapiro	register char *p = args;
473564562Sgshapiro	PH_MAP_STRUCT *pmap = NULL;
473664562Sgshapiro
473790792Sgshapiro	/* initialize version string */
4738168515Sgshapiro	(void) sm_snprintf(phmap_id, sizeof(phmap_id),
473990792Sgshapiro			   "sendmail-%s phmap-20010529 libphclient-%s",
474090792Sgshapiro			   Version, libphclient_version);
474190792Sgshapiro
4742168515Sgshapiro	pmap = (PH_MAP_STRUCT *) xalloc(sizeof(*pmap));
474364562Sgshapiro
474464562Sgshapiro	/* defaults */
474564562Sgshapiro	pmap->ph_servers = NULL;
474664562Sgshapiro	pmap->ph_field_list = NULL;
474790792Sgshapiro	pmap->ph = NULL;
474864562Sgshapiro	pmap->ph_timeout = 0;
474990792Sgshapiro	pmap->ph_fastclose = 0;
475064562Sgshapiro
475164562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
475264562Sgshapiro	for (;;)
475364562Sgshapiro	{
475464562Sgshapiro		while (isascii(*p) && isspace(*p))
475564562Sgshapiro			p++;
475664562Sgshapiro		if (*p != '-')
475764562Sgshapiro			break;
475864562Sgshapiro		switch (*++p)
475964562Sgshapiro		{
476064562Sgshapiro		  case 'N':
476164562Sgshapiro			map->map_mflags |= MF_INCLNULL;
476264562Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
476364562Sgshapiro			break;
476464562Sgshapiro
476564562Sgshapiro		  case 'O':
476664562Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
476764562Sgshapiro			break;
476864562Sgshapiro
476964562Sgshapiro		  case 'o':
477064562Sgshapiro			map->map_mflags |= MF_OPTIONAL;
477164562Sgshapiro			break;
477264562Sgshapiro
477364562Sgshapiro		  case 'f':
477464562Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
477564562Sgshapiro			break;
477664562Sgshapiro
477764562Sgshapiro		  case 'm':
477864562Sgshapiro			map->map_mflags |= MF_MATCHONLY;
477964562Sgshapiro			break;
478064562Sgshapiro
478164562Sgshapiro		  case 'A':
478264562Sgshapiro			map->map_mflags |= MF_APPEND;
478364562Sgshapiro			break;
478464562Sgshapiro
478564562Sgshapiro		  case 'q':
478664562Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
478764562Sgshapiro			break;
478864562Sgshapiro
478964562Sgshapiro		  case 't':
479064562Sgshapiro			map->map_mflags |= MF_NODEFER;
479164562Sgshapiro			break;
479264562Sgshapiro
479364562Sgshapiro		  case 'a':
479464562Sgshapiro			map->map_app = ++p;
479564562Sgshapiro			break;
479664562Sgshapiro
479764562Sgshapiro		  case 'T':
479864562Sgshapiro			map->map_tapp = ++p;
479964562Sgshapiro			break;
480064562Sgshapiro
480164562Sgshapiro		  case 'l':
480264562Sgshapiro			while (isascii(*++p) && isspace(*p))
480364562Sgshapiro				continue;
480464562Sgshapiro			pmap->ph_timeout = atoi(p);
480564562Sgshapiro			break;
480664562Sgshapiro
480764562Sgshapiro		  case 'S':
480864562Sgshapiro			map->map_spacesub = *++p;
480964562Sgshapiro			break;
481064562Sgshapiro
481164562Sgshapiro		  case 'D':
481264562Sgshapiro			map->map_mflags |= MF_DEFER;
481364562Sgshapiro			break;
481464562Sgshapiro
481564562Sgshapiro		  case 'h':		/* PH server list */
481664562Sgshapiro			while (isascii(*++p) && isspace(*p))
481764562Sgshapiro				continue;
481864562Sgshapiro			pmap->ph_servers = p;
481964562Sgshapiro			break;
482064562Sgshapiro
482190792Sgshapiro		  case 'k':		/* fields to search for */
482264562Sgshapiro			while (isascii(*++p) && isspace(*p))
482364562Sgshapiro				continue;
482464562Sgshapiro			pmap->ph_field_list = p;
482564562Sgshapiro			break;
482664562Sgshapiro
482764562Sgshapiro		  default:
482890792Sgshapiro			syserr("ph_map_parseargs: unknown option -%c", *p);
482964562Sgshapiro		}
483064562Sgshapiro
483164562Sgshapiro		/* try to account for quoted strings */
483264562Sgshapiro		done = isascii(*p) && isspace(*p);
483364562Sgshapiro		while (*p != '\0' && !done)
483464562Sgshapiro		{
483564562Sgshapiro			if (*p == '"')
483664562Sgshapiro			{
483764562Sgshapiro				while (*++p != '"' && *p != '\0')
483864562Sgshapiro					continue;
483964562Sgshapiro				if (*p != '\0')
484064562Sgshapiro					p++;
484164562Sgshapiro			}
484264562Sgshapiro			else
484364562Sgshapiro				p++;
484464562Sgshapiro			done = isascii(*p) && isspace(*p);
484564562Sgshapiro		}
484664562Sgshapiro
484764562Sgshapiro		if (*p != '\0')
484864562Sgshapiro			*p++ = '\0';
484964562Sgshapiro	}
485064562Sgshapiro
485164562Sgshapiro	if (map->map_app != NULL)
485264562Sgshapiro		map->map_app = newstr(ph_map_dequote(map->map_app));
485364562Sgshapiro	if (map->map_tapp != NULL)
485464562Sgshapiro		map->map_tapp = newstr(ph_map_dequote(map->map_tapp));
485564562Sgshapiro
485664562Sgshapiro	if (pmap->ph_field_list != NULL)
485764562Sgshapiro		pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
485864562Sgshapiro
485964562Sgshapiro	if (pmap->ph_servers != NULL)
486064562Sgshapiro		pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
486164562Sgshapiro	else
486264562Sgshapiro	{
486364562Sgshapiro		syserr("ph_map_parseargs: -h flag is required");
486490792Sgshapiro		return false;
486564562Sgshapiro	}
486664562Sgshapiro
486764562Sgshapiro	map->map_db1 = (ARBPTR_T) pmap;
486890792Sgshapiro	return true;
486964562Sgshapiro}
487064562Sgshapiro
487164562Sgshapiro/*
487264562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
487364562Sgshapiro*/
487464562Sgshapiro
487590792Sgshapirovoid
487690792Sgshapiroph_map_close(map)
487764562Sgshapiro	MAP *map;
487864562Sgshapiro{
487964562Sgshapiro	PH_MAP_STRUCT *pmap;
488064562Sgshapiro
488164562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
488290792Sgshapiro	if (tTd(38, 9))
488394334Sgshapiro		sm_dprintf("ph_map_close(%s): pmap->ph_fastclose=%d\n",
488490792Sgshapiro			   map->map_mname, pmap->ph_fastclose);
488564562Sgshapiro
488690792Sgshapiro
488790792Sgshapiro	if (pmap->ph != NULL)
488864562Sgshapiro	{
488990792Sgshapiro		ph_set_sendhook(pmap->ph, NULL);
489090792Sgshapiro		ph_set_recvhook(pmap->ph, NULL);
489190792Sgshapiro		ph_close(pmap->ph, pmap->ph_fastclose);
489264562Sgshapiro	}
489390792Sgshapiro
489464562Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
489564562Sgshapiro}
489664562Sgshapiro
489764562Sgshapirostatic jmp_buf  PHTimeout;
489864562Sgshapiro
489964562Sgshapiro/* ARGSUSED */
490064562Sgshapirostatic void
490190792Sgshapiroph_timeout(unused)
490290792Sgshapiro	int unused;
490364562Sgshapiro{
490477349Sgshapiro	/*
490577349Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
490677349Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
490777349Sgshapiro	**	DOING.
490877349Sgshapiro	*/
490977349Sgshapiro
491077349Sgshapiro	errno = ETIMEDOUT;
491164562Sgshapiro	longjmp(PHTimeout, 1);
491264562Sgshapiro}
491364562Sgshapiro
491490792Sgshapirostatic void
4915110560Sgshapiro#if NPH_VERSION >= 10200
4916110560Sgshapiroph_map_send_debug(appdata, text)
4917110560Sgshapiro	void *appdata;
4918110560Sgshapiro#else
491990792Sgshapiroph_map_send_debug(text)
4920110560Sgshapiro#endif
492190792Sgshapiro	char *text;
492264562Sgshapiro{
492390792Sgshapiro	if (LogLevel > 9)
492490792Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
492590792Sgshapiro			  "ph_map_send_debug: ==> %s", text);
492690792Sgshapiro	if (tTd(38, 20))
492790792Sgshapiro		sm_dprintf("ph_map_send_debug: ==> %s\n", text);
492890792Sgshapiro}
492964562Sgshapiro
493090792Sgshapirostatic void
4931110560Sgshapiro#if NPH_VERSION >= 10200
4932110560Sgshapiroph_map_recv_debug(appdata, text)
4933110560Sgshapiro	void *appdata;
4934110560Sgshapiro#else
493590792Sgshapiroph_map_recv_debug(text)
4936110560Sgshapiro#endif
493790792Sgshapiro	char *text;
493890792Sgshapiro{
493990792Sgshapiro	if (LogLevel > 10)
494090792Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
494190792Sgshapiro			  "ph_map_recv_debug: <== %s", text);
494290792Sgshapiro	if (tTd(38, 21))
494390792Sgshapiro		sm_dprintf("ph_map_recv_debug: <== %s\n", text);
494464562Sgshapiro}
494564562Sgshapiro
494690792Sgshapiro/*
494764562Sgshapiro**  PH_MAP_OPEN -- sub for opening PH map
494864562Sgshapiro*/
494964562Sgshapirobool
495064562Sgshapiroph_map_open(map, mode)
495164562Sgshapiro	MAP *map;
495264562Sgshapiro	int mode;
495364562Sgshapiro{
495490792Sgshapiro	PH_MAP_STRUCT *pmap;
495590792Sgshapiro	register SM_EVENT *ev = NULL;
495664562Sgshapiro	int save_errno = 0;
495790792Sgshapiro	char *hostlist, *host;
495864562Sgshapiro
495964562Sgshapiro	if (tTd(38, 2))
496090792Sgshapiro		sm_dprintf("ph_map_open(%s)\n", map->map_mname);
496164562Sgshapiro
496264562Sgshapiro	mode &= O_ACCMODE;
496364562Sgshapiro	if (mode != O_RDONLY)
496464562Sgshapiro	{
496564562Sgshapiro		/* issue a pseudo-error message */
496690792Sgshapiro		errno = SM_EMAPCANTWRITE;
496790792Sgshapiro		return false;
496864562Sgshapiro	}
496964562Sgshapiro
497066494Sgshapiro	if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER &&
497166494Sgshapiro	    bitset(MF_DEFER, map->map_mflags))
497266494Sgshapiro	{
497366494Sgshapiro		if (tTd(9, 1))
497490792Sgshapiro			sm_dprintf("ph_map_open(%s) => DEFERRED\n",
497590792Sgshapiro				   map->map_mname);
497666494Sgshapiro
497766494Sgshapiro		/*
497890792Sgshapiro		**  Unset MF_DEFER here so that map_lookup() returns
497990792Sgshapiro		**  a temporary failure using the bogus map and
498090792Sgshapiro		**  map->map_tapp instead of the default permanent error.
498166494Sgshapiro		*/
498266494Sgshapiro
498366494Sgshapiro		map->map_mflags &= ~MF_DEFER;
498490792Sgshapiro		return false;
498566494Sgshapiro	}
498666494Sgshapiro
498764562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
498890792Sgshapiro	pmap->ph_fastclose = 0;		/* refresh field for reopen */
498964562Sgshapiro
499090792Sgshapiro	/* try each host in the list */
499164562Sgshapiro	hostlist = newstr(pmap->ph_servers);
499290792Sgshapiro	for (host = strtok(hostlist, " ");
499390792Sgshapiro	     host != NULL;
499490792Sgshapiro	     host = strtok(NULL, " "))
499564562Sgshapiro	{
499690792Sgshapiro		/* set timeout */
499764562Sgshapiro		if (pmap->ph_timeout != 0)
499864562Sgshapiro		{
499964562Sgshapiro			if (setjmp(PHTimeout) != 0)
500064562Sgshapiro			{
500164562Sgshapiro				ev = NULL;
500264562Sgshapiro				if (LogLevel > 1)
500364562Sgshapiro					sm_syslog(LOG_NOTICE, CurEnv->e_id,
500464562Sgshapiro						  "timeout connecting to PH server %.100s",
500590792Sgshapiro						  host);
500664562Sgshapiro				errno = ETIMEDOUT;
500764562Sgshapiro				goto ph_map_open_abort;
500864562Sgshapiro			}
500990792Sgshapiro			ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
501064562Sgshapiro		}
501190792Sgshapiro
501290792Sgshapiro		/* open connection to server */
5013110560Sgshapiro		if (ph_open(&(pmap->ph), host,
5014110560Sgshapiro			    PH_OPEN_ROUNDROBIN|PH_OPEN_DONTID,
5015110560Sgshapiro			    ph_map_send_debug, ph_map_recv_debug
5016110560Sgshapiro#if NPH_VERSION >= 10200
5017110560Sgshapiro			    , NULL
5018110560Sgshapiro#endif
5019110560Sgshapiro			    ) == 0
5020110560Sgshapiro		    && ph_id(pmap->ph, phmap_id) == 0)
502164562Sgshapiro		{
502264562Sgshapiro			if (ev != NULL)
502390792Sgshapiro				sm_clrevent(ev);
502490792Sgshapiro			sm_free(hostlist); /* XXX */
502590792Sgshapiro			return true;
502664562Sgshapiro		}
502790792Sgshapiro
502864562Sgshapiro  ph_map_open_abort:
502990792Sgshapiro		save_errno = errno;
503064562Sgshapiro		if (ev != NULL)
503190792Sgshapiro			sm_clrevent(ev);
5032110560Sgshapiro		pmap->ph_fastclose = PH_CLOSE_FAST;
503390792Sgshapiro		ph_map_close(map);
503490792Sgshapiro		errno = save_errno;
503590792Sgshapiro	}
503664562Sgshapiro
503766494Sgshapiro	if (bitset(MF_NODEFER, map->map_mflags))
503864562Sgshapiro	{
503966494Sgshapiro		if (errno == 0)
504064562Sgshapiro			errno = EAGAIN;
504166494Sgshapiro		syserr("ph_map_open: %s: cannot connect to PH server",
504266494Sgshapiro		       map->map_mname);
504364562Sgshapiro	}
504466494Sgshapiro	else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1)
504564562Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
504666494Sgshapiro			  "ph_map_open: %s: cannot connect to PH server",
504766494Sgshapiro			  map->map_mname);
504890792Sgshapiro	sm_free(hostlist); /* XXX */
504990792Sgshapiro	return false;
505064562Sgshapiro}
505164562Sgshapiro
505264562Sgshapiro/*
505364562Sgshapiro**  PH_MAP_LOOKUP -- look up key from ph server
505464562Sgshapiro*/
505564562Sgshapiro
505664562Sgshapirochar *
505764562Sgshapiroph_map_lookup(map, key, args, pstat)
505864562Sgshapiro	MAP *map;
505964562Sgshapiro	char *key;
506064562Sgshapiro	char **args;
506164562Sgshapiro	int *pstat;
506264562Sgshapiro{
506390792Sgshapiro	int i, save_errno = 0;
506490792Sgshapiro	register SM_EVENT *ev = NULL;
506564562Sgshapiro	PH_MAP_STRUCT *pmap;
506690792Sgshapiro	char *value = NULL;
506764562Sgshapiro
506864562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
506964562Sgshapiro
507064562Sgshapiro	*pstat = EX_OK;
507164562Sgshapiro
507290792Sgshapiro	/* set timeout */
507364562Sgshapiro	if (pmap->ph_timeout != 0)
507464562Sgshapiro	{
507564562Sgshapiro		if (setjmp(PHTimeout) != 0)
507664562Sgshapiro		{
507764562Sgshapiro			ev = NULL;
507864562Sgshapiro			if (LogLevel > 1)
507964562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
508064562Sgshapiro					  "timeout during PH lookup of %.100s",
508164562Sgshapiro					  key);
508264562Sgshapiro			errno = ETIMEDOUT;
508364562Sgshapiro			*pstat = EX_TEMPFAIL;
508464562Sgshapiro			goto ph_map_lookup_abort;
508564562Sgshapiro		}
508690792Sgshapiro		ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
508764562Sgshapiro	}
508864562Sgshapiro
508990792Sgshapiro	/* perform lookup */
509090792Sgshapiro	i = ph_email_resolve(pmap->ph, key, pmap->ph_field_list, &value);
509190792Sgshapiro	if (i == -1)
509290792Sgshapiro		*pstat = EX_TEMPFAIL;
5093110560Sgshapiro	else if (i == PH_ERR_NOMATCH || i == PH_ERR_DATAERR)
509490792Sgshapiro		*pstat = EX_UNAVAILABLE;
509564562Sgshapiro
509664562Sgshapiro  ph_map_lookup_abort:
509764562Sgshapiro	if (ev != NULL)
509890792Sgshapiro		sm_clrevent(ev);
509964562Sgshapiro
510064562Sgshapiro	/*
510190792Sgshapiro	**  Close the connection if the timer popped
510264562Sgshapiro	**  or we got a temporary PH error
510364562Sgshapiro	*/
510464562Sgshapiro
510564562Sgshapiro	if (*pstat == EX_TEMPFAIL)
510690792Sgshapiro	{
510790792Sgshapiro		save_errno = errno;
5108110560Sgshapiro		pmap->ph_fastclose = PH_CLOSE_FAST;
510990792Sgshapiro		ph_map_close(map);
511090792Sgshapiro		errno = save_errno;
511190792Sgshapiro	}
511264562Sgshapiro
511364562Sgshapiro	if (*pstat == EX_OK)
511464562Sgshapiro	{
511564562Sgshapiro		if (tTd(38,20))
511690792Sgshapiro			sm_dprintf("ph_map_lookup: %s => %s\n", key, value);
511764562Sgshapiro
511864562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
511990792Sgshapiro			return map_rewrite(map, key, strlen(key), NULL);
512064562Sgshapiro		else
512190792Sgshapiro			return map_rewrite(map, value, strlen(value), args);
512264562Sgshapiro	}
512364562Sgshapiro
512464562Sgshapiro	return NULL;
512564562Sgshapiro}
512664562Sgshapiro#endif /* PH_MAP */
5127168515Sgshapiro
512890792Sgshapiro/*
512942575Speter**  syslog map
513038032Speter*/
513138032Speter
513238032Speter#define map_prio	map_lockfd	/* overload field */
513338032Speter
513438032Speter/*
513542575Speter**  SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
513638032Speter*/
513738032Speter
513838032Speterbool
513938032Spetersyslog_map_parseargs(map, args)
514038032Speter	MAP *map;
514138032Speter	char *args;
514238032Speter{
514338032Speter	char *p = args;
514438032Speter	char *priority = NULL;
514538032Speter
514664562Sgshapiro	/* there is no check whether there is really an argument */
514764562Sgshapiro	while (*p != '\0')
514838032Speter	{
514938032Speter		while (isascii(*p) && isspace(*p))
515038032Speter			p++;
515138032Speter		if (*p != '-')
515238032Speter			break;
515364562Sgshapiro		++p;
515464562Sgshapiro		if (*p == 'D')
515564562Sgshapiro		{
515664562Sgshapiro			map->map_mflags |= MF_DEFER;
515764562Sgshapiro			++p;
515864562Sgshapiro		}
515964562Sgshapiro		else if (*p == 'S')
516064562Sgshapiro		{
516164562Sgshapiro			map->map_spacesub = *++p;
516264562Sgshapiro			if (*p != '\0')
516364562Sgshapiro				p++;
516464562Sgshapiro		}
516564562Sgshapiro		else if (*p == 'L')
516664562Sgshapiro		{
516764562Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p))
516864562Sgshapiro				continue;
516964562Sgshapiro			if (*p == '\0')
517064562Sgshapiro				break;
517164562Sgshapiro			priority = p;
517264562Sgshapiro			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
517364562Sgshapiro				p++;
517464562Sgshapiro			if (*p != '\0')
517564562Sgshapiro				*p++ = '\0';
517664562Sgshapiro		}
517764562Sgshapiro		else
517864562Sgshapiro		{
517964562Sgshapiro			syserr("Illegal option %c map syslog", *p);
518064562Sgshapiro			++p;
518164562Sgshapiro		}
518238032Speter	}
518338032Speter
518438032Speter	if (priority == NULL)
518538032Speter		map->map_prio = LOG_INFO;
518638032Speter	else
518738032Speter	{
518890792Sgshapiro		if (sm_strncasecmp("LOG_", priority, 4) == 0)
518938032Speter			priority += 4;
519038032Speter
519138032Speter#ifdef LOG_EMERG
519290792Sgshapiro		if (sm_strcasecmp("EMERG", priority) == 0)
519338032Speter			map->map_prio = LOG_EMERG;
519438032Speter		else
519564562Sgshapiro#endif /* LOG_EMERG */
519638032Speter#ifdef LOG_ALERT
519790792Sgshapiro		if (sm_strcasecmp("ALERT", priority) == 0)
519838032Speter			map->map_prio = LOG_ALERT;
519938032Speter		else
520064562Sgshapiro#endif /* LOG_ALERT */
520138032Speter#ifdef LOG_CRIT
520290792Sgshapiro		if (sm_strcasecmp("CRIT", priority) == 0)
520338032Speter			map->map_prio = LOG_CRIT;
520438032Speter		else
520564562Sgshapiro#endif /* LOG_CRIT */
520638032Speter#ifdef LOG_ERR
520790792Sgshapiro		if (sm_strcasecmp("ERR", priority) == 0)
520838032Speter			map->map_prio = LOG_ERR;
520938032Speter		else
521064562Sgshapiro#endif /* LOG_ERR */
521138032Speter#ifdef LOG_WARNING
521290792Sgshapiro		if (sm_strcasecmp("WARNING", priority) == 0)
521338032Speter			map->map_prio = LOG_WARNING;
521438032Speter		else
521564562Sgshapiro#endif /* LOG_WARNING */
521638032Speter#ifdef LOG_NOTICE
521790792Sgshapiro		if (sm_strcasecmp("NOTICE", priority) == 0)
521838032Speter			map->map_prio = LOG_NOTICE;
521938032Speter		else
522064562Sgshapiro#endif /* LOG_NOTICE */
522138032Speter#ifdef LOG_INFO
522290792Sgshapiro		if (sm_strcasecmp("INFO", priority) == 0)
522338032Speter			map->map_prio = LOG_INFO;
522438032Speter		else
522564562Sgshapiro#endif /* LOG_INFO */
522638032Speter#ifdef LOG_DEBUG
522790792Sgshapiro		if (sm_strcasecmp("DEBUG", priority) == 0)
522838032Speter			map->map_prio = LOG_DEBUG;
522938032Speter		else
523064562Sgshapiro#endif /* LOG_DEBUG */
523138032Speter		{
523290792Sgshapiro			syserr("syslog_map_parseargs: Unknown priority %s",
523338032Speter			       priority);
523490792Sgshapiro			return false;
523538032Speter		}
523638032Speter	}
523790792Sgshapiro	return true;
523838032Speter}
523938032Speter
524038032Speter/*
524142575Speter**  SYSLOG_MAP_LOOKUP -- rewrite and syslog message.  Always return empty string
524238032Speter*/
524338032Speter
524438032Speterchar *
524538032Spetersyslog_map_lookup(map, string, args, statp)
524638032Speter	MAP *map;
524738032Speter	char *string;
524838032Speter	char **args;
524938032Speter	int *statp;
525038032Speter{
525138032Speter	char *ptr = map_rewrite(map, string, strlen(string), args);
525238032Speter
525338032Speter	if (ptr != NULL)
525438032Speter	{
525538032Speter		if (tTd(38, 20))
525690792Sgshapiro			sm_dprintf("syslog_map_lookup(%s (priority %d): %s\n",
525764562Sgshapiro				map->map_mname, map->map_prio, ptr);
525838032Speter
525938032Speter		sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
526038032Speter	}
526138032Speter
526238032Speter	*statp = EX_OK;
526338032Speter	return "";
526438032Speter}
526538032Speter
5266168515Sgshapiro#if _FFR_DPRINTF_MAP
526790792Sgshapiro/*
5268168515Sgshapiro**  dprintf map
5269168515Sgshapiro*/
5270168515Sgshapiro
5271168515Sgshapiro#define map_dbg_level	map_lockfd	/* overload field */
5272168515Sgshapiro
5273168515Sgshapiro/*
5274168515Sgshapiro**  DPRINTF_MAP_PARSEARGS -- check for priority level to dprintf messages.
5275168515Sgshapiro*/
5276168515Sgshapiro
5277168515Sgshapirobool
5278168515Sgshapirodprintf_map_parseargs(map, args)
5279168515Sgshapiro	MAP *map;
5280168515Sgshapiro	char *args;
5281168515Sgshapiro{
5282168515Sgshapiro	char *p = args;
5283168515Sgshapiro	char *dbg_level = NULL;
5284168515Sgshapiro
5285168515Sgshapiro	/* there is no check whether there is really an argument */
5286168515Sgshapiro	while (*p != '\0')
5287168515Sgshapiro	{
5288168515Sgshapiro		while (isascii(*p) && isspace(*p))
5289168515Sgshapiro			p++;
5290168515Sgshapiro		if (*p != '-')
5291168515Sgshapiro			break;
5292168515Sgshapiro		++p;
5293168515Sgshapiro		if (*p == 'D')
5294168515Sgshapiro		{
5295168515Sgshapiro			map->map_mflags |= MF_DEFER;
5296168515Sgshapiro			++p;
5297168515Sgshapiro		}
5298168515Sgshapiro		else if (*p == 'S')
5299168515Sgshapiro		{
5300168515Sgshapiro			map->map_spacesub = *++p;
5301168515Sgshapiro			if (*p != '\0')
5302168515Sgshapiro				p++;
5303168515Sgshapiro		}
5304168515Sgshapiro		else if (*p == 'd')
5305168515Sgshapiro		{
5306168515Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p))
5307168515Sgshapiro				continue;
5308168515Sgshapiro			if (*p == '\0')
5309168515Sgshapiro				break;
5310168515Sgshapiro			dbg_level = p;
5311168515Sgshapiro			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
5312168515Sgshapiro				p++;
5313168515Sgshapiro			if (*p != '\0')
5314168515Sgshapiro				*p++ = '\0';
5315168515Sgshapiro		}
5316168515Sgshapiro		else
5317168515Sgshapiro		{
5318168515Sgshapiro			syserr("Illegal option %c map dprintf", *p);
5319168515Sgshapiro			++p;
5320168515Sgshapiro		}
5321168515Sgshapiro	}
5322168515Sgshapiro
5323168515Sgshapiro	if (dbg_level == NULL)
5324168515Sgshapiro		map->map_dbg_level = 0;
5325168515Sgshapiro	else
5326168515Sgshapiro	{
5327168515Sgshapiro		if (!(isascii(*dbg_level) && isdigit(*dbg_level)))
5328168515Sgshapiro		{
5329168515Sgshapiro			syserr("dprintf map \"%s\", file %s: -d should specify a number, not %s",
5330168515Sgshapiro				map->map_mname, map->map_file,
5331168515Sgshapiro				dbg_level);
5332168515Sgshapiro			return false;
5333168515Sgshapiro		}
5334168515Sgshapiro		map->map_dbg_level = atoi(dbg_level);
5335168515Sgshapiro	}
5336168515Sgshapiro	return true;
5337168515Sgshapiro}
5338168515Sgshapiro
5339168515Sgshapiro/*
5340168515Sgshapiro**  DPRINTF_MAP_LOOKUP -- rewrite and print message.  Always return empty string
5341168515Sgshapiro*/
5342168515Sgshapiro
5343168515Sgshapirochar *
5344168515Sgshapirodprintf_map_lookup(map, string, args, statp)
5345168515Sgshapiro	MAP *map;
5346168515Sgshapiro	char *string;
5347168515Sgshapiro	char **args;
5348168515Sgshapiro	int *statp;
5349168515Sgshapiro{
5350168515Sgshapiro	char *ptr = map_rewrite(map, string, strlen(string), args);
5351168515Sgshapiro
5352168515Sgshapiro	if (ptr != NULL && tTd(85, map->map_dbg_level))
5353168515Sgshapiro		sm_dprintf("%s\n", ptr);
5354168515Sgshapiro	*statp = EX_OK;
5355168515Sgshapiro	return "";
5356168515Sgshapiro}
5357168515Sgshapiro#endif /* _FFR_DPRINTF_MAP */
5358168515Sgshapiro
5359168515Sgshapiro/*
536038032Speter**  HESIOD Modules
536138032Speter*/
536238032Speter
536390792Sgshapiro#if HESIOD
536438032Speter
536538032Speterbool
536638032Speterhes_map_open(map, mode)
536738032Speter	MAP *map;
536838032Speter	int mode;
536938032Speter{
537038032Speter	if (tTd(38, 2))
537190792Sgshapiro		sm_dprintf("hes_map_open(%s, %s, %d)\n",
537238032Speter			map->map_mname, map->map_file, mode);
537338032Speter
537438032Speter	if (mode != O_RDONLY)
537538032Speter	{
537638032Speter		/* issue a pseudo-error message */
537790792Sgshapiro		errno = SM_EMAPCANTWRITE;
537890792Sgshapiro		return false;
537938032Speter	}
538038032Speter
538164562Sgshapiro# ifdef HESIOD_INIT
538238032Speter	if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
538390792Sgshapiro		return true;
538438032Speter
538538032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
538694334Sgshapiro		syserr("451 4.3.5 cannot initialize Hesiod map (%s)",
538790792Sgshapiro			sm_errstring(errno));
538890792Sgshapiro	return false;
538964562Sgshapiro# else /* HESIOD_INIT */
539038032Speter	if (hes_error() == HES_ER_UNINIT)
539138032Speter		hes_init();
539238032Speter	switch (hes_error())
539338032Speter	{
539438032Speter	  case HES_ER_OK:
539538032Speter	  case HES_ER_NOTFOUND:
539690792Sgshapiro		return true;
539738032Speter	}
539838032Speter
539938032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
540094334Sgshapiro		syserr("451 4.3.5 cannot initialize Hesiod map (%d)", hes_error());
540138032Speter
540290792Sgshapiro	return false;
540364562Sgshapiro# endif /* HESIOD_INIT */
540438032Speter}
540538032Speter
540638032Speterchar *
540738032Speterhes_map_lookup(map, name, av, statp)
540838032Speter	MAP *map;
540938032Speter	char *name;
541038032Speter	char **av;
541138032Speter	int *statp;
541238032Speter{
541338032Speter	char **hp;
541438032Speter
541538032Speter	if (tTd(38, 20))
541690792Sgshapiro		sm_dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
541738032Speter
541838032Speter	if (name[0] == '\\')
541938032Speter	{
542038032Speter		char *np;
542138032Speter		int nl;
542277349Sgshapiro		int save_errno;
542338032Speter		char nbuf[MAXNAME];
542438032Speter
542538032Speter		nl = strlen(name);
5426168515Sgshapiro		if (nl < sizeof(nbuf) - 1)
542738032Speter			np = nbuf;
542838032Speter		else
542938032Speter			np = xalloc(strlen(name) + 2);
543038032Speter		np[0] = '\\';
5431168515Sgshapiro		(void) sm_strlcpy(&np[1], name, (sizeof(nbuf)) - 1);
543264562Sgshapiro# ifdef HESIOD_INIT
543338032Speter		hp = hesiod_resolve(HesiodContext, np, map->map_file);
543464562Sgshapiro# else /* HESIOD_INIT */
543538032Speter		hp = hes_resolve(np, map->map_file);
543664562Sgshapiro# endif /* HESIOD_INIT */
543777349Sgshapiro		save_errno = errno;
543838032Speter		if (np != nbuf)
543990792Sgshapiro			sm_free(np); /* XXX */
544077349Sgshapiro		errno = save_errno;
544138032Speter	}
544238032Speter	else
544338032Speter	{
544464562Sgshapiro# ifdef HESIOD_INIT
544538032Speter		hp = hesiod_resolve(HesiodContext, name, map->map_file);
544664562Sgshapiro# else /* HESIOD_INIT */
544738032Speter		hp = hes_resolve(name, map->map_file);
544864562Sgshapiro# endif /* HESIOD_INIT */
544938032Speter	}
545064562Sgshapiro# ifdef HESIOD_INIT
545177349Sgshapiro	if (hp == NULL || *hp == NULL)
545238032Speter	{
545338032Speter		switch (errno)
545438032Speter		{
545538032Speter		  case ENOENT:
545638032Speter			  *statp = EX_NOTFOUND;
545738032Speter			  break;
545838032Speter		  case ECONNREFUSED:
545938032Speter			  *statp = EX_TEMPFAIL;
546038032Speter			  break;
546190792Sgshapiro		  case EMSGSIZE:
546238032Speter		  case ENOMEM:
546338032Speter		  default:
546438032Speter			  *statp = EX_UNAVAILABLE;
546538032Speter			  break;
546638032Speter		}
546782017Sgshapiro		if (hp != NULL)
546882017Sgshapiro			hesiod_free_list(HesiodContext, hp);
546938032Speter		return NULL;
547038032Speter	}
547164562Sgshapiro# else /* HESIOD_INIT */
547238032Speter	if (hp == NULL || hp[0] == NULL)
547338032Speter	{
547438032Speter		switch (hes_error())
547538032Speter		{
547638032Speter		  case HES_ER_OK:
547738032Speter			*statp = EX_OK;
547838032Speter			break;
547938032Speter
548038032Speter		  case HES_ER_NOTFOUND:
548138032Speter			*statp = EX_NOTFOUND;
548238032Speter			break;
548338032Speter
548438032Speter		  case HES_ER_CONFIG:
548538032Speter			*statp = EX_UNAVAILABLE;
548638032Speter			break;
548738032Speter
548838032Speter		  case HES_ER_NET:
548938032Speter			*statp = EX_TEMPFAIL;
549038032Speter			break;
549138032Speter		}
549238032Speter		return NULL;
549338032Speter	}
549464562Sgshapiro# endif /* HESIOD_INIT */
549538032Speter
549638032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
549738032Speter		return map_rewrite(map, name, strlen(name), NULL);
549838032Speter	else
549938032Speter		return map_rewrite(map, hp[0], strlen(hp[0]), av);
550038032Speter}
550138032Speter
550290792Sgshapiro/*
550390792Sgshapiro**  HES_MAP_CLOSE -- free the Hesiod context
550490792Sgshapiro*/
550590792Sgshapiro
550690792Sgshapirovoid
550790792Sgshapirohes_map_close(map)
550890792Sgshapiro	MAP *map;
550990792Sgshapiro{
551090792Sgshapiro	if (tTd(38, 20))
551190792Sgshapiro		sm_dprintf("hes_map_close(%s)\n", map->map_file);
551290792Sgshapiro
551390792Sgshapiro# ifdef HESIOD_INIT
551490792Sgshapiro	/* Free the hesiod context */
551590792Sgshapiro	if (HesiodContext != NULL)
551690792Sgshapiro	{
551790792Sgshapiro		hesiod_end(HesiodContext);
551890792Sgshapiro		HesiodContext = NULL;
551990792Sgshapiro	}
552090792Sgshapiro# endif /* HESIOD_INIT */
552190792Sgshapiro}
552290792Sgshapiro
552364562Sgshapiro#endif /* HESIOD */
552490792Sgshapiro/*
552538032Speter**  NeXT NETINFO Modules
552638032Speter*/
552738032Speter
552838032Speter#if NETINFO
552938032Speter
553038032Speter# define NETINFO_DEFAULT_DIR		"/aliases"
553138032Speter# define NETINFO_DEFAULT_PROPERTY	"members"
553238032Speter
553338032Speter/*
553438032Speter**  NI_MAP_OPEN -- open NetInfo Aliases
553538032Speter*/
553638032Speter
553738032Speterbool
553838032Speterni_map_open(map, mode)
553938032Speter	MAP *map;
554038032Speter	int mode;
554138032Speter{
554238032Speter	if (tTd(38, 2))
554390792Sgshapiro		sm_dprintf("ni_map_open(%s, %s, %d)\n",
554438032Speter			map->map_mname, map->map_file, mode);
554538032Speter	mode &= O_ACCMODE;
554638032Speter
554738032Speter	if (*map->map_file == '\0')
554838032Speter		map->map_file = NETINFO_DEFAULT_DIR;
554938032Speter
555038032Speter	if (map->map_valcolnm == NULL)
555138032Speter		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
555238032Speter
555390792Sgshapiro	if (map->map_coldelim == '\0')
555490792Sgshapiro	{
555590792Sgshapiro		if (bitset(MF_ALIAS, map->map_mflags))
555690792Sgshapiro			map->map_coldelim = ',';
555790792Sgshapiro		else if (bitset(MF_FILECLASS, map->map_mflags))
555890792Sgshapiro			map->map_coldelim = ' ';
555990792Sgshapiro	}
556090792Sgshapiro	return true;
556138032Speter}
556238032Speter
556338032Speter
556438032Speter/*
556538032Speter**  NI_MAP_LOOKUP -- look up a datum in NetInfo
556638032Speter*/
556738032Speter
556838032Speterchar *
556938032Speterni_map_lookup(map, name, av, statp)
557038032Speter	MAP *map;
557138032Speter	char *name;
557238032Speter	char **av;
557338032Speter	int *statp;
557438032Speter{
557538032Speter	char *res;
557638032Speter	char *propval;
557738032Speter
557838032Speter	if (tTd(38, 20))
557990792Sgshapiro		sm_dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
558038032Speter
558138032Speter	propval = ni_propval(map->map_file, map->map_keycolnm, name,
558238032Speter			     map->map_valcolnm, map->map_coldelim);
558338032Speter
558438032Speter	if (propval == NULL)
558538032Speter		return NULL;
558638032Speter
558790792Sgshapiro	SM_TRY
558890792Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
558990792Sgshapiro			res = map_rewrite(map, name, strlen(name), NULL);
559090792Sgshapiro		else
559190792Sgshapiro			res = map_rewrite(map, propval, strlen(propval), av);
559290792Sgshapiro	SM_FINALLY
559390792Sgshapiro		sm_free(propval);
559490792Sgshapiro	SM_END_TRY
559538032Speter	return res;
559638032Speter}
559738032Speter
559838032Speter
559964562Sgshapirostatic bool
560038032Speterni_getcanonname(name, hbsize, statp)
560138032Speter	char *name;
560238032Speter	int hbsize;
560338032Speter	int *statp;
560438032Speter{
560538032Speter	char *vptr;
560638032Speter	char *ptr;
560738032Speter	char nbuf[MAXNAME + 1];
560838032Speter
560938032Speter	if (tTd(38, 20))
561090792Sgshapiro		sm_dprintf("ni_getcanonname(%s)\n", name);
561138032Speter
5612168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
561338032Speter	{
561438032Speter		*statp = EX_UNAVAILABLE;
561590792Sgshapiro		return false;
561638032Speter	}
561773188Sgshapiro	(void) shorten_hostname(nbuf);
561838032Speter
561938032Speter	/* we only accept single token search key */
562038032Speter	if (strchr(nbuf, '.'))
562138032Speter	{
562238032Speter		*statp = EX_NOHOST;
562390792Sgshapiro		return false;
562438032Speter	}
562538032Speter
562638032Speter	/* Do the search */
562738032Speter	vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
562838032Speter
562938032Speter	if (vptr == NULL)
563038032Speter	{
563138032Speter		*statp = EX_NOHOST;
563290792Sgshapiro		return false;
563338032Speter	}
563438032Speter
563538032Speter	/* Only want the first machine name */
563638032Speter	if ((ptr = strchr(vptr, '\n')) != NULL)
563738032Speter		*ptr = '\0';
563838032Speter
563990792Sgshapiro	if (sm_strlcpy(name, vptr, hbsize) >= hbsize)
564038032Speter	{
564177349Sgshapiro		sm_free(vptr);
564290792Sgshapiro		*statp = EX_UNAVAILABLE;
564390792Sgshapiro		return true;
564438032Speter	}
564577349Sgshapiro	sm_free(vptr);
564690792Sgshapiro	*statp = EX_OK;
564790792Sgshapiro	return false;
564838032Speter}
564990792Sgshapiro#endif /* NETINFO */
565038032Speter/*
565138032Speter**  TEXT (unindexed text file) Modules
565238032Speter**
565338032Speter**	This code donated by Sun Microsystems.
565438032Speter*/
565538032Speter
565638032Speter#define map_sff		map_lockfd	/* overload field */
565738032Speter
565838032Speter
565938032Speter/*
566038032Speter**  TEXT_MAP_OPEN -- open text table
566138032Speter*/
566238032Speter
566338032Speterbool
566438032Spetertext_map_open(map, mode)
566538032Speter	MAP *map;
566638032Speter	int mode;
566738032Speter{
566864562Sgshapiro	long sff;
566938032Speter	int i;
567038032Speter
567138032Speter	if (tTd(38, 2))
567290792Sgshapiro		sm_dprintf("text_map_open(%s, %s, %d)\n",
567338032Speter			map->map_mname, map->map_file, mode);
567438032Speter
567538032Speter	mode &= O_ACCMODE;
567638032Speter	if (mode != O_RDONLY)
567738032Speter	{
567838032Speter		errno = EPERM;
567990792Sgshapiro		return false;
568038032Speter	}
568138032Speter
568238032Speter	if (*map->map_file == '\0')
568338032Speter	{
568438032Speter		syserr("text map \"%s\": file name required",
568538032Speter			map->map_mname);
568690792Sgshapiro		return false;
568738032Speter	}
568838032Speter
568938032Speter	if (map->map_file[0] != '/')
569038032Speter	{
569138032Speter		syserr("text map \"%s\": file name must be fully qualified",
569238032Speter			map->map_mname);
569390792Sgshapiro		return false;
569438032Speter	}
569538032Speter
569638032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
569764562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
569838032Speter		sff |= SFF_NOWLINK;
569964562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
570038032Speter		sff |= SFF_SAFEDIRPATH;
570138032Speter	if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
570238032Speter			  sff, S_IRUSR, NULL)) != 0)
570338032Speter	{
570464562Sgshapiro		int save_errno = errno;
570564562Sgshapiro
570638032Speter		/* cannot open this map */
570738032Speter		if (tTd(38, 2))
570890792Sgshapiro			sm_dprintf("\tunsafe map file: %d\n", i);
570964562Sgshapiro		errno = save_errno;
571038032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
571138032Speter			syserr("text map \"%s\": unsafe map file %s",
571238032Speter				map->map_mname, map->map_file);
571390792Sgshapiro		return false;
571438032Speter	}
571538032Speter
571638032Speter	if (map->map_keycolnm == NULL)
571738032Speter		map->map_keycolno = 0;
571838032Speter	else
571938032Speter	{
572038032Speter		if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
572138032Speter		{
572238032Speter			syserr("text map \"%s\", file %s: -k should specify a number, not %s",
572338032Speter				map->map_mname, map->map_file,
572438032Speter				map->map_keycolnm);
572590792Sgshapiro			return false;
572638032Speter		}
572738032Speter		map->map_keycolno = atoi(map->map_keycolnm);
572838032Speter	}
572938032Speter
573038032Speter	if (map->map_valcolnm == NULL)
573138032Speter		map->map_valcolno = 0;
573238032Speter	else
573338032Speter	{
573438032Speter		if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
573538032Speter		{
573638032Speter			syserr("text map \"%s\", file %s: -v should specify a number, not %s",
573738032Speter					map->map_mname, map->map_file,
573838032Speter					map->map_valcolnm);
573990792Sgshapiro			return false;
574038032Speter		}
574138032Speter		map->map_valcolno = atoi(map->map_valcolnm);
574238032Speter	}
574338032Speter
574438032Speter	if (tTd(38, 2))
574538032Speter	{
574690792Sgshapiro		sm_dprintf("text_map_open(%s, %s): delimiter = ",
574738032Speter			map->map_mname, map->map_file);
574838032Speter		if (map->map_coldelim == '\0')
574990792Sgshapiro			sm_dprintf("(white space)\n");
575038032Speter		else
575190792Sgshapiro			sm_dprintf("%c\n", map->map_coldelim);
575238032Speter	}
575338032Speter
575438032Speter	map->map_sff = sff;
575590792Sgshapiro	return true;
575638032Speter}
575738032Speter
575838032Speter
575938032Speter/*
576038032Speter**  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
576138032Speter*/
576238032Speter
576338032Speterchar *
576438032Spetertext_map_lookup(map, name, av, statp)
576538032Speter	MAP *map;
576638032Speter	char *name;
576738032Speter	char **av;
576838032Speter	int *statp;
576938032Speter{
577038032Speter	char *vp;
577138032Speter	auto int vsize;
577238032Speter	int buflen;
577390792Sgshapiro	SM_FILE_T *f;
577438032Speter	char delim;
577538032Speter	int key_idx;
577638032Speter	bool found_it;
577764562Sgshapiro	long sff = map->map_sff;
577838032Speter	char search_key[MAXNAME + 1];
577938032Speter	char linebuf[MAXLINE];
578038032Speter	char buf[MAXNAME + 1];
578138032Speter
578290792Sgshapiro	found_it = false;
578338032Speter	if (tTd(38, 20))
578490792Sgshapiro		sm_dprintf("text_map_lookup(%s, %s)\n", map->map_mname,  name);
578538032Speter
578638032Speter	buflen = strlen(name);
5787168515Sgshapiro	if (buflen > sizeof(search_key) - 1)
5788168515Sgshapiro		buflen = sizeof(search_key) - 1;	/* XXX just cut if off? */
578964562Sgshapiro	memmove(search_key, name, buflen);
579038032Speter	search_key[buflen] = '\0';
579138032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
579238032Speter		makelower(search_key);
579338032Speter
579438032Speter	f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
579538032Speter	if (f == NULL)
579638032Speter	{
579738032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
579838032Speter		*statp = EX_UNAVAILABLE;
579938032Speter		return NULL;
580038032Speter	}
580138032Speter	key_idx = map->map_keycolno;
580238032Speter	delim = map->map_coldelim;
580398121Sgshapiro	while (sm_io_fgets(f, SM_TIME_DEFAULT,
5804168515Sgshapiro			   linebuf, sizeof(linebuf)) != NULL)
580538032Speter	{
580638032Speter		char *p;
580738032Speter
580838032Speter		/* skip comment line */
580938032Speter		if (linebuf[0] == '#')
581038032Speter			continue;
581138032Speter		p = strchr(linebuf, '\n');
581238032Speter		if (p != NULL)
581338032Speter			*p = '\0';
5814168515Sgshapiro		p = get_column(linebuf, key_idx, delim, buf, sizeof(buf));
581590792Sgshapiro		if (p != NULL && sm_strcasecmp(search_key, p) == 0)
581638032Speter		{
581790792Sgshapiro			found_it = true;
581838032Speter			break;
581938032Speter		}
582038032Speter	}
582190792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
582238032Speter	if (!found_it)
582338032Speter	{
582438032Speter		*statp = EX_NOTFOUND;
582538032Speter		return NULL;
582638032Speter	}
5827168515Sgshapiro	vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof(buf));
582842575Speter	if (vp == NULL)
582942575Speter	{
583042575Speter		*statp = EX_NOTFOUND;
583142575Speter		return NULL;
583242575Speter	}
583338032Speter	vsize = strlen(vp);
583438032Speter	*statp = EX_OK;
583538032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
583638032Speter		return map_rewrite(map, name, strlen(name), NULL);
583738032Speter	else
583838032Speter		return map_rewrite(map, vp, vsize, av);
583938032Speter}
584038032Speter
584138032Speter/*
584238032Speter**  TEXT_GETCANONNAME -- look up canonical name in hosts file
584338032Speter*/
584438032Speter
584564562Sgshapirostatic bool
584638032Spetertext_getcanonname(name, hbsize, statp)
584738032Speter	char *name;
584838032Speter	int hbsize;
584938032Speter	int *statp;
585038032Speter{
585138032Speter	bool found;
585273188Sgshapiro	char *dot;
585390792Sgshapiro	SM_FILE_T *f;
585438032Speter	char linebuf[MAXLINE];
585538032Speter	char cbuf[MAXNAME + 1];
585638032Speter	char nbuf[MAXNAME + 1];
585738032Speter
585838032Speter	if (tTd(38, 20))
585990792Sgshapiro		sm_dprintf("text_getcanonname(%s)\n", name);
586038032Speter
5861168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
586238032Speter	{
586338032Speter		*statp = EX_UNAVAILABLE;
586490792Sgshapiro		return false;
586538032Speter	}
586673188Sgshapiro	dot = shorten_hostname(nbuf);
586738032Speter
586890792Sgshapiro	f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, HostsFile, SM_IO_RDONLY,
586990792Sgshapiro		       NULL);
587038032Speter	if (f == NULL)
587138032Speter	{
587238032Speter		*statp = EX_UNAVAILABLE;
587390792Sgshapiro		return false;
587438032Speter	}
587590792Sgshapiro	found = false;
587690792Sgshapiro	while (!found &&
587798121Sgshapiro		sm_io_fgets(f, SM_TIME_DEFAULT,
5878168515Sgshapiro			    linebuf, sizeof(linebuf)) != NULL)
587938032Speter	{
588038032Speter		char *p = strpbrk(linebuf, "#\n");
588138032Speter
588238032Speter		if (p != NULL)
588338032Speter			*p = '\0';
588438032Speter		if (linebuf[0] != '\0')
588573188Sgshapiro			found = extract_canonname(nbuf, dot, linebuf,
5886168515Sgshapiro						  cbuf, sizeof(cbuf));
588738032Speter	}
588890792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
588938032Speter	if (!found)
589038032Speter	{
589138032Speter		*statp = EX_NOHOST;
589290792Sgshapiro		return false;
589338032Speter	}
589438032Speter
589590792Sgshapiro	if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
589638032Speter	{
589790792Sgshapiro		*statp = EX_UNAVAILABLE;
589890792Sgshapiro		return false;
589938032Speter	}
590090792Sgshapiro	*statp = EX_OK;
590190792Sgshapiro	return true;
590238032Speter}
590390792Sgshapiro/*
590438032Speter**  STAB (Symbol Table) Modules
590538032Speter*/
590638032Speter
590738032Speter
590838032Speter/*
590938032Speter**  STAB_MAP_LOOKUP -- look up alias in symbol table
591038032Speter*/
591138032Speter
591238032Speter/* ARGSUSED2 */
591338032Speterchar *
591438032Speterstab_map_lookup(map, name, av, pstat)
591538032Speter	register MAP *map;
591638032Speter	char *name;
591738032Speter	char **av;
591838032Speter	int *pstat;
591938032Speter{
592038032Speter	register STAB *s;
592138032Speter
592238032Speter	if (tTd(38, 20))
592390792Sgshapiro		sm_dprintf("stab_lookup(%s, %s)\n",
592438032Speter			map->map_mname, name);
592538032Speter
592638032Speter	s = stab(name, ST_ALIAS, ST_FIND);
5927147078Sgshapiro	if (s == NULL)
5928147078Sgshapiro		return NULL;
5929147078Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
5930147078Sgshapiro		return map_rewrite(map, name, strlen(name), NULL);
5931147078Sgshapiro	else
5932147078Sgshapiro		return map_rewrite(map, s->s_alias, strlen(s->s_alias), av);
593338032Speter}
593438032Speter
593538032Speter/*
593638032Speter**  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
593738032Speter*/
593838032Speter
593938032Spetervoid
594038032Speterstab_map_store(map, lhs, rhs)
594138032Speter	register MAP *map;
594238032Speter	char *lhs;
594338032Speter	char *rhs;
594438032Speter{
594538032Speter	register STAB *s;
594638032Speter
594738032Speter	s = stab(lhs, ST_ALIAS, ST_ENTER);
594838032Speter	s->s_alias = newstr(rhs);
594938032Speter}
595038032Speter
595138032Speter
595238032Speter/*
595338032Speter**  STAB_MAP_OPEN -- initialize (reads data file)
595438032Speter**
595538032Speter**	This is a wierd case -- it is only intended as a fallback for
595638032Speter**	aliases.  For this reason, opens for write (only during a
595738032Speter**	"newaliases") always fails, and opens for read open the
595838032Speter**	actual underlying text file instead of the database.
595938032Speter*/
596038032Speter
596138032Speterbool
596238032Speterstab_map_open(map, mode)
596338032Speter	register MAP *map;
596438032Speter	int mode;
596538032Speter{
596690792Sgshapiro	SM_FILE_T *af;
596764562Sgshapiro	long sff;
596838032Speter	struct stat st;
596938032Speter
597038032Speter	if (tTd(38, 2))
597190792Sgshapiro		sm_dprintf("stab_map_open(%s, %s, %d)\n",
597238032Speter			map->map_mname, map->map_file, mode);
597338032Speter
597438032Speter	mode &= O_ACCMODE;
597538032Speter	if (mode != O_RDONLY)
597638032Speter	{
597738032Speter		errno = EPERM;
597890792Sgshapiro		return false;
597938032Speter	}
598038032Speter
598138032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
598264562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
598338032Speter		sff |= SFF_NOWLINK;
598464562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
598538032Speter		sff |= SFF_SAFEDIRPATH;
598638032Speter	af = safefopen(map->map_file, O_RDONLY, 0444, sff);
598738032Speter	if (af == NULL)
598890792Sgshapiro		return false;
598990792Sgshapiro	readaliases(map, af, false, false);
599038032Speter
599190792Sgshapiro	if (fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &st) >= 0)
599238032Speter		map->map_mtime = st.st_mtime;
599390792Sgshapiro	(void) sm_io_close(af, SM_TIME_DEFAULT);
599438032Speter
599590792Sgshapiro	return true;
599638032Speter}
599790792Sgshapiro/*
599838032Speter**  Implicit Modules
599938032Speter**
600038032Speter**	Tries several types.  For back compatibility of aliases.
600138032Speter*/
600238032Speter
600338032Speter
600438032Speter/*
600538032Speter**  IMPL_MAP_LOOKUP -- lookup in best open database
600638032Speter*/
600738032Speter
600838032Speterchar *
600938032Speterimpl_map_lookup(map, name, av, pstat)
601038032Speter	MAP *map;
601138032Speter	char *name;
601238032Speter	char **av;
601338032Speter	int *pstat;
601438032Speter{
601538032Speter	if (tTd(38, 20))
601690792Sgshapiro		sm_dprintf("impl_map_lookup(%s, %s)\n",
601738032Speter			map->map_mname, name);
601838032Speter
601990792Sgshapiro#if NEWDB
602038032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
602138032Speter		return db_map_lookup(map, name, av, pstat);
602264562Sgshapiro#endif /* NEWDB */
602390792Sgshapiro#if NDBM
602438032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
602538032Speter		return ndbm_map_lookup(map, name, av, pstat);
602664562Sgshapiro#endif /* NDBM */
602738032Speter	return stab_map_lookup(map, name, av, pstat);
602838032Speter}
602938032Speter
603038032Speter/*
603138032Speter**  IMPL_MAP_STORE -- store in open databases
603238032Speter*/
603338032Speter
603438032Spetervoid
603538032Speterimpl_map_store(map, lhs, rhs)
603638032Speter	MAP *map;
603738032Speter	char *lhs;
603838032Speter	char *rhs;
603938032Speter{
604038032Speter	if (tTd(38, 12))
604190792Sgshapiro		sm_dprintf("impl_map_store(%s, %s, %s)\n",
604238032Speter			map->map_mname, lhs, rhs);
604390792Sgshapiro#if NEWDB
604438032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
604538032Speter		db_map_store(map, lhs, rhs);
604664562Sgshapiro#endif /* NEWDB */
604790792Sgshapiro#if NDBM
604838032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
604938032Speter		ndbm_map_store(map, lhs, rhs);
605064562Sgshapiro#endif /* NDBM */
605138032Speter	stab_map_store(map, lhs, rhs);
605238032Speter}
605338032Speter
605438032Speter/*
605538032Speter**  IMPL_MAP_OPEN -- implicit database open
605638032Speter*/
605738032Speter
605838032Speterbool
605938032Speterimpl_map_open(map, mode)
606038032Speter	MAP *map;
606138032Speter	int mode;
606238032Speter{
606338032Speter	if (tTd(38, 2))
606490792Sgshapiro		sm_dprintf("impl_map_open(%s, %s, %d)\n",
606538032Speter			map->map_mname, map->map_file, mode);
606638032Speter
606738032Speter	mode &= O_ACCMODE;
606890792Sgshapiro#if NEWDB
606938032Speter	map->map_mflags |= MF_IMPL_HASH;
607038032Speter	if (hash_map_open(map, mode))
607138032Speter	{
607238032Speter# ifdef NDBM_YP_COMPAT
607338032Speter		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
607464562Sgshapiro# endif /* NDBM_YP_COMPAT */
607590792Sgshapiro			return true;
607638032Speter	}
607738032Speter	else
607838032Speter		map->map_mflags &= ~MF_IMPL_HASH;
607964562Sgshapiro#endif /* NEWDB */
608090792Sgshapiro#if NDBM
608138032Speter	map->map_mflags |= MF_IMPL_NDBM;
608238032Speter	if (ndbm_map_open(map, mode))
608338032Speter	{
608490792Sgshapiro		return true;
608538032Speter	}
608638032Speter	else
608738032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
608864562Sgshapiro#endif /* NDBM */
608938032Speter
609038032Speter#if defined(NEWDB) || defined(NDBM)
609138032Speter	if (Verbose)
609238032Speter		message("WARNING: cannot open alias database %s%s",
609338032Speter			map->map_file,
609438032Speter			mode == O_RDONLY ? "; reading text version" : "");
609564562Sgshapiro#else /* defined(NEWDB) || defined(NDBM) */
609638032Speter	if (mode != O_RDONLY)
609738032Speter		usrerr("Cannot rebuild aliases: no database format defined");
609864562Sgshapiro#endif /* defined(NEWDB) || defined(NDBM) */
609938032Speter
610038032Speter	if (mode == O_RDONLY)
610138032Speter		return stab_map_open(map, mode);
610238032Speter	else
610390792Sgshapiro		return false;
610438032Speter}
610538032Speter
610638032Speter
610738032Speter/*
610838032Speter**  IMPL_MAP_CLOSE -- close any open database(s)
610938032Speter*/
611038032Speter
611138032Spetervoid
611238032Speterimpl_map_close(map)
611338032Speter	MAP *map;
611438032Speter{
611538032Speter	if (tTd(38, 9))
611690792Sgshapiro		sm_dprintf("impl_map_close(%s, %s, %lx)\n",
611738032Speter			map->map_mname, map->map_file, map->map_mflags);
611890792Sgshapiro#if NEWDB
611938032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
612038032Speter	{
612138032Speter		db_map_close(map);
612238032Speter		map->map_mflags &= ~MF_IMPL_HASH;
612338032Speter	}
612464562Sgshapiro#endif /* NEWDB */
612538032Speter
612690792Sgshapiro#if NDBM
612738032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
612838032Speter	{
612938032Speter		ndbm_map_close(map);
613038032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
613138032Speter	}
613264562Sgshapiro#endif /* NDBM */
613338032Speter}
613490792Sgshapiro/*
613538032Speter**  User map class.
613638032Speter**
613738032Speter**	Provides access to the system password file.
613838032Speter*/
613938032Speter
614038032Speter/*
614138032Speter**  USER_MAP_OPEN -- open user map
614238032Speter**
614338032Speter**	Really just binds field names to field numbers.
614438032Speter*/
614538032Speter
614638032Speterbool
614738032Speteruser_map_open(map, mode)
614838032Speter	MAP *map;
614938032Speter	int mode;
615038032Speter{
615138032Speter	if (tTd(38, 2))
615290792Sgshapiro		sm_dprintf("user_map_open(%s, %d)\n",
615338032Speter			map->map_mname, mode);
615438032Speter
615538032Speter	mode &= O_ACCMODE;
615638032Speter	if (mode != O_RDONLY)
615738032Speter	{
615838032Speter		/* issue a pseudo-error message */
615990792Sgshapiro		errno = SM_EMAPCANTWRITE;
616090792Sgshapiro		return false;
616138032Speter	}
616238032Speter	if (map->map_valcolnm == NULL)
616364562Sgshapiro		/* EMPTY */
616438032Speter		/* nothing */ ;
616590792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "name") == 0)
616638032Speter		map->map_valcolno = 1;
616790792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "passwd") == 0)
616838032Speter		map->map_valcolno = 2;
616990792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "uid") == 0)
617038032Speter		map->map_valcolno = 3;
617190792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "gid") == 0)
617238032Speter		map->map_valcolno = 4;
617390792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "gecos") == 0)
617438032Speter		map->map_valcolno = 5;
617590792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "dir") == 0)
617638032Speter		map->map_valcolno = 6;
617790792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "shell") == 0)
617838032Speter		map->map_valcolno = 7;
617938032Speter	else
618038032Speter	{
618138032Speter		syserr("User map %s: unknown column name %s",
618238032Speter			map->map_mname, map->map_valcolnm);
618390792Sgshapiro		return false;
618438032Speter	}
618590792Sgshapiro	return true;
618638032Speter}
618738032Speter
618838032Speter
618938032Speter/*
619038032Speter**  USER_MAP_LOOKUP -- look up a user in the passwd file.
619138032Speter*/
619238032Speter
619338032Speter/* ARGSUSED3 */
619438032Speterchar *
619538032Speteruser_map_lookup(map, key, av, statp)
619638032Speter	MAP *map;
619738032Speter	char *key;
619838032Speter	char **av;
619938032Speter	int *statp;
620038032Speter{
620138032Speter	auto bool fuzzy;
620290792Sgshapiro	SM_MBDB_T user;
620338032Speter
620438032Speter	if (tTd(38, 20))
620590792Sgshapiro		sm_dprintf("user_map_lookup(%s, %s)\n",
620638032Speter			map->map_mname, key);
620738032Speter
620890792Sgshapiro	*statp = finduser(key, &fuzzy, &user);
620990792Sgshapiro	if (*statp != EX_OK)
621038032Speter		return NULL;
621138032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
621238032Speter		return map_rewrite(map, key, strlen(key), NULL);
621338032Speter	else
621438032Speter	{
621538032Speter		char *rwval = NULL;
621638032Speter		char buf[30];
621738032Speter
621838032Speter		switch (map->map_valcolno)
621938032Speter		{
622038032Speter		  case 0:
622138032Speter		  case 1:
622290792Sgshapiro			rwval = user.mbdb_name;
622338032Speter			break;
622438032Speter
622538032Speter		  case 2:
622690792Sgshapiro			rwval = "x";	/* passwd no longer supported */
622738032Speter			break;
622838032Speter
622938032Speter		  case 3:
6230168515Sgshapiro			(void) sm_snprintf(buf, sizeof(buf), "%d",
623190792Sgshapiro					   (int) user.mbdb_uid);
623238032Speter			rwval = buf;
623338032Speter			break;
623438032Speter
623538032Speter		  case 4:
6236168515Sgshapiro			(void) sm_snprintf(buf, sizeof(buf), "%d",
623790792Sgshapiro					   (int) user.mbdb_gid);
623838032Speter			rwval = buf;
623938032Speter			break;
624038032Speter
624138032Speter		  case 5:
624290792Sgshapiro			rwval = user.mbdb_fullname;
624338032Speter			break;
624438032Speter
624538032Speter		  case 6:
624690792Sgshapiro			rwval = user.mbdb_homedir;
624738032Speter			break;
624838032Speter
624938032Speter		  case 7:
625090792Sgshapiro			rwval = user.mbdb_shell;
625138032Speter			break;
6252159609Sgshapiro		  default:
6253159609Sgshapiro			syserr("user_map %s: bogus field %d",
6254159609Sgshapiro				map->map_mname, map->map_valcolno);
6255159609Sgshapiro			return NULL;
625638032Speter		}
625738032Speter		return map_rewrite(map, rwval, strlen(rwval), av);
625838032Speter	}
625938032Speter}
626090792Sgshapiro/*
626138032Speter**  Program map type.
626238032Speter**
626338032Speter**	This provides access to arbitrary programs.  It should be used
626438032Speter**	only very sparingly, since there is no way to bound the cost
626538032Speter**	of invoking an arbitrary program.
626638032Speter*/
626738032Speter
626838032Speterchar *
626938032Speterprog_map_lookup(map, name, av, statp)
627038032Speter	MAP *map;
627138032Speter	char *name;
627238032Speter	char **av;
627338032Speter	int *statp;
627438032Speter{
627538032Speter	int i;
627664562Sgshapiro	int save_errno;
627738032Speter	int fd;
627864562Sgshapiro	int status;
627938032Speter	auto pid_t pid;
628064562Sgshapiro	register char *p;
628138032Speter	char *rval;
628238032Speter	char *argv[MAXPV + 1];
628338032Speter	char buf[MAXLINE];
628438032Speter
628538032Speter	if (tTd(38, 20))
628690792Sgshapiro		sm_dprintf("prog_map_lookup(%s, %s) %s\n",
628738032Speter			map->map_mname, name, map->map_file);
628838032Speter
628938032Speter	i = 0;
629038032Speter	argv[i++] = map->map_file;
629138032Speter	if (map->map_rebuild != NULL)
629238032Speter	{
6293168515Sgshapiro		(void) sm_strlcpy(buf, map->map_rebuild, sizeof(buf));
629438032Speter		for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
629538032Speter		{
629638032Speter			if (i >= MAXPV - 1)
629738032Speter				break;
629838032Speter			argv[i++] = p;
629938032Speter		}
630038032Speter	}
630138032Speter	argv[i++] = name;
630238032Speter	argv[i] = NULL;
630338032Speter	if (tTd(38, 21))
630438032Speter	{
630590792Sgshapiro		sm_dprintf("prog_open:");
630638032Speter		for (i = 0; argv[i] != NULL; i++)
630790792Sgshapiro			sm_dprintf(" %s", argv[i]);
630890792Sgshapiro		sm_dprintf("\n");
630938032Speter	}
631090792Sgshapiro	(void) sm_blocksignal(SIGCHLD);
631138032Speter	pid = prog_open(argv, &fd, CurEnv);
631238032Speter	if (pid < 0)
631338032Speter	{
631438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
631538032Speter			syserr("prog_map_lookup(%s) failed (%s) -- closing",
631690792Sgshapiro			       map->map_mname, sm_errstring(errno));
631738032Speter		else if (tTd(38, 9))
631890792Sgshapiro			sm_dprintf("prog_map_lookup(%s) failed (%s) -- closing",
631990792Sgshapiro				   map->map_mname, sm_errstring(errno));
632038032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
632138032Speter		*statp = EX_OSFILE;
632238032Speter		return NULL;
632338032Speter	}
6324168515Sgshapiro	i = read(fd, buf, sizeof(buf) - 1);
632538032Speter	if (i < 0)
632638032Speter	{
632790792Sgshapiro		syserr("prog_map_lookup(%s): read error %s",
632890792Sgshapiro		       map->map_mname, sm_errstring(errno));
632938032Speter		rval = NULL;
633038032Speter	}
633138032Speter	else if (i == 0)
633238032Speter	{
633338032Speter		if (tTd(38, 20))
633490792Sgshapiro			sm_dprintf("prog_map_lookup(%s): empty answer\n",
633590792Sgshapiro				   map->map_mname);
633638032Speter		rval = NULL;
633738032Speter	}
633838032Speter	else
633938032Speter	{
634038032Speter		buf[i] = '\0';
634138032Speter		p = strchr(buf, '\n');
634238032Speter		if (p != NULL)
634338032Speter			*p = '\0';
634438032Speter
634538032Speter		/* collect the return value */
634638032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
634738032Speter			rval = map_rewrite(map, name, strlen(name), NULL);
634838032Speter		else
634977349Sgshapiro			rval = map_rewrite(map, buf, strlen(buf), av);
635038032Speter
635138032Speter		/* now flush any additional output */
6352168515Sgshapiro		while ((i = read(fd, buf, sizeof(buf))) > 0)
635338032Speter			continue;
635438032Speter	}
635538032Speter
635638032Speter	/* wait for the process to terminate */
635764562Sgshapiro	(void) close(fd);
635864562Sgshapiro	status = waitfor(pid);
635964562Sgshapiro	save_errno = errno;
636090792Sgshapiro	(void) sm_releasesignal(SIGCHLD);
636164562Sgshapiro	errno = save_errno;
636238032Speter
636364562Sgshapiro	if (status == -1)
636438032Speter	{
636590792Sgshapiro		syserr("prog_map_lookup(%s): wait error %s",
636690792Sgshapiro		       map->map_mname, sm_errstring(errno));
636738032Speter		*statp = EX_SOFTWARE;
636838032Speter		rval = NULL;
636938032Speter	}
637064562Sgshapiro	else if (WIFEXITED(status))
637138032Speter	{
637264562Sgshapiro		if ((*statp = WEXITSTATUS(status)) != EX_OK)
637338032Speter			rval = NULL;
637438032Speter	}
637538032Speter	else
637638032Speter	{
637738032Speter		syserr("prog_map_lookup(%s): child died on signal %d",
637890792Sgshapiro		       map->map_mname, status);
637938032Speter		*statp = EX_UNAVAILABLE;
638038032Speter		rval = NULL;
638138032Speter	}
638238032Speter	return rval;
638338032Speter}
638490792Sgshapiro/*
638538032Speter**  Sequenced map type.
638638032Speter**
638738032Speter**	Tries each map in order until something matches, much like
638838032Speter**	implicit.  Stores go to the first map in the list that can
638938032Speter**	support storing.
639038032Speter**
639138032Speter**	This is slightly unusual in that there are two interfaces.
639238032Speter**	The "sequence" interface lets you stack maps arbitrarily.
639338032Speter**	The "switch" interface builds a sequence map by looking
639438032Speter**	at a system-dependent configuration file such as
639538032Speter**	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
639638032Speter**
639738032Speter**	We don't need an explicit open, since all maps are
639890792Sgshapiro**	opened on demand.
639938032Speter*/
640038032Speter
640138032Speter/*
640238032Speter**  SEQ_MAP_PARSE -- Sequenced map parsing
640338032Speter*/
640438032Speter
640538032Speterbool
640638032Speterseq_map_parse(map, ap)
640738032Speter	MAP *map;
640838032Speter	char *ap;
640938032Speter{
641038032Speter	int maxmap;
641138032Speter
641238032Speter	if (tTd(38, 2))
641390792Sgshapiro		sm_dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
641438032Speter	maxmap = 0;
641538032Speter	while (*ap != '\0')
641638032Speter	{
641738032Speter		register char *p;
641838032Speter		STAB *s;
641938032Speter
642038032Speter		/* find beginning of map name */
642138032Speter		while (isascii(*ap) && isspace(*ap))
642238032Speter			ap++;
642364562Sgshapiro		for (p = ap;
642464562Sgshapiro		     (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.';
642564562Sgshapiro		     p++)
642638032Speter			continue;
642738032Speter		if (*p != '\0')
642838032Speter			*p++ = '\0';
642938032Speter		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
643038032Speter			p++;
643138032Speter		if (*ap == '\0')
643238032Speter		{
643338032Speter			ap = p;
643438032Speter			continue;
643538032Speter		}
643638032Speter		s = stab(ap, ST_MAP, ST_FIND);
643738032Speter		if (s == NULL)
643838032Speter		{
643938032Speter			syserr("Sequence map %s: unknown member map %s",
644038032Speter				map->map_mname, ap);
644138032Speter		}
644290792Sgshapiro		else if (maxmap >= MAXMAPSTACK)
644338032Speter		{
644438032Speter			syserr("Sequence map %s: too many member maps (%d max)",
644538032Speter				map->map_mname, MAXMAPSTACK);
644638032Speter			maxmap++;
644738032Speter		}
644838032Speter		else if (maxmap < MAXMAPSTACK)
644938032Speter		{
645038032Speter			map->map_stack[maxmap++] = &s->s_map;
645138032Speter		}
645238032Speter		ap = p;
645338032Speter	}
645490792Sgshapiro	return true;
645538032Speter}
645638032Speter
645738032Speter/*
645838032Speter**  SWITCH_MAP_OPEN -- open a switched map
645938032Speter**
646038032Speter**	This looks at the system-dependent configuration and builds
646138032Speter**	a sequence map that does the same thing.
646238032Speter**
646338032Speter**	Every system must define a switch_map_find routine in conf.c
646438032Speter**	that will return the list of service types associated with a
646538032Speter**	given service class.
646638032Speter*/
646738032Speter
646838032Speterbool
646938032Speterswitch_map_open(map, mode)
647038032Speter	MAP *map;
647138032Speter	int mode;
647238032Speter{
647338032Speter	int mapno;
647438032Speter	int nmaps;
647538032Speter	char *maptype[MAXMAPSTACK];
647638032Speter
647738032Speter	if (tTd(38, 2))
647890792Sgshapiro		sm_dprintf("switch_map_open(%s, %s, %d)\n",
647938032Speter			map->map_mname, map->map_file, mode);
648038032Speter
648138032Speter	mode &= O_ACCMODE;
648238032Speter	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
648338032Speter	if (tTd(38, 19))
648438032Speter	{
648590792Sgshapiro		sm_dprintf("\tswitch_map_find => %d\n", nmaps);
648638032Speter		for (mapno = 0; mapno < nmaps; mapno++)
648790792Sgshapiro			sm_dprintf("\t\t%s\n", maptype[mapno]);
648838032Speter	}
648938032Speter	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
649090792Sgshapiro		return false;
649138032Speter
649238032Speter	for (mapno = 0; mapno < nmaps; mapno++)
649338032Speter	{
649438032Speter		register STAB *s;
649538032Speter		char nbuf[MAXNAME + 1];
649638032Speter
649738032Speter		if (maptype[mapno] == NULL)
649838032Speter			continue;
6499168515Sgshapiro		(void) sm_strlcpyn(nbuf, sizeof(nbuf), 3,
650090792Sgshapiro				   map->map_mname, ".", maptype[mapno]);
650138032Speter		s = stab(nbuf, ST_MAP, ST_FIND);
650238032Speter		if (s == NULL)
650338032Speter		{
650438032Speter			syserr("Switch map %s: unknown member map %s",
650538032Speter				map->map_mname, nbuf);
650638032Speter		}
650738032Speter		else
650838032Speter		{
650938032Speter			map->map_stack[mapno] = &s->s_map;
651038032Speter			if (tTd(38, 4))
651190792Sgshapiro				sm_dprintf("\tmap_stack[%d] = %s:%s\n",
651290792Sgshapiro					   mapno,
651390792Sgshapiro					   s->s_map.map_class->map_cname,
651490792Sgshapiro					   nbuf);
651538032Speter		}
651638032Speter	}
651790792Sgshapiro	return true;
651838032Speter}
651938032Speter
652090792Sgshapiro#if 0
652138032Speter/*
652238032Speter**  SEQ_MAP_CLOSE -- close all underlying maps
652338032Speter*/
652438032Speter
652538032Spetervoid
652638032Speterseq_map_close(map)
652738032Speter	MAP *map;
652838032Speter{
652938032Speter	int mapno;
653038032Speter
653138032Speter	if (tTd(38, 9))
653290792Sgshapiro		sm_dprintf("seq_map_close(%s)\n", map->map_mname);
653338032Speter
653438032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
653538032Speter	{
653638032Speter		MAP *mm = map->map_stack[mapno];
653738032Speter
653838032Speter		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
653938032Speter			continue;
654077349Sgshapiro		mm->map_mflags |= MF_CLOSING;
654138032Speter		mm->map_class->map_close(mm);
654277349Sgshapiro		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
654338032Speter	}
654438032Speter}
654590792Sgshapiro#endif /* 0 */
654638032Speter
654738032Speter/*
654838032Speter**  SEQ_MAP_LOOKUP -- sequenced map lookup
654938032Speter*/
655038032Speter
655138032Speterchar *
655238032Speterseq_map_lookup(map, key, args, pstat)
655338032Speter	MAP *map;
655438032Speter	char *key;
655538032Speter	char **args;
655638032Speter	int *pstat;
655738032Speter{
655838032Speter	int mapno;
655938032Speter	int mapbit = 0x01;
656090792Sgshapiro	bool tempfail = false;
656138032Speter
656238032Speter	if (tTd(38, 20))
656390792Sgshapiro		sm_dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
656438032Speter
656538032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
656638032Speter	{
656738032Speter		MAP *mm = map->map_stack[mapno];
656838032Speter		char *rv;
656938032Speter
657038032Speter		if (mm == NULL)
657138032Speter			continue;
657264562Sgshapiro		if (!bitset(MF_OPEN, mm->map_mflags) &&
657364562Sgshapiro		    !openmap(mm))
657438032Speter		{
657538032Speter			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
657638032Speter			{
657738032Speter				*pstat = EX_UNAVAILABLE;
657838032Speter				return NULL;
657938032Speter			}
658038032Speter			continue;
658138032Speter		}
658238032Speter		*pstat = EX_OK;
658338032Speter		rv = mm->map_class->map_lookup(mm, key, args, pstat);
658438032Speter		if (rv != NULL)
658538032Speter			return rv;
658638032Speter		if (*pstat == EX_TEMPFAIL)
658738032Speter		{
658838032Speter			if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
658938032Speter				return NULL;
659090792Sgshapiro			tempfail = true;
659138032Speter		}
659238032Speter		else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
659338032Speter			break;
659438032Speter	}
659538032Speter	if (tempfail)
659638032Speter		*pstat = EX_TEMPFAIL;
659738032Speter	else if (*pstat == EX_OK)
659838032Speter		*pstat = EX_NOTFOUND;
659938032Speter	return NULL;
660038032Speter}
660138032Speter
660238032Speter/*
660338032Speter**  SEQ_MAP_STORE -- sequenced map store
660438032Speter*/
660538032Speter
660638032Spetervoid
660738032Speterseq_map_store(map, key, val)
660838032Speter	MAP *map;
660938032Speter	char *key;
661038032Speter	char *val;
661138032Speter{
661238032Speter	int mapno;
661338032Speter
661438032Speter	if (tTd(38, 12))
661590792Sgshapiro		sm_dprintf("seq_map_store(%s, %s, %s)\n",
661638032Speter			map->map_mname, key, val);
661738032Speter
661838032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
661938032Speter	{
662038032Speter		MAP *mm = map->map_stack[mapno];
662138032Speter
662238032Speter		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
662338032Speter			continue;
662438032Speter
662538032Speter		mm->map_class->map_store(mm, key, val);
662638032Speter		return;
662738032Speter	}
662838032Speter	syserr("seq_map_store(%s, %s, %s): no writable map",
662938032Speter		map->map_mname, key, val);
663038032Speter}
663190792Sgshapiro/*
663238032Speter**  NULL stubs
663338032Speter*/
663438032Speter
663538032Speter/* ARGSUSED */
663638032Speterbool
663738032Speternull_map_open(map, mode)
663838032Speter	MAP *map;
663938032Speter	int mode;
664038032Speter{
664190792Sgshapiro	return true;
664238032Speter}
664338032Speter
664438032Speter/* ARGSUSED */
664538032Spetervoid
664638032Speternull_map_close(map)
664738032Speter	MAP *map;
664838032Speter{
664938032Speter	return;
665038032Speter}
665138032Speter
665238032Speterchar *
665338032Speternull_map_lookup(map, key, args, pstat)
665438032Speter	MAP *map;
665538032Speter	char *key;
665638032Speter	char **args;
665738032Speter	int *pstat;
665838032Speter{
665938032Speter	*pstat = EX_NOTFOUND;
666038032Speter	return NULL;
666138032Speter}
666238032Speter
666338032Speter/* ARGSUSED */
666438032Spetervoid
666538032Speternull_map_store(map, key, val)
666638032Speter	MAP *map;
666738032Speter	char *key;
666838032Speter	char *val;
666938032Speter{
667038032Speter	return;
667138032Speter}
667238032Speter
667338032Speter/*
667438032Speter**  BOGUS stubs
667538032Speter*/
667638032Speter
667738032Speterchar *
667838032Speterbogus_map_lookup(map, key, args, pstat)
667938032Speter	MAP *map;
668038032Speter	char *key;
668138032Speter	char **args;
668238032Speter	int *pstat;
668338032Speter{
668438032Speter	*pstat = EX_TEMPFAIL;
668538032Speter	return NULL;
668638032Speter}
668738032Speter
668838032SpeterMAPCLASS	BogusMapClass =
668938032Speter{
669090792Sgshapiro	"bogus-map",		NULL,			0,
669190792Sgshapiro	NULL,			bogus_map_lookup,	null_map_store,
669290792Sgshapiro	null_map_open,		null_map_close,
669338032Speter};
669490792Sgshapiro/*
669564562Sgshapiro**  MACRO modules
669664562Sgshapiro*/
669764562Sgshapiro
669864562Sgshapirochar *
669964562Sgshapiromacro_map_lookup(map, name, av, statp)
670064562Sgshapiro	MAP *map;
670164562Sgshapiro	char *name;
670264562Sgshapiro	char **av;
670364562Sgshapiro	int *statp;
670464562Sgshapiro{
670564562Sgshapiro	int mid;
670664562Sgshapiro
670764562Sgshapiro	if (tTd(38, 20))
670890792Sgshapiro		sm_dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
670964562Sgshapiro			name == NULL ? "NULL" : name);
671064562Sgshapiro
671164562Sgshapiro	if (name == NULL ||
671264562Sgshapiro	    *name == '\0' ||
671390792Sgshapiro	    (mid = macid(name)) == 0)
671464562Sgshapiro	{
671564562Sgshapiro		*statp = EX_CONFIG;
671664562Sgshapiro		return NULL;
671764562Sgshapiro	}
671864562Sgshapiro
671964562Sgshapiro	if (av[1] == NULL)
672090792Sgshapiro		macdefine(&CurEnv->e_macro, A_PERM, mid, NULL);
672164562Sgshapiro	else
672290792Sgshapiro		macdefine(&CurEnv->e_macro, A_TEMP, mid, av[1]);
672364562Sgshapiro
672464562Sgshapiro	*statp = EX_OK;
672564562Sgshapiro	return "";
672664562Sgshapiro}
672790792Sgshapiro/*
672838032Speter**  REGEX modules
672938032Speter*/
673038032Speter
673190792Sgshapiro#if MAP_REGEX
673238032Speter
673338032Speter# include <regex.h>
673438032Speter
673538032Speter# define DEFAULT_DELIM	CONDELSE
673638032Speter# define END_OF_FIELDS	-1
673738032Speter# define ERRBUF_SIZE	80
673838032Speter# define MAX_MATCH	32
673938032Speter
674064562Sgshapiro# define xnalloc(s)	memset(xalloc(s), '\0', s);
674138032Speter
674238032Speterstruct regex_map
674338032Speter{
674471345Sgshapiro	regex_t	*regex_pattern_buf;	/* xalloc it */
674538032Speter	int	*regex_subfields;	/* move to type MAP */
674664562Sgshapiro	char	*regex_delim;		/* move to type MAP */
674738032Speter};
674838032Speter
6749141858Sgshapirostatic int	parse_fields __P((char *, int *, int, int));
6750141858Sgshapirostatic char	*regex_map_rewrite __P((MAP *, const char*, size_t, char **));
6751141858Sgshapiro
675238032Speterstatic int
675338032Speterparse_fields(s, ibuf, blen, nr_substrings)
675438032Speter	char *s;
675538032Speter	int *ibuf;		/* array */
675638032Speter	int blen;		/* number of elements in ibuf */
675738032Speter	int nr_substrings;	/* number of substrings in the pattern */
675838032Speter{
675938032Speter	register char *cp;
676038032Speter	int i = 0;
676190792Sgshapiro	bool lastone = false;
676238032Speter
676338032Speter	blen--;		/* for terminating END_OF_FIELDS */
676438032Speter	cp = s;
676538032Speter	do
676638032Speter	{
676738032Speter		for (;; cp++)
676838032Speter		{
676938032Speter			if (*cp == ',')
677038032Speter			{
677138032Speter				*cp = '\0';
677238032Speter				break;
677338032Speter			}
677438032Speter			if (*cp == '\0')
677538032Speter			{
677690792Sgshapiro				lastone = true;
677738032Speter				break;
677838032Speter			}
677938032Speter		}
678038032Speter		if (i < blen)
678138032Speter		{
678238032Speter			int val = atoi(s);
678338032Speter
678438032Speter			if (val < 0 || val >= nr_substrings)
678538032Speter			{
678638032Speter				syserr("field (%d) out of range, only %d substrings in pattern",
678738032Speter				       val, nr_substrings);
678838032Speter				return -1;
678938032Speter			}
679038032Speter			ibuf[i++] = val;
679138032Speter		}
679238032Speter		else
679338032Speter		{
679490792Sgshapiro			syserr("too many fields, %d max", blen);
679538032Speter			return -1;
679638032Speter		}
679738032Speter		s = ++cp;
679838032Speter	} while (!lastone);
679938032Speter	ibuf[i] = END_OF_FIELDS;
680038032Speter	return i;
680138032Speter}
680238032Speter
680338032Speterbool
680438032Speterregex_map_init(map, ap)
680538032Speter	MAP *map;
680638032Speter	char *ap;
680738032Speter{
680838032Speter	int regerr;
680938032Speter	struct regex_map *map_p;
681038032Speter	register char *p;
681138032Speter	char *sub_param = NULL;
681238032Speter	int pflags;
681390792Sgshapiro	static char defdstr[] = { (char) DEFAULT_DELIM, '\0' };
681438032Speter
681538032Speter	if (tTd(38, 2))
681690792Sgshapiro		sm_dprintf("regex_map_init: mapname '%s', args '%s'\n",
681764562Sgshapiro			map->map_mname, ap);
681838032Speter
681938032Speter	pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
682038032Speter	p = ap;
6821168515Sgshapiro	map_p = (struct regex_map *) xnalloc(sizeof(*map_p));
682271345Sgshapiro	map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t));
682338032Speter
682438032Speter	for (;;)
682564562Sgshapiro	{
682638032Speter		while (isascii(*p) && isspace(*p))
682738032Speter			p++;
682838032Speter		if (*p != '-')
682938032Speter			break;
683038032Speter		switch (*++p)
683138032Speter		{
683238032Speter		  case 'n':	/* not */
683338032Speter			map->map_mflags |= MF_REGEX_NOT;
683438032Speter			break;
683538032Speter
683638032Speter		  case 'f':	/* case sensitive */
683738032Speter			map->map_mflags |= MF_NOFOLDCASE;
683838032Speter			pflags &= ~REG_ICASE;
683938032Speter			break;
684038032Speter
684138032Speter		  case 'b':	/* basic regular expressions */
684238032Speter			pflags &= ~REG_EXTENDED;
684338032Speter			break;
684438032Speter
684538032Speter		  case 's':	/* substring match () syntax */
684638032Speter			sub_param = ++p;
684738032Speter			pflags &= ~REG_NOSUB;
684838032Speter			break;
684938032Speter
685038032Speter		  case 'd':	/* delimiter */
685164562Sgshapiro			map_p->regex_delim = ++p;
685238032Speter			break;
685338032Speter
685438032Speter		  case 'a':	/* map append */
685538032Speter			map->map_app = ++p;
685638032Speter			break;
685738032Speter
685838032Speter		  case 'm':	/* matchonly */
685938032Speter			map->map_mflags |= MF_MATCHONLY;
686038032Speter			break;
686138032Speter
6862120256Sgshapiro		  case 'q':
6863120256Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
6864120256Sgshapiro			break;
6865120256Sgshapiro
686664562Sgshapiro		  case 'S':
686764562Sgshapiro			map->map_spacesub = *++p;
686864562Sgshapiro			break;
686964562Sgshapiro
687064562Sgshapiro		  case 'D':
687164562Sgshapiro			map->map_mflags |= MF_DEFER;
687264562Sgshapiro			break;
687364562Sgshapiro
687438032Speter		}
687564562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
687664562Sgshapiro			p++;
687764562Sgshapiro		if (*p != '\0')
687864562Sgshapiro			*p++ = '\0';
687938032Speter	}
688038032Speter	if (tTd(38, 3))
688190792Sgshapiro		sm_dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
688238032Speter
688371345Sgshapiro	if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0)
688438032Speter	{
688538032Speter		/* Errorhandling */
688638032Speter		char errbuf[ERRBUF_SIZE];
688738032Speter
688871345Sgshapiro		(void) regerror(regerr, map_p->regex_pattern_buf,
6889168515Sgshapiro			 errbuf, sizeof(errbuf));
689090792Sgshapiro		syserr("pattern-compile-error: %s", errbuf);
689190792Sgshapiro		sm_free(map_p->regex_pattern_buf); /* XXX */
689290792Sgshapiro		sm_free(map_p); /* XXX */
689390792Sgshapiro		return false;
689438032Speter	}
689538032Speter
689638032Speter	if (map->map_app != NULL)
689738032Speter		map->map_app = newstr(map->map_app);
689864562Sgshapiro	if (map_p->regex_delim != NULL)
689964562Sgshapiro		map_p->regex_delim = newstr(map_p->regex_delim);
690038032Speter	else
690164562Sgshapiro		map_p->regex_delim = defdstr;
690238032Speter
690338032Speter	if (!bitset(REG_NOSUB, pflags))
690438032Speter	{
690538032Speter		/* substring matching */
690638032Speter		int substrings;
690764562Sgshapiro		int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1));
690838032Speter
690971345Sgshapiro		substrings = map_p->regex_pattern_buf->re_nsub + 1;
691038032Speter
691138032Speter		if (tTd(38, 3))
691290792Sgshapiro			sm_dprintf("regex_map_init: nr of substrings %d\n",
691364562Sgshapiro				substrings);
691438032Speter
691538032Speter		if (substrings >= MAX_MATCH)
691638032Speter		{
691790792Sgshapiro			syserr("too many substrings, %d max", MAX_MATCH);
691890792Sgshapiro			sm_free(map_p->regex_pattern_buf); /* XXX */
691990792Sgshapiro			sm_free(map_p); /* XXX */
692090792Sgshapiro			return false;
692138032Speter		}
692238032Speter		if (sub_param != NULL && sub_param[0] != '\0')
692338032Speter		{
692438032Speter			/* optional parameter -sfields */
692538032Speter			if (parse_fields(sub_param, fields,
692638032Speter					 MAX_MATCH + 1, substrings) == -1)
692790792Sgshapiro				return false;
692838032Speter		}
692938032Speter		else
693038032Speter		{
693138032Speter			int i;
693238032Speter
693390792Sgshapiro			/* set default fields */
693438032Speter			for (i = 0; i < substrings; i++)
693538032Speter				fields[i] = i;
693638032Speter			fields[i] = END_OF_FIELDS;
693738032Speter		}
693838032Speter		map_p->regex_subfields = fields;
693938032Speter		if (tTd(38, 3))
694038032Speter		{
694138032Speter			int *ip;
694238032Speter
694390792Sgshapiro			sm_dprintf("regex_map_init: subfields");
694438032Speter			for (ip = fields; *ip != END_OF_FIELDS; ip++)
694590792Sgshapiro				sm_dprintf(" %d", *ip);
694690792Sgshapiro			sm_dprintf("\n");
694738032Speter		}
694838032Speter	}
694990792Sgshapiro	map->map_db1 = (ARBPTR_T) map_p;	/* dirty hack */
695090792Sgshapiro	return true;
695138032Speter}
695238032Speter
695338032Speterstatic char *
695438032Speterregex_map_rewrite(map, s, slen, av)
695538032Speter	MAP *map;
695638032Speter	const char *s;
695738032Speter	size_t slen;
695838032Speter	char **av;
695938032Speter{
696038032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
696138032Speter		return map_rewrite(map, av[0], strlen(av[0]), NULL);
696238032Speter	else
696377349Sgshapiro		return map_rewrite(map, s, slen, av);
696438032Speter}
696538032Speter
696638032Speterchar *
696738032Speterregex_map_lookup(map, name, av, statp)
696838032Speter	MAP *map;
696938032Speter	char *name;
697038032Speter	char **av;
697138032Speter	int *statp;
697238032Speter{
697338032Speter	int reg_res;
697438032Speter	struct regex_map *map_p;
697538032Speter	regmatch_t pmatch[MAX_MATCH];
697638032Speter
697738032Speter	if (tTd(38, 20))
697838032Speter	{
697938032Speter		char **cpp;
698038032Speter
698190792Sgshapiro		sm_dprintf("regex_map_lookup: key '%s'\n", name);
698264562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
698390792Sgshapiro			sm_dprintf("regex_map_lookup: arg '%s'\n", *cpp);
698438032Speter	}
698538032Speter
698638032Speter	map_p = (struct regex_map *)(map->map_db1);
698771345Sgshapiro	reg_res = regexec(map_p->regex_pattern_buf,
698864562Sgshapiro			  name, MAX_MATCH, pmatch, 0);
698938032Speter
699038032Speter	if (bitset(MF_REGEX_NOT, map->map_mflags))
699138032Speter	{
699238032Speter		/* option -n */
699338032Speter		if (reg_res == REG_NOMATCH)
699490792Sgshapiro			return regex_map_rewrite(map, "", (size_t) 0, av);
699538032Speter		else
699638032Speter			return NULL;
699738032Speter	}
699838032Speter	if (reg_res == REG_NOMATCH)
699938032Speter		return NULL;
700038032Speter
700138032Speter	if (map_p->regex_subfields != NULL)
700238032Speter	{
700338032Speter		/* option -s */
700438032Speter		static char retbuf[MAXNAME];
700538032Speter		int fields[MAX_MATCH + 1];
700690792Sgshapiro		bool first = true;
700738032Speter		int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
700890792Sgshapiro		bool quotemode = false, bslashmode = false;
700938032Speter		register char *dp, *sp;
701038032Speter		char *endp, *ldp;
701138032Speter		int *ip;
701238032Speter
701338032Speter		dp = retbuf;
701438032Speter		ldp = retbuf + sizeof(retbuf) - 1;
701538032Speter
701638032Speter		if (av[1] != NULL)
701738032Speter		{
701838032Speter			if (parse_fields(av[1], fields, MAX_MATCH + 1,
701971345Sgshapiro					 (int) map_p->regex_pattern_buf->re_nsub + 1) == -1)
702038032Speter			{
702138032Speter				*statp = EX_CONFIG;
702238032Speter				return NULL;
702338032Speter			}
702438032Speter			ip = fields;
702538032Speter		}
702638032Speter		else
702738032Speter			ip = map_p->regex_subfields;
702838032Speter
702938032Speter		for ( ; *ip != END_OF_FIELDS; ip++)
703038032Speter		{
703138032Speter			if (!first)
703238032Speter			{
703364562Sgshapiro				for (sp = map_p->regex_delim; *sp; sp++)
703438032Speter				{
703538032Speter					if (dp < ldp)
703638032Speter						*dp++ = *sp;
703738032Speter				}
703838032Speter			}
703938032Speter			else
704090792Sgshapiro				first = false;
704138032Speter
704271345Sgshapiro			if (*ip >= MAX_MATCH ||
704371345Sgshapiro			    pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
704438032Speter				continue;
704538032Speter
704638032Speter			sp = name + pmatch[*ip].rm_so;
704738032Speter			endp = name + pmatch[*ip].rm_eo;
704838032Speter			for (; endp > sp; sp++)
704938032Speter			{
705038032Speter				if (dp < ldp)
705138032Speter				{
705264562Sgshapiro					if (bslashmode)
705364562Sgshapiro					{
705438032Speter						*dp++ = *sp;
705590792Sgshapiro						bslashmode = false;
705638032Speter					}
705764562Sgshapiro					else if (quotemode && *sp != '"' &&
705838032Speter						*sp != '\\')
705938032Speter					{
706038032Speter						*dp++ = *sp;
706138032Speter					}
706290792Sgshapiro					else switch (*dp++ = *sp)
706338032Speter					{
706490792Sgshapiro					  case '\\':
706590792Sgshapiro						bslashmode = true;
706638032Speter						break;
706738032Speter
706890792Sgshapiro					  case '(':
706938032Speter						cmntcnt++;
707038032Speter						break;
707138032Speter
707290792Sgshapiro					  case ')':
707338032Speter						cmntcnt--;
707438032Speter						break;
707538032Speter
707690792Sgshapiro					  case '<':
707738032Speter						anglecnt++;
707838032Speter						break;
707938032Speter
708090792Sgshapiro					  case '>':
708138032Speter						anglecnt--;
708238032Speter						break;
708338032Speter
708490792Sgshapiro					  case ' ':
708538032Speter						spacecnt++;
708638032Speter						break;
708738032Speter
708890792Sgshapiro					  case '"':
708938032Speter						quotemode = !quotemode;
709038032Speter						break;
709138032Speter					}
709238032Speter				}
709338032Speter			}
709438032Speter		}
709538032Speter		if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
709638032Speter		    bslashmode || spacecnt != 0)
709738032Speter		{
709864562Sgshapiro			sm_syslog(LOG_WARNING, NOQID,
709964562Sgshapiro				  "Warning: regex may cause prescan() failure map=%s lookup=%s",
710064562Sgshapiro				  map->map_mname, name);
710138032Speter			return NULL;
710238032Speter		}
710338032Speter
710438032Speter		*dp = '\0';
710538032Speter
710638032Speter		return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
710738032Speter	}
710838032Speter	return regex_map_rewrite(map, "", (size_t)0, av);
710938032Speter}
711038032Speter#endif /* MAP_REGEX */
711190792Sgshapiro/*
711264562Sgshapiro**  NSD modules
711364562Sgshapiro*/
711490792Sgshapiro#if MAP_NSD
711564562Sgshapiro
711664562Sgshapiro# include <ndbm.h>
711764562Sgshapiro# define _DATUM_DEFINED
711864562Sgshapiro# include <ns_api.h>
711964562Sgshapiro
712064562Sgshapirotypedef struct ns_map_list
712164562Sgshapiro{
712290792Sgshapiro	ns_map_t		*map;		/* XXX ns_ ? */
712390792Sgshapiro	char			*mapname;
712490792Sgshapiro	struct ns_map_list	*next;
712564562Sgshapiro} ns_map_list_t;
712664562Sgshapiro
712764562Sgshapirostatic ns_map_t *
712864562Sgshapirons_map_t_find(mapname)
712964562Sgshapiro	char *mapname;
713064562Sgshapiro{
713164562Sgshapiro	static ns_map_list_t *ns_maps = NULL;
713264562Sgshapiro	ns_map_list_t *ns_map;
713364562Sgshapiro
713464562Sgshapiro	/* walk the list of maps looking for the correctly named map */
713564562Sgshapiro	for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next)
713664562Sgshapiro	{
713764562Sgshapiro		if (strcmp(ns_map->mapname, mapname) == 0)
713864562Sgshapiro			break;
713964562Sgshapiro	}
714064562Sgshapiro
714164562Sgshapiro	/* if we are looking at a NULL ns_map_list_t, then create a new one */
714264562Sgshapiro	if (ns_map == NULL)
714364562Sgshapiro	{
7144168515Sgshapiro		ns_map = (ns_map_list_t *) xalloc(sizeof(*ns_map));
714564562Sgshapiro		ns_map->mapname = newstr(mapname);
7146168515Sgshapiro		ns_map->map = (ns_map_t *) xalloc(sizeof(*ns_map->map));
7147168515Sgshapiro		memset(ns_map->map, '\0', sizeof(*ns_map->map));
714864562Sgshapiro		ns_map->next = ns_maps;
714964562Sgshapiro		ns_maps = ns_map;
715064562Sgshapiro	}
715164562Sgshapiro	return ns_map->map;
715264562Sgshapiro}
715364562Sgshapiro
715464562Sgshapirochar *
715564562Sgshapironsd_map_lookup(map, name, av, statp)
715664562Sgshapiro	MAP *map;
715764562Sgshapiro	char *name;
715864562Sgshapiro	char **av;
715964562Sgshapiro	int *statp;
716064562Sgshapiro{
716171345Sgshapiro	int buflen, r;
716264562Sgshapiro	char *p;
716364562Sgshapiro	ns_map_t *ns_map;
716464562Sgshapiro	char keybuf[MAXNAME + 1];
716564562Sgshapiro	char buf[MAXLINE];
716664562Sgshapiro
716764562Sgshapiro	if (tTd(38, 20))
716890792Sgshapiro		sm_dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
716964562Sgshapiro
717064562Sgshapiro	buflen = strlen(name);
7171168515Sgshapiro	if (buflen > sizeof(keybuf) - 1)
7172168515Sgshapiro		buflen = sizeof(keybuf) - 1;	/* XXX simply cut off? */
717364562Sgshapiro	memmove(keybuf, name, buflen);
717464562Sgshapiro	keybuf[buflen] = '\0';
717564562Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
717664562Sgshapiro		makelower(keybuf);
717764562Sgshapiro
717864562Sgshapiro	ns_map = ns_map_t_find(map->map_file);
717964562Sgshapiro	if (ns_map == NULL)
718064562Sgshapiro	{
718164562Sgshapiro		if (tTd(38, 20))
718290792Sgshapiro			sm_dprintf("nsd_map_t_find failed\n");
718371345Sgshapiro		*statp = EX_UNAVAILABLE;
718464562Sgshapiro		return NULL;
718564562Sgshapiro	}
718698121Sgshapiro	r = ns_lookup(ns_map, NULL, map->map_file, keybuf, NULL,
7187168515Sgshapiro		      buf, sizeof(buf));
718871345Sgshapiro	if (r == NS_UNAVAIL || r == NS_TRYAGAIN)
718971345Sgshapiro	{
719071345Sgshapiro		*statp = EX_TEMPFAIL;
719164562Sgshapiro		return NULL;
719271345Sgshapiro	}
719377349Sgshapiro	if (r == NS_BADREQ
719477349Sgshapiro# ifdef NS_NOPERM
719577349Sgshapiro	    || r == NS_NOPERM
719677349Sgshapiro# endif /* NS_NOPERM */
719777349Sgshapiro	    )
719871345Sgshapiro	{
719971345Sgshapiro		*statp = EX_CONFIG;
720071345Sgshapiro		return NULL;
720171345Sgshapiro	}
720271345Sgshapiro	if (r != NS_SUCCESS)
720371345Sgshapiro	{
720471345Sgshapiro		*statp = EX_NOTFOUND;
720571345Sgshapiro		return NULL;
720671345Sgshapiro	}
720764562Sgshapiro
720871345Sgshapiro	*statp = EX_OK;
720971345Sgshapiro
721064562Sgshapiro	/* Null out trailing \n */
721164562Sgshapiro	if ((p = strchr(buf, '\n')) != NULL)
721264562Sgshapiro		*p = '\0';
721364562Sgshapiro
721464562Sgshapiro	return map_rewrite(map, buf, strlen(buf), av);
721564562Sgshapiro}
721664562Sgshapiro#endif /* MAP_NSD */
721764562Sgshapiro
721864562Sgshapirochar *
721964562Sgshapiroarith_map_lookup(map, name, av, statp)
722064562Sgshapiro	MAP *map;
722164562Sgshapiro	char *name;
722264562Sgshapiro	char **av;
722364562Sgshapiro	int *statp;
722464562Sgshapiro{
722564562Sgshapiro	long r;
722664562Sgshapiro	long v[2];
722790792Sgshapiro	bool res = false;
722864562Sgshapiro	bool boolres;
722964562Sgshapiro	static char result[16];
723064562Sgshapiro	char **cpp;
723164562Sgshapiro
723264562Sgshapiro	if (tTd(38, 2))
723364562Sgshapiro	{
723490792Sgshapiro		sm_dprintf("arith_map_lookup: key '%s'\n", name);
723564562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
723690792Sgshapiro			sm_dprintf("arith_map_lookup: arg '%s'\n", *cpp);
723764562Sgshapiro	}
723864562Sgshapiro	r = 0;
723990792Sgshapiro	boolres = false;
724064562Sgshapiro	cpp = av;
724164562Sgshapiro	*statp = EX_OK;
724264562Sgshapiro
724364562Sgshapiro	/*
724464562Sgshapiro	**  read arguments for arith map
724564562Sgshapiro	**  - no check is made whether they are really numbers
724664562Sgshapiro	**  - just ignores args after the second
724764562Sgshapiro	*/
724890792Sgshapiro
724964562Sgshapiro	for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
725064562Sgshapiro		v[r++] = strtol(*cpp, NULL, 0);
725164562Sgshapiro
725264562Sgshapiro	/* operator and (at least) two operands given? */
725364562Sgshapiro	if (name != NULL && r == 2)
725464562Sgshapiro	{
725590792Sgshapiro		switch (*name)
725664562Sgshapiro		{
725764562Sgshapiro		  case '|':
725864562Sgshapiro			r = v[0] | v[1];
725964562Sgshapiro			break;
726064562Sgshapiro
726164562Sgshapiro		  case '&':
726264562Sgshapiro			r = v[0] & v[1];
726364562Sgshapiro			break;
726464562Sgshapiro
726564562Sgshapiro		  case '%':
726664562Sgshapiro			if (v[1] == 0)
726764562Sgshapiro				return NULL;
726864562Sgshapiro			r = v[0] % v[1];
726964562Sgshapiro			break;
727064562Sgshapiro		  case '+':
727164562Sgshapiro			r = v[0] + v[1];
727264562Sgshapiro			break;
727364562Sgshapiro
727464562Sgshapiro		  case '-':
727564562Sgshapiro			r = v[0] - v[1];
727664562Sgshapiro			break;
727764562Sgshapiro
727864562Sgshapiro		  case '*':
727964562Sgshapiro			r = v[0] * v[1];
728064562Sgshapiro			break;
728164562Sgshapiro
728264562Sgshapiro		  case '/':
728364562Sgshapiro			if (v[1] == 0)
728464562Sgshapiro				return NULL;
728564562Sgshapiro			r = v[0] / v[1];
728664562Sgshapiro			break;
728764562Sgshapiro
728864562Sgshapiro		  case 'l':
728964562Sgshapiro			res = v[0] < v[1];
729090792Sgshapiro			boolres = true;
729164562Sgshapiro			break;
729264562Sgshapiro
729364562Sgshapiro		  case '=':
729464562Sgshapiro			res = v[0] == v[1];
729590792Sgshapiro			boolres = true;
729664562Sgshapiro			break;
729764562Sgshapiro
7298168515Sgshapiro		  case 'r':
7299168515Sgshapiro			r = v[1] - v[0] + 1;
7300168515Sgshapiro			if (r <= 0)
7301168515Sgshapiro				return NULL;
7302168515Sgshapiro			r = get_random() % r + v[0];
7303168515Sgshapiro			break;
7304168515Sgshapiro
730564562Sgshapiro		  default:
730664562Sgshapiro			/* XXX */
730764562Sgshapiro			*statp = EX_CONFIG;
730864562Sgshapiro			if (LogLevel > 10)
730964562Sgshapiro				sm_syslog(LOG_WARNING, NOQID,
731064562Sgshapiro					  "arith_map: unknown operator %c",
731164562Sgshapiro					  isprint(*name) ? *name : '?');
731264562Sgshapiro			return NULL;
731364562Sgshapiro		}
731464562Sgshapiro		if (boolres)
7315168515Sgshapiro			(void) sm_snprintf(result, sizeof(result),
731690792Sgshapiro				res ? "TRUE" : "FALSE");
731764562Sgshapiro		else
7318168515Sgshapiro			(void) sm_snprintf(result, sizeof(result), "%ld", r);
731964562Sgshapiro		return result;
732064562Sgshapiro	}
732164562Sgshapiro	*statp = EX_CONFIG;
732264562Sgshapiro	return NULL;
732364562Sgshapiro}
7324132943Sgshapiro
7325132943Sgshapiro#if SOCKETMAP
7326132943Sgshapiro
7327132943Sgshapiro# if NETINET || NETINET6
7328132943Sgshapiro#  include <arpa/inet.h>
7329132943Sgshapiro# endif /* NETINET || NETINET6 */
7330132943Sgshapiro
7331132943Sgshapiro# define socket_map_next map_stack[0]
7332132943Sgshapiro
7333132943Sgshapiro/*
7334132943Sgshapiro**  SOCKET_MAP_OPEN -- open socket table
7335132943Sgshapiro*/
7336132943Sgshapiro
7337132943Sgshapirobool
7338132943Sgshapirosocket_map_open(map, mode)
7339132943Sgshapiro	MAP *map;
7340132943Sgshapiro	int mode;
7341132943Sgshapiro{
7342132943Sgshapiro	STAB *s;
7343132943Sgshapiro	int sock = 0;
7344132943Sgshapiro	SOCKADDR_LEN_T addrlen = 0;
7345132943Sgshapiro	int addrno = 0;
7346132943Sgshapiro	int save_errno;
7347132943Sgshapiro	char *p;
7348132943Sgshapiro	char *colon;
7349132943Sgshapiro	char *at;
7350132943Sgshapiro	struct hostent *hp = NULL;
7351132943Sgshapiro	SOCKADDR addr;
7352132943Sgshapiro
7353132943Sgshapiro	if (tTd(38, 2))
7354132943Sgshapiro		sm_dprintf("socket_map_open(%s, %s, %d)\n",
7355132943Sgshapiro			map->map_mname, map->map_file, mode);
7356132943Sgshapiro
7357132943Sgshapiro	mode &= O_ACCMODE;
7358132943Sgshapiro
7359132943Sgshapiro	/* sendmail doesn't have the ability to write to SOCKET (yet) */
7360132943Sgshapiro	if (mode != O_RDONLY)
7361132943Sgshapiro	{
7362132943Sgshapiro		/* issue a pseudo-error message */
7363132943Sgshapiro		errno = SM_EMAPCANTWRITE;
7364132943Sgshapiro		return false;
7365132943Sgshapiro	}
7366132943Sgshapiro
7367132943Sgshapiro	if (*map->map_file == '\0')
7368132943Sgshapiro	{
7369132943Sgshapiro		syserr("socket map \"%s\": empty or missing socket information",
7370132943Sgshapiro			map->map_mname);
7371132943Sgshapiro		return false;
7372132943Sgshapiro	}
7373132943Sgshapiro
7374132943Sgshapiro	s = socket_map_findconn(map->map_file);
7375132943Sgshapiro	if (s->s_socketmap != NULL)
7376132943Sgshapiro	{
7377132943Sgshapiro		/* Copy open connection */
7378132943Sgshapiro		map->map_db1 = s->s_socketmap->map_db1;
7379132943Sgshapiro
7380132943Sgshapiro		/* Add this map as head of linked list */
7381132943Sgshapiro		map->socket_map_next = s->s_socketmap;
7382132943Sgshapiro		s->s_socketmap = map;
7383132943Sgshapiro
7384132943Sgshapiro		if (tTd(38, 2))
7385132943Sgshapiro			sm_dprintf("using cached connection\n");
7386132943Sgshapiro		return true;
7387132943Sgshapiro	}
7388132943Sgshapiro
7389132943Sgshapiro	if (tTd(38, 2))
7390132943Sgshapiro		sm_dprintf("opening new connection\n");
7391132943Sgshapiro
7392132943Sgshapiro	/* following code is ripped from milter.c */
7393132943Sgshapiro	/* XXX It should be put in a library... */
7394132943Sgshapiro
7395132943Sgshapiro	/* protocol:filename or protocol:port@host */
7396168515Sgshapiro	memset(&addr, '\0', sizeof(addr));
7397132943Sgshapiro	p = map->map_file;
7398132943Sgshapiro	colon = strchr(p, ':');
7399132943Sgshapiro	if (colon != NULL)
7400132943Sgshapiro	{
7401132943Sgshapiro		*colon = '\0';
7402132943Sgshapiro
7403132943Sgshapiro		if (*p == '\0')
7404132943Sgshapiro		{
7405132943Sgshapiro# if NETUNIX
7406132943Sgshapiro			/* default to AF_UNIX */
7407132943Sgshapiro			addr.sa.sa_family = AF_UNIX;
7408132943Sgshapiro# else /* NETUNIX */
7409132943Sgshapiro#  if NETINET
7410132943Sgshapiro			/* default to AF_INET */
7411132943Sgshapiro			addr.sa.sa_family = AF_INET;
7412132943Sgshapiro#  else /* NETINET */
7413132943Sgshapiro#   if NETINET6
7414132943Sgshapiro			/* default to AF_INET6 */
7415132943Sgshapiro			addr.sa.sa_family = AF_INET6;
7416132943Sgshapiro#   else /* NETINET6 */
7417132943Sgshapiro			/* no protocols available */
7418132943Sgshapiro			syserr("socket map \"%s\": no valid socket protocols available",
7419132943Sgshapiro			map->map_mname);
7420132943Sgshapiro			return false;
7421132943Sgshapiro#   endif /* NETINET6 */
7422132943Sgshapiro#  endif /* NETINET */
7423132943Sgshapiro# endif /* NETUNIX */
7424132943Sgshapiro		}
7425132943Sgshapiro# if NETUNIX
7426132943Sgshapiro		else if (sm_strcasecmp(p, "unix") == 0 ||
7427132943Sgshapiro			 sm_strcasecmp(p, "local") == 0)
7428132943Sgshapiro			addr.sa.sa_family = AF_UNIX;
7429132943Sgshapiro# endif /* NETUNIX */
7430132943Sgshapiro# if NETINET
7431132943Sgshapiro		else if (sm_strcasecmp(p, "inet") == 0)
7432132943Sgshapiro			addr.sa.sa_family = AF_INET;
7433132943Sgshapiro# endif /* NETINET */
7434132943Sgshapiro# if NETINET6
7435132943Sgshapiro		else if (sm_strcasecmp(p, "inet6") == 0)
7436132943Sgshapiro			addr.sa.sa_family = AF_INET6;
7437132943Sgshapiro# endif /* NETINET6 */
7438132943Sgshapiro		else
7439132943Sgshapiro		{
7440132943Sgshapiro# ifdef EPROTONOSUPPORT
7441132943Sgshapiro			errno = EPROTONOSUPPORT;
7442132943Sgshapiro# else /* EPROTONOSUPPORT */
7443132943Sgshapiro			errno = EINVAL;
7444132943Sgshapiro# endif /* EPROTONOSUPPORT */
7445132943Sgshapiro			syserr("socket map \"%s\": unknown socket type %s",
7446132943Sgshapiro			       map->map_mname, p);
7447132943Sgshapiro			return false;
7448132943Sgshapiro		}
7449132943Sgshapiro		*colon++ = ':';
7450132943Sgshapiro	}
7451132943Sgshapiro	else
7452132943Sgshapiro	{
7453132943Sgshapiro		colon = p;
7454132943Sgshapiro#if NETUNIX
7455132943Sgshapiro		/* default to AF_UNIX */
7456132943Sgshapiro		addr.sa.sa_family = AF_UNIX;
7457132943Sgshapiro#else /* NETUNIX */
7458132943Sgshapiro# if NETINET
7459132943Sgshapiro		/* default to AF_INET */
7460132943Sgshapiro		addr.sa.sa_family = AF_INET;
7461132943Sgshapiro# else /* NETINET */
7462132943Sgshapiro#  if NETINET6
7463132943Sgshapiro		/* default to AF_INET6 */
7464132943Sgshapiro		addr.sa.sa_family = AF_INET6;
7465132943Sgshapiro#  else /* NETINET6 */
7466132943Sgshapiro		syserr("socket map \"%s\": unknown socket type %s",
7467132943Sgshapiro		       map->map_mname, p);
7468132943Sgshapiro		return false;
7469132943Sgshapiro#  endif /* NETINET6 */
7470132943Sgshapiro# endif /* NETINET */
7471132943Sgshapiro#endif /* NETUNIX */
7472132943Sgshapiro	}
7473132943Sgshapiro
7474132943Sgshapiro# if NETUNIX
7475132943Sgshapiro	if (addr.sa.sa_family == AF_UNIX)
7476132943Sgshapiro	{
7477132943Sgshapiro		long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK;
7478132943Sgshapiro
7479132943Sgshapiro		at = colon;
7480168515Sgshapiro		if (strlen(colon) >= sizeof(addr.sunix.sun_path))
7481132943Sgshapiro		{
7482132943Sgshapiro			syserr("socket map \"%s\": local socket name %s too long",
7483132943Sgshapiro			       map->map_mname, colon);
7484132943Sgshapiro			return false;
7485132943Sgshapiro		}
7486132943Sgshapiro		errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
7487132943Sgshapiro				 S_IRUSR|S_IWUSR, NULL);
7488132943Sgshapiro
7489132943Sgshapiro		if (errno != 0)
7490132943Sgshapiro		{
7491132943Sgshapiro			/* if not safe, don't create */
7492132943Sgshapiro				syserr("socket map \"%s\": local socket name %s unsafe",
7493132943Sgshapiro			       map->map_mname, colon);
7494132943Sgshapiro			return false;
7495132943Sgshapiro		}
7496132943Sgshapiro
7497132943Sgshapiro		(void) sm_strlcpy(addr.sunix.sun_path, colon,
7498168515Sgshapiro			       sizeof(addr.sunix.sun_path));
7499168515Sgshapiro		addrlen = sizeof(struct sockaddr_un);
7500132943Sgshapiro	}
7501132943Sgshapiro	else
7502132943Sgshapiro# endif /* NETUNIX */
7503132943Sgshapiro# if NETINET || NETINET6
7504132943Sgshapiro	if (false
7505132943Sgshapiro#  if NETINET
7506132943Sgshapiro		 || addr.sa.sa_family == AF_INET
7507132943Sgshapiro#  endif /* NETINET */
7508132943Sgshapiro#  if NETINET6
7509132943Sgshapiro		 || addr.sa.sa_family == AF_INET6
7510132943Sgshapiro#  endif /* NETINET6 */
7511132943Sgshapiro		 )
7512132943Sgshapiro	{
7513132943Sgshapiro		unsigned short port;
7514132943Sgshapiro
7515132943Sgshapiro		/* Parse port@host */
7516132943Sgshapiro		at = strchr(colon, '@');
7517132943Sgshapiro		if (at == NULL)
7518132943Sgshapiro		{
7519132943Sgshapiro			syserr("socket map \"%s\": bad address %s (expected port@host)",
7520132943Sgshapiro				       map->map_mname, colon);
7521132943Sgshapiro			return false;
7522132943Sgshapiro		}
7523132943Sgshapiro		*at = '\0';
7524132943Sgshapiro		if (isascii(*colon) && isdigit(*colon))
7525132943Sgshapiro			port = htons((unsigned short) atoi(colon));
7526132943Sgshapiro		else
7527132943Sgshapiro		{
7528132943Sgshapiro#  ifdef NO_GETSERVBYNAME
7529132943Sgshapiro			syserr("socket map \"%s\": invalid port number %s",
7530132943Sgshapiro				       map->map_mname, colon);
7531132943Sgshapiro			return false;
7532132943Sgshapiro#  else /* NO_GETSERVBYNAME */
7533132943Sgshapiro			register struct servent *sp;
7534132943Sgshapiro
7535132943Sgshapiro			sp = getservbyname(colon, "tcp");
7536132943Sgshapiro			if (sp == NULL)
7537132943Sgshapiro			{
7538132943Sgshapiro				syserr("socket map \"%s\": unknown port name %s",
7539132943Sgshapiro					       map->map_mname, colon);
7540132943Sgshapiro				return false;
7541132943Sgshapiro			}
7542132943Sgshapiro			port = sp->s_port;
7543132943Sgshapiro#  endif /* NO_GETSERVBYNAME */
7544132943Sgshapiro		}
7545132943Sgshapiro		*at++ = '@';
7546132943Sgshapiro		if (*at == '[')
7547132943Sgshapiro		{
7548132943Sgshapiro			char *end;
7549132943Sgshapiro
7550132943Sgshapiro			end = strchr(at, ']');
7551132943Sgshapiro			if (end != NULL)
7552132943Sgshapiro			{
7553132943Sgshapiro				bool found = false;
7554132943Sgshapiro#  if NETINET
7555132943Sgshapiro				unsigned long hid = INADDR_NONE;
7556132943Sgshapiro#  endif /* NETINET */
7557132943Sgshapiro#  if NETINET6
7558132943Sgshapiro				struct sockaddr_in6 hid6;
7559132943Sgshapiro#  endif /* NETINET6 */
7560132943Sgshapiro
7561132943Sgshapiro				*end = '\0';
7562132943Sgshapiro#  if NETINET
7563132943Sgshapiro				if (addr.sa.sa_family == AF_INET &&
7564132943Sgshapiro				    (hid = inet_addr(&at[1])) != INADDR_NONE)
7565132943Sgshapiro				{
7566132943Sgshapiro					addr.sin.sin_addr.s_addr = hid;
7567132943Sgshapiro					addr.sin.sin_port = port;
7568132943Sgshapiro					found = true;
7569132943Sgshapiro				}
7570132943Sgshapiro#  endif /* NETINET */
7571132943Sgshapiro#  if NETINET6
7572168515Sgshapiro				(void) memset(&hid6, '\0', sizeof(hid6));
7573132943Sgshapiro				if (addr.sa.sa_family == AF_INET6 &&
7574132943Sgshapiro				    anynet_pton(AF_INET6, &at[1],
7575132943Sgshapiro						&hid6.sin6_addr) == 1)
7576132943Sgshapiro				{
7577132943Sgshapiro					addr.sin6.sin6_addr = hid6.sin6_addr;
7578132943Sgshapiro					addr.sin6.sin6_port = port;
7579132943Sgshapiro					found = true;
7580132943Sgshapiro				}
7581132943Sgshapiro#  endif /* NETINET6 */
7582132943Sgshapiro				*end = ']';
7583132943Sgshapiro				if (!found)
7584132943Sgshapiro				{
7585132943Sgshapiro					syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
7586132943Sgshapiro					       map->map_mname, at);
7587132943Sgshapiro					return false;
7588132943Sgshapiro				}
7589132943Sgshapiro			}
7590132943Sgshapiro			else
7591132943Sgshapiro			{
7592132943Sgshapiro				syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
7593132943Sgshapiro				       map->map_mname, at);
7594132943Sgshapiro				return false;
7595132943Sgshapiro			}
7596132943Sgshapiro		}
7597132943Sgshapiro		else
7598132943Sgshapiro		{
7599132943Sgshapiro			hp = sm_gethostbyname(at, addr.sa.sa_family);
7600132943Sgshapiro			if (hp == NULL)
7601132943Sgshapiro			{
7602132943Sgshapiro				syserr("socket map \"%s\": Unknown host name %s",
7603132943Sgshapiro					map->map_mname, at);
7604132943Sgshapiro				return false;
7605132943Sgshapiro			}
7606132943Sgshapiro			addr.sa.sa_family = hp->h_addrtype;
7607132943Sgshapiro			switch (hp->h_addrtype)
7608132943Sgshapiro			{
7609132943Sgshapiro#  if NETINET
7610132943Sgshapiro			  case AF_INET:
7611132943Sgshapiro				memmove(&addr.sin.sin_addr,
7612132943Sgshapiro					hp->h_addr, INADDRSZ);
7613132943Sgshapiro				addr.sin.sin_port = port;
7614168515Sgshapiro				addrlen = sizeof(struct sockaddr_in);
7615132943Sgshapiro				addrno = 1;
7616132943Sgshapiro				break;
7617132943Sgshapiro#  endif /* NETINET */
7618132943Sgshapiro
7619132943Sgshapiro#  if NETINET6
7620132943Sgshapiro			  case AF_INET6:
7621132943Sgshapiro				memmove(&addr.sin6.sin6_addr,
7622132943Sgshapiro					hp->h_addr, IN6ADDRSZ);
7623132943Sgshapiro				addr.sin6.sin6_port = port;
7624168515Sgshapiro				addrlen = sizeof(struct sockaddr_in6);
7625132943Sgshapiro				addrno = 1;
7626132943Sgshapiro				break;
7627132943Sgshapiro#  endif /* NETINET6 */
7628132943Sgshapiro
7629132943Sgshapiro			  default:
7630132943Sgshapiro				syserr("socket map \"%s\": Unknown protocol for %s (%d)",
7631132943Sgshapiro					map->map_mname, at, hp->h_addrtype);
7632132943Sgshapiro#  if NETINET6
7633132943Sgshapiro				freehostent(hp);
7634132943Sgshapiro#  endif /* NETINET6 */
7635132943Sgshapiro				return false;
7636132943Sgshapiro			}
7637132943Sgshapiro		}
7638132943Sgshapiro	}
7639132943Sgshapiro	else
7640132943Sgshapiro# endif /* NETINET || NETINET6 */
7641132943Sgshapiro	{
7642132943Sgshapiro		syserr("socket map \"%s\": unknown socket protocol",
7643132943Sgshapiro			map->map_mname);
7644132943Sgshapiro		return false;
7645132943Sgshapiro	}
7646132943Sgshapiro
7647132943Sgshapiro	/* nope, actually connecting */
7648132943Sgshapiro	for (;;)
7649132943Sgshapiro	{
7650132943Sgshapiro		sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
7651132943Sgshapiro		if (sock < 0)
7652132943Sgshapiro		{
7653132943Sgshapiro			save_errno = errno;
7654132943Sgshapiro			if (tTd(38, 5))
7655132943Sgshapiro				sm_dprintf("socket map \"%s\": error creating socket: %s\n",
7656132943Sgshapiro					   map->map_mname,
7657132943Sgshapiro					   sm_errstring(save_errno));
7658132943Sgshapiro# if NETINET6
7659132943Sgshapiro			if (hp != NULL)
7660132943Sgshapiro				freehostent(hp);
7661132943Sgshapiro# endif /* NETINET6 */
7662132943Sgshapiro			return false;
7663132943Sgshapiro		}
7664132943Sgshapiro
7665132943Sgshapiro		if (connect(sock, (struct sockaddr *) &addr, addrlen) >= 0)
7666132943Sgshapiro			break;
7667132943Sgshapiro
7668132943Sgshapiro		/* couldn't connect.... try next address */
7669132943Sgshapiro		save_errno = errno;
7670132943Sgshapiro		p = CurHostName;
7671132943Sgshapiro		CurHostName = at;
7672132943Sgshapiro		if (tTd(38, 5))
7673132943Sgshapiro			sm_dprintf("socket_open (%s): open %s failed: %s\n",
7674132943Sgshapiro				map->map_mname, at, sm_errstring(save_errno));
7675132943Sgshapiro		CurHostName = p;
7676132943Sgshapiro		(void) close(sock);
7677132943Sgshapiro
7678132943Sgshapiro		/* try next address */
7679132943Sgshapiro		if (hp != NULL && hp->h_addr_list[addrno] != NULL)
7680132943Sgshapiro		{
7681132943Sgshapiro			switch (addr.sa.sa_family)
7682132943Sgshapiro			{
7683132943Sgshapiro# if NETINET
7684132943Sgshapiro			  case AF_INET:
7685132943Sgshapiro				memmove(&addr.sin.sin_addr,
7686132943Sgshapiro					hp->h_addr_list[addrno++],
7687132943Sgshapiro					INADDRSZ);
7688132943Sgshapiro				break;
7689132943Sgshapiro# endif /* NETINET */
7690132943Sgshapiro
7691132943Sgshapiro# if NETINET6
7692132943Sgshapiro			  case AF_INET6:
7693132943Sgshapiro				memmove(&addr.sin6.sin6_addr,
7694132943Sgshapiro					hp->h_addr_list[addrno++],
7695132943Sgshapiro					IN6ADDRSZ);
7696132943Sgshapiro				break;
7697132943Sgshapiro# endif /* NETINET6 */
7698132943Sgshapiro
7699132943Sgshapiro			  default:
7700132943Sgshapiro				if (tTd(38, 5))
7701132943Sgshapiro					sm_dprintf("socket map \"%s\": Unknown protocol for %s (%d)\n",
7702132943Sgshapiro						   map->map_mname, at,
7703132943Sgshapiro						   hp->h_addrtype);
7704132943Sgshapiro# if NETINET6
7705132943Sgshapiro				freehostent(hp);
7706132943Sgshapiro# endif /* NETINET6 */
7707132943Sgshapiro				return false;
7708132943Sgshapiro			}
7709132943Sgshapiro			continue;
7710132943Sgshapiro		}
7711132943Sgshapiro		p = CurHostName;
7712132943Sgshapiro		CurHostName = at;
7713132943Sgshapiro		if (tTd(38, 5))
7714132943Sgshapiro			sm_dprintf("socket map \"%s\": error connecting to socket map: %s\n",
7715132943Sgshapiro				   map->map_mname, sm_errstring(save_errno));
7716132943Sgshapiro		CurHostName = p;
7717132943Sgshapiro# if NETINET6
7718132943Sgshapiro		if (hp != NULL)
7719132943Sgshapiro			freehostent(hp);
7720132943Sgshapiro# endif /* NETINET6 */
7721132943Sgshapiro		return false;
7722132943Sgshapiro	}
7723132943Sgshapiro# if NETINET6
7724132943Sgshapiro	if (hp != NULL)
7725132943Sgshapiro	{
7726132943Sgshapiro		freehostent(hp);
7727132943Sgshapiro		hp = NULL;
7728132943Sgshapiro	}
7729132943Sgshapiro# endif /* NETINET6 */
7730132943Sgshapiro	if ((map->map_db1 = (ARBPTR_T) sm_io_open(SmFtStdiofd,
7731132943Sgshapiro						  SM_TIME_DEFAULT,
7732132943Sgshapiro						  (void *) &sock,
7733132943Sgshapiro						  SM_IO_RDWR,
7734132943Sgshapiro						  NULL)) == NULL)
7735132943Sgshapiro	{
7736132943Sgshapiro		close(sock);
7737132943Sgshapiro		if (tTd(38, 2))
7738132943Sgshapiro		    sm_dprintf("socket_open (%s): failed to create stream: %s\n",
7739132943Sgshapiro			       map->map_mname, sm_errstring(errno));
7740132943Sgshapiro		return false;
7741132943Sgshapiro	}
7742132943Sgshapiro
7743132943Sgshapiro	/* Save connection for reuse */
7744132943Sgshapiro	s->s_socketmap = map;
7745132943Sgshapiro	return true;
7746132943Sgshapiro}
7747132943Sgshapiro
7748132943Sgshapiro/*
7749132943Sgshapiro**  SOCKET_MAP_FINDCONN -- find a SOCKET connection to the server
7750132943Sgshapiro**
7751132943Sgshapiro**	Cache SOCKET connections based on the connection specifier
7752132943Sgshapiro**	and PID so we don't have multiple connections open to
7753132943Sgshapiro**	the same server for different maps.  Need a separate connection
7754132943Sgshapiro**	per PID since a parent process may close the map before the
7755132943Sgshapiro**	child is done with it.
7756132943Sgshapiro**
7757132943Sgshapiro**	Parameters:
7758132943Sgshapiro**		conn -- SOCKET map connection specifier
7759132943Sgshapiro**
7760132943Sgshapiro**	Returns:
7761132943Sgshapiro**		Symbol table entry for the SOCKET connection.
7762132943Sgshapiro*/
7763132943Sgshapiro
7764132943Sgshapirostatic STAB *
7765132943Sgshapirosocket_map_findconn(conn)
7766132943Sgshapiro	const char *conn;
7767132943Sgshapiro{
7768132943Sgshapiro	char *nbuf;
7769132943Sgshapiro	STAB *SM_NONVOLATILE s = NULL;
7770132943Sgshapiro
7771132943Sgshapiro	nbuf = sm_stringf_x("%s%c%d", conn, CONDELSE, (int) CurrentPid);
7772132943Sgshapiro	SM_TRY
7773132943Sgshapiro		s = stab(nbuf, ST_SOCKETMAP, ST_ENTER);
7774132943Sgshapiro	SM_FINALLY
7775132943Sgshapiro		sm_free(nbuf);
7776132943Sgshapiro	SM_END_TRY
7777132943Sgshapiro	return s;
7778132943Sgshapiro}
7779132943Sgshapiro
7780132943Sgshapiro/*
7781132943Sgshapiro**  SOCKET_MAP_CLOSE -- close the socket
7782132943Sgshapiro*/
7783132943Sgshapiro
7784132943Sgshapirovoid
7785132943Sgshapirosocket_map_close(map)
7786132943Sgshapiro	MAP *map;
7787132943Sgshapiro{
7788132943Sgshapiro	STAB *s;
7789132943Sgshapiro	MAP *smap;
7790132943Sgshapiro
7791132943Sgshapiro	if (tTd(38, 20))
7792132943Sgshapiro		sm_dprintf("socket_map_close(%s), pid=%ld\n", map->map_file,
7793132943Sgshapiro			(long) CurrentPid);
7794132943Sgshapiro
7795132943Sgshapiro	/* Check if already closed */
7796132943Sgshapiro	if (map->map_db1 == NULL)
7797132943Sgshapiro	{
7798132943Sgshapiro		if (tTd(38, 20))
7799132943Sgshapiro			sm_dprintf("socket_map_close(%s) already closed\n",
7800132943Sgshapiro				map->map_file);
7801132943Sgshapiro		return;
7802132943Sgshapiro	}
7803132943Sgshapiro	sm_io_close((SM_FILE_T *)map->map_db1, SM_TIME_DEFAULT);
7804132943Sgshapiro
7805132943Sgshapiro	/* Mark all the maps that share the connection as closed */
7806132943Sgshapiro	s = socket_map_findconn(map->map_file);
7807132943Sgshapiro	smap = s->s_socketmap;
7808132943Sgshapiro	while (smap != NULL)
7809132943Sgshapiro	{
7810132943Sgshapiro		MAP *next;
7811132943Sgshapiro
7812132943Sgshapiro		if (tTd(38, 2) && smap != map)
7813132943Sgshapiro			sm_dprintf("socket_map_close(%s): closed %s (shared SOCKET connection)\n",
7814132943Sgshapiro				map->map_mname, smap->map_mname);
7815132943Sgshapiro
7816132943Sgshapiro		smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
7817132943Sgshapiro		smap->map_db1 = NULL;
7818132943Sgshapiro		next = smap->socket_map_next;
7819132943Sgshapiro		smap->socket_map_next = NULL;
7820132943Sgshapiro		smap = next;
7821132943Sgshapiro	}
7822132943Sgshapiro	s->s_socketmap = NULL;
7823132943Sgshapiro}
7824132943Sgshapiro
7825132943Sgshapiro/*
7826132943Sgshapiro** SOCKET_MAP_LOOKUP -- look up a datum in a SOCKET table
7827132943Sgshapiro*/
7828132943Sgshapiro
7829132943Sgshapirochar *
7830132943Sgshapirosocket_map_lookup(map, name, av, statp)
7831132943Sgshapiro	MAP *map;
7832132943Sgshapiro	char *name;
7833132943Sgshapiro	char **av;
7834132943Sgshapiro	int *statp;
7835132943Sgshapiro{
7836132943Sgshapiro	unsigned int nettolen, replylen, recvlen;
7837147078Sgshapiro	char *replybuf, *rval, *value, *status, *key;
7838132943Sgshapiro	SM_FILE_T *f;
7839147078Sgshapiro	char keybuf[MAXNAME + 1];
7840132943Sgshapiro
7841132943Sgshapiro	replybuf = NULL;
7842132943Sgshapiro	rval = NULL;
7843132943Sgshapiro	f = (SM_FILE_T *)map->map_db1;
7844132943Sgshapiro	if (tTd(38, 20))
7845132943Sgshapiro		sm_dprintf("socket_map_lookup(%s, %s) %s\n",
7846132943Sgshapiro			map->map_mname, name, map->map_file);
7847132943Sgshapiro
7848147078Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
7849147078Sgshapiro	{
7850147078Sgshapiro		nettolen = strlen(name);
7851168515Sgshapiro		if (nettolen > sizeof(keybuf) - 1)
7852168515Sgshapiro			nettolen = sizeof(keybuf) - 1;
7853147078Sgshapiro		memmove(keybuf, name, nettolen);
7854147078Sgshapiro		keybuf[nettolen] = '\0';
7855147078Sgshapiro		makelower(keybuf);
7856147078Sgshapiro		key = keybuf;
7857147078Sgshapiro	}
7858147078Sgshapiro	else
7859147078Sgshapiro		key = name;
7860147078Sgshapiro
7861147078Sgshapiro	nettolen = strlen(map->map_mname) + 1 + strlen(key);
7862132943Sgshapiro	SM_ASSERT(nettolen > strlen(map->map_mname));
7863147078Sgshapiro	SM_ASSERT(nettolen > strlen(key));
7864132943Sgshapiro	if ((sm_io_fprintf(f, SM_TIME_DEFAULT, "%u:%s %s,",
7865147078Sgshapiro			   nettolen, map->map_mname, key) == SM_IO_EOF) ||
7866132943Sgshapiro	    (sm_io_flush(f, SM_TIME_DEFAULT) != 0) ||
7867132943Sgshapiro	    (sm_io_error(f)))
7868132943Sgshapiro	{
7869132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): failed to send lookup request",
7870132943Sgshapiro			map->map_mname);
7871132943Sgshapiro		*statp = EX_TEMPFAIL;
7872132943Sgshapiro		goto errcl;
7873132943Sgshapiro	}
7874132943Sgshapiro
7875132943Sgshapiro	if (sm_io_fscanf(f, SM_TIME_DEFAULT, "%9u", &replylen) != 1)
7876132943Sgshapiro	{
7877132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): failed to read length parameter of reply",
7878132943Sgshapiro			map->map_mname);
7879132943Sgshapiro		*statp = EX_TEMPFAIL;
7880132943Sgshapiro		goto errcl;
7881132943Sgshapiro	}
7882132943Sgshapiro	if (replylen > SOCKETMAP_MAXL)
7883132943Sgshapiro	{
7884132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): reply too long: %u",
7885132943Sgshapiro			   map->map_mname, replylen);
7886132943Sgshapiro		*statp = EX_TEMPFAIL;
7887132943Sgshapiro		goto errcl;
7888132943Sgshapiro	}
7889132943Sgshapiro	if (sm_io_getc(f, SM_TIME_DEFAULT) != ':')
7890132943Sgshapiro	{
7891132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): missing ':' in reply",
7892132943Sgshapiro			map->map_mname);
7893132943Sgshapiro		*statp = EX_TEMPFAIL;
7894132943Sgshapiro		goto error;
7895132943Sgshapiro	}
7896132943Sgshapiro
7897132943Sgshapiro	replybuf = (char *) sm_malloc(replylen + 1);
7898132943Sgshapiro	if (replybuf == NULL)
7899132943Sgshapiro	{
7900132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): can't allocate %u bytes",
7901132943Sgshapiro			map->map_mname, replylen + 1);
7902132943Sgshapiro		*statp = EX_OSERR;
7903132943Sgshapiro		goto error;
7904132943Sgshapiro	}
7905132943Sgshapiro
7906132943Sgshapiro	recvlen = sm_io_read(f, SM_TIME_DEFAULT, replybuf, replylen);
7907132943Sgshapiro	if (recvlen < replylen)
7908132943Sgshapiro	{
7909132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): received only %u of %u reply characters",
7910132943Sgshapiro			   map->map_mname, recvlen, replylen);
7911132943Sgshapiro		*statp = EX_TEMPFAIL;
7912132943Sgshapiro		goto errcl;
7913132943Sgshapiro	}
7914132943Sgshapiro	if (sm_io_getc(f, SM_TIME_DEFAULT) != ',')
7915132943Sgshapiro	{
7916132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): missing ',' in reply",
7917132943Sgshapiro			map->map_mname);
7918132943Sgshapiro		*statp = EX_TEMPFAIL;
7919132943Sgshapiro		goto errcl;
7920132943Sgshapiro	}
7921132943Sgshapiro	status = replybuf;
7922132943Sgshapiro	replybuf[recvlen] = '\0';
7923132943Sgshapiro	value = strchr(replybuf, ' ');
7924132943Sgshapiro	if (value != NULL)
7925132943Sgshapiro	{
7926132943Sgshapiro		*value = '\0';
7927132943Sgshapiro		value++;
7928132943Sgshapiro	}
7929132943Sgshapiro	if (strcmp(status, "OK") == 0)
7930132943Sgshapiro	{
7931132943Sgshapiro		*statp = EX_OK;
7932132943Sgshapiro
7933132943Sgshapiro		/* collect the return value */
7934132943Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
7935147078Sgshapiro			rval = map_rewrite(map, key, strlen(key), NULL);
7936132943Sgshapiro		else
7937132943Sgshapiro			rval = map_rewrite(map, value, strlen(value), av);
7938132943Sgshapiro	}
7939132943Sgshapiro	else if (strcmp(status, "NOTFOUND") == 0)
7940132943Sgshapiro	{
7941132943Sgshapiro		*statp = EX_NOTFOUND;
7942132943Sgshapiro		if (tTd(38, 20))
7943132943Sgshapiro			sm_dprintf("socket_map_lookup(%s): %s not found\n",
7944147078Sgshapiro				map->map_mname, key);
7945132943Sgshapiro	}
7946132943Sgshapiro	else
7947132943Sgshapiro	{
7948132943Sgshapiro		if (tTd(38, 5))
7949132943Sgshapiro			sm_dprintf("socket_map_lookup(%s, %s): server returned error: type=%s, reason=%s\n",
7950147078Sgshapiro				map->map_mname, key, status,
7951132943Sgshapiro				value ? value : "");
7952132943Sgshapiro		if ((strcmp(status, "TEMP") == 0) ||
7953132943Sgshapiro		    (strcmp(status, "TIMEOUT") == 0))
7954132943Sgshapiro			*statp = EX_TEMPFAIL;
7955132943Sgshapiro		else if(strcmp(status, "PERM") == 0)
7956132943Sgshapiro			*statp = EX_UNAVAILABLE;
7957132943Sgshapiro		else
7958132943Sgshapiro			*statp = EX_PROTOCOL;
7959132943Sgshapiro	}
7960132943Sgshapiro
7961132943Sgshapiro	if (replybuf != NULL)
7962132943Sgshapiro		sm_free(replybuf);
7963132943Sgshapiro	return rval;
7964132943Sgshapiro
7965132943Sgshapiro  errcl:
7966132943Sgshapiro	socket_map_close(map);
7967132943Sgshapiro  error:
7968132943Sgshapiro	if (replybuf != NULL)
7969132943Sgshapiro		sm_free(replybuf);
7970132943Sgshapiro	return rval;
7971132943Sgshapiro}
7972132943Sgshapiro#endif /* SOCKETMAP */
7973