map.c revision 249729
138032Speter/*
2203004Sgshapiro * Copyright (c) 1998-2008 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
16249729SgshapiroSM_RCSID("@(#)$Id: map.c,v 8.711 2013/03/12 15:24:52 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;
733203004Sgshapiro	auto int status = EX_UNAVAILABLE;
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;
1713203004Sgshapiro			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;
2362203004Sgshapiro			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>
2886249729Sgshapiro# ifndef NIS_TABLE_OBJ
2887249729Sgshapiro#  define NIS_TABLE_OBJ TABLE_OBJ
2888249729Sgshapiro# endif /* NIS_TABLE_OBJ */
288938032Speter
289064562Sgshapiro# define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
289164562Sgshapiro# define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
289264562Sgshapiro# define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
289364562Sgshapiro# define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
289438032Speter
289538032Speter/*
289638032Speter**  NISPLUS_MAP_OPEN -- open nisplus table
289738032Speter*/
289838032Speter
289938032Speterbool
290038032Speternisplus_map_open(map, mode)
290138032Speter	MAP *map;
290238032Speter	int mode;
290338032Speter{
290438032Speter	nis_result *res = NULL;
290538032Speter	int retry_cnt, max_col, i;
290638032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
290738032Speter
290838032Speter	if (tTd(38, 2))
290990792Sgshapiro		sm_dprintf("nisplus_map_open(%s, %s, %d)\n",
291038032Speter			map->map_mname, map->map_file, mode);
291138032Speter
291238032Speter	mode &= O_ACCMODE;
291338032Speter	if (mode != O_RDONLY)
291438032Speter	{
291538032Speter		errno = EPERM;
291690792Sgshapiro		return false;
291738032Speter	}
291838032Speter
291938032Speter	if (*map->map_file == '\0')
292038032Speter		map->map_file = "mail_aliases.org_dir";
292138032Speter
292238032Speter	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
292338032Speter	{
292438032Speter		/* set default NISPLUS Domain to $m */
292538032Speter		map->map_domain = newstr(nisplus_default_domain());
292638032Speter		if (tTd(38, 2))
292790792Sgshapiro			sm_dprintf("nisplus_map_open(%s): using domain %s\n",
292864562Sgshapiro				map->map_file, map->map_domain);
292938032Speter	}
293038032Speter	if (!PARTIAL_NAME(map->map_file))
293138032Speter	{
293238032Speter		map->map_domain = newstr("");
2933168515Sgshapiro		(void) sm_strlcpy(qbuf, map->map_file, sizeof(qbuf));
293438032Speter	}
293538032Speter	else
293638032Speter	{
293738032Speter		/* check to see if this map actually exists */
2938168515Sgshapiro		(void) sm_strlcpyn(qbuf, sizeof(qbuf), 3,
293990792Sgshapiro				   map->map_file, ".", map->map_domain);
294038032Speter	}
294138032Speter
294238032Speter	retry_cnt = 0;
294338032Speter	while (res == NULL || res->status != NIS_SUCCESS)
294438032Speter	{
294538032Speter		res = nis_lookup(qbuf, FOLLOW_LINKS);
294638032Speter		switch (res->status)
294738032Speter		{
294838032Speter		  case NIS_SUCCESS:
294938032Speter			break;
295038032Speter
295138032Speter		  case NIS_TRYAGAIN:
295238032Speter		  case NIS_RPCERROR:
295338032Speter		  case NIS_NAMEUNREACHABLE:
295438032Speter			if (retry_cnt++ > 4)
295538032Speter			{
295638032Speter				errno = EAGAIN;
295790792Sgshapiro				return false;
295838032Speter			}
295938032Speter			/* try not to overwhelm hosed server */
296038032Speter			sleep(2);
296138032Speter			break;
296238032Speter
296338032Speter		  default:		/* all other nisplus errors */
296464562Sgshapiro# if 0
296538032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
296694334Sgshapiro				syserr("451 4.3.5 Cannot find table %s.%s: %s",
296738032Speter					map->map_file, map->map_domain,
296838032Speter					nis_sperrno(res->status));
296964562Sgshapiro# endif /* 0 */
297038032Speter			errno = EAGAIN;
297190792Sgshapiro			return false;
297238032Speter		}
297338032Speter	}
297438032Speter
297538032Speter	if (NIS_RES_NUMOBJ(res) != 1 ||
2976249729Sgshapiro	    (NIS_RES_OBJECT(res)->zo_data.zo_type != NIS_TABLE_OBJ))
297738032Speter	{
297838032Speter		if (tTd(38, 10))
297990792Sgshapiro			sm_dprintf("nisplus_map_open: %s is not a table\n", qbuf);
298064562Sgshapiro# if 0
298138032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
298294334Sgshapiro			syserr("451 4.3.5 %s.%s: %s is not a table",
298338032Speter				map->map_file, map->map_domain,
298438032Speter				nis_sperrno(res->status));
298564562Sgshapiro# endif /* 0 */
298638032Speter		errno = EBADF;
298790792Sgshapiro		return false;
298838032Speter	}
298938032Speter	/* default key column is column 0 */
299038032Speter	if (map->map_keycolnm == NULL)
299138032Speter		map->map_keycolnm = newstr(COL_NAME(res,0));
299238032Speter
299338032Speter	max_col = COL_MAX(res);
299438032Speter
299538032Speter	/* verify the key column exist */
299690792Sgshapiro	for (i = 0; i < max_col; i++)
299738032Speter	{
299864562Sgshapiro		if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0)
299938032Speter			break;
300038032Speter	}
300138032Speter	if (i == max_col)
300238032Speter	{
300338032Speter		if (tTd(38, 2))
300490792Sgshapiro			sm_dprintf("nisplus_map_open(%s): can not find key column %s\n",
300538032Speter				map->map_file, map->map_keycolnm);
300638032Speter		errno = ENOENT;
300790792Sgshapiro		return false;
300838032Speter	}
300938032Speter
301038032Speter	/* default value column is the last column */
301138032Speter	if (map->map_valcolnm == NULL)
301238032Speter	{
301338032Speter		map->map_valcolno = max_col - 1;
301490792Sgshapiro		return true;
301538032Speter	}
301638032Speter
301764562Sgshapiro	for (i = 0; i< max_col; i++)
301838032Speter	{
301938032Speter		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
302038032Speter		{
302138032Speter			map->map_valcolno = i;
302290792Sgshapiro			return true;
302338032Speter		}
302438032Speter	}
302538032Speter
302638032Speter	if (tTd(38, 2))
302790792Sgshapiro		sm_dprintf("nisplus_map_open(%s): can not find column %s\n",
302864562Sgshapiro			map->map_file, map->map_keycolnm);
302938032Speter	errno = ENOENT;
303090792Sgshapiro	return false;
303138032Speter}
303238032Speter
303338032Speter
303438032Speter/*
303538032Speter**  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
303638032Speter*/
303738032Speter
303838032Speterchar *
303938032Speternisplus_map_lookup(map, name, av, statp)
304038032Speter	MAP *map;
304138032Speter	char *name;
304238032Speter	char **av;
304338032Speter	int *statp;
304438032Speter{
304538032Speter	char *p;
304638032Speter	auto int vsize;
304738032Speter	char *skp;
304838032Speter	int skleft;
304938032Speter	char search_key[MAXNAME + 4];
305038032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
305138032Speter	nis_result *result;
305238032Speter
305338032Speter	if (tTd(38, 20))
305490792Sgshapiro		sm_dprintf("nisplus_map_lookup(%s, %s)\n",
305538032Speter			map->map_mname, name);
305638032Speter
305738032Speter	if (!bitset(MF_OPEN, map->map_mflags))
305838032Speter	{
305938032Speter		if (nisplus_map_open(map, O_RDONLY))
306042575Speter		{
306138032Speter			map->map_mflags |= MF_OPEN;
306290792Sgshapiro			map->map_pid = CurrentPid;
306342575Speter		}
306438032Speter		else
306538032Speter		{
306638032Speter			*statp = EX_UNAVAILABLE;
306738032Speter			return NULL;
306838032Speter		}
306938032Speter	}
307038032Speter
307138032Speter	/*
307238032Speter	**  Copy the name to the key buffer, escaping double quote characters
307338032Speter	**  by doubling them and quoting "]" and "," to avoid having the
307438032Speter	**  NIS+ parser choke on them.
307538032Speter	*/
307638032Speter
3077168515Sgshapiro	skleft = sizeof(search_key) - 4;
307838032Speter	skp = search_key;
307938032Speter	for (p = name; *p != '\0' && skleft > 0; p++)
308038032Speter	{
308138032Speter		switch (*p)
308238032Speter		{
308338032Speter		  case ']':
308438032Speter		  case ',':
308538032Speter			/* quote the character */
308638032Speter			*skp++ = '"';
308738032Speter			*skp++ = *p;
308838032Speter			*skp++ = '"';
308938032Speter			skleft -= 3;
309038032Speter			break;
309138032Speter
309238032Speter		  case '"':
309338032Speter			/* double the quote */
309438032Speter			*skp++ = '"';
309538032Speter			skleft--;
309664562Sgshapiro			/* FALLTHROUGH */
309738032Speter
309838032Speter		  default:
309938032Speter			*skp++ = *p;
310038032Speter			skleft--;
310138032Speter			break;
310238032Speter		}
310338032Speter	}
310438032Speter	*skp = '\0';
310538032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
310638032Speter		makelower(search_key);
310738032Speter
310838032Speter	/* construct the query */
310938032Speter	if (PARTIAL_NAME(map->map_file))
3110168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf), "[%s=%s],%s.%s",
311138032Speter			map->map_keycolnm, search_key, map->map_file,
311238032Speter			map->map_domain);
311338032Speter	else
3114168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf), "[%s=%s],%s",
311538032Speter			map->map_keycolnm, search_key, map->map_file);
311638032Speter
311738032Speter	if (tTd(38, 20))
311890792Sgshapiro		sm_dprintf("qbuf=%s\n", qbuf);
311938032Speter	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
312038032Speter	if (result->status == NIS_SUCCESS)
312138032Speter	{
312238032Speter		int count;
312338032Speter		char *str;
312438032Speter
312538032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
312638032Speter		{
312738032Speter			if (LogLevel > 10)
312838032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
312964562Sgshapiro					  "%s: lookup error, expected 1 entry, got %d",
313064562Sgshapiro					  map->map_file, count);
313138032Speter
313238032Speter			/* ignore second entry */
313338032Speter			if (tTd(38, 20))
313490792Sgshapiro				sm_dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
313538032Speter					name, count);
313638032Speter		}
313738032Speter
313838032Speter		p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
313938032Speter		/* set the length of the result */
314038032Speter		if (p == NULL)
314138032Speter			p = "";
314238032Speter		vsize = strlen(p);
314338032Speter		if (tTd(38, 20))
314490792Sgshapiro			sm_dprintf("nisplus_map_lookup(%s), found %s\n",
314538032Speter				name, p);
314638032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
314738032Speter			str = map_rewrite(map, name, strlen(name), NULL);
314838032Speter		else
314938032Speter			str = map_rewrite(map, p, vsize, av);
315038032Speter		nis_freeresult(result);
315138032Speter		*statp = EX_OK;
315238032Speter		return str;
315338032Speter	}
315438032Speter	else
315538032Speter	{
315638032Speter		if (result->status == NIS_NOTFOUND)
315738032Speter			*statp = EX_NOTFOUND;
315838032Speter		else if (result->status == NIS_TRYAGAIN)
315938032Speter			*statp = EX_TEMPFAIL;
316038032Speter		else
316138032Speter		{
316238032Speter			*statp = EX_UNAVAILABLE;
316338032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
316438032Speter		}
316538032Speter	}
316638032Speter	if (tTd(38, 20))
316790792Sgshapiro		sm_dprintf("nisplus_map_lookup(%s), failed\n", name);
316838032Speter	nis_freeresult(result);
316938032Speter	return NULL;
317038032Speter}
317138032Speter
317238032Speter
317338032Speter
317438032Speter/*
317538032Speter**  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
317638032Speter*/
317738032Speter
317864562Sgshapirostatic bool
317938032Speternisplus_getcanonname(name, hbsize, statp)
318038032Speter	char *name;
318138032Speter	int hbsize;
318238032Speter	int *statp;
318338032Speter{
318438032Speter	char *vp;
318538032Speter	auto int vsize;
318638032Speter	nis_result *result;
318738032Speter	char *p;
318838032Speter	char nbuf[MAXNAME + 1];
318938032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
319038032Speter
3191168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
319238032Speter	{
319338032Speter		*statp = EX_UNAVAILABLE;
319490792Sgshapiro		return false;
319538032Speter	}
319673188Sgshapiro	(void) shorten_hostname(nbuf);
319738032Speter
319838032Speter	p = strchr(nbuf, '.');
319938032Speter	if (p == NULL)
320038032Speter	{
320138032Speter		/* single token */
3202168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf),
320390792Sgshapiro			"[name=%s],hosts.org_dir", nbuf);
320438032Speter	}
320538032Speter	else if (p[1] != '\0')
320638032Speter	{
320738032Speter		/* multi token -- take only first token in nbuf */
320838032Speter		*p = '\0';
3209168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf),
321090792Sgshapiro				   "[name=%s],hosts.org_dir.%s", nbuf, &p[1]);
321138032Speter	}
321238032Speter	else
321338032Speter	{
321438032Speter		*statp = EX_NOHOST;
321590792Sgshapiro		return false;
321638032Speter	}
321738032Speter
321838032Speter	if (tTd(38, 20))
321994334Sgshapiro		sm_dprintf("\nnisplus_getcanonname(%s), qbuf=%s\n",
322090792Sgshapiro			   name, qbuf);
322138032Speter
322238032Speter	result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
322390792Sgshapiro			  NULL, NULL);
322438032Speter
322538032Speter	if (result->status == NIS_SUCCESS)
322638032Speter	{
322738032Speter		int count;
322838032Speter		char *domain;
322938032Speter
323038032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
323138032Speter		{
323238032Speter			if (LogLevel > 10)
323338032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
323464562Sgshapiro					  "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
323564562Sgshapiro					  count);
323638032Speter
323738032Speter			/* ignore second entry */
323838032Speter			if (tTd(38, 20))
323994334Sgshapiro				sm_dprintf("nisplus_getcanonname(%s), got %d entries, all but first ignored\n",
324090792Sgshapiro					   name, count);
324138032Speter		}
324238032Speter
324338032Speter		if (tTd(38, 20))
324494334Sgshapiro			sm_dprintf("nisplus_getcanonname(%s), found in directory \"%s\"\n",
324590792Sgshapiro				   name, (NIS_RES_OBJECT(result))->zo_domain);
324638032Speter
324738032Speter
324838032Speter		vp = ((NIS_RES_OBJECT(result))->EN_col(0));
324938032Speter		vsize = strlen(vp);
325038032Speter		if (tTd(38, 20))
325190792Sgshapiro			sm_dprintf("nisplus_getcanonname(%s), found %s\n",
325290792Sgshapiro				   name, vp);
325338032Speter		if (strchr(vp, '.') != NULL)
325438032Speter		{
325538032Speter			domain = "";
325638032Speter		}
325738032Speter		else
325838032Speter		{
325938032Speter			domain = macvalue('m', CurEnv);
326038032Speter			if (domain == NULL)
326138032Speter				domain = "";
326238032Speter		}
326338032Speter		if (hbsize > vsize + (int) strlen(domain) + 1)
326438032Speter		{
326538032Speter			if (domain[0] == '\0')
326690792Sgshapiro				(void) sm_strlcpy(name, vp, hbsize);
326738032Speter			else
326890792Sgshapiro				(void) sm_snprintf(name, hbsize,
326990792Sgshapiro						   "%s.%s", vp, domain);
327038032Speter			*statp = EX_OK;
327138032Speter		}
327238032Speter		else
327338032Speter			*statp = EX_NOHOST;
327438032Speter		nis_freeresult(result);
327590792Sgshapiro		return true;
327638032Speter	}
327738032Speter	else
327838032Speter	{
327938032Speter		if (result->status == NIS_NOTFOUND)
328038032Speter			*statp = EX_NOHOST;
328138032Speter		else if (result->status == NIS_TRYAGAIN)
328238032Speter			*statp = EX_TEMPFAIL;
328338032Speter		else
328438032Speter			*statp = EX_UNAVAILABLE;
328538032Speter	}
328638032Speter	if (tTd(38, 20))
328790792Sgshapiro		sm_dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
328890792Sgshapiro			   name, result->status, *statp);
328938032Speter	nis_freeresult(result);
329090792Sgshapiro	return false;
329138032Speter}
329238032Speter
329338032Speterchar *
329438032Speternisplus_default_domain()
329538032Speter{
329638032Speter	static char default_domain[MAXNAME + 1] = "";
329738032Speter	char *p;
329838032Speter
329938032Speter	if (default_domain[0] != '\0')
330064562Sgshapiro		return default_domain;
330138032Speter
330238032Speter	p = nis_local_directory();
3303168515Sgshapiro	(void) sm_strlcpy(default_domain, p, sizeof(default_domain));
330438032Speter	return default_domain;
330538032Speter}
330638032Speter
330738032Speter#endif /* NISPLUS */
330890792Sgshapiro/*
330938032Speter**  LDAP Modules
331038032Speter*/
331138032Speter
331264562Sgshapiro/*
331364562Sgshapiro**  LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs
331464562Sgshapiro*/
331564562Sgshapiro
331664562Sgshapiro#if defined(LDAPMAP) || defined(PH_MAP)
331764562Sgshapiro
331890792Sgshapiro# if PH_MAP
331964562Sgshapiro#  define ph_map_dequote ldapmap_dequote
332064562Sgshapiro# endif /* PH_MAP */
332164562Sgshapiro
332290792Sgshapirostatic char *ldapmap_dequote __P((char *));
332390792Sgshapiro
332490792Sgshapirostatic char *
332564562Sgshapiroldapmap_dequote(str)
332664562Sgshapiro	char *str;
332764562Sgshapiro{
332864562Sgshapiro	char *p;
332964562Sgshapiro	char *start;
333064562Sgshapiro
333164562Sgshapiro	if (str == NULL)
333264562Sgshapiro		return NULL;
333364562Sgshapiro
333464562Sgshapiro	p = str;
333564562Sgshapiro	if (*p == '"')
333664562Sgshapiro	{
333764562Sgshapiro		/* Should probably swallow initial whitespace here */
333864562Sgshapiro		start = ++p;
333964562Sgshapiro	}
334064562Sgshapiro	else
334164562Sgshapiro		return str;
334264562Sgshapiro	while (*p != '"' && *p != '\0')
334364562Sgshapiro		p++;
334464562Sgshapiro	if (*p != '\0')
334564562Sgshapiro		*p = '\0';
334664562Sgshapiro	return start;
334764562Sgshapiro}
334864562Sgshapiro#endif /* defined(LDAPMAP) || defined(PH_MAP) */
334964562Sgshapiro
335090792Sgshapiro#if LDAPMAP
335138032Speter
335290792Sgshapirostatic SM_LDAP_STRUCT *LDAPDefaults = NULL;
335338032Speter
335438032Speter/*
335564562Sgshapiro**  LDAPMAP_OPEN -- open LDAP map
335638032Speter**
335764562Sgshapiro**	Connect to the LDAP server.  Re-use existing connections since a
335864562Sgshapiro**	single server connection to a host (with the same host, port,
335964562Sgshapiro**	bind DN, and secret) can answer queries for multiple maps.
336038032Speter*/
336138032Speter
336238032Speterbool
336364562Sgshapiroldapmap_open(map, mode)
336438032Speter	MAP *map;
336538032Speter	int mode;
336638032Speter{
336790792Sgshapiro	SM_LDAP_STRUCT *lmap;
336864562Sgshapiro	STAB *s;
3369132943Sgshapiro	char *id;
337064562Sgshapiro
337138032Speter	if (tTd(38, 2))
337290792Sgshapiro		sm_dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode);
337338032Speter
3374168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && \
3375168515Sgshapiro    HASLDAPGETALIASBYNAME
3376168515Sgshapiro	if (VendorCode == VENDOR_SUN &&
3377168515Sgshapiro	    strcmp(map->map_mname, "aliases.ldap") == 0)
3378168515Sgshapiro	{
3379168515Sgshapiro		return true;
3380168515Sgshapiro	}
3381168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && ... */
3382168515Sgshapiro
338338032Speter	mode &= O_ACCMODE;
338464562Sgshapiro
338564562Sgshapiro	/* sendmail doesn't have the ability to write to LDAP (yet) */
338638032Speter	if (mode != O_RDONLY)
338738032Speter	{
338838032Speter		/* issue a pseudo-error message */
338990792Sgshapiro		errno = SM_EMAPCANTWRITE;
339090792Sgshapiro		return false;
339138032Speter	}
339264562Sgshapiro
339390792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
339464562Sgshapiro
339564562Sgshapiro	s = ldapmap_findconn(lmap);
339677349Sgshapiro	if (s->s_lmap != NULL)
339764562Sgshapiro	{
339864562Sgshapiro		/* Already have a connection open to this LDAP server */
339990792Sgshapiro		lmap->ldap_ld = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_ld;
340090792Sgshapiro		lmap->ldap_pid = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_pid;
340177349Sgshapiro
340277349Sgshapiro		/* Add this map as head of linked list */
340377349Sgshapiro		lmap->ldap_next = s->s_lmap;
340477349Sgshapiro		s->s_lmap = map;
340577349Sgshapiro
340666494Sgshapiro		if (tTd(38, 2))
340790792Sgshapiro			sm_dprintf("using cached connection\n");
340890792Sgshapiro		return true;
340964562Sgshapiro	}
341064562Sgshapiro
341166494Sgshapiro	if (tTd(38, 2))
341290792Sgshapiro		sm_dprintf("opening new connection\n");
341366494Sgshapiro
3414132943Sgshapiro	if (lmap->ldap_host != NULL)
3415132943Sgshapiro		id = lmap->ldap_host;
3416132943Sgshapiro	else if (lmap->ldap_uri != NULL)
3417132943Sgshapiro		id = lmap->ldap_uri;
3418132943Sgshapiro	else
3419132943Sgshapiro		id = "localhost";
3420132943Sgshapiro
3421203004Sgshapiro	if (tTd(74, 104))
3422203004Sgshapiro	{
3423203004Sgshapiro		extern MAPCLASS NullMapClass;
3424203004Sgshapiro
3425203004Sgshapiro		/* debug mode: don't actually open an LDAP connection */
3426203004Sgshapiro		map->map_orgclass = map->map_class;
3427203004Sgshapiro		map->map_class = &NullMapClass;
3428203004Sgshapiro		map->map_mflags |= MF_OPEN;
3429203004Sgshapiro		map->map_pid = CurrentPid;
3430203004Sgshapiro		return true;
3431203004Sgshapiro	}
3432203004Sgshapiro
343364562Sgshapiro	/* No connection yet, connect */
343490792Sgshapiro	if (!sm_ldap_start(map->map_mname, lmap))
343538032Speter	{
343690792Sgshapiro		if (errno == ETIMEDOUT)
343738032Speter		{
343838032Speter			if (LogLevel > 1)
343938032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
3440244833Sgshapiro					  "timeout connecting to LDAP server %.100s",
3441132943Sgshapiro					  id);
344238032Speter		}
344338032Speter
344438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
344538032Speter		{
344664562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
3447132943Sgshapiro			{
344864562Sgshapiro				syserr("%s failed to %s in map %s",
344964562Sgshapiro# if USE_LDAP_INIT
345090792Sgshapiro				       "ldap_init/ldap_bind",
345164562Sgshapiro# else /* USE_LDAP_INIT */
345264562Sgshapiro				       "ldap_open",
345364562Sgshapiro# endif /* USE_LDAP_INIT */
3454132943Sgshapiro				       id, map->map_mname);
3455132943Sgshapiro			}
345664562Sgshapiro			else
3457132943Sgshapiro			{
345894334Sgshapiro				syserr("451 4.3.5 %s failed to %s in map %s",
345964562Sgshapiro# if USE_LDAP_INIT
346090792Sgshapiro				       "ldap_init/ldap_bind",
346164562Sgshapiro# else /* USE_LDAP_INIT */
346264562Sgshapiro				       "ldap_open",
346364562Sgshapiro# endif /* USE_LDAP_INIT */
3464132943Sgshapiro				       id, map->map_mname);
3465132943Sgshapiro			}
346638032Speter		}
346790792Sgshapiro		return false;
346838032Speter	}
346938032Speter
347090792Sgshapiro	/* Save connection for reuse */
347190792Sgshapiro	s->s_lmap = map;
347290792Sgshapiro	return true;
347338032Speter}
347438032Speter
347538032Speter/*
347664562Sgshapiro**  LDAPMAP_CLOSE -- close ldap map
347738032Speter*/
347838032Speter
347938032Spetervoid
348064562Sgshapiroldapmap_close(map)
348138032Speter	MAP *map;
348238032Speter{
348390792Sgshapiro	SM_LDAP_STRUCT *lmap;
348464562Sgshapiro	STAB *s;
348543730Speter
348664562Sgshapiro	if (tTd(38, 2))
348790792Sgshapiro		sm_dprintf("ldapmap_close(%s)\n", map->map_mname);
348864562Sgshapiro
348990792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
349064562Sgshapiro
349164562Sgshapiro	/* Check if already closed */
349264562Sgshapiro	if (lmap->ldap_ld == NULL)
349364562Sgshapiro		return;
349464562Sgshapiro
349577349Sgshapiro	/* Close the LDAP connection */
349690792Sgshapiro	sm_ldap_close(lmap);
349777349Sgshapiro
349877349Sgshapiro	/* Mark all the maps that share the connection as closed */
349964562Sgshapiro	s = ldapmap_findconn(lmap);
350064562Sgshapiro
350177349Sgshapiro	while (s->s_lmap != NULL)
350277349Sgshapiro	{
350377349Sgshapiro		MAP *smap = s->s_lmap;
350464562Sgshapiro
350577349Sgshapiro		if (tTd(38, 2) && smap != map)
350690792Sgshapiro			sm_dprintf("ldapmap_close(%s): closed %s (shared LDAP connection)\n",
350790792Sgshapiro				   map->map_mname, smap->map_mname);
350877349Sgshapiro		smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
350990792Sgshapiro		lmap = (SM_LDAP_STRUCT *) smap->map_db1;
351064562Sgshapiro		lmap->ldap_ld = NULL;
351177349Sgshapiro		s->s_lmap = lmap->ldap_next;
351277349Sgshapiro		lmap->ldap_next = NULL;
351343730Speter	}
351438032Speter}
351538032Speter
351664562Sgshapiro# ifdef SUNET_ID
351743730Speter/*
351890792Sgshapiro**  SUNET_ID_HASH -- Convert a string to its Sunet_id canonical form
351942575Speter**  This only makes sense at Stanford University.
352038032Speter*/
352138032Speter
352290792Sgshapirostatic char *
352338032Spetersunet_id_hash(str)
352438032Speter	char *str;
352538032Speter{
352638032Speter	char *p, *p_last;
352738032Speter
352838032Speter	p = str;
352938032Speter	p_last = p;
353038032Speter	while (*p != '\0')
353138032Speter	{
3532203004Sgshapiro		if (isascii(*p) && (islower(*p) || isdigit(*p)))
353338032Speter		{
353438032Speter			*p_last = *p;
353538032Speter			p_last++;
353638032Speter		}
3537203004Sgshapiro		else if (isascii(*p) && isupper(*p))
353838032Speter		{
353938032Speter			*p_last = tolower(*p);
354038032Speter			p_last++;
354138032Speter		}
354238032Speter		++p;
354338032Speter	}
354438032Speter	if (*p_last != '\0')
354538032Speter		*p_last = '\0';
354664562Sgshapiro	return str;
354738032Speter}
3548168515Sgshapiro#  define SM_CONVERT_ID(str)	sunet_id_hash(str)
3549168515Sgshapiro# else /* SUNET_ID */
3550168515Sgshapiro#  define SM_CONVERT_ID(str)	makelower(str)
355164562Sgshapiro# endif /* SUNET_ID */
355238032Speter
355338032Speter/*
355464562Sgshapiro**  LDAPMAP_LOOKUP -- look up a datum in a LDAP map
355538032Speter*/
355638032Speter
355738032Speterchar *
355864562Sgshapiroldapmap_lookup(map, name, av, statp)
355938032Speter	MAP *map;
356038032Speter	char *name;
356138032Speter	char **av;
356238032Speter	int *statp;
356338032Speter{
3564132943Sgshapiro	int flags;
3565168515Sgshapiro	int i;
356694334Sgshapiro	int plen = 0;
356794334Sgshapiro	int psize = 0;
356864562Sgshapiro	int msgid;
356990792Sgshapiro	int save_errno;
357090792Sgshapiro	char *vp, *p;
357164562Sgshapiro	char *result = NULL;
3572132943Sgshapiro	SM_RPOOL_T *rpool;
357390792Sgshapiro	SM_LDAP_STRUCT *lmap = NULL;
3574168515Sgshapiro	char *argv[SM_LDAP_ARGS];
3575157001Sgshapiro	char keybuf[MAXKEY];
3576168515Sgshapiro#if SM_LDAP_ARGS != MAX_MAP_ARGS
3577168515Sgshapiro# ERROR _SM_LDAP_ARGS must be the same as _MAX_MAP_ARGS
3578168515Sgshapiro#endif /* SM_LDAP_ARGS != MAX_MAP_ARGS */
357938032Speter
3580168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && \
3581168515Sgshapiro    HASLDAPGETALIASBYNAME
3582168515Sgshapiro	if (VendorCode == VENDOR_SUN &&
3583168515Sgshapiro	    strcmp(map->map_mname, "aliases.ldap") == 0)
3584168515Sgshapiro	{
3585168515Sgshapiro		int rc;
3586173340Sgshapiro#if defined(GETLDAPALIASBYNAME_VERSION) && (GETLDAPALIASBYNAME_VERSION >= 2)
3587173340Sgshapiro		extern char *__getldapaliasbyname();
3588173340Sgshapiro		char *answer;
358938032Speter
3590173340Sgshapiro		answer = __getldapaliasbyname(name, &rc);
3591173340Sgshapiro#else
3592173340Sgshapiro		char answer[MAXNAME + 1];
3593173340Sgshapiro
3594168515Sgshapiro		rc = __getldapaliasbyname(name, answer, sizeof(answer));
3595173340Sgshapiro#endif
3596168515Sgshapiro		if (rc != 0)
3597168515Sgshapiro		{
3598168515Sgshapiro			if (tTd(38, 20))
3599168515Sgshapiro				sm_dprintf("getldapaliasbyname(%.100s) failed, errno=%d\n",
3600168515Sgshapiro					   name, errno);
3601168515Sgshapiro			*statp = EX_NOTFOUND;
3602168515Sgshapiro			return NULL;
3603168515Sgshapiro		}
3604168515Sgshapiro		*statp = EX_OK;
3605168515Sgshapiro		if (tTd(38, 20))
3606168515Sgshapiro			sm_dprintf("getldapaliasbyname(%.100s) => %s\n", name,
3607168515Sgshapiro				   answer);
3608168515Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
3609168515Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
3610168515Sgshapiro		else
3611168515Sgshapiro			result = map_rewrite(map, answer, strlen(answer), av);
3612173340Sgshapiro#if defined(GETLDAPALIASBYNAME_VERSION) && (GETLDAPALIASBYNAME_VERSION >= 2)
3613173340Sgshapiro		free(answer);
3614173340Sgshapiro#endif
3615168515Sgshapiro		return result;
3616168515Sgshapiro	}
3617168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && ... */
3618168515Sgshapiro
361938032Speter	/* Get ldap struct pointer from map */
362090792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
362190792Sgshapiro	sm_ldap_setopts(lmap->ldap_ld, lmap);
362238032Speter
3623168515Sgshapiro	if (lmap->ldap_multi_args)
3624168515Sgshapiro	{
3625168515Sgshapiro		SM_REQUIRE(av != NULL);
3626168515Sgshapiro		memset(argv, '\0', sizeof(argv));
3627168515Sgshapiro		for (i = 0; i < SM_LDAP_ARGS && av[i] != NULL; i++)
3628168515Sgshapiro		{
3629168515Sgshapiro			argv[i] = sm_strdup(av[i]);
3630168515Sgshapiro			if (argv[i] == NULL)
3631168515Sgshapiro			{
3632168515Sgshapiro				int save_errno, j;
363338032Speter
3634168515Sgshapiro				save_errno = errno;
3635168515Sgshapiro				for (j = 0; j < i && argv[j] != NULL; j++)
3636168515Sgshapiro					SM_FREE(argv[j]);
3637168515Sgshapiro				*statp = EX_TEMPFAIL;
3638168515Sgshapiro				errno = save_errno;
3639168515Sgshapiro				return NULL;
3640168515Sgshapiro			}
3641168515Sgshapiro
3642168515Sgshapiro			if (!bitset(MF_NOFOLDCASE, map->map_mflags))
3643168515Sgshapiro				SM_CONVERT_ID(av[i]);
3644168515Sgshapiro		}
3645168515Sgshapiro	}
3646168515Sgshapiro	else
364764562Sgshapiro	{
3648168515Sgshapiro		(void) sm_strlcpy(keybuf, name, sizeof(keybuf));
3649168515Sgshapiro
3650168515Sgshapiro		if (!bitset(MF_NOFOLDCASE, map->map_mflags))
3651168515Sgshapiro			SM_CONVERT_ID(keybuf);
365264562Sgshapiro	}
365338032Speter
3654168515Sgshapiro	if (tTd(38, 20))
365538032Speter	{
3656168515Sgshapiro		if (lmap->ldap_multi_args)
3657168515Sgshapiro		{
3658168515Sgshapiro			sm_dprintf("ldapmap_lookup(%s, argv)\n",
3659168515Sgshapiro				map->map_mname);
3660168515Sgshapiro			for (i = 0; i < SM_LDAP_ARGS; i++)
3661168515Sgshapiro			{
3662168515Sgshapiro				sm_dprintf("   argv[%d] = %s\n", i,
3663168515Sgshapiro					   argv[i] == NULL ? "NULL" : argv[i]);
3664168515Sgshapiro			}
3665168515Sgshapiro		}
3666168515Sgshapiro		else
3667168515Sgshapiro		{
3668168515Sgshapiro			sm_dprintf("ldapmap_lookup(%s, %s)\n",
3669168515Sgshapiro				   map->map_mname, name);
3670168515Sgshapiro		}
3671168515Sgshapiro	}
3672168515Sgshapiro
3673168515Sgshapiro	if (lmap->ldap_multi_args)
3674168515Sgshapiro	{
3675168515Sgshapiro		msgid = sm_ldap_search_m(lmap, argv);
3676168515Sgshapiro
3677168515Sgshapiro		/* free the argv array and its content, no longer needed */
3678168515Sgshapiro		for (i = 0; i < SM_LDAP_ARGS && argv[i] != NULL; i++)
3679168515Sgshapiro			SM_FREE(argv[i]);
3680168515Sgshapiro	}
3681168515Sgshapiro	else
3682168515Sgshapiro		msgid = sm_ldap_search(lmap, keybuf);
3683168515Sgshapiro	if (msgid == SM_LDAP_ERR)
3684168515Sgshapiro	{
368590792Sgshapiro		errno = sm_ldap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
368677349Sgshapiro		save_errno = errno;
368764562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
368838032Speter		{
3689168515Sgshapiro			/*
3690168515Sgshapiro			**  Do not include keybuf as this error may be shown
3691168515Sgshapiro			**  to outsiders.
3692168515Sgshapiro			*/
3693168515Sgshapiro
369464562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
3695168515Sgshapiro				syserr("Error in ldap_search in map %s",
3696168515Sgshapiro				       map->map_mname);
369764562Sgshapiro			else
3698168515Sgshapiro				syserr("451 4.3.5 Error in ldap_search in map %s",
3699168515Sgshapiro				       map->map_mname);
370038032Speter		}
370164562Sgshapiro		*statp = EX_TEMPFAIL;
370290792Sgshapiro		switch (save_errno - E_LDAPBASE)
370390792Sgshapiro		{
370494334Sgshapiro# ifdef LDAP_SERVER_DOWN
370590792Sgshapiro		  case LDAP_SERVER_DOWN:
370694334Sgshapiro# endif /* LDAP_SERVER_DOWN */
370790792Sgshapiro		  case LDAP_TIMEOUT:
370890792Sgshapiro		  case LDAP_UNAVAILABLE:
370966494Sgshapiro			/* server disappeared, try reopen on next search */
371077349Sgshapiro			ldapmap_close(map);
371190792Sgshapiro			break;
371266494Sgshapiro		}
371377349Sgshapiro		errno = save_errno;
371464562Sgshapiro		return NULL;
371564562Sgshapiro	}
3716168515Sgshapiro#if SM_LDAP_ERROR_ON_MISSING_ARGS
3717168515Sgshapiro	else if (msgid == SM_LDAP_ERR_ARG_MISS)
3718168515Sgshapiro	{
3719168515Sgshapiro		if (bitset(MF_NODEFER, map->map_mflags))
3720168515Sgshapiro			syserr("Error in ldap_search in map %s, too few arguments",
3721168515Sgshapiro			       map->map_mname);
3722168515Sgshapiro		else
3723168515Sgshapiro			syserr("554 5.3.5 Error in ldap_search in map %s, too few arguments",
3724168515Sgshapiro			       map->map_mname);
3725168515Sgshapiro		*statp = EX_CONFIG;
3726168515Sgshapiro		return NULL;
3727168515Sgshapiro	}
3728168515Sgshapiro#endif /* SM_LDAP_ERROR_ON_MISSING_ARGS */
372964562Sgshapiro
373064562Sgshapiro	*statp = EX_NOTFOUND;
373164562Sgshapiro	vp = NULL;
373264562Sgshapiro
3733132943Sgshapiro	flags = 0;
3734132943Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
3735132943Sgshapiro		flags |= SM_LDAP_SINGLEMATCH;
3736132943Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
3737132943Sgshapiro		flags |= SM_LDAP_MATCHONLY;
3738157001Sgshapiro# if _FFR_LDAP_SINGLEDN
3739157001Sgshapiro	if (bitset(MF_SINGLEDN, map->map_mflags))
3740157001Sgshapiro		flags |= SM_LDAP_SINGLEDN;
3741157001Sgshapiro# endif /* _FFR_LDAP_SINGLEDN */
374290792Sgshapiro
3743132943Sgshapiro	/* Create an rpool for search related memory usage */
3744132943Sgshapiro	rpool = sm_rpool_new_x(NULL);
374590792Sgshapiro
3746132943Sgshapiro	p = NULL;
3747132943Sgshapiro	*statp = sm_ldap_results(lmap, msgid, flags, map->map_coldelim,
3748132943Sgshapiro				 rpool, &p, &plen, &psize, NULL);
3749132943Sgshapiro	save_errno = errno;
375090792Sgshapiro
3751132943Sgshapiro	/* Copy result so rpool can be freed */
3752132943Sgshapiro	if (*statp == EX_OK && p != NULL)
3753132943Sgshapiro		vp = newstr(p);
3754132943Sgshapiro	sm_rpool_free(rpool);
375590792Sgshapiro
3756132943Sgshapiro	/* need to restart LDAP connection? */
3757132943Sgshapiro	if (*statp == EX_RESTART)
375864562Sgshapiro	{
3759132943Sgshapiro		*statp = EX_TEMPFAIL;
3760132943Sgshapiro		ldapmap_close(map);
376138032Speter	}
376238032Speter
3763132943Sgshapiro	errno = save_errno;
3764132943Sgshapiro	if (*statp != EX_OK && *statp != EX_NOTFOUND)
376538032Speter	{
376664562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
376764562Sgshapiro		{
376864562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
3769244833Sgshapiro				syserr("Error getting LDAP results, map=%s, name=%s",
3770244833Sgshapiro				       map->map_mname, name);
377164562Sgshapiro			else
3772244833Sgshapiro				syserr("451 4.3.5 Error getting LDAP results, map=%s, name=%s",
3773244833Sgshapiro				       map->map_mname, name);
377464562Sgshapiro		}
377577349Sgshapiro		errno = save_errno;
377664562Sgshapiro		return NULL;
377738032Speter	}
377890792Sgshapiro
377964562Sgshapiro	/* Did we match anything? */
378071345Sgshapiro	if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags))
378164562Sgshapiro		return NULL;
378238032Speter
378364562Sgshapiro	if (*statp == EX_OK)
378464562Sgshapiro	{
378564562Sgshapiro		if (LogLevel > 9)
378664562Sgshapiro			sm_syslog(LOG_INFO, CurEnv->e_id,
3787244833Sgshapiro				  "ldap=%s, %.100s=>%s", map->map_mname, name,
378871345Sgshapiro				  vp == NULL ? "<NULL>" : vp);
378964562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
379064562Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
379164562Sgshapiro		else
379271345Sgshapiro		{
379371345Sgshapiro			/* vp != NULL according to test above */
379464562Sgshapiro			result = map_rewrite(map, vp, strlen(vp), av);
379571345Sgshapiro		}
379671345Sgshapiro		if (vp != NULL)
379790792Sgshapiro			sm_free(vp); /* XXX */
379864562Sgshapiro	}
379964562Sgshapiro	return result;
380038032Speter}
380138032Speter
380238032Speter/*
380364562Sgshapiro**  LDAPMAP_FINDCONN -- find an LDAP connection to the server
380464562Sgshapiro**
380564562Sgshapiro**	Cache LDAP connections based on the host, port, bind DN,
380666494Sgshapiro**	secret, and PID so we don't have multiple connections open to
380766494Sgshapiro**	the same server for different maps.  Need a separate connection
380866494Sgshapiro**	per PID since a parent process may close the map before the
380966494Sgshapiro**	child is done with it.
381064562Sgshapiro**
381164562Sgshapiro**	Parameters:
381264562Sgshapiro**		lmap -- LDAP map information
381364562Sgshapiro**
381464562Sgshapiro**	Returns:
381564562Sgshapiro**		Symbol table entry for the LDAP connection.
381638032Speter*/
381738032Speter
381864562Sgshapirostatic STAB *
381964562Sgshapiroldapmap_findconn(lmap)
382090792Sgshapiro	SM_LDAP_STRUCT *lmap;
382138032Speter{
382294334Sgshapiro	char *format;
382364562Sgshapiro	char *nbuf;
3824132943Sgshapiro	char *id;
382590792Sgshapiro	STAB *SM_NONVOLATILE s = NULL;
382638032Speter
3827132943Sgshapiro	if (lmap->ldap_host != NULL)
3828132943Sgshapiro		id = lmap->ldap_host;
3829132943Sgshapiro	else if (lmap->ldap_uri != NULL)
3830132943Sgshapiro		id = lmap->ldap_uri;
3831132943Sgshapiro	else
3832132943Sgshapiro		id = "localhost";
3833132943Sgshapiro
383494334Sgshapiro	format = "%s%c%d%c%d%c%s%c%s%d";
383594334Sgshapiro	nbuf = sm_stringf_x(format,
3836132943Sgshapiro			    id,
383790792Sgshapiro			    CONDELSE,
383890792Sgshapiro			    lmap->ldap_port,
383990792Sgshapiro			    CONDELSE,
384094334Sgshapiro			    lmap->ldap_version,
384194334Sgshapiro			    CONDELSE,
384290792Sgshapiro			    (lmap->ldap_binddn == NULL ? ""
384390792Sgshapiro						       : lmap->ldap_binddn),
384490792Sgshapiro			    CONDELSE,
384590792Sgshapiro			    (lmap->ldap_secret == NULL ? ""
384690792Sgshapiro						       : lmap->ldap_secret),
384790792Sgshapiro			    (int) CurrentPid);
384890792Sgshapiro	SM_TRY
384990792Sgshapiro		s = stab(nbuf, ST_LMAP, ST_ENTER);
385090792Sgshapiro	SM_FINALLY
385190792Sgshapiro		sm_free(nbuf);
385290792Sgshapiro	SM_END_TRY
385364562Sgshapiro	return s;
385464562Sgshapiro}
385538032Speter/*
385664562Sgshapiro**  LDAPMAP_PARSEARGS -- parse ldap map definition args.
385764562Sgshapiro*/
385838032Speter
385990792Sgshapirostatic struct lamvalues LDAPAuthMethods[] =
386064562Sgshapiro{
386164562Sgshapiro	{	"none",		LDAP_AUTH_NONE		},
386264562Sgshapiro	{	"simple",	LDAP_AUTH_SIMPLE	},
386364562Sgshapiro# ifdef LDAP_AUTH_KRBV4
386464562Sgshapiro	{	"krbv4",	LDAP_AUTH_KRBV4		},
386564562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
386664562Sgshapiro	{	NULL,		0			}
386764562Sgshapiro};
386838032Speter
386990792Sgshapirostatic struct ladvalues LDAPAliasDereference[] =
387064562Sgshapiro{
387164562Sgshapiro	{	"never",	LDAP_DEREF_NEVER	},
387264562Sgshapiro	{	"always",	LDAP_DEREF_ALWAYS	},
387364562Sgshapiro	{	"search",	LDAP_DEREF_SEARCHING	},
387464562Sgshapiro	{	"find",		LDAP_DEREF_FINDING	},
387564562Sgshapiro	{	NULL,		0			}
387664562Sgshapiro};
387738032Speter
387890792Sgshapirostatic struct lssvalues LDAPSearchScope[] =
387964562Sgshapiro{
388064562Sgshapiro	{	"base",		LDAP_SCOPE_BASE		},
388164562Sgshapiro	{	"one",		LDAP_SCOPE_ONELEVEL	},
388264562Sgshapiro	{	"sub",		LDAP_SCOPE_SUBTREE	},
388364562Sgshapiro	{	NULL,		0			}
388464562Sgshapiro};
388538032Speter
388664562Sgshapirobool
388764562Sgshapiroldapmap_parseargs(map, args)
388864562Sgshapiro	MAP *map;
388964562Sgshapiro	char *args;
389064562Sgshapiro{
389190792Sgshapiro	bool secretread = true;
3892132943Sgshapiro	bool attrssetup = false;
389364562Sgshapiro	int i;
389464562Sgshapiro	register char *p = args;
389590792Sgshapiro	SM_LDAP_STRUCT *lmap;
389664562Sgshapiro	struct lamvalues *lam;
389764562Sgshapiro	struct ladvalues *lad;
389864562Sgshapiro	struct lssvalues *lss;
389990792Sgshapiro	char ldapfilt[MAXLINE];
390064562Sgshapiro	char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
390164562Sgshapiro
390264562Sgshapiro	/* Get ldap struct pointer from map */
390390792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
390464562Sgshapiro
390564562Sgshapiro	/* Check if setting the initial LDAP defaults */
390664562Sgshapiro	if (lmap == NULL || lmap != LDAPDefaults)
390764562Sgshapiro	{
390890792Sgshapiro		/* We need to alloc an SM_LDAP_STRUCT struct */
3909168515Sgshapiro		lmap = (SM_LDAP_STRUCT *) xalloc(sizeof(*lmap));
391064562Sgshapiro		if (LDAPDefaults == NULL)
391190792Sgshapiro			sm_ldap_clear(lmap);
391264562Sgshapiro		else
391364562Sgshapiro			STRUCTCOPY(*LDAPDefaults, *lmap);
391464562Sgshapiro	}
391564562Sgshapiro
391664562Sgshapiro	/* there is no check whether there is really an argument */
391764562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
391864562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
391990792Sgshapiro
392090792Sgshapiro	/* Check if setting up an alias or file class LDAP map */
392190792Sgshapiro	if (bitset(MF_ALIAS, map->map_mflags))
392290792Sgshapiro	{
392390792Sgshapiro		/* Comma separate if used as an alias file */
392490792Sgshapiro		map->map_coldelim = ',';
392590792Sgshapiro		if (*args == '\0')
392690792Sgshapiro		{
392790792Sgshapiro			int n;
392890792Sgshapiro			char *lc;
392990792Sgshapiro			char jbuf[MAXHOSTNAMELEN];
393090792Sgshapiro			char lcbuf[MAXLINE];
393190792Sgshapiro
393290792Sgshapiro			/* Get $j */
3933168515Sgshapiro			expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope);
393490792Sgshapiro			if (jbuf[0] == '\0')
393590792Sgshapiro			{
393690792Sgshapiro				(void) sm_strlcpy(jbuf, "localhost",
3937168515Sgshapiro						  sizeof(jbuf));
393890792Sgshapiro			}
393990792Sgshapiro
394090792Sgshapiro			lc = macvalue(macid("{sendmailMTACluster}"), CurEnv);
394190792Sgshapiro			if (lc == NULL)
394290792Sgshapiro				lc = "";
394390792Sgshapiro			else
394490792Sgshapiro			{
3945168515Sgshapiro				expand(lc, lcbuf, sizeof(lcbuf), CurEnv);
394690792Sgshapiro				lc = lcbuf;
394790792Sgshapiro			}
394890792Sgshapiro
3949168515Sgshapiro			n = sm_snprintf(ldapfilt, sizeof(ldapfilt),
395090792Sgshapiro					"(&(objectClass=sendmailMTAAliasObject)(sendmailMTAAliasGrouping=aliases)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))(sendmailMTAKey=%%0))",
395190792Sgshapiro					lc, jbuf);
3952168515Sgshapiro			if (n >= sizeof(ldapfilt))
395390792Sgshapiro			{
395490792Sgshapiro				syserr("%s: Default LDAP string too long",
395590792Sgshapiro				       map->map_mname);
395690792Sgshapiro				return false;
395790792Sgshapiro			}
395890792Sgshapiro
395990792Sgshapiro			/* default args for an alias LDAP entry */
396090792Sgshapiro			lmap->ldap_filter = ldapfilt;
3961132943Sgshapiro			lmap->ldap_attr[0] = "objectClass";
3962132943Sgshapiro			lmap->ldap_attr_type[0] = SM_LDAP_ATTR_OBJCLASS;
3963132943Sgshapiro			lmap->ldap_attr_needobjclass[0] = NULL;
3964132943Sgshapiro			lmap->ldap_attr[1] = "sendmailMTAAliasValue";
3965132943Sgshapiro			lmap->ldap_attr_type[1] = SM_LDAP_ATTR_NORMAL;
3966132943Sgshapiro			lmap->ldap_attr_needobjclass[1] = NULL;
3967132943Sgshapiro			lmap->ldap_attr[2] = "sendmailMTAAliasSearch";
3968132943Sgshapiro			lmap->ldap_attr_type[2] = SM_LDAP_ATTR_FILTER;
3969132943Sgshapiro			lmap->ldap_attr_needobjclass[2] = "sendmailMTAMapObject";
3970132943Sgshapiro			lmap->ldap_attr[3] = "sendmailMTAAliasURL";
3971132943Sgshapiro			lmap->ldap_attr_type[3] = SM_LDAP_ATTR_URL;
3972132943Sgshapiro			lmap->ldap_attr_needobjclass[3] = "sendmailMTAMapObject";
3973132943Sgshapiro			lmap->ldap_attr[4] = NULL;
3974132943Sgshapiro			lmap->ldap_attr_type[4] = SM_LDAP_ATTR_NONE;
3975132943Sgshapiro			lmap->ldap_attr_needobjclass[4] = NULL;
3976132943Sgshapiro			attrssetup = true;
397790792Sgshapiro		}
397890792Sgshapiro	}
397990792Sgshapiro	else if (bitset(MF_FILECLASS, map->map_mflags))
398090792Sgshapiro	{
398190792Sgshapiro		/* Space separate if used as a file class file */
398290792Sgshapiro		map->map_coldelim = ' ';
398390792Sgshapiro	}
398490792Sgshapiro
3985203004Sgshapiro# if _FFR_LDAP_NETWORK_TIMEOUT
3986203004Sgshapiro	lmap->ldap_networktmo = 120;
3987203004Sgshapiro# endif /* _FFR_LDAP_NETWORK_TIMEOUT */
3988203004Sgshapiro
398938032Speter	for (;;)
399038032Speter	{
399138032Speter		while (isascii(*p) && isspace(*p))
399238032Speter			p++;
399338032Speter		if (*p != '-')
399438032Speter			break;
399538032Speter		switch (*++p)
399638032Speter		{
3997173340Sgshapiro		  case 'A':
3998173340Sgshapiro			map->map_mflags |= MF_APPEND;
399938032Speter			break;
400038032Speter
4001173340Sgshapiro		  case 'a':
4002173340Sgshapiro			map->map_app = ++p;
400338032Speter			break;
400438032Speter
4005173340Sgshapiro		  case 'D':
4006173340Sgshapiro			map->map_mflags |= MF_DEFER;
400738032Speter			break;
400838032Speter
400938032Speter		  case 'f':
401038032Speter			map->map_mflags |= MF_NOFOLDCASE;
401138032Speter			break;
401238032Speter
401338032Speter		  case 'm':
401438032Speter			map->map_mflags |= MF_MATCHONLY;
401538032Speter			break;
401638032Speter
4017173340Sgshapiro		  case 'N':
4018173340Sgshapiro			map->map_mflags |= MF_INCLNULL;
4019173340Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
402038032Speter			break;
402138032Speter
4022173340Sgshapiro		  case 'O':
4023173340Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
4024173340Sgshapiro			break;
4025173340Sgshapiro
4026173340Sgshapiro		  case 'o':
4027173340Sgshapiro			map->map_mflags |= MF_OPTIONAL;
4028173340Sgshapiro			break;
4029173340Sgshapiro
403038032Speter		  case 'q':
403138032Speter			map->map_mflags |= MF_KEEPQUOTES;
403238032Speter			break;
403338032Speter
4034173340Sgshapiro		  case 'S':
4035173340Sgshapiro			map->map_spacesub = *++p;
403638032Speter			break;
403738032Speter
403838032Speter		  case 'T':
403938032Speter			map->map_tapp = ++p;
404038032Speter			break;
404138032Speter
404264562Sgshapiro		  case 't':
404364562Sgshapiro			map->map_mflags |= MF_NODEFER;
404464562Sgshapiro			break;
404564562Sgshapiro
404664562Sgshapiro		  case 'z':
404764562Sgshapiro			if (*++p != '\\')
404864562Sgshapiro				map->map_coldelim = *p;
404964562Sgshapiro			else
405064562Sgshapiro			{
405164562Sgshapiro				switch (*++p)
405264562Sgshapiro				{
405364562Sgshapiro				  case 'n':
405464562Sgshapiro					map->map_coldelim = '\n';
405564562Sgshapiro					break;
405664562Sgshapiro
405764562Sgshapiro				  case 't':
405864562Sgshapiro					map->map_coldelim = '\t';
405964562Sgshapiro					break;
406064562Sgshapiro
406164562Sgshapiro				  default:
406264562Sgshapiro					map->map_coldelim = '\\';
406364562Sgshapiro				}
406464562Sgshapiro			}
406564562Sgshapiro			break;
406664562Sgshapiro
406764562Sgshapiro			/* Start of ldapmap specific args */
4068173340Sgshapiro		  case '1':
4069173340Sgshapiro			map->map_mflags |= MF_SINGLEMATCH;
4070173340Sgshapiro			break;
407190792Sgshapiro
4072173340Sgshapiro# if _FFR_LDAP_SINGLEDN
4073173340Sgshapiro		  case '2':
4074173340Sgshapiro			map->map_mflags |= MF_SINGLEDN;
4075173340Sgshapiro			break;
4076173340Sgshapiro# endif /* _FFR_LDAP_SINGLEDN */
407790792Sgshapiro
4078173340Sgshapiro		  case 'b':		/* search base */
4079173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4080173340Sgshapiro				continue;
4081173340Sgshapiro			lmap->ldap_base = p;
4082173340Sgshapiro			break;
4083173340Sgshapiro
4084173340Sgshapiro# if _FFR_LDAP_NETWORK_TIMEOUT
4085173340Sgshapiro		  case 'c':		/* network (connect) timeout */
4086173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4087173340Sgshapiro				continue;
4088203004Sgshapiro			lmap->ldap_networktmo = atoi(p);
4089173340Sgshapiro			break;
4090173340Sgshapiro# endif /* _FFR_LDAP_NETWORK_TIMEOUT */
4091173340Sgshapiro
4092173340Sgshapiro		  case 'd':		/* Dn to bind to server as */
4093173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4094173340Sgshapiro				continue;
4095173340Sgshapiro			lmap->ldap_binddn = p;
4096173340Sgshapiro			break;
4097173340Sgshapiro
4098173340Sgshapiro		  case 'H':		/* Use LDAP URI */
4099173340Sgshapiro#  if !USE_LDAP_INIT
4100173340Sgshapiro			syserr("Must compile with -DUSE_LDAP_INIT to use LDAP URIs (-H) in map %s",
4101173340Sgshapiro			       map->map_mname);
4102173340Sgshapiro			return false;
4103173340Sgshapiro#   else /* !USE_LDAP_INIT */
4104173340Sgshapiro			if (lmap->ldap_host != NULL)
4105173340Sgshapiro			{
4106173340Sgshapiro				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
4107173340Sgshapiro				       map->map_mname);
4108173340Sgshapiro				return false;
410990792Sgshapiro			}
4110173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4111173340Sgshapiro				continue;
4112173340Sgshapiro			lmap->ldap_uri = p;
411390792Sgshapiro			break;
4114173340Sgshapiro#  endif /* !USE_LDAP_INIT */
411590792Sgshapiro
4116173340Sgshapiro		  case 'h':		/* ldap host */
4117173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4118173340Sgshapiro				continue;
4119173340Sgshapiro			if (lmap->ldap_uri != NULL)
4120173340Sgshapiro			{
4121173340Sgshapiro				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
4122173340Sgshapiro				       map->map_mname);
4123173340Sgshapiro				return false;
4124173340Sgshapiro			}
4125173340Sgshapiro			lmap->ldap_host = p;
4126173340Sgshapiro			break;
4127173340Sgshapiro
4128173340Sgshapiro		  case 'K':
4129173340Sgshapiro			lmap->ldap_multi_args = true;
4130173340Sgshapiro			break;
4131173340Sgshapiro
413238032Speter		  case 'k':		/* search field */
413338032Speter			while (isascii(*++p) && isspace(*p))
413438032Speter				continue;
413564562Sgshapiro			lmap->ldap_filter = p;
413638032Speter			break;
413738032Speter
4138173340Sgshapiro		  case 'l':		/* time limit */
413938032Speter			while (isascii(*++p) && isspace(*p))
414038032Speter				continue;
4141173340Sgshapiro			lmap->ldap_timelimit = atoi(p);
4142173340Sgshapiro			lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit;
414338032Speter			break;
414438032Speter
4145173340Sgshapiro		  case 'M':		/* Method for binding */
4146173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4147173340Sgshapiro				continue;
4148173340Sgshapiro
4149173340Sgshapiro			if (sm_strncasecmp(p, "LDAP_AUTH_", 10) == 0)
4150173340Sgshapiro				p += 10;
4151173340Sgshapiro
4152173340Sgshapiro			for (lam = LDAPAuthMethods;
4153173340Sgshapiro			     lam != NULL && lam->lam_name != NULL; lam++)
4154173340Sgshapiro			{
4155173340Sgshapiro				if (sm_strncasecmp(p, lam->lam_name,
4156173340Sgshapiro						   strlen(lam->lam_name)) == 0)
4157173340Sgshapiro					break;
4158173340Sgshapiro			}
4159173340Sgshapiro			if (lam->lam_name != NULL)
4160173340Sgshapiro				lmap->ldap_method = lam->lam_code;
4161173340Sgshapiro			else
4162173340Sgshapiro			{
4163173340Sgshapiro				/* bad config line */
4164173340Sgshapiro				if (!bitset(MCF_OPTFILE,
4165173340Sgshapiro					    map->map_class->map_cflags))
4166173340Sgshapiro				{
4167173340Sgshapiro					char *ptr;
4168173340Sgshapiro
4169173340Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
4170173340Sgshapiro						*ptr = '\0';
4171173340Sgshapiro					syserr("Method for binding must be [none|simple|krbv4] (not %s) in map %s",
4172173340Sgshapiro						p, map->map_mname);
4173173340Sgshapiro					if (ptr != NULL)
4174173340Sgshapiro						*ptr = ' ';
4175173340Sgshapiro					return false;
4176173340Sgshapiro				}
4177173340Sgshapiro			}
417864562Sgshapiro			break;
417964562Sgshapiro
4180173340Sgshapiro		  case 'n':		/* retrieve attribute names only */
4181173340Sgshapiro			lmap->ldap_attrsonly = LDAPMAP_TRUE;
4182157001Sgshapiro			break;
4183157001Sgshapiro
4184173340Sgshapiro			/*
4185173340Sgshapiro			**  This is a string that is dependent on the
4186173340Sgshapiro			**  method used defined by 'M'.
4187173340Sgshapiro			*/
4188173340Sgshapiro
4189173340Sgshapiro		  case 'P':		/* Secret password for binding */
4190173340Sgshapiro			 while (isascii(*++p) && isspace(*p))
4191173340Sgshapiro				continue;
4192173340Sgshapiro			lmap->ldap_secret = p;
4193173340Sgshapiro			secretread = false;
4194173340Sgshapiro			break;
4195173340Sgshapiro
4196173340Sgshapiro		  case 'p':		/* ldap port */
4197173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4198173340Sgshapiro				continue;
4199173340Sgshapiro			lmap->ldap_port = atoi(p);
4200173340Sgshapiro			break;
4201173340Sgshapiro
420238032Speter			/* args stolen from ldapsearch.c */
420338032Speter		  case 'R':		/* don't auto chase referrals */
420464562Sgshapiro# ifdef LDAP_REFERRALS
420538032Speter			lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
420664562Sgshapiro# else /* LDAP_REFERRALS */
420790792Sgshapiro			syserr("compile with -DLDAP_REFERRALS for referral support");
420864562Sgshapiro# endif /* LDAP_REFERRALS */
420938032Speter			break;
421038032Speter
421164562Sgshapiro		  case 'r':		/* alias dereferencing */
421264562Sgshapiro			while (isascii(*++p) && isspace(*p))
421364562Sgshapiro				continue;
421464562Sgshapiro
421590792Sgshapiro			if (sm_strncasecmp(p, "LDAP_DEREF_", 11) == 0)
421664562Sgshapiro				p += 11;
421764562Sgshapiro
421864562Sgshapiro			for (lad = LDAPAliasDereference;
421964562Sgshapiro			     lad != NULL && lad->lad_name != NULL; lad++)
422038032Speter			{
422190792Sgshapiro				if (sm_strncasecmp(p, lad->lad_name,
422290792Sgshapiro						   strlen(lad->lad_name)) == 0)
422364562Sgshapiro					break;
422438032Speter			}
422564562Sgshapiro			if (lad->lad_name != NULL)
422664562Sgshapiro				lmap->ldap_deref = lad->lad_code;
422764562Sgshapiro			else
422838032Speter			{
422964562Sgshapiro				/* bad config line */
423064562Sgshapiro				if (!bitset(MCF_OPTFILE,
423164562Sgshapiro					    map->map_class->map_cflags))
423264562Sgshapiro				{
423364562Sgshapiro					char *ptr;
423464562Sgshapiro
423564562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
423664562Sgshapiro						*ptr = '\0';
423773188Sgshapiro					syserr("Deref must be [never|always|search|find] (not %s) in map %s",
423864562Sgshapiro						p, map->map_mname);
423964562Sgshapiro					if (ptr != NULL)
424064562Sgshapiro						*ptr = ' ';
424190792Sgshapiro					return false;
424264562Sgshapiro				}
424338032Speter			}
424464562Sgshapiro			break;
424564562Sgshapiro
424664562Sgshapiro		  case 's':		/* search scope */
424764562Sgshapiro			while (isascii(*++p) && isspace(*p))
424864562Sgshapiro				continue;
424964562Sgshapiro
425090792Sgshapiro			if (sm_strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
425164562Sgshapiro				p += 11;
425264562Sgshapiro
425364562Sgshapiro			for (lss = LDAPSearchScope;
425464562Sgshapiro			     lss != NULL && lss->lss_name != NULL; lss++)
425538032Speter			{
425690792Sgshapiro				if (sm_strncasecmp(p, lss->lss_name,
425790792Sgshapiro						   strlen(lss->lss_name)) == 0)
425864562Sgshapiro					break;
425938032Speter			}
426064562Sgshapiro			if (lss->lss_name != NULL)
426164562Sgshapiro				lmap->ldap_scope = lss->lss_code;
426238032Speter			else
426364562Sgshapiro			{
426464562Sgshapiro				/* bad config line */
426564562Sgshapiro				if (!bitset(MCF_OPTFILE,
426664562Sgshapiro					    map->map_class->map_cflags))
426738032Speter				{
426838032Speter					char *ptr;
426938032Speter
427038032Speter					if ((ptr = strchr(p, ' ')) != NULL)
427138032Speter						*ptr = '\0';
427273188Sgshapiro					syserr("Scope must be [base|one|sub] (not %s) in map %s",
427338032Speter						p, map->map_mname);
427438032Speter					if (ptr != NULL)
427538032Speter						*ptr = ' ';
427690792Sgshapiro					return false;
427738032Speter				}
427838032Speter			}
427938032Speter			break;
428038032Speter
4281173340Sgshapiro		  case 'V':
4282173340Sgshapiro			if (*++p != '\\')
4283173340Sgshapiro				lmap->ldap_attrsep = *p;
428464562Sgshapiro			else
428564562Sgshapiro			{
4286173340Sgshapiro				switch (*++p)
428764562Sgshapiro				{
4288173340Sgshapiro				  case 'n':
4289173340Sgshapiro					lmap->ldap_attrsep = '\n';
4290173340Sgshapiro					break;
429164562Sgshapiro
4292173340Sgshapiro				  case 't':
4293173340Sgshapiro					lmap->ldap_attrsep = '\t';
4294173340Sgshapiro					break;
4295173340Sgshapiro
4296173340Sgshapiro				  default:
4297173340Sgshapiro					lmap->ldap_attrsep = '\\';
429864562Sgshapiro				}
429964562Sgshapiro			}
430064562Sgshapiro			break;
430164562Sgshapiro
4302173340Sgshapiro		  case 'v':		/* attr to return */
430394334Sgshapiro			while (isascii(*++p) && isspace(*p))
430494334Sgshapiro				continue;
4305173340Sgshapiro			lmap->ldap_attr[0] = p;
4306173340Sgshapiro			lmap->ldap_attr[1] = NULL;
430794334Sgshapiro			break;
430894334Sgshapiro
430994334Sgshapiro		  case 'w':
431094334Sgshapiro			/* -w should be for passwd, -P should be for version */
431194334Sgshapiro			while (isascii(*++p) && isspace(*p))
431294334Sgshapiro				continue;
431394334Sgshapiro			lmap->ldap_version = atoi(p);
4314132943Sgshapiro# ifdef LDAP_VERSION_MAX
431594334Sgshapiro			if (lmap->ldap_version > LDAP_VERSION_MAX)
431694334Sgshapiro			{
431794334Sgshapiro				syserr("LDAP version %d exceeds max of %d in map %s",
431894334Sgshapiro				       lmap->ldap_version, LDAP_VERSION_MAX,
431994334Sgshapiro				       map->map_mname);
432094334Sgshapiro				return false;
432194334Sgshapiro			}
4322132943Sgshapiro# endif /* LDAP_VERSION_MAX */
4323132943Sgshapiro# ifdef LDAP_VERSION_MIN
432494334Sgshapiro			if (lmap->ldap_version < LDAP_VERSION_MIN)
432594334Sgshapiro			{
432694334Sgshapiro				syserr("LDAP version %d is lower than min of %d in map %s",
432794334Sgshapiro				       lmap->ldap_version, LDAP_VERSION_MIN,
432894334Sgshapiro				       map->map_mname);
432994334Sgshapiro				return false;
433094334Sgshapiro			}
4331132943Sgshapiro# endif /* LDAP_VERSION_MIN */
433294334Sgshapiro			break;
433394334Sgshapiro
4334173340Sgshapiro		  case 'Z':
4335173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4336173340Sgshapiro				continue;
4337173340Sgshapiro			lmap->ldap_sizelimit = atoi(p);
4338168515Sgshapiro			break;
4339168515Sgshapiro
434064562Sgshapiro		  default:
434164562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
434264562Sgshapiro			break;
434338032Speter		}
434438032Speter
434564562Sgshapiro		/* need to account for quoted strings here */
434664562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
434738032Speter		{
434838032Speter			if (*p == '"')
434938032Speter			{
435038032Speter				while (*++p != '"' && *p != '\0')
435138032Speter					continue;
435238032Speter				if (*p != '\0')
435338032Speter					p++;
435438032Speter			}
435538032Speter			else
435638032Speter				p++;
435738032Speter		}
435838032Speter
435938032Speter		if (*p != '\0')
436038032Speter			*p++ = '\0';
436138032Speter	}
436238032Speter
436338032Speter	if (map->map_app != NULL)
436464562Sgshapiro		map->map_app = newstr(ldapmap_dequote(map->map_app));
436538032Speter	if (map->map_tapp != NULL)
436664562Sgshapiro		map->map_tapp = newstr(ldapmap_dequote(map->map_tapp));
436738032Speter
436838032Speter	/*
436942575Speter	**  We need to swallow up all the stuff into a struct
437042575Speter	**  and dump it into map->map_dbptr1
437138032Speter	*/
437238032Speter
4373132943Sgshapiro	if (lmap->ldap_host != NULL &&
437464562Sgshapiro	    (LDAPDefaults == NULL ||
437564562Sgshapiro	     LDAPDefaults == lmap ||
4376132943Sgshapiro	     LDAPDefaults->ldap_host != lmap->ldap_host))
4377132943Sgshapiro		lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host));
4378132943Sgshapiro	map->map_domain = lmap->ldap_host;
437964562Sgshapiro
4380132943Sgshapiro	if (lmap->ldap_uri != NULL &&
4381132943Sgshapiro	    (LDAPDefaults == NULL ||
4382132943Sgshapiro	     LDAPDefaults == lmap ||
4383132943Sgshapiro	     LDAPDefaults->ldap_uri != lmap->ldap_uri))
4384132943Sgshapiro		lmap->ldap_uri = newstr(ldapmap_dequote(lmap->ldap_uri));
4385132943Sgshapiro	map->map_domain = lmap->ldap_uri;
4386132943Sgshapiro
438764562Sgshapiro	if (lmap->ldap_binddn != NULL &&
438864562Sgshapiro	    (LDAPDefaults == NULL ||
438964562Sgshapiro	     LDAPDefaults == lmap ||
439064562Sgshapiro	     LDAPDefaults->ldap_binddn != lmap->ldap_binddn))
439164562Sgshapiro		lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn));
439264562Sgshapiro
439364562Sgshapiro	if (lmap->ldap_secret != NULL &&
439464562Sgshapiro	    (LDAPDefaults == NULL ||
439564562Sgshapiro	     LDAPDefaults == lmap ||
439664562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
439738032Speter	{
439890792Sgshapiro		SM_FILE_T *sfd;
439964562Sgshapiro		long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
440038032Speter
440164562Sgshapiro		if (DontLockReadFiles)
440264562Sgshapiro			sff |= SFF_NOLOCK;
440338032Speter
440464562Sgshapiro		/* need to use method to map secret to passwd string */
440564562Sgshapiro		switch (lmap->ldap_method)
440664562Sgshapiro		{
440764562Sgshapiro		  case LDAP_AUTH_NONE:
440864562Sgshapiro			/* Do nothing */
440964562Sgshapiro			break;
441038032Speter
441164562Sgshapiro		  case LDAP_AUTH_SIMPLE:
441238032Speter
441364562Sgshapiro			/*
441464562Sgshapiro			**  Secret is the name of a file with
441564562Sgshapiro			**  the first line as the password.
441664562Sgshapiro			*/
441764562Sgshapiro
441864562Sgshapiro			/* Already read in the secret? */
441964562Sgshapiro			if (secretread)
442064562Sgshapiro				break;
442164562Sgshapiro
442264562Sgshapiro			sfd = safefopen(ldapmap_dequote(lmap->ldap_secret),
442364562Sgshapiro					O_RDONLY, 0, sff);
442464562Sgshapiro			if (sfd == NULL)
442564562Sgshapiro			{
442664562Sgshapiro				syserr("LDAP map: cannot open secret %s",
442764562Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
442890792Sgshapiro				return false;
442964562Sgshapiro			}
4430168515Sgshapiro			lmap->ldap_secret = sfgets(m_tmp, sizeof(m_tmp),
443166494Sgshapiro						   sfd, TimeOuts.to_fileopen,
443266494Sgshapiro						   "ldapmap_parseargs");
443390792Sgshapiro			(void) sm_io_close(sfd, SM_TIME_DEFAULT);
443498121Sgshapiro			if (strlen(m_tmp) > LDAPMAP_MAX_PASSWD)
443598121Sgshapiro			{
443698121Sgshapiro				syserr("LDAP map: secret in %s too long",
443798121Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
443898121Sgshapiro				return false;
443998121Sgshapiro			}
444064562Sgshapiro			if (lmap->ldap_secret != NULL &&
444164562Sgshapiro			    strlen(m_tmp) > 0)
444264562Sgshapiro			{
444364562Sgshapiro				/* chomp newline */
444464562Sgshapiro				if (m_tmp[strlen(m_tmp) - 1] == '\n')
444564562Sgshapiro					m_tmp[strlen(m_tmp) - 1] = '\0';
444664562Sgshapiro
444764562Sgshapiro				lmap->ldap_secret = m_tmp;
444864562Sgshapiro			}
444964562Sgshapiro			break;
445064562Sgshapiro
445164562Sgshapiro# ifdef LDAP_AUTH_KRBV4
445264562Sgshapiro		  case LDAP_AUTH_KRBV4:
445364562Sgshapiro
445464562Sgshapiro			/*
445564562Sgshapiro			**  Secret is where the ticket file is
445664562Sgshapiro			**  stashed
445764562Sgshapiro			*/
445864562Sgshapiro
4459168515Sgshapiro			(void) sm_snprintf(m_tmp, sizeof(m_tmp),
446090792Sgshapiro				"KRBTKFILE=%s",
446190792Sgshapiro				ldapmap_dequote(lmap->ldap_secret));
446264562Sgshapiro			lmap->ldap_secret = m_tmp;
446364562Sgshapiro			break;
446464562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
446564562Sgshapiro
446664562Sgshapiro		  default:	       /* Should NEVER get here */
446764562Sgshapiro			syserr("LDAP map: Illegal value in lmap method");
446890792Sgshapiro			return false;
446990792Sgshapiro			/* NOTREACHED */
447064562Sgshapiro			break;
447164562Sgshapiro		}
447238032Speter	}
447338032Speter
447464562Sgshapiro	if (lmap->ldap_secret != NULL &&
447564562Sgshapiro	    (LDAPDefaults == NULL ||
447664562Sgshapiro	     LDAPDefaults == lmap ||
447764562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
447864562Sgshapiro		lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret));
447938032Speter
448064562Sgshapiro	if (lmap->ldap_base != NULL &&
448164562Sgshapiro	    (LDAPDefaults == NULL ||
448264562Sgshapiro	     LDAPDefaults == lmap ||
448364562Sgshapiro	     LDAPDefaults->ldap_base != lmap->ldap_base))
448464562Sgshapiro		lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base));
448564562Sgshapiro
448664562Sgshapiro	/*
448764562Sgshapiro	**  Save the server from extra work.  If request is for a single
448864562Sgshapiro	**  match, tell the server to only return enough records to
448964562Sgshapiro	**  determine if there is a single match or not.  This can not
449064562Sgshapiro	**  be one since the server would only return one and we wouldn't
449164562Sgshapiro	**  know if there were others available.
449264562Sgshapiro	*/
449364562Sgshapiro
449464562Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
449564562Sgshapiro		lmap->ldap_sizelimit = 2;
449664562Sgshapiro
449764562Sgshapiro	/* If setting defaults, don't process ldap_filter and ldap_attr */
449864562Sgshapiro	if (lmap == LDAPDefaults)
449990792Sgshapiro		return true;
450064562Sgshapiro
450164562Sgshapiro	if (lmap->ldap_filter != NULL)
450264562Sgshapiro		lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
450338032Speter	else
450438032Speter	{
450538032Speter		if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
450638032Speter		{
450738032Speter			syserr("No filter given in map %s", map->map_mname);
450890792Sgshapiro			return false;
450938032Speter		}
451038032Speter	}
451164562Sgshapiro
4512132943Sgshapiro	if (!attrssetup && lmap->ldap_attr[0] != NULL)
451338032Speter	{
451490792Sgshapiro		bool recurse = false;
451594334Sgshapiro		bool normalseen = false;
451690792Sgshapiro
451764562Sgshapiro		i = 0;
451864562Sgshapiro		p = ldapmap_dequote(lmap->ldap_attr[0]);
451964562Sgshapiro		lmap->ldap_attr[0] = NULL;
452064562Sgshapiro
452194334Sgshapiro		/* Prime the attr list with the objectClass attribute */
452294334Sgshapiro		lmap->ldap_attr[i] = "objectClass";
452394334Sgshapiro		lmap->ldap_attr_type[i] = SM_LDAP_ATTR_OBJCLASS;
452494334Sgshapiro		lmap->ldap_attr_needobjclass[i] = NULL;
452594334Sgshapiro		i++;
452694334Sgshapiro
452764562Sgshapiro		while (p != NULL)
452838032Speter		{
452964562Sgshapiro			char *v;
453064562Sgshapiro
453164562Sgshapiro			while (isascii(*p) && isspace(*p))
453264562Sgshapiro				p++;
453364562Sgshapiro			if (*p == '\0')
453464562Sgshapiro				break;
453564562Sgshapiro			v = p;
453664562Sgshapiro			p = strchr(v, ',');
453764562Sgshapiro			if (p != NULL)
453864562Sgshapiro				*p++ = '\0';
453964562Sgshapiro
454071345Sgshapiro			if (i >= LDAPMAP_MAX_ATTR)
454164562Sgshapiro			{
454264562Sgshapiro				syserr("Too many return attributes in %s (max %d)",
454364562Sgshapiro				       map->map_mname, LDAPMAP_MAX_ATTR);
454490792Sgshapiro				return false;
454564562Sgshapiro			}
454664562Sgshapiro			if (*v != '\0')
454790792Sgshapiro			{
454894334Sgshapiro				int j;
454994334Sgshapiro				int use;
455090792Sgshapiro				char *type;
455194334Sgshapiro				char *needobjclass;
455290792Sgshapiro
455390792Sgshapiro				type = strchr(v, ':');
455490792Sgshapiro				if (type != NULL)
455594334Sgshapiro				{
455690792Sgshapiro					*type++ = '\0';
455794334Sgshapiro					needobjclass = strchr(type, ':');
455894334Sgshapiro					if (needobjclass != NULL)
455994334Sgshapiro						*needobjclass++ = '\0';
456094334Sgshapiro				}
456194334Sgshapiro				else
456294334Sgshapiro				{
456394334Sgshapiro					needobjclass = NULL;
456494334Sgshapiro				}
456590792Sgshapiro
456694334Sgshapiro				use = i;
456790792Sgshapiro
456894334Sgshapiro				/* allow override on "objectClass" type */
456994334Sgshapiro				if (sm_strcasecmp(v, "objectClass") == 0 &&
457094334Sgshapiro				    lmap->ldap_attr_type[0] == SM_LDAP_ATTR_OBJCLASS)
457190792Sgshapiro				{
457294334Sgshapiro					use = 0;
457394334Sgshapiro				}
457494334Sgshapiro				else
457594334Sgshapiro				{
457694334Sgshapiro					/*
457794334Sgshapiro					**  Don't add something to attribute
457894334Sgshapiro					**  list twice.
457994334Sgshapiro					*/
458094334Sgshapiro
458194334Sgshapiro					for (j = 1; j < i; j++)
458290792Sgshapiro					{
458394334Sgshapiro						if (sm_strcasecmp(v, lmap->ldap_attr[j]) == 0)
458494334Sgshapiro						{
458594334Sgshapiro							syserr("Duplicate attribute (%s) in %s",
458694334Sgshapiro							       v, map->map_mname);
458794334Sgshapiro							return false;
458894334Sgshapiro						}
458990792Sgshapiro					}
459094334Sgshapiro
459194334Sgshapiro					lmap->ldap_attr[use] = newstr(v);
459294334Sgshapiro					if (needobjclass != NULL &&
459394334Sgshapiro					    *needobjclass != '\0' &&
459494334Sgshapiro					    *needobjclass != '*')
459590792Sgshapiro					{
459694334Sgshapiro						lmap->ldap_attr_needobjclass[use] = newstr(needobjclass);
459794334Sgshapiro					}
459894334Sgshapiro					else
459994334Sgshapiro					{
460094334Sgshapiro						lmap->ldap_attr_needobjclass[use] = NULL;
460194334Sgshapiro					}
460294334Sgshapiro
460394334Sgshapiro				}
460494334Sgshapiro
460594334Sgshapiro				if (type != NULL && *type != '\0')
460694334Sgshapiro				{
460794334Sgshapiro					if (sm_strcasecmp(type, "dn") == 0)
460894334Sgshapiro					{
460990792Sgshapiro						recurse = true;
461094334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_DN;
461190792Sgshapiro					}
461290792Sgshapiro					else if (sm_strcasecmp(type, "filter") == 0)
461390792Sgshapiro					{
461490792Sgshapiro						recurse = true;
461594334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_FILTER;
461690792Sgshapiro					}
461790792Sgshapiro					else if (sm_strcasecmp(type, "url") == 0)
461890792Sgshapiro					{
461990792Sgshapiro						recurse = true;
462094334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_URL;
462190792Sgshapiro					}
462294334Sgshapiro					else if (sm_strcasecmp(type, "normal") == 0)
462390792Sgshapiro					{
462494334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
462594334Sgshapiro						normalseen = true;
462690792Sgshapiro					}
462790792Sgshapiro					else
462890792Sgshapiro					{
462990792Sgshapiro						syserr("Unknown attribute type (%s) in %s",
463090792Sgshapiro						       type, map->map_mname);
463190792Sgshapiro						return false;
463290792Sgshapiro					}
463390792Sgshapiro				}
463490792Sgshapiro				else
463594334Sgshapiro				{
463694334Sgshapiro					lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
463794334Sgshapiro					normalseen = true;
463894334Sgshapiro				}
463990792Sgshapiro				i++;
464090792Sgshapiro			}
464138032Speter		}
464264562Sgshapiro		lmap->ldap_attr[i] = NULL;
4643141858Sgshapiro
4644141858Sgshapiro		/* Set in case needed in future code */
4645132943Sgshapiro		attrssetup = true;
4646141858Sgshapiro
464794334Sgshapiro		if (recurse && !normalseen)
464890792Sgshapiro		{
464994334Sgshapiro			syserr("LDAP recursion requested in %s but no returnable attribute given",
465090792Sgshapiro			       map->map_mname);
465190792Sgshapiro			return false;
465290792Sgshapiro		}
465390792Sgshapiro		if (recurse && lmap->ldap_attrsonly == LDAPMAP_TRUE)
465490792Sgshapiro		{
465590792Sgshapiro			syserr("LDAP recursion requested in %s can not be used with -n",
465690792Sgshapiro			       map->map_mname);
465790792Sgshapiro			return false;
465890792Sgshapiro		}
465938032Speter	}
466038032Speter	map->map_db1 = (ARBPTR_T) lmap;
466190792Sgshapiro	return true;
466238032Speter}
466338032Speter
466464562Sgshapiro/*
466564562Sgshapiro**  LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
466664562Sgshapiro**
466764562Sgshapiro**	Parameters:
466864562Sgshapiro**		spec -- map argument string from LDAPDefaults option
466964562Sgshapiro**
467064562Sgshapiro**	Returns:
467164562Sgshapiro**		None.
467264562Sgshapiro*/
467364562Sgshapiro
467464562Sgshapirovoid
467564562Sgshapiroldapmap_set_defaults(spec)
467664562Sgshapiro	char *spec;
467764562Sgshapiro{
467873188Sgshapiro	STAB *class;
467964562Sgshapiro	MAP map;
468064562Sgshapiro
468164562Sgshapiro	/* Allocate and set the default values */
468264562Sgshapiro	if (LDAPDefaults == NULL)
4683168515Sgshapiro		LDAPDefaults = (SM_LDAP_STRUCT *) xalloc(sizeof(*LDAPDefaults));
468490792Sgshapiro	sm_ldap_clear(LDAPDefaults);
468564562Sgshapiro
4686168515Sgshapiro	memset(&map, '\0', sizeof(map));
468773188Sgshapiro
468873188Sgshapiro	/* look up the class */
468973188Sgshapiro	class = stab("ldap", ST_MAPCLASS, ST_FIND);
469073188Sgshapiro	if (class == NULL)
469173188Sgshapiro	{
469273188Sgshapiro		syserr("readcf: LDAPDefaultSpec: class ldap not available");
469373188Sgshapiro		return;
469473188Sgshapiro	}
469573188Sgshapiro	map.map_class = &class->s_mapclass;
469664562Sgshapiro	map.map_db1 = (ARBPTR_T) LDAPDefaults;
469773188Sgshapiro	map.map_mname = "O LDAPDefaultSpec";
469864562Sgshapiro
469964562Sgshapiro	(void) ldapmap_parseargs(&map, spec);
470064562Sgshapiro
470164562Sgshapiro	/* These should never be set in LDAPDefaults */
470264562Sgshapiro	if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) ||
470364562Sgshapiro	    map.map_spacesub != SpaceSub ||
470464562Sgshapiro	    map.map_app != NULL ||
470564562Sgshapiro	    map.map_tapp != NULL)
470664562Sgshapiro	{
470764562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
470890792Sgshapiro		SM_FREE_CLR(map.map_app);
470990792Sgshapiro		SM_FREE_CLR(map.map_tapp);
471064562Sgshapiro	}
471164562Sgshapiro
471264562Sgshapiro	if (LDAPDefaults->ldap_filter != NULL)
471364562Sgshapiro	{
471464562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
471594334Sgshapiro
471664562Sgshapiro		/* don't free, it isn't malloc'ed in parseargs */
471764562Sgshapiro		LDAPDefaults->ldap_filter = NULL;
471864562Sgshapiro	}
471964562Sgshapiro
472064562Sgshapiro	if (LDAPDefaults->ldap_attr[0] != NULL)
472164562Sgshapiro	{
472264562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes");
472364562Sgshapiro		/* don't free, they aren't malloc'ed in parseargs */
472464562Sgshapiro		LDAPDefaults->ldap_attr[0] = NULL;
472564562Sgshapiro	}
472664562Sgshapiro}
472764562Sgshapiro#endif /* LDAPMAP */
472890792Sgshapiro/*
472964562Sgshapiro**  PH map
473064562Sgshapiro*/
473164562Sgshapiro
473290792Sgshapiro#if PH_MAP
473364562Sgshapiro
473464562Sgshapiro/*
473564562Sgshapiro**  Support for the CCSO Nameserver (ph/qi).
473664562Sgshapiro**  This code is intended to replace the so-called "ph mailer".
4737168515Sgshapiro**  Contributed by Mark D. Roth.  Contact him for support.
473864562Sgshapiro*/
473964562Sgshapiro
474090792Sgshapiro/* what version of the ph map code we're running */
4741110560Sgshapirostatic char phmap_id[128];
474264562Sgshapiro
474390792Sgshapiro/* sendmail version for phmap id string */
474490792Sgshapiroextern const char Version[];
474590792Sgshapiro
4746132943Sgshapiro/* assume we're using nph-1.2.x if not specified */
4747110560Sgshapiro# ifndef NPH_VERSION
4748132943Sgshapiro#  define NPH_VERSION		10200
4749110560Sgshapiro# endif
4750110560Sgshapiro
4751110560Sgshapiro/* compatibility for versions older than nph-1.2.0 */
4752110560Sgshapiro# if NPH_VERSION < 10200
4753110560Sgshapiro#  define PH_OPEN_ROUNDROBIN	PH_ROUNDROBIN
4754110560Sgshapiro#  define PH_OPEN_DONTID	PH_DONTID
4755110560Sgshapiro#  define PH_CLOSE_FAST		PH_FASTCLOSE
4756110560Sgshapiro#  define PH_ERR_DATAERR	PH_DATAERR
4757110560Sgshapiro#  define PH_ERR_NOMATCH	PH_NOMATCH
4758110560Sgshapiro# endif /* NPH_VERSION < 10200 */
4759110560Sgshapiro
476064562Sgshapiro/*
476164562Sgshapiro**  PH_MAP_PARSEARGS -- parse ph map definition args.
476264562Sgshapiro*/
476364562Sgshapiro
476464562Sgshapirobool
476564562Sgshapiroph_map_parseargs(map, args)
476664562Sgshapiro	MAP *map;
476764562Sgshapiro	char *args;
476864562Sgshapiro{
476990792Sgshapiro	register bool done;
477090792Sgshapiro	register char *p = args;
477164562Sgshapiro	PH_MAP_STRUCT *pmap = NULL;
477264562Sgshapiro
477390792Sgshapiro	/* initialize version string */
4774168515Sgshapiro	(void) sm_snprintf(phmap_id, sizeof(phmap_id),
477590792Sgshapiro			   "sendmail-%s phmap-20010529 libphclient-%s",
477690792Sgshapiro			   Version, libphclient_version);
477790792Sgshapiro
4778168515Sgshapiro	pmap = (PH_MAP_STRUCT *) xalloc(sizeof(*pmap));
477964562Sgshapiro
478064562Sgshapiro	/* defaults */
478164562Sgshapiro	pmap->ph_servers = NULL;
478264562Sgshapiro	pmap->ph_field_list = NULL;
478390792Sgshapiro	pmap->ph = NULL;
478464562Sgshapiro	pmap->ph_timeout = 0;
478590792Sgshapiro	pmap->ph_fastclose = 0;
478664562Sgshapiro
478764562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
478864562Sgshapiro	for (;;)
478964562Sgshapiro	{
479064562Sgshapiro		while (isascii(*p) && isspace(*p))
479164562Sgshapiro			p++;
479264562Sgshapiro		if (*p != '-')
479364562Sgshapiro			break;
479464562Sgshapiro		switch (*++p)
479564562Sgshapiro		{
479664562Sgshapiro		  case 'N':
479764562Sgshapiro			map->map_mflags |= MF_INCLNULL;
479864562Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
479964562Sgshapiro			break;
480064562Sgshapiro
480164562Sgshapiro		  case 'O':
480264562Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
480364562Sgshapiro			break;
480464562Sgshapiro
480564562Sgshapiro		  case 'o':
480664562Sgshapiro			map->map_mflags |= MF_OPTIONAL;
480764562Sgshapiro			break;
480864562Sgshapiro
480964562Sgshapiro		  case 'f':
481064562Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
481164562Sgshapiro			break;
481264562Sgshapiro
481364562Sgshapiro		  case 'm':
481464562Sgshapiro			map->map_mflags |= MF_MATCHONLY;
481564562Sgshapiro			break;
481664562Sgshapiro
481764562Sgshapiro		  case 'A':
481864562Sgshapiro			map->map_mflags |= MF_APPEND;
481964562Sgshapiro			break;
482064562Sgshapiro
482164562Sgshapiro		  case 'q':
482264562Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
482364562Sgshapiro			break;
482464562Sgshapiro
482564562Sgshapiro		  case 't':
482664562Sgshapiro			map->map_mflags |= MF_NODEFER;
482764562Sgshapiro			break;
482864562Sgshapiro
482964562Sgshapiro		  case 'a':
483064562Sgshapiro			map->map_app = ++p;
483164562Sgshapiro			break;
483264562Sgshapiro
483364562Sgshapiro		  case 'T':
483464562Sgshapiro			map->map_tapp = ++p;
483564562Sgshapiro			break;
483664562Sgshapiro
483764562Sgshapiro		  case 'l':
483864562Sgshapiro			while (isascii(*++p) && isspace(*p))
483964562Sgshapiro				continue;
484064562Sgshapiro			pmap->ph_timeout = atoi(p);
484164562Sgshapiro			break;
484264562Sgshapiro
484364562Sgshapiro		  case 'S':
484464562Sgshapiro			map->map_spacesub = *++p;
484564562Sgshapiro			break;
484664562Sgshapiro
484764562Sgshapiro		  case 'D':
484864562Sgshapiro			map->map_mflags |= MF_DEFER;
484964562Sgshapiro			break;
485064562Sgshapiro
485164562Sgshapiro		  case 'h':		/* PH server list */
485264562Sgshapiro			while (isascii(*++p) && isspace(*p))
485364562Sgshapiro				continue;
485464562Sgshapiro			pmap->ph_servers = p;
485564562Sgshapiro			break;
485664562Sgshapiro
485790792Sgshapiro		  case 'k':		/* fields to search for */
485864562Sgshapiro			while (isascii(*++p) && isspace(*p))
485964562Sgshapiro				continue;
486064562Sgshapiro			pmap->ph_field_list = p;
486164562Sgshapiro			break;
486264562Sgshapiro
486364562Sgshapiro		  default:
486490792Sgshapiro			syserr("ph_map_parseargs: unknown option -%c", *p);
486564562Sgshapiro		}
486664562Sgshapiro
486764562Sgshapiro		/* try to account for quoted strings */
486864562Sgshapiro		done = isascii(*p) && isspace(*p);
486964562Sgshapiro		while (*p != '\0' && !done)
487064562Sgshapiro		{
487164562Sgshapiro			if (*p == '"')
487264562Sgshapiro			{
487364562Sgshapiro				while (*++p != '"' && *p != '\0')
487464562Sgshapiro					continue;
487564562Sgshapiro				if (*p != '\0')
487664562Sgshapiro					p++;
487764562Sgshapiro			}
487864562Sgshapiro			else
487964562Sgshapiro				p++;
488064562Sgshapiro			done = isascii(*p) && isspace(*p);
488164562Sgshapiro		}
488264562Sgshapiro
488364562Sgshapiro		if (*p != '\0')
488464562Sgshapiro			*p++ = '\0';
488564562Sgshapiro	}
488664562Sgshapiro
488764562Sgshapiro	if (map->map_app != NULL)
488864562Sgshapiro		map->map_app = newstr(ph_map_dequote(map->map_app));
488964562Sgshapiro	if (map->map_tapp != NULL)
489064562Sgshapiro		map->map_tapp = newstr(ph_map_dequote(map->map_tapp));
489164562Sgshapiro
489264562Sgshapiro	if (pmap->ph_field_list != NULL)
489364562Sgshapiro		pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
489464562Sgshapiro
489564562Sgshapiro	if (pmap->ph_servers != NULL)
489664562Sgshapiro		pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
489764562Sgshapiro	else
489864562Sgshapiro	{
489964562Sgshapiro		syserr("ph_map_parseargs: -h flag is required");
490090792Sgshapiro		return false;
490164562Sgshapiro	}
490264562Sgshapiro
490364562Sgshapiro	map->map_db1 = (ARBPTR_T) pmap;
490490792Sgshapiro	return true;
490564562Sgshapiro}
490664562Sgshapiro
490764562Sgshapiro/*
490864562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
490964562Sgshapiro*/
491064562Sgshapiro
491190792Sgshapirovoid
491290792Sgshapiroph_map_close(map)
491364562Sgshapiro	MAP *map;
491464562Sgshapiro{
491564562Sgshapiro	PH_MAP_STRUCT *pmap;
491664562Sgshapiro
491764562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
491890792Sgshapiro	if (tTd(38, 9))
491994334Sgshapiro		sm_dprintf("ph_map_close(%s): pmap->ph_fastclose=%d\n",
492090792Sgshapiro			   map->map_mname, pmap->ph_fastclose);
492164562Sgshapiro
492290792Sgshapiro
492390792Sgshapiro	if (pmap->ph != NULL)
492464562Sgshapiro	{
492590792Sgshapiro		ph_set_sendhook(pmap->ph, NULL);
492690792Sgshapiro		ph_set_recvhook(pmap->ph, NULL);
492790792Sgshapiro		ph_close(pmap->ph, pmap->ph_fastclose);
492864562Sgshapiro	}
492990792Sgshapiro
493064562Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
493164562Sgshapiro}
493264562Sgshapiro
493364562Sgshapirostatic jmp_buf  PHTimeout;
493464562Sgshapiro
493564562Sgshapiro/* ARGSUSED */
493664562Sgshapirostatic void
493790792Sgshapiroph_timeout(unused)
493890792Sgshapiro	int unused;
493964562Sgshapiro{
494077349Sgshapiro	/*
494177349Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
494277349Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
494377349Sgshapiro	**	DOING.
494477349Sgshapiro	*/
494577349Sgshapiro
494677349Sgshapiro	errno = ETIMEDOUT;
494764562Sgshapiro	longjmp(PHTimeout, 1);
494864562Sgshapiro}
494964562Sgshapiro
495090792Sgshapirostatic void
4951110560Sgshapiro#if NPH_VERSION >= 10200
4952110560Sgshapiroph_map_send_debug(appdata, text)
4953110560Sgshapiro	void *appdata;
4954110560Sgshapiro#else
495590792Sgshapiroph_map_send_debug(text)
4956110560Sgshapiro#endif
495790792Sgshapiro	char *text;
495864562Sgshapiro{
495990792Sgshapiro	if (LogLevel > 9)
496090792Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
496190792Sgshapiro			  "ph_map_send_debug: ==> %s", text);
496290792Sgshapiro	if (tTd(38, 20))
496390792Sgshapiro		sm_dprintf("ph_map_send_debug: ==> %s\n", text);
496490792Sgshapiro}
496564562Sgshapiro
496690792Sgshapirostatic void
4967110560Sgshapiro#if NPH_VERSION >= 10200
4968110560Sgshapiroph_map_recv_debug(appdata, text)
4969110560Sgshapiro	void *appdata;
4970110560Sgshapiro#else
497190792Sgshapiroph_map_recv_debug(text)
4972110560Sgshapiro#endif
497390792Sgshapiro	char *text;
497490792Sgshapiro{
497590792Sgshapiro	if (LogLevel > 10)
497690792Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
497790792Sgshapiro			  "ph_map_recv_debug: <== %s", text);
497890792Sgshapiro	if (tTd(38, 21))
497990792Sgshapiro		sm_dprintf("ph_map_recv_debug: <== %s\n", text);
498064562Sgshapiro}
498164562Sgshapiro
498290792Sgshapiro/*
498364562Sgshapiro**  PH_MAP_OPEN -- sub for opening PH map
498464562Sgshapiro*/
498564562Sgshapirobool
498664562Sgshapiroph_map_open(map, mode)
498764562Sgshapiro	MAP *map;
498864562Sgshapiro	int mode;
498964562Sgshapiro{
499090792Sgshapiro	PH_MAP_STRUCT *pmap;
499190792Sgshapiro	register SM_EVENT *ev = NULL;
499264562Sgshapiro	int save_errno = 0;
499390792Sgshapiro	char *hostlist, *host;
499464562Sgshapiro
499564562Sgshapiro	if (tTd(38, 2))
499690792Sgshapiro		sm_dprintf("ph_map_open(%s)\n", map->map_mname);
499764562Sgshapiro
499864562Sgshapiro	mode &= O_ACCMODE;
499964562Sgshapiro	if (mode != O_RDONLY)
500064562Sgshapiro	{
500164562Sgshapiro		/* issue a pseudo-error message */
500290792Sgshapiro		errno = SM_EMAPCANTWRITE;
500390792Sgshapiro		return false;
500464562Sgshapiro	}
500564562Sgshapiro
500666494Sgshapiro	if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER &&
500766494Sgshapiro	    bitset(MF_DEFER, map->map_mflags))
500866494Sgshapiro	{
500966494Sgshapiro		if (tTd(9, 1))
501090792Sgshapiro			sm_dprintf("ph_map_open(%s) => DEFERRED\n",
501190792Sgshapiro				   map->map_mname);
501266494Sgshapiro
501366494Sgshapiro		/*
501490792Sgshapiro		**  Unset MF_DEFER here so that map_lookup() returns
501590792Sgshapiro		**  a temporary failure using the bogus map and
501690792Sgshapiro		**  map->map_tapp instead of the default permanent error.
501766494Sgshapiro		*/
501866494Sgshapiro
501966494Sgshapiro		map->map_mflags &= ~MF_DEFER;
502090792Sgshapiro		return false;
502166494Sgshapiro	}
502266494Sgshapiro
502364562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
502490792Sgshapiro	pmap->ph_fastclose = 0;		/* refresh field for reopen */
502564562Sgshapiro
502690792Sgshapiro	/* try each host in the list */
502764562Sgshapiro	hostlist = newstr(pmap->ph_servers);
502890792Sgshapiro	for (host = strtok(hostlist, " ");
502990792Sgshapiro	     host != NULL;
503090792Sgshapiro	     host = strtok(NULL, " "))
503164562Sgshapiro	{
503290792Sgshapiro		/* set timeout */
503364562Sgshapiro		if (pmap->ph_timeout != 0)
503464562Sgshapiro		{
503564562Sgshapiro			if (setjmp(PHTimeout) != 0)
503664562Sgshapiro			{
503764562Sgshapiro				ev = NULL;
503864562Sgshapiro				if (LogLevel > 1)
503964562Sgshapiro					sm_syslog(LOG_NOTICE, CurEnv->e_id,
504064562Sgshapiro						  "timeout connecting to PH server %.100s",
504190792Sgshapiro						  host);
504264562Sgshapiro				errno = ETIMEDOUT;
504364562Sgshapiro				goto ph_map_open_abort;
504464562Sgshapiro			}
504590792Sgshapiro			ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
504664562Sgshapiro		}
504790792Sgshapiro
504890792Sgshapiro		/* open connection to server */
5049110560Sgshapiro		if (ph_open(&(pmap->ph), host,
5050110560Sgshapiro			    PH_OPEN_ROUNDROBIN|PH_OPEN_DONTID,
5051110560Sgshapiro			    ph_map_send_debug, ph_map_recv_debug
5052110560Sgshapiro#if NPH_VERSION >= 10200
5053110560Sgshapiro			    , NULL
5054110560Sgshapiro#endif
5055110560Sgshapiro			    ) == 0
5056110560Sgshapiro		    && ph_id(pmap->ph, phmap_id) == 0)
505764562Sgshapiro		{
505864562Sgshapiro			if (ev != NULL)
505990792Sgshapiro				sm_clrevent(ev);
506090792Sgshapiro			sm_free(hostlist); /* XXX */
506190792Sgshapiro			return true;
506264562Sgshapiro		}
506390792Sgshapiro
506464562Sgshapiro  ph_map_open_abort:
506590792Sgshapiro		save_errno = errno;
506664562Sgshapiro		if (ev != NULL)
506790792Sgshapiro			sm_clrevent(ev);
5068110560Sgshapiro		pmap->ph_fastclose = PH_CLOSE_FAST;
506990792Sgshapiro		ph_map_close(map);
507090792Sgshapiro		errno = save_errno;
507190792Sgshapiro	}
507264562Sgshapiro
507366494Sgshapiro	if (bitset(MF_NODEFER, map->map_mflags))
507464562Sgshapiro	{
507566494Sgshapiro		if (errno == 0)
507664562Sgshapiro			errno = EAGAIN;
507766494Sgshapiro		syserr("ph_map_open: %s: cannot connect to PH server",
507866494Sgshapiro		       map->map_mname);
507964562Sgshapiro	}
508066494Sgshapiro	else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1)
508164562Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
508266494Sgshapiro			  "ph_map_open: %s: cannot connect to PH server",
508366494Sgshapiro			  map->map_mname);
508490792Sgshapiro	sm_free(hostlist); /* XXX */
508590792Sgshapiro	return false;
508664562Sgshapiro}
508764562Sgshapiro
508864562Sgshapiro/*
508964562Sgshapiro**  PH_MAP_LOOKUP -- look up key from ph server
509064562Sgshapiro*/
509164562Sgshapiro
509264562Sgshapirochar *
509364562Sgshapiroph_map_lookup(map, key, args, pstat)
509464562Sgshapiro	MAP *map;
509564562Sgshapiro	char *key;
509664562Sgshapiro	char **args;
509764562Sgshapiro	int *pstat;
509864562Sgshapiro{
509990792Sgshapiro	int i, save_errno = 0;
510090792Sgshapiro	register SM_EVENT *ev = NULL;
510164562Sgshapiro	PH_MAP_STRUCT *pmap;
510290792Sgshapiro	char *value = NULL;
510364562Sgshapiro
510464562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
510564562Sgshapiro
510664562Sgshapiro	*pstat = EX_OK;
510764562Sgshapiro
510890792Sgshapiro	/* set timeout */
510964562Sgshapiro	if (pmap->ph_timeout != 0)
511064562Sgshapiro	{
511164562Sgshapiro		if (setjmp(PHTimeout) != 0)
511264562Sgshapiro		{
511364562Sgshapiro			ev = NULL;
511464562Sgshapiro			if (LogLevel > 1)
511564562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
511664562Sgshapiro					  "timeout during PH lookup of %.100s",
511764562Sgshapiro					  key);
511864562Sgshapiro			errno = ETIMEDOUT;
511964562Sgshapiro			*pstat = EX_TEMPFAIL;
512064562Sgshapiro			goto ph_map_lookup_abort;
512164562Sgshapiro		}
512290792Sgshapiro		ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
512364562Sgshapiro	}
512464562Sgshapiro
512590792Sgshapiro	/* perform lookup */
512690792Sgshapiro	i = ph_email_resolve(pmap->ph, key, pmap->ph_field_list, &value);
512790792Sgshapiro	if (i == -1)
512890792Sgshapiro		*pstat = EX_TEMPFAIL;
5129110560Sgshapiro	else if (i == PH_ERR_NOMATCH || i == PH_ERR_DATAERR)
513090792Sgshapiro		*pstat = EX_UNAVAILABLE;
513164562Sgshapiro
513264562Sgshapiro  ph_map_lookup_abort:
513364562Sgshapiro	if (ev != NULL)
513490792Sgshapiro		sm_clrevent(ev);
513564562Sgshapiro
513664562Sgshapiro	/*
513790792Sgshapiro	**  Close the connection if the timer popped
513864562Sgshapiro	**  or we got a temporary PH error
513964562Sgshapiro	*/
514064562Sgshapiro
514164562Sgshapiro	if (*pstat == EX_TEMPFAIL)
514290792Sgshapiro	{
514390792Sgshapiro		save_errno = errno;
5144110560Sgshapiro		pmap->ph_fastclose = PH_CLOSE_FAST;
514590792Sgshapiro		ph_map_close(map);
514690792Sgshapiro		errno = save_errno;
514790792Sgshapiro	}
514864562Sgshapiro
514964562Sgshapiro	if (*pstat == EX_OK)
515064562Sgshapiro	{
515164562Sgshapiro		if (tTd(38,20))
515290792Sgshapiro			sm_dprintf("ph_map_lookup: %s => %s\n", key, value);
515364562Sgshapiro
515464562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
515590792Sgshapiro			return map_rewrite(map, key, strlen(key), NULL);
515664562Sgshapiro		else
515790792Sgshapiro			return map_rewrite(map, value, strlen(value), args);
515864562Sgshapiro	}
515964562Sgshapiro
516064562Sgshapiro	return NULL;
516164562Sgshapiro}
516264562Sgshapiro#endif /* PH_MAP */
5163168515Sgshapiro
516490792Sgshapiro/*
516542575Speter**  syslog map
516638032Speter*/
516738032Speter
516838032Speter#define map_prio	map_lockfd	/* overload field */
516938032Speter
517038032Speter/*
517142575Speter**  SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
517238032Speter*/
517338032Speter
517438032Speterbool
517538032Spetersyslog_map_parseargs(map, args)
517638032Speter	MAP *map;
517738032Speter	char *args;
517838032Speter{
517938032Speter	char *p = args;
518038032Speter	char *priority = NULL;
518138032Speter
518264562Sgshapiro	/* there is no check whether there is really an argument */
518364562Sgshapiro	while (*p != '\0')
518438032Speter	{
518538032Speter		while (isascii(*p) && isspace(*p))
518638032Speter			p++;
518738032Speter		if (*p != '-')
518838032Speter			break;
518964562Sgshapiro		++p;
519064562Sgshapiro		if (*p == 'D')
519164562Sgshapiro		{
519264562Sgshapiro			map->map_mflags |= MF_DEFER;
519364562Sgshapiro			++p;
519464562Sgshapiro		}
519564562Sgshapiro		else if (*p == 'S')
519664562Sgshapiro		{
519764562Sgshapiro			map->map_spacesub = *++p;
519864562Sgshapiro			if (*p != '\0')
519964562Sgshapiro				p++;
520064562Sgshapiro		}
520164562Sgshapiro		else if (*p == 'L')
520264562Sgshapiro		{
520364562Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p))
520464562Sgshapiro				continue;
520564562Sgshapiro			if (*p == '\0')
520664562Sgshapiro				break;
520764562Sgshapiro			priority = p;
520864562Sgshapiro			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
520964562Sgshapiro				p++;
521064562Sgshapiro			if (*p != '\0')
521164562Sgshapiro				*p++ = '\0';
521264562Sgshapiro		}
521364562Sgshapiro		else
521464562Sgshapiro		{
521564562Sgshapiro			syserr("Illegal option %c map syslog", *p);
521664562Sgshapiro			++p;
521764562Sgshapiro		}
521838032Speter	}
521938032Speter
522038032Speter	if (priority == NULL)
522138032Speter		map->map_prio = LOG_INFO;
522238032Speter	else
522338032Speter	{
522490792Sgshapiro		if (sm_strncasecmp("LOG_", priority, 4) == 0)
522538032Speter			priority += 4;
522638032Speter
522738032Speter#ifdef LOG_EMERG
522890792Sgshapiro		if (sm_strcasecmp("EMERG", priority) == 0)
522938032Speter			map->map_prio = LOG_EMERG;
523038032Speter		else
523164562Sgshapiro#endif /* LOG_EMERG */
523238032Speter#ifdef LOG_ALERT
523390792Sgshapiro		if (sm_strcasecmp("ALERT", priority) == 0)
523438032Speter			map->map_prio = LOG_ALERT;
523538032Speter		else
523664562Sgshapiro#endif /* LOG_ALERT */
523738032Speter#ifdef LOG_CRIT
523890792Sgshapiro		if (sm_strcasecmp("CRIT", priority) == 0)
523938032Speter			map->map_prio = LOG_CRIT;
524038032Speter		else
524164562Sgshapiro#endif /* LOG_CRIT */
524238032Speter#ifdef LOG_ERR
524390792Sgshapiro		if (sm_strcasecmp("ERR", priority) == 0)
524438032Speter			map->map_prio = LOG_ERR;
524538032Speter		else
524664562Sgshapiro#endif /* LOG_ERR */
524738032Speter#ifdef LOG_WARNING
524890792Sgshapiro		if (sm_strcasecmp("WARNING", priority) == 0)
524938032Speter			map->map_prio = LOG_WARNING;
525038032Speter		else
525164562Sgshapiro#endif /* LOG_WARNING */
525238032Speter#ifdef LOG_NOTICE
525390792Sgshapiro		if (sm_strcasecmp("NOTICE", priority) == 0)
525438032Speter			map->map_prio = LOG_NOTICE;
525538032Speter		else
525664562Sgshapiro#endif /* LOG_NOTICE */
525738032Speter#ifdef LOG_INFO
525890792Sgshapiro		if (sm_strcasecmp("INFO", priority) == 0)
525938032Speter			map->map_prio = LOG_INFO;
526038032Speter		else
526164562Sgshapiro#endif /* LOG_INFO */
526238032Speter#ifdef LOG_DEBUG
526390792Sgshapiro		if (sm_strcasecmp("DEBUG", priority) == 0)
526438032Speter			map->map_prio = LOG_DEBUG;
526538032Speter		else
526664562Sgshapiro#endif /* LOG_DEBUG */
526738032Speter		{
526890792Sgshapiro			syserr("syslog_map_parseargs: Unknown priority %s",
526938032Speter			       priority);
527090792Sgshapiro			return false;
527138032Speter		}
527238032Speter	}
527390792Sgshapiro	return true;
527438032Speter}
527538032Speter
527638032Speter/*
527742575Speter**  SYSLOG_MAP_LOOKUP -- rewrite and syslog message.  Always return empty string
527838032Speter*/
527938032Speter
528038032Speterchar *
528138032Spetersyslog_map_lookup(map, string, args, statp)
528238032Speter	MAP *map;
528338032Speter	char *string;
528438032Speter	char **args;
528538032Speter	int *statp;
528638032Speter{
528738032Speter	char *ptr = map_rewrite(map, string, strlen(string), args);
528838032Speter
528938032Speter	if (ptr != NULL)
529038032Speter	{
529138032Speter		if (tTd(38, 20))
529290792Sgshapiro			sm_dprintf("syslog_map_lookup(%s (priority %d): %s\n",
529364562Sgshapiro				map->map_mname, map->map_prio, ptr);
529438032Speter
529538032Speter		sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
529638032Speter	}
529738032Speter
529838032Speter	*statp = EX_OK;
529938032Speter	return "";
530038032Speter}
530138032Speter
5302168515Sgshapiro#if _FFR_DPRINTF_MAP
530390792Sgshapiro/*
5304168515Sgshapiro**  dprintf map
5305168515Sgshapiro*/
5306168515Sgshapiro
5307168515Sgshapiro#define map_dbg_level	map_lockfd	/* overload field */
5308168515Sgshapiro
5309168515Sgshapiro/*
5310168515Sgshapiro**  DPRINTF_MAP_PARSEARGS -- check for priority level to dprintf messages.
5311168515Sgshapiro*/
5312168515Sgshapiro
5313168515Sgshapirobool
5314168515Sgshapirodprintf_map_parseargs(map, args)
5315168515Sgshapiro	MAP *map;
5316168515Sgshapiro	char *args;
5317168515Sgshapiro{
5318168515Sgshapiro	char *p = args;
5319168515Sgshapiro	char *dbg_level = NULL;
5320168515Sgshapiro
5321168515Sgshapiro	/* there is no check whether there is really an argument */
5322168515Sgshapiro	while (*p != '\0')
5323168515Sgshapiro	{
5324168515Sgshapiro		while (isascii(*p) && isspace(*p))
5325168515Sgshapiro			p++;
5326168515Sgshapiro		if (*p != '-')
5327168515Sgshapiro			break;
5328168515Sgshapiro		++p;
5329168515Sgshapiro		if (*p == 'D')
5330168515Sgshapiro		{
5331168515Sgshapiro			map->map_mflags |= MF_DEFER;
5332168515Sgshapiro			++p;
5333168515Sgshapiro		}
5334168515Sgshapiro		else if (*p == 'S')
5335168515Sgshapiro		{
5336168515Sgshapiro			map->map_spacesub = *++p;
5337168515Sgshapiro			if (*p != '\0')
5338168515Sgshapiro				p++;
5339168515Sgshapiro		}
5340168515Sgshapiro		else if (*p == 'd')
5341168515Sgshapiro		{
5342168515Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p))
5343168515Sgshapiro				continue;
5344168515Sgshapiro			if (*p == '\0')
5345168515Sgshapiro				break;
5346168515Sgshapiro			dbg_level = p;
5347168515Sgshapiro			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
5348168515Sgshapiro				p++;
5349168515Sgshapiro			if (*p != '\0')
5350168515Sgshapiro				*p++ = '\0';
5351168515Sgshapiro		}
5352168515Sgshapiro		else
5353168515Sgshapiro		{
5354168515Sgshapiro			syserr("Illegal option %c map dprintf", *p);
5355168515Sgshapiro			++p;
5356168515Sgshapiro		}
5357168515Sgshapiro	}
5358168515Sgshapiro
5359168515Sgshapiro	if (dbg_level == NULL)
5360168515Sgshapiro		map->map_dbg_level = 0;
5361168515Sgshapiro	else
5362168515Sgshapiro	{
5363168515Sgshapiro		if (!(isascii(*dbg_level) && isdigit(*dbg_level)))
5364168515Sgshapiro		{
5365168515Sgshapiro			syserr("dprintf map \"%s\", file %s: -d should specify a number, not %s",
5366168515Sgshapiro				map->map_mname, map->map_file,
5367168515Sgshapiro				dbg_level);
5368168515Sgshapiro			return false;
5369168515Sgshapiro		}
5370168515Sgshapiro		map->map_dbg_level = atoi(dbg_level);
5371168515Sgshapiro	}
5372168515Sgshapiro	return true;
5373168515Sgshapiro}
5374168515Sgshapiro
5375168515Sgshapiro/*
5376168515Sgshapiro**  DPRINTF_MAP_LOOKUP -- rewrite and print message.  Always return empty string
5377168515Sgshapiro*/
5378168515Sgshapiro
5379168515Sgshapirochar *
5380168515Sgshapirodprintf_map_lookup(map, string, args, statp)
5381168515Sgshapiro	MAP *map;
5382168515Sgshapiro	char *string;
5383168515Sgshapiro	char **args;
5384168515Sgshapiro	int *statp;
5385168515Sgshapiro{
5386168515Sgshapiro	char *ptr = map_rewrite(map, string, strlen(string), args);
5387168515Sgshapiro
5388168515Sgshapiro	if (ptr != NULL && tTd(85, map->map_dbg_level))
5389168515Sgshapiro		sm_dprintf("%s\n", ptr);
5390168515Sgshapiro	*statp = EX_OK;
5391168515Sgshapiro	return "";
5392168515Sgshapiro}
5393168515Sgshapiro#endif /* _FFR_DPRINTF_MAP */
5394168515Sgshapiro
5395168515Sgshapiro/*
539638032Speter**  HESIOD Modules
539738032Speter*/
539838032Speter
539990792Sgshapiro#if HESIOD
540038032Speter
540138032Speterbool
540238032Speterhes_map_open(map, mode)
540338032Speter	MAP *map;
540438032Speter	int mode;
540538032Speter{
540638032Speter	if (tTd(38, 2))
540790792Sgshapiro		sm_dprintf("hes_map_open(%s, %s, %d)\n",
540838032Speter			map->map_mname, map->map_file, mode);
540938032Speter
541038032Speter	if (mode != O_RDONLY)
541138032Speter	{
541238032Speter		/* issue a pseudo-error message */
541390792Sgshapiro		errno = SM_EMAPCANTWRITE;
541490792Sgshapiro		return false;
541538032Speter	}
541638032Speter
541764562Sgshapiro# ifdef HESIOD_INIT
541838032Speter	if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
541990792Sgshapiro		return true;
542038032Speter
542138032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
542294334Sgshapiro		syserr("451 4.3.5 cannot initialize Hesiod map (%s)",
542390792Sgshapiro			sm_errstring(errno));
542490792Sgshapiro	return false;
542564562Sgshapiro# else /* HESIOD_INIT */
542638032Speter	if (hes_error() == HES_ER_UNINIT)
542738032Speter		hes_init();
542838032Speter	switch (hes_error())
542938032Speter	{
543038032Speter	  case HES_ER_OK:
543138032Speter	  case HES_ER_NOTFOUND:
543290792Sgshapiro		return true;
543338032Speter	}
543438032Speter
543538032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
543694334Sgshapiro		syserr("451 4.3.5 cannot initialize Hesiod map (%d)", hes_error());
543738032Speter
543890792Sgshapiro	return false;
543964562Sgshapiro# endif /* HESIOD_INIT */
544038032Speter}
544138032Speter
544238032Speterchar *
544338032Speterhes_map_lookup(map, name, av, statp)
544438032Speter	MAP *map;
544538032Speter	char *name;
544638032Speter	char **av;
544738032Speter	int *statp;
544838032Speter{
544938032Speter	char **hp;
545038032Speter
545138032Speter	if (tTd(38, 20))
545290792Sgshapiro		sm_dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
545338032Speter
545438032Speter	if (name[0] == '\\')
545538032Speter	{
545638032Speter		char *np;
545738032Speter		int nl;
545877349Sgshapiro		int save_errno;
545938032Speter		char nbuf[MAXNAME];
546038032Speter
546138032Speter		nl = strlen(name);
5462168515Sgshapiro		if (nl < sizeof(nbuf) - 1)
546338032Speter			np = nbuf;
546438032Speter		else
546538032Speter			np = xalloc(strlen(name) + 2);
546638032Speter		np[0] = '\\';
5467168515Sgshapiro		(void) sm_strlcpy(&np[1], name, (sizeof(nbuf)) - 1);
546864562Sgshapiro# ifdef HESIOD_INIT
546938032Speter		hp = hesiod_resolve(HesiodContext, np, map->map_file);
547064562Sgshapiro# else /* HESIOD_INIT */
547138032Speter		hp = hes_resolve(np, map->map_file);
547264562Sgshapiro# endif /* HESIOD_INIT */
547377349Sgshapiro		save_errno = errno;
547438032Speter		if (np != nbuf)
547590792Sgshapiro			sm_free(np); /* XXX */
547677349Sgshapiro		errno = save_errno;
547738032Speter	}
547838032Speter	else
547938032Speter	{
548064562Sgshapiro# ifdef HESIOD_INIT
548138032Speter		hp = hesiod_resolve(HesiodContext, name, map->map_file);
548264562Sgshapiro# else /* HESIOD_INIT */
548338032Speter		hp = hes_resolve(name, map->map_file);
548464562Sgshapiro# endif /* HESIOD_INIT */
548538032Speter	}
548664562Sgshapiro# ifdef HESIOD_INIT
548777349Sgshapiro	if (hp == NULL || *hp == NULL)
548838032Speter	{
548938032Speter		switch (errno)
549038032Speter		{
549138032Speter		  case ENOENT:
549238032Speter			  *statp = EX_NOTFOUND;
549338032Speter			  break;
549438032Speter		  case ECONNREFUSED:
549538032Speter			  *statp = EX_TEMPFAIL;
549638032Speter			  break;
549790792Sgshapiro		  case EMSGSIZE:
549838032Speter		  case ENOMEM:
549938032Speter		  default:
550038032Speter			  *statp = EX_UNAVAILABLE;
550138032Speter			  break;
550238032Speter		}
550382017Sgshapiro		if (hp != NULL)
550482017Sgshapiro			hesiod_free_list(HesiodContext, hp);
550538032Speter		return NULL;
550638032Speter	}
550764562Sgshapiro# else /* HESIOD_INIT */
550838032Speter	if (hp == NULL || hp[0] == NULL)
550938032Speter	{
551038032Speter		switch (hes_error())
551138032Speter		{
551238032Speter		  case HES_ER_OK:
551338032Speter			*statp = EX_OK;
551438032Speter			break;
551538032Speter
551638032Speter		  case HES_ER_NOTFOUND:
551738032Speter			*statp = EX_NOTFOUND;
551838032Speter			break;
551938032Speter
552038032Speter		  case HES_ER_CONFIG:
552138032Speter			*statp = EX_UNAVAILABLE;
552238032Speter			break;
552338032Speter
552438032Speter		  case HES_ER_NET:
552538032Speter			*statp = EX_TEMPFAIL;
552638032Speter			break;
552738032Speter		}
552838032Speter		return NULL;
552938032Speter	}
553064562Sgshapiro# endif /* HESIOD_INIT */
553138032Speter
553238032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
553338032Speter		return map_rewrite(map, name, strlen(name), NULL);
553438032Speter	else
553538032Speter		return map_rewrite(map, hp[0], strlen(hp[0]), av);
553638032Speter}
553738032Speter
553890792Sgshapiro/*
553990792Sgshapiro**  HES_MAP_CLOSE -- free the Hesiod context
554090792Sgshapiro*/
554190792Sgshapiro
554290792Sgshapirovoid
554390792Sgshapirohes_map_close(map)
554490792Sgshapiro	MAP *map;
554590792Sgshapiro{
554690792Sgshapiro	if (tTd(38, 20))
554790792Sgshapiro		sm_dprintf("hes_map_close(%s)\n", map->map_file);
554890792Sgshapiro
554990792Sgshapiro# ifdef HESIOD_INIT
555090792Sgshapiro	/* Free the hesiod context */
555190792Sgshapiro	if (HesiodContext != NULL)
555290792Sgshapiro	{
555390792Sgshapiro		hesiod_end(HesiodContext);
555490792Sgshapiro		HesiodContext = NULL;
555590792Sgshapiro	}
555690792Sgshapiro# endif /* HESIOD_INIT */
555790792Sgshapiro}
555890792Sgshapiro
555964562Sgshapiro#endif /* HESIOD */
556090792Sgshapiro/*
556138032Speter**  NeXT NETINFO Modules
556238032Speter*/
556338032Speter
556438032Speter#if NETINFO
556538032Speter
556638032Speter# define NETINFO_DEFAULT_DIR		"/aliases"
556738032Speter# define NETINFO_DEFAULT_PROPERTY	"members"
556838032Speter
556938032Speter/*
557038032Speter**  NI_MAP_OPEN -- open NetInfo Aliases
557138032Speter*/
557238032Speter
557338032Speterbool
557438032Speterni_map_open(map, mode)
557538032Speter	MAP *map;
557638032Speter	int mode;
557738032Speter{
557838032Speter	if (tTd(38, 2))
557990792Sgshapiro		sm_dprintf("ni_map_open(%s, %s, %d)\n",
558038032Speter			map->map_mname, map->map_file, mode);
558138032Speter	mode &= O_ACCMODE;
558238032Speter
558338032Speter	if (*map->map_file == '\0')
558438032Speter		map->map_file = NETINFO_DEFAULT_DIR;
558538032Speter
558638032Speter	if (map->map_valcolnm == NULL)
558738032Speter		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
558838032Speter
558990792Sgshapiro	if (map->map_coldelim == '\0')
559090792Sgshapiro	{
559190792Sgshapiro		if (bitset(MF_ALIAS, map->map_mflags))
559290792Sgshapiro			map->map_coldelim = ',';
559390792Sgshapiro		else if (bitset(MF_FILECLASS, map->map_mflags))
559490792Sgshapiro			map->map_coldelim = ' ';
559590792Sgshapiro	}
559690792Sgshapiro	return true;
559738032Speter}
559838032Speter
559938032Speter
560038032Speter/*
560138032Speter**  NI_MAP_LOOKUP -- look up a datum in NetInfo
560238032Speter*/
560338032Speter
560438032Speterchar *
560538032Speterni_map_lookup(map, name, av, statp)
560638032Speter	MAP *map;
560738032Speter	char *name;
560838032Speter	char **av;
560938032Speter	int *statp;
561038032Speter{
561138032Speter	char *res;
561238032Speter	char *propval;
561338032Speter
561438032Speter	if (tTd(38, 20))
561590792Sgshapiro		sm_dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
561638032Speter
561738032Speter	propval = ni_propval(map->map_file, map->map_keycolnm, name,
561838032Speter			     map->map_valcolnm, map->map_coldelim);
561938032Speter
562038032Speter	if (propval == NULL)
562138032Speter		return NULL;
562238032Speter
562390792Sgshapiro	SM_TRY
562490792Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
562590792Sgshapiro			res = map_rewrite(map, name, strlen(name), NULL);
562690792Sgshapiro		else
562790792Sgshapiro			res = map_rewrite(map, propval, strlen(propval), av);
562890792Sgshapiro	SM_FINALLY
562990792Sgshapiro		sm_free(propval);
563090792Sgshapiro	SM_END_TRY
563138032Speter	return res;
563238032Speter}
563338032Speter
563438032Speter
563564562Sgshapirostatic bool
563638032Speterni_getcanonname(name, hbsize, statp)
563738032Speter	char *name;
563838032Speter	int hbsize;
563938032Speter	int *statp;
564038032Speter{
564138032Speter	char *vptr;
564238032Speter	char *ptr;
564338032Speter	char nbuf[MAXNAME + 1];
564438032Speter
564538032Speter	if (tTd(38, 20))
564690792Sgshapiro		sm_dprintf("ni_getcanonname(%s)\n", name);
564738032Speter
5648168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
564938032Speter	{
565038032Speter		*statp = EX_UNAVAILABLE;
565190792Sgshapiro		return false;
565238032Speter	}
565373188Sgshapiro	(void) shorten_hostname(nbuf);
565438032Speter
565538032Speter	/* we only accept single token search key */
565638032Speter	if (strchr(nbuf, '.'))
565738032Speter	{
565838032Speter		*statp = EX_NOHOST;
565990792Sgshapiro		return false;
566038032Speter	}
566138032Speter
566238032Speter	/* Do the search */
566338032Speter	vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
566438032Speter
566538032Speter	if (vptr == NULL)
566638032Speter	{
566738032Speter		*statp = EX_NOHOST;
566890792Sgshapiro		return false;
566938032Speter	}
567038032Speter
567138032Speter	/* Only want the first machine name */
567238032Speter	if ((ptr = strchr(vptr, '\n')) != NULL)
567338032Speter		*ptr = '\0';
567438032Speter
567590792Sgshapiro	if (sm_strlcpy(name, vptr, hbsize) >= hbsize)
567638032Speter	{
567777349Sgshapiro		sm_free(vptr);
567890792Sgshapiro		*statp = EX_UNAVAILABLE;
567990792Sgshapiro		return true;
568038032Speter	}
568177349Sgshapiro	sm_free(vptr);
568290792Sgshapiro	*statp = EX_OK;
568390792Sgshapiro	return false;
568438032Speter}
568590792Sgshapiro#endif /* NETINFO */
568638032Speter/*
568738032Speter**  TEXT (unindexed text file) Modules
568838032Speter**
568938032Speter**	This code donated by Sun Microsystems.
569038032Speter*/
569138032Speter
569238032Speter#define map_sff		map_lockfd	/* overload field */
569338032Speter
569438032Speter
569538032Speter/*
569638032Speter**  TEXT_MAP_OPEN -- open text table
569738032Speter*/
569838032Speter
569938032Speterbool
570038032Spetertext_map_open(map, mode)
570138032Speter	MAP *map;
570238032Speter	int mode;
570338032Speter{
570464562Sgshapiro	long sff;
570538032Speter	int i;
570638032Speter
570738032Speter	if (tTd(38, 2))
570890792Sgshapiro		sm_dprintf("text_map_open(%s, %s, %d)\n",
570938032Speter			map->map_mname, map->map_file, mode);
571038032Speter
571138032Speter	mode &= O_ACCMODE;
571238032Speter	if (mode != O_RDONLY)
571338032Speter	{
571438032Speter		errno = EPERM;
571590792Sgshapiro		return false;
571638032Speter	}
571738032Speter
571838032Speter	if (*map->map_file == '\0')
571938032Speter	{
572038032Speter		syserr("text map \"%s\": file name required",
572138032Speter			map->map_mname);
572290792Sgshapiro		return false;
572338032Speter	}
572438032Speter
572538032Speter	if (map->map_file[0] != '/')
572638032Speter	{
572738032Speter		syserr("text map \"%s\": file name must be fully qualified",
572838032Speter			map->map_mname);
572990792Sgshapiro		return false;
573038032Speter	}
573138032Speter
573238032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
573364562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
573438032Speter		sff |= SFF_NOWLINK;
573564562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
573638032Speter		sff |= SFF_SAFEDIRPATH;
573738032Speter	if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
573838032Speter			  sff, S_IRUSR, NULL)) != 0)
573938032Speter	{
574064562Sgshapiro		int save_errno = errno;
574164562Sgshapiro
574238032Speter		/* cannot open this map */
574338032Speter		if (tTd(38, 2))
574490792Sgshapiro			sm_dprintf("\tunsafe map file: %d\n", i);
574564562Sgshapiro		errno = save_errno;
574638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
574738032Speter			syserr("text map \"%s\": unsafe map file %s",
574838032Speter				map->map_mname, map->map_file);
574990792Sgshapiro		return false;
575038032Speter	}
575138032Speter
575238032Speter	if (map->map_keycolnm == NULL)
575338032Speter		map->map_keycolno = 0;
575438032Speter	else
575538032Speter	{
575638032Speter		if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
575738032Speter		{
575838032Speter			syserr("text map \"%s\", file %s: -k should specify a number, not %s",
575938032Speter				map->map_mname, map->map_file,
576038032Speter				map->map_keycolnm);
576190792Sgshapiro			return false;
576238032Speter		}
576338032Speter		map->map_keycolno = atoi(map->map_keycolnm);
576438032Speter	}
576538032Speter
576638032Speter	if (map->map_valcolnm == NULL)
576738032Speter		map->map_valcolno = 0;
576838032Speter	else
576938032Speter	{
577038032Speter		if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
577138032Speter		{
577238032Speter			syserr("text map \"%s\", file %s: -v should specify a number, not %s",
577338032Speter					map->map_mname, map->map_file,
577438032Speter					map->map_valcolnm);
577590792Sgshapiro			return false;
577638032Speter		}
577738032Speter		map->map_valcolno = atoi(map->map_valcolnm);
577838032Speter	}
577938032Speter
578038032Speter	if (tTd(38, 2))
578138032Speter	{
578290792Sgshapiro		sm_dprintf("text_map_open(%s, %s): delimiter = ",
578338032Speter			map->map_mname, map->map_file);
578438032Speter		if (map->map_coldelim == '\0')
578590792Sgshapiro			sm_dprintf("(white space)\n");
578638032Speter		else
578790792Sgshapiro			sm_dprintf("%c\n", map->map_coldelim);
578838032Speter	}
578938032Speter
579038032Speter	map->map_sff = sff;
579190792Sgshapiro	return true;
579238032Speter}
579338032Speter
579438032Speter
579538032Speter/*
579638032Speter**  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
579738032Speter*/
579838032Speter
579938032Speterchar *
580038032Spetertext_map_lookup(map, name, av, statp)
580138032Speter	MAP *map;
580238032Speter	char *name;
580338032Speter	char **av;
580438032Speter	int *statp;
580538032Speter{
580638032Speter	char *vp;
580738032Speter	auto int vsize;
580838032Speter	int buflen;
580990792Sgshapiro	SM_FILE_T *f;
581038032Speter	char delim;
581138032Speter	int key_idx;
581238032Speter	bool found_it;
581364562Sgshapiro	long sff = map->map_sff;
581438032Speter	char search_key[MAXNAME + 1];
581538032Speter	char linebuf[MAXLINE];
581638032Speter	char buf[MAXNAME + 1];
581738032Speter
581890792Sgshapiro	found_it = false;
581938032Speter	if (tTd(38, 20))
582090792Sgshapiro		sm_dprintf("text_map_lookup(%s, %s)\n", map->map_mname,  name);
582138032Speter
582238032Speter	buflen = strlen(name);
5823168515Sgshapiro	if (buflen > sizeof(search_key) - 1)
5824168515Sgshapiro		buflen = sizeof(search_key) - 1;	/* XXX just cut if off? */
582564562Sgshapiro	memmove(search_key, name, buflen);
582638032Speter	search_key[buflen] = '\0';
582738032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
582838032Speter		makelower(search_key);
582938032Speter
583038032Speter	f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
583138032Speter	if (f == NULL)
583238032Speter	{
583338032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
583438032Speter		*statp = EX_UNAVAILABLE;
583538032Speter		return NULL;
583638032Speter	}
583738032Speter	key_idx = map->map_keycolno;
583838032Speter	delim = map->map_coldelim;
583998121Sgshapiro	while (sm_io_fgets(f, SM_TIME_DEFAULT,
5840249729Sgshapiro			   linebuf, sizeof(linebuf)) >= 0)
584138032Speter	{
584238032Speter		char *p;
584338032Speter
584438032Speter		/* skip comment line */
584538032Speter		if (linebuf[0] == '#')
584638032Speter			continue;
584738032Speter		p = strchr(linebuf, '\n');
584838032Speter		if (p != NULL)
584938032Speter			*p = '\0';
5850168515Sgshapiro		p = get_column(linebuf, key_idx, delim, buf, sizeof(buf));
585190792Sgshapiro		if (p != NULL && sm_strcasecmp(search_key, p) == 0)
585238032Speter		{
585390792Sgshapiro			found_it = true;
585438032Speter			break;
585538032Speter		}
585638032Speter	}
585790792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
585838032Speter	if (!found_it)
585938032Speter	{
586038032Speter		*statp = EX_NOTFOUND;
586138032Speter		return NULL;
586238032Speter	}
5863168515Sgshapiro	vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof(buf));
586442575Speter	if (vp == NULL)
586542575Speter	{
586642575Speter		*statp = EX_NOTFOUND;
586742575Speter		return NULL;
586842575Speter	}
586938032Speter	vsize = strlen(vp);
587038032Speter	*statp = EX_OK;
587138032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
587238032Speter		return map_rewrite(map, name, strlen(name), NULL);
587338032Speter	else
587438032Speter		return map_rewrite(map, vp, vsize, av);
587538032Speter}
587638032Speter
587738032Speter/*
587838032Speter**  TEXT_GETCANONNAME -- look up canonical name in hosts file
587938032Speter*/
588038032Speter
588164562Sgshapirostatic bool
588238032Spetertext_getcanonname(name, hbsize, statp)
588338032Speter	char *name;
588438032Speter	int hbsize;
588538032Speter	int *statp;
588638032Speter{
588738032Speter	bool found;
588873188Sgshapiro	char *dot;
588990792Sgshapiro	SM_FILE_T *f;
589038032Speter	char linebuf[MAXLINE];
589138032Speter	char cbuf[MAXNAME + 1];
589238032Speter	char nbuf[MAXNAME + 1];
589338032Speter
589438032Speter	if (tTd(38, 20))
589590792Sgshapiro		sm_dprintf("text_getcanonname(%s)\n", name);
589638032Speter
5897168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
589838032Speter	{
589938032Speter		*statp = EX_UNAVAILABLE;
590090792Sgshapiro		return false;
590138032Speter	}
590273188Sgshapiro	dot = shorten_hostname(nbuf);
590338032Speter
590490792Sgshapiro	f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, HostsFile, SM_IO_RDONLY,
590590792Sgshapiro		       NULL);
590638032Speter	if (f == NULL)
590738032Speter	{
590838032Speter		*statp = EX_UNAVAILABLE;
590990792Sgshapiro		return false;
591038032Speter	}
591190792Sgshapiro	found = false;
591290792Sgshapiro	while (!found &&
591398121Sgshapiro		sm_io_fgets(f, SM_TIME_DEFAULT,
5914249729Sgshapiro			    linebuf, sizeof(linebuf)) >= 0)
591538032Speter	{
591638032Speter		char *p = strpbrk(linebuf, "#\n");
591738032Speter
591838032Speter		if (p != NULL)
591938032Speter			*p = '\0';
592038032Speter		if (linebuf[0] != '\0')
592173188Sgshapiro			found = extract_canonname(nbuf, dot, linebuf,
5922168515Sgshapiro						  cbuf, sizeof(cbuf));
592338032Speter	}
592490792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
592538032Speter	if (!found)
592638032Speter	{
592738032Speter		*statp = EX_NOHOST;
592890792Sgshapiro		return false;
592938032Speter	}
593038032Speter
593190792Sgshapiro	if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
593238032Speter	{
593390792Sgshapiro		*statp = EX_UNAVAILABLE;
593490792Sgshapiro		return false;
593538032Speter	}
593690792Sgshapiro	*statp = EX_OK;
593790792Sgshapiro	return true;
593838032Speter}
593990792Sgshapiro/*
594038032Speter**  STAB (Symbol Table) Modules
594138032Speter*/
594238032Speter
594338032Speter
594438032Speter/*
594538032Speter**  STAB_MAP_LOOKUP -- look up alias in symbol table
594638032Speter*/
594738032Speter
594838032Speter/* ARGSUSED2 */
594938032Speterchar *
595038032Speterstab_map_lookup(map, name, av, pstat)
595138032Speter	register MAP *map;
595238032Speter	char *name;
595338032Speter	char **av;
595438032Speter	int *pstat;
595538032Speter{
595638032Speter	register STAB *s;
595738032Speter
595838032Speter	if (tTd(38, 20))
595990792Sgshapiro		sm_dprintf("stab_lookup(%s, %s)\n",
596038032Speter			map->map_mname, name);
596138032Speter
596238032Speter	s = stab(name, ST_ALIAS, ST_FIND);
5963147078Sgshapiro	if (s == NULL)
5964147078Sgshapiro		return NULL;
5965147078Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
5966147078Sgshapiro		return map_rewrite(map, name, strlen(name), NULL);
5967147078Sgshapiro	else
5968147078Sgshapiro		return map_rewrite(map, s->s_alias, strlen(s->s_alias), av);
596938032Speter}
597038032Speter
597138032Speter/*
597238032Speter**  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
597338032Speter*/
597438032Speter
597538032Spetervoid
597638032Speterstab_map_store(map, lhs, rhs)
597738032Speter	register MAP *map;
597838032Speter	char *lhs;
597938032Speter	char *rhs;
598038032Speter{
598138032Speter	register STAB *s;
598238032Speter
598338032Speter	s = stab(lhs, ST_ALIAS, ST_ENTER);
598438032Speter	s->s_alias = newstr(rhs);
598538032Speter}
598638032Speter
598738032Speter
598838032Speter/*
598938032Speter**  STAB_MAP_OPEN -- initialize (reads data file)
599038032Speter**
5991223067Sgshapiro**	This is a weird case -- it is only intended as a fallback for
599238032Speter**	aliases.  For this reason, opens for write (only during a
599338032Speter**	"newaliases") always fails, and opens for read open the
599438032Speter**	actual underlying text file instead of the database.
599538032Speter*/
599638032Speter
599738032Speterbool
599838032Speterstab_map_open(map, mode)
599938032Speter	register MAP *map;
600038032Speter	int mode;
600138032Speter{
600290792Sgshapiro	SM_FILE_T *af;
600364562Sgshapiro	long sff;
600438032Speter	struct stat st;
600538032Speter
600638032Speter	if (tTd(38, 2))
600790792Sgshapiro		sm_dprintf("stab_map_open(%s, %s, %d)\n",
600838032Speter			map->map_mname, map->map_file, mode);
600938032Speter
601038032Speter	mode &= O_ACCMODE;
601138032Speter	if (mode != O_RDONLY)
601238032Speter	{
601338032Speter		errno = EPERM;
601490792Sgshapiro		return false;
601538032Speter	}
601638032Speter
601738032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
601864562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
601938032Speter		sff |= SFF_NOWLINK;
602064562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
602138032Speter		sff |= SFF_SAFEDIRPATH;
602238032Speter	af = safefopen(map->map_file, O_RDONLY, 0444, sff);
602338032Speter	if (af == NULL)
602490792Sgshapiro		return false;
602590792Sgshapiro	readaliases(map, af, false, false);
602638032Speter
602790792Sgshapiro	if (fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &st) >= 0)
602838032Speter		map->map_mtime = st.st_mtime;
602990792Sgshapiro	(void) sm_io_close(af, SM_TIME_DEFAULT);
603038032Speter
603190792Sgshapiro	return true;
603238032Speter}
603390792Sgshapiro/*
603438032Speter**  Implicit Modules
603538032Speter**
603638032Speter**	Tries several types.  For back compatibility of aliases.
603738032Speter*/
603838032Speter
603938032Speter
604038032Speter/*
604138032Speter**  IMPL_MAP_LOOKUP -- lookup in best open database
604238032Speter*/
604338032Speter
604438032Speterchar *
604538032Speterimpl_map_lookup(map, name, av, pstat)
604638032Speter	MAP *map;
604738032Speter	char *name;
604838032Speter	char **av;
604938032Speter	int *pstat;
605038032Speter{
605138032Speter	if (tTd(38, 20))
605290792Sgshapiro		sm_dprintf("impl_map_lookup(%s, %s)\n",
605338032Speter			map->map_mname, name);
605438032Speter
605590792Sgshapiro#if NEWDB
605638032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
605738032Speter		return db_map_lookup(map, name, av, pstat);
605864562Sgshapiro#endif /* NEWDB */
605990792Sgshapiro#if NDBM
606038032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
606138032Speter		return ndbm_map_lookup(map, name, av, pstat);
606264562Sgshapiro#endif /* NDBM */
606338032Speter	return stab_map_lookup(map, name, av, pstat);
606438032Speter}
606538032Speter
606638032Speter/*
606738032Speter**  IMPL_MAP_STORE -- store in open databases
606838032Speter*/
606938032Speter
607038032Spetervoid
607138032Speterimpl_map_store(map, lhs, rhs)
607238032Speter	MAP *map;
607338032Speter	char *lhs;
607438032Speter	char *rhs;
607538032Speter{
607638032Speter	if (tTd(38, 12))
607790792Sgshapiro		sm_dprintf("impl_map_store(%s, %s, %s)\n",
607838032Speter			map->map_mname, lhs, rhs);
607990792Sgshapiro#if NEWDB
608038032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
608138032Speter		db_map_store(map, lhs, rhs);
608264562Sgshapiro#endif /* NEWDB */
608390792Sgshapiro#if NDBM
608438032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
608538032Speter		ndbm_map_store(map, lhs, rhs);
608664562Sgshapiro#endif /* NDBM */
608738032Speter	stab_map_store(map, lhs, rhs);
608838032Speter}
608938032Speter
609038032Speter/*
609138032Speter**  IMPL_MAP_OPEN -- implicit database open
609238032Speter*/
609338032Speter
609438032Speterbool
609538032Speterimpl_map_open(map, mode)
609638032Speter	MAP *map;
609738032Speter	int mode;
609838032Speter{
609938032Speter	if (tTd(38, 2))
610090792Sgshapiro		sm_dprintf("impl_map_open(%s, %s, %d)\n",
610138032Speter			map->map_mname, map->map_file, mode);
610238032Speter
610338032Speter	mode &= O_ACCMODE;
610490792Sgshapiro#if NEWDB
610538032Speter	map->map_mflags |= MF_IMPL_HASH;
610638032Speter	if (hash_map_open(map, mode))
610738032Speter	{
610838032Speter# ifdef NDBM_YP_COMPAT
610938032Speter		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
611064562Sgshapiro# endif /* NDBM_YP_COMPAT */
611190792Sgshapiro			return true;
611238032Speter	}
611338032Speter	else
611438032Speter		map->map_mflags &= ~MF_IMPL_HASH;
611564562Sgshapiro#endif /* NEWDB */
611690792Sgshapiro#if NDBM
611738032Speter	map->map_mflags |= MF_IMPL_NDBM;
611838032Speter	if (ndbm_map_open(map, mode))
611938032Speter	{
612090792Sgshapiro		return true;
612138032Speter	}
612238032Speter	else
612338032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
612464562Sgshapiro#endif /* NDBM */
612538032Speter
612638032Speter#if defined(NEWDB) || defined(NDBM)
612738032Speter	if (Verbose)
612838032Speter		message("WARNING: cannot open alias database %s%s",
612938032Speter			map->map_file,
613038032Speter			mode == O_RDONLY ? "; reading text version" : "");
613164562Sgshapiro#else /* defined(NEWDB) || defined(NDBM) */
613238032Speter	if (mode != O_RDONLY)
613338032Speter		usrerr("Cannot rebuild aliases: no database format defined");
613464562Sgshapiro#endif /* defined(NEWDB) || defined(NDBM) */
613538032Speter
613638032Speter	if (mode == O_RDONLY)
613738032Speter		return stab_map_open(map, mode);
613838032Speter	else
613990792Sgshapiro		return false;
614038032Speter}
614138032Speter
614238032Speter
614338032Speter/*
614438032Speter**  IMPL_MAP_CLOSE -- close any open database(s)
614538032Speter*/
614638032Speter
614738032Spetervoid
614838032Speterimpl_map_close(map)
614938032Speter	MAP *map;
615038032Speter{
615138032Speter	if (tTd(38, 9))
615290792Sgshapiro		sm_dprintf("impl_map_close(%s, %s, %lx)\n",
615338032Speter			map->map_mname, map->map_file, map->map_mflags);
615490792Sgshapiro#if NEWDB
615538032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
615638032Speter	{
615738032Speter		db_map_close(map);
615838032Speter		map->map_mflags &= ~MF_IMPL_HASH;
615938032Speter	}
616064562Sgshapiro#endif /* NEWDB */
616138032Speter
616290792Sgshapiro#if NDBM
616338032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
616438032Speter	{
616538032Speter		ndbm_map_close(map);
616638032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
616738032Speter	}
616864562Sgshapiro#endif /* NDBM */
616938032Speter}
617090792Sgshapiro/*
617138032Speter**  User map class.
617238032Speter**
617338032Speter**	Provides access to the system password file.
617438032Speter*/
617538032Speter
617638032Speter/*
617738032Speter**  USER_MAP_OPEN -- open user map
617838032Speter**
617938032Speter**	Really just binds field names to field numbers.
618038032Speter*/
618138032Speter
618238032Speterbool
618338032Speteruser_map_open(map, mode)
618438032Speter	MAP *map;
618538032Speter	int mode;
618638032Speter{
618738032Speter	if (tTd(38, 2))
618890792Sgshapiro		sm_dprintf("user_map_open(%s, %d)\n",
618938032Speter			map->map_mname, mode);
619038032Speter
619138032Speter	mode &= O_ACCMODE;
619238032Speter	if (mode != O_RDONLY)
619338032Speter	{
619438032Speter		/* issue a pseudo-error message */
619590792Sgshapiro		errno = SM_EMAPCANTWRITE;
619690792Sgshapiro		return false;
619738032Speter	}
619838032Speter	if (map->map_valcolnm == NULL)
619964562Sgshapiro		/* EMPTY */
620038032Speter		/* nothing */ ;
620190792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "name") == 0)
620238032Speter		map->map_valcolno = 1;
620390792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "passwd") == 0)
620438032Speter		map->map_valcolno = 2;
620590792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "uid") == 0)
620638032Speter		map->map_valcolno = 3;
620790792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "gid") == 0)
620838032Speter		map->map_valcolno = 4;
620990792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "gecos") == 0)
621038032Speter		map->map_valcolno = 5;
621190792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "dir") == 0)
621238032Speter		map->map_valcolno = 6;
621390792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "shell") == 0)
621438032Speter		map->map_valcolno = 7;
621538032Speter	else
621638032Speter	{
621738032Speter		syserr("User map %s: unknown column name %s",
621838032Speter			map->map_mname, map->map_valcolnm);
621990792Sgshapiro		return false;
622038032Speter	}
622190792Sgshapiro	return true;
622238032Speter}
622338032Speter
622438032Speter
622538032Speter/*
622638032Speter**  USER_MAP_LOOKUP -- look up a user in the passwd file.
622738032Speter*/
622838032Speter
622938032Speter/* ARGSUSED3 */
623038032Speterchar *
623138032Speteruser_map_lookup(map, key, av, statp)
623238032Speter	MAP *map;
623338032Speter	char *key;
623438032Speter	char **av;
623538032Speter	int *statp;
623638032Speter{
623738032Speter	auto bool fuzzy;
623890792Sgshapiro	SM_MBDB_T user;
623938032Speter
624038032Speter	if (tTd(38, 20))
624190792Sgshapiro		sm_dprintf("user_map_lookup(%s, %s)\n",
624238032Speter			map->map_mname, key);
624338032Speter
624490792Sgshapiro	*statp = finduser(key, &fuzzy, &user);
624590792Sgshapiro	if (*statp != EX_OK)
624638032Speter		return NULL;
624738032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
624838032Speter		return map_rewrite(map, key, strlen(key), NULL);
624938032Speter	else
625038032Speter	{
625138032Speter		char *rwval = NULL;
625238032Speter		char buf[30];
625338032Speter
625438032Speter		switch (map->map_valcolno)
625538032Speter		{
625638032Speter		  case 0:
625738032Speter		  case 1:
625890792Sgshapiro			rwval = user.mbdb_name;
625938032Speter			break;
626038032Speter
626138032Speter		  case 2:
626290792Sgshapiro			rwval = "x";	/* passwd no longer supported */
626338032Speter			break;
626438032Speter
626538032Speter		  case 3:
6266168515Sgshapiro			(void) sm_snprintf(buf, sizeof(buf), "%d",
626790792Sgshapiro					   (int) user.mbdb_uid);
626838032Speter			rwval = buf;
626938032Speter			break;
627038032Speter
627138032Speter		  case 4:
6272168515Sgshapiro			(void) sm_snprintf(buf, sizeof(buf), "%d",
627390792Sgshapiro					   (int) user.mbdb_gid);
627438032Speter			rwval = buf;
627538032Speter			break;
627638032Speter
627738032Speter		  case 5:
627890792Sgshapiro			rwval = user.mbdb_fullname;
627938032Speter			break;
628038032Speter
628138032Speter		  case 6:
628290792Sgshapiro			rwval = user.mbdb_homedir;
628338032Speter			break;
628438032Speter
628538032Speter		  case 7:
628690792Sgshapiro			rwval = user.mbdb_shell;
628738032Speter			break;
6288159609Sgshapiro		  default:
6289159609Sgshapiro			syserr("user_map %s: bogus field %d",
6290159609Sgshapiro				map->map_mname, map->map_valcolno);
6291159609Sgshapiro			return NULL;
629238032Speter		}
629338032Speter		return map_rewrite(map, rwval, strlen(rwval), av);
629438032Speter	}
629538032Speter}
629690792Sgshapiro/*
629738032Speter**  Program map type.
629838032Speter**
629938032Speter**	This provides access to arbitrary programs.  It should be used
630038032Speter**	only very sparingly, since there is no way to bound the cost
630138032Speter**	of invoking an arbitrary program.
630238032Speter*/
630338032Speter
630438032Speterchar *
630538032Speterprog_map_lookup(map, name, av, statp)
630638032Speter	MAP *map;
630738032Speter	char *name;
630838032Speter	char **av;
630938032Speter	int *statp;
631038032Speter{
631138032Speter	int i;
631264562Sgshapiro	int save_errno;
631338032Speter	int fd;
631464562Sgshapiro	int status;
631538032Speter	auto pid_t pid;
631664562Sgshapiro	register char *p;
631738032Speter	char *rval;
631838032Speter	char *argv[MAXPV + 1];
631938032Speter	char buf[MAXLINE];
632038032Speter
632138032Speter	if (tTd(38, 20))
632290792Sgshapiro		sm_dprintf("prog_map_lookup(%s, %s) %s\n",
632338032Speter			map->map_mname, name, map->map_file);
632438032Speter
632538032Speter	i = 0;
632638032Speter	argv[i++] = map->map_file;
632738032Speter	if (map->map_rebuild != NULL)
632838032Speter	{
6329168515Sgshapiro		(void) sm_strlcpy(buf, map->map_rebuild, sizeof(buf));
633038032Speter		for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
633138032Speter		{
633238032Speter			if (i >= MAXPV - 1)
633338032Speter				break;
633438032Speter			argv[i++] = p;
633538032Speter		}
633638032Speter	}
633738032Speter	argv[i++] = name;
633838032Speter	argv[i] = NULL;
633938032Speter	if (tTd(38, 21))
634038032Speter	{
634190792Sgshapiro		sm_dprintf("prog_open:");
634238032Speter		for (i = 0; argv[i] != NULL; i++)
634390792Sgshapiro			sm_dprintf(" %s", argv[i]);
634490792Sgshapiro		sm_dprintf("\n");
634538032Speter	}
634690792Sgshapiro	(void) sm_blocksignal(SIGCHLD);
634738032Speter	pid = prog_open(argv, &fd, CurEnv);
634838032Speter	if (pid < 0)
634938032Speter	{
635038032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
635138032Speter			syserr("prog_map_lookup(%s) failed (%s) -- closing",
635290792Sgshapiro			       map->map_mname, sm_errstring(errno));
635338032Speter		else if (tTd(38, 9))
635490792Sgshapiro			sm_dprintf("prog_map_lookup(%s) failed (%s) -- closing",
635590792Sgshapiro				   map->map_mname, sm_errstring(errno));
635638032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
635738032Speter		*statp = EX_OSFILE;
635838032Speter		return NULL;
635938032Speter	}
6360168515Sgshapiro	i = read(fd, buf, sizeof(buf) - 1);
636138032Speter	if (i < 0)
636238032Speter	{
636390792Sgshapiro		syserr("prog_map_lookup(%s): read error %s",
636490792Sgshapiro		       map->map_mname, sm_errstring(errno));
636538032Speter		rval = NULL;
636638032Speter	}
636738032Speter	else if (i == 0)
636838032Speter	{
636938032Speter		if (tTd(38, 20))
637090792Sgshapiro			sm_dprintf("prog_map_lookup(%s): empty answer\n",
637190792Sgshapiro				   map->map_mname);
637238032Speter		rval = NULL;
637338032Speter	}
637438032Speter	else
637538032Speter	{
637638032Speter		buf[i] = '\0';
637738032Speter		p = strchr(buf, '\n');
637838032Speter		if (p != NULL)
637938032Speter			*p = '\0';
638038032Speter
638138032Speter		/* collect the return value */
638238032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
638338032Speter			rval = map_rewrite(map, name, strlen(name), NULL);
638438032Speter		else
638577349Sgshapiro			rval = map_rewrite(map, buf, strlen(buf), av);
638638032Speter
638738032Speter		/* now flush any additional output */
6388168515Sgshapiro		while ((i = read(fd, buf, sizeof(buf))) > 0)
638938032Speter			continue;
639038032Speter	}
639138032Speter
639238032Speter	/* wait for the process to terminate */
639364562Sgshapiro	(void) close(fd);
639464562Sgshapiro	status = waitfor(pid);
639564562Sgshapiro	save_errno = errno;
639690792Sgshapiro	(void) sm_releasesignal(SIGCHLD);
639764562Sgshapiro	errno = save_errno;
639838032Speter
639964562Sgshapiro	if (status == -1)
640038032Speter	{
640190792Sgshapiro		syserr("prog_map_lookup(%s): wait error %s",
640290792Sgshapiro		       map->map_mname, sm_errstring(errno));
640338032Speter		*statp = EX_SOFTWARE;
640438032Speter		rval = NULL;
640538032Speter	}
640664562Sgshapiro	else if (WIFEXITED(status))
640738032Speter	{
640864562Sgshapiro		if ((*statp = WEXITSTATUS(status)) != EX_OK)
640938032Speter			rval = NULL;
641038032Speter	}
641138032Speter	else
641238032Speter	{
641338032Speter		syserr("prog_map_lookup(%s): child died on signal %d",
641490792Sgshapiro		       map->map_mname, status);
641538032Speter		*statp = EX_UNAVAILABLE;
641638032Speter		rval = NULL;
641738032Speter	}
641838032Speter	return rval;
641938032Speter}
642090792Sgshapiro/*
642138032Speter**  Sequenced map type.
642238032Speter**
642338032Speter**	Tries each map in order until something matches, much like
642438032Speter**	implicit.  Stores go to the first map in the list that can
642538032Speter**	support storing.
642638032Speter**
642738032Speter**	This is slightly unusual in that there are two interfaces.
642838032Speter**	The "sequence" interface lets you stack maps arbitrarily.
642938032Speter**	The "switch" interface builds a sequence map by looking
643038032Speter**	at a system-dependent configuration file such as
643138032Speter**	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
643238032Speter**
643338032Speter**	We don't need an explicit open, since all maps are
643490792Sgshapiro**	opened on demand.
643538032Speter*/
643638032Speter
643738032Speter/*
643838032Speter**  SEQ_MAP_PARSE -- Sequenced map parsing
643938032Speter*/
644038032Speter
644138032Speterbool
644238032Speterseq_map_parse(map, ap)
644338032Speter	MAP *map;
644438032Speter	char *ap;
644538032Speter{
644638032Speter	int maxmap;
644738032Speter
644838032Speter	if (tTd(38, 2))
644990792Sgshapiro		sm_dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
645038032Speter	maxmap = 0;
645138032Speter	while (*ap != '\0')
645238032Speter	{
645338032Speter		register char *p;
645438032Speter		STAB *s;
645538032Speter
645638032Speter		/* find beginning of map name */
645738032Speter		while (isascii(*ap) && isspace(*ap))
645838032Speter			ap++;
645964562Sgshapiro		for (p = ap;
646064562Sgshapiro		     (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.';
646164562Sgshapiro		     p++)
646238032Speter			continue;
646338032Speter		if (*p != '\0')
646438032Speter			*p++ = '\0';
646538032Speter		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
646638032Speter			p++;
646738032Speter		if (*ap == '\0')
646838032Speter		{
646938032Speter			ap = p;
647038032Speter			continue;
647138032Speter		}
647238032Speter		s = stab(ap, ST_MAP, ST_FIND);
647338032Speter		if (s == NULL)
647438032Speter		{
647538032Speter			syserr("Sequence map %s: unknown member map %s",
647638032Speter				map->map_mname, ap);
647738032Speter		}
647890792Sgshapiro		else if (maxmap >= MAXMAPSTACK)
647938032Speter		{
648038032Speter			syserr("Sequence map %s: too many member maps (%d max)",
648138032Speter				map->map_mname, MAXMAPSTACK);
648238032Speter			maxmap++;
648338032Speter		}
648438032Speter		else if (maxmap < MAXMAPSTACK)
648538032Speter		{
648638032Speter			map->map_stack[maxmap++] = &s->s_map;
648738032Speter		}
648838032Speter		ap = p;
648938032Speter	}
649090792Sgshapiro	return true;
649138032Speter}
649238032Speter
649338032Speter/*
649438032Speter**  SWITCH_MAP_OPEN -- open a switched map
649538032Speter**
649638032Speter**	This looks at the system-dependent configuration and builds
649738032Speter**	a sequence map that does the same thing.
649838032Speter**
649938032Speter**	Every system must define a switch_map_find routine in conf.c
650038032Speter**	that will return the list of service types associated with a
650138032Speter**	given service class.
650238032Speter*/
650338032Speter
650438032Speterbool
650538032Speterswitch_map_open(map, mode)
650638032Speter	MAP *map;
650738032Speter	int mode;
650838032Speter{
650938032Speter	int mapno;
651038032Speter	int nmaps;
651138032Speter	char *maptype[MAXMAPSTACK];
651238032Speter
651338032Speter	if (tTd(38, 2))
651490792Sgshapiro		sm_dprintf("switch_map_open(%s, %s, %d)\n",
651538032Speter			map->map_mname, map->map_file, mode);
651638032Speter
651738032Speter	mode &= O_ACCMODE;
651838032Speter	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
651938032Speter	if (tTd(38, 19))
652038032Speter	{
652190792Sgshapiro		sm_dprintf("\tswitch_map_find => %d\n", nmaps);
652238032Speter		for (mapno = 0; mapno < nmaps; mapno++)
652390792Sgshapiro			sm_dprintf("\t\t%s\n", maptype[mapno]);
652438032Speter	}
652538032Speter	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
652690792Sgshapiro		return false;
652738032Speter
652838032Speter	for (mapno = 0; mapno < nmaps; mapno++)
652938032Speter	{
653038032Speter		register STAB *s;
653138032Speter		char nbuf[MAXNAME + 1];
653238032Speter
653338032Speter		if (maptype[mapno] == NULL)
653438032Speter			continue;
6535168515Sgshapiro		(void) sm_strlcpyn(nbuf, sizeof(nbuf), 3,
653690792Sgshapiro				   map->map_mname, ".", maptype[mapno]);
653738032Speter		s = stab(nbuf, ST_MAP, ST_FIND);
653838032Speter		if (s == NULL)
653938032Speter		{
654038032Speter			syserr("Switch map %s: unknown member map %s",
654138032Speter				map->map_mname, nbuf);
654238032Speter		}
654338032Speter		else
654438032Speter		{
654538032Speter			map->map_stack[mapno] = &s->s_map;
654638032Speter			if (tTd(38, 4))
654790792Sgshapiro				sm_dprintf("\tmap_stack[%d] = %s:%s\n",
654890792Sgshapiro					   mapno,
654990792Sgshapiro					   s->s_map.map_class->map_cname,
655090792Sgshapiro					   nbuf);
655138032Speter		}
655238032Speter	}
655390792Sgshapiro	return true;
655438032Speter}
655538032Speter
655690792Sgshapiro#if 0
655738032Speter/*
655838032Speter**  SEQ_MAP_CLOSE -- close all underlying maps
655938032Speter*/
656038032Speter
656138032Spetervoid
656238032Speterseq_map_close(map)
656338032Speter	MAP *map;
656438032Speter{
656538032Speter	int mapno;
656638032Speter
656738032Speter	if (tTd(38, 9))
656890792Sgshapiro		sm_dprintf("seq_map_close(%s)\n", map->map_mname);
656938032Speter
657038032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
657138032Speter	{
657238032Speter		MAP *mm = map->map_stack[mapno];
657338032Speter
657438032Speter		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
657538032Speter			continue;
657677349Sgshapiro		mm->map_mflags |= MF_CLOSING;
657738032Speter		mm->map_class->map_close(mm);
657877349Sgshapiro		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
657938032Speter	}
658038032Speter}
658190792Sgshapiro#endif /* 0 */
658238032Speter
658338032Speter/*
658438032Speter**  SEQ_MAP_LOOKUP -- sequenced map lookup
658538032Speter*/
658638032Speter
658738032Speterchar *
658838032Speterseq_map_lookup(map, key, args, pstat)
658938032Speter	MAP *map;
659038032Speter	char *key;
659138032Speter	char **args;
659238032Speter	int *pstat;
659338032Speter{
659438032Speter	int mapno;
659538032Speter	int mapbit = 0x01;
659690792Sgshapiro	bool tempfail = false;
659738032Speter
659838032Speter	if (tTd(38, 20))
659990792Sgshapiro		sm_dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
660038032Speter
660138032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
660238032Speter	{
660338032Speter		MAP *mm = map->map_stack[mapno];
660438032Speter		char *rv;
660538032Speter
660638032Speter		if (mm == NULL)
660738032Speter			continue;
660864562Sgshapiro		if (!bitset(MF_OPEN, mm->map_mflags) &&
660964562Sgshapiro		    !openmap(mm))
661038032Speter		{
661138032Speter			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
661238032Speter			{
661338032Speter				*pstat = EX_UNAVAILABLE;
661438032Speter				return NULL;
661538032Speter			}
661638032Speter			continue;
661738032Speter		}
661838032Speter		*pstat = EX_OK;
661938032Speter		rv = mm->map_class->map_lookup(mm, key, args, pstat);
662038032Speter		if (rv != NULL)
662138032Speter			return rv;
662238032Speter		if (*pstat == EX_TEMPFAIL)
662338032Speter		{
662438032Speter			if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
662538032Speter				return NULL;
662690792Sgshapiro			tempfail = true;
662738032Speter		}
662838032Speter		else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
662938032Speter			break;
663038032Speter	}
663138032Speter	if (tempfail)
663238032Speter		*pstat = EX_TEMPFAIL;
663338032Speter	else if (*pstat == EX_OK)
663438032Speter		*pstat = EX_NOTFOUND;
663538032Speter	return NULL;
663638032Speter}
663738032Speter
663838032Speter/*
663938032Speter**  SEQ_MAP_STORE -- sequenced map store
664038032Speter*/
664138032Speter
664238032Spetervoid
664338032Speterseq_map_store(map, key, val)
664438032Speter	MAP *map;
664538032Speter	char *key;
664638032Speter	char *val;
664738032Speter{
664838032Speter	int mapno;
664938032Speter
665038032Speter	if (tTd(38, 12))
665190792Sgshapiro		sm_dprintf("seq_map_store(%s, %s, %s)\n",
665238032Speter			map->map_mname, key, val);
665338032Speter
665438032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
665538032Speter	{
665638032Speter		MAP *mm = map->map_stack[mapno];
665738032Speter
665838032Speter		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
665938032Speter			continue;
666038032Speter
666138032Speter		mm->map_class->map_store(mm, key, val);
666238032Speter		return;
666338032Speter	}
666438032Speter	syserr("seq_map_store(%s, %s, %s): no writable map",
666538032Speter		map->map_mname, key, val);
666638032Speter}
666790792Sgshapiro/*
666838032Speter**  NULL stubs
666938032Speter*/
667038032Speter
667138032Speter/* ARGSUSED */
667238032Speterbool
667338032Speternull_map_open(map, mode)
667438032Speter	MAP *map;
667538032Speter	int mode;
667638032Speter{
667790792Sgshapiro	return true;
667838032Speter}
667938032Speter
668038032Speter/* ARGSUSED */
668138032Spetervoid
668238032Speternull_map_close(map)
668338032Speter	MAP *map;
668438032Speter{
668538032Speter	return;
668638032Speter}
668738032Speter
668838032Speterchar *
668938032Speternull_map_lookup(map, key, args, pstat)
669038032Speter	MAP *map;
669138032Speter	char *key;
669238032Speter	char **args;
669338032Speter	int *pstat;
669438032Speter{
669538032Speter	*pstat = EX_NOTFOUND;
669638032Speter	return NULL;
669738032Speter}
669838032Speter
669938032Speter/* ARGSUSED */
670038032Spetervoid
670138032Speternull_map_store(map, key, val)
670238032Speter	MAP *map;
670338032Speter	char *key;
670438032Speter	char *val;
670538032Speter{
670638032Speter	return;
670738032Speter}
670838032Speter
6709203004SgshapiroMAPCLASS	NullMapClass =
6710203004Sgshapiro{
6711203004Sgshapiro	"null-map",		NULL,			0,
6712203004Sgshapiro	NULL,			null_map_lookup,	null_map_store,
6713203004Sgshapiro	null_map_open,		null_map_close,
6714203004Sgshapiro};
6715203004Sgshapiro
671638032Speter/*
671738032Speter**  BOGUS stubs
671838032Speter*/
671938032Speter
672038032Speterchar *
672138032Speterbogus_map_lookup(map, key, args, pstat)
672238032Speter	MAP *map;
672338032Speter	char *key;
672438032Speter	char **args;
672538032Speter	int *pstat;
672638032Speter{
672738032Speter	*pstat = EX_TEMPFAIL;
672838032Speter	return NULL;
672938032Speter}
673038032Speter
673138032SpeterMAPCLASS	BogusMapClass =
673238032Speter{
673390792Sgshapiro	"bogus-map",		NULL,			0,
673490792Sgshapiro	NULL,			bogus_map_lookup,	null_map_store,
673590792Sgshapiro	null_map_open,		null_map_close,
673638032Speter};
673790792Sgshapiro/*
673864562Sgshapiro**  MACRO modules
673964562Sgshapiro*/
674064562Sgshapiro
674164562Sgshapirochar *
674264562Sgshapiromacro_map_lookup(map, name, av, statp)
674364562Sgshapiro	MAP *map;
674464562Sgshapiro	char *name;
674564562Sgshapiro	char **av;
674664562Sgshapiro	int *statp;
674764562Sgshapiro{
674864562Sgshapiro	int mid;
674964562Sgshapiro
675064562Sgshapiro	if (tTd(38, 20))
675190792Sgshapiro		sm_dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
675264562Sgshapiro			name == NULL ? "NULL" : name);
675364562Sgshapiro
675464562Sgshapiro	if (name == NULL ||
675564562Sgshapiro	    *name == '\0' ||
675690792Sgshapiro	    (mid = macid(name)) == 0)
675764562Sgshapiro	{
675864562Sgshapiro		*statp = EX_CONFIG;
675964562Sgshapiro		return NULL;
676064562Sgshapiro	}
676164562Sgshapiro
676264562Sgshapiro	if (av[1] == NULL)
676390792Sgshapiro		macdefine(&CurEnv->e_macro, A_PERM, mid, NULL);
676464562Sgshapiro	else
676590792Sgshapiro		macdefine(&CurEnv->e_macro, A_TEMP, mid, av[1]);
676664562Sgshapiro
676764562Sgshapiro	*statp = EX_OK;
676864562Sgshapiro	return "";
676964562Sgshapiro}
677090792Sgshapiro/*
677138032Speter**  REGEX modules
677238032Speter*/
677338032Speter
677490792Sgshapiro#if MAP_REGEX
677538032Speter
677638032Speter# include <regex.h>
677738032Speter
677838032Speter# define DEFAULT_DELIM	CONDELSE
677938032Speter# define END_OF_FIELDS	-1
678038032Speter# define ERRBUF_SIZE	80
678138032Speter# define MAX_MATCH	32
678238032Speter
678364562Sgshapiro# define xnalloc(s)	memset(xalloc(s), '\0', s);
678438032Speter
678538032Speterstruct regex_map
678638032Speter{
678771345Sgshapiro	regex_t	*regex_pattern_buf;	/* xalloc it */
678838032Speter	int	*regex_subfields;	/* move to type MAP */
678964562Sgshapiro	char	*regex_delim;		/* move to type MAP */
679038032Speter};
679138032Speter
6792141858Sgshapirostatic int	parse_fields __P((char *, int *, int, int));
6793141858Sgshapirostatic char	*regex_map_rewrite __P((MAP *, const char*, size_t, char **));
6794141858Sgshapiro
679538032Speterstatic int
679638032Speterparse_fields(s, ibuf, blen, nr_substrings)
679738032Speter	char *s;
679838032Speter	int *ibuf;		/* array */
679938032Speter	int blen;		/* number of elements in ibuf */
680038032Speter	int nr_substrings;	/* number of substrings in the pattern */
680138032Speter{
680238032Speter	register char *cp;
680338032Speter	int i = 0;
680490792Sgshapiro	bool lastone = false;
680538032Speter
680638032Speter	blen--;		/* for terminating END_OF_FIELDS */
680738032Speter	cp = s;
680838032Speter	do
680938032Speter	{
681038032Speter		for (;; cp++)
681138032Speter		{
681238032Speter			if (*cp == ',')
681338032Speter			{
681438032Speter				*cp = '\0';
681538032Speter				break;
681638032Speter			}
681738032Speter			if (*cp == '\0')
681838032Speter			{
681990792Sgshapiro				lastone = true;
682038032Speter				break;
682138032Speter			}
682238032Speter		}
682338032Speter		if (i < blen)
682438032Speter		{
682538032Speter			int val = atoi(s);
682638032Speter
682738032Speter			if (val < 0 || val >= nr_substrings)
682838032Speter			{
682938032Speter				syserr("field (%d) out of range, only %d substrings in pattern",
683038032Speter				       val, nr_substrings);
683138032Speter				return -1;
683238032Speter			}
683338032Speter			ibuf[i++] = val;
683438032Speter		}
683538032Speter		else
683638032Speter		{
683790792Sgshapiro			syserr("too many fields, %d max", blen);
683838032Speter			return -1;
683938032Speter		}
684038032Speter		s = ++cp;
684138032Speter	} while (!lastone);
684238032Speter	ibuf[i] = END_OF_FIELDS;
684338032Speter	return i;
684438032Speter}
684538032Speter
684638032Speterbool
684738032Speterregex_map_init(map, ap)
684838032Speter	MAP *map;
684938032Speter	char *ap;
685038032Speter{
685138032Speter	int regerr;
685238032Speter	struct regex_map *map_p;
685338032Speter	register char *p;
685438032Speter	char *sub_param = NULL;
685538032Speter	int pflags;
685690792Sgshapiro	static char defdstr[] = { (char) DEFAULT_DELIM, '\0' };
685738032Speter
685838032Speter	if (tTd(38, 2))
685990792Sgshapiro		sm_dprintf("regex_map_init: mapname '%s', args '%s'\n",
686064562Sgshapiro			map->map_mname, ap);
686138032Speter
686238032Speter	pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
686338032Speter	p = ap;
6864168515Sgshapiro	map_p = (struct regex_map *) xnalloc(sizeof(*map_p));
686571345Sgshapiro	map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t));
686638032Speter
686738032Speter	for (;;)
686864562Sgshapiro	{
686938032Speter		while (isascii(*p) && isspace(*p))
687038032Speter			p++;
687138032Speter		if (*p != '-')
687238032Speter			break;
687338032Speter		switch (*++p)
687438032Speter		{
687538032Speter		  case 'n':	/* not */
687638032Speter			map->map_mflags |= MF_REGEX_NOT;
687738032Speter			break;
687838032Speter
687938032Speter		  case 'f':	/* case sensitive */
688038032Speter			map->map_mflags |= MF_NOFOLDCASE;
688138032Speter			pflags &= ~REG_ICASE;
688238032Speter			break;
688338032Speter
688438032Speter		  case 'b':	/* basic regular expressions */
688538032Speter			pflags &= ~REG_EXTENDED;
688638032Speter			break;
688738032Speter
688838032Speter		  case 's':	/* substring match () syntax */
688938032Speter			sub_param = ++p;
689038032Speter			pflags &= ~REG_NOSUB;
689138032Speter			break;
689238032Speter
689338032Speter		  case 'd':	/* delimiter */
689464562Sgshapiro			map_p->regex_delim = ++p;
689538032Speter			break;
689638032Speter
689738032Speter		  case 'a':	/* map append */
689838032Speter			map->map_app = ++p;
689938032Speter			break;
690038032Speter
690138032Speter		  case 'm':	/* matchonly */
690238032Speter			map->map_mflags |= MF_MATCHONLY;
690338032Speter			break;
690438032Speter
6905120256Sgshapiro		  case 'q':
6906120256Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
6907120256Sgshapiro			break;
6908120256Sgshapiro
690964562Sgshapiro		  case 'S':
691064562Sgshapiro			map->map_spacesub = *++p;
691164562Sgshapiro			break;
691264562Sgshapiro
691364562Sgshapiro		  case 'D':
691464562Sgshapiro			map->map_mflags |= MF_DEFER;
691564562Sgshapiro			break;
691664562Sgshapiro
691738032Speter		}
691864562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
691964562Sgshapiro			p++;
692064562Sgshapiro		if (*p != '\0')
692164562Sgshapiro			*p++ = '\0';
692238032Speter	}
692338032Speter	if (tTd(38, 3))
692490792Sgshapiro		sm_dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
692538032Speter
692671345Sgshapiro	if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0)
692738032Speter	{
692838032Speter		/* Errorhandling */
692938032Speter		char errbuf[ERRBUF_SIZE];
693038032Speter
693171345Sgshapiro		(void) regerror(regerr, map_p->regex_pattern_buf,
6932168515Sgshapiro			 errbuf, sizeof(errbuf));
693390792Sgshapiro		syserr("pattern-compile-error: %s", errbuf);
693490792Sgshapiro		sm_free(map_p->regex_pattern_buf); /* XXX */
693590792Sgshapiro		sm_free(map_p); /* XXX */
693690792Sgshapiro		return false;
693738032Speter	}
693838032Speter
693938032Speter	if (map->map_app != NULL)
694038032Speter		map->map_app = newstr(map->map_app);
694164562Sgshapiro	if (map_p->regex_delim != NULL)
694264562Sgshapiro		map_p->regex_delim = newstr(map_p->regex_delim);
694338032Speter	else
694464562Sgshapiro		map_p->regex_delim = defdstr;
694538032Speter
694638032Speter	if (!bitset(REG_NOSUB, pflags))
694738032Speter	{
694838032Speter		/* substring matching */
694938032Speter		int substrings;
695064562Sgshapiro		int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1));
695138032Speter
695271345Sgshapiro		substrings = map_p->regex_pattern_buf->re_nsub + 1;
695338032Speter
695438032Speter		if (tTd(38, 3))
695590792Sgshapiro			sm_dprintf("regex_map_init: nr of substrings %d\n",
695664562Sgshapiro				substrings);
695738032Speter
695838032Speter		if (substrings >= MAX_MATCH)
695938032Speter		{
696090792Sgshapiro			syserr("too many substrings, %d max", MAX_MATCH);
696190792Sgshapiro			sm_free(map_p->regex_pattern_buf); /* XXX */
696290792Sgshapiro			sm_free(map_p); /* XXX */
696390792Sgshapiro			return false;
696438032Speter		}
696538032Speter		if (sub_param != NULL && sub_param[0] != '\0')
696638032Speter		{
696738032Speter			/* optional parameter -sfields */
696838032Speter			if (parse_fields(sub_param, fields,
696938032Speter					 MAX_MATCH + 1, substrings) == -1)
697090792Sgshapiro				return false;
697138032Speter		}
697238032Speter		else
697338032Speter		{
697438032Speter			int i;
697538032Speter
697690792Sgshapiro			/* set default fields */
697738032Speter			for (i = 0; i < substrings; i++)
697838032Speter				fields[i] = i;
697938032Speter			fields[i] = END_OF_FIELDS;
698038032Speter		}
698138032Speter		map_p->regex_subfields = fields;
698238032Speter		if (tTd(38, 3))
698338032Speter		{
698438032Speter			int *ip;
698538032Speter
698690792Sgshapiro			sm_dprintf("regex_map_init: subfields");
698738032Speter			for (ip = fields; *ip != END_OF_FIELDS; ip++)
698890792Sgshapiro				sm_dprintf(" %d", *ip);
698990792Sgshapiro			sm_dprintf("\n");
699038032Speter		}
699138032Speter	}
699290792Sgshapiro	map->map_db1 = (ARBPTR_T) map_p;	/* dirty hack */
699390792Sgshapiro	return true;
699438032Speter}
699538032Speter
699638032Speterstatic char *
699738032Speterregex_map_rewrite(map, s, slen, av)
699838032Speter	MAP *map;
699938032Speter	const char *s;
700038032Speter	size_t slen;
700138032Speter	char **av;
700238032Speter{
700338032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
700438032Speter		return map_rewrite(map, av[0], strlen(av[0]), NULL);
700538032Speter	else
700677349Sgshapiro		return map_rewrite(map, s, slen, av);
700738032Speter}
700838032Speter
700938032Speterchar *
701038032Speterregex_map_lookup(map, name, av, statp)
701138032Speter	MAP *map;
701238032Speter	char *name;
701338032Speter	char **av;
701438032Speter	int *statp;
701538032Speter{
701638032Speter	int reg_res;
701738032Speter	struct regex_map *map_p;
701838032Speter	regmatch_t pmatch[MAX_MATCH];
701938032Speter
702038032Speter	if (tTd(38, 20))
702138032Speter	{
702238032Speter		char **cpp;
702338032Speter
702490792Sgshapiro		sm_dprintf("regex_map_lookup: key '%s'\n", name);
702564562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
702690792Sgshapiro			sm_dprintf("regex_map_lookup: arg '%s'\n", *cpp);
702738032Speter	}
702838032Speter
702938032Speter	map_p = (struct regex_map *)(map->map_db1);
703071345Sgshapiro	reg_res = regexec(map_p->regex_pattern_buf,
703164562Sgshapiro			  name, MAX_MATCH, pmatch, 0);
703238032Speter
703338032Speter	if (bitset(MF_REGEX_NOT, map->map_mflags))
703438032Speter	{
703538032Speter		/* option -n */
703638032Speter		if (reg_res == REG_NOMATCH)
703790792Sgshapiro			return regex_map_rewrite(map, "", (size_t) 0, av);
703838032Speter		else
703938032Speter			return NULL;
704038032Speter	}
704138032Speter	if (reg_res == REG_NOMATCH)
704238032Speter		return NULL;
704338032Speter
704438032Speter	if (map_p->regex_subfields != NULL)
704538032Speter	{
704638032Speter		/* option -s */
704738032Speter		static char retbuf[MAXNAME];
704838032Speter		int fields[MAX_MATCH + 1];
704990792Sgshapiro		bool first = true;
705038032Speter		int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
705190792Sgshapiro		bool quotemode = false, bslashmode = false;
705238032Speter		register char *dp, *sp;
705338032Speter		char *endp, *ldp;
705438032Speter		int *ip;
705538032Speter
705638032Speter		dp = retbuf;
705738032Speter		ldp = retbuf + sizeof(retbuf) - 1;
705838032Speter
705938032Speter		if (av[1] != NULL)
706038032Speter		{
706138032Speter			if (parse_fields(av[1], fields, MAX_MATCH + 1,
706271345Sgshapiro					 (int) map_p->regex_pattern_buf->re_nsub + 1) == -1)
706338032Speter			{
706438032Speter				*statp = EX_CONFIG;
706538032Speter				return NULL;
706638032Speter			}
706738032Speter			ip = fields;
706838032Speter		}
706938032Speter		else
707038032Speter			ip = map_p->regex_subfields;
707138032Speter
707238032Speter		for ( ; *ip != END_OF_FIELDS; ip++)
707338032Speter		{
707438032Speter			if (!first)
707538032Speter			{
707664562Sgshapiro				for (sp = map_p->regex_delim; *sp; sp++)
707738032Speter				{
707838032Speter					if (dp < ldp)
707938032Speter						*dp++ = *sp;
708038032Speter				}
708138032Speter			}
708238032Speter			else
708390792Sgshapiro				first = false;
708438032Speter
708571345Sgshapiro			if (*ip >= MAX_MATCH ||
708671345Sgshapiro			    pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
708738032Speter				continue;
708838032Speter
708938032Speter			sp = name + pmatch[*ip].rm_so;
709038032Speter			endp = name + pmatch[*ip].rm_eo;
709138032Speter			for (; endp > sp; sp++)
709238032Speter			{
709338032Speter				if (dp < ldp)
709438032Speter				{
709564562Sgshapiro					if (bslashmode)
709664562Sgshapiro					{
709738032Speter						*dp++ = *sp;
709890792Sgshapiro						bslashmode = false;
709938032Speter					}
710064562Sgshapiro					else if (quotemode && *sp != '"' &&
710138032Speter						*sp != '\\')
710238032Speter					{
710338032Speter						*dp++ = *sp;
710438032Speter					}
710590792Sgshapiro					else switch (*dp++ = *sp)
710638032Speter					{
710790792Sgshapiro					  case '\\':
710890792Sgshapiro						bslashmode = true;
710938032Speter						break;
711038032Speter
711190792Sgshapiro					  case '(':
711238032Speter						cmntcnt++;
711338032Speter						break;
711438032Speter
711590792Sgshapiro					  case ')':
711638032Speter						cmntcnt--;
711738032Speter						break;
711838032Speter
711990792Sgshapiro					  case '<':
712038032Speter						anglecnt++;
712138032Speter						break;
712238032Speter
712390792Sgshapiro					  case '>':
712438032Speter						anglecnt--;
712538032Speter						break;
712638032Speter
712790792Sgshapiro					  case ' ':
712838032Speter						spacecnt++;
712938032Speter						break;
713038032Speter
713190792Sgshapiro					  case '"':
713238032Speter						quotemode = !quotemode;
713338032Speter						break;
713438032Speter					}
713538032Speter				}
713638032Speter			}
713738032Speter		}
713838032Speter		if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
713938032Speter		    bslashmode || spacecnt != 0)
714038032Speter		{
714164562Sgshapiro			sm_syslog(LOG_WARNING, NOQID,
714264562Sgshapiro				  "Warning: regex may cause prescan() failure map=%s lookup=%s",
714364562Sgshapiro				  map->map_mname, name);
714438032Speter			return NULL;
714538032Speter		}
714638032Speter
714738032Speter		*dp = '\0';
714838032Speter
714938032Speter		return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
715038032Speter	}
715138032Speter	return regex_map_rewrite(map, "", (size_t)0, av);
715238032Speter}
715338032Speter#endif /* MAP_REGEX */
715490792Sgshapiro/*
715564562Sgshapiro**  NSD modules
715664562Sgshapiro*/
715790792Sgshapiro#if MAP_NSD
715864562Sgshapiro
715964562Sgshapiro# include <ndbm.h>
716064562Sgshapiro# define _DATUM_DEFINED
716164562Sgshapiro# include <ns_api.h>
716264562Sgshapiro
716364562Sgshapirotypedef struct ns_map_list
716464562Sgshapiro{
716590792Sgshapiro	ns_map_t		*map;		/* XXX ns_ ? */
716690792Sgshapiro	char			*mapname;
716790792Sgshapiro	struct ns_map_list	*next;
716864562Sgshapiro} ns_map_list_t;
716964562Sgshapiro
717064562Sgshapirostatic ns_map_t *
717164562Sgshapirons_map_t_find(mapname)
717264562Sgshapiro	char *mapname;
717364562Sgshapiro{
717464562Sgshapiro	static ns_map_list_t *ns_maps = NULL;
717564562Sgshapiro	ns_map_list_t *ns_map;
717664562Sgshapiro
717764562Sgshapiro	/* walk the list of maps looking for the correctly named map */
717864562Sgshapiro	for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next)
717964562Sgshapiro	{
718064562Sgshapiro		if (strcmp(ns_map->mapname, mapname) == 0)
718164562Sgshapiro			break;
718264562Sgshapiro	}
718364562Sgshapiro
718464562Sgshapiro	/* if we are looking at a NULL ns_map_list_t, then create a new one */
718564562Sgshapiro	if (ns_map == NULL)
718664562Sgshapiro	{
7187168515Sgshapiro		ns_map = (ns_map_list_t *) xalloc(sizeof(*ns_map));
718864562Sgshapiro		ns_map->mapname = newstr(mapname);
7189168515Sgshapiro		ns_map->map = (ns_map_t *) xalloc(sizeof(*ns_map->map));
7190168515Sgshapiro		memset(ns_map->map, '\0', sizeof(*ns_map->map));
719164562Sgshapiro		ns_map->next = ns_maps;
719264562Sgshapiro		ns_maps = ns_map;
719364562Sgshapiro	}
719464562Sgshapiro	return ns_map->map;
719564562Sgshapiro}
719664562Sgshapiro
719764562Sgshapirochar *
719864562Sgshapironsd_map_lookup(map, name, av, statp)
719964562Sgshapiro	MAP *map;
720064562Sgshapiro	char *name;
720164562Sgshapiro	char **av;
720264562Sgshapiro	int *statp;
720364562Sgshapiro{
720471345Sgshapiro	int buflen, r;
720564562Sgshapiro	char *p;
720664562Sgshapiro	ns_map_t *ns_map;
720764562Sgshapiro	char keybuf[MAXNAME + 1];
720864562Sgshapiro	char buf[MAXLINE];
720964562Sgshapiro
721064562Sgshapiro	if (tTd(38, 20))
721190792Sgshapiro		sm_dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
721264562Sgshapiro
721364562Sgshapiro	buflen = strlen(name);
7214168515Sgshapiro	if (buflen > sizeof(keybuf) - 1)
7215168515Sgshapiro		buflen = sizeof(keybuf) - 1;	/* XXX simply cut off? */
721664562Sgshapiro	memmove(keybuf, name, buflen);
721764562Sgshapiro	keybuf[buflen] = '\0';
721864562Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
721964562Sgshapiro		makelower(keybuf);
722064562Sgshapiro
722164562Sgshapiro	ns_map = ns_map_t_find(map->map_file);
722264562Sgshapiro	if (ns_map == NULL)
722364562Sgshapiro	{
722464562Sgshapiro		if (tTd(38, 20))
722590792Sgshapiro			sm_dprintf("nsd_map_t_find failed\n");
722671345Sgshapiro		*statp = EX_UNAVAILABLE;
722764562Sgshapiro		return NULL;
722864562Sgshapiro	}
722998121Sgshapiro	r = ns_lookup(ns_map, NULL, map->map_file, keybuf, NULL,
7230168515Sgshapiro		      buf, sizeof(buf));
723171345Sgshapiro	if (r == NS_UNAVAIL || r == NS_TRYAGAIN)
723271345Sgshapiro	{
723371345Sgshapiro		*statp = EX_TEMPFAIL;
723464562Sgshapiro		return NULL;
723571345Sgshapiro	}
723677349Sgshapiro	if (r == NS_BADREQ
723777349Sgshapiro# ifdef NS_NOPERM
723877349Sgshapiro	    || r == NS_NOPERM
723977349Sgshapiro# endif /* NS_NOPERM */
724077349Sgshapiro	    )
724171345Sgshapiro	{
724271345Sgshapiro		*statp = EX_CONFIG;
724371345Sgshapiro		return NULL;
724471345Sgshapiro	}
724571345Sgshapiro	if (r != NS_SUCCESS)
724671345Sgshapiro	{
724771345Sgshapiro		*statp = EX_NOTFOUND;
724871345Sgshapiro		return NULL;
724971345Sgshapiro	}
725064562Sgshapiro
725171345Sgshapiro	*statp = EX_OK;
725271345Sgshapiro
725364562Sgshapiro	/* Null out trailing \n */
725464562Sgshapiro	if ((p = strchr(buf, '\n')) != NULL)
725564562Sgshapiro		*p = '\0';
725664562Sgshapiro
725764562Sgshapiro	return map_rewrite(map, buf, strlen(buf), av);
725864562Sgshapiro}
725964562Sgshapiro#endif /* MAP_NSD */
726064562Sgshapiro
726164562Sgshapirochar *
726264562Sgshapiroarith_map_lookup(map, name, av, statp)
726364562Sgshapiro	MAP *map;
726464562Sgshapiro	char *name;
726564562Sgshapiro	char **av;
726664562Sgshapiro	int *statp;
726764562Sgshapiro{
726864562Sgshapiro	long r;
726964562Sgshapiro	long v[2];
727090792Sgshapiro	bool res = false;
727164562Sgshapiro	bool boolres;
727264562Sgshapiro	static char result[16];
727364562Sgshapiro	char **cpp;
727464562Sgshapiro
727564562Sgshapiro	if (tTd(38, 2))
727664562Sgshapiro	{
727790792Sgshapiro		sm_dprintf("arith_map_lookup: key '%s'\n", name);
727864562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
727990792Sgshapiro			sm_dprintf("arith_map_lookup: arg '%s'\n", *cpp);
728064562Sgshapiro	}
728164562Sgshapiro	r = 0;
728290792Sgshapiro	boolres = false;
728364562Sgshapiro	cpp = av;
728464562Sgshapiro	*statp = EX_OK;
728564562Sgshapiro
728664562Sgshapiro	/*
728764562Sgshapiro	**  read arguments for arith map
728864562Sgshapiro	**  - no check is made whether they are really numbers
728964562Sgshapiro	**  - just ignores args after the second
729064562Sgshapiro	*/
729190792Sgshapiro
729264562Sgshapiro	for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
729364562Sgshapiro		v[r++] = strtol(*cpp, NULL, 0);
729464562Sgshapiro
729564562Sgshapiro	/* operator and (at least) two operands given? */
729664562Sgshapiro	if (name != NULL && r == 2)
729764562Sgshapiro	{
729890792Sgshapiro		switch (*name)
729964562Sgshapiro		{
730064562Sgshapiro		  case '|':
730164562Sgshapiro			r = v[0] | v[1];
730264562Sgshapiro			break;
730364562Sgshapiro
730464562Sgshapiro		  case '&':
730564562Sgshapiro			r = v[0] & v[1];
730664562Sgshapiro			break;
730764562Sgshapiro
730864562Sgshapiro		  case '%':
730964562Sgshapiro			if (v[1] == 0)
731064562Sgshapiro				return NULL;
731164562Sgshapiro			r = v[0] % v[1];
731264562Sgshapiro			break;
731364562Sgshapiro		  case '+':
731464562Sgshapiro			r = v[0] + v[1];
731564562Sgshapiro			break;
731664562Sgshapiro
731764562Sgshapiro		  case '-':
731864562Sgshapiro			r = v[0] - v[1];
731964562Sgshapiro			break;
732064562Sgshapiro
732164562Sgshapiro		  case '*':
732264562Sgshapiro			r = v[0] * v[1];
732364562Sgshapiro			break;
732464562Sgshapiro
732564562Sgshapiro		  case '/':
732664562Sgshapiro			if (v[1] == 0)
732764562Sgshapiro				return NULL;
732864562Sgshapiro			r = v[0] / v[1];
732964562Sgshapiro			break;
733064562Sgshapiro
733164562Sgshapiro		  case 'l':
733264562Sgshapiro			res = v[0] < v[1];
733390792Sgshapiro			boolres = true;
733464562Sgshapiro			break;
733564562Sgshapiro
733664562Sgshapiro		  case '=':
733764562Sgshapiro			res = v[0] == v[1];
733890792Sgshapiro			boolres = true;
733964562Sgshapiro			break;
734064562Sgshapiro
7341168515Sgshapiro		  case 'r':
7342168515Sgshapiro			r = v[1] - v[0] + 1;
7343168515Sgshapiro			if (r <= 0)
7344168515Sgshapiro				return NULL;
7345168515Sgshapiro			r = get_random() % r + v[0];
7346168515Sgshapiro			break;
7347168515Sgshapiro
734864562Sgshapiro		  default:
734964562Sgshapiro			/* XXX */
735064562Sgshapiro			*statp = EX_CONFIG;
735164562Sgshapiro			if (LogLevel > 10)
735264562Sgshapiro				sm_syslog(LOG_WARNING, NOQID,
735364562Sgshapiro					  "arith_map: unknown operator %c",
7354203004Sgshapiro					  (isascii(*name) && isprint(*name)) ?
7355203004Sgshapiro					  *name : '?');
735664562Sgshapiro			return NULL;
735764562Sgshapiro		}
735864562Sgshapiro		if (boolres)
7359168515Sgshapiro			(void) sm_snprintf(result, sizeof(result),
736090792Sgshapiro				res ? "TRUE" : "FALSE");
736164562Sgshapiro		else
7362168515Sgshapiro			(void) sm_snprintf(result, sizeof(result), "%ld", r);
736364562Sgshapiro		return result;
736464562Sgshapiro	}
736564562Sgshapiro	*statp = EX_CONFIG;
736664562Sgshapiro	return NULL;
736764562Sgshapiro}
7368132943Sgshapiro
7369132943Sgshapiro#if SOCKETMAP
7370132943Sgshapiro
7371132943Sgshapiro# if NETINET || NETINET6
7372132943Sgshapiro#  include <arpa/inet.h>
7373132943Sgshapiro# endif /* NETINET || NETINET6 */
7374132943Sgshapiro
7375132943Sgshapiro# define socket_map_next map_stack[0]
7376132943Sgshapiro
7377132943Sgshapiro/*
7378132943Sgshapiro**  SOCKET_MAP_OPEN -- open socket table
7379132943Sgshapiro*/
7380132943Sgshapiro
7381132943Sgshapirobool
7382132943Sgshapirosocket_map_open(map, mode)
7383132943Sgshapiro	MAP *map;
7384132943Sgshapiro	int mode;
7385132943Sgshapiro{
7386132943Sgshapiro	STAB *s;
7387132943Sgshapiro	int sock = 0;
7388132943Sgshapiro	SOCKADDR_LEN_T addrlen = 0;
7389132943Sgshapiro	int addrno = 0;
7390132943Sgshapiro	int save_errno;
7391132943Sgshapiro	char *p;
7392132943Sgshapiro	char *colon;
7393132943Sgshapiro	char *at;
7394132943Sgshapiro	struct hostent *hp = NULL;
7395132943Sgshapiro	SOCKADDR addr;
7396132943Sgshapiro
7397132943Sgshapiro	if (tTd(38, 2))
7398132943Sgshapiro		sm_dprintf("socket_map_open(%s, %s, %d)\n",
7399132943Sgshapiro			map->map_mname, map->map_file, mode);
7400132943Sgshapiro
7401132943Sgshapiro	mode &= O_ACCMODE;
7402132943Sgshapiro
7403132943Sgshapiro	/* sendmail doesn't have the ability to write to SOCKET (yet) */
7404132943Sgshapiro	if (mode != O_RDONLY)
7405132943Sgshapiro	{
7406132943Sgshapiro		/* issue a pseudo-error message */
7407132943Sgshapiro		errno = SM_EMAPCANTWRITE;
7408132943Sgshapiro		return false;
7409132943Sgshapiro	}
7410132943Sgshapiro
7411132943Sgshapiro	if (*map->map_file == '\0')
7412132943Sgshapiro	{
7413132943Sgshapiro		syserr("socket map \"%s\": empty or missing socket information",
7414132943Sgshapiro			map->map_mname);
7415132943Sgshapiro		return false;
7416132943Sgshapiro	}
7417132943Sgshapiro
7418132943Sgshapiro	s = socket_map_findconn(map->map_file);
7419132943Sgshapiro	if (s->s_socketmap != NULL)
7420132943Sgshapiro	{
7421132943Sgshapiro		/* Copy open connection */
7422132943Sgshapiro		map->map_db1 = s->s_socketmap->map_db1;
7423132943Sgshapiro
7424132943Sgshapiro		/* Add this map as head of linked list */
7425132943Sgshapiro		map->socket_map_next = s->s_socketmap;
7426132943Sgshapiro		s->s_socketmap = map;
7427132943Sgshapiro
7428132943Sgshapiro		if (tTd(38, 2))
7429132943Sgshapiro			sm_dprintf("using cached connection\n");
7430132943Sgshapiro		return true;
7431132943Sgshapiro	}
7432132943Sgshapiro
7433132943Sgshapiro	if (tTd(38, 2))
7434132943Sgshapiro		sm_dprintf("opening new connection\n");
7435132943Sgshapiro
7436132943Sgshapiro	/* following code is ripped from milter.c */
7437132943Sgshapiro	/* XXX It should be put in a library... */
7438132943Sgshapiro
7439132943Sgshapiro	/* protocol:filename or protocol:port@host */
7440168515Sgshapiro	memset(&addr, '\0', sizeof(addr));
7441132943Sgshapiro	p = map->map_file;
7442132943Sgshapiro	colon = strchr(p, ':');
7443132943Sgshapiro	if (colon != NULL)
7444132943Sgshapiro	{
7445132943Sgshapiro		*colon = '\0';
7446132943Sgshapiro
7447132943Sgshapiro		if (*p == '\0')
7448132943Sgshapiro		{
7449132943Sgshapiro# if NETUNIX
7450132943Sgshapiro			/* default to AF_UNIX */
7451132943Sgshapiro			addr.sa.sa_family = AF_UNIX;
7452132943Sgshapiro# else /* NETUNIX */
7453132943Sgshapiro#  if NETINET
7454132943Sgshapiro			/* default to AF_INET */
7455132943Sgshapiro			addr.sa.sa_family = AF_INET;
7456132943Sgshapiro#  else /* NETINET */
7457132943Sgshapiro#   if NETINET6
7458132943Sgshapiro			/* default to AF_INET6 */
7459132943Sgshapiro			addr.sa.sa_family = AF_INET6;
7460132943Sgshapiro#   else /* NETINET6 */
7461132943Sgshapiro			/* no protocols available */
7462132943Sgshapiro			syserr("socket map \"%s\": no valid socket protocols available",
7463132943Sgshapiro			map->map_mname);
7464132943Sgshapiro			return false;
7465132943Sgshapiro#   endif /* NETINET6 */
7466132943Sgshapiro#  endif /* NETINET */
7467132943Sgshapiro# endif /* NETUNIX */
7468132943Sgshapiro		}
7469132943Sgshapiro# if NETUNIX
7470132943Sgshapiro		else if (sm_strcasecmp(p, "unix") == 0 ||
7471132943Sgshapiro			 sm_strcasecmp(p, "local") == 0)
7472132943Sgshapiro			addr.sa.sa_family = AF_UNIX;
7473132943Sgshapiro# endif /* NETUNIX */
7474132943Sgshapiro# if NETINET
7475132943Sgshapiro		else if (sm_strcasecmp(p, "inet") == 0)
7476132943Sgshapiro			addr.sa.sa_family = AF_INET;
7477132943Sgshapiro# endif /* NETINET */
7478132943Sgshapiro# if NETINET6
7479132943Sgshapiro		else if (sm_strcasecmp(p, "inet6") == 0)
7480132943Sgshapiro			addr.sa.sa_family = AF_INET6;
7481132943Sgshapiro# endif /* NETINET6 */
7482132943Sgshapiro		else
7483132943Sgshapiro		{
7484132943Sgshapiro# ifdef EPROTONOSUPPORT
7485132943Sgshapiro			errno = EPROTONOSUPPORT;
7486132943Sgshapiro# else /* EPROTONOSUPPORT */
7487132943Sgshapiro			errno = EINVAL;
7488132943Sgshapiro# endif /* EPROTONOSUPPORT */
7489132943Sgshapiro			syserr("socket map \"%s\": unknown socket type %s",
7490132943Sgshapiro			       map->map_mname, p);
7491132943Sgshapiro			return false;
7492132943Sgshapiro		}
7493132943Sgshapiro		*colon++ = ':';
7494132943Sgshapiro	}
7495132943Sgshapiro	else
7496132943Sgshapiro	{
7497132943Sgshapiro		colon = p;
7498132943Sgshapiro#if NETUNIX
7499132943Sgshapiro		/* default to AF_UNIX */
7500132943Sgshapiro		addr.sa.sa_family = AF_UNIX;
7501132943Sgshapiro#else /* NETUNIX */
7502132943Sgshapiro# if NETINET
7503132943Sgshapiro		/* default to AF_INET */
7504132943Sgshapiro		addr.sa.sa_family = AF_INET;
7505132943Sgshapiro# else /* NETINET */
7506132943Sgshapiro#  if NETINET6
7507132943Sgshapiro		/* default to AF_INET6 */
7508132943Sgshapiro		addr.sa.sa_family = AF_INET6;
7509132943Sgshapiro#  else /* NETINET6 */
7510132943Sgshapiro		syserr("socket map \"%s\": unknown socket type %s",
7511132943Sgshapiro		       map->map_mname, p);
7512132943Sgshapiro		return false;
7513132943Sgshapiro#  endif /* NETINET6 */
7514132943Sgshapiro# endif /* NETINET */
7515132943Sgshapiro#endif /* NETUNIX */
7516132943Sgshapiro	}
7517132943Sgshapiro
7518132943Sgshapiro# if NETUNIX
7519132943Sgshapiro	if (addr.sa.sa_family == AF_UNIX)
7520132943Sgshapiro	{
7521132943Sgshapiro		long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK;
7522132943Sgshapiro
7523132943Sgshapiro		at = colon;
7524168515Sgshapiro		if (strlen(colon) >= sizeof(addr.sunix.sun_path))
7525132943Sgshapiro		{
7526132943Sgshapiro			syserr("socket map \"%s\": local socket name %s too long",
7527132943Sgshapiro			       map->map_mname, colon);
7528132943Sgshapiro			return false;
7529132943Sgshapiro		}
7530132943Sgshapiro		errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
7531132943Sgshapiro				 S_IRUSR|S_IWUSR, NULL);
7532132943Sgshapiro
7533132943Sgshapiro		if (errno != 0)
7534132943Sgshapiro		{
7535132943Sgshapiro			/* if not safe, don't create */
7536132943Sgshapiro				syserr("socket map \"%s\": local socket name %s unsafe",
7537132943Sgshapiro			       map->map_mname, colon);
7538132943Sgshapiro			return false;
7539132943Sgshapiro		}
7540132943Sgshapiro
7541132943Sgshapiro		(void) sm_strlcpy(addr.sunix.sun_path, colon,
7542168515Sgshapiro			       sizeof(addr.sunix.sun_path));
7543168515Sgshapiro		addrlen = sizeof(struct sockaddr_un);
7544132943Sgshapiro	}
7545132943Sgshapiro	else
7546132943Sgshapiro# endif /* NETUNIX */
7547132943Sgshapiro# if NETINET || NETINET6
7548132943Sgshapiro	if (false
7549132943Sgshapiro#  if NETINET
7550132943Sgshapiro		 || addr.sa.sa_family == AF_INET
7551132943Sgshapiro#  endif /* NETINET */
7552132943Sgshapiro#  if NETINET6
7553132943Sgshapiro		 || addr.sa.sa_family == AF_INET6
7554132943Sgshapiro#  endif /* NETINET6 */
7555132943Sgshapiro		 )
7556132943Sgshapiro	{
7557132943Sgshapiro		unsigned short port;
7558132943Sgshapiro
7559132943Sgshapiro		/* Parse port@host */
7560132943Sgshapiro		at = strchr(colon, '@');
7561132943Sgshapiro		if (at == NULL)
7562132943Sgshapiro		{
7563132943Sgshapiro			syserr("socket map \"%s\": bad address %s (expected port@host)",
7564132943Sgshapiro				       map->map_mname, colon);
7565132943Sgshapiro			return false;
7566132943Sgshapiro		}
7567132943Sgshapiro		*at = '\0';
7568132943Sgshapiro		if (isascii(*colon) && isdigit(*colon))
7569132943Sgshapiro			port = htons((unsigned short) atoi(colon));
7570132943Sgshapiro		else
7571132943Sgshapiro		{
7572132943Sgshapiro#  ifdef NO_GETSERVBYNAME
7573132943Sgshapiro			syserr("socket map \"%s\": invalid port number %s",
7574132943Sgshapiro				       map->map_mname, colon);
7575132943Sgshapiro			return false;
7576132943Sgshapiro#  else /* NO_GETSERVBYNAME */
7577132943Sgshapiro			register struct servent *sp;
7578132943Sgshapiro
7579132943Sgshapiro			sp = getservbyname(colon, "tcp");
7580132943Sgshapiro			if (sp == NULL)
7581132943Sgshapiro			{
7582132943Sgshapiro				syserr("socket map \"%s\": unknown port name %s",
7583132943Sgshapiro					       map->map_mname, colon);
7584132943Sgshapiro				return false;
7585132943Sgshapiro			}
7586132943Sgshapiro			port = sp->s_port;
7587132943Sgshapiro#  endif /* NO_GETSERVBYNAME */
7588132943Sgshapiro		}
7589132943Sgshapiro		*at++ = '@';
7590132943Sgshapiro		if (*at == '[')
7591132943Sgshapiro		{
7592132943Sgshapiro			char *end;
7593132943Sgshapiro
7594132943Sgshapiro			end = strchr(at, ']');
7595132943Sgshapiro			if (end != NULL)
7596132943Sgshapiro			{
7597132943Sgshapiro				bool found = false;
7598132943Sgshapiro#  if NETINET
7599132943Sgshapiro				unsigned long hid = INADDR_NONE;
7600132943Sgshapiro#  endif /* NETINET */
7601132943Sgshapiro#  if NETINET6
7602132943Sgshapiro				struct sockaddr_in6 hid6;
7603132943Sgshapiro#  endif /* NETINET6 */
7604132943Sgshapiro
7605132943Sgshapiro				*end = '\0';
7606132943Sgshapiro#  if NETINET
7607132943Sgshapiro				if (addr.sa.sa_family == AF_INET &&
7608132943Sgshapiro				    (hid = inet_addr(&at[1])) != INADDR_NONE)
7609132943Sgshapiro				{
7610132943Sgshapiro					addr.sin.sin_addr.s_addr = hid;
7611132943Sgshapiro					addr.sin.sin_port = port;
7612132943Sgshapiro					found = true;
7613132943Sgshapiro				}
7614132943Sgshapiro#  endif /* NETINET */
7615132943Sgshapiro#  if NETINET6
7616168515Sgshapiro				(void) memset(&hid6, '\0', sizeof(hid6));
7617132943Sgshapiro				if (addr.sa.sa_family == AF_INET6 &&
7618132943Sgshapiro				    anynet_pton(AF_INET6, &at[1],
7619132943Sgshapiro						&hid6.sin6_addr) == 1)
7620132943Sgshapiro				{
7621132943Sgshapiro					addr.sin6.sin6_addr = hid6.sin6_addr;
7622132943Sgshapiro					addr.sin6.sin6_port = port;
7623132943Sgshapiro					found = true;
7624132943Sgshapiro				}
7625132943Sgshapiro#  endif /* NETINET6 */
7626132943Sgshapiro				*end = ']';
7627132943Sgshapiro				if (!found)
7628132943Sgshapiro				{
7629132943Sgshapiro					syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
7630132943Sgshapiro					       map->map_mname, at);
7631132943Sgshapiro					return false;
7632132943Sgshapiro				}
7633132943Sgshapiro			}
7634132943Sgshapiro			else
7635132943Sgshapiro			{
7636132943Sgshapiro				syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
7637132943Sgshapiro				       map->map_mname, at);
7638132943Sgshapiro				return false;
7639132943Sgshapiro			}
7640132943Sgshapiro		}
7641132943Sgshapiro		else
7642132943Sgshapiro		{
7643132943Sgshapiro			hp = sm_gethostbyname(at, addr.sa.sa_family);
7644132943Sgshapiro			if (hp == NULL)
7645132943Sgshapiro			{
7646132943Sgshapiro				syserr("socket map \"%s\": Unknown host name %s",
7647132943Sgshapiro					map->map_mname, at);
7648132943Sgshapiro				return false;
7649132943Sgshapiro			}
7650132943Sgshapiro			addr.sa.sa_family = hp->h_addrtype;
7651132943Sgshapiro			switch (hp->h_addrtype)
7652132943Sgshapiro			{
7653132943Sgshapiro#  if NETINET
7654132943Sgshapiro			  case AF_INET:
7655132943Sgshapiro				memmove(&addr.sin.sin_addr,
7656132943Sgshapiro					hp->h_addr, INADDRSZ);
7657132943Sgshapiro				addr.sin.sin_port = port;
7658168515Sgshapiro				addrlen = sizeof(struct sockaddr_in);
7659132943Sgshapiro				addrno = 1;
7660132943Sgshapiro				break;
7661132943Sgshapiro#  endif /* NETINET */
7662132943Sgshapiro
7663132943Sgshapiro#  if NETINET6
7664132943Sgshapiro			  case AF_INET6:
7665132943Sgshapiro				memmove(&addr.sin6.sin6_addr,
7666132943Sgshapiro					hp->h_addr, IN6ADDRSZ);
7667132943Sgshapiro				addr.sin6.sin6_port = port;
7668168515Sgshapiro				addrlen = sizeof(struct sockaddr_in6);
7669132943Sgshapiro				addrno = 1;
7670132943Sgshapiro				break;
7671132943Sgshapiro#  endif /* NETINET6 */
7672132943Sgshapiro
7673132943Sgshapiro			  default:
7674132943Sgshapiro				syserr("socket map \"%s\": Unknown protocol for %s (%d)",
7675132943Sgshapiro					map->map_mname, at, hp->h_addrtype);
7676132943Sgshapiro#  if NETINET6
7677132943Sgshapiro				freehostent(hp);
7678132943Sgshapiro#  endif /* NETINET6 */
7679132943Sgshapiro				return false;
7680132943Sgshapiro			}
7681132943Sgshapiro		}
7682132943Sgshapiro	}
7683132943Sgshapiro	else
7684132943Sgshapiro# endif /* NETINET || NETINET6 */
7685132943Sgshapiro	{
7686132943Sgshapiro		syserr("socket map \"%s\": unknown socket protocol",
7687132943Sgshapiro			map->map_mname);
7688132943Sgshapiro		return false;
7689132943Sgshapiro	}
7690132943Sgshapiro
7691132943Sgshapiro	/* nope, actually connecting */
7692132943Sgshapiro	for (;;)
7693132943Sgshapiro	{
7694132943Sgshapiro		sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
7695132943Sgshapiro		if (sock < 0)
7696132943Sgshapiro		{
7697132943Sgshapiro			save_errno = errno;
7698132943Sgshapiro			if (tTd(38, 5))
7699132943Sgshapiro				sm_dprintf("socket map \"%s\": error creating socket: %s\n",
7700132943Sgshapiro					   map->map_mname,
7701132943Sgshapiro					   sm_errstring(save_errno));
7702132943Sgshapiro# if NETINET6
7703132943Sgshapiro			if (hp != NULL)
7704132943Sgshapiro				freehostent(hp);
7705132943Sgshapiro# endif /* NETINET6 */
7706132943Sgshapiro			return false;
7707132943Sgshapiro		}
7708132943Sgshapiro
7709132943Sgshapiro		if (connect(sock, (struct sockaddr *) &addr, addrlen) >= 0)
7710132943Sgshapiro			break;
7711132943Sgshapiro
7712132943Sgshapiro		/* couldn't connect.... try next address */
7713132943Sgshapiro		save_errno = errno;
7714132943Sgshapiro		p = CurHostName;
7715132943Sgshapiro		CurHostName = at;
7716132943Sgshapiro		if (tTd(38, 5))
7717132943Sgshapiro			sm_dprintf("socket_open (%s): open %s failed: %s\n",
7718132943Sgshapiro				map->map_mname, at, sm_errstring(save_errno));
7719132943Sgshapiro		CurHostName = p;
7720132943Sgshapiro		(void) close(sock);
7721132943Sgshapiro
7722132943Sgshapiro		/* try next address */
7723132943Sgshapiro		if (hp != NULL && hp->h_addr_list[addrno] != NULL)
7724132943Sgshapiro		{
7725132943Sgshapiro			switch (addr.sa.sa_family)
7726132943Sgshapiro			{
7727132943Sgshapiro# if NETINET
7728132943Sgshapiro			  case AF_INET:
7729132943Sgshapiro				memmove(&addr.sin.sin_addr,
7730132943Sgshapiro					hp->h_addr_list[addrno++],
7731132943Sgshapiro					INADDRSZ);
7732132943Sgshapiro				break;
7733132943Sgshapiro# endif /* NETINET */
7734132943Sgshapiro
7735132943Sgshapiro# if NETINET6
7736132943Sgshapiro			  case AF_INET6:
7737132943Sgshapiro				memmove(&addr.sin6.sin6_addr,
7738132943Sgshapiro					hp->h_addr_list[addrno++],
7739132943Sgshapiro					IN6ADDRSZ);
7740132943Sgshapiro				break;
7741132943Sgshapiro# endif /* NETINET6 */
7742132943Sgshapiro
7743132943Sgshapiro			  default:
7744132943Sgshapiro				if (tTd(38, 5))
7745132943Sgshapiro					sm_dprintf("socket map \"%s\": Unknown protocol for %s (%d)\n",
7746132943Sgshapiro						   map->map_mname, at,
7747132943Sgshapiro						   hp->h_addrtype);
7748132943Sgshapiro# if NETINET6
7749132943Sgshapiro				freehostent(hp);
7750132943Sgshapiro# endif /* NETINET6 */
7751132943Sgshapiro				return false;
7752132943Sgshapiro			}
7753132943Sgshapiro			continue;
7754132943Sgshapiro		}
7755132943Sgshapiro		p = CurHostName;
7756132943Sgshapiro		CurHostName = at;
7757132943Sgshapiro		if (tTd(38, 5))
7758132943Sgshapiro			sm_dprintf("socket map \"%s\": error connecting to socket map: %s\n",
7759132943Sgshapiro				   map->map_mname, sm_errstring(save_errno));
7760132943Sgshapiro		CurHostName = p;
7761132943Sgshapiro# if NETINET6
7762132943Sgshapiro		if (hp != NULL)
7763132943Sgshapiro			freehostent(hp);
7764132943Sgshapiro# endif /* NETINET6 */
7765132943Sgshapiro		return false;
7766132943Sgshapiro	}
7767132943Sgshapiro# if NETINET6
7768132943Sgshapiro	if (hp != NULL)
7769132943Sgshapiro	{
7770132943Sgshapiro		freehostent(hp);
7771132943Sgshapiro		hp = NULL;
7772132943Sgshapiro	}
7773132943Sgshapiro# endif /* NETINET6 */
7774132943Sgshapiro	if ((map->map_db1 = (ARBPTR_T) sm_io_open(SmFtStdiofd,
7775132943Sgshapiro						  SM_TIME_DEFAULT,
7776132943Sgshapiro						  (void *) &sock,
7777132943Sgshapiro						  SM_IO_RDWR,
7778132943Sgshapiro						  NULL)) == NULL)
7779132943Sgshapiro	{
7780132943Sgshapiro		close(sock);
7781132943Sgshapiro		if (tTd(38, 2))
7782132943Sgshapiro		    sm_dprintf("socket_open (%s): failed to create stream: %s\n",
7783132943Sgshapiro			       map->map_mname, sm_errstring(errno));
7784132943Sgshapiro		return false;
7785132943Sgshapiro	}
7786132943Sgshapiro
7787132943Sgshapiro	/* Save connection for reuse */
7788132943Sgshapiro	s->s_socketmap = map;
7789132943Sgshapiro	return true;
7790132943Sgshapiro}
7791132943Sgshapiro
7792132943Sgshapiro/*
7793132943Sgshapiro**  SOCKET_MAP_FINDCONN -- find a SOCKET connection to the server
7794132943Sgshapiro**
7795132943Sgshapiro**	Cache SOCKET connections based on the connection specifier
7796132943Sgshapiro**	and PID so we don't have multiple connections open to
7797132943Sgshapiro**	the same server for different maps.  Need a separate connection
7798132943Sgshapiro**	per PID since a parent process may close the map before the
7799132943Sgshapiro**	child is done with it.
7800132943Sgshapiro**
7801132943Sgshapiro**	Parameters:
7802132943Sgshapiro**		conn -- SOCKET map connection specifier
7803132943Sgshapiro**
7804132943Sgshapiro**	Returns:
7805132943Sgshapiro**		Symbol table entry for the SOCKET connection.
7806132943Sgshapiro*/
7807132943Sgshapiro
7808132943Sgshapirostatic STAB *
7809132943Sgshapirosocket_map_findconn(conn)
7810132943Sgshapiro	const char *conn;
7811132943Sgshapiro{
7812132943Sgshapiro	char *nbuf;
7813132943Sgshapiro	STAB *SM_NONVOLATILE s = NULL;
7814132943Sgshapiro
7815132943Sgshapiro	nbuf = sm_stringf_x("%s%c%d", conn, CONDELSE, (int) CurrentPid);
7816132943Sgshapiro	SM_TRY
7817132943Sgshapiro		s = stab(nbuf, ST_SOCKETMAP, ST_ENTER);
7818132943Sgshapiro	SM_FINALLY
7819132943Sgshapiro		sm_free(nbuf);
7820132943Sgshapiro	SM_END_TRY
7821132943Sgshapiro	return s;
7822132943Sgshapiro}
7823132943Sgshapiro
7824132943Sgshapiro/*
7825132943Sgshapiro**  SOCKET_MAP_CLOSE -- close the socket
7826132943Sgshapiro*/
7827132943Sgshapiro
7828132943Sgshapirovoid
7829132943Sgshapirosocket_map_close(map)
7830132943Sgshapiro	MAP *map;
7831132943Sgshapiro{
7832132943Sgshapiro	STAB *s;
7833132943Sgshapiro	MAP *smap;
7834132943Sgshapiro
7835132943Sgshapiro	if (tTd(38, 20))
7836132943Sgshapiro		sm_dprintf("socket_map_close(%s), pid=%ld\n", map->map_file,
7837132943Sgshapiro			(long) CurrentPid);
7838132943Sgshapiro
7839132943Sgshapiro	/* Check if already closed */
7840132943Sgshapiro	if (map->map_db1 == NULL)
7841132943Sgshapiro	{
7842132943Sgshapiro		if (tTd(38, 20))
7843132943Sgshapiro			sm_dprintf("socket_map_close(%s) already closed\n",
7844132943Sgshapiro				map->map_file);
7845132943Sgshapiro		return;
7846132943Sgshapiro	}
7847132943Sgshapiro	sm_io_close((SM_FILE_T *)map->map_db1, SM_TIME_DEFAULT);
7848132943Sgshapiro
7849132943Sgshapiro	/* Mark all the maps that share the connection as closed */
7850132943Sgshapiro	s = socket_map_findconn(map->map_file);
7851132943Sgshapiro	smap = s->s_socketmap;
7852132943Sgshapiro	while (smap != NULL)
7853132943Sgshapiro	{
7854132943Sgshapiro		MAP *next;
7855132943Sgshapiro
7856132943Sgshapiro		if (tTd(38, 2) && smap != map)
7857132943Sgshapiro			sm_dprintf("socket_map_close(%s): closed %s (shared SOCKET connection)\n",
7858132943Sgshapiro				map->map_mname, smap->map_mname);
7859132943Sgshapiro
7860132943Sgshapiro		smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
7861132943Sgshapiro		smap->map_db1 = NULL;
7862132943Sgshapiro		next = smap->socket_map_next;
7863132943Sgshapiro		smap->socket_map_next = NULL;
7864132943Sgshapiro		smap = next;
7865132943Sgshapiro	}
7866132943Sgshapiro	s->s_socketmap = NULL;
7867132943Sgshapiro}
7868132943Sgshapiro
7869132943Sgshapiro/*
7870132943Sgshapiro** SOCKET_MAP_LOOKUP -- look up a datum in a SOCKET table
7871132943Sgshapiro*/
7872132943Sgshapiro
7873132943Sgshapirochar *
7874132943Sgshapirosocket_map_lookup(map, name, av, statp)
7875132943Sgshapiro	MAP *map;
7876132943Sgshapiro	char *name;
7877132943Sgshapiro	char **av;
7878132943Sgshapiro	int *statp;
7879132943Sgshapiro{
7880132943Sgshapiro	unsigned int nettolen, replylen, recvlen;
7881147078Sgshapiro	char *replybuf, *rval, *value, *status, *key;
7882132943Sgshapiro	SM_FILE_T *f;
7883147078Sgshapiro	char keybuf[MAXNAME + 1];
7884132943Sgshapiro
7885132943Sgshapiro	replybuf = NULL;
7886132943Sgshapiro	rval = NULL;
7887132943Sgshapiro	f = (SM_FILE_T *)map->map_db1;
7888132943Sgshapiro	if (tTd(38, 20))
7889132943Sgshapiro		sm_dprintf("socket_map_lookup(%s, %s) %s\n",
7890132943Sgshapiro			map->map_mname, name, map->map_file);
7891132943Sgshapiro
7892147078Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
7893147078Sgshapiro	{
7894147078Sgshapiro		nettolen = strlen(name);
7895168515Sgshapiro		if (nettolen > sizeof(keybuf) - 1)
7896168515Sgshapiro			nettolen = sizeof(keybuf) - 1;
7897147078Sgshapiro		memmove(keybuf, name, nettolen);
7898147078Sgshapiro		keybuf[nettolen] = '\0';
7899147078Sgshapiro		makelower(keybuf);
7900147078Sgshapiro		key = keybuf;
7901147078Sgshapiro	}
7902147078Sgshapiro	else
7903147078Sgshapiro		key = name;
7904147078Sgshapiro
7905147078Sgshapiro	nettolen = strlen(map->map_mname) + 1 + strlen(key);
7906132943Sgshapiro	SM_ASSERT(nettolen > strlen(map->map_mname));
7907147078Sgshapiro	SM_ASSERT(nettolen > strlen(key));
7908132943Sgshapiro	if ((sm_io_fprintf(f, SM_TIME_DEFAULT, "%u:%s %s,",
7909147078Sgshapiro			   nettolen, map->map_mname, key) == SM_IO_EOF) ||
7910132943Sgshapiro	    (sm_io_flush(f, SM_TIME_DEFAULT) != 0) ||
7911132943Sgshapiro	    (sm_io_error(f)))
7912132943Sgshapiro	{
7913132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): failed to send lookup request",
7914132943Sgshapiro			map->map_mname);
7915132943Sgshapiro		*statp = EX_TEMPFAIL;
7916132943Sgshapiro		goto errcl;
7917132943Sgshapiro	}
7918132943Sgshapiro
7919132943Sgshapiro	if (sm_io_fscanf(f, SM_TIME_DEFAULT, "%9u", &replylen) != 1)
7920132943Sgshapiro	{
7921132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): failed to read length parameter of reply",
7922132943Sgshapiro			map->map_mname);
7923132943Sgshapiro		*statp = EX_TEMPFAIL;
7924132943Sgshapiro		goto errcl;
7925132943Sgshapiro	}
7926132943Sgshapiro	if (replylen > SOCKETMAP_MAXL)
7927132943Sgshapiro	{
7928132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): reply too long: %u",
7929132943Sgshapiro			   map->map_mname, replylen);
7930132943Sgshapiro		*statp = EX_TEMPFAIL;
7931132943Sgshapiro		goto errcl;
7932132943Sgshapiro	}
7933132943Sgshapiro	if (sm_io_getc(f, SM_TIME_DEFAULT) != ':')
7934132943Sgshapiro	{
7935132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): missing ':' in reply",
7936132943Sgshapiro			map->map_mname);
7937132943Sgshapiro		*statp = EX_TEMPFAIL;
7938132943Sgshapiro		goto error;
7939132943Sgshapiro	}
7940132943Sgshapiro
7941132943Sgshapiro	replybuf = (char *) sm_malloc(replylen + 1);
7942132943Sgshapiro	if (replybuf == NULL)
7943132943Sgshapiro	{
7944132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): can't allocate %u bytes",
7945132943Sgshapiro			map->map_mname, replylen + 1);
7946132943Sgshapiro		*statp = EX_OSERR;
7947132943Sgshapiro		goto error;
7948132943Sgshapiro	}
7949132943Sgshapiro
7950132943Sgshapiro	recvlen = sm_io_read(f, SM_TIME_DEFAULT, replybuf, replylen);
7951132943Sgshapiro	if (recvlen < replylen)
7952132943Sgshapiro	{
7953132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): received only %u of %u reply characters",
7954132943Sgshapiro			   map->map_mname, recvlen, replylen);
7955132943Sgshapiro		*statp = EX_TEMPFAIL;
7956132943Sgshapiro		goto errcl;
7957132943Sgshapiro	}
7958132943Sgshapiro	if (sm_io_getc(f, SM_TIME_DEFAULT) != ',')
7959132943Sgshapiro	{
7960132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): missing ',' in reply",
7961132943Sgshapiro			map->map_mname);
7962132943Sgshapiro		*statp = EX_TEMPFAIL;
7963132943Sgshapiro		goto errcl;
7964132943Sgshapiro	}
7965132943Sgshapiro	status = replybuf;
7966132943Sgshapiro	replybuf[recvlen] = '\0';
7967132943Sgshapiro	value = strchr(replybuf, ' ');
7968132943Sgshapiro	if (value != NULL)
7969132943Sgshapiro	{
7970132943Sgshapiro		*value = '\0';
7971132943Sgshapiro		value++;
7972132943Sgshapiro	}
7973132943Sgshapiro	if (strcmp(status, "OK") == 0)
7974132943Sgshapiro	{
7975132943Sgshapiro		*statp = EX_OK;
7976132943Sgshapiro
7977132943Sgshapiro		/* collect the return value */
7978132943Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
7979147078Sgshapiro			rval = map_rewrite(map, key, strlen(key), NULL);
7980132943Sgshapiro		else
7981132943Sgshapiro			rval = map_rewrite(map, value, strlen(value), av);
7982132943Sgshapiro	}
7983132943Sgshapiro	else if (strcmp(status, "NOTFOUND") == 0)
7984132943Sgshapiro	{
7985132943Sgshapiro		*statp = EX_NOTFOUND;
7986132943Sgshapiro		if (tTd(38, 20))
7987132943Sgshapiro			sm_dprintf("socket_map_lookup(%s): %s not found\n",
7988147078Sgshapiro				map->map_mname, key);
7989132943Sgshapiro	}
7990132943Sgshapiro	else
7991132943Sgshapiro	{
7992132943Sgshapiro		if (tTd(38, 5))
7993132943Sgshapiro			sm_dprintf("socket_map_lookup(%s, %s): server returned error: type=%s, reason=%s\n",
7994147078Sgshapiro				map->map_mname, key, status,
7995132943Sgshapiro				value ? value : "");
7996132943Sgshapiro		if ((strcmp(status, "TEMP") == 0) ||
7997132943Sgshapiro		    (strcmp(status, "TIMEOUT") == 0))
7998132943Sgshapiro			*statp = EX_TEMPFAIL;
7999132943Sgshapiro		else if(strcmp(status, "PERM") == 0)
8000132943Sgshapiro			*statp = EX_UNAVAILABLE;
8001132943Sgshapiro		else
8002132943Sgshapiro			*statp = EX_PROTOCOL;
8003132943Sgshapiro	}
8004132943Sgshapiro
8005132943Sgshapiro	if (replybuf != NULL)
8006132943Sgshapiro		sm_free(replybuf);
8007132943Sgshapiro	return rval;
8008132943Sgshapiro
8009132943Sgshapiro  errcl:
8010132943Sgshapiro	socket_map_close(map);
8011132943Sgshapiro  error:
8012132943Sgshapiro	if (replybuf != NULL)
8013132943Sgshapiro		sm_free(replybuf);
8014132943Sgshapiro	return rval;
8015132943Sgshapiro}
8016132943Sgshapiro#endif /* SOCKETMAP */
8017