138032Speter/*
2261363Sgshapiro * Copyright (c) 1998-2008 Proofpoint, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1992, 1995-1997 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1992, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1464562Sgshapiro#include <sendmail.h>
1538032Speter
16266692SgshapiroSM_RCSID("@(#)$Id: map.c,v 8.713 2013-11-22 20:51:55 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
207285303Sgshapiro		  case 'd':
208285303Sgshapiro			{
209285303Sgshapiro				char *h;
210285303Sgshapiro
211285303Sgshapiro				++p;
212285303Sgshapiro				h = strchr(p, ' ');
213285303Sgshapiro				if (h != NULL)
214285303Sgshapiro					*h = '\0';
215285303Sgshapiro				map->map_timeout = convtime(p, 's');
216285303Sgshapiro				if (h != NULL)
217285303Sgshapiro					*h = ' ';
218285303Sgshapiro			}
219285303Sgshapiro			break;
220285303Sgshapiro
22138032Speter		  case 'T':
22238032Speter			map->map_tapp = ++p;
22338032Speter			break;
22438032Speter
22538032Speter		  case 'k':
22638032Speter			while (isascii(*++p) && isspace(*p))
22738032Speter				continue;
22838032Speter			map->map_keycolnm = p;
22938032Speter			break;
23038032Speter
23138032Speter		  case 'v':
23238032Speter			while (isascii(*++p) && isspace(*p))
23338032Speter				continue;
23438032Speter			map->map_valcolnm = p;
23538032Speter			break;
23638032Speter
23738032Speter		  case 'z':
23838032Speter			if (*++p != '\\')
23938032Speter				map->map_coldelim = *p;
24038032Speter			else
24138032Speter			{
24238032Speter				switch (*++p)
24338032Speter				{
24438032Speter				  case 'n':
24538032Speter					map->map_coldelim = '\n';
24638032Speter					break;
24738032Speter
24838032Speter				  case 't':
24938032Speter					map->map_coldelim = '\t';
25038032Speter					break;
25138032Speter
25238032Speter				  default:
25338032Speter					map->map_coldelim = '\\';
25438032Speter				}
25538032Speter			}
25638032Speter			break;
25738032Speter
25838032Speter		  case 't':
25938032Speter			map->map_mflags |= MF_NODEFER;
26038032Speter			break;
26138032Speter
26264562Sgshapiro
26364562Sgshapiro		  case 'S':
26464562Sgshapiro			map->map_spacesub = *++p;
26538032Speter			break;
26638032Speter
26764562Sgshapiro		  case 'D':
26864562Sgshapiro			map->map_mflags |= MF_DEFER;
26938032Speter			break;
27064562Sgshapiro
27164562Sgshapiro		  default:
27264562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
27364562Sgshapiro			break;
27438032Speter		}
27538032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
27638032Speter			p++;
27738032Speter		if (*p != '\0')
27838032Speter			*p++ = '\0';
27938032Speter	}
28038032Speter	if (map->map_app != NULL)
28138032Speter		map->map_app = newstr(map->map_app);
28238032Speter	if (map->map_tapp != NULL)
28338032Speter		map->map_tapp = newstr(map->map_tapp);
28438032Speter	if (map->map_keycolnm != NULL)
28538032Speter		map->map_keycolnm = newstr(map->map_keycolnm);
28638032Speter	if (map->map_valcolnm != NULL)
28738032Speter		map->map_valcolnm = newstr(map->map_valcolnm);
28838032Speter
28938032Speter	if (*p != '\0')
29038032Speter	{
29138032Speter		map->map_file = p;
29238032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
29338032Speter			p++;
29438032Speter		if (*p != '\0')
29538032Speter			*p++ = '\0';
29638032Speter		map->map_file = newstr(map->map_file);
29738032Speter	}
29838032Speter
29938032Speter	while (*p != '\0' && isascii(*p) && isspace(*p))
30038032Speter		p++;
30138032Speter	if (*p != '\0')
30238032Speter		map->map_rebuild = newstr(p);
30338032Speter
30438032Speter	if (map->map_file == NULL &&
30538032Speter	    !bitset(MCF_OPTFILE, map->map_class->map_cflags))
30638032Speter	{
30738032Speter		syserr("No file name for %s map %s",
30838032Speter			map->map_class->map_cname, map->map_mname);
30990792Sgshapiro		return false;
31038032Speter	}
31190792Sgshapiro	return true;
31238032Speter}
31390792Sgshapiro/*
31438032Speter**  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
31538032Speter**
31638032Speter**	It also adds the map_app string.  It can be used as a utility
31738032Speter**	in the map_lookup method.
31838032Speter**
31938032Speter**	Parameters:
32038032Speter**		map -- the map that causes this.
32138032Speter**		s -- the string to rewrite, NOT necessarily null terminated.
32238032Speter**		slen -- the length of s.
32338032Speter**		av -- arguments to interpolate into buf.
32438032Speter**
32538032Speter**	Returns:
32638032Speter**		Pointer to rewritten result.  This is static data that
32738032Speter**		should be copied if it is to be saved!
32838032Speter*/
32938032Speter
33038032Speterchar *
33138032Spetermap_rewrite(map, s, slen, av)
33238032Speter	register MAP *map;
33338032Speter	register const char *s;
33438032Speter	size_t slen;
33538032Speter	char **av;
33638032Speter{
33738032Speter	register char *bp;
33838032Speter	register char c;
33938032Speter	char **avp;
34038032Speter	register char *ap;
34138032Speter	size_t l;
34238032Speter	size_t len;
34338032Speter	static size_t buflen = 0;
34438032Speter	static char *buf = NULL;
34538032Speter
34638032Speter	if (tTd(39, 1))
34738032Speter	{
34890792Sgshapiro		sm_dprintf("map_rewrite(%.*s), av =", (int) slen, s);
34938032Speter		if (av == NULL)
35090792Sgshapiro			sm_dprintf(" (nullv)");
35138032Speter		else
35238032Speter		{
35338032Speter			for (avp = av; *avp != NULL; avp++)
35490792Sgshapiro				sm_dprintf("\n\t%s", *avp);
35538032Speter		}
35690792Sgshapiro		sm_dprintf("\n");
35738032Speter	}
35838032Speter
35938032Speter	/* count expected size of output (can safely overestimate) */
36038032Speter	l = len = slen;
36138032Speter	if (av != NULL)
36238032Speter	{
36338032Speter		const char *sp = s;
36438032Speter
36538032Speter		while (l-- > 0 && (c = *sp++) != '\0')
36638032Speter		{
36738032Speter			if (c != '%')
36838032Speter				continue;
36938032Speter			if (l-- <= 0)
37038032Speter				break;
37138032Speter			c = *sp++;
37238032Speter			if (!(isascii(c) && isdigit(c)))
37338032Speter				continue;
37438032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
37538032Speter				continue;
37638032Speter			if (*avp == NULL)
37738032Speter				continue;
37838032Speter			len += strlen(*avp);
37938032Speter		}
38038032Speter	}
38138032Speter	if (map->map_app != NULL)
38238032Speter		len += strlen(map->map_app);
38338032Speter	if (buflen < ++len)
38438032Speter	{
38538032Speter		/* need to malloc additional space */
38638032Speter		buflen = len;
38738032Speter		if (buf != NULL)
38877349Sgshapiro			sm_free(buf);
38990792Sgshapiro		buf = sm_pmalloc_x(buflen);
39038032Speter	}
39138032Speter
39238032Speter	bp = buf;
39338032Speter	if (av == NULL)
39438032Speter	{
39564562Sgshapiro		memmove(bp, s, slen);
39638032Speter		bp += slen;
39764562Sgshapiro
39864562Sgshapiro		/* assert(len > slen); */
39964562Sgshapiro		len -= slen;
40038032Speter	}
40138032Speter	else
40238032Speter	{
40338032Speter		while (slen-- > 0 && (c = *s++) != '\0')
40438032Speter		{
40538032Speter			if (c != '%')
40638032Speter			{
40738032Speter  pushc:
408120256Sgshapiro				if (len-- <= 1)
40990792Sgshapiro				     break;
41038032Speter				*bp++ = c;
41138032Speter				continue;
41238032Speter			}
41338032Speter			if (slen-- <= 0 || (c = *s++) == '\0')
41438032Speter				c = '%';
41538032Speter			if (c == '%')
41638032Speter				goto pushc;
41738032Speter			if (!(isascii(c) && isdigit(c)))
41838032Speter			{
419120256Sgshapiro				if (len-- <= 1)
420120256Sgshapiro				     break;
42138032Speter				*bp++ = '%';
42238032Speter				goto pushc;
42338032Speter			}
42438032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
42538032Speter				continue;
42638032Speter			if (*avp == NULL)
42738032Speter				continue;
42838032Speter
42938032Speter			/* transliterate argument into output string */
43064562Sgshapiro			for (ap = *avp; (c = *ap++) != '\0' && len > 0; --len)
43138032Speter				*bp++ = c;
43238032Speter		}
43338032Speter	}
43464562Sgshapiro	if (map->map_app != NULL && len > 0)
43590792Sgshapiro		(void) sm_strlcpy(bp, map->map_app, len);
43638032Speter	else
43738032Speter		*bp = '\0';
43838032Speter	if (tTd(39, 1))
43990792Sgshapiro		sm_dprintf("map_rewrite => %s\n", buf);
44038032Speter	return buf;
44138032Speter}
44290792Sgshapiro/*
44364562Sgshapiro**  INITMAPS -- rebuild alias maps
44438032Speter**
44538032Speter**	Parameters:
44664562Sgshapiro**		none.
44738032Speter**
44838032Speter**	Returns:
44938032Speter**		none.
45038032Speter*/
45138032Speter
45238032Spetervoid
45364562Sgshapiroinitmaps()
45438032Speter{
45538032Speter#if XDEBUG
45638032Speter	checkfd012("entering initmaps");
45764562Sgshapiro#endif /* XDEBUG */
45838032Speter	stabapply(map_init, 0);
45938032Speter#if XDEBUG
46038032Speter	checkfd012("exiting initmaps");
46164562Sgshapiro#endif /* XDEBUG */
46238032Speter}
46390792Sgshapiro/*
46464562Sgshapiro**  MAP_INIT -- rebuild a map
46564562Sgshapiro**
46664562Sgshapiro**	Parameters:
46764562Sgshapiro**		s -- STAB entry: if map: try to rebuild
46864562Sgshapiro**		unused -- unused variable
46964562Sgshapiro**
47064562Sgshapiro**	Returns:
47164562Sgshapiro**		none.
47264562Sgshapiro**
47364562Sgshapiro**	Side Effects:
47464562Sgshapiro**		will close already open rebuildable map.
47564562Sgshapiro*/
47638032Speter
47764562Sgshapiro/* ARGSUSED1 */
47864562Sgshapirostatic void
47964562Sgshapiromap_init(s, unused)
48038032Speter	register STAB *s;
48164562Sgshapiro	int unused;
48238032Speter{
48338032Speter	register MAP *map;
48438032Speter
48538032Speter	/* has to be a map */
48690792Sgshapiro	if (s->s_symtype != ST_MAP)
48738032Speter		return;
48838032Speter
48938032Speter	map = &s->s_map;
49038032Speter	if (!bitset(MF_VALID, map->map_mflags))
49138032Speter		return;
49238032Speter
49338032Speter	if (tTd(38, 2))
49490792Sgshapiro		sm_dprintf("map_init(%s:%s, %s)\n",
49538032Speter			map->map_class->map_cname == NULL ? "NULL" :
49638032Speter				map->map_class->map_cname,
49738032Speter			map->map_mname == NULL ? "NULL" : map->map_mname,
49864562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
49938032Speter
50064562Sgshapiro	if (!bitset(MF_ALIAS, map->map_mflags) ||
50164562Sgshapiro	    !bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
50238032Speter	{
50338032Speter		if (tTd(38, 3))
50490792Sgshapiro			sm_dprintf("\tnot rebuildable\n");
50538032Speter		return;
50638032Speter	}
50738032Speter
50838032Speter	/* if already open, close it (for nested open) */
50938032Speter	if (bitset(MF_OPEN, map->map_mflags))
51038032Speter	{
51177349Sgshapiro		map->map_mflags |= MF_CLOSING;
51238032Speter		map->map_class->map_close(map);
51377349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
51438032Speter	}
51538032Speter
51690792Sgshapiro	(void) rebuildaliases(map, false);
51764562Sgshapiro	return;
51864562Sgshapiro}
51990792Sgshapiro/*
52064562Sgshapiro**  OPENMAP -- open a map
52164562Sgshapiro**
52264562Sgshapiro**	Parameters:
52364562Sgshapiro**		map -- map to open (it must not be open).
52464562Sgshapiro**
52564562Sgshapiro**	Returns:
52664562Sgshapiro**		whether open succeeded.
52764562Sgshapiro*/
52864562Sgshapiro
52964562Sgshapirobool
53064562Sgshapiroopenmap(map)
53164562Sgshapiro	MAP *map;
53264562Sgshapiro{
53390792Sgshapiro	bool restore = false;
53464562Sgshapiro	bool savehold = HoldErrs;
53564562Sgshapiro	bool savequick = QuickAbort;
53664562Sgshapiro	int saveerrors = Errors;
53764562Sgshapiro
53864562Sgshapiro	if (!bitset(MF_VALID, map->map_mflags))
53990792Sgshapiro		return false;
54064562Sgshapiro
54164562Sgshapiro	/* better safe than sorry... */
54264562Sgshapiro	if (bitset(MF_OPEN, map->map_mflags))
54390792Sgshapiro		return true;
54464562Sgshapiro
54564562Sgshapiro	/* Don't send a map open error out via SMTP */
54664562Sgshapiro	if ((OnlyOneError || QuickAbort) &&
54764562Sgshapiro	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))
54838032Speter	{
54990792Sgshapiro		restore = true;
55090792Sgshapiro		HoldErrs = true;
55190792Sgshapiro		QuickAbort = false;
55238032Speter	}
55338032Speter
55464562Sgshapiro	errno = 0;
55538032Speter	if (map->map_class->map_open(map, O_RDONLY))
55638032Speter	{
55738032Speter		if (tTd(38, 4))
55890792Sgshapiro			sm_dprintf("openmap()\t%s:%s %s: valid\n",
55938032Speter				map->map_class->map_cname == NULL ? "NULL" :
56038032Speter					map->map_class->map_cname,
56138032Speter				map->map_mname == NULL ? "NULL" :
56238032Speter					map->map_mname,
56338032Speter				map->map_file == NULL ? "NULL" :
56438032Speter					map->map_file);
56538032Speter		map->map_mflags |= MF_OPEN;
56690792Sgshapiro		map->map_pid = CurrentPid;
56738032Speter	}
56838032Speter	else
56938032Speter	{
57038032Speter		if (tTd(38, 4))
57190792Sgshapiro			sm_dprintf("openmap()\t%s:%s %s: invalid%s%s\n",
57238032Speter				map->map_class->map_cname == NULL ? "NULL" :
57338032Speter					map->map_class->map_cname,
57438032Speter				map->map_mname == NULL ? "NULL" :
57538032Speter					map->map_mname,
57638032Speter				map->map_file == NULL ? "NULL" :
57738032Speter					map->map_file,
57864562Sgshapiro				errno == 0 ? "" : ": ",
57990792Sgshapiro				errno == 0 ? "" : sm_errstring(errno));
58038032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
58138032Speter		{
58238032Speter			extern MAPCLASS BogusMapClass;
58338032Speter
58490792Sgshapiro			map->map_orgclass = map->map_class;
58538032Speter			map->map_class = &BogusMapClass;
58690792Sgshapiro			map->map_mflags |= MF_OPEN|MF_OPENBOGUS;
58790792Sgshapiro			map->map_pid = CurrentPid;
58838032Speter		}
58964562Sgshapiro		else
59064562Sgshapiro		{
59164562Sgshapiro			/* don't try again */
59264562Sgshapiro			map->map_mflags &= ~MF_VALID;
59364562Sgshapiro		}
59438032Speter	}
59564562Sgshapiro
59664562Sgshapiro	if (restore)
59764562Sgshapiro	{
59864562Sgshapiro		Errors = saveerrors;
59964562Sgshapiro		HoldErrs = savehold;
60064562Sgshapiro		QuickAbort = savequick;
60164562Sgshapiro	}
60264562Sgshapiro
60364562Sgshapiro	return bitset(MF_OPEN, map->map_mflags);
60438032Speter}
60590792Sgshapiro/*
60642575Speter**  CLOSEMAPS -- close all open maps opened by the current pid.
60742575Speter**
60842575Speter**	Parameters:
60990792Sgshapiro**		bogus -- only close bogus maps.
61042575Speter**
61142575Speter**	Returns:
61242575Speter**		none.
61342575Speter*/
61442575Speter
61542575Spetervoid
61690792Sgshapiroclosemaps(bogus)
61790792Sgshapiro	bool bogus;
61842575Speter{
61990792Sgshapiro	stabapply(map_close, bogus);
62042575Speter}
62190792Sgshapiro/*
62264562Sgshapiro**  MAP_CLOSE -- close a map opened by the current pid.
62364562Sgshapiro**
62464562Sgshapiro**	Parameters:
62590792Sgshapiro**		s -- STAB entry: if map: try to close
62690792Sgshapiro**		bogus -- only close bogus maps or MCF_NOTPERSIST maps.
62764562Sgshapiro**
62864562Sgshapiro**	Returns:
62964562Sgshapiro**		none.
63064562Sgshapiro*/
63142575Speter
63242575Speter/* ARGSUSED1 */
63364562Sgshapirostatic void
63490792Sgshapiromap_close(s, bogus)
63542575Speter	register STAB *s;
63690792Sgshapiro	int bogus;	/* int because of stabapply(), used as bool */
63742575Speter{
63842575Speter	MAP *map;
63990792Sgshapiro	extern MAPCLASS BogusMapClass;
64042575Speter
64190792Sgshapiro	if (s->s_symtype != ST_MAP)
64242575Speter		return;
64364562Sgshapiro
64442575Speter	map = &s->s_map;
64542575Speter
64690792Sgshapiro	/*
64790792Sgshapiro	**  close the map iff:
64890792Sgshapiro	**  it is valid and open and opened by this process
64990792Sgshapiro	**  and (!bogus or it's a bogus map or it is not persistent)
65090792Sgshapiro	**  negate this: return iff
65190792Sgshapiro	**  it is not valid or it is not open or not opened by this process
65290792Sgshapiro	**  or (bogus and it's not a bogus map and it's not not-persistent)
65390792Sgshapiro	*/
65490792Sgshapiro
65542575Speter	if (!bitset(MF_VALID, map->map_mflags) ||
65642575Speter	    !bitset(MF_OPEN, map->map_mflags) ||
65777349Sgshapiro	    bitset(MF_CLOSING, map->map_mflags) ||
65890792Sgshapiro	    map->map_pid != CurrentPid ||
65990792Sgshapiro	    (bogus && map->map_class != &BogusMapClass &&
66090792Sgshapiro	     !bitset(MCF_NOTPERSIST, map->map_class->map_cflags)))
66142575Speter		return;
66264562Sgshapiro
66390792Sgshapiro	if (map->map_class == &BogusMapClass && map->map_orgclass != NULL &&
66490792Sgshapiro	    map->map_orgclass != &BogusMapClass)
66590792Sgshapiro		map->map_class = map->map_orgclass;
66642575Speter	if (tTd(38, 5))
66790792Sgshapiro		sm_dprintf("closemaps: closing %s (%s)\n",
66864562Sgshapiro			map->map_mname == NULL ? "NULL" : map->map_mname,
66964562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
67064562Sgshapiro
67190792Sgshapiro	if (!bitset(MF_OPENBOGUS, map->map_mflags))
67290792Sgshapiro	{
67390792Sgshapiro		map->map_mflags |= MF_CLOSING;
67490792Sgshapiro		map->map_class->map_close(map);
67590792Sgshapiro	}
67690792Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_OPENBOGUS|MF_CLOSING);
67742575Speter}
678168515Sgshapiro
679168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
680168515Sgshapiroextern int getdomainname();
681168515Sgshapiro
682168515Sgshapiro/* this is mainly for backward compatibility in Sun environment */
683168515Sgshapirostatic char *
684168515Sgshapirosun_init_domain()
685168515Sgshapiro{
686168515Sgshapiro	/*
687168515Sgshapiro	**  Get the domain name from the kernel.
688168515Sgshapiro	**  If it does not start with a leading dot, then remove
689168515Sgshapiro	**  the first component.  Since leading dots are funny Unix
690168515Sgshapiro	**  files, we treat a leading "+" the same as a leading dot.
691168515Sgshapiro	**  Finally, force there to be at least one dot in the domain name
692168515Sgshapiro	**  (i.e. top-level domains are not allowed, like "com", must be
693168515Sgshapiro	**  something like "sun.com").
694168515Sgshapiro	*/
695168515Sgshapiro
696168515Sgshapiro	char buf[MAXNAME];
697168515Sgshapiro	char *period, *autodomain;
698168515Sgshapiro
699168515Sgshapiro	if (getdomainname(buf, sizeof buf) < 0)
700168515Sgshapiro		return NULL;
701168515Sgshapiro
702168515Sgshapiro	if (buf[0] == '\0')
703168515Sgshapiro		return NULL;
704168515Sgshapiro
705168515Sgshapiro	if (tTd(0, 20))
706168515Sgshapiro		printf("domainname = %s\n", buf);
707168515Sgshapiro
708168515Sgshapiro	if (buf[0] == '+')
709168515Sgshapiro		buf[0] = '.';
710168515Sgshapiro	period = strchr(buf, '.');
711168515Sgshapiro	if (period == NULL)
712168515Sgshapiro		autodomain = buf;
713168515Sgshapiro	else
714168515Sgshapiro		autodomain = period + 1;
715168515Sgshapiro	if (strchr(autodomain, '.') == NULL)
716168515Sgshapiro		return newstr(buf);
717168515Sgshapiro	else
718168515Sgshapiro		return newstr(autodomain);
719168515Sgshapiro}
720168515Sgshapiro#endif /* SUN_EXTENSIONS && SUN_INIT_DOMAIN */
721168515Sgshapiro
72290792Sgshapiro/*
72338032Speter**  GETCANONNAME -- look up name using service switch
72438032Speter**
72538032Speter**	Parameters:
72638032Speter**		host -- the host name to look up.
72738032Speter**		hbsize -- the size of the host buffer.
72838032Speter**		trymx -- if set, try MX records.
72990792Sgshapiro**		pttl -- pointer to return TTL (can be NULL).
73038032Speter**
73138032Speter**	Returns:
73290792Sgshapiro**		true -- if the host was found.
73390792Sgshapiro**		false -- otherwise.
73438032Speter*/
73538032Speter
73638032Speterbool
73790792Sgshapirogetcanonname(host, hbsize, trymx, pttl)
73838032Speter	char *host;
73938032Speter	int hbsize;
74038032Speter	bool trymx;
74190792Sgshapiro	int *pttl;
74238032Speter{
74338032Speter	int nmaps;
74438032Speter	int mapno;
74590792Sgshapiro	bool found = false;
74690792Sgshapiro	bool got_tempfail = false;
747203004Sgshapiro	auto int status = EX_UNAVAILABLE;
74838032Speter	char *maptype[MAXMAPSTACK];
74938032Speter	short mapreturn[MAXMAPACTIONS];
750168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
751168515Sgshapiro	bool should_try_nis_domain = false;
752168515Sgshapiro	static char *nis_domain = NULL;
753168515Sgshapiro#endif
75438032Speter
75538032Speter	nmaps = switch_map_find("hosts", maptype, mapreturn);
75690792Sgshapiro	if (pttl != 0)
75790792Sgshapiro		*pttl = SM_DEFAULT_TTL;
75838032Speter	for (mapno = 0; mapno < nmaps; mapno++)
75938032Speter	{
76038032Speter		int i;
76138032Speter
76238032Speter		if (tTd(38, 20))
76390792Sgshapiro			sm_dprintf("getcanonname(%s), trying %s\n",
76438032Speter				host, maptype[mapno]);
76538032Speter		if (strcmp("files", maptype[mapno]) == 0)
76638032Speter		{
76764562Sgshapiro			found = text_getcanonname(host, hbsize, &status);
76838032Speter		}
76990792Sgshapiro#if NIS
77038032Speter		else if (strcmp("nis", maptype[mapno]) == 0)
77138032Speter		{
77264562Sgshapiro			found = nis_getcanonname(host, hbsize, &status);
773168515Sgshapiro# if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
774168515Sgshapiro			if (nis_domain == NULL)
775168515Sgshapiro				nis_domain = sun_init_domain();
776168515Sgshapiro# endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
77738032Speter		}
77864562Sgshapiro#endif /* NIS */
77990792Sgshapiro#if NISPLUS
78038032Speter		else if (strcmp("nisplus", maptype[mapno]) == 0)
78138032Speter		{
78264562Sgshapiro			found = nisplus_getcanonname(host, hbsize, &status);
783168515Sgshapiro# if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
784168515Sgshapiro			if (nis_domain == NULL)
785168515Sgshapiro				nis_domain = sun_init_domain();
786168515Sgshapiro# endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
78738032Speter		}
78864562Sgshapiro#endif /* NISPLUS */
78938032Speter#if NAMED_BIND
79038032Speter		else if (strcmp("dns", maptype[mapno]) == 0)
79138032Speter		{
79290792Sgshapiro			found = dns_getcanonname(host, hbsize, trymx, &status,							 pttl);
79338032Speter		}
79464562Sgshapiro#endif /* NAMED_BIND */
79538032Speter#if NETINFO
79638032Speter		else if (strcmp("netinfo", maptype[mapno]) == 0)
79738032Speter		{
79864562Sgshapiro			found = ni_getcanonname(host, hbsize, &status);
79938032Speter		}
80064562Sgshapiro#endif /* NETINFO */
80138032Speter		else
80238032Speter		{
80390792Sgshapiro			found = false;
80464562Sgshapiro			status = EX_UNAVAILABLE;
80538032Speter		}
80638032Speter
80738032Speter		/*
80838032Speter		**  Heuristic: if $m is not set, we are running during system
80938032Speter		**  startup.  In this case, when a name is apparently found
81038032Speter		**  but has no dot, treat is as not found.  This avoids
81138032Speter		**  problems if /etc/hosts has no FQDN but is listed first
81238032Speter		**  in the service switch.
81338032Speter		*/
81438032Speter
81538032Speter		if (found &&
81638032Speter		    (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
81738032Speter			break;
81838032Speter
819168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
820168515Sgshapiro		if (found)
821168515Sgshapiro			should_try_nis_domain = true;
822168515Sgshapiro		/* but don't break, as we need to try all methods first */
823168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
824168515Sgshapiro
82538032Speter		/* see if we should continue */
82664562Sgshapiro		if (status == EX_TEMPFAIL)
82738032Speter		{
82838032Speter			i = MA_TRYAGAIN;
82990792Sgshapiro			got_tempfail = true;
83038032Speter		}
83164562Sgshapiro		else if (status == EX_NOTFOUND)
83238032Speter			i = MA_NOTFOUND;
83338032Speter		else
83438032Speter			i = MA_UNAVAIL;
83538032Speter		if (bitset(1 << mapno, mapreturn[i]))
83638032Speter			break;
83738032Speter	}
83838032Speter
83938032Speter	if (found)
84038032Speter	{
84138032Speter		char *d;
84238032Speter
84338032Speter		if (tTd(38, 20))
84490792Sgshapiro			sm_dprintf("getcanonname(%s), found\n", host);
84538032Speter
84638032Speter		/*
84738032Speter		**  If returned name is still single token, compensate
84838032Speter		**  by tagging on $m.  This is because some sites set
84938032Speter		**  up their DNS or NIS databases wrong.
85038032Speter		*/
85138032Speter
85238032Speter		if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
85338032Speter		{
85438032Speter			d = macvalue('m', CurEnv);
85538032Speter			if (d != NULL &&
85638032Speter			    hbsize > (int) (strlen(host) + strlen(d) + 1))
85738032Speter			{
85838032Speter				if (host[strlen(host) - 1] != '.')
85990792Sgshapiro					(void) sm_strlcat2(host, ".", d,
86090792Sgshapiro							   hbsize);
86190792Sgshapiro				else
86290792Sgshapiro					(void) sm_strlcat(host, d, hbsize);
86338032Speter			}
86438032Speter			else
865168515Sgshapiro			{
866168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
867168515Sgshapiro				if (VendorCode == VENDOR_SUN &&
868168515Sgshapiro				    should_try_nis_domain)
869168515Sgshapiro				{
870168515Sgshapiro					goto try_nis_domain;
871168515Sgshapiro				}
872168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
87390792Sgshapiro				return false;
874168515Sgshapiro			}
87538032Speter		}
87690792Sgshapiro		return true;
87738032Speter	}
87838032Speter
879168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
880168515Sgshapiro	if (VendorCode == VENDOR_SUN && should_try_nis_domain)
881168515Sgshapiro	{
882168515Sgshapiro  try_nis_domain:
883168515Sgshapiro		if (nis_domain != NULL &&
884168515Sgshapiro		    strlen(nis_domain) + strlen(host) + 1 < hbsize)
885168515Sgshapiro		{
886168515Sgshapiro			(void) sm_strlcat2(host, ".", nis_domain, hbsize);
887168515Sgshapiro			return true;
888168515Sgshapiro		}
889168515Sgshapiro	}
890168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
891168515Sgshapiro
89238032Speter	if (tTd(38, 20))
89390792Sgshapiro		sm_dprintf("getcanonname(%s), failed, status=%d\n", host,
89490792Sgshapiro			status);
89538032Speter
89638032Speter	if (got_tempfail)
89773188Sgshapiro		SM_SET_H_ERRNO(TRY_AGAIN);
89838032Speter	else
89973188Sgshapiro		SM_SET_H_ERRNO(HOST_NOT_FOUND);
90090792Sgshapiro
90190792Sgshapiro	return false;
90238032Speter}
90390792Sgshapiro/*
90438032Speter**  EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
90538032Speter**
90638032Speter**	Parameters:
90738032Speter**		name -- the name against which to match.
90873188Sgshapiro**		dot -- where to reinsert '.' to get FQDN
90938032Speter**		line -- the /etc/hosts line.
91038032Speter**		cbuf -- the location to store the result.
91138032Speter**		cbuflen -- the size of cbuf.
91238032Speter**
91338032Speter**	Returns:
91490792Sgshapiro**		true -- if the line matched the desired name.
91590792Sgshapiro**		false -- otherwise.
91638032Speter*/
91738032Speter
91864562Sgshapirostatic bool
91973188Sgshapiroextract_canonname(name, dot, line, cbuf, cbuflen)
92038032Speter	char *name;
92173188Sgshapiro	char *dot;
92238032Speter	char *line;
92338032Speter	char cbuf[];
92438032Speter	int cbuflen;
92538032Speter{
92638032Speter	int i;
92738032Speter	char *p;
92890792Sgshapiro	bool found = false;
92938032Speter
93038032Speter	cbuf[0] = '\0';
93138032Speter	if (line[0] == '#')
93290792Sgshapiro		return false;
93338032Speter
93438032Speter	for (i = 1; ; i++)
93538032Speter	{
93638032Speter		char nbuf[MAXNAME + 1];
93738032Speter
938168515Sgshapiro		p = get_column(line, i, '\0', nbuf, sizeof(nbuf));
93938032Speter		if (p == NULL)
94038032Speter			break;
94138032Speter		if (*p == '\0')
94238032Speter			continue;
94338032Speter		if (cbuf[0] == '\0' ||
94438032Speter		    (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
94538032Speter		{
94690792Sgshapiro			(void) sm_strlcpy(cbuf, p, cbuflen);
94738032Speter		}
94890792Sgshapiro		if (sm_strcasecmp(name, p) == 0)
94990792Sgshapiro			found = true;
95073188Sgshapiro		else if (dot != NULL)
95173188Sgshapiro		{
95273188Sgshapiro			/* try looking for the FQDN as well */
95373188Sgshapiro			*dot = '.';
95490792Sgshapiro			if (sm_strcasecmp(name, p) == 0)
95590792Sgshapiro				found = true;
95673188Sgshapiro			*dot = '\0';
95773188Sgshapiro		}
95838032Speter	}
95938032Speter	if (found && strchr(cbuf, '.') == NULL)
96038032Speter	{
96138032Speter		/* try to add a domain on the end of the name */
96238032Speter		char *domain = macvalue('m', CurEnv);
96338032Speter
96438032Speter		if (domain != NULL &&
96564562Sgshapiro		    strlen(domain) + (i = strlen(cbuf)) + 1 < (size_t) cbuflen)
96638032Speter		{
96764562Sgshapiro			p = &cbuf[i];
96838032Speter			*p++ = '.';
96990792Sgshapiro			(void) sm_strlcpy(p, domain, cbuflen - i - 1);
97038032Speter		}
97138032Speter	}
97238032Speter	return found;
97338032Speter}
97490792Sgshapiro
97590792Sgshapiro/*
97690792Sgshapiro**  DNS modules
97790792Sgshapiro*/
97890792Sgshapiro
97990792Sgshapiro#if NAMED_BIND
98090792Sgshapiro# if DNSMAP
98190792Sgshapiro
98290792Sgshapiro#  include "sm_resolve.h"
98390792Sgshapiro#  if NETINET || NETINET6
98490792Sgshapiro#   include <arpa/inet.h>
98590792Sgshapiro#  endif /* NETINET || NETINET6 */
98690792Sgshapiro
98790792Sgshapiro/*
98890792Sgshapiro**  DNS_MAP_OPEN -- stub to check proper value for dns map type
98990792Sgshapiro*/
99090792Sgshapiro
99190792Sgshapirobool
99290792Sgshapirodns_map_open(map, mode)
99390792Sgshapiro	MAP *map;
99490792Sgshapiro	int mode;
99590792Sgshapiro{
99690792Sgshapiro	if (tTd(38,2))
99790792Sgshapiro		sm_dprintf("dns_map_open(%s, %d)\n", map->map_mname, mode);
99890792Sgshapiro
99990792Sgshapiro	mode &= O_ACCMODE;
100090792Sgshapiro	if (mode != O_RDONLY)
100190792Sgshapiro	{
100290792Sgshapiro		/* issue a pseudo-error message */
100390792Sgshapiro		errno = SM_EMAPCANTWRITE;
100490792Sgshapiro		return false;
100590792Sgshapiro	}
100690792Sgshapiro	return true;
100790792Sgshapiro}
100890792Sgshapiro
100990792Sgshapiro/*
101090792Sgshapiro**  DNS_MAP_PARSEARGS -- parse dns map definition args.
101190792Sgshapiro**
101290792Sgshapiro**	Parameters:
101390792Sgshapiro**		map -- pointer to MAP
101490792Sgshapiro**		args -- pointer to the args on the config line.
101590792Sgshapiro**
101690792Sgshapiro**	Returns:
101790792Sgshapiro**		true -- if everything parsed OK.
101890792Sgshapiro**		false -- otherwise.
101990792Sgshapiro*/
102090792Sgshapiro
1021168515Sgshapiro#define map_sizelimit	map_lockfd	/* overload field */
102290792Sgshapiro
102390792Sgshapirostruct dns_map
102490792Sgshapiro{
102590792Sgshapiro	int dns_m_type;
102690792Sgshapiro};
102790792Sgshapiro
102890792Sgshapirobool
102990792Sgshapirodns_map_parseargs(map,args)
103090792Sgshapiro	MAP *map;
103190792Sgshapiro	char *args;
103290792Sgshapiro{
103390792Sgshapiro	register char *p = args;
103490792Sgshapiro	struct dns_map *map_p;
103590792Sgshapiro
1036168515Sgshapiro	map_p = (struct dns_map *) xalloc(sizeof(*map_p));
103790792Sgshapiro	map_p->dns_m_type = -1;
103890792Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
103990792Sgshapiro
104090792Sgshapiro	for (;;)
104190792Sgshapiro	{
104290792Sgshapiro		while (isascii(*p) && isspace(*p))
104390792Sgshapiro			p++;
104490792Sgshapiro		if (*p != '-')
104590792Sgshapiro			break;
104690792Sgshapiro		switch (*++p)
104790792Sgshapiro		{
104890792Sgshapiro		  case 'N':
104990792Sgshapiro			map->map_mflags |= MF_INCLNULL;
105090792Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
105190792Sgshapiro			break;
105290792Sgshapiro
105390792Sgshapiro		  case 'O':
105490792Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
105590792Sgshapiro			break;
105690792Sgshapiro
105790792Sgshapiro		  case 'o':
105890792Sgshapiro			map->map_mflags |= MF_OPTIONAL;
105990792Sgshapiro			break;
106090792Sgshapiro
106190792Sgshapiro		  case 'f':
106290792Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
106390792Sgshapiro			break;
106490792Sgshapiro
106590792Sgshapiro		  case 'm':
106690792Sgshapiro			map->map_mflags |= MF_MATCHONLY;
106790792Sgshapiro			break;
106890792Sgshapiro
106990792Sgshapiro		  case 'A':
107090792Sgshapiro			map->map_mflags |= MF_APPEND;
107190792Sgshapiro			break;
107290792Sgshapiro
107390792Sgshapiro		  case 'q':
107490792Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
107590792Sgshapiro			break;
107690792Sgshapiro
107790792Sgshapiro		  case 't':
107890792Sgshapiro			map->map_mflags |= MF_NODEFER;
107990792Sgshapiro			break;
108090792Sgshapiro
108190792Sgshapiro		  case 'a':
108290792Sgshapiro			map->map_app = ++p;
108390792Sgshapiro			break;
108490792Sgshapiro
108590792Sgshapiro		  case 'T':
108690792Sgshapiro			map->map_tapp = ++p;
108790792Sgshapiro			break;
108890792Sgshapiro
108990792Sgshapiro		  case 'd':
109090792Sgshapiro			{
109190792Sgshapiro				char *h;
109290792Sgshapiro
109390792Sgshapiro				++p;
109490792Sgshapiro				h = strchr(p, ' ');
109590792Sgshapiro				if (h != NULL)
109690792Sgshapiro					*h = '\0';
109790792Sgshapiro				map->map_timeout = convtime(p, 's');
109890792Sgshapiro				if (h != NULL)
109990792Sgshapiro					*h = ' ';
110090792Sgshapiro			}
110190792Sgshapiro			break;
110290792Sgshapiro
110390792Sgshapiro		  case 'r':
110490792Sgshapiro			while (isascii(*++p) && isspace(*p))
110590792Sgshapiro				continue;
110690792Sgshapiro			map->map_retry = atoi(p);
110790792Sgshapiro			break;
110890792Sgshapiro
110990792Sgshapiro		  case 'z':
111090792Sgshapiro			if (*++p != '\\')
111190792Sgshapiro				map->map_coldelim = *p;
111290792Sgshapiro			else
111390792Sgshapiro			{
111490792Sgshapiro				switch (*++p)
111590792Sgshapiro				{
111690792Sgshapiro				  case 'n':
111790792Sgshapiro					map->map_coldelim = '\n';
111890792Sgshapiro					break;
111990792Sgshapiro
112090792Sgshapiro				  case 't':
112190792Sgshapiro					map->map_coldelim = '\t';
112290792Sgshapiro					break;
112390792Sgshapiro
112490792Sgshapiro				  default:
112590792Sgshapiro					map->map_coldelim = '\\';
112690792Sgshapiro				}
112790792Sgshapiro			}
112890792Sgshapiro			break;
112990792Sgshapiro
113090792Sgshapiro		  case 'Z':
113190792Sgshapiro			while (isascii(*++p) && isspace(*p))
113290792Sgshapiro				continue;
113390792Sgshapiro			map->map_sizelimit = atoi(p);
113490792Sgshapiro			break;
113590792Sgshapiro
113690792Sgshapiro			/* Start of dns_map specific args */
113790792Sgshapiro		  case 'R':		/* search field */
113890792Sgshapiro			{
113990792Sgshapiro				char *h;
114090792Sgshapiro
114190792Sgshapiro				while (isascii(*++p) && isspace(*p))
114290792Sgshapiro					continue;
114390792Sgshapiro				h = strchr(p, ' ');
114490792Sgshapiro				if (h != NULL)
114590792Sgshapiro					*h = '\0';
114690792Sgshapiro				map_p->dns_m_type = dns_string_to_type(p);
114790792Sgshapiro				if (h != NULL)
114890792Sgshapiro					*h = ' ';
114990792Sgshapiro				if (map_p->dns_m_type < 0)
115090792Sgshapiro					syserr("dns map %s: wrong type %s",
115190792Sgshapiro						map->map_mname, p);
115290792Sgshapiro			}
115390792Sgshapiro			break;
115490792Sgshapiro
115590792Sgshapiro		  case 'B':		/* base domain */
115690792Sgshapiro			{
115790792Sgshapiro				char *h;
115890792Sgshapiro
115990792Sgshapiro				while (isascii(*++p) && isspace(*p))
116090792Sgshapiro					continue;
116190792Sgshapiro				h = strchr(p, ' ');
116290792Sgshapiro				if (h != NULL)
116390792Sgshapiro					*h = '\0';
116490792Sgshapiro
116590792Sgshapiro				/*
116690792Sgshapiro				**  slight abuse of map->map_file; it isn't
116790792Sgshapiro				**	used otherwise in this map type.
116890792Sgshapiro				*/
116990792Sgshapiro
117090792Sgshapiro				map->map_file = newstr(p);
117190792Sgshapiro				if (h != NULL)
117290792Sgshapiro					*h = ' ';
117390792Sgshapiro			}
117490792Sgshapiro			break;
117590792Sgshapiro		}
117690792Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
117790792Sgshapiro			p++;
117890792Sgshapiro		if (*p != '\0')
117990792Sgshapiro			*p++ = '\0';
118090792Sgshapiro	}
118190792Sgshapiro	if (map_p->dns_m_type < 0)
118290792Sgshapiro		syserr("dns map %s: missing -R type", map->map_mname);
118390792Sgshapiro	if (map->map_app != NULL)
118490792Sgshapiro		map->map_app = newstr(map->map_app);
118590792Sgshapiro	if (map->map_tapp != NULL)
118690792Sgshapiro		map->map_tapp = newstr(map->map_tapp);
118790792Sgshapiro
118890792Sgshapiro	/*
1189168515Sgshapiro	**  Assumption: assert(sizeof(int) <= sizeof(ARBPTR_T));
119090792Sgshapiro	**  Even if this assumption is wrong, we use only one byte,
119190792Sgshapiro	**  so it doesn't really matter.
119290792Sgshapiro	*/
119390792Sgshapiro
119490792Sgshapiro	map->map_db1 = (ARBPTR_T) map_p;
119590792Sgshapiro	return true;
119690792Sgshapiro}
119790792Sgshapiro
119890792Sgshapiro/*
119990792Sgshapiro**  DNS_MAP_LOOKUP -- perform dns map lookup.
120090792Sgshapiro**
120190792Sgshapiro**	Parameters:
120290792Sgshapiro**		map -- pointer to MAP
120390792Sgshapiro**		name -- name to lookup
120490792Sgshapiro**		av -- arguments to interpolate into buf.
120590792Sgshapiro**		statp -- pointer to status (EX_)
120690792Sgshapiro**
120790792Sgshapiro**	Returns:
120890792Sgshapiro**		result of lookup if succeeded.
120990792Sgshapiro**		NULL -- otherwise.
121090792Sgshapiro*/
121190792Sgshapiro
121290792Sgshapirochar *
121390792Sgshapirodns_map_lookup(map, name, av, statp)
121490792Sgshapiro	MAP *map;
121590792Sgshapiro	char *name;
121690792Sgshapiro	char **av;
121790792Sgshapiro	int *statp;
121890792Sgshapiro{
121990792Sgshapiro	int resnum = 0;
122090792Sgshapiro	char *vp = NULL, *result = NULL;
122190792Sgshapiro	size_t vsize;
122290792Sgshapiro	struct dns_map *map_p;
122390792Sgshapiro	RESOURCE_RECORD_T *rr = NULL;
122490792Sgshapiro	DNS_REPLY_T *r = NULL;
122590792Sgshapiro#  if NETINET6
122690792Sgshapiro	static char buf6[INET6_ADDRSTRLEN];
122790792Sgshapiro#  endif /* NETINET6 */
122890792Sgshapiro
122990792Sgshapiro	if (tTd(38, 20))
123090792Sgshapiro		sm_dprintf("dns_map_lookup(%s, %s)\n",
123190792Sgshapiro			   map->map_mname, name);
123290792Sgshapiro
123390792Sgshapiro	map_p = (struct dns_map *)(map->map_db1);
123490792Sgshapiro	if (map->map_file != NULL && *map->map_file != '\0')
123590792Sgshapiro	{
123690792Sgshapiro		size_t len;
123790792Sgshapiro		char *appdomain;
123890792Sgshapiro
123990792Sgshapiro		len = strlen(map->map_file) + strlen(name) + 2;
124090792Sgshapiro		appdomain = (char *) sm_malloc(len);
124190792Sgshapiro		if (appdomain == NULL)
124290792Sgshapiro		{
124390792Sgshapiro			*statp = EX_UNAVAILABLE;
124490792Sgshapiro			return NULL;
124590792Sgshapiro		}
124690792Sgshapiro		(void) sm_strlcpyn(appdomain, len, 3, name, ".", map->map_file);
124790792Sgshapiro		r = dns_lookup_int(appdomain, C_IN, map_p->dns_m_type,
124890792Sgshapiro				   map->map_timeout, map->map_retry);
124990792Sgshapiro		sm_free(appdomain);
125090792Sgshapiro	}
125190792Sgshapiro	else
125290792Sgshapiro	{
125390792Sgshapiro		r = dns_lookup_int(name, C_IN, map_p->dns_m_type,
125490792Sgshapiro				   map->map_timeout, map->map_retry);
125590792Sgshapiro	}
125690792Sgshapiro
125790792Sgshapiro	if (r == NULL)
125890792Sgshapiro	{
125990792Sgshapiro		result = NULL;
1260120256Sgshapiro		if (h_errno == TRY_AGAIN || transienterror(errno))
126190792Sgshapiro			*statp = EX_TEMPFAIL;
126290792Sgshapiro		else
126390792Sgshapiro			*statp = EX_NOTFOUND;
126490792Sgshapiro		goto cleanup;
126590792Sgshapiro	}
126690792Sgshapiro	*statp = EX_OK;
126790792Sgshapiro	for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next)
126890792Sgshapiro	{
126990792Sgshapiro		char *type = NULL;
127090792Sgshapiro		char *value = NULL;
127190792Sgshapiro
127290792Sgshapiro		switch (rr->rr_type)
127390792Sgshapiro		{
127490792Sgshapiro		  case T_NS:
127590792Sgshapiro			type = "T_NS";
127690792Sgshapiro			value = rr->rr_u.rr_txt;
127790792Sgshapiro			break;
127890792Sgshapiro		  case T_CNAME:
127990792Sgshapiro			type = "T_CNAME";
128090792Sgshapiro			value = rr->rr_u.rr_txt;
128190792Sgshapiro			break;
128290792Sgshapiro		  case T_AFSDB:
128390792Sgshapiro			type = "T_AFSDB";
128490792Sgshapiro			value = rr->rr_u.rr_mx->mx_r_domain;
128590792Sgshapiro			break;
128690792Sgshapiro		  case T_SRV:
128790792Sgshapiro			type = "T_SRV";
128890792Sgshapiro			value = rr->rr_u.rr_srv->srv_r_target;
128990792Sgshapiro			break;
129090792Sgshapiro		  case T_PTR:
129190792Sgshapiro			type = "T_PTR";
129290792Sgshapiro			value = rr->rr_u.rr_txt;
129390792Sgshapiro			break;
129490792Sgshapiro		  case T_TXT:
129590792Sgshapiro			type = "T_TXT";
129690792Sgshapiro			value = rr->rr_u.rr_txt;
129790792Sgshapiro			break;
129890792Sgshapiro		  case T_MX:
129990792Sgshapiro			type = "T_MX";
130090792Sgshapiro			value = rr->rr_u.rr_mx->mx_r_domain;
130190792Sgshapiro			break;
130290792Sgshapiro#  if NETINET
130390792Sgshapiro		  case T_A:
130490792Sgshapiro			type = "T_A";
130590792Sgshapiro			value = inet_ntoa(*(rr->rr_u.rr_a));
130690792Sgshapiro			break;
130790792Sgshapiro#  endif /* NETINET */
130890792Sgshapiro#  if NETINET6
130990792Sgshapiro		  case T_AAAA:
131090792Sgshapiro			type = "T_AAAA";
131190792Sgshapiro			value = anynet_ntop(rr->rr_u.rr_aaaa, buf6,
1312168515Sgshapiro					    sizeof(buf6));
131390792Sgshapiro			break;
131490792Sgshapiro#  endif /* NETINET6 */
131590792Sgshapiro		}
131690792Sgshapiro
131798841Sgshapiro		(void) strreplnonprt(value, 'X');
131890792Sgshapiro		if (map_p->dns_m_type != rr->rr_type)
131990792Sgshapiro		{
132090792Sgshapiro			if (tTd(38, 40))
132190792Sgshapiro				sm_dprintf("\tskipping type %s (%d) value %s\n",
132290792Sgshapiro					   type != NULL ? type : "<UNKNOWN>",
132390792Sgshapiro					   rr->rr_type,
132490792Sgshapiro					   value != NULL ? value : "<NO VALUE>");
132590792Sgshapiro			continue;
132690792Sgshapiro		}
132790792Sgshapiro
132890792Sgshapiro#  if NETINET6
132990792Sgshapiro		if (rr->rr_type == T_AAAA && value == NULL)
133090792Sgshapiro		{
133190792Sgshapiro			result = NULL;
133290792Sgshapiro			*statp = EX_DATAERR;
133390792Sgshapiro			if (tTd(38, 40))
133490792Sgshapiro				sm_dprintf("\tbad T_AAAA conversion\n");
133590792Sgshapiro			goto cleanup;
133690792Sgshapiro		}
133790792Sgshapiro#  endif /* NETINET6 */
133890792Sgshapiro		if (tTd(38, 40))
133990792Sgshapiro			sm_dprintf("\tfound type %s (%d) value %s\n",
134090792Sgshapiro				   type != NULL ? type : "<UNKNOWN>",
134190792Sgshapiro				   rr->rr_type,
134290792Sgshapiro				   value != NULL ? value : "<NO VALUE>");
134390792Sgshapiro		if (value != NULL &&
134490792Sgshapiro		    (map->map_coldelim == '\0' ||
134590792Sgshapiro		     map->map_sizelimit == 1 ||
134690792Sgshapiro		     bitset(MF_MATCHONLY, map->map_mflags)))
134790792Sgshapiro		{
134890792Sgshapiro			/* Only care about the first match */
134990792Sgshapiro			vp = newstr(value);
135090792Sgshapiro			break;
135190792Sgshapiro		}
135290792Sgshapiro		else if (vp == NULL)
135390792Sgshapiro		{
135490792Sgshapiro			/* First result */
135590792Sgshapiro			vp = newstr(value);
135690792Sgshapiro		}
135790792Sgshapiro		else
135890792Sgshapiro		{
135990792Sgshapiro			/* concatenate the results */
136090792Sgshapiro			int sz;
136190792Sgshapiro			char *new;
136290792Sgshapiro
136390792Sgshapiro			sz = strlen(vp) + strlen(value) + 2;
136490792Sgshapiro			new = xalloc(sz);
136590792Sgshapiro			(void) sm_snprintf(new, sz, "%s%c%s",
136690792Sgshapiro					   vp, map->map_coldelim, value);
136790792Sgshapiro			sm_free(vp);
136890792Sgshapiro			vp = new;
136990792Sgshapiro			if (map->map_sizelimit > 0 &&
137090792Sgshapiro			    ++resnum >= map->map_sizelimit)
137190792Sgshapiro				break;
137290792Sgshapiro		}
137390792Sgshapiro	}
137490792Sgshapiro	if (vp == NULL)
137590792Sgshapiro	{
137690792Sgshapiro		result = NULL;
137790792Sgshapiro		*statp = EX_NOTFOUND;
137890792Sgshapiro		if (tTd(38, 40))
137990792Sgshapiro			sm_dprintf("\tno match found\n");
138090792Sgshapiro		goto cleanup;
138190792Sgshapiro	}
138290792Sgshapiro
138390792Sgshapiro	/* Cleanly truncate for rulesets */
138490792Sgshapiro	truncate_at_delim(vp, PSBUFSIZE / 2, map->map_coldelim);
138590792Sgshapiro
138690792Sgshapiro	vsize = strlen(vp);
138790792Sgshapiro
138890792Sgshapiro	if (LogLevel > 9)
138990792Sgshapiro		sm_syslog(LOG_INFO, CurEnv->e_id, "dns %.100s => %s",
139090792Sgshapiro			  name, vp);
139190792Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
139290792Sgshapiro		result = map_rewrite(map, name, strlen(name), NULL);
139390792Sgshapiro	else
139490792Sgshapiro		result = map_rewrite(map, vp, vsize, av);
139590792Sgshapiro
139690792Sgshapiro  cleanup:
139790792Sgshapiro	if (vp != NULL)
139890792Sgshapiro		sm_free(vp);
139990792Sgshapiro	if (r != NULL)
140090792Sgshapiro		dns_free_data(r);
140190792Sgshapiro	return result;
140290792Sgshapiro}
140390792Sgshapiro# endif /* DNSMAP */
140490792Sgshapiro#endif /* NAMED_BIND */
140590792Sgshapiro
140690792Sgshapiro/*
140738032Speter**  NDBM modules
140838032Speter*/
140938032Speter
141090792Sgshapiro#if NDBM
141138032Speter
141238032Speter/*
141338032Speter**  NDBM_MAP_OPEN -- DBM-style map open
141438032Speter*/
141538032Speter
141638032Speterbool
141738032Speterndbm_map_open(map, mode)
141838032Speter	MAP *map;
141938032Speter	int mode;
142038032Speter{
142138032Speter	register DBM *dbm;
142264562Sgshapiro	int save_errno;
142338032Speter	int dfd;
142438032Speter	int pfd;
142564562Sgshapiro	long sff;
142638032Speter	int ret;
142738032Speter	int smode = S_IREAD;
142898121Sgshapiro	char dirfile[MAXPATHLEN];
142998121Sgshapiro	char pagfile[MAXPATHLEN];
143064562Sgshapiro	struct stat st;
143138032Speter	struct stat std, stp;
143238032Speter
143338032Speter	if (tTd(38, 2))
143490792Sgshapiro		sm_dprintf("ndbm_map_open(%s, %s, %d)\n",
143538032Speter			map->map_mname, map->map_file, mode);
143638032Speter	map->map_lockfd = -1;
143738032Speter	mode &= O_ACCMODE;
143838032Speter
143938032Speter	/* do initial file and directory checks */
1440168515Sgshapiro	if (sm_strlcpyn(dirfile, sizeof(dirfile), 2,
1441168515Sgshapiro			map->map_file, ".dir") >= sizeof(dirfile) ||
1442168515Sgshapiro	    sm_strlcpyn(pagfile, sizeof(pagfile), 2,
1443168515Sgshapiro			map->map_file, ".pag") >= sizeof(pagfile))
144498121Sgshapiro	{
144598121Sgshapiro		errno = 0;
144698121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
144798121Sgshapiro			syserr("dbm map \"%s\": map file %s name too long",
144898121Sgshapiro				map->map_mname, map->map_file);
144998121Sgshapiro		return false;
145098121Sgshapiro	}
145138032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
145238032Speter	if (mode == O_RDWR)
145338032Speter	{
145438032Speter		sff |= SFF_CREAT;
145564562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
145638032Speter			sff |= SFF_NOSLINK;
145764562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
145838032Speter			sff |= SFF_NOHLINK;
145938032Speter		smode = S_IWRITE;
146038032Speter	}
146138032Speter	else
146238032Speter	{
146364562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
146438032Speter			sff |= SFF_NOWLINK;
146538032Speter	}
146664562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
146738032Speter		sff |= SFF_SAFEDIRPATH;
146838032Speter	ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
146990792Sgshapiro		       sff, smode, &std);
147038032Speter	if (ret == 0)
147138032Speter		ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
147238032Speter			       sff, smode, &stp);
147364562Sgshapiro
147438032Speter	if (ret != 0)
147538032Speter	{
147638032Speter		char *prob = "unsafe";
147738032Speter
147838032Speter		/* cannot open this map */
147938032Speter		if (ret == ENOENT)
148038032Speter			prob = "missing";
148138032Speter		if (tTd(38, 2))
148290792Sgshapiro			sm_dprintf("\t%s map file: %d\n", prob, ret);
148338032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
148438032Speter			syserr("dbm map \"%s\": %s map file %s",
148538032Speter				map->map_mname, prob, map->map_file);
148690792Sgshapiro		return false;
148738032Speter	}
148838032Speter	if (std.st_mode == ST_MODE_NOFILE)
148938032Speter		mode |= O_CREAT|O_EXCL;
149038032Speter
149164562Sgshapiro# if LOCK_ON_OPEN
149238032Speter	if (mode == O_RDONLY)
149338032Speter		mode |= O_SHLOCK;
149438032Speter	else
149538032Speter		mode |= O_TRUNC|O_EXLOCK;
149664562Sgshapiro# else /* LOCK_ON_OPEN */
149738032Speter	if ((mode & O_ACCMODE) == O_RDWR)
149838032Speter	{
149964562Sgshapiro#  if NOFTRUNCATE
150038032Speter		/*
150138032Speter		**  Warning: race condition.  Try to lock the file as
150238032Speter		**  quickly as possible after opening it.
150338032Speter		**	This may also have security problems on some systems,
150438032Speter		**	but there isn't anything we can do about it.
150538032Speter		*/
150638032Speter
150738032Speter		mode |= O_TRUNC;
150864562Sgshapiro#  else /* NOFTRUNCATE */
150938032Speter		/*
151038032Speter		**  This ugly code opens the map without truncating it,
151138032Speter		**  locks the file, then truncates it.  Necessary to
151238032Speter		**  avoid race conditions.
151338032Speter		*/
151438032Speter
151538032Speter		int dirfd;
151638032Speter		int pagfd;
151764562Sgshapiro		long sff = SFF_CREAT|SFF_OPENASROOT;
151838032Speter
151964562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
152038032Speter			sff |= SFF_NOSLINK;
152164562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
152238032Speter			sff |= SFF_NOHLINK;
152338032Speter
152438032Speter		dirfd = safeopen(dirfile, mode, DBMMODE, sff);
152538032Speter		pagfd = safeopen(pagfile, mode, DBMMODE, sff);
152638032Speter
152738032Speter		if (dirfd < 0 || pagfd < 0)
152838032Speter		{
152964562Sgshapiro			save_errno = errno;
153038032Speter			if (dirfd >= 0)
153138032Speter				(void) close(dirfd);
153238032Speter			if (pagfd >= 0)
153338032Speter				(void) close(pagfd);
153438032Speter			errno = save_errno;
153538032Speter			syserr("ndbm_map_open: cannot create database %s",
153638032Speter				map->map_file);
153790792Sgshapiro			return false;
153838032Speter		}
153938032Speter		if (ftruncate(dirfd, (off_t) 0) < 0 ||
154038032Speter		    ftruncate(pagfd, (off_t) 0) < 0)
154138032Speter		{
154264562Sgshapiro			save_errno = errno;
154338032Speter			(void) close(dirfd);
154438032Speter			(void) close(pagfd);
154538032Speter			errno = save_errno;
154638032Speter			syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
154738032Speter				map->map_file);
154890792Sgshapiro			return false;
154938032Speter		}
155038032Speter
155138032Speter		/* if new file, get "before" bits for later filechanged check */
155238032Speter		if (std.st_mode == ST_MODE_NOFILE &&
155338032Speter		    (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
155438032Speter		{
155564562Sgshapiro			save_errno = errno;
155638032Speter			(void) close(dirfd);
155738032Speter			(void) close(pagfd);
155838032Speter			errno = save_errno;
155938032Speter			syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
156038032Speter				map->map_file);
156190792Sgshapiro			return false;
156238032Speter		}
156338032Speter
156438032Speter		/* have to save the lock for the duration (bletch) */
156538032Speter		map->map_lockfd = dirfd;
156664562Sgshapiro		(void) close(pagfd);
156738032Speter
156838032Speter		/* twiddle bits for dbm_open */
156938032Speter		mode &= ~(O_CREAT|O_EXCL);
157064562Sgshapiro#  endif /* NOFTRUNCATE */
157138032Speter	}
157264562Sgshapiro# endif /* LOCK_ON_OPEN */
157338032Speter
157438032Speter	/* open the database */
157538032Speter	dbm = dbm_open(map->map_file, mode, DBMMODE);
157638032Speter	if (dbm == NULL)
157738032Speter	{
157864562Sgshapiro		save_errno = errno;
157938032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
158090792Sgshapiro		    aliaswait(map, ".pag", false))
158190792Sgshapiro			return true;
158264562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
158338032Speter		if (map->map_lockfd >= 0)
158464562Sgshapiro			(void) close(map->map_lockfd);
158564562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
158638032Speter		errno = save_errno;
158738032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
158838032Speter			syserr("Cannot open DBM database %s", map->map_file);
158990792Sgshapiro		return false;
159038032Speter	}
159138032Speter	dfd = dbm_dirfno(dbm);
159238032Speter	pfd = dbm_pagfno(dbm);
159338032Speter	if (dfd == pfd)
159438032Speter	{
159538032Speter		/* heuristic: if files are linked, this is actually gdbm */
159638032Speter		dbm_close(dbm);
159764562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
159838032Speter		if (map->map_lockfd >= 0)
159964562Sgshapiro			(void) close(map->map_lockfd);
160064562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
160138032Speter		errno = 0;
160238032Speter		syserr("dbm map \"%s\": cannot support GDBM",
160338032Speter			map->map_mname);
160490792Sgshapiro		return false;
160538032Speter	}
160638032Speter
160738032Speter	if (filechanged(dirfile, dfd, &std) ||
160838032Speter	    filechanged(pagfile, pfd, &stp))
160938032Speter	{
161064562Sgshapiro		save_errno = errno;
161138032Speter		dbm_close(dbm);
161264562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
161338032Speter		if (map->map_lockfd >= 0)
161464562Sgshapiro			(void) close(map->map_lockfd);
161564562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
161638032Speter		errno = save_errno;
161738032Speter		syserr("ndbm_map_open(%s): file changed after open",
161838032Speter			map->map_file);
161990792Sgshapiro		return false;
162038032Speter	}
162138032Speter
162238032Speter	map->map_db1 = (ARBPTR_T) dbm;
162364562Sgshapiro
162464562Sgshapiro	/*
162564562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
162664562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
162764562Sgshapiro	**  map_mtime to be set
162864562Sgshapiro	*/
162964562Sgshapiro
163077349Sgshapiro	if (fstat(pfd, &st) >= 0)
163164562Sgshapiro		map->map_mtime = st.st_mtime;
163264562Sgshapiro
163338032Speter	if (mode == O_RDONLY)
163438032Speter	{
163564562Sgshapiro# if LOCK_ON_OPEN
163638032Speter		if (dfd >= 0)
163738032Speter			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
163838032Speter		if (pfd >= 0)
163938032Speter			(void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
164064562Sgshapiro# endif /* LOCK_ON_OPEN */
164138032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
164290792Sgshapiro		    !aliaswait(map, ".pag", true))
164390792Sgshapiro			return false;
164438032Speter	}
164538032Speter	else
164638032Speter	{
164738032Speter		map->map_mflags |= MF_LOCKED;
164842575Speter		if (geteuid() == 0 && TrustedUid != 0)
164938032Speter		{
165064562Sgshapiro#  if HASFCHOWN
165142575Speter			if (fchown(dfd, TrustedUid, -1) < 0 ||
165242575Speter			    fchown(pfd, TrustedUid, -1) < 0)
165338032Speter			{
165438032Speter				int err = errno;
165538032Speter
165638032Speter				sm_syslog(LOG_ALERT, NOQID,
165738032Speter					  "ownership change on %s failed: %s",
165890792Sgshapiro					  map->map_file, sm_errstring(err));
165938032Speter				message("050 ownership change on %s failed: %s",
166090792Sgshapiro					map->map_file, sm_errstring(err));
166138032Speter			}
166290792Sgshapiro#  else /* HASFCHOWN */
166390792Sgshapiro			sm_syslog(LOG_ALERT, NOQID,
166490792Sgshapiro				  "no fchown(): cannot change ownership on %s",
166590792Sgshapiro				  map->map_file);
166690792Sgshapiro			message("050 no fchown(): cannot change ownership on %s",
166790792Sgshapiro				map->map_file);
166864562Sgshapiro#  endif /* HASFCHOWN */
166938032Speter		}
167038032Speter	}
167190792Sgshapiro	return true;
167238032Speter}
167338032Speter
167438032Speter
167538032Speter/*
167638032Speter**  NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
167738032Speter*/
167838032Speter
167938032Speterchar *
168038032Speterndbm_map_lookup(map, name, av, statp)
168138032Speter	MAP *map;
168238032Speter	char *name;
168338032Speter	char **av;
168438032Speter	int *statp;
168538032Speter{
168638032Speter	datum key, val;
168777349Sgshapiro	int dfd, pfd;
168838032Speter	char keybuf[MAXNAME + 1];
168938032Speter	struct stat stbuf;
169038032Speter
169138032Speter	if (tTd(38, 20))
169290792Sgshapiro		sm_dprintf("ndbm_map_lookup(%s, %s)\n",
169338032Speter			map->map_mname, name);
169438032Speter
169538032Speter	key.dptr = name;
169638032Speter	key.dsize = strlen(name);
169738032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
169838032Speter	{
1699168515Sgshapiro		if (key.dsize > sizeof(keybuf) - 1)
1700168515Sgshapiro			key.dsize = sizeof(keybuf) - 1;
170164562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
170238032Speter		keybuf[key.dsize] = '\0';
170338032Speter		makelower(keybuf);
170438032Speter		key.dptr = keybuf;
170538032Speter	}
170638032Speterlockdbm:
170777349Sgshapiro	dfd = dbm_dirfno((DBM *) map->map_db1);
170877349Sgshapiro	if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
170977349Sgshapiro		(void) lockfile(dfd, map->map_file, ".dir", LOCK_SH);
171077349Sgshapiro	pfd = dbm_pagfno((DBM *) map->map_db1);
171177349Sgshapiro	if (pfd < 0 || fstat(pfd, &stbuf) < 0 ||
171277349Sgshapiro	    stbuf.st_mtime > map->map_mtime)
171338032Speter	{
171438032Speter		/* Reopen the database to sync the cache */
171538032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
171638032Speter								 : O_RDONLY;
171738032Speter
171877349Sgshapiro		if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
171977349Sgshapiro			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
172077349Sgshapiro		map->map_mflags |= MF_CLOSING;
172138032Speter		map->map_class->map_close(map);
172277349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
172338032Speter		if (map->map_class->map_open(map, omode))
172438032Speter		{
172538032Speter			map->map_mflags |= MF_OPEN;
172690792Sgshapiro			map->map_pid = CurrentPid;
1727203004Sgshapiro			if ((omode & O_ACCMODE) == O_RDWR)
172838032Speter				map->map_mflags |= MF_WRITABLE;
172938032Speter			goto lockdbm;
173038032Speter		}
173138032Speter		else
173238032Speter		{
173338032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
173438032Speter			{
173538032Speter				extern MAPCLASS BogusMapClass;
173638032Speter
173738032Speter				*statp = EX_TEMPFAIL;
173890792Sgshapiro				map->map_orgclass = map->map_class;
173938032Speter				map->map_class = &BogusMapClass;
174038032Speter				map->map_mflags |= MF_OPEN;
174190792Sgshapiro				map->map_pid = CurrentPid;
174238032Speter				syserr("Cannot reopen NDBM database %s",
174338032Speter					map->map_file);
174438032Speter			}
174538032Speter			return NULL;
174638032Speter		}
174738032Speter	}
174838032Speter	val.dptr = NULL;
174938032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
175038032Speter	{
175138032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
175238032Speter		if (val.dptr != NULL)
175338032Speter			map->map_mflags &= ~MF_TRY1NULL;
175438032Speter	}
175538032Speter	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
175638032Speter	{
175738032Speter		key.dsize++;
175838032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
175938032Speter		if (val.dptr != NULL)
176038032Speter			map->map_mflags &= ~MF_TRY0NULL;
176138032Speter	}
176277349Sgshapiro	if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
176377349Sgshapiro		(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
176438032Speter	if (val.dptr == NULL)
176538032Speter		return NULL;
176638032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
176738032Speter		return map_rewrite(map, name, strlen(name), NULL);
176838032Speter	else
176938032Speter		return map_rewrite(map, val.dptr, val.dsize, av);
177038032Speter}
177138032Speter
177238032Speter
177338032Speter/*
177438032Speter**  NDBM_MAP_STORE -- store a datum in the database
177538032Speter*/
177638032Speter
177738032Spetervoid
177838032Speterndbm_map_store(map, lhs, rhs)
177938032Speter	register MAP *map;
178038032Speter	char *lhs;
178138032Speter	char *rhs;
178238032Speter{
178338032Speter	datum key;
178438032Speter	datum data;
178564562Sgshapiro	int status;
178638032Speter	char keybuf[MAXNAME + 1];
178738032Speter
178838032Speter	if (tTd(38, 12))
178990792Sgshapiro		sm_dprintf("ndbm_map_store(%s, %s, %s)\n",
179038032Speter			map->map_mname, lhs, rhs);
179138032Speter
179238032Speter	key.dsize = strlen(lhs);
179338032Speter	key.dptr = lhs;
179438032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
179538032Speter	{
1796168515Sgshapiro		if (key.dsize > sizeof(keybuf) - 1)
1797168515Sgshapiro			key.dsize = sizeof(keybuf) - 1;
179864562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
179938032Speter		keybuf[key.dsize] = '\0';
180038032Speter		makelower(keybuf);
180138032Speter		key.dptr = keybuf;
180238032Speter	}
180338032Speter
180438032Speter	data.dsize = strlen(rhs);
180538032Speter	data.dptr = rhs;
180638032Speter
180738032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
180838032Speter	{
180938032Speter		key.dsize++;
181038032Speter		data.dsize++;
181138032Speter	}
181238032Speter
181364562Sgshapiro	status = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
181464562Sgshapiro	if (status > 0)
181538032Speter	{
181638032Speter		if (!bitset(MF_APPEND, map->map_mflags))
181738032Speter			message("050 Warning: duplicate alias name %s", lhs);
181838032Speter		else
181938032Speter		{
182038032Speter			static char *buf = NULL;
182138032Speter			static int bufsiz = 0;
182238032Speter			auto int xstat;
182338032Speter			datum old;
182438032Speter
182538032Speter			old.dptr = ndbm_map_lookup(map, key.dptr,
182690792Sgshapiro						   (char **) NULL, &xstat);
182738032Speter			if (old.dptr != NULL && *(char *) old.dptr != '\0')
182838032Speter			{
182938032Speter				old.dsize = strlen(old.dptr);
183038032Speter				if (data.dsize + old.dsize + 2 > bufsiz)
183138032Speter				{
183238032Speter					if (buf != NULL)
183390792Sgshapiro						(void) sm_free(buf);
183438032Speter					bufsiz = data.dsize + old.dsize + 2;
183590792Sgshapiro					buf = sm_pmalloc_x(bufsiz);
183638032Speter				}
183790792Sgshapiro				(void) sm_strlcpyn(buf, bufsiz, 3,
183890792Sgshapiro					data.dptr, ",", old.dptr);
183938032Speter				data.dsize = data.dsize + old.dsize + 1;
184038032Speter				data.dptr = buf;
184138032Speter				if (tTd(38, 9))
184290792Sgshapiro					sm_dprintf("ndbm_map_store append=%s\n",
1843285303Sgshapiro						(char *)data.dptr);
184438032Speter			}
184538032Speter		}
184664562Sgshapiro		status = dbm_store((DBM *) map->map_db1,
184764562Sgshapiro				   key, data, DBM_REPLACE);
184838032Speter	}
184964562Sgshapiro	if (status != 0)
185064562Sgshapiro		syserr("readaliases: dbm put (%s): %d", lhs, status);
185138032Speter}
185238032Speter
185338032Speter
185438032Speter/*
185538032Speter**  NDBM_MAP_CLOSE -- close the database
185638032Speter*/
185738032Speter
185838032Spetervoid
185938032Speterndbm_map_close(map)
186038032Speter	register MAP  *map;
186138032Speter{
186238032Speter	if (tTd(38, 9))
186390792Sgshapiro		sm_dprintf("ndbm_map_close(%s, %s, %lx)\n",
186438032Speter			map->map_mname, map->map_file, map->map_mflags);
186538032Speter
186638032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
186738032Speter	{
186864562Sgshapiro# ifdef NDBM_YP_COMPAT
186938032Speter		bool inclnull;
187042575Speter		char buf[MAXHOSTNAMELEN];
187138032Speter
187238032Speter		inclnull = bitset(MF_INCLNULL, map->map_mflags);
187338032Speter		map->map_mflags &= ~MF_INCLNULL;
187438032Speter
187538032Speter		if (strstr(map->map_file, "/yp/") != NULL)
187638032Speter		{
187738032Speter			long save_mflags = map->map_mflags;
187838032Speter
187938032Speter			map->map_mflags |= MF_NOFOLDCASE;
188038032Speter
1881168515Sgshapiro			(void) sm_snprintf(buf, sizeof(buf), "%010ld", curtime());
188238032Speter			ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
188338032Speter
1884168515Sgshapiro			(void) gethostname(buf, sizeof(buf));
188538032Speter			ndbm_map_store(map, "YP_MASTER_NAME", buf);
188638032Speter
188738032Speter			map->map_mflags = save_mflags;
188838032Speter		}
188938032Speter
189038032Speter		if (inclnull)
189138032Speter			map->map_mflags |= MF_INCLNULL;
189264562Sgshapiro# endif /* NDBM_YP_COMPAT */
189338032Speter
189438032Speter		/* write out the distinguished alias */
189538032Speter		ndbm_map_store(map, "@", "@");
189638032Speter	}
189738032Speter	dbm_close((DBM *) map->map_db1);
189838032Speter
189938032Speter	/* release lock (if needed) */
190064562Sgshapiro# if !LOCK_ON_OPEN
190138032Speter	if (map->map_lockfd >= 0)
190238032Speter		(void) close(map->map_lockfd);
190364562Sgshapiro# endif /* !LOCK_ON_OPEN */
190438032Speter}
190538032Speter
190664562Sgshapiro#endif /* NDBM */
190790792Sgshapiro/*
190838032Speter**  NEWDB (Hash and BTree) Modules
190938032Speter*/
191038032Speter
191190792Sgshapiro#if NEWDB
191238032Speter
191338032Speter/*
191438032Speter**  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
191538032Speter**
191638032Speter**	These do rather bizarre locking.  If you can lock on open,
191738032Speter**	do that to avoid the condition of opening a database that
191838032Speter**	is being rebuilt.  If you don't, we'll try to fake it, but
191938032Speter**	there will be a race condition.  If opening for read-only,
192038032Speter**	we immediately release the lock to avoid freezing things up.
192138032Speter**	We really ought to hold the lock, but guarantee that we won't
192238032Speter**	be pokey about it.  That's hard to do.
192338032Speter*/
192438032Speter
192538032Speter/* these should be K line arguments */
192664562Sgshapiro# if DB_VERSION_MAJOR < 2
192764562Sgshapiro#  define db_cachesize	cachesize
192864562Sgshapiro#  define h_nelem	nelem
192964562Sgshapiro#  ifndef DB_CACHE_SIZE
193064562Sgshapiro#   define DB_CACHE_SIZE	(1024 * 1024)	/* database memory cache size */
193164562Sgshapiro#  endif /* ! DB_CACHE_SIZE */
193264562Sgshapiro#  ifndef DB_HASH_NELEM
193364562Sgshapiro#   define DB_HASH_NELEM	4096		/* (starting) size of hash table */
193464562Sgshapiro#  endif /* ! DB_HASH_NELEM */
193564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
193638032Speter
193738032Speterbool
193838032Speterbt_map_open(map, mode)
193938032Speter	MAP *map;
194038032Speter	int mode;
194138032Speter{
194264562Sgshapiro# if DB_VERSION_MAJOR < 2
194338032Speter	BTREEINFO btinfo;
194464562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
194564562Sgshapiro# if DB_VERSION_MAJOR == 2
194638032Speter	DB_INFO btinfo;
194764562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
194864562Sgshapiro# if DB_VERSION_MAJOR > 2
194964562Sgshapiro	void *btinfo = NULL;
195064562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
195138032Speter
195238032Speter	if (tTd(38, 2))
195390792Sgshapiro		sm_dprintf("bt_map_open(%s, %s, %d)\n",
195438032Speter			map->map_mname, map->map_file, mode);
195538032Speter
195664562Sgshapiro# if DB_VERSION_MAJOR < 3
1957168515Sgshapiro	memset(&btinfo, '\0', sizeof(btinfo));
195864562Sgshapiro#  ifdef DB_CACHE_SIZE
195938032Speter	btinfo.db_cachesize = DB_CACHE_SIZE;
196064562Sgshapiro#  endif /* DB_CACHE_SIZE */
196164562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
196264562Sgshapiro
196338032Speter	return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
196438032Speter}
196538032Speter
196638032Speterbool
196738032Speterhash_map_open(map, mode)
196838032Speter	MAP *map;
196938032Speter	int mode;
197038032Speter{
197164562Sgshapiro# if DB_VERSION_MAJOR < 2
197238032Speter	HASHINFO hinfo;
197364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
197464562Sgshapiro# if DB_VERSION_MAJOR == 2
197538032Speter	DB_INFO hinfo;
197664562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
197764562Sgshapiro# if DB_VERSION_MAJOR > 2
197864562Sgshapiro	void *hinfo = NULL;
197964562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
198038032Speter
198138032Speter	if (tTd(38, 2))
198290792Sgshapiro		sm_dprintf("hash_map_open(%s, %s, %d)\n",
198338032Speter			map->map_mname, map->map_file, mode);
198438032Speter
198564562Sgshapiro# if DB_VERSION_MAJOR < 3
1986168515Sgshapiro	memset(&hinfo, '\0', sizeof(hinfo));
198764562Sgshapiro#  ifdef DB_HASH_NELEM
198838032Speter	hinfo.h_nelem = DB_HASH_NELEM;
198964562Sgshapiro#  endif /* DB_HASH_NELEM */
199064562Sgshapiro#  ifdef DB_CACHE_SIZE
199138032Speter	hinfo.db_cachesize = DB_CACHE_SIZE;
199264562Sgshapiro#  endif /* DB_CACHE_SIZE */
199364562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
199464562Sgshapiro
199538032Speter	return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
199638032Speter}
199738032Speter
199864562Sgshapirostatic bool
199938032Speterdb_map_open(map, mode, mapclassname, dbtype, openinfo)
200038032Speter	MAP *map;
200138032Speter	int mode;
200238032Speter	char *mapclassname;
200338032Speter	DBTYPE dbtype;
200464562Sgshapiro# if DB_VERSION_MAJOR < 2
200538032Speter	const void *openinfo;
200664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
200764562Sgshapiro# if DB_VERSION_MAJOR == 2
200838032Speter	DB_INFO *openinfo;
200964562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
201064562Sgshapiro# if DB_VERSION_MAJOR > 2
201164562Sgshapiro	void **openinfo;
201264562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
201338032Speter{
201438032Speter	DB *db = NULL;
201538032Speter	int i;
201638032Speter	int omode;
201738032Speter	int smode = S_IREAD;
201838032Speter	int fd;
201964562Sgshapiro	long sff;
202064562Sgshapiro	int save_errno;
202138032Speter	struct stat st;
202298121Sgshapiro	char buf[MAXPATHLEN];
202338032Speter
202438032Speter	/* do initial file and directory checks */
2025168515Sgshapiro	if (sm_strlcpy(buf, map->map_file, sizeof(buf)) >= sizeof(buf))
202698121Sgshapiro	{
202798121Sgshapiro		errno = 0;
202898121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
202998121Sgshapiro			syserr("map \"%s\": map file %s name too long",
203098121Sgshapiro				map->map_mname, map->map_file);
203198121Sgshapiro		return false;
203298121Sgshapiro	}
203338032Speter	i = strlen(buf);
203438032Speter	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
203598121Sgshapiro	{
2036168515Sgshapiro		if (sm_strlcat(buf, ".db", sizeof(buf)) >= sizeof(buf))
203798121Sgshapiro		{
203898121Sgshapiro			errno = 0;
203998121Sgshapiro			if (!bitset(MF_OPTIONAL, map->map_mflags))
204098121Sgshapiro				syserr("map \"%s\": map file %s name too long",
204198121Sgshapiro					map->map_mname, map->map_file);
204298121Sgshapiro			return false;
204398121Sgshapiro		}
204498121Sgshapiro	}
204538032Speter
204638032Speter	mode &= O_ACCMODE;
204738032Speter	omode = mode;
204838032Speter
204938032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
205038032Speter	if (mode == O_RDWR)
205138032Speter	{
205238032Speter		sff |= SFF_CREAT;
205364562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
205438032Speter			sff |= SFF_NOSLINK;
205564562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
205638032Speter			sff |= SFF_NOHLINK;
205738032Speter		smode = S_IWRITE;
205838032Speter	}
205938032Speter	else
206038032Speter	{
206164562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
206238032Speter			sff |= SFF_NOWLINK;
206338032Speter	}
206464562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
206538032Speter		sff |= SFF_SAFEDIRPATH;
206638032Speter	i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
206764562Sgshapiro
206838032Speter	if (i != 0)
206938032Speter	{
207038032Speter		char *prob = "unsafe";
207138032Speter
207238032Speter		/* cannot open this map */
207338032Speter		if (i == ENOENT)
207438032Speter			prob = "missing";
207538032Speter		if (tTd(38, 2))
207690792Sgshapiro			sm_dprintf("\t%s map file: %s\n", prob, sm_errstring(i));
207738032Speter		errno = i;
207838032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
207938032Speter			syserr("%s map \"%s\": %s map file %s",
208038032Speter				mapclassname, map->map_mname, prob, buf);
208190792Sgshapiro		return false;
208238032Speter	}
208338032Speter	if (st.st_mode == ST_MODE_NOFILE)
208438032Speter		omode |= O_CREAT|O_EXCL;
208538032Speter
208638032Speter	map->map_lockfd = -1;
208738032Speter
208864562Sgshapiro# if LOCK_ON_OPEN
208938032Speter	if (mode == O_RDWR)
209038032Speter		omode |= O_TRUNC|O_EXLOCK;
209138032Speter	else
209238032Speter		omode |= O_SHLOCK;
209364562Sgshapiro# else /* LOCK_ON_OPEN */
209438032Speter	/*
209538032Speter	**  Pre-lock the file to avoid race conditions.  In particular,
209638032Speter	**  since dbopen returns NULL if the file is zero length, we
209738032Speter	**  must have a locked instance around the dbopen.
209838032Speter	*/
209938032Speter
210038032Speter	fd = open(buf, omode, DBMMODE);
210138032Speter	if (fd < 0)
210238032Speter	{
210338032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
210438032Speter			syserr("db_map_open: cannot pre-open database %s", buf);
210590792Sgshapiro		return false;
210638032Speter	}
210738032Speter
210838032Speter	/* make sure no baddies slipped in just before the open... */
210938032Speter	if (filechanged(buf, fd, &st))
211038032Speter	{
211164562Sgshapiro		save_errno = errno;
211238032Speter		(void) close(fd);
211338032Speter		errno = save_errno;
211438032Speter		syserr("db_map_open(%s): file changed after pre-open", buf);
211590792Sgshapiro		return false;
211638032Speter	}
211738032Speter
211838032Speter	/* if new file, get the "before" bits for later filechanged check */
211938032Speter	if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
212038032Speter	{
212164562Sgshapiro		save_errno = errno;
212238032Speter		(void) close(fd);
212338032Speter		errno = save_errno;
212438032Speter		syserr("db_map_open(%s): cannot fstat pre-opened file",
212538032Speter			buf);
212690792Sgshapiro		return false;
212738032Speter	}
212838032Speter
212938032Speter	/* actually lock the pre-opened file */
213038032Speter	if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
213138032Speter		syserr("db_map_open: cannot lock %s", buf);
213238032Speter
213338032Speter	/* set up mode bits for dbopen */
213438032Speter	if (mode == O_RDWR)
213538032Speter		omode |= O_TRUNC;
213638032Speter	omode &= ~(O_EXCL|O_CREAT);
213764562Sgshapiro# endif /* LOCK_ON_OPEN */
213838032Speter
213964562Sgshapiro# if DB_VERSION_MAJOR < 2
214038032Speter	db = dbopen(buf, omode, DBMMODE, dbtype, openinfo);
214164562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
214238032Speter	{
214338032Speter		int flags = 0;
214464562Sgshapiro#  if DB_VERSION_MAJOR > 2
214564562Sgshapiro		int ret;
214664562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
214738032Speter
214838032Speter		if (mode == O_RDONLY)
214938032Speter			flags |= DB_RDONLY;
215038032Speter		if (bitset(O_CREAT, omode))
215138032Speter			flags |= DB_CREATE;
215238032Speter		if (bitset(O_TRUNC, omode))
215338032Speter			flags |= DB_TRUNCATE;
2154110560Sgshapiro		SM_DB_FLAG_ADD(flags);
215538032Speter
215664562Sgshapiro#  if DB_VERSION_MAJOR > 2
215764562Sgshapiro		ret = db_create(&db, NULL, 0);
215864562Sgshapiro#  ifdef DB_CACHE_SIZE
215964562Sgshapiro		if (ret == 0 && db != NULL)
216064562Sgshapiro		{
216164562Sgshapiro			ret = db->set_cachesize(db, 0, DB_CACHE_SIZE, 0);
216264562Sgshapiro			if (ret != 0)
216364562Sgshapiro			{
216464562Sgshapiro				(void) db->close(db, 0);
216564562Sgshapiro				db = NULL;
216664562Sgshapiro			}
216764562Sgshapiro		}
216864562Sgshapiro#  endif /* DB_CACHE_SIZE */
216964562Sgshapiro#  ifdef DB_HASH_NELEM
217064562Sgshapiro		if (dbtype == DB_HASH && ret == 0 && db != NULL)
217164562Sgshapiro		{
217264562Sgshapiro			ret = db->set_h_nelem(db, DB_HASH_NELEM);
217364562Sgshapiro			if (ret != 0)
217464562Sgshapiro			{
217564562Sgshapiro				(void) db->close(db, 0);
217664562Sgshapiro				db = NULL;
217764562Sgshapiro			}
217864562Sgshapiro		}
217964562Sgshapiro#  endif /* DB_HASH_NELEM */
218064562Sgshapiro		if (ret == 0 && db != NULL)
218164562Sgshapiro		{
2182110560Sgshapiro			ret = db->open(db,
2183110560Sgshapiro					DBTXN	/* transaction for DB 4.1 */
2184110560Sgshapiro					buf, NULL, dbtype, flags, DBMMODE);
218564562Sgshapiro			if (ret != 0)
218664562Sgshapiro			{
218773188Sgshapiro#ifdef DB_OLD_VERSION
218873188Sgshapiro				if (ret == DB_OLD_VERSION)
218973188Sgshapiro					ret = EINVAL;
219073188Sgshapiro#endif /* DB_OLD_VERSION */
219164562Sgshapiro				(void) db->close(db, 0);
219264562Sgshapiro				db = NULL;
219364562Sgshapiro			}
219464562Sgshapiro		}
219564562Sgshapiro		errno = ret;
219664562Sgshapiro#  else /* DB_VERSION_MAJOR > 2 */
219738032Speter		errno = db_open(buf, dbtype, flags, DBMMODE,
219838032Speter				NULL, openinfo, &db);
219964562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
220038032Speter	}
220164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
220264562Sgshapiro	save_errno = errno;
220338032Speter
220464562Sgshapiro# if !LOCK_ON_OPEN
220538032Speter	if (mode == O_RDWR)
220638032Speter		map->map_lockfd = fd;
220738032Speter	else
220838032Speter		(void) close(fd);
220964562Sgshapiro# endif /* !LOCK_ON_OPEN */
221038032Speter
221138032Speter	if (db == NULL)
221238032Speter	{
221338032Speter		if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
221490792Sgshapiro		    aliaswait(map, ".db", false))
221590792Sgshapiro			return true;
221664562Sgshapiro# if !LOCK_ON_OPEN
221738032Speter		if (map->map_lockfd >= 0)
221838032Speter			(void) close(map->map_lockfd);
221964562Sgshapiro# endif /* !LOCK_ON_OPEN */
222064562Sgshapiro		errno = save_errno;
222138032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
222238032Speter			syserr("Cannot open %s database %s",
222338032Speter				mapclassname, buf);
222490792Sgshapiro		return false;
222538032Speter	}
222638032Speter
222764562Sgshapiro# if DB_VERSION_MAJOR < 2
222838032Speter	fd = db->fd(db);
222964562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
223038032Speter	fd = -1;
223138032Speter	errno = db->fd(db, &fd);
223264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
223338032Speter	if (filechanged(buf, fd, &st))
223438032Speter	{
223564562Sgshapiro		save_errno = errno;
223664562Sgshapiro# if DB_VERSION_MAJOR < 2
223764562Sgshapiro		(void) db->close(db);
223864562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
223938032Speter		errno = db->close(db, 0);
224064562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
224164562Sgshapiro# if !LOCK_ON_OPEN
224238032Speter		if (map->map_lockfd >= 0)
224364562Sgshapiro			(void) close(map->map_lockfd);
224464562Sgshapiro# endif /* !LOCK_ON_OPEN */
224538032Speter		errno = save_errno;
224638032Speter		syserr("db_map_open(%s): file changed after open", buf);
224790792Sgshapiro		return false;
224838032Speter	}
224938032Speter
225038032Speter	if (mode == O_RDWR)
225138032Speter		map->map_mflags |= MF_LOCKED;
225264562Sgshapiro# if LOCK_ON_OPEN
225338032Speter	if (fd >= 0 && mode == O_RDONLY)
225438032Speter	{
225538032Speter		(void) lockfile(fd, buf, NULL, LOCK_UN);
225638032Speter	}
225764562Sgshapiro# endif /* LOCK_ON_OPEN */
225838032Speter
225938032Speter	/* try to make sure that at least the database header is on disk */
226038032Speter	if (mode == O_RDWR)
226138032Speter	{
226238032Speter		(void) db->sync(db, 0);
226342575Speter		if (geteuid() == 0 && TrustedUid != 0)
226438032Speter		{
226564562Sgshapiro#  if HASFCHOWN
226642575Speter			if (fchown(fd, TrustedUid, -1) < 0)
226738032Speter			{
226838032Speter				int err = errno;
226938032Speter
227038032Speter				sm_syslog(LOG_ALERT, NOQID,
227138032Speter					  "ownership change on %s failed: %s",
227290792Sgshapiro					  buf, sm_errstring(err));
227338032Speter				message("050 ownership change on %s failed: %s",
227490792Sgshapiro					buf, sm_errstring(err));
227538032Speter			}
227690792Sgshapiro#  else /* HASFCHOWN */
227790792Sgshapiro			sm_syslog(LOG_ALERT, NOQID,
227890792Sgshapiro				  "no fchown(): cannot change ownership on %s",
227990792Sgshapiro				  map->map_file);
228090792Sgshapiro			message("050 no fchown(): cannot change ownership on %s",
228190792Sgshapiro				map->map_file);
228264562Sgshapiro#  endif /* HASFCHOWN */
228338032Speter		}
228438032Speter	}
228538032Speter
228664562Sgshapiro	map->map_db2 = (ARBPTR_T) db;
228764562Sgshapiro
228864562Sgshapiro	/*
228964562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
229064562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
229164562Sgshapiro	**  map_mtime to be set
229264562Sgshapiro	*/
229364562Sgshapiro
229438032Speter	if (fd >= 0 && fstat(fd, &st) >= 0)
229538032Speter		map->map_mtime = st.st_mtime;
229638032Speter
229738032Speter	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
229890792Sgshapiro	    !aliaswait(map, ".db", true))
229990792Sgshapiro		return false;
230090792Sgshapiro	return true;
230138032Speter}
230238032Speter
230338032Speter
230438032Speter/*
230538032Speter**  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
230638032Speter*/
230738032Speter
230838032Speterchar *
230938032Speterdb_map_lookup(map, name, av, statp)
231038032Speter	MAP *map;
231138032Speter	char *name;
231238032Speter	char **av;
231338032Speter	int *statp;
231438032Speter{
231538032Speter	DBT key, val;
231638032Speter	register DB *db = (DB *) map->map_db2;
231738032Speter	int i;
231838032Speter	int st;
231964562Sgshapiro	int save_errno;
232038032Speter	int fd;
232138032Speter	struct stat stbuf;
232238032Speter	char keybuf[MAXNAME + 1];
232398121Sgshapiro	char buf[MAXPATHLEN];
232438032Speter
2325168515Sgshapiro	memset(&key, '\0', sizeof(key));
2326168515Sgshapiro	memset(&val, '\0', sizeof(val));
232738032Speter
232838032Speter	if (tTd(38, 20))
232990792Sgshapiro		sm_dprintf("db_map_lookup(%s, %s)\n",
233038032Speter			map->map_mname, name);
233138032Speter
2332168515Sgshapiro	if (sm_strlcpy(buf, map->map_file, sizeof(buf)) >= sizeof(buf))
233398121Sgshapiro	{
233498121Sgshapiro		errno = 0;
233598121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
233698121Sgshapiro			syserr("map \"%s\": map file %s name too long",
233798121Sgshapiro				map->map_mname, map->map_file);
233898121Sgshapiro		return NULL;
233998121Sgshapiro	}
234098121Sgshapiro	i = strlen(buf);
234138032Speter	if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
234238032Speter		buf[i - 3] = '\0';
234338032Speter
234438032Speter	key.size = strlen(name);
2345168515Sgshapiro	if (key.size > sizeof(keybuf) - 1)
2346168515Sgshapiro		key.size = sizeof(keybuf) - 1;
234738032Speter	key.data = keybuf;
234864562Sgshapiro	memmove(keybuf, name, key.size);
234938032Speter	keybuf[key.size] = '\0';
235038032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
235138032Speter		makelower(keybuf);
235238032Speter  lockdb:
235364562Sgshapiro# if DB_VERSION_MAJOR < 2
235438032Speter	fd = db->fd(db);
235564562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
235638032Speter	fd = -1;
235738032Speter	errno = db->fd(db, &fd);
235864562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
235938032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
236038032Speter		(void) lockfile(fd, buf, ".db", LOCK_SH);
236138032Speter	if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
236238032Speter	{
236338032Speter		/* Reopen the database to sync the cache */
236438032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
236538032Speter								 : O_RDONLY;
236638032Speter
236764562Sgshapiro		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
236864562Sgshapiro			(void) lockfile(fd, buf, ".db", LOCK_UN);
236977349Sgshapiro		map->map_mflags |= MF_CLOSING;
237038032Speter		map->map_class->map_close(map);
237177349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
237238032Speter		if (map->map_class->map_open(map, omode))
237338032Speter		{
237438032Speter			map->map_mflags |= MF_OPEN;
237590792Sgshapiro			map->map_pid = CurrentPid;
2376203004Sgshapiro			if ((omode & O_ACCMODE) == O_RDWR)
237738032Speter				map->map_mflags |= MF_WRITABLE;
237838032Speter			db = (DB *) map->map_db2;
237938032Speter			goto lockdb;
238038032Speter		}
238138032Speter		else
238238032Speter		{
238338032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
238438032Speter			{
238538032Speter				extern MAPCLASS BogusMapClass;
238638032Speter
238738032Speter				*statp = EX_TEMPFAIL;
238890792Sgshapiro				map->map_orgclass = map->map_class;
238938032Speter				map->map_class = &BogusMapClass;
239038032Speter				map->map_mflags |= MF_OPEN;
239190792Sgshapiro				map->map_pid = CurrentPid;
239238032Speter				syserr("Cannot reopen DB database %s",
239338032Speter					map->map_file);
239438032Speter			}
239538032Speter			return NULL;
239638032Speter		}
239738032Speter	}
239838032Speter
239938032Speter	st = 1;
240038032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
240138032Speter	{
240264562Sgshapiro# if DB_VERSION_MAJOR < 2
240338032Speter		st = db->get(db, &key, &val, 0);
240464562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
240538032Speter		errno = db->get(db, NULL, &key, &val, 0);
240638032Speter		switch (errno)
240738032Speter		{
240838032Speter		  case DB_NOTFOUND:
240938032Speter		  case DB_KEYEMPTY:
241038032Speter			st = 1;
241138032Speter			break;
241238032Speter
241338032Speter		  case 0:
241438032Speter			st = 0;
241538032Speter			break;
241638032Speter
241738032Speter		  default:
241838032Speter			st = -1;
241938032Speter			break;
242038032Speter		}
242164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
242238032Speter		if (st == 0)
242338032Speter			map->map_mflags &= ~MF_TRY1NULL;
242438032Speter	}
242538032Speter	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
242638032Speter	{
242738032Speter		key.size++;
242864562Sgshapiro# if DB_VERSION_MAJOR < 2
242938032Speter		st = db->get(db, &key, &val, 0);
243064562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
243138032Speter		errno = db->get(db, NULL, &key, &val, 0);
243238032Speter		switch (errno)
243338032Speter		{
243438032Speter		  case DB_NOTFOUND:
243538032Speter		  case DB_KEYEMPTY:
243638032Speter			st = 1;
243738032Speter			break;
243838032Speter
243938032Speter		  case 0:
244038032Speter			st = 0;
244138032Speter			break;
244238032Speter
244338032Speter		  default:
244438032Speter			st = -1;
244538032Speter			break;
244638032Speter		}
244764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
244838032Speter		if (st == 0)
244938032Speter			map->map_mflags &= ~MF_TRY0NULL;
245038032Speter	}
245164562Sgshapiro	save_errno = errno;
245238032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
245338032Speter		(void) lockfile(fd, buf, ".db", LOCK_UN);
245438032Speter	if (st != 0)
245538032Speter	{
245664562Sgshapiro		errno = save_errno;
245738032Speter		if (st < 0)
245838032Speter			syserr("db_map_lookup: get (%s)", name);
245938032Speter		return NULL;
246038032Speter	}
246138032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
246238032Speter		return map_rewrite(map, name, strlen(name), NULL);
246338032Speter	else
246438032Speter		return map_rewrite(map, val.data, val.size, av);
246538032Speter}
246638032Speter
246738032Speter
246838032Speter/*
246938032Speter**  DB_MAP_STORE -- store a datum in the NEWDB database
247038032Speter*/
247138032Speter
247238032Spetervoid
247338032Speterdb_map_store(map, lhs, rhs)
247438032Speter	register MAP *map;
247538032Speter	char *lhs;
247638032Speter	char *rhs;
247738032Speter{
247864562Sgshapiro	int status;
247938032Speter	DBT key;
248038032Speter	DBT data;
248138032Speter	register DB *db = map->map_db2;
248238032Speter	char keybuf[MAXNAME + 1];
248338032Speter
2484168515Sgshapiro	memset(&key, '\0', sizeof(key));
2485168515Sgshapiro	memset(&data, '\0', sizeof(data));
248638032Speter
248738032Speter	if (tTd(38, 12))
248890792Sgshapiro		sm_dprintf("db_map_store(%s, %s, %s)\n",
248938032Speter			map->map_mname, lhs, rhs);
249038032Speter
249138032Speter	key.size = strlen(lhs);
249238032Speter	key.data = lhs;
249338032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
249438032Speter	{
2495168515Sgshapiro		if (key.size > sizeof(keybuf) - 1)
2496168515Sgshapiro			key.size = sizeof(keybuf) - 1;
249764562Sgshapiro		memmove(keybuf, key.data, key.size);
249838032Speter		keybuf[key.size] = '\0';
249938032Speter		makelower(keybuf);
250038032Speter		key.data = keybuf;
250138032Speter	}
250238032Speter
250338032Speter	data.size = strlen(rhs);
250438032Speter	data.data = rhs;
250538032Speter
250638032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
250738032Speter	{
250838032Speter		key.size++;
250938032Speter		data.size++;
251038032Speter	}
251138032Speter
251264562Sgshapiro# if DB_VERSION_MAJOR < 2
251364562Sgshapiro	status = db->put(db, &key, &data, R_NOOVERWRITE);
251464562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
251538032Speter	errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE);
251638032Speter	switch (errno)
251738032Speter	{
251838032Speter	  case DB_KEYEXIST:
251964562Sgshapiro		status = 1;
252038032Speter		break;
252138032Speter
252238032Speter	  case 0:
252364562Sgshapiro		status = 0;
252438032Speter		break;
252538032Speter
252638032Speter	  default:
252764562Sgshapiro		status = -1;
252838032Speter		break;
252938032Speter	}
253064562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
253164562Sgshapiro	if (status > 0)
253238032Speter	{
253338032Speter		if (!bitset(MF_APPEND, map->map_mflags))
253438032Speter			message("050 Warning: duplicate alias name %s", lhs);
253538032Speter		else
253638032Speter		{
253738032Speter			static char *buf = NULL;
253838032Speter			static int bufsiz = 0;
253938032Speter			DBT old;
254038032Speter
2541168515Sgshapiro			memset(&old, '\0', sizeof(old));
254238032Speter
254364562Sgshapiro			old.data = db_map_lookup(map, key.data,
254490792Sgshapiro						 (char **) NULL, &status);
254538032Speter			if (old.data != NULL)
254638032Speter			{
254738032Speter				old.size = strlen(old.data);
254890792Sgshapiro				if (data.size + old.size + 2 > (size_t) bufsiz)
254938032Speter				{
255038032Speter					if (buf != NULL)
255177349Sgshapiro						sm_free(buf);
255238032Speter					bufsiz = data.size + old.size + 2;
255390792Sgshapiro					buf = sm_pmalloc_x(bufsiz);
255438032Speter				}
255590792Sgshapiro				(void) sm_strlcpyn(buf, bufsiz, 3,
255690792Sgshapiro					(char *) data.data, ",",
255790792Sgshapiro					(char *) old.data);
255838032Speter				data.size = data.size + old.size + 1;
255938032Speter				data.data = buf;
256038032Speter				if (tTd(38, 9))
256190792Sgshapiro					sm_dprintf("db_map_store append=%s\n",
256264562Sgshapiro						(char *) data.data);
256338032Speter			}
256438032Speter		}
256564562Sgshapiro# if DB_VERSION_MAJOR < 2
256664562Sgshapiro		status = db->put(db, &key, &data, 0);
256764562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
256864562Sgshapiro		status = errno = db->put(db, NULL, &key, &data, 0);
256964562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
257038032Speter	}
257164562Sgshapiro	if (status != 0)
257238032Speter		syserr("readaliases: db put (%s)", lhs);
257338032Speter}
257438032Speter
257538032Speter
257638032Speter/*
257738032Speter**  DB_MAP_CLOSE -- add distinguished entries and close the database
257838032Speter*/
257938032Speter
258038032Spetervoid
258138032Speterdb_map_close(map)
258238032Speter	MAP *map;
258338032Speter{
258438032Speter	register DB *db = map->map_db2;
258538032Speter
258638032Speter	if (tTd(38, 9))
258790792Sgshapiro		sm_dprintf("db_map_close(%s, %s, %lx)\n",
258838032Speter			map->map_mname, map->map_file, map->map_mflags);
258938032Speter
259038032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
259138032Speter	{
259238032Speter		/* write out the distinguished alias */
259338032Speter		db_map_store(map, "@", "@");
259438032Speter	}
259538032Speter
259638032Speter	(void) db->sync(db, 0);
259738032Speter
259864562Sgshapiro# if !LOCK_ON_OPEN
259938032Speter	if (map->map_lockfd >= 0)
260038032Speter		(void) close(map->map_lockfd);
260164562Sgshapiro# endif /* !LOCK_ON_OPEN */
260238032Speter
260364562Sgshapiro# if DB_VERSION_MAJOR < 2
260438032Speter	if (db->close(db) != 0)
260564562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
260642575Speter	/*
260742575Speter	**  Berkeley DB can use internal shared memory
260842575Speter	**  locking for its memory pool.  Closing a map
260942575Speter	**  opened by another process will interfere
261042575Speter	**  with the shared memory and locks of the parent
261142575Speter	**  process leaving things in a bad state.
261243730Speter	*/
261343730Speter
261443730Speter	/*
261542575Speter	**  If this map was not opened by the current
261643730Speter	**  process, do not close the map but recover
261742575Speter	**  the file descriptor.
261842575Speter	*/
261990792Sgshapiro
262090792Sgshapiro	if (map->map_pid != CurrentPid)
262142575Speter	{
262242575Speter		int fd = -1;
262342575Speter
262442575Speter		errno = db->fd(db, &fd);
262542575Speter		if (fd >= 0)
262642575Speter			(void) close(fd);
262742575Speter		return;
262842575Speter	}
262942575Speter
263038032Speter	if ((errno = db->close(db, 0)) != 0)
263164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
263242575Speter		syserr("db_map_close(%s, %s, %lx): db close failure",
263342575Speter			map->map_mname, map->map_file, map->map_mflags);
263438032Speter}
263564562Sgshapiro#endif /* NEWDB */
263690792Sgshapiro/*
263738032Speter**  NIS Modules
263838032Speter*/
263938032Speter
264090792Sgshapiro#if NIS
264138032Speter
264238032Speter# ifndef YPERR_BUSY
264338032Speter#  define YPERR_BUSY	16
264464562Sgshapiro# endif /* ! YPERR_BUSY */
264538032Speter
264638032Speter/*
264738032Speter**  NIS_MAP_OPEN -- open DBM map
264838032Speter*/
264938032Speter
265038032Speterbool
265138032Speternis_map_open(map, mode)
265238032Speter	MAP *map;
265338032Speter	int mode;
265438032Speter{
265538032Speter	int yperr;
265638032Speter	register char *p;
265738032Speter	auto char *vp;
265838032Speter	auto int vsize;
265938032Speter
266038032Speter	if (tTd(38, 2))
266190792Sgshapiro		sm_dprintf("nis_map_open(%s, %s, %d)\n",
266238032Speter			map->map_mname, map->map_file, mode);
266338032Speter
266438032Speter	mode &= O_ACCMODE;
266538032Speter	if (mode != O_RDONLY)
266638032Speter	{
266738032Speter		/* issue a pseudo-error message */
266890792Sgshapiro		errno = SM_EMAPCANTWRITE;
266990792Sgshapiro		return false;
267038032Speter	}
267138032Speter
267238032Speter	p = strchr(map->map_file, '@');
267338032Speter	if (p != NULL)
267438032Speter	{
267538032Speter		*p++ = '\0';
267638032Speter		if (*p != '\0')
267738032Speter			map->map_domain = p;
267838032Speter	}
267938032Speter
268038032Speter	if (*map->map_file == '\0')
268138032Speter		map->map_file = "mail.aliases";
268238032Speter
268338032Speter	if (map->map_domain == NULL)
268438032Speter	{
268538032Speter		yperr = yp_get_default_domain(&map->map_domain);
268638032Speter		if (yperr != 0)
268738032Speter		{
268838032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
268994334Sgshapiro				syserr("451 4.3.5 NIS map %s specified, but NIS not running",
269064562Sgshapiro				       map->map_file);
269190792Sgshapiro			return false;
269238032Speter		}
269338032Speter	}
269438032Speter
269538032Speter	/* check to see if this map actually exists */
269664562Sgshapiro	vp = NULL;
269738032Speter	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
269838032Speter			&vp, &vsize);
269938032Speter	if (tTd(38, 10))
270090792Sgshapiro		sm_dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n",
270138032Speter			map->map_domain, map->map_file, yperr_string(yperr));
270264562Sgshapiro	if (vp != NULL)
270377349Sgshapiro		sm_free(vp);
270464562Sgshapiro
270538032Speter	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
270638032Speter	{
270738032Speter		/*
270838032Speter		**  We ought to be calling aliaswait() here if this is an
270938032Speter		**  alias file, but powerful HP-UX NIS servers  apparently
271038032Speter		**  don't insert the @:@ token into the alias map when it
271138032Speter		**  is rebuilt, so aliaswait() just hangs.  I hate HP-UX.
271238032Speter		*/
271338032Speter
271464562Sgshapiro# if 0
271538032Speter		if (!bitset(MF_ALIAS, map->map_mflags) ||
271690792Sgshapiro		    aliaswait(map, NULL, true))
271764562Sgshapiro# endif /* 0 */
271890792Sgshapiro			return true;
271938032Speter	}
272038032Speter
272138032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
272238032Speter	{
272394334Sgshapiro		syserr("451 4.3.5 Cannot bind to map %s in domain %s: %s",
272438032Speter			map->map_file, map->map_domain, yperr_string(yperr));
272538032Speter	}
272638032Speter
272790792Sgshapiro	return false;
272838032Speter}
272938032Speter
273038032Speter
273138032Speter/*
273238032Speter**  NIS_MAP_LOOKUP -- look up a datum in a NIS map
273338032Speter*/
273438032Speter
273538032Speter/* ARGSUSED3 */
273638032Speterchar *
273738032Speternis_map_lookup(map, name, av, statp)
273838032Speter	MAP *map;
273938032Speter	char *name;
274038032Speter	char **av;
274138032Speter	int *statp;
274238032Speter{
274338032Speter	char *vp;
274438032Speter	auto int vsize;
274538032Speter	int buflen;
274638032Speter	int yperr;
274738032Speter	char keybuf[MAXNAME + 1];
274890792Sgshapiro	char *SM_NONVOLATILE result = NULL;
274938032Speter
275038032Speter	if (tTd(38, 20))
275190792Sgshapiro		sm_dprintf("nis_map_lookup(%s, %s)\n",
275238032Speter			map->map_mname, name);
275338032Speter
275438032Speter	buflen = strlen(name);
2755168515Sgshapiro	if (buflen > sizeof(keybuf) - 1)
2756168515Sgshapiro		buflen = sizeof(keybuf) - 1;
275764562Sgshapiro	memmove(keybuf, name, buflen);
275838032Speter	keybuf[buflen] = '\0';
275938032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
276038032Speter		makelower(keybuf);
276138032Speter	yperr = YPERR_KEY;
276264562Sgshapiro	vp = NULL;
276338032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
276438032Speter	{
276538032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
276638032Speter			     &vp, &vsize);
276738032Speter		if (yperr == 0)
276838032Speter			map->map_mflags &= ~MF_TRY1NULL;
276938032Speter	}
277038032Speter	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
277138032Speter	{
277290792Sgshapiro		SM_FREE_CLR(vp);
277338032Speter		buflen++;
277438032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
277538032Speter			     &vp, &vsize);
277638032Speter		if (yperr == 0)
277738032Speter			map->map_mflags &= ~MF_TRY0NULL;
277838032Speter	}
277938032Speter	if (yperr != 0)
278038032Speter	{
278138032Speter		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
278238032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
278364562Sgshapiro		if (vp != NULL)
278477349Sgshapiro			sm_free(vp);
278538032Speter		return NULL;
278638032Speter	}
278790792Sgshapiro	SM_TRY
278890792Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
278990792Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
279090792Sgshapiro		else
279190792Sgshapiro			result = map_rewrite(map, vp, vsize, av);
279290792Sgshapiro	SM_FINALLY
279364562Sgshapiro		if (vp != NULL)
279477349Sgshapiro			sm_free(vp);
279590792Sgshapiro	SM_END_TRY
279690792Sgshapiro	return result;
279738032Speter}
279838032Speter
279938032Speter
280038032Speter/*
280138032Speter**  NIS_GETCANONNAME -- look up canonical name in NIS
280238032Speter*/
280338032Speter
280464562Sgshapirostatic bool
280538032Speternis_getcanonname(name, hbsize, statp)
280638032Speter	char *name;
280738032Speter	int hbsize;
280838032Speter	int *statp;
280938032Speter{
281038032Speter	char *vp;
281138032Speter	auto int vsize;
281238032Speter	int keylen;
281338032Speter	int yperr;
281490792Sgshapiro	static bool try0null = true;
281590792Sgshapiro	static bool try1null = true;
281638032Speter	static char *yp_domain = NULL;
281738032Speter	char host_record[MAXLINE];
281838032Speter	char cbuf[MAXNAME];
281938032Speter	char nbuf[MAXNAME + 1];
282038032Speter
282138032Speter	if (tTd(38, 20))
282290792Sgshapiro		sm_dprintf("nis_getcanonname(%s)\n", name);
282338032Speter
2824168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
282538032Speter	{
282638032Speter		*statp = EX_UNAVAILABLE;
282790792Sgshapiro		return false;
282838032Speter	}
282973188Sgshapiro	(void) shorten_hostname(nbuf);
283038032Speter	keylen = strlen(nbuf);
283138032Speter
283238032Speter	if (yp_domain == NULL)
283364562Sgshapiro		(void) yp_get_default_domain(&yp_domain);
283438032Speter	makelower(nbuf);
283538032Speter	yperr = YPERR_KEY;
283664562Sgshapiro	vp = NULL;
283738032Speter	if (try0null)
283838032Speter	{
283938032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
284038032Speter			     &vp, &vsize);
284138032Speter		if (yperr == 0)
284290792Sgshapiro			try1null = false;
284338032Speter	}
284438032Speter	if (yperr == YPERR_KEY && try1null)
284538032Speter	{
284690792Sgshapiro		SM_FREE_CLR(vp);
284738032Speter		keylen++;
284838032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
284938032Speter			     &vp, &vsize);
285038032Speter		if (yperr == 0)
285190792Sgshapiro			try0null = false;
285238032Speter	}
285338032Speter	if (yperr != 0)
285438032Speter	{
285538032Speter		if (yperr == YPERR_KEY)
285638032Speter			*statp = EX_NOHOST;
285738032Speter		else if (yperr == YPERR_BUSY)
285838032Speter			*statp = EX_TEMPFAIL;
285938032Speter		else
286038032Speter			*statp = EX_UNAVAILABLE;
286164562Sgshapiro		if (vp != NULL)
286277349Sgshapiro			sm_free(vp);
286390792Sgshapiro		return false;
286438032Speter	}
2865168515Sgshapiro	(void) sm_strlcpy(host_record, vp, sizeof(host_record));
286677349Sgshapiro	sm_free(vp);
286738032Speter	if (tTd(38, 44))
286890792Sgshapiro		sm_dprintf("got record `%s'\n", host_record);
286990792Sgshapiro	vp = strpbrk(host_record, "#\n");
287090792Sgshapiro	if (vp != NULL)
287190792Sgshapiro		*vp = '\0';
2872168515Sgshapiro	if (!extract_canonname(nbuf, NULL, host_record, cbuf, sizeof(cbuf)))
287338032Speter	{
287438032Speter		/* this should not happen, but.... */
287538032Speter		*statp = EX_NOHOST;
287690792Sgshapiro		return false;
287738032Speter	}
287890792Sgshapiro	if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
287938032Speter	{
288038032Speter		*statp = EX_UNAVAILABLE;
288190792Sgshapiro		return false;
288238032Speter	}
288338032Speter	*statp = EX_OK;
288490792Sgshapiro	return true;
288538032Speter}
288638032Speter
288764562Sgshapiro#endif /* NIS */
288890792Sgshapiro/*
288938032Speter**  NISPLUS Modules
289038032Speter**
289138032Speter**	This code donated by Sun Microsystems.
289238032Speter*/
289338032Speter
289490792Sgshapiro#if NISPLUS
289538032Speter
289664562Sgshapiro# undef NIS		/* symbol conflict in nis.h */
289764562Sgshapiro# undef T_UNSPEC	/* symbol conflict in nis.h -> ... -> sys/tiuser.h */
289864562Sgshapiro# include <rpcsvc/nis.h>
289964562Sgshapiro# include <rpcsvc/nislib.h>
2900249729Sgshapiro# ifndef NIS_TABLE_OBJ
2901249729Sgshapiro#  define NIS_TABLE_OBJ TABLE_OBJ
2902249729Sgshapiro# endif /* NIS_TABLE_OBJ */
290338032Speter
290464562Sgshapiro# define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
290564562Sgshapiro# define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
290664562Sgshapiro# define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
290764562Sgshapiro# define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
290838032Speter
290938032Speter/*
291038032Speter**  NISPLUS_MAP_OPEN -- open nisplus table
291138032Speter*/
291238032Speter
291338032Speterbool
291438032Speternisplus_map_open(map, mode)
291538032Speter	MAP *map;
291638032Speter	int mode;
291738032Speter{
291838032Speter	nis_result *res = NULL;
291938032Speter	int retry_cnt, max_col, i;
292038032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
292138032Speter
292238032Speter	if (tTd(38, 2))
292390792Sgshapiro		sm_dprintf("nisplus_map_open(%s, %s, %d)\n",
292438032Speter			map->map_mname, map->map_file, mode);
292538032Speter
292638032Speter	mode &= O_ACCMODE;
292738032Speter	if (mode != O_RDONLY)
292838032Speter	{
292938032Speter		errno = EPERM;
293090792Sgshapiro		return false;
293138032Speter	}
293238032Speter
293338032Speter	if (*map->map_file == '\0')
293438032Speter		map->map_file = "mail_aliases.org_dir";
293538032Speter
293638032Speter	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
293738032Speter	{
293838032Speter		/* set default NISPLUS Domain to $m */
293938032Speter		map->map_domain = newstr(nisplus_default_domain());
294038032Speter		if (tTd(38, 2))
294190792Sgshapiro			sm_dprintf("nisplus_map_open(%s): using domain %s\n",
294264562Sgshapiro				map->map_file, map->map_domain);
294338032Speter	}
294438032Speter	if (!PARTIAL_NAME(map->map_file))
294538032Speter	{
294638032Speter		map->map_domain = newstr("");
2947168515Sgshapiro		(void) sm_strlcpy(qbuf, map->map_file, sizeof(qbuf));
294838032Speter	}
294938032Speter	else
295038032Speter	{
295138032Speter		/* check to see if this map actually exists */
2952168515Sgshapiro		(void) sm_strlcpyn(qbuf, sizeof(qbuf), 3,
295390792Sgshapiro				   map->map_file, ".", map->map_domain);
295438032Speter	}
295538032Speter
295638032Speter	retry_cnt = 0;
295738032Speter	while (res == NULL || res->status != NIS_SUCCESS)
295838032Speter	{
295938032Speter		res = nis_lookup(qbuf, FOLLOW_LINKS);
296038032Speter		switch (res->status)
296138032Speter		{
296238032Speter		  case NIS_SUCCESS:
296338032Speter			break;
296438032Speter
296538032Speter		  case NIS_TRYAGAIN:
296638032Speter		  case NIS_RPCERROR:
296738032Speter		  case NIS_NAMEUNREACHABLE:
296838032Speter			if (retry_cnt++ > 4)
296938032Speter			{
297038032Speter				errno = EAGAIN;
297190792Sgshapiro				return false;
297238032Speter			}
297338032Speter			/* try not to overwhelm hosed server */
297438032Speter			sleep(2);
297538032Speter			break;
297638032Speter
297738032Speter		  default:		/* all other nisplus errors */
297864562Sgshapiro# if 0
297938032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
298094334Sgshapiro				syserr("451 4.3.5 Cannot find table %s.%s: %s",
298138032Speter					map->map_file, map->map_domain,
298238032Speter					nis_sperrno(res->status));
298364562Sgshapiro# endif /* 0 */
298438032Speter			errno = EAGAIN;
298590792Sgshapiro			return false;
298638032Speter		}
298738032Speter	}
298838032Speter
298938032Speter	if (NIS_RES_NUMOBJ(res) != 1 ||
2990249729Sgshapiro	    (NIS_RES_OBJECT(res)->zo_data.zo_type != NIS_TABLE_OBJ))
299138032Speter	{
299238032Speter		if (tTd(38, 10))
299390792Sgshapiro			sm_dprintf("nisplus_map_open: %s is not a table\n", qbuf);
299464562Sgshapiro# if 0
299538032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
299694334Sgshapiro			syserr("451 4.3.5 %s.%s: %s is not a table",
299738032Speter				map->map_file, map->map_domain,
299838032Speter				nis_sperrno(res->status));
299964562Sgshapiro# endif /* 0 */
300038032Speter		errno = EBADF;
300190792Sgshapiro		return false;
300238032Speter	}
300338032Speter	/* default key column is column 0 */
300438032Speter	if (map->map_keycolnm == NULL)
300538032Speter		map->map_keycolnm = newstr(COL_NAME(res,0));
300638032Speter
300738032Speter	max_col = COL_MAX(res);
300838032Speter
300938032Speter	/* verify the key column exist */
301090792Sgshapiro	for (i = 0; i < max_col; i++)
301138032Speter	{
301264562Sgshapiro		if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0)
301338032Speter			break;
301438032Speter	}
301538032Speter	if (i == max_col)
301638032Speter	{
301738032Speter		if (tTd(38, 2))
301890792Sgshapiro			sm_dprintf("nisplus_map_open(%s): can not find key column %s\n",
301938032Speter				map->map_file, map->map_keycolnm);
302038032Speter		errno = ENOENT;
302190792Sgshapiro		return false;
302238032Speter	}
302338032Speter
302438032Speter	/* default value column is the last column */
302538032Speter	if (map->map_valcolnm == NULL)
302638032Speter	{
302738032Speter		map->map_valcolno = max_col - 1;
302890792Sgshapiro		return true;
302938032Speter	}
303038032Speter
303164562Sgshapiro	for (i = 0; i< max_col; i++)
303238032Speter	{
303338032Speter		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
303438032Speter		{
303538032Speter			map->map_valcolno = i;
303690792Sgshapiro			return true;
303738032Speter		}
303838032Speter	}
303938032Speter
304038032Speter	if (tTd(38, 2))
304190792Sgshapiro		sm_dprintf("nisplus_map_open(%s): can not find column %s\n",
304264562Sgshapiro			map->map_file, map->map_keycolnm);
304338032Speter	errno = ENOENT;
304490792Sgshapiro	return false;
304538032Speter}
304638032Speter
304738032Speter
304838032Speter/*
304938032Speter**  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
305038032Speter*/
305138032Speter
305238032Speterchar *
305338032Speternisplus_map_lookup(map, name, av, statp)
305438032Speter	MAP *map;
305538032Speter	char *name;
305638032Speter	char **av;
305738032Speter	int *statp;
305838032Speter{
305938032Speter	char *p;
306038032Speter	auto int vsize;
306138032Speter	char *skp;
306238032Speter	int skleft;
306338032Speter	char search_key[MAXNAME + 4];
306438032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
306538032Speter	nis_result *result;
306638032Speter
306738032Speter	if (tTd(38, 20))
306890792Sgshapiro		sm_dprintf("nisplus_map_lookup(%s, %s)\n",
306938032Speter			map->map_mname, name);
307038032Speter
307138032Speter	if (!bitset(MF_OPEN, map->map_mflags))
307238032Speter	{
307338032Speter		if (nisplus_map_open(map, O_RDONLY))
307442575Speter		{
307538032Speter			map->map_mflags |= MF_OPEN;
307690792Sgshapiro			map->map_pid = CurrentPid;
307742575Speter		}
307838032Speter		else
307938032Speter		{
308038032Speter			*statp = EX_UNAVAILABLE;
308138032Speter			return NULL;
308238032Speter		}
308338032Speter	}
308438032Speter
308538032Speter	/*
308638032Speter	**  Copy the name to the key buffer, escaping double quote characters
308738032Speter	**  by doubling them and quoting "]" and "," to avoid having the
308838032Speter	**  NIS+ parser choke on them.
308938032Speter	*/
309038032Speter
3091168515Sgshapiro	skleft = sizeof(search_key) - 4;
309238032Speter	skp = search_key;
309338032Speter	for (p = name; *p != '\0' && skleft > 0; p++)
309438032Speter	{
309538032Speter		switch (*p)
309638032Speter		{
309738032Speter		  case ']':
309838032Speter		  case ',':
309938032Speter			/* quote the character */
310038032Speter			*skp++ = '"';
310138032Speter			*skp++ = *p;
310238032Speter			*skp++ = '"';
310338032Speter			skleft -= 3;
310438032Speter			break;
310538032Speter
310638032Speter		  case '"':
310738032Speter			/* double the quote */
310838032Speter			*skp++ = '"';
310938032Speter			skleft--;
311064562Sgshapiro			/* FALLTHROUGH */
311138032Speter
311238032Speter		  default:
311338032Speter			*skp++ = *p;
311438032Speter			skleft--;
311538032Speter			break;
311638032Speter		}
311738032Speter	}
311838032Speter	*skp = '\0';
311938032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
312038032Speter		makelower(search_key);
312138032Speter
312238032Speter	/* construct the query */
312338032Speter	if (PARTIAL_NAME(map->map_file))
3124168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf), "[%s=%s],%s.%s",
312538032Speter			map->map_keycolnm, search_key, map->map_file,
312638032Speter			map->map_domain);
312738032Speter	else
3128168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf), "[%s=%s],%s",
312938032Speter			map->map_keycolnm, search_key, map->map_file);
313038032Speter
313138032Speter	if (tTd(38, 20))
313290792Sgshapiro		sm_dprintf("qbuf=%s\n", qbuf);
313338032Speter	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
313438032Speter	if (result->status == NIS_SUCCESS)
313538032Speter	{
313638032Speter		int count;
313738032Speter		char *str;
313838032Speter
313938032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
314038032Speter		{
314138032Speter			if (LogLevel > 10)
314238032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
314364562Sgshapiro					  "%s: lookup error, expected 1 entry, got %d",
314464562Sgshapiro					  map->map_file, count);
314538032Speter
314638032Speter			/* ignore second entry */
314738032Speter			if (tTd(38, 20))
314890792Sgshapiro				sm_dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
314938032Speter					name, count);
315038032Speter		}
315138032Speter
315238032Speter		p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
315338032Speter		/* set the length of the result */
315438032Speter		if (p == NULL)
315538032Speter			p = "";
315638032Speter		vsize = strlen(p);
315738032Speter		if (tTd(38, 20))
315890792Sgshapiro			sm_dprintf("nisplus_map_lookup(%s), found %s\n",
315938032Speter				name, p);
316038032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
316138032Speter			str = map_rewrite(map, name, strlen(name), NULL);
316238032Speter		else
316338032Speter			str = map_rewrite(map, p, vsize, av);
316438032Speter		nis_freeresult(result);
316538032Speter		*statp = EX_OK;
316638032Speter		return str;
316738032Speter	}
316838032Speter	else
316938032Speter	{
317038032Speter		if (result->status == NIS_NOTFOUND)
317138032Speter			*statp = EX_NOTFOUND;
317238032Speter		else if (result->status == NIS_TRYAGAIN)
317338032Speter			*statp = EX_TEMPFAIL;
317438032Speter		else
317538032Speter		{
317638032Speter			*statp = EX_UNAVAILABLE;
317738032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
317838032Speter		}
317938032Speter	}
318038032Speter	if (tTd(38, 20))
318190792Sgshapiro		sm_dprintf("nisplus_map_lookup(%s), failed\n", name);
318238032Speter	nis_freeresult(result);
318338032Speter	return NULL;
318438032Speter}
318538032Speter
318638032Speter
318738032Speter
318838032Speter/*
318938032Speter**  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
319038032Speter*/
319138032Speter
319264562Sgshapirostatic bool
319338032Speternisplus_getcanonname(name, hbsize, statp)
319438032Speter	char *name;
319538032Speter	int hbsize;
319638032Speter	int *statp;
319738032Speter{
319838032Speter	char *vp;
319938032Speter	auto int vsize;
320038032Speter	nis_result *result;
320138032Speter	char *p;
320238032Speter	char nbuf[MAXNAME + 1];
320338032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
320438032Speter
3205168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
320638032Speter	{
320738032Speter		*statp = EX_UNAVAILABLE;
320890792Sgshapiro		return false;
320938032Speter	}
321073188Sgshapiro	(void) shorten_hostname(nbuf);
321138032Speter
321238032Speter	p = strchr(nbuf, '.');
321338032Speter	if (p == NULL)
321438032Speter	{
321538032Speter		/* single token */
3216168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf),
321790792Sgshapiro			"[name=%s],hosts.org_dir", nbuf);
321838032Speter	}
321938032Speter	else if (p[1] != '\0')
322038032Speter	{
322138032Speter		/* multi token -- take only first token in nbuf */
322238032Speter		*p = '\0';
3223168515Sgshapiro		(void) sm_snprintf(qbuf, sizeof(qbuf),
322490792Sgshapiro				   "[name=%s],hosts.org_dir.%s", nbuf, &p[1]);
322538032Speter	}
322638032Speter	else
322738032Speter	{
322838032Speter		*statp = EX_NOHOST;
322990792Sgshapiro		return false;
323038032Speter	}
323138032Speter
323238032Speter	if (tTd(38, 20))
323394334Sgshapiro		sm_dprintf("\nnisplus_getcanonname(%s), qbuf=%s\n",
323490792Sgshapiro			   name, qbuf);
323538032Speter
323638032Speter	result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
323790792Sgshapiro			  NULL, NULL);
323838032Speter
323938032Speter	if (result->status == NIS_SUCCESS)
324038032Speter	{
324138032Speter		int count;
324238032Speter		char *domain;
324338032Speter
324438032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
324538032Speter		{
324638032Speter			if (LogLevel > 10)
324738032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
324864562Sgshapiro					  "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
324964562Sgshapiro					  count);
325038032Speter
325138032Speter			/* ignore second entry */
325238032Speter			if (tTd(38, 20))
325394334Sgshapiro				sm_dprintf("nisplus_getcanonname(%s), got %d entries, all but first ignored\n",
325490792Sgshapiro					   name, count);
325538032Speter		}
325638032Speter
325738032Speter		if (tTd(38, 20))
325894334Sgshapiro			sm_dprintf("nisplus_getcanonname(%s), found in directory \"%s\"\n",
325990792Sgshapiro				   name, (NIS_RES_OBJECT(result))->zo_domain);
326038032Speter
326138032Speter
326238032Speter		vp = ((NIS_RES_OBJECT(result))->EN_col(0));
326338032Speter		vsize = strlen(vp);
326438032Speter		if (tTd(38, 20))
326590792Sgshapiro			sm_dprintf("nisplus_getcanonname(%s), found %s\n",
326690792Sgshapiro				   name, vp);
326738032Speter		if (strchr(vp, '.') != NULL)
326838032Speter		{
326938032Speter			domain = "";
327038032Speter		}
327138032Speter		else
327238032Speter		{
327338032Speter			domain = macvalue('m', CurEnv);
327438032Speter			if (domain == NULL)
327538032Speter				domain = "";
327638032Speter		}
327738032Speter		if (hbsize > vsize + (int) strlen(domain) + 1)
327838032Speter		{
327938032Speter			if (domain[0] == '\0')
328090792Sgshapiro				(void) sm_strlcpy(name, vp, hbsize);
328138032Speter			else
328290792Sgshapiro				(void) sm_snprintf(name, hbsize,
328390792Sgshapiro						   "%s.%s", vp, domain);
328438032Speter			*statp = EX_OK;
328538032Speter		}
328638032Speter		else
328738032Speter			*statp = EX_NOHOST;
328838032Speter		nis_freeresult(result);
328990792Sgshapiro		return true;
329038032Speter	}
329138032Speter	else
329238032Speter	{
329338032Speter		if (result->status == NIS_NOTFOUND)
329438032Speter			*statp = EX_NOHOST;
329538032Speter		else if (result->status == NIS_TRYAGAIN)
329638032Speter			*statp = EX_TEMPFAIL;
329738032Speter		else
329838032Speter			*statp = EX_UNAVAILABLE;
329938032Speter	}
330038032Speter	if (tTd(38, 20))
330190792Sgshapiro		sm_dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
330290792Sgshapiro			   name, result->status, *statp);
330338032Speter	nis_freeresult(result);
330490792Sgshapiro	return false;
330538032Speter}
330638032Speter
330738032Speterchar *
330838032Speternisplus_default_domain()
330938032Speter{
331038032Speter	static char default_domain[MAXNAME + 1] = "";
331138032Speter	char *p;
331238032Speter
331338032Speter	if (default_domain[0] != '\0')
331464562Sgshapiro		return default_domain;
331538032Speter
331638032Speter	p = nis_local_directory();
3317168515Sgshapiro	(void) sm_strlcpy(default_domain, p, sizeof(default_domain));
331838032Speter	return default_domain;
331938032Speter}
332038032Speter
332138032Speter#endif /* NISPLUS */
332290792Sgshapiro/*
332338032Speter**  LDAP Modules
332438032Speter*/
332538032Speter
332664562Sgshapiro/*
332764562Sgshapiro**  LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs
332864562Sgshapiro*/
332964562Sgshapiro
333064562Sgshapiro#if defined(LDAPMAP) || defined(PH_MAP)
333164562Sgshapiro
333290792Sgshapiro# if PH_MAP
333364562Sgshapiro#  define ph_map_dequote ldapmap_dequote
333464562Sgshapiro# endif /* PH_MAP */
333564562Sgshapiro
333690792Sgshapirostatic char *ldapmap_dequote __P((char *));
333790792Sgshapiro
333890792Sgshapirostatic char *
333964562Sgshapiroldapmap_dequote(str)
334064562Sgshapiro	char *str;
334164562Sgshapiro{
334264562Sgshapiro	char *p;
334364562Sgshapiro	char *start;
334464562Sgshapiro
334564562Sgshapiro	if (str == NULL)
334664562Sgshapiro		return NULL;
334764562Sgshapiro
334864562Sgshapiro	p = str;
334964562Sgshapiro	if (*p == '"')
335064562Sgshapiro	{
335164562Sgshapiro		/* Should probably swallow initial whitespace here */
335264562Sgshapiro		start = ++p;
335364562Sgshapiro	}
335464562Sgshapiro	else
335564562Sgshapiro		return str;
335664562Sgshapiro	while (*p != '"' && *p != '\0')
335764562Sgshapiro		p++;
335864562Sgshapiro	if (*p != '\0')
335964562Sgshapiro		*p = '\0';
336064562Sgshapiro	return start;
336164562Sgshapiro}
336264562Sgshapiro#endif /* defined(LDAPMAP) || defined(PH_MAP) */
336364562Sgshapiro
336490792Sgshapiro#if LDAPMAP
336538032Speter
336690792Sgshapirostatic SM_LDAP_STRUCT *LDAPDefaults = NULL;
336738032Speter
336838032Speter/*
336964562Sgshapiro**  LDAPMAP_OPEN -- open LDAP map
337038032Speter**
337164562Sgshapiro**	Connect to the LDAP server.  Re-use existing connections since a
337264562Sgshapiro**	single server connection to a host (with the same host, port,
337364562Sgshapiro**	bind DN, and secret) can answer queries for multiple maps.
337438032Speter*/
337538032Speter
337638032Speterbool
337764562Sgshapiroldapmap_open(map, mode)
337838032Speter	MAP *map;
337938032Speter	int mode;
338038032Speter{
338190792Sgshapiro	SM_LDAP_STRUCT *lmap;
338264562Sgshapiro	STAB *s;
3383132943Sgshapiro	char *id;
338464562Sgshapiro
338538032Speter	if (tTd(38, 2))
338690792Sgshapiro		sm_dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode);
338738032Speter
3388168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && \
3389168515Sgshapiro    HASLDAPGETALIASBYNAME
3390168515Sgshapiro	if (VendorCode == VENDOR_SUN &&
3391168515Sgshapiro	    strcmp(map->map_mname, "aliases.ldap") == 0)
3392168515Sgshapiro	{
3393168515Sgshapiro		return true;
3394168515Sgshapiro	}
3395168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && ... */
3396168515Sgshapiro
339738032Speter	mode &= O_ACCMODE;
339864562Sgshapiro
339964562Sgshapiro	/* sendmail doesn't have the ability to write to LDAP (yet) */
340038032Speter	if (mode != O_RDONLY)
340138032Speter	{
340238032Speter		/* issue a pseudo-error message */
340390792Sgshapiro		errno = SM_EMAPCANTWRITE;
340490792Sgshapiro		return false;
340538032Speter	}
340664562Sgshapiro
340790792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
340864562Sgshapiro
340964562Sgshapiro	s = ldapmap_findconn(lmap);
341077349Sgshapiro	if (s->s_lmap != NULL)
341164562Sgshapiro	{
341264562Sgshapiro		/* Already have a connection open to this LDAP server */
341390792Sgshapiro		lmap->ldap_ld = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_ld;
341490792Sgshapiro		lmap->ldap_pid = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_pid;
341577349Sgshapiro
341677349Sgshapiro		/* Add this map as head of linked list */
341777349Sgshapiro		lmap->ldap_next = s->s_lmap;
341877349Sgshapiro		s->s_lmap = map;
341977349Sgshapiro
342066494Sgshapiro		if (tTd(38, 2))
342190792Sgshapiro			sm_dprintf("using cached connection\n");
342290792Sgshapiro		return true;
342364562Sgshapiro	}
342464562Sgshapiro
342566494Sgshapiro	if (tTd(38, 2))
342690792Sgshapiro		sm_dprintf("opening new connection\n");
342766494Sgshapiro
3428132943Sgshapiro	if (lmap->ldap_host != NULL)
3429132943Sgshapiro		id = lmap->ldap_host;
3430132943Sgshapiro	else if (lmap->ldap_uri != NULL)
3431132943Sgshapiro		id = lmap->ldap_uri;
3432132943Sgshapiro	else
3433132943Sgshapiro		id = "localhost";
3434132943Sgshapiro
3435203004Sgshapiro	if (tTd(74, 104))
3436203004Sgshapiro	{
3437203004Sgshapiro		extern MAPCLASS NullMapClass;
3438203004Sgshapiro
3439203004Sgshapiro		/* debug mode: don't actually open an LDAP connection */
3440203004Sgshapiro		map->map_orgclass = map->map_class;
3441203004Sgshapiro		map->map_class = &NullMapClass;
3442203004Sgshapiro		map->map_mflags |= MF_OPEN;
3443203004Sgshapiro		map->map_pid = CurrentPid;
3444203004Sgshapiro		return true;
3445203004Sgshapiro	}
3446203004Sgshapiro
344764562Sgshapiro	/* No connection yet, connect */
344890792Sgshapiro	if (!sm_ldap_start(map->map_mname, lmap))
344938032Speter	{
345090792Sgshapiro		if (errno == ETIMEDOUT)
345138032Speter		{
345238032Speter			if (LogLevel > 1)
345338032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
3454244833Sgshapiro					  "timeout connecting to LDAP server %.100s",
3455132943Sgshapiro					  id);
345638032Speter		}
345738032Speter
345838032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
345938032Speter		{
346064562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
3461132943Sgshapiro			{
346264562Sgshapiro				syserr("%s failed to %s in map %s",
346364562Sgshapiro# if USE_LDAP_INIT
346490792Sgshapiro				       "ldap_init/ldap_bind",
346564562Sgshapiro# else /* USE_LDAP_INIT */
346664562Sgshapiro				       "ldap_open",
346764562Sgshapiro# endif /* USE_LDAP_INIT */
3468132943Sgshapiro				       id, map->map_mname);
3469132943Sgshapiro			}
347064562Sgshapiro			else
3471132943Sgshapiro			{
347294334Sgshapiro				syserr("451 4.3.5 %s failed to %s in map %s",
347364562Sgshapiro# if USE_LDAP_INIT
347490792Sgshapiro				       "ldap_init/ldap_bind",
347564562Sgshapiro# else /* USE_LDAP_INIT */
347664562Sgshapiro				       "ldap_open",
347764562Sgshapiro# endif /* USE_LDAP_INIT */
3478132943Sgshapiro				       id, map->map_mname);
3479132943Sgshapiro			}
348038032Speter		}
348190792Sgshapiro		return false;
348238032Speter	}
348338032Speter
348490792Sgshapiro	/* Save connection for reuse */
348590792Sgshapiro	s->s_lmap = map;
348690792Sgshapiro	return true;
348738032Speter}
348838032Speter
348938032Speter/*
349064562Sgshapiro**  LDAPMAP_CLOSE -- close ldap map
349138032Speter*/
349238032Speter
349338032Spetervoid
349464562Sgshapiroldapmap_close(map)
349538032Speter	MAP *map;
349638032Speter{
349790792Sgshapiro	SM_LDAP_STRUCT *lmap;
349864562Sgshapiro	STAB *s;
349943730Speter
350064562Sgshapiro	if (tTd(38, 2))
350190792Sgshapiro		sm_dprintf("ldapmap_close(%s)\n", map->map_mname);
350264562Sgshapiro
350390792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
350464562Sgshapiro
350564562Sgshapiro	/* Check if already closed */
350664562Sgshapiro	if (lmap->ldap_ld == NULL)
350764562Sgshapiro		return;
350864562Sgshapiro
350977349Sgshapiro	/* Close the LDAP connection */
351090792Sgshapiro	sm_ldap_close(lmap);
351177349Sgshapiro
351277349Sgshapiro	/* Mark all the maps that share the connection as closed */
351364562Sgshapiro	s = ldapmap_findconn(lmap);
351464562Sgshapiro
351577349Sgshapiro	while (s->s_lmap != NULL)
351677349Sgshapiro	{
351777349Sgshapiro		MAP *smap = s->s_lmap;
351864562Sgshapiro
351977349Sgshapiro		if (tTd(38, 2) && smap != map)
352090792Sgshapiro			sm_dprintf("ldapmap_close(%s): closed %s (shared LDAP connection)\n",
352190792Sgshapiro				   map->map_mname, smap->map_mname);
352277349Sgshapiro		smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
352390792Sgshapiro		lmap = (SM_LDAP_STRUCT *) smap->map_db1;
352464562Sgshapiro		lmap->ldap_ld = NULL;
352577349Sgshapiro		s->s_lmap = lmap->ldap_next;
352677349Sgshapiro		lmap->ldap_next = NULL;
352743730Speter	}
352838032Speter}
352938032Speter
353064562Sgshapiro# ifdef SUNET_ID
353143730Speter/*
353290792Sgshapiro**  SUNET_ID_HASH -- Convert a string to its Sunet_id canonical form
353342575Speter**  This only makes sense at Stanford University.
353438032Speter*/
353538032Speter
353690792Sgshapirostatic char *
353738032Spetersunet_id_hash(str)
353838032Speter	char *str;
353938032Speter{
354038032Speter	char *p, *p_last;
354138032Speter
354238032Speter	p = str;
354338032Speter	p_last = p;
354438032Speter	while (*p != '\0')
354538032Speter	{
3546203004Sgshapiro		if (isascii(*p) && (islower(*p) || isdigit(*p)))
354738032Speter		{
354838032Speter			*p_last = *p;
354938032Speter			p_last++;
355038032Speter		}
3551203004Sgshapiro		else if (isascii(*p) && isupper(*p))
355238032Speter		{
355338032Speter			*p_last = tolower(*p);
355438032Speter			p_last++;
355538032Speter		}
355638032Speter		++p;
355738032Speter	}
355838032Speter	if (*p_last != '\0')
355938032Speter		*p_last = '\0';
356064562Sgshapiro	return str;
356138032Speter}
3562168515Sgshapiro#  define SM_CONVERT_ID(str)	sunet_id_hash(str)
3563168515Sgshapiro# else /* SUNET_ID */
3564168515Sgshapiro#  define SM_CONVERT_ID(str)	makelower(str)
356564562Sgshapiro# endif /* SUNET_ID */
356638032Speter
356738032Speter/*
356864562Sgshapiro**  LDAPMAP_LOOKUP -- look up a datum in a LDAP map
356938032Speter*/
357038032Speter
357138032Speterchar *
357264562Sgshapiroldapmap_lookup(map, name, av, statp)
357338032Speter	MAP *map;
357438032Speter	char *name;
357538032Speter	char **av;
357638032Speter	int *statp;
357738032Speter{
3578132943Sgshapiro	int flags;
3579168515Sgshapiro	int i;
358094334Sgshapiro	int plen = 0;
358194334Sgshapiro	int psize = 0;
358264562Sgshapiro	int msgid;
358390792Sgshapiro	int save_errno;
358490792Sgshapiro	char *vp, *p;
358564562Sgshapiro	char *result = NULL;
3586132943Sgshapiro	SM_RPOOL_T *rpool;
358790792Sgshapiro	SM_LDAP_STRUCT *lmap = NULL;
3588168515Sgshapiro	char *argv[SM_LDAP_ARGS];
3589157001Sgshapiro	char keybuf[MAXKEY];
3590168515Sgshapiro#if SM_LDAP_ARGS != MAX_MAP_ARGS
3591168515Sgshapiro# ERROR _SM_LDAP_ARGS must be the same as _MAX_MAP_ARGS
3592168515Sgshapiro#endif /* SM_LDAP_ARGS != MAX_MAP_ARGS */
359338032Speter
3594168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && \
3595168515Sgshapiro    HASLDAPGETALIASBYNAME
3596168515Sgshapiro	if (VendorCode == VENDOR_SUN &&
3597168515Sgshapiro	    strcmp(map->map_mname, "aliases.ldap") == 0)
3598168515Sgshapiro	{
3599168515Sgshapiro		int rc;
3600173340Sgshapiro#if defined(GETLDAPALIASBYNAME_VERSION) && (GETLDAPALIASBYNAME_VERSION >= 2)
3601173340Sgshapiro		extern char *__getldapaliasbyname();
3602173340Sgshapiro		char *answer;
360338032Speter
3604173340Sgshapiro		answer = __getldapaliasbyname(name, &rc);
3605173340Sgshapiro#else
3606173340Sgshapiro		char answer[MAXNAME + 1];
3607173340Sgshapiro
3608168515Sgshapiro		rc = __getldapaliasbyname(name, answer, sizeof(answer));
3609173340Sgshapiro#endif
3610168515Sgshapiro		if (rc != 0)
3611168515Sgshapiro		{
3612168515Sgshapiro			if (tTd(38, 20))
3613168515Sgshapiro				sm_dprintf("getldapaliasbyname(%.100s) failed, errno=%d\n",
3614168515Sgshapiro					   name, errno);
3615168515Sgshapiro			*statp = EX_NOTFOUND;
3616168515Sgshapiro			return NULL;
3617168515Sgshapiro		}
3618168515Sgshapiro		*statp = EX_OK;
3619168515Sgshapiro		if (tTd(38, 20))
3620168515Sgshapiro			sm_dprintf("getldapaliasbyname(%.100s) => %s\n", name,
3621168515Sgshapiro				   answer);
3622168515Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
3623168515Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
3624168515Sgshapiro		else
3625168515Sgshapiro			result = map_rewrite(map, answer, strlen(answer), av);
3626173340Sgshapiro#if defined(GETLDAPALIASBYNAME_VERSION) && (GETLDAPALIASBYNAME_VERSION >= 2)
3627173340Sgshapiro		free(answer);
3628173340Sgshapiro#endif
3629168515Sgshapiro		return result;
3630168515Sgshapiro	}
3631168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && ... */
3632168515Sgshapiro
363338032Speter	/* Get ldap struct pointer from map */
363490792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
363590792Sgshapiro	sm_ldap_setopts(lmap->ldap_ld, lmap);
363638032Speter
3637168515Sgshapiro	if (lmap->ldap_multi_args)
3638168515Sgshapiro	{
3639168515Sgshapiro		SM_REQUIRE(av != NULL);
3640168515Sgshapiro		memset(argv, '\0', sizeof(argv));
3641168515Sgshapiro		for (i = 0; i < SM_LDAP_ARGS && av[i] != NULL; i++)
3642168515Sgshapiro		{
3643168515Sgshapiro			argv[i] = sm_strdup(av[i]);
3644168515Sgshapiro			if (argv[i] == NULL)
3645168515Sgshapiro			{
3646168515Sgshapiro				int save_errno, j;
364738032Speter
3648168515Sgshapiro				save_errno = errno;
3649168515Sgshapiro				for (j = 0; j < i && argv[j] != NULL; j++)
3650168515Sgshapiro					SM_FREE(argv[j]);
3651168515Sgshapiro				*statp = EX_TEMPFAIL;
3652168515Sgshapiro				errno = save_errno;
3653168515Sgshapiro				return NULL;
3654168515Sgshapiro			}
3655168515Sgshapiro
3656168515Sgshapiro			if (!bitset(MF_NOFOLDCASE, map->map_mflags))
3657168515Sgshapiro				SM_CONVERT_ID(av[i]);
3658168515Sgshapiro		}
3659168515Sgshapiro	}
3660168515Sgshapiro	else
366164562Sgshapiro	{
3662168515Sgshapiro		(void) sm_strlcpy(keybuf, name, sizeof(keybuf));
3663168515Sgshapiro
3664168515Sgshapiro		if (!bitset(MF_NOFOLDCASE, map->map_mflags))
3665168515Sgshapiro			SM_CONVERT_ID(keybuf);
366664562Sgshapiro	}
366738032Speter
3668168515Sgshapiro	if (tTd(38, 20))
366938032Speter	{
3670168515Sgshapiro		if (lmap->ldap_multi_args)
3671168515Sgshapiro		{
3672168515Sgshapiro			sm_dprintf("ldapmap_lookup(%s, argv)\n",
3673168515Sgshapiro				map->map_mname);
3674168515Sgshapiro			for (i = 0; i < SM_LDAP_ARGS; i++)
3675168515Sgshapiro			{
3676168515Sgshapiro				sm_dprintf("   argv[%d] = %s\n", i,
3677168515Sgshapiro					   argv[i] == NULL ? "NULL" : argv[i]);
3678168515Sgshapiro			}
3679168515Sgshapiro		}
3680168515Sgshapiro		else
3681168515Sgshapiro		{
3682168515Sgshapiro			sm_dprintf("ldapmap_lookup(%s, %s)\n",
3683168515Sgshapiro				   map->map_mname, name);
3684168515Sgshapiro		}
3685168515Sgshapiro	}
3686168515Sgshapiro
3687168515Sgshapiro	if (lmap->ldap_multi_args)
3688168515Sgshapiro	{
3689168515Sgshapiro		msgid = sm_ldap_search_m(lmap, argv);
3690168515Sgshapiro
3691168515Sgshapiro		/* free the argv array and its content, no longer needed */
3692168515Sgshapiro		for (i = 0; i < SM_LDAP_ARGS && argv[i] != NULL; i++)
3693168515Sgshapiro			SM_FREE(argv[i]);
3694168515Sgshapiro	}
3695168515Sgshapiro	else
3696168515Sgshapiro		msgid = sm_ldap_search(lmap, keybuf);
3697168515Sgshapiro	if (msgid == SM_LDAP_ERR)
3698168515Sgshapiro	{
369990792Sgshapiro		errno = sm_ldap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
370077349Sgshapiro		save_errno = errno;
370164562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
370238032Speter		{
3703168515Sgshapiro			/*
3704168515Sgshapiro			**  Do not include keybuf as this error may be shown
3705168515Sgshapiro			**  to outsiders.
3706168515Sgshapiro			*/
3707168515Sgshapiro
370864562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
3709168515Sgshapiro				syserr("Error in ldap_search in map %s",
3710168515Sgshapiro				       map->map_mname);
371164562Sgshapiro			else
3712168515Sgshapiro				syserr("451 4.3.5 Error in ldap_search in map %s",
3713168515Sgshapiro				       map->map_mname);
371438032Speter		}
371564562Sgshapiro		*statp = EX_TEMPFAIL;
371690792Sgshapiro		switch (save_errno - E_LDAPBASE)
371790792Sgshapiro		{
371894334Sgshapiro# ifdef LDAP_SERVER_DOWN
371990792Sgshapiro		  case LDAP_SERVER_DOWN:
372094334Sgshapiro# endif /* LDAP_SERVER_DOWN */
372190792Sgshapiro		  case LDAP_TIMEOUT:
372290792Sgshapiro		  case LDAP_UNAVAILABLE:
372366494Sgshapiro			/* server disappeared, try reopen on next search */
372477349Sgshapiro			ldapmap_close(map);
372590792Sgshapiro			break;
372666494Sgshapiro		}
372777349Sgshapiro		errno = save_errno;
372864562Sgshapiro		return NULL;
372964562Sgshapiro	}
3730168515Sgshapiro#if SM_LDAP_ERROR_ON_MISSING_ARGS
3731168515Sgshapiro	else if (msgid == SM_LDAP_ERR_ARG_MISS)
3732168515Sgshapiro	{
3733168515Sgshapiro		if (bitset(MF_NODEFER, map->map_mflags))
3734168515Sgshapiro			syserr("Error in ldap_search in map %s, too few arguments",
3735168515Sgshapiro			       map->map_mname);
3736168515Sgshapiro		else
3737168515Sgshapiro			syserr("554 5.3.5 Error in ldap_search in map %s, too few arguments",
3738168515Sgshapiro			       map->map_mname);
3739168515Sgshapiro		*statp = EX_CONFIG;
3740168515Sgshapiro		return NULL;
3741168515Sgshapiro	}
3742168515Sgshapiro#endif /* SM_LDAP_ERROR_ON_MISSING_ARGS */
374364562Sgshapiro
374464562Sgshapiro	*statp = EX_NOTFOUND;
374564562Sgshapiro	vp = NULL;
374664562Sgshapiro
3747132943Sgshapiro	flags = 0;
3748132943Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
3749132943Sgshapiro		flags |= SM_LDAP_SINGLEMATCH;
3750132943Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
3751132943Sgshapiro		flags |= SM_LDAP_MATCHONLY;
3752157001Sgshapiro# if _FFR_LDAP_SINGLEDN
3753157001Sgshapiro	if (bitset(MF_SINGLEDN, map->map_mflags))
3754157001Sgshapiro		flags |= SM_LDAP_SINGLEDN;
3755157001Sgshapiro# endif /* _FFR_LDAP_SINGLEDN */
375690792Sgshapiro
3757132943Sgshapiro	/* Create an rpool for search related memory usage */
3758132943Sgshapiro	rpool = sm_rpool_new_x(NULL);
375990792Sgshapiro
3760132943Sgshapiro	p = NULL;
3761132943Sgshapiro	*statp = sm_ldap_results(lmap, msgid, flags, map->map_coldelim,
3762132943Sgshapiro				 rpool, &p, &plen, &psize, NULL);
3763132943Sgshapiro	save_errno = errno;
376490792Sgshapiro
3765132943Sgshapiro	/* Copy result so rpool can be freed */
3766132943Sgshapiro	if (*statp == EX_OK && p != NULL)
3767132943Sgshapiro		vp = newstr(p);
3768132943Sgshapiro	sm_rpool_free(rpool);
376990792Sgshapiro
3770132943Sgshapiro	/* need to restart LDAP connection? */
3771132943Sgshapiro	if (*statp == EX_RESTART)
377264562Sgshapiro	{
3773132943Sgshapiro		*statp = EX_TEMPFAIL;
3774132943Sgshapiro		ldapmap_close(map);
377538032Speter	}
377638032Speter
3777132943Sgshapiro	errno = save_errno;
3778132943Sgshapiro	if (*statp != EX_OK && *statp != EX_NOTFOUND)
377938032Speter	{
378064562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
378164562Sgshapiro		{
378264562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
3783244833Sgshapiro				syserr("Error getting LDAP results, map=%s, name=%s",
3784244833Sgshapiro				       map->map_mname, name);
378564562Sgshapiro			else
3786244833Sgshapiro				syserr("451 4.3.5 Error getting LDAP results, map=%s, name=%s",
3787244833Sgshapiro				       map->map_mname, name);
378864562Sgshapiro		}
378977349Sgshapiro		errno = save_errno;
379064562Sgshapiro		return NULL;
379138032Speter	}
379290792Sgshapiro
379364562Sgshapiro	/* Did we match anything? */
379471345Sgshapiro	if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags))
379564562Sgshapiro		return NULL;
379638032Speter
379764562Sgshapiro	if (*statp == EX_OK)
379864562Sgshapiro	{
379964562Sgshapiro		if (LogLevel > 9)
380064562Sgshapiro			sm_syslog(LOG_INFO, CurEnv->e_id,
3801244833Sgshapiro				  "ldap=%s, %.100s=>%s", map->map_mname, name,
380271345Sgshapiro				  vp == NULL ? "<NULL>" : vp);
380364562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
380464562Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
380564562Sgshapiro		else
380671345Sgshapiro		{
380771345Sgshapiro			/* vp != NULL according to test above */
380864562Sgshapiro			result = map_rewrite(map, vp, strlen(vp), av);
380971345Sgshapiro		}
381071345Sgshapiro		if (vp != NULL)
381190792Sgshapiro			sm_free(vp); /* XXX */
381264562Sgshapiro	}
381364562Sgshapiro	return result;
381438032Speter}
381538032Speter
381638032Speter/*
381764562Sgshapiro**  LDAPMAP_FINDCONN -- find an LDAP connection to the server
381864562Sgshapiro**
381964562Sgshapiro**	Cache LDAP connections based on the host, port, bind DN,
382066494Sgshapiro**	secret, and PID so we don't have multiple connections open to
382166494Sgshapiro**	the same server for different maps.  Need a separate connection
382266494Sgshapiro**	per PID since a parent process may close the map before the
382366494Sgshapiro**	child is done with it.
382464562Sgshapiro**
382564562Sgshapiro**	Parameters:
382664562Sgshapiro**		lmap -- LDAP map information
382764562Sgshapiro**
382864562Sgshapiro**	Returns:
382964562Sgshapiro**		Symbol table entry for the LDAP connection.
383038032Speter*/
383138032Speter
383264562Sgshapirostatic STAB *
383364562Sgshapiroldapmap_findconn(lmap)
383490792Sgshapiro	SM_LDAP_STRUCT *lmap;
383538032Speter{
383694334Sgshapiro	char *format;
383764562Sgshapiro	char *nbuf;
3838132943Sgshapiro	char *id;
383990792Sgshapiro	STAB *SM_NONVOLATILE s = NULL;
384038032Speter
3841132943Sgshapiro	if (lmap->ldap_host != NULL)
3842132943Sgshapiro		id = lmap->ldap_host;
3843132943Sgshapiro	else if (lmap->ldap_uri != NULL)
3844132943Sgshapiro		id = lmap->ldap_uri;
3845132943Sgshapiro	else
3846132943Sgshapiro		id = "localhost";
3847132943Sgshapiro
384894334Sgshapiro	format = "%s%c%d%c%d%c%s%c%s%d";
384994334Sgshapiro	nbuf = sm_stringf_x(format,
3850132943Sgshapiro			    id,
385190792Sgshapiro			    CONDELSE,
385290792Sgshapiro			    lmap->ldap_port,
385390792Sgshapiro			    CONDELSE,
385494334Sgshapiro			    lmap->ldap_version,
385594334Sgshapiro			    CONDELSE,
385690792Sgshapiro			    (lmap->ldap_binddn == NULL ? ""
385790792Sgshapiro						       : lmap->ldap_binddn),
385890792Sgshapiro			    CONDELSE,
385990792Sgshapiro			    (lmap->ldap_secret == NULL ? ""
386090792Sgshapiro						       : lmap->ldap_secret),
386190792Sgshapiro			    (int) CurrentPid);
386290792Sgshapiro	SM_TRY
386390792Sgshapiro		s = stab(nbuf, ST_LMAP, ST_ENTER);
386490792Sgshapiro	SM_FINALLY
386590792Sgshapiro		sm_free(nbuf);
386690792Sgshapiro	SM_END_TRY
386764562Sgshapiro	return s;
386864562Sgshapiro}
386938032Speter/*
387064562Sgshapiro**  LDAPMAP_PARSEARGS -- parse ldap map definition args.
387164562Sgshapiro*/
387238032Speter
387390792Sgshapirostatic struct lamvalues LDAPAuthMethods[] =
387464562Sgshapiro{
387564562Sgshapiro	{	"none",		LDAP_AUTH_NONE		},
387664562Sgshapiro	{	"simple",	LDAP_AUTH_SIMPLE	},
387764562Sgshapiro# ifdef LDAP_AUTH_KRBV4
387864562Sgshapiro	{	"krbv4",	LDAP_AUTH_KRBV4		},
387964562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
388064562Sgshapiro	{	NULL,		0			}
388164562Sgshapiro};
388238032Speter
388390792Sgshapirostatic struct ladvalues LDAPAliasDereference[] =
388464562Sgshapiro{
388564562Sgshapiro	{	"never",	LDAP_DEREF_NEVER	},
388664562Sgshapiro	{	"always",	LDAP_DEREF_ALWAYS	},
388764562Sgshapiro	{	"search",	LDAP_DEREF_SEARCHING	},
388864562Sgshapiro	{	"find",		LDAP_DEREF_FINDING	},
388964562Sgshapiro	{	NULL,		0			}
389064562Sgshapiro};
389138032Speter
389290792Sgshapirostatic struct lssvalues LDAPSearchScope[] =
389364562Sgshapiro{
389464562Sgshapiro	{	"base",		LDAP_SCOPE_BASE		},
389564562Sgshapiro	{	"one",		LDAP_SCOPE_ONELEVEL	},
389664562Sgshapiro	{	"sub",		LDAP_SCOPE_SUBTREE	},
389764562Sgshapiro	{	NULL,		0			}
389864562Sgshapiro};
389938032Speter
390064562Sgshapirobool
390164562Sgshapiroldapmap_parseargs(map, args)
390264562Sgshapiro	MAP *map;
390364562Sgshapiro	char *args;
390464562Sgshapiro{
390590792Sgshapiro	bool secretread = true;
3906132943Sgshapiro	bool attrssetup = false;
390764562Sgshapiro	int i;
390864562Sgshapiro	register char *p = args;
390990792Sgshapiro	SM_LDAP_STRUCT *lmap;
391064562Sgshapiro	struct lamvalues *lam;
391164562Sgshapiro	struct ladvalues *lad;
391264562Sgshapiro	struct lssvalues *lss;
391390792Sgshapiro	char ldapfilt[MAXLINE];
391464562Sgshapiro	char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
391564562Sgshapiro
391664562Sgshapiro	/* Get ldap struct pointer from map */
391790792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
391864562Sgshapiro
391964562Sgshapiro	/* Check if setting the initial LDAP defaults */
392064562Sgshapiro	if (lmap == NULL || lmap != LDAPDefaults)
392164562Sgshapiro	{
392290792Sgshapiro		/* We need to alloc an SM_LDAP_STRUCT struct */
3923168515Sgshapiro		lmap = (SM_LDAP_STRUCT *) xalloc(sizeof(*lmap));
392464562Sgshapiro		if (LDAPDefaults == NULL)
392590792Sgshapiro			sm_ldap_clear(lmap);
392664562Sgshapiro		else
392764562Sgshapiro			STRUCTCOPY(*LDAPDefaults, *lmap);
392864562Sgshapiro	}
392964562Sgshapiro
393064562Sgshapiro	/* there is no check whether there is really an argument */
393164562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
393264562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
393390792Sgshapiro
393490792Sgshapiro	/* Check if setting up an alias or file class LDAP map */
393590792Sgshapiro	if (bitset(MF_ALIAS, map->map_mflags))
393690792Sgshapiro	{
393790792Sgshapiro		/* Comma separate if used as an alias file */
393890792Sgshapiro		map->map_coldelim = ',';
393990792Sgshapiro		if (*args == '\0')
394090792Sgshapiro		{
394190792Sgshapiro			int n;
394290792Sgshapiro			char *lc;
394390792Sgshapiro			char jbuf[MAXHOSTNAMELEN];
394490792Sgshapiro			char lcbuf[MAXLINE];
394590792Sgshapiro
394690792Sgshapiro			/* Get $j */
3947168515Sgshapiro			expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope);
394890792Sgshapiro			if (jbuf[0] == '\0')
394990792Sgshapiro			{
395090792Sgshapiro				(void) sm_strlcpy(jbuf, "localhost",
3951168515Sgshapiro						  sizeof(jbuf));
395290792Sgshapiro			}
395390792Sgshapiro
395490792Sgshapiro			lc = macvalue(macid("{sendmailMTACluster}"), CurEnv);
395590792Sgshapiro			if (lc == NULL)
395690792Sgshapiro				lc = "";
395790792Sgshapiro			else
395890792Sgshapiro			{
3959168515Sgshapiro				expand(lc, lcbuf, sizeof(lcbuf), CurEnv);
396090792Sgshapiro				lc = lcbuf;
396190792Sgshapiro			}
396290792Sgshapiro
3963168515Sgshapiro			n = sm_snprintf(ldapfilt, sizeof(ldapfilt),
396490792Sgshapiro					"(&(objectClass=sendmailMTAAliasObject)(sendmailMTAAliasGrouping=aliases)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))(sendmailMTAKey=%%0))",
396590792Sgshapiro					lc, jbuf);
3966168515Sgshapiro			if (n >= sizeof(ldapfilt))
396790792Sgshapiro			{
396890792Sgshapiro				syserr("%s: Default LDAP string too long",
396990792Sgshapiro				       map->map_mname);
397090792Sgshapiro				return false;
397190792Sgshapiro			}
397290792Sgshapiro
397390792Sgshapiro			/* default args for an alias LDAP entry */
397490792Sgshapiro			lmap->ldap_filter = ldapfilt;
3975132943Sgshapiro			lmap->ldap_attr[0] = "objectClass";
3976132943Sgshapiro			lmap->ldap_attr_type[0] = SM_LDAP_ATTR_OBJCLASS;
3977132943Sgshapiro			lmap->ldap_attr_needobjclass[0] = NULL;
3978132943Sgshapiro			lmap->ldap_attr[1] = "sendmailMTAAliasValue";
3979132943Sgshapiro			lmap->ldap_attr_type[1] = SM_LDAP_ATTR_NORMAL;
3980132943Sgshapiro			lmap->ldap_attr_needobjclass[1] = NULL;
3981132943Sgshapiro			lmap->ldap_attr[2] = "sendmailMTAAliasSearch";
3982132943Sgshapiro			lmap->ldap_attr_type[2] = SM_LDAP_ATTR_FILTER;
3983132943Sgshapiro			lmap->ldap_attr_needobjclass[2] = "sendmailMTAMapObject";
3984132943Sgshapiro			lmap->ldap_attr[3] = "sendmailMTAAliasURL";
3985132943Sgshapiro			lmap->ldap_attr_type[3] = SM_LDAP_ATTR_URL;
3986132943Sgshapiro			lmap->ldap_attr_needobjclass[3] = "sendmailMTAMapObject";
3987132943Sgshapiro			lmap->ldap_attr[4] = NULL;
3988132943Sgshapiro			lmap->ldap_attr_type[4] = SM_LDAP_ATTR_NONE;
3989132943Sgshapiro			lmap->ldap_attr_needobjclass[4] = NULL;
3990132943Sgshapiro			attrssetup = true;
399190792Sgshapiro		}
399290792Sgshapiro	}
399390792Sgshapiro	else if (bitset(MF_FILECLASS, map->map_mflags))
399490792Sgshapiro	{
399590792Sgshapiro		/* Space separate if used as a file class file */
399690792Sgshapiro		map->map_coldelim = ' ';
399790792Sgshapiro	}
399890792Sgshapiro
3999203004Sgshapiro# if _FFR_LDAP_NETWORK_TIMEOUT
4000203004Sgshapiro	lmap->ldap_networktmo = 120;
4001203004Sgshapiro# endif /* _FFR_LDAP_NETWORK_TIMEOUT */
4002203004Sgshapiro
400338032Speter	for (;;)
400438032Speter	{
400538032Speter		while (isascii(*p) && isspace(*p))
400638032Speter			p++;
400738032Speter		if (*p != '-')
400838032Speter			break;
400938032Speter		switch (*++p)
401038032Speter		{
4011173340Sgshapiro		  case 'A':
4012173340Sgshapiro			map->map_mflags |= MF_APPEND;
401338032Speter			break;
401438032Speter
4015173340Sgshapiro		  case 'a':
4016173340Sgshapiro			map->map_app = ++p;
401738032Speter			break;
401838032Speter
4019173340Sgshapiro		  case 'D':
4020173340Sgshapiro			map->map_mflags |= MF_DEFER;
402138032Speter			break;
402238032Speter
402338032Speter		  case 'f':
402438032Speter			map->map_mflags |= MF_NOFOLDCASE;
402538032Speter			break;
402638032Speter
402738032Speter		  case 'm':
402838032Speter			map->map_mflags |= MF_MATCHONLY;
402938032Speter			break;
403038032Speter
4031173340Sgshapiro		  case 'N':
4032173340Sgshapiro			map->map_mflags |= MF_INCLNULL;
4033173340Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
403438032Speter			break;
403538032Speter
4036173340Sgshapiro		  case 'O':
4037173340Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
4038173340Sgshapiro			break;
4039173340Sgshapiro
4040173340Sgshapiro		  case 'o':
4041173340Sgshapiro			map->map_mflags |= MF_OPTIONAL;
4042173340Sgshapiro			break;
4043173340Sgshapiro
404438032Speter		  case 'q':
404538032Speter			map->map_mflags |= MF_KEEPQUOTES;
404638032Speter			break;
404738032Speter
4048173340Sgshapiro		  case 'S':
4049173340Sgshapiro			map->map_spacesub = *++p;
405038032Speter			break;
405138032Speter
405238032Speter		  case 'T':
405338032Speter			map->map_tapp = ++p;
405438032Speter			break;
405538032Speter
405664562Sgshapiro		  case 't':
405764562Sgshapiro			map->map_mflags |= MF_NODEFER;
405864562Sgshapiro			break;
405964562Sgshapiro
406064562Sgshapiro		  case 'z':
406164562Sgshapiro			if (*++p != '\\')
406264562Sgshapiro				map->map_coldelim = *p;
406364562Sgshapiro			else
406464562Sgshapiro			{
406564562Sgshapiro				switch (*++p)
406664562Sgshapiro				{
406764562Sgshapiro				  case 'n':
406864562Sgshapiro					map->map_coldelim = '\n';
406964562Sgshapiro					break;
407064562Sgshapiro
407164562Sgshapiro				  case 't':
407264562Sgshapiro					map->map_coldelim = '\t';
407364562Sgshapiro					break;
407464562Sgshapiro
407564562Sgshapiro				  default:
407664562Sgshapiro					map->map_coldelim = '\\';
407764562Sgshapiro				}
407864562Sgshapiro			}
407964562Sgshapiro			break;
408064562Sgshapiro
408164562Sgshapiro			/* Start of ldapmap specific args */
4082173340Sgshapiro		  case '1':
4083173340Sgshapiro			map->map_mflags |= MF_SINGLEMATCH;
4084173340Sgshapiro			break;
408590792Sgshapiro
4086173340Sgshapiro# if _FFR_LDAP_SINGLEDN
4087173340Sgshapiro		  case '2':
4088173340Sgshapiro			map->map_mflags |= MF_SINGLEDN;
4089173340Sgshapiro			break;
4090173340Sgshapiro# endif /* _FFR_LDAP_SINGLEDN */
409190792Sgshapiro
4092173340Sgshapiro		  case 'b':		/* search base */
4093173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4094173340Sgshapiro				continue;
4095173340Sgshapiro			lmap->ldap_base = p;
4096173340Sgshapiro			break;
4097173340Sgshapiro
4098173340Sgshapiro# if _FFR_LDAP_NETWORK_TIMEOUT
4099173340Sgshapiro		  case 'c':		/* network (connect) timeout */
4100173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4101173340Sgshapiro				continue;
4102203004Sgshapiro			lmap->ldap_networktmo = atoi(p);
4103173340Sgshapiro			break;
4104173340Sgshapiro# endif /* _FFR_LDAP_NETWORK_TIMEOUT */
4105173340Sgshapiro
4106173340Sgshapiro		  case 'd':		/* Dn to bind to server as */
4107173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4108173340Sgshapiro				continue;
4109173340Sgshapiro			lmap->ldap_binddn = p;
4110173340Sgshapiro			break;
4111173340Sgshapiro
4112173340Sgshapiro		  case 'H':		/* Use LDAP URI */
4113173340Sgshapiro#  if !USE_LDAP_INIT
4114173340Sgshapiro			syserr("Must compile with -DUSE_LDAP_INIT to use LDAP URIs (-H) in map %s",
4115173340Sgshapiro			       map->map_mname);
4116173340Sgshapiro			return false;
4117173340Sgshapiro#   else /* !USE_LDAP_INIT */
4118173340Sgshapiro			if (lmap->ldap_host != NULL)
4119173340Sgshapiro			{
4120173340Sgshapiro				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
4121173340Sgshapiro				       map->map_mname);
4122173340Sgshapiro				return false;
412390792Sgshapiro			}
4124173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4125173340Sgshapiro				continue;
4126173340Sgshapiro			lmap->ldap_uri = p;
412790792Sgshapiro			break;
4128173340Sgshapiro#  endif /* !USE_LDAP_INIT */
412990792Sgshapiro
4130173340Sgshapiro		  case 'h':		/* ldap host */
4131173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4132173340Sgshapiro				continue;
4133173340Sgshapiro			if (lmap->ldap_uri != NULL)
4134173340Sgshapiro			{
4135173340Sgshapiro				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
4136173340Sgshapiro				       map->map_mname);
4137173340Sgshapiro				return false;
4138173340Sgshapiro			}
4139173340Sgshapiro			lmap->ldap_host = p;
4140173340Sgshapiro			break;
4141173340Sgshapiro
4142173340Sgshapiro		  case 'K':
4143173340Sgshapiro			lmap->ldap_multi_args = true;
4144173340Sgshapiro			break;
4145173340Sgshapiro
414638032Speter		  case 'k':		/* search field */
414738032Speter			while (isascii(*++p) && isspace(*p))
414838032Speter				continue;
414964562Sgshapiro			lmap->ldap_filter = p;
415038032Speter			break;
415138032Speter
4152173340Sgshapiro		  case 'l':		/* time limit */
415338032Speter			while (isascii(*++p) && isspace(*p))
415438032Speter				continue;
4155173340Sgshapiro			lmap->ldap_timelimit = atoi(p);
4156173340Sgshapiro			lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit;
415738032Speter			break;
415838032Speter
4159173340Sgshapiro		  case 'M':		/* Method for binding */
4160173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4161173340Sgshapiro				continue;
4162173340Sgshapiro
4163173340Sgshapiro			if (sm_strncasecmp(p, "LDAP_AUTH_", 10) == 0)
4164173340Sgshapiro				p += 10;
4165173340Sgshapiro
4166173340Sgshapiro			for (lam = LDAPAuthMethods;
4167173340Sgshapiro			     lam != NULL && lam->lam_name != NULL; lam++)
4168173340Sgshapiro			{
4169173340Sgshapiro				if (sm_strncasecmp(p, lam->lam_name,
4170173340Sgshapiro						   strlen(lam->lam_name)) == 0)
4171173340Sgshapiro					break;
4172173340Sgshapiro			}
4173173340Sgshapiro			if (lam->lam_name != NULL)
4174173340Sgshapiro				lmap->ldap_method = lam->lam_code;
4175173340Sgshapiro			else
4176173340Sgshapiro			{
4177173340Sgshapiro				/* bad config line */
4178173340Sgshapiro				if (!bitset(MCF_OPTFILE,
4179173340Sgshapiro					    map->map_class->map_cflags))
4180173340Sgshapiro				{
4181173340Sgshapiro					char *ptr;
4182173340Sgshapiro
4183173340Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
4184173340Sgshapiro						*ptr = '\0';
4185173340Sgshapiro					syserr("Method for binding must be [none|simple|krbv4] (not %s) in map %s",
4186173340Sgshapiro						p, map->map_mname);
4187173340Sgshapiro					if (ptr != NULL)
4188173340Sgshapiro						*ptr = ' ';
4189173340Sgshapiro					return false;
4190173340Sgshapiro				}
4191173340Sgshapiro			}
419264562Sgshapiro			break;
419364562Sgshapiro
4194173340Sgshapiro		  case 'n':		/* retrieve attribute names only */
4195173340Sgshapiro			lmap->ldap_attrsonly = LDAPMAP_TRUE;
4196157001Sgshapiro			break;
4197157001Sgshapiro
4198173340Sgshapiro			/*
4199173340Sgshapiro			**  This is a string that is dependent on the
4200173340Sgshapiro			**  method used defined by 'M'.
4201173340Sgshapiro			*/
4202173340Sgshapiro
4203173340Sgshapiro		  case 'P':		/* Secret password for binding */
4204173340Sgshapiro			 while (isascii(*++p) && isspace(*p))
4205173340Sgshapiro				continue;
4206173340Sgshapiro			lmap->ldap_secret = p;
4207173340Sgshapiro			secretread = false;
4208173340Sgshapiro			break;
4209173340Sgshapiro
4210173340Sgshapiro		  case 'p':		/* ldap port */
4211173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4212173340Sgshapiro				continue;
4213173340Sgshapiro			lmap->ldap_port = atoi(p);
4214173340Sgshapiro			break;
4215173340Sgshapiro
421638032Speter			/* args stolen from ldapsearch.c */
421738032Speter		  case 'R':		/* don't auto chase referrals */
421864562Sgshapiro# ifdef LDAP_REFERRALS
421938032Speter			lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
422064562Sgshapiro# else /* LDAP_REFERRALS */
422190792Sgshapiro			syserr("compile with -DLDAP_REFERRALS for referral support");
422264562Sgshapiro# endif /* LDAP_REFERRALS */
422338032Speter			break;
422438032Speter
422564562Sgshapiro		  case 'r':		/* alias dereferencing */
422664562Sgshapiro			while (isascii(*++p) && isspace(*p))
422764562Sgshapiro				continue;
422864562Sgshapiro
422990792Sgshapiro			if (sm_strncasecmp(p, "LDAP_DEREF_", 11) == 0)
423064562Sgshapiro				p += 11;
423164562Sgshapiro
423264562Sgshapiro			for (lad = LDAPAliasDereference;
423364562Sgshapiro			     lad != NULL && lad->lad_name != NULL; lad++)
423438032Speter			{
423590792Sgshapiro				if (sm_strncasecmp(p, lad->lad_name,
423690792Sgshapiro						   strlen(lad->lad_name)) == 0)
423764562Sgshapiro					break;
423838032Speter			}
423964562Sgshapiro			if (lad->lad_name != NULL)
424064562Sgshapiro				lmap->ldap_deref = lad->lad_code;
424164562Sgshapiro			else
424238032Speter			{
424364562Sgshapiro				/* bad config line */
424464562Sgshapiro				if (!bitset(MCF_OPTFILE,
424564562Sgshapiro					    map->map_class->map_cflags))
424664562Sgshapiro				{
424764562Sgshapiro					char *ptr;
424864562Sgshapiro
424964562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
425064562Sgshapiro						*ptr = '\0';
425173188Sgshapiro					syserr("Deref must be [never|always|search|find] (not %s) in map %s",
425264562Sgshapiro						p, map->map_mname);
425364562Sgshapiro					if (ptr != NULL)
425464562Sgshapiro						*ptr = ' ';
425590792Sgshapiro					return false;
425664562Sgshapiro				}
425738032Speter			}
425864562Sgshapiro			break;
425964562Sgshapiro
426064562Sgshapiro		  case 's':		/* search scope */
426164562Sgshapiro			while (isascii(*++p) && isspace(*p))
426264562Sgshapiro				continue;
426364562Sgshapiro
426490792Sgshapiro			if (sm_strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
426564562Sgshapiro				p += 11;
426664562Sgshapiro
426764562Sgshapiro			for (lss = LDAPSearchScope;
426864562Sgshapiro			     lss != NULL && lss->lss_name != NULL; lss++)
426938032Speter			{
427090792Sgshapiro				if (sm_strncasecmp(p, lss->lss_name,
427190792Sgshapiro						   strlen(lss->lss_name)) == 0)
427264562Sgshapiro					break;
427338032Speter			}
427464562Sgshapiro			if (lss->lss_name != NULL)
427564562Sgshapiro				lmap->ldap_scope = lss->lss_code;
427638032Speter			else
427764562Sgshapiro			{
427864562Sgshapiro				/* bad config line */
427964562Sgshapiro				if (!bitset(MCF_OPTFILE,
428064562Sgshapiro					    map->map_class->map_cflags))
428138032Speter				{
428238032Speter					char *ptr;
428338032Speter
428438032Speter					if ((ptr = strchr(p, ' ')) != NULL)
428538032Speter						*ptr = '\0';
428673188Sgshapiro					syserr("Scope must be [base|one|sub] (not %s) in map %s",
428738032Speter						p, map->map_mname);
428838032Speter					if (ptr != NULL)
428938032Speter						*ptr = ' ';
429090792Sgshapiro					return false;
429138032Speter				}
429238032Speter			}
429338032Speter			break;
429438032Speter
4295173340Sgshapiro		  case 'V':
4296173340Sgshapiro			if (*++p != '\\')
4297173340Sgshapiro				lmap->ldap_attrsep = *p;
429864562Sgshapiro			else
429964562Sgshapiro			{
4300173340Sgshapiro				switch (*++p)
430164562Sgshapiro				{
4302173340Sgshapiro				  case 'n':
4303173340Sgshapiro					lmap->ldap_attrsep = '\n';
4304173340Sgshapiro					break;
430564562Sgshapiro
4306173340Sgshapiro				  case 't':
4307173340Sgshapiro					lmap->ldap_attrsep = '\t';
4308173340Sgshapiro					break;
4309173340Sgshapiro
4310173340Sgshapiro				  default:
4311173340Sgshapiro					lmap->ldap_attrsep = '\\';
431264562Sgshapiro				}
431364562Sgshapiro			}
431464562Sgshapiro			break;
431564562Sgshapiro
4316173340Sgshapiro		  case 'v':		/* attr to return */
431794334Sgshapiro			while (isascii(*++p) && isspace(*p))
431894334Sgshapiro				continue;
4319173340Sgshapiro			lmap->ldap_attr[0] = p;
4320173340Sgshapiro			lmap->ldap_attr[1] = NULL;
432194334Sgshapiro			break;
432294334Sgshapiro
432394334Sgshapiro		  case 'w':
432494334Sgshapiro			/* -w should be for passwd, -P should be for version */
432594334Sgshapiro			while (isascii(*++p) && isspace(*p))
432694334Sgshapiro				continue;
432794334Sgshapiro			lmap->ldap_version = atoi(p);
4328132943Sgshapiro# ifdef LDAP_VERSION_MAX
432994334Sgshapiro			if (lmap->ldap_version > LDAP_VERSION_MAX)
433094334Sgshapiro			{
433194334Sgshapiro				syserr("LDAP version %d exceeds max of %d in map %s",
433294334Sgshapiro				       lmap->ldap_version, LDAP_VERSION_MAX,
433394334Sgshapiro				       map->map_mname);
433494334Sgshapiro				return false;
433594334Sgshapiro			}
4336132943Sgshapiro# endif /* LDAP_VERSION_MAX */
4337132943Sgshapiro# ifdef LDAP_VERSION_MIN
433894334Sgshapiro			if (lmap->ldap_version < LDAP_VERSION_MIN)
433994334Sgshapiro			{
434094334Sgshapiro				syserr("LDAP version %d is lower than min of %d in map %s",
434194334Sgshapiro				       lmap->ldap_version, LDAP_VERSION_MIN,
434294334Sgshapiro				       map->map_mname);
434394334Sgshapiro				return false;
434494334Sgshapiro			}
4345132943Sgshapiro# endif /* LDAP_VERSION_MIN */
434694334Sgshapiro			break;
434794334Sgshapiro
4348173340Sgshapiro		  case 'Z':
4349173340Sgshapiro			while (isascii(*++p) && isspace(*p))
4350173340Sgshapiro				continue;
4351173340Sgshapiro			lmap->ldap_sizelimit = atoi(p);
4352168515Sgshapiro			break;
4353168515Sgshapiro
435464562Sgshapiro		  default:
435564562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
435664562Sgshapiro			break;
435738032Speter		}
435838032Speter
435964562Sgshapiro		/* need to account for quoted strings here */
436064562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
436138032Speter		{
436238032Speter			if (*p == '"')
436338032Speter			{
436438032Speter				while (*++p != '"' && *p != '\0')
436538032Speter					continue;
436638032Speter				if (*p != '\0')
436738032Speter					p++;
436838032Speter			}
436938032Speter			else
437038032Speter				p++;
437138032Speter		}
437238032Speter
437338032Speter		if (*p != '\0')
437438032Speter			*p++ = '\0';
437538032Speter	}
437638032Speter
437738032Speter	if (map->map_app != NULL)
437864562Sgshapiro		map->map_app = newstr(ldapmap_dequote(map->map_app));
437938032Speter	if (map->map_tapp != NULL)
438064562Sgshapiro		map->map_tapp = newstr(ldapmap_dequote(map->map_tapp));
438138032Speter
438238032Speter	/*
438342575Speter	**  We need to swallow up all the stuff into a struct
438442575Speter	**  and dump it into map->map_dbptr1
438538032Speter	*/
438638032Speter
4387132943Sgshapiro	if (lmap->ldap_host != NULL &&
438864562Sgshapiro	    (LDAPDefaults == NULL ||
438964562Sgshapiro	     LDAPDefaults == lmap ||
4390132943Sgshapiro	     LDAPDefaults->ldap_host != lmap->ldap_host))
4391132943Sgshapiro		lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host));
4392132943Sgshapiro	map->map_domain = lmap->ldap_host;
439364562Sgshapiro
4394132943Sgshapiro	if (lmap->ldap_uri != NULL &&
4395132943Sgshapiro	    (LDAPDefaults == NULL ||
4396132943Sgshapiro	     LDAPDefaults == lmap ||
4397132943Sgshapiro	     LDAPDefaults->ldap_uri != lmap->ldap_uri))
4398132943Sgshapiro		lmap->ldap_uri = newstr(ldapmap_dequote(lmap->ldap_uri));
4399132943Sgshapiro	map->map_domain = lmap->ldap_uri;
4400132943Sgshapiro
440164562Sgshapiro	if (lmap->ldap_binddn != NULL &&
440264562Sgshapiro	    (LDAPDefaults == NULL ||
440364562Sgshapiro	     LDAPDefaults == lmap ||
440464562Sgshapiro	     LDAPDefaults->ldap_binddn != lmap->ldap_binddn))
440564562Sgshapiro		lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn));
440664562Sgshapiro
440764562Sgshapiro	if (lmap->ldap_secret != NULL &&
440864562Sgshapiro	    (LDAPDefaults == NULL ||
440964562Sgshapiro	     LDAPDefaults == lmap ||
441064562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
441138032Speter	{
441290792Sgshapiro		SM_FILE_T *sfd;
441364562Sgshapiro		long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
441438032Speter
441564562Sgshapiro		if (DontLockReadFiles)
441664562Sgshapiro			sff |= SFF_NOLOCK;
441738032Speter
441864562Sgshapiro		/* need to use method to map secret to passwd string */
441964562Sgshapiro		switch (lmap->ldap_method)
442064562Sgshapiro		{
442164562Sgshapiro		  case LDAP_AUTH_NONE:
442264562Sgshapiro			/* Do nothing */
442364562Sgshapiro			break;
442438032Speter
442564562Sgshapiro		  case LDAP_AUTH_SIMPLE:
442638032Speter
442764562Sgshapiro			/*
442864562Sgshapiro			**  Secret is the name of a file with
442964562Sgshapiro			**  the first line as the password.
443064562Sgshapiro			*/
443164562Sgshapiro
443264562Sgshapiro			/* Already read in the secret? */
443364562Sgshapiro			if (secretread)
443464562Sgshapiro				break;
443564562Sgshapiro
443664562Sgshapiro			sfd = safefopen(ldapmap_dequote(lmap->ldap_secret),
443764562Sgshapiro					O_RDONLY, 0, sff);
443864562Sgshapiro			if (sfd == NULL)
443964562Sgshapiro			{
444064562Sgshapiro				syserr("LDAP map: cannot open secret %s",
444164562Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
444290792Sgshapiro				return false;
444364562Sgshapiro			}
4444168515Sgshapiro			lmap->ldap_secret = sfgets(m_tmp, sizeof(m_tmp),
444566494Sgshapiro						   sfd, TimeOuts.to_fileopen,
444666494Sgshapiro						   "ldapmap_parseargs");
444790792Sgshapiro			(void) sm_io_close(sfd, SM_TIME_DEFAULT);
444898121Sgshapiro			if (strlen(m_tmp) > LDAPMAP_MAX_PASSWD)
444998121Sgshapiro			{
445098121Sgshapiro				syserr("LDAP map: secret in %s too long",
445198121Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
445298121Sgshapiro				return false;
445398121Sgshapiro			}
445464562Sgshapiro			if (lmap->ldap_secret != NULL &&
445564562Sgshapiro			    strlen(m_tmp) > 0)
445664562Sgshapiro			{
445764562Sgshapiro				/* chomp newline */
445864562Sgshapiro				if (m_tmp[strlen(m_tmp) - 1] == '\n')
445964562Sgshapiro					m_tmp[strlen(m_tmp) - 1] = '\0';
446064562Sgshapiro
446164562Sgshapiro				lmap->ldap_secret = m_tmp;
446264562Sgshapiro			}
446364562Sgshapiro			break;
446464562Sgshapiro
446564562Sgshapiro# ifdef LDAP_AUTH_KRBV4
446664562Sgshapiro		  case LDAP_AUTH_KRBV4:
446764562Sgshapiro
446864562Sgshapiro			/*
446964562Sgshapiro			**  Secret is where the ticket file is
447064562Sgshapiro			**  stashed
447164562Sgshapiro			*/
447264562Sgshapiro
4473168515Sgshapiro			(void) sm_snprintf(m_tmp, sizeof(m_tmp),
447490792Sgshapiro				"KRBTKFILE=%s",
447590792Sgshapiro				ldapmap_dequote(lmap->ldap_secret));
447664562Sgshapiro			lmap->ldap_secret = m_tmp;
447764562Sgshapiro			break;
447864562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
447964562Sgshapiro
448064562Sgshapiro		  default:	       /* Should NEVER get here */
448164562Sgshapiro			syserr("LDAP map: Illegal value in lmap method");
448290792Sgshapiro			return false;
448390792Sgshapiro			/* NOTREACHED */
448464562Sgshapiro			break;
448564562Sgshapiro		}
448638032Speter	}
448738032Speter
448864562Sgshapiro	if (lmap->ldap_secret != NULL &&
448964562Sgshapiro	    (LDAPDefaults == NULL ||
449064562Sgshapiro	     LDAPDefaults == lmap ||
449164562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
449264562Sgshapiro		lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret));
449338032Speter
449464562Sgshapiro	if (lmap->ldap_base != NULL &&
449564562Sgshapiro	    (LDAPDefaults == NULL ||
449664562Sgshapiro	     LDAPDefaults == lmap ||
449764562Sgshapiro	     LDAPDefaults->ldap_base != lmap->ldap_base))
449864562Sgshapiro		lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base));
449964562Sgshapiro
450064562Sgshapiro	/*
450164562Sgshapiro	**  Save the server from extra work.  If request is for a single
450264562Sgshapiro	**  match, tell the server to only return enough records to
450364562Sgshapiro	**  determine if there is a single match or not.  This can not
450464562Sgshapiro	**  be one since the server would only return one and we wouldn't
450564562Sgshapiro	**  know if there were others available.
450664562Sgshapiro	*/
450764562Sgshapiro
450864562Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
450964562Sgshapiro		lmap->ldap_sizelimit = 2;
451064562Sgshapiro
451164562Sgshapiro	/* If setting defaults, don't process ldap_filter and ldap_attr */
451264562Sgshapiro	if (lmap == LDAPDefaults)
451390792Sgshapiro		return true;
451464562Sgshapiro
451564562Sgshapiro	if (lmap->ldap_filter != NULL)
451664562Sgshapiro		lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
451738032Speter	else
451838032Speter	{
451938032Speter		if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
452038032Speter		{
452138032Speter			syserr("No filter given in map %s", map->map_mname);
452290792Sgshapiro			return false;
452338032Speter		}
452438032Speter	}
452564562Sgshapiro
4526132943Sgshapiro	if (!attrssetup && lmap->ldap_attr[0] != NULL)
452738032Speter	{
452890792Sgshapiro		bool recurse = false;
452994334Sgshapiro		bool normalseen = false;
453090792Sgshapiro
453164562Sgshapiro		i = 0;
453264562Sgshapiro		p = ldapmap_dequote(lmap->ldap_attr[0]);
453364562Sgshapiro		lmap->ldap_attr[0] = NULL;
453464562Sgshapiro
453594334Sgshapiro		/* Prime the attr list with the objectClass attribute */
453694334Sgshapiro		lmap->ldap_attr[i] = "objectClass";
453794334Sgshapiro		lmap->ldap_attr_type[i] = SM_LDAP_ATTR_OBJCLASS;
453894334Sgshapiro		lmap->ldap_attr_needobjclass[i] = NULL;
453994334Sgshapiro		i++;
454094334Sgshapiro
454164562Sgshapiro		while (p != NULL)
454238032Speter		{
454364562Sgshapiro			char *v;
454464562Sgshapiro
454564562Sgshapiro			while (isascii(*p) && isspace(*p))
454664562Sgshapiro				p++;
454764562Sgshapiro			if (*p == '\0')
454864562Sgshapiro				break;
454964562Sgshapiro			v = p;
455064562Sgshapiro			p = strchr(v, ',');
455164562Sgshapiro			if (p != NULL)
455264562Sgshapiro				*p++ = '\0';
455364562Sgshapiro
455471345Sgshapiro			if (i >= LDAPMAP_MAX_ATTR)
455564562Sgshapiro			{
455664562Sgshapiro				syserr("Too many return attributes in %s (max %d)",
455764562Sgshapiro				       map->map_mname, LDAPMAP_MAX_ATTR);
455890792Sgshapiro				return false;
455964562Sgshapiro			}
456064562Sgshapiro			if (*v != '\0')
456190792Sgshapiro			{
456294334Sgshapiro				int j;
456394334Sgshapiro				int use;
456490792Sgshapiro				char *type;
456594334Sgshapiro				char *needobjclass;
456690792Sgshapiro
456790792Sgshapiro				type = strchr(v, ':');
456890792Sgshapiro				if (type != NULL)
456994334Sgshapiro				{
457090792Sgshapiro					*type++ = '\0';
457194334Sgshapiro					needobjclass = strchr(type, ':');
457294334Sgshapiro					if (needobjclass != NULL)
457394334Sgshapiro						*needobjclass++ = '\0';
457494334Sgshapiro				}
457594334Sgshapiro				else
457694334Sgshapiro				{
457794334Sgshapiro					needobjclass = NULL;
457894334Sgshapiro				}
457990792Sgshapiro
458094334Sgshapiro				use = i;
458190792Sgshapiro
458294334Sgshapiro				/* allow override on "objectClass" type */
458394334Sgshapiro				if (sm_strcasecmp(v, "objectClass") == 0 &&
458494334Sgshapiro				    lmap->ldap_attr_type[0] == SM_LDAP_ATTR_OBJCLASS)
458590792Sgshapiro				{
458694334Sgshapiro					use = 0;
458794334Sgshapiro				}
458894334Sgshapiro				else
458994334Sgshapiro				{
459094334Sgshapiro					/*
459194334Sgshapiro					**  Don't add something to attribute
459294334Sgshapiro					**  list twice.
459394334Sgshapiro					*/
459494334Sgshapiro
459594334Sgshapiro					for (j = 1; j < i; j++)
459690792Sgshapiro					{
459794334Sgshapiro						if (sm_strcasecmp(v, lmap->ldap_attr[j]) == 0)
459894334Sgshapiro						{
459994334Sgshapiro							syserr("Duplicate attribute (%s) in %s",
460094334Sgshapiro							       v, map->map_mname);
460194334Sgshapiro							return false;
460294334Sgshapiro						}
460390792Sgshapiro					}
460494334Sgshapiro
460594334Sgshapiro					lmap->ldap_attr[use] = newstr(v);
460694334Sgshapiro					if (needobjclass != NULL &&
460794334Sgshapiro					    *needobjclass != '\0' &&
460894334Sgshapiro					    *needobjclass != '*')
460990792Sgshapiro					{
461094334Sgshapiro						lmap->ldap_attr_needobjclass[use] = newstr(needobjclass);
461194334Sgshapiro					}
461294334Sgshapiro					else
461394334Sgshapiro					{
461494334Sgshapiro						lmap->ldap_attr_needobjclass[use] = NULL;
461594334Sgshapiro					}
461694334Sgshapiro
461794334Sgshapiro				}
461894334Sgshapiro
461994334Sgshapiro				if (type != NULL && *type != '\0')
462094334Sgshapiro				{
462194334Sgshapiro					if (sm_strcasecmp(type, "dn") == 0)
462294334Sgshapiro					{
462390792Sgshapiro						recurse = true;
462494334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_DN;
462590792Sgshapiro					}
462690792Sgshapiro					else if (sm_strcasecmp(type, "filter") == 0)
462790792Sgshapiro					{
462890792Sgshapiro						recurse = true;
462994334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_FILTER;
463090792Sgshapiro					}
463190792Sgshapiro					else if (sm_strcasecmp(type, "url") == 0)
463290792Sgshapiro					{
463390792Sgshapiro						recurse = true;
463494334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_URL;
463590792Sgshapiro					}
463694334Sgshapiro					else if (sm_strcasecmp(type, "normal") == 0)
463790792Sgshapiro					{
463894334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
463994334Sgshapiro						normalseen = true;
464090792Sgshapiro					}
464190792Sgshapiro					else
464290792Sgshapiro					{
464390792Sgshapiro						syserr("Unknown attribute type (%s) in %s",
464490792Sgshapiro						       type, map->map_mname);
464590792Sgshapiro						return false;
464690792Sgshapiro					}
464790792Sgshapiro				}
464890792Sgshapiro				else
464994334Sgshapiro				{
465094334Sgshapiro					lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
465194334Sgshapiro					normalseen = true;
465294334Sgshapiro				}
465390792Sgshapiro				i++;
465490792Sgshapiro			}
465538032Speter		}
465664562Sgshapiro		lmap->ldap_attr[i] = NULL;
4657141858Sgshapiro
4658141858Sgshapiro		/* Set in case needed in future code */
4659132943Sgshapiro		attrssetup = true;
4660141858Sgshapiro
466194334Sgshapiro		if (recurse && !normalseen)
466290792Sgshapiro		{
466394334Sgshapiro			syserr("LDAP recursion requested in %s but no returnable attribute given",
466490792Sgshapiro			       map->map_mname);
466590792Sgshapiro			return false;
466690792Sgshapiro		}
466790792Sgshapiro		if (recurse && lmap->ldap_attrsonly == LDAPMAP_TRUE)
466890792Sgshapiro		{
466990792Sgshapiro			syserr("LDAP recursion requested in %s can not be used with -n",
467090792Sgshapiro			       map->map_mname);
467190792Sgshapiro			return false;
467290792Sgshapiro		}
467338032Speter	}
467438032Speter	map->map_db1 = (ARBPTR_T) lmap;
467590792Sgshapiro	return true;
467638032Speter}
467738032Speter
467864562Sgshapiro/*
467964562Sgshapiro**  LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
468064562Sgshapiro**
468164562Sgshapiro**	Parameters:
468264562Sgshapiro**		spec -- map argument string from LDAPDefaults option
468364562Sgshapiro**
468464562Sgshapiro**	Returns:
468564562Sgshapiro**		None.
468664562Sgshapiro*/
468764562Sgshapiro
468864562Sgshapirovoid
468964562Sgshapiroldapmap_set_defaults(spec)
469064562Sgshapiro	char *spec;
469164562Sgshapiro{
469273188Sgshapiro	STAB *class;
469364562Sgshapiro	MAP map;
469464562Sgshapiro
469564562Sgshapiro	/* Allocate and set the default values */
469664562Sgshapiro	if (LDAPDefaults == NULL)
4697168515Sgshapiro		LDAPDefaults = (SM_LDAP_STRUCT *) xalloc(sizeof(*LDAPDefaults));
469890792Sgshapiro	sm_ldap_clear(LDAPDefaults);
469964562Sgshapiro
4700168515Sgshapiro	memset(&map, '\0', sizeof(map));
470173188Sgshapiro
470273188Sgshapiro	/* look up the class */
470373188Sgshapiro	class = stab("ldap", ST_MAPCLASS, ST_FIND);
470473188Sgshapiro	if (class == NULL)
470573188Sgshapiro	{
470673188Sgshapiro		syserr("readcf: LDAPDefaultSpec: class ldap not available");
470773188Sgshapiro		return;
470873188Sgshapiro	}
470973188Sgshapiro	map.map_class = &class->s_mapclass;
471064562Sgshapiro	map.map_db1 = (ARBPTR_T) LDAPDefaults;
471173188Sgshapiro	map.map_mname = "O LDAPDefaultSpec";
471264562Sgshapiro
471364562Sgshapiro	(void) ldapmap_parseargs(&map, spec);
471464562Sgshapiro
471564562Sgshapiro	/* These should never be set in LDAPDefaults */
471664562Sgshapiro	if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) ||
471764562Sgshapiro	    map.map_spacesub != SpaceSub ||
471864562Sgshapiro	    map.map_app != NULL ||
471964562Sgshapiro	    map.map_tapp != NULL)
472064562Sgshapiro	{
472164562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
472290792Sgshapiro		SM_FREE_CLR(map.map_app);
472390792Sgshapiro		SM_FREE_CLR(map.map_tapp);
472464562Sgshapiro	}
472564562Sgshapiro
472664562Sgshapiro	if (LDAPDefaults->ldap_filter != NULL)
472764562Sgshapiro	{
472864562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
472994334Sgshapiro
473064562Sgshapiro		/* don't free, it isn't malloc'ed in parseargs */
473164562Sgshapiro		LDAPDefaults->ldap_filter = NULL;
473264562Sgshapiro	}
473364562Sgshapiro
473464562Sgshapiro	if (LDAPDefaults->ldap_attr[0] != NULL)
473564562Sgshapiro	{
473664562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes");
473764562Sgshapiro		/* don't free, they aren't malloc'ed in parseargs */
473864562Sgshapiro		LDAPDefaults->ldap_attr[0] = NULL;
473964562Sgshapiro	}
474064562Sgshapiro}
474164562Sgshapiro#endif /* LDAPMAP */
474290792Sgshapiro/*
474364562Sgshapiro**  PH map
474464562Sgshapiro*/
474564562Sgshapiro
474690792Sgshapiro#if PH_MAP
474764562Sgshapiro
474864562Sgshapiro/*
474964562Sgshapiro**  Support for the CCSO Nameserver (ph/qi).
475064562Sgshapiro**  This code is intended to replace the so-called "ph mailer".
4751168515Sgshapiro**  Contributed by Mark D. Roth.  Contact him for support.
475264562Sgshapiro*/
475364562Sgshapiro
475490792Sgshapiro/* what version of the ph map code we're running */
4755110560Sgshapirostatic char phmap_id[128];
475664562Sgshapiro
475790792Sgshapiro/* sendmail version for phmap id string */
475890792Sgshapiroextern const char Version[];
475990792Sgshapiro
4760132943Sgshapiro/* assume we're using nph-1.2.x if not specified */
4761110560Sgshapiro# ifndef NPH_VERSION
4762132943Sgshapiro#  define NPH_VERSION		10200
4763110560Sgshapiro# endif
4764110560Sgshapiro
4765110560Sgshapiro/* compatibility for versions older than nph-1.2.0 */
4766110560Sgshapiro# if NPH_VERSION < 10200
4767110560Sgshapiro#  define PH_OPEN_ROUNDROBIN	PH_ROUNDROBIN
4768110560Sgshapiro#  define PH_OPEN_DONTID	PH_DONTID
4769110560Sgshapiro#  define PH_CLOSE_FAST		PH_FASTCLOSE
4770110560Sgshapiro#  define PH_ERR_DATAERR	PH_DATAERR
4771110560Sgshapiro#  define PH_ERR_NOMATCH	PH_NOMATCH
4772110560Sgshapiro# endif /* NPH_VERSION < 10200 */
4773110560Sgshapiro
477464562Sgshapiro/*
477564562Sgshapiro**  PH_MAP_PARSEARGS -- parse ph map definition args.
477664562Sgshapiro*/
477764562Sgshapiro
477864562Sgshapirobool
477964562Sgshapiroph_map_parseargs(map, args)
478064562Sgshapiro	MAP *map;
478164562Sgshapiro	char *args;
478264562Sgshapiro{
478390792Sgshapiro	register bool done;
478490792Sgshapiro	register char *p = args;
478564562Sgshapiro	PH_MAP_STRUCT *pmap = NULL;
478664562Sgshapiro
478790792Sgshapiro	/* initialize version string */
4788168515Sgshapiro	(void) sm_snprintf(phmap_id, sizeof(phmap_id),
478990792Sgshapiro			   "sendmail-%s phmap-20010529 libphclient-%s",
479090792Sgshapiro			   Version, libphclient_version);
479190792Sgshapiro
4792168515Sgshapiro	pmap = (PH_MAP_STRUCT *) xalloc(sizeof(*pmap));
479364562Sgshapiro
479464562Sgshapiro	/* defaults */
479564562Sgshapiro	pmap->ph_servers = NULL;
479664562Sgshapiro	pmap->ph_field_list = NULL;
479790792Sgshapiro	pmap->ph = NULL;
479864562Sgshapiro	pmap->ph_timeout = 0;
479990792Sgshapiro	pmap->ph_fastclose = 0;
480064562Sgshapiro
480164562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
480264562Sgshapiro	for (;;)
480364562Sgshapiro	{
480464562Sgshapiro		while (isascii(*p) && isspace(*p))
480564562Sgshapiro			p++;
480664562Sgshapiro		if (*p != '-')
480764562Sgshapiro			break;
480864562Sgshapiro		switch (*++p)
480964562Sgshapiro		{
481064562Sgshapiro		  case 'N':
481164562Sgshapiro			map->map_mflags |= MF_INCLNULL;
481264562Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
481364562Sgshapiro			break;
481464562Sgshapiro
481564562Sgshapiro		  case 'O':
481664562Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
481764562Sgshapiro			break;
481864562Sgshapiro
481964562Sgshapiro		  case 'o':
482064562Sgshapiro			map->map_mflags |= MF_OPTIONAL;
482164562Sgshapiro			break;
482264562Sgshapiro
482364562Sgshapiro		  case 'f':
482464562Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
482564562Sgshapiro			break;
482664562Sgshapiro
482764562Sgshapiro		  case 'm':
482864562Sgshapiro			map->map_mflags |= MF_MATCHONLY;
482964562Sgshapiro			break;
483064562Sgshapiro
483164562Sgshapiro		  case 'A':
483264562Sgshapiro			map->map_mflags |= MF_APPEND;
483364562Sgshapiro			break;
483464562Sgshapiro
483564562Sgshapiro		  case 'q':
483664562Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
483764562Sgshapiro			break;
483864562Sgshapiro
483964562Sgshapiro		  case 't':
484064562Sgshapiro			map->map_mflags |= MF_NODEFER;
484164562Sgshapiro			break;
484264562Sgshapiro
484364562Sgshapiro		  case 'a':
484464562Sgshapiro			map->map_app = ++p;
484564562Sgshapiro			break;
484664562Sgshapiro
484764562Sgshapiro		  case 'T':
484864562Sgshapiro			map->map_tapp = ++p;
484964562Sgshapiro			break;
485064562Sgshapiro
485164562Sgshapiro		  case 'l':
485264562Sgshapiro			while (isascii(*++p) && isspace(*p))
485364562Sgshapiro				continue;
485464562Sgshapiro			pmap->ph_timeout = atoi(p);
485564562Sgshapiro			break;
485664562Sgshapiro
485764562Sgshapiro		  case 'S':
485864562Sgshapiro			map->map_spacesub = *++p;
485964562Sgshapiro			break;
486064562Sgshapiro
486164562Sgshapiro		  case 'D':
486264562Sgshapiro			map->map_mflags |= MF_DEFER;
486364562Sgshapiro			break;
486464562Sgshapiro
486564562Sgshapiro		  case 'h':		/* PH server list */
486664562Sgshapiro			while (isascii(*++p) && isspace(*p))
486764562Sgshapiro				continue;
486864562Sgshapiro			pmap->ph_servers = p;
486964562Sgshapiro			break;
487064562Sgshapiro
487190792Sgshapiro		  case 'k':		/* fields to search for */
487264562Sgshapiro			while (isascii(*++p) && isspace(*p))
487364562Sgshapiro				continue;
487464562Sgshapiro			pmap->ph_field_list = p;
487564562Sgshapiro			break;
487664562Sgshapiro
487764562Sgshapiro		  default:
487890792Sgshapiro			syserr("ph_map_parseargs: unknown option -%c", *p);
487964562Sgshapiro		}
488064562Sgshapiro
488164562Sgshapiro		/* try to account for quoted strings */
488264562Sgshapiro		done = isascii(*p) && isspace(*p);
488364562Sgshapiro		while (*p != '\0' && !done)
488464562Sgshapiro		{
488564562Sgshapiro			if (*p == '"')
488664562Sgshapiro			{
488764562Sgshapiro				while (*++p != '"' && *p != '\0')
488864562Sgshapiro					continue;
488964562Sgshapiro				if (*p != '\0')
489064562Sgshapiro					p++;
489164562Sgshapiro			}
489264562Sgshapiro			else
489364562Sgshapiro				p++;
489464562Sgshapiro			done = isascii(*p) && isspace(*p);
489564562Sgshapiro		}
489664562Sgshapiro
489764562Sgshapiro		if (*p != '\0')
489864562Sgshapiro			*p++ = '\0';
489964562Sgshapiro	}
490064562Sgshapiro
490164562Sgshapiro	if (map->map_app != NULL)
490264562Sgshapiro		map->map_app = newstr(ph_map_dequote(map->map_app));
490364562Sgshapiro	if (map->map_tapp != NULL)
490464562Sgshapiro		map->map_tapp = newstr(ph_map_dequote(map->map_tapp));
490564562Sgshapiro
490664562Sgshapiro	if (pmap->ph_field_list != NULL)
490764562Sgshapiro		pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
490864562Sgshapiro
490964562Sgshapiro	if (pmap->ph_servers != NULL)
491064562Sgshapiro		pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
491164562Sgshapiro	else
491264562Sgshapiro	{
491364562Sgshapiro		syserr("ph_map_parseargs: -h flag is required");
491490792Sgshapiro		return false;
491564562Sgshapiro	}
491664562Sgshapiro
491764562Sgshapiro	map->map_db1 = (ARBPTR_T) pmap;
491890792Sgshapiro	return true;
491964562Sgshapiro}
492064562Sgshapiro
492164562Sgshapiro/*
492264562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
492364562Sgshapiro*/
492464562Sgshapiro
492590792Sgshapirovoid
492690792Sgshapiroph_map_close(map)
492764562Sgshapiro	MAP *map;
492864562Sgshapiro{
492964562Sgshapiro	PH_MAP_STRUCT *pmap;
493064562Sgshapiro
493164562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
493290792Sgshapiro	if (tTd(38, 9))
493394334Sgshapiro		sm_dprintf("ph_map_close(%s): pmap->ph_fastclose=%d\n",
493490792Sgshapiro			   map->map_mname, pmap->ph_fastclose);
493564562Sgshapiro
493690792Sgshapiro
493790792Sgshapiro	if (pmap->ph != NULL)
493864562Sgshapiro	{
493990792Sgshapiro		ph_set_sendhook(pmap->ph, NULL);
494090792Sgshapiro		ph_set_recvhook(pmap->ph, NULL);
494190792Sgshapiro		ph_close(pmap->ph, pmap->ph_fastclose);
494264562Sgshapiro	}
494390792Sgshapiro
494464562Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
494564562Sgshapiro}
494664562Sgshapiro
494764562Sgshapirostatic jmp_buf  PHTimeout;
494864562Sgshapiro
494964562Sgshapiro/* ARGSUSED */
495064562Sgshapirostatic void
495190792Sgshapiroph_timeout(unused)
495290792Sgshapiro	int unused;
495364562Sgshapiro{
495477349Sgshapiro	/*
495577349Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
495677349Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
495777349Sgshapiro	**	DOING.
495877349Sgshapiro	*/
495977349Sgshapiro
496077349Sgshapiro	errno = ETIMEDOUT;
496164562Sgshapiro	longjmp(PHTimeout, 1);
496264562Sgshapiro}
496364562Sgshapiro
496490792Sgshapirostatic void
4965110560Sgshapiro#if NPH_VERSION >= 10200
4966110560Sgshapiroph_map_send_debug(appdata, text)
4967110560Sgshapiro	void *appdata;
4968110560Sgshapiro#else
496990792Sgshapiroph_map_send_debug(text)
4970110560Sgshapiro#endif
497190792Sgshapiro	char *text;
497264562Sgshapiro{
497390792Sgshapiro	if (LogLevel > 9)
497490792Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
497590792Sgshapiro			  "ph_map_send_debug: ==> %s", text);
497690792Sgshapiro	if (tTd(38, 20))
497790792Sgshapiro		sm_dprintf("ph_map_send_debug: ==> %s\n", text);
497890792Sgshapiro}
497964562Sgshapiro
498090792Sgshapirostatic void
4981110560Sgshapiro#if NPH_VERSION >= 10200
4982110560Sgshapiroph_map_recv_debug(appdata, text)
4983110560Sgshapiro	void *appdata;
4984110560Sgshapiro#else
498590792Sgshapiroph_map_recv_debug(text)
4986110560Sgshapiro#endif
498790792Sgshapiro	char *text;
498890792Sgshapiro{
498990792Sgshapiro	if (LogLevel > 10)
499090792Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
499190792Sgshapiro			  "ph_map_recv_debug: <== %s", text);
499290792Sgshapiro	if (tTd(38, 21))
499390792Sgshapiro		sm_dprintf("ph_map_recv_debug: <== %s\n", text);
499464562Sgshapiro}
499564562Sgshapiro
499690792Sgshapiro/*
499764562Sgshapiro**  PH_MAP_OPEN -- sub for opening PH map
499864562Sgshapiro*/
499964562Sgshapirobool
500064562Sgshapiroph_map_open(map, mode)
500164562Sgshapiro	MAP *map;
500264562Sgshapiro	int mode;
500364562Sgshapiro{
500490792Sgshapiro	PH_MAP_STRUCT *pmap;
500590792Sgshapiro	register SM_EVENT *ev = NULL;
500664562Sgshapiro	int save_errno = 0;
500790792Sgshapiro	char *hostlist, *host;
500864562Sgshapiro
500964562Sgshapiro	if (tTd(38, 2))
501090792Sgshapiro		sm_dprintf("ph_map_open(%s)\n", map->map_mname);
501164562Sgshapiro
501264562Sgshapiro	mode &= O_ACCMODE;
501364562Sgshapiro	if (mode != O_RDONLY)
501464562Sgshapiro	{
501564562Sgshapiro		/* issue a pseudo-error message */
501690792Sgshapiro		errno = SM_EMAPCANTWRITE;
501790792Sgshapiro		return false;
501864562Sgshapiro	}
501964562Sgshapiro
502066494Sgshapiro	if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER &&
502166494Sgshapiro	    bitset(MF_DEFER, map->map_mflags))
502266494Sgshapiro	{
502366494Sgshapiro		if (tTd(9, 1))
502490792Sgshapiro			sm_dprintf("ph_map_open(%s) => DEFERRED\n",
502590792Sgshapiro				   map->map_mname);
502666494Sgshapiro
502766494Sgshapiro		/*
502890792Sgshapiro		**  Unset MF_DEFER here so that map_lookup() returns
502990792Sgshapiro		**  a temporary failure using the bogus map and
503090792Sgshapiro		**  map->map_tapp instead of the default permanent error.
503166494Sgshapiro		*/
503266494Sgshapiro
503366494Sgshapiro		map->map_mflags &= ~MF_DEFER;
503490792Sgshapiro		return false;
503566494Sgshapiro	}
503666494Sgshapiro
503764562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
503890792Sgshapiro	pmap->ph_fastclose = 0;		/* refresh field for reopen */
503964562Sgshapiro
504090792Sgshapiro	/* try each host in the list */
504164562Sgshapiro	hostlist = newstr(pmap->ph_servers);
504290792Sgshapiro	for (host = strtok(hostlist, " ");
504390792Sgshapiro	     host != NULL;
504490792Sgshapiro	     host = strtok(NULL, " "))
504564562Sgshapiro	{
504690792Sgshapiro		/* set timeout */
504764562Sgshapiro		if (pmap->ph_timeout != 0)
504864562Sgshapiro		{
504964562Sgshapiro			if (setjmp(PHTimeout) != 0)
505064562Sgshapiro			{
505164562Sgshapiro				ev = NULL;
505264562Sgshapiro				if (LogLevel > 1)
505364562Sgshapiro					sm_syslog(LOG_NOTICE, CurEnv->e_id,
505464562Sgshapiro						  "timeout connecting to PH server %.100s",
505590792Sgshapiro						  host);
505664562Sgshapiro				errno = ETIMEDOUT;
505764562Sgshapiro				goto ph_map_open_abort;
505864562Sgshapiro			}
505990792Sgshapiro			ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
506064562Sgshapiro		}
506190792Sgshapiro
506290792Sgshapiro		/* open connection to server */
5063110560Sgshapiro		if (ph_open(&(pmap->ph), host,
5064110560Sgshapiro			    PH_OPEN_ROUNDROBIN|PH_OPEN_DONTID,
5065110560Sgshapiro			    ph_map_send_debug, ph_map_recv_debug
5066110560Sgshapiro#if NPH_VERSION >= 10200
5067110560Sgshapiro			    , NULL
5068110560Sgshapiro#endif
5069110560Sgshapiro			    ) == 0
5070110560Sgshapiro		    && ph_id(pmap->ph, phmap_id) == 0)
507164562Sgshapiro		{
507264562Sgshapiro			if (ev != NULL)
507390792Sgshapiro				sm_clrevent(ev);
507490792Sgshapiro			sm_free(hostlist); /* XXX */
507590792Sgshapiro			return true;
507664562Sgshapiro		}
507790792Sgshapiro
507864562Sgshapiro  ph_map_open_abort:
507990792Sgshapiro		save_errno = errno;
508064562Sgshapiro		if (ev != NULL)
508190792Sgshapiro			sm_clrevent(ev);
5082110560Sgshapiro		pmap->ph_fastclose = PH_CLOSE_FAST;
508390792Sgshapiro		ph_map_close(map);
508490792Sgshapiro		errno = save_errno;
508590792Sgshapiro	}
508664562Sgshapiro
508766494Sgshapiro	if (bitset(MF_NODEFER, map->map_mflags))
508864562Sgshapiro	{
508966494Sgshapiro		if (errno == 0)
509064562Sgshapiro			errno = EAGAIN;
509166494Sgshapiro		syserr("ph_map_open: %s: cannot connect to PH server",
509266494Sgshapiro		       map->map_mname);
509364562Sgshapiro	}
509466494Sgshapiro	else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1)
509564562Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
509666494Sgshapiro			  "ph_map_open: %s: cannot connect to PH server",
509766494Sgshapiro			  map->map_mname);
509890792Sgshapiro	sm_free(hostlist); /* XXX */
509990792Sgshapiro	return false;
510064562Sgshapiro}
510164562Sgshapiro
510264562Sgshapiro/*
510364562Sgshapiro**  PH_MAP_LOOKUP -- look up key from ph server
510464562Sgshapiro*/
510564562Sgshapiro
510664562Sgshapirochar *
510764562Sgshapiroph_map_lookup(map, key, args, pstat)
510864562Sgshapiro	MAP *map;
510964562Sgshapiro	char *key;
511064562Sgshapiro	char **args;
511164562Sgshapiro	int *pstat;
511264562Sgshapiro{
511390792Sgshapiro	int i, save_errno = 0;
511490792Sgshapiro	register SM_EVENT *ev = NULL;
511564562Sgshapiro	PH_MAP_STRUCT *pmap;
511690792Sgshapiro	char *value = NULL;
511764562Sgshapiro
511864562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
511964562Sgshapiro
512064562Sgshapiro	*pstat = EX_OK;
512164562Sgshapiro
512290792Sgshapiro	/* set timeout */
512364562Sgshapiro	if (pmap->ph_timeout != 0)
512464562Sgshapiro	{
512564562Sgshapiro		if (setjmp(PHTimeout) != 0)
512664562Sgshapiro		{
512764562Sgshapiro			ev = NULL;
512864562Sgshapiro			if (LogLevel > 1)
512964562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
513064562Sgshapiro					  "timeout during PH lookup of %.100s",
513164562Sgshapiro					  key);
513264562Sgshapiro			errno = ETIMEDOUT;
513364562Sgshapiro			*pstat = EX_TEMPFAIL;
513464562Sgshapiro			goto ph_map_lookup_abort;
513564562Sgshapiro		}
513690792Sgshapiro		ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
513764562Sgshapiro	}
513864562Sgshapiro
513990792Sgshapiro	/* perform lookup */
514090792Sgshapiro	i = ph_email_resolve(pmap->ph, key, pmap->ph_field_list, &value);
514190792Sgshapiro	if (i == -1)
514290792Sgshapiro		*pstat = EX_TEMPFAIL;
5143110560Sgshapiro	else if (i == PH_ERR_NOMATCH || i == PH_ERR_DATAERR)
514490792Sgshapiro		*pstat = EX_UNAVAILABLE;
514564562Sgshapiro
514664562Sgshapiro  ph_map_lookup_abort:
514764562Sgshapiro	if (ev != NULL)
514890792Sgshapiro		sm_clrevent(ev);
514964562Sgshapiro
515064562Sgshapiro	/*
515190792Sgshapiro	**  Close the connection if the timer popped
515264562Sgshapiro	**  or we got a temporary PH error
515364562Sgshapiro	*/
515464562Sgshapiro
515564562Sgshapiro	if (*pstat == EX_TEMPFAIL)
515690792Sgshapiro	{
515790792Sgshapiro		save_errno = errno;
5158110560Sgshapiro		pmap->ph_fastclose = PH_CLOSE_FAST;
515990792Sgshapiro		ph_map_close(map);
516090792Sgshapiro		errno = save_errno;
516190792Sgshapiro	}
516264562Sgshapiro
516364562Sgshapiro	if (*pstat == EX_OK)
516464562Sgshapiro	{
516564562Sgshapiro		if (tTd(38,20))
516690792Sgshapiro			sm_dprintf("ph_map_lookup: %s => %s\n", key, value);
516764562Sgshapiro
516864562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
516990792Sgshapiro			return map_rewrite(map, key, strlen(key), NULL);
517064562Sgshapiro		else
517190792Sgshapiro			return map_rewrite(map, value, strlen(value), args);
517264562Sgshapiro	}
517364562Sgshapiro
517464562Sgshapiro	return NULL;
517564562Sgshapiro}
517664562Sgshapiro#endif /* PH_MAP */
5177168515Sgshapiro
517890792Sgshapiro/*
517942575Speter**  syslog map
518038032Speter*/
518138032Speter
518238032Speter#define map_prio	map_lockfd	/* overload field */
518338032Speter
518438032Speter/*
518542575Speter**  SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
518638032Speter*/
518738032Speter
518838032Speterbool
518938032Spetersyslog_map_parseargs(map, args)
519038032Speter	MAP *map;
519138032Speter	char *args;
519238032Speter{
519338032Speter	char *p = args;
519438032Speter	char *priority = NULL;
519538032Speter
519664562Sgshapiro	/* there is no check whether there is really an argument */
519764562Sgshapiro	while (*p != '\0')
519838032Speter	{
519938032Speter		while (isascii(*p) && isspace(*p))
520038032Speter			p++;
520138032Speter		if (*p != '-')
520238032Speter			break;
520364562Sgshapiro		++p;
520464562Sgshapiro		if (*p == 'D')
520564562Sgshapiro		{
520664562Sgshapiro			map->map_mflags |= MF_DEFER;
520764562Sgshapiro			++p;
520864562Sgshapiro		}
520964562Sgshapiro		else if (*p == 'S')
521064562Sgshapiro		{
521164562Sgshapiro			map->map_spacesub = *++p;
521264562Sgshapiro			if (*p != '\0')
521364562Sgshapiro				p++;
521464562Sgshapiro		}
521564562Sgshapiro		else if (*p == 'L')
521664562Sgshapiro		{
521764562Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p))
521864562Sgshapiro				continue;
521964562Sgshapiro			if (*p == '\0')
522064562Sgshapiro				break;
522164562Sgshapiro			priority = p;
522264562Sgshapiro			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
522364562Sgshapiro				p++;
522464562Sgshapiro			if (*p != '\0')
522564562Sgshapiro				*p++ = '\0';
522664562Sgshapiro		}
522764562Sgshapiro		else
522864562Sgshapiro		{
522964562Sgshapiro			syserr("Illegal option %c map syslog", *p);
523064562Sgshapiro			++p;
523164562Sgshapiro		}
523238032Speter	}
523338032Speter
523438032Speter	if (priority == NULL)
523538032Speter		map->map_prio = LOG_INFO;
523638032Speter	else
523738032Speter	{
523890792Sgshapiro		if (sm_strncasecmp("LOG_", priority, 4) == 0)
523938032Speter			priority += 4;
524038032Speter
524138032Speter#ifdef LOG_EMERG
524290792Sgshapiro		if (sm_strcasecmp("EMERG", priority) == 0)
524338032Speter			map->map_prio = LOG_EMERG;
524438032Speter		else
524564562Sgshapiro#endif /* LOG_EMERG */
524638032Speter#ifdef LOG_ALERT
524790792Sgshapiro		if (sm_strcasecmp("ALERT", priority) == 0)
524838032Speter			map->map_prio = LOG_ALERT;
524938032Speter		else
525064562Sgshapiro#endif /* LOG_ALERT */
525138032Speter#ifdef LOG_CRIT
525290792Sgshapiro		if (sm_strcasecmp("CRIT", priority) == 0)
525338032Speter			map->map_prio = LOG_CRIT;
525438032Speter		else
525564562Sgshapiro#endif /* LOG_CRIT */
525638032Speter#ifdef LOG_ERR
525790792Sgshapiro		if (sm_strcasecmp("ERR", priority) == 0)
525838032Speter			map->map_prio = LOG_ERR;
525938032Speter		else
526064562Sgshapiro#endif /* LOG_ERR */
526138032Speter#ifdef LOG_WARNING
526290792Sgshapiro		if (sm_strcasecmp("WARNING", priority) == 0)
526338032Speter			map->map_prio = LOG_WARNING;
526438032Speter		else
526564562Sgshapiro#endif /* LOG_WARNING */
526638032Speter#ifdef LOG_NOTICE
526790792Sgshapiro		if (sm_strcasecmp("NOTICE", priority) == 0)
526838032Speter			map->map_prio = LOG_NOTICE;
526938032Speter		else
527064562Sgshapiro#endif /* LOG_NOTICE */
527138032Speter#ifdef LOG_INFO
527290792Sgshapiro		if (sm_strcasecmp("INFO", priority) == 0)
527338032Speter			map->map_prio = LOG_INFO;
527438032Speter		else
527564562Sgshapiro#endif /* LOG_INFO */
527638032Speter#ifdef LOG_DEBUG
527790792Sgshapiro		if (sm_strcasecmp("DEBUG", priority) == 0)
527838032Speter			map->map_prio = LOG_DEBUG;
527938032Speter		else
528064562Sgshapiro#endif /* LOG_DEBUG */
528138032Speter		{
528290792Sgshapiro			syserr("syslog_map_parseargs: Unknown priority %s",
528338032Speter			       priority);
528490792Sgshapiro			return false;
528538032Speter		}
528638032Speter	}
528790792Sgshapiro	return true;
528838032Speter}
528938032Speter
529038032Speter/*
529142575Speter**  SYSLOG_MAP_LOOKUP -- rewrite and syslog message.  Always return empty string
529238032Speter*/
529338032Speter
529438032Speterchar *
529538032Spetersyslog_map_lookup(map, string, args, statp)
529638032Speter	MAP *map;
529738032Speter	char *string;
529838032Speter	char **args;
529938032Speter	int *statp;
530038032Speter{
530138032Speter	char *ptr = map_rewrite(map, string, strlen(string), args);
530238032Speter
530338032Speter	if (ptr != NULL)
530438032Speter	{
530538032Speter		if (tTd(38, 20))
530690792Sgshapiro			sm_dprintf("syslog_map_lookup(%s (priority %d): %s\n",
530764562Sgshapiro				map->map_mname, map->map_prio, ptr);
530838032Speter
530938032Speter		sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
531038032Speter	}
531138032Speter
531238032Speter	*statp = EX_OK;
531338032Speter	return "";
531438032Speter}
531538032Speter
5316168515Sgshapiro#if _FFR_DPRINTF_MAP
531790792Sgshapiro/*
5318168515Sgshapiro**  dprintf map
5319168515Sgshapiro*/
5320168515Sgshapiro
5321168515Sgshapiro#define map_dbg_level	map_lockfd	/* overload field */
5322168515Sgshapiro
5323168515Sgshapiro/*
5324168515Sgshapiro**  DPRINTF_MAP_PARSEARGS -- check for priority level to dprintf messages.
5325168515Sgshapiro*/
5326168515Sgshapiro
5327168515Sgshapirobool
5328168515Sgshapirodprintf_map_parseargs(map, args)
5329168515Sgshapiro	MAP *map;
5330168515Sgshapiro	char *args;
5331168515Sgshapiro{
5332168515Sgshapiro	char *p = args;
5333168515Sgshapiro	char *dbg_level = NULL;
5334168515Sgshapiro
5335168515Sgshapiro	/* there is no check whether there is really an argument */
5336168515Sgshapiro	while (*p != '\0')
5337168515Sgshapiro	{
5338168515Sgshapiro		while (isascii(*p) && isspace(*p))
5339168515Sgshapiro			p++;
5340168515Sgshapiro		if (*p != '-')
5341168515Sgshapiro			break;
5342168515Sgshapiro		++p;
5343168515Sgshapiro		if (*p == 'D')
5344168515Sgshapiro		{
5345168515Sgshapiro			map->map_mflags |= MF_DEFER;
5346168515Sgshapiro			++p;
5347168515Sgshapiro		}
5348168515Sgshapiro		else if (*p == 'S')
5349168515Sgshapiro		{
5350168515Sgshapiro			map->map_spacesub = *++p;
5351168515Sgshapiro			if (*p != '\0')
5352168515Sgshapiro				p++;
5353168515Sgshapiro		}
5354168515Sgshapiro		else if (*p == 'd')
5355168515Sgshapiro		{
5356168515Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p))
5357168515Sgshapiro				continue;
5358168515Sgshapiro			if (*p == '\0')
5359168515Sgshapiro				break;
5360168515Sgshapiro			dbg_level = p;
5361168515Sgshapiro			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
5362168515Sgshapiro				p++;
5363168515Sgshapiro			if (*p != '\0')
5364168515Sgshapiro				*p++ = '\0';
5365168515Sgshapiro		}
5366168515Sgshapiro		else
5367168515Sgshapiro		{
5368168515Sgshapiro			syserr("Illegal option %c map dprintf", *p);
5369168515Sgshapiro			++p;
5370168515Sgshapiro		}
5371168515Sgshapiro	}
5372168515Sgshapiro
5373168515Sgshapiro	if (dbg_level == NULL)
5374168515Sgshapiro		map->map_dbg_level = 0;
5375168515Sgshapiro	else
5376168515Sgshapiro	{
5377168515Sgshapiro		if (!(isascii(*dbg_level) && isdigit(*dbg_level)))
5378168515Sgshapiro		{
5379168515Sgshapiro			syserr("dprintf map \"%s\", file %s: -d should specify a number, not %s",
5380168515Sgshapiro				map->map_mname, map->map_file,
5381168515Sgshapiro				dbg_level);
5382168515Sgshapiro			return false;
5383168515Sgshapiro		}
5384168515Sgshapiro		map->map_dbg_level = atoi(dbg_level);
5385168515Sgshapiro	}
5386168515Sgshapiro	return true;
5387168515Sgshapiro}
5388168515Sgshapiro
5389168515Sgshapiro/*
5390168515Sgshapiro**  DPRINTF_MAP_LOOKUP -- rewrite and print message.  Always return empty string
5391168515Sgshapiro*/
5392168515Sgshapiro
5393168515Sgshapirochar *
5394168515Sgshapirodprintf_map_lookup(map, string, args, statp)
5395168515Sgshapiro	MAP *map;
5396168515Sgshapiro	char *string;
5397168515Sgshapiro	char **args;
5398168515Sgshapiro	int *statp;
5399168515Sgshapiro{
5400168515Sgshapiro	char *ptr = map_rewrite(map, string, strlen(string), args);
5401168515Sgshapiro
5402168515Sgshapiro	if (ptr != NULL && tTd(85, map->map_dbg_level))
5403168515Sgshapiro		sm_dprintf("%s\n", ptr);
5404168515Sgshapiro	*statp = EX_OK;
5405168515Sgshapiro	return "";
5406168515Sgshapiro}
5407168515Sgshapiro#endif /* _FFR_DPRINTF_MAP */
5408168515Sgshapiro
5409168515Sgshapiro/*
541038032Speter**  HESIOD Modules
541138032Speter*/
541238032Speter
541390792Sgshapiro#if HESIOD
541438032Speter
541538032Speterbool
541638032Speterhes_map_open(map, mode)
541738032Speter	MAP *map;
541838032Speter	int mode;
541938032Speter{
542038032Speter	if (tTd(38, 2))
542190792Sgshapiro		sm_dprintf("hes_map_open(%s, %s, %d)\n",
542238032Speter			map->map_mname, map->map_file, mode);
542338032Speter
542438032Speter	if (mode != O_RDONLY)
542538032Speter	{
542638032Speter		/* issue a pseudo-error message */
542790792Sgshapiro		errno = SM_EMAPCANTWRITE;
542890792Sgshapiro		return false;
542938032Speter	}
543038032Speter
543164562Sgshapiro# ifdef HESIOD_INIT
543238032Speter	if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
543390792Sgshapiro		return true;
543438032Speter
543538032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
543694334Sgshapiro		syserr("451 4.3.5 cannot initialize Hesiod map (%s)",
543790792Sgshapiro			sm_errstring(errno));
543890792Sgshapiro	return false;
543964562Sgshapiro# else /* HESIOD_INIT */
544038032Speter	if (hes_error() == HES_ER_UNINIT)
544138032Speter		hes_init();
544238032Speter	switch (hes_error())
544338032Speter	{
544438032Speter	  case HES_ER_OK:
544538032Speter	  case HES_ER_NOTFOUND:
544690792Sgshapiro		return true;
544738032Speter	}
544838032Speter
544938032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
545094334Sgshapiro		syserr("451 4.3.5 cannot initialize Hesiod map (%d)", hes_error());
545138032Speter
545290792Sgshapiro	return false;
545364562Sgshapiro# endif /* HESIOD_INIT */
545438032Speter}
545538032Speter
545638032Speterchar *
545738032Speterhes_map_lookup(map, name, av, statp)
545838032Speter	MAP *map;
545938032Speter	char *name;
546038032Speter	char **av;
546138032Speter	int *statp;
546238032Speter{
546338032Speter	char **hp;
546438032Speter
546538032Speter	if (tTd(38, 20))
546690792Sgshapiro		sm_dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
546738032Speter
546838032Speter	if (name[0] == '\\')
546938032Speter	{
547038032Speter		char *np;
547138032Speter		int nl;
547277349Sgshapiro		int save_errno;
547338032Speter		char nbuf[MAXNAME];
547438032Speter
547538032Speter		nl = strlen(name);
5476168515Sgshapiro		if (nl < sizeof(nbuf) - 1)
547738032Speter			np = nbuf;
547838032Speter		else
547938032Speter			np = xalloc(strlen(name) + 2);
548038032Speter		np[0] = '\\';
5481168515Sgshapiro		(void) sm_strlcpy(&np[1], name, (sizeof(nbuf)) - 1);
548264562Sgshapiro# ifdef HESIOD_INIT
548338032Speter		hp = hesiod_resolve(HesiodContext, np, map->map_file);
548464562Sgshapiro# else /* HESIOD_INIT */
548538032Speter		hp = hes_resolve(np, map->map_file);
548664562Sgshapiro# endif /* HESIOD_INIT */
548777349Sgshapiro		save_errno = errno;
548838032Speter		if (np != nbuf)
548990792Sgshapiro			sm_free(np); /* XXX */
549077349Sgshapiro		errno = save_errno;
549138032Speter	}
549238032Speter	else
549338032Speter	{
549464562Sgshapiro# ifdef HESIOD_INIT
549538032Speter		hp = hesiod_resolve(HesiodContext, name, map->map_file);
549664562Sgshapiro# else /* HESIOD_INIT */
549738032Speter		hp = hes_resolve(name, map->map_file);
549864562Sgshapiro# endif /* HESIOD_INIT */
549938032Speter	}
550064562Sgshapiro# ifdef HESIOD_INIT
550177349Sgshapiro	if (hp == NULL || *hp == NULL)
550238032Speter	{
550338032Speter		switch (errno)
550438032Speter		{
550538032Speter		  case ENOENT:
550638032Speter			  *statp = EX_NOTFOUND;
550738032Speter			  break;
550838032Speter		  case ECONNREFUSED:
550938032Speter			  *statp = EX_TEMPFAIL;
551038032Speter			  break;
551190792Sgshapiro		  case EMSGSIZE:
551238032Speter		  case ENOMEM:
551338032Speter		  default:
551438032Speter			  *statp = EX_UNAVAILABLE;
551538032Speter			  break;
551638032Speter		}
551782017Sgshapiro		if (hp != NULL)
551882017Sgshapiro			hesiod_free_list(HesiodContext, hp);
551938032Speter		return NULL;
552038032Speter	}
552164562Sgshapiro# else /* HESIOD_INIT */
552238032Speter	if (hp == NULL || hp[0] == NULL)
552338032Speter	{
552438032Speter		switch (hes_error())
552538032Speter		{
552638032Speter		  case HES_ER_OK:
552738032Speter			*statp = EX_OK;
552838032Speter			break;
552938032Speter
553038032Speter		  case HES_ER_NOTFOUND:
553138032Speter			*statp = EX_NOTFOUND;
553238032Speter			break;
553338032Speter
553438032Speter		  case HES_ER_CONFIG:
553538032Speter			*statp = EX_UNAVAILABLE;
553638032Speter			break;
553738032Speter
553838032Speter		  case HES_ER_NET:
553938032Speter			*statp = EX_TEMPFAIL;
554038032Speter			break;
554138032Speter		}
554238032Speter		return NULL;
554338032Speter	}
554464562Sgshapiro# endif /* HESIOD_INIT */
554538032Speter
554638032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
554738032Speter		return map_rewrite(map, name, strlen(name), NULL);
554838032Speter	else
554938032Speter		return map_rewrite(map, hp[0], strlen(hp[0]), av);
555038032Speter}
555138032Speter
555290792Sgshapiro/*
555390792Sgshapiro**  HES_MAP_CLOSE -- free the Hesiod context
555490792Sgshapiro*/
555590792Sgshapiro
555690792Sgshapirovoid
555790792Sgshapirohes_map_close(map)
555890792Sgshapiro	MAP *map;
555990792Sgshapiro{
556090792Sgshapiro	if (tTd(38, 20))
556190792Sgshapiro		sm_dprintf("hes_map_close(%s)\n", map->map_file);
556290792Sgshapiro
556390792Sgshapiro# ifdef HESIOD_INIT
556490792Sgshapiro	/* Free the hesiod context */
556590792Sgshapiro	if (HesiodContext != NULL)
556690792Sgshapiro	{
556790792Sgshapiro		hesiod_end(HesiodContext);
556890792Sgshapiro		HesiodContext = NULL;
556990792Sgshapiro	}
557090792Sgshapiro# endif /* HESIOD_INIT */
557190792Sgshapiro}
557290792Sgshapiro
557364562Sgshapiro#endif /* HESIOD */
557490792Sgshapiro/*
557538032Speter**  NeXT NETINFO Modules
557638032Speter*/
557738032Speter
557838032Speter#if NETINFO
557938032Speter
558038032Speter# define NETINFO_DEFAULT_DIR		"/aliases"
558138032Speter# define NETINFO_DEFAULT_PROPERTY	"members"
558238032Speter
558338032Speter/*
558438032Speter**  NI_MAP_OPEN -- open NetInfo Aliases
558538032Speter*/
558638032Speter
558738032Speterbool
558838032Speterni_map_open(map, mode)
558938032Speter	MAP *map;
559038032Speter	int mode;
559138032Speter{
559238032Speter	if (tTd(38, 2))
559390792Sgshapiro		sm_dprintf("ni_map_open(%s, %s, %d)\n",
559438032Speter			map->map_mname, map->map_file, mode);
559538032Speter	mode &= O_ACCMODE;
559638032Speter
559738032Speter	if (*map->map_file == '\0')
559838032Speter		map->map_file = NETINFO_DEFAULT_DIR;
559938032Speter
560038032Speter	if (map->map_valcolnm == NULL)
560138032Speter		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
560238032Speter
560390792Sgshapiro	if (map->map_coldelim == '\0')
560490792Sgshapiro	{
560590792Sgshapiro		if (bitset(MF_ALIAS, map->map_mflags))
560690792Sgshapiro			map->map_coldelim = ',';
560790792Sgshapiro		else if (bitset(MF_FILECLASS, map->map_mflags))
560890792Sgshapiro			map->map_coldelim = ' ';
560990792Sgshapiro	}
561090792Sgshapiro	return true;
561138032Speter}
561238032Speter
561338032Speter
561438032Speter/*
561538032Speter**  NI_MAP_LOOKUP -- look up a datum in NetInfo
561638032Speter*/
561738032Speter
561838032Speterchar *
561938032Speterni_map_lookup(map, name, av, statp)
562038032Speter	MAP *map;
562138032Speter	char *name;
562238032Speter	char **av;
562338032Speter	int *statp;
562438032Speter{
562538032Speter	char *res;
562638032Speter	char *propval;
562738032Speter
562838032Speter	if (tTd(38, 20))
562990792Sgshapiro		sm_dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
563038032Speter
563138032Speter	propval = ni_propval(map->map_file, map->map_keycolnm, name,
563238032Speter			     map->map_valcolnm, map->map_coldelim);
563338032Speter
563438032Speter	if (propval == NULL)
563538032Speter		return NULL;
563638032Speter
563790792Sgshapiro	SM_TRY
563890792Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
563990792Sgshapiro			res = map_rewrite(map, name, strlen(name), NULL);
564090792Sgshapiro		else
564190792Sgshapiro			res = map_rewrite(map, propval, strlen(propval), av);
564290792Sgshapiro	SM_FINALLY
564390792Sgshapiro		sm_free(propval);
564490792Sgshapiro	SM_END_TRY
564538032Speter	return res;
564638032Speter}
564738032Speter
564838032Speter
564964562Sgshapirostatic bool
565038032Speterni_getcanonname(name, hbsize, statp)
565138032Speter	char *name;
565238032Speter	int hbsize;
565338032Speter	int *statp;
565438032Speter{
565538032Speter	char *vptr;
565638032Speter	char *ptr;
565738032Speter	char nbuf[MAXNAME + 1];
565838032Speter
565938032Speter	if (tTd(38, 20))
566090792Sgshapiro		sm_dprintf("ni_getcanonname(%s)\n", name);
566138032Speter
5662168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
566338032Speter	{
566438032Speter		*statp = EX_UNAVAILABLE;
566590792Sgshapiro		return false;
566638032Speter	}
566773188Sgshapiro	(void) shorten_hostname(nbuf);
566838032Speter
566938032Speter	/* we only accept single token search key */
567038032Speter	if (strchr(nbuf, '.'))
567138032Speter	{
567238032Speter		*statp = EX_NOHOST;
567390792Sgshapiro		return false;
567438032Speter	}
567538032Speter
567638032Speter	/* Do the search */
567738032Speter	vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
567838032Speter
567938032Speter	if (vptr == NULL)
568038032Speter	{
568138032Speter		*statp = EX_NOHOST;
568290792Sgshapiro		return false;
568338032Speter	}
568438032Speter
568538032Speter	/* Only want the first machine name */
568638032Speter	if ((ptr = strchr(vptr, '\n')) != NULL)
568738032Speter		*ptr = '\0';
568838032Speter
568990792Sgshapiro	if (sm_strlcpy(name, vptr, hbsize) >= hbsize)
569038032Speter	{
569177349Sgshapiro		sm_free(vptr);
569290792Sgshapiro		*statp = EX_UNAVAILABLE;
569390792Sgshapiro		return true;
569438032Speter	}
569577349Sgshapiro	sm_free(vptr);
569690792Sgshapiro	*statp = EX_OK;
569790792Sgshapiro	return false;
569838032Speter}
569990792Sgshapiro#endif /* NETINFO */
570038032Speter/*
570138032Speter**  TEXT (unindexed text file) Modules
570238032Speter**
570338032Speter**	This code donated by Sun Microsystems.
570438032Speter*/
570538032Speter
570638032Speter#define map_sff		map_lockfd	/* overload field */
570738032Speter
570838032Speter
570938032Speter/*
571038032Speter**  TEXT_MAP_OPEN -- open text table
571138032Speter*/
571238032Speter
571338032Speterbool
571438032Spetertext_map_open(map, mode)
571538032Speter	MAP *map;
571638032Speter	int mode;
571738032Speter{
571864562Sgshapiro	long sff;
571938032Speter	int i;
572038032Speter
572138032Speter	if (tTd(38, 2))
572290792Sgshapiro		sm_dprintf("text_map_open(%s, %s, %d)\n",
572338032Speter			map->map_mname, map->map_file, mode);
572438032Speter
572538032Speter	mode &= O_ACCMODE;
572638032Speter	if (mode != O_RDONLY)
572738032Speter	{
572838032Speter		errno = EPERM;
572990792Sgshapiro		return false;
573038032Speter	}
573138032Speter
573238032Speter	if (*map->map_file == '\0')
573338032Speter	{
573438032Speter		syserr("text map \"%s\": file name required",
573538032Speter			map->map_mname);
573690792Sgshapiro		return false;
573738032Speter	}
573838032Speter
573938032Speter	if (map->map_file[0] != '/')
574038032Speter	{
574138032Speter		syserr("text map \"%s\": file name must be fully qualified",
574238032Speter			map->map_mname);
574390792Sgshapiro		return false;
574438032Speter	}
574538032Speter
574638032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
574764562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
574838032Speter		sff |= SFF_NOWLINK;
574964562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
575038032Speter		sff |= SFF_SAFEDIRPATH;
575138032Speter	if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
575238032Speter			  sff, S_IRUSR, NULL)) != 0)
575338032Speter	{
575464562Sgshapiro		int save_errno = errno;
575564562Sgshapiro
575638032Speter		/* cannot open this map */
575738032Speter		if (tTd(38, 2))
575890792Sgshapiro			sm_dprintf("\tunsafe map file: %d\n", i);
575964562Sgshapiro		errno = save_errno;
576038032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
576138032Speter			syserr("text map \"%s\": unsafe map file %s",
576238032Speter				map->map_mname, map->map_file);
576390792Sgshapiro		return false;
576438032Speter	}
576538032Speter
576638032Speter	if (map->map_keycolnm == NULL)
576738032Speter		map->map_keycolno = 0;
576838032Speter	else
576938032Speter	{
577038032Speter		if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
577138032Speter		{
577238032Speter			syserr("text map \"%s\", file %s: -k should specify a number, not %s",
577338032Speter				map->map_mname, map->map_file,
577438032Speter				map->map_keycolnm);
577590792Sgshapiro			return false;
577638032Speter		}
577738032Speter		map->map_keycolno = atoi(map->map_keycolnm);
577838032Speter	}
577938032Speter
578038032Speter	if (map->map_valcolnm == NULL)
578138032Speter		map->map_valcolno = 0;
578238032Speter	else
578338032Speter	{
578438032Speter		if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
578538032Speter		{
578638032Speter			syserr("text map \"%s\", file %s: -v should specify a number, not %s",
578738032Speter					map->map_mname, map->map_file,
578838032Speter					map->map_valcolnm);
578990792Sgshapiro			return false;
579038032Speter		}
579138032Speter		map->map_valcolno = atoi(map->map_valcolnm);
579238032Speter	}
579338032Speter
579438032Speter	if (tTd(38, 2))
579538032Speter	{
579690792Sgshapiro		sm_dprintf("text_map_open(%s, %s): delimiter = ",
579738032Speter			map->map_mname, map->map_file);
579838032Speter		if (map->map_coldelim == '\0')
579990792Sgshapiro			sm_dprintf("(white space)\n");
580038032Speter		else
580190792Sgshapiro			sm_dprintf("%c\n", map->map_coldelim);
580238032Speter	}
580338032Speter
580438032Speter	map->map_sff = sff;
580590792Sgshapiro	return true;
580638032Speter}
580738032Speter
580838032Speter
580938032Speter/*
581038032Speter**  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
581138032Speter*/
581238032Speter
581338032Speterchar *
581438032Spetertext_map_lookup(map, name, av, statp)
581538032Speter	MAP *map;
581638032Speter	char *name;
581738032Speter	char **av;
581838032Speter	int *statp;
581938032Speter{
582038032Speter	char *vp;
582138032Speter	auto int vsize;
582238032Speter	int buflen;
582390792Sgshapiro	SM_FILE_T *f;
582438032Speter	char delim;
582538032Speter	int key_idx;
582638032Speter	bool found_it;
582764562Sgshapiro	long sff = map->map_sff;
582838032Speter	char search_key[MAXNAME + 1];
582938032Speter	char linebuf[MAXLINE];
583038032Speter	char buf[MAXNAME + 1];
583138032Speter
583290792Sgshapiro	found_it = false;
583338032Speter	if (tTd(38, 20))
583490792Sgshapiro		sm_dprintf("text_map_lookup(%s, %s)\n", map->map_mname,  name);
583538032Speter
583638032Speter	buflen = strlen(name);
5837168515Sgshapiro	if (buflen > sizeof(search_key) - 1)
5838168515Sgshapiro		buflen = sizeof(search_key) - 1;	/* XXX just cut if off? */
583964562Sgshapiro	memmove(search_key, name, buflen);
584038032Speter	search_key[buflen] = '\0';
584138032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
584238032Speter		makelower(search_key);
584338032Speter
584438032Speter	f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
584538032Speter	if (f == NULL)
584638032Speter	{
584738032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
584838032Speter		*statp = EX_UNAVAILABLE;
584938032Speter		return NULL;
585038032Speter	}
585138032Speter	key_idx = map->map_keycolno;
585238032Speter	delim = map->map_coldelim;
585398121Sgshapiro	while (sm_io_fgets(f, SM_TIME_DEFAULT,
5854249729Sgshapiro			   linebuf, sizeof(linebuf)) >= 0)
585538032Speter	{
585638032Speter		char *p;
585738032Speter
585838032Speter		/* skip comment line */
585938032Speter		if (linebuf[0] == '#')
586038032Speter			continue;
586138032Speter		p = strchr(linebuf, '\n');
586238032Speter		if (p != NULL)
586338032Speter			*p = '\0';
5864168515Sgshapiro		p = get_column(linebuf, key_idx, delim, buf, sizeof(buf));
586590792Sgshapiro		if (p != NULL && sm_strcasecmp(search_key, p) == 0)
586638032Speter		{
586790792Sgshapiro			found_it = true;
586838032Speter			break;
586938032Speter		}
587038032Speter	}
587190792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
587238032Speter	if (!found_it)
587338032Speter	{
587438032Speter		*statp = EX_NOTFOUND;
587538032Speter		return NULL;
587638032Speter	}
5877168515Sgshapiro	vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof(buf));
587842575Speter	if (vp == NULL)
587942575Speter	{
588042575Speter		*statp = EX_NOTFOUND;
588142575Speter		return NULL;
588242575Speter	}
588338032Speter	vsize = strlen(vp);
588438032Speter	*statp = EX_OK;
588538032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
588638032Speter		return map_rewrite(map, name, strlen(name), NULL);
588738032Speter	else
588838032Speter		return map_rewrite(map, vp, vsize, av);
588938032Speter}
589038032Speter
589138032Speter/*
589238032Speter**  TEXT_GETCANONNAME -- look up canonical name in hosts file
589338032Speter*/
589438032Speter
589564562Sgshapirostatic bool
589638032Spetertext_getcanonname(name, hbsize, statp)
589738032Speter	char *name;
589838032Speter	int hbsize;
589938032Speter	int *statp;
590038032Speter{
590138032Speter	bool found;
590273188Sgshapiro	char *dot;
590390792Sgshapiro	SM_FILE_T *f;
590438032Speter	char linebuf[MAXLINE];
590538032Speter	char cbuf[MAXNAME + 1];
590638032Speter	char nbuf[MAXNAME + 1];
590738032Speter
590838032Speter	if (tTd(38, 20))
590990792Sgshapiro		sm_dprintf("text_getcanonname(%s)\n", name);
591038032Speter
5911168515Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
591238032Speter	{
591338032Speter		*statp = EX_UNAVAILABLE;
591490792Sgshapiro		return false;
591538032Speter	}
591673188Sgshapiro	dot = shorten_hostname(nbuf);
591738032Speter
591890792Sgshapiro	f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, HostsFile, SM_IO_RDONLY,
591990792Sgshapiro		       NULL);
592038032Speter	if (f == NULL)
592138032Speter	{
592238032Speter		*statp = EX_UNAVAILABLE;
592390792Sgshapiro		return false;
592438032Speter	}
592590792Sgshapiro	found = false;
592690792Sgshapiro	while (!found &&
592798121Sgshapiro		sm_io_fgets(f, SM_TIME_DEFAULT,
5928249729Sgshapiro			    linebuf, sizeof(linebuf)) >= 0)
592938032Speter	{
593038032Speter		char *p = strpbrk(linebuf, "#\n");
593138032Speter
593238032Speter		if (p != NULL)
593338032Speter			*p = '\0';
593438032Speter		if (linebuf[0] != '\0')
593573188Sgshapiro			found = extract_canonname(nbuf, dot, linebuf,
5936168515Sgshapiro						  cbuf, sizeof(cbuf));
593738032Speter	}
593890792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
593938032Speter	if (!found)
594038032Speter	{
594138032Speter		*statp = EX_NOHOST;
594290792Sgshapiro		return false;
594338032Speter	}
594438032Speter
594590792Sgshapiro	if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
594638032Speter	{
594790792Sgshapiro		*statp = EX_UNAVAILABLE;
594890792Sgshapiro		return false;
594938032Speter	}
595090792Sgshapiro	*statp = EX_OK;
595190792Sgshapiro	return true;
595238032Speter}
595390792Sgshapiro/*
595438032Speter**  STAB (Symbol Table) Modules
595538032Speter*/
595638032Speter
595738032Speter
595838032Speter/*
595938032Speter**  STAB_MAP_LOOKUP -- look up alias in symbol table
596038032Speter*/
596138032Speter
596238032Speter/* ARGSUSED2 */
596338032Speterchar *
596438032Speterstab_map_lookup(map, name, av, pstat)
596538032Speter	register MAP *map;
596638032Speter	char *name;
596738032Speter	char **av;
596838032Speter	int *pstat;
596938032Speter{
597038032Speter	register STAB *s;
597138032Speter
597238032Speter	if (tTd(38, 20))
597390792Sgshapiro		sm_dprintf("stab_lookup(%s, %s)\n",
597438032Speter			map->map_mname, name);
597538032Speter
597638032Speter	s = stab(name, ST_ALIAS, ST_FIND);
5977147078Sgshapiro	if (s == NULL)
5978147078Sgshapiro		return NULL;
5979147078Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
5980147078Sgshapiro		return map_rewrite(map, name, strlen(name), NULL);
5981147078Sgshapiro	else
5982147078Sgshapiro		return map_rewrite(map, s->s_alias, strlen(s->s_alias), av);
598338032Speter}
598438032Speter
598538032Speter/*
598638032Speter**  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
598738032Speter*/
598838032Speter
598938032Spetervoid
599038032Speterstab_map_store(map, lhs, rhs)
599138032Speter	register MAP *map;
599238032Speter	char *lhs;
599338032Speter	char *rhs;
599438032Speter{
599538032Speter	register STAB *s;
599638032Speter
599738032Speter	s = stab(lhs, ST_ALIAS, ST_ENTER);
599838032Speter	s->s_alias = newstr(rhs);
599938032Speter}
600038032Speter
600138032Speter
600238032Speter/*
600338032Speter**  STAB_MAP_OPEN -- initialize (reads data file)
600438032Speter**
6005223067Sgshapiro**	This is a weird case -- it is only intended as a fallback for
600638032Speter**	aliases.  For this reason, opens for write (only during a
600738032Speter**	"newaliases") always fails, and opens for read open the
600838032Speter**	actual underlying text file instead of the database.
600938032Speter*/
601038032Speter
601138032Speterbool
601238032Speterstab_map_open(map, mode)
601338032Speter	register MAP *map;
601438032Speter	int mode;
601538032Speter{
601690792Sgshapiro	SM_FILE_T *af;
601764562Sgshapiro	long sff;
601838032Speter	struct stat st;
601938032Speter
602038032Speter	if (tTd(38, 2))
602190792Sgshapiro		sm_dprintf("stab_map_open(%s, %s, %d)\n",
602238032Speter			map->map_mname, map->map_file, mode);
602338032Speter
602438032Speter	mode &= O_ACCMODE;
602538032Speter	if (mode != O_RDONLY)
602638032Speter	{
602738032Speter		errno = EPERM;
602890792Sgshapiro		return false;
602938032Speter	}
603038032Speter
603138032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
603264562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
603338032Speter		sff |= SFF_NOWLINK;
603464562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
603538032Speter		sff |= SFF_SAFEDIRPATH;
603638032Speter	af = safefopen(map->map_file, O_RDONLY, 0444, sff);
603738032Speter	if (af == NULL)
603890792Sgshapiro		return false;
603990792Sgshapiro	readaliases(map, af, false, false);
604038032Speter
604190792Sgshapiro	if (fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &st) >= 0)
604238032Speter		map->map_mtime = st.st_mtime;
604390792Sgshapiro	(void) sm_io_close(af, SM_TIME_DEFAULT);
604438032Speter
604590792Sgshapiro	return true;
604638032Speter}
604790792Sgshapiro/*
604838032Speter**  Implicit Modules
604938032Speter**
605038032Speter**	Tries several types.  For back compatibility of aliases.
605138032Speter*/
605238032Speter
605338032Speter
605438032Speter/*
605538032Speter**  IMPL_MAP_LOOKUP -- lookup in best open database
605638032Speter*/
605738032Speter
605838032Speterchar *
605938032Speterimpl_map_lookup(map, name, av, pstat)
606038032Speter	MAP *map;
606138032Speter	char *name;
606238032Speter	char **av;
606338032Speter	int *pstat;
606438032Speter{
606538032Speter	if (tTd(38, 20))
606690792Sgshapiro		sm_dprintf("impl_map_lookup(%s, %s)\n",
606738032Speter			map->map_mname, name);
606838032Speter
606990792Sgshapiro#if NEWDB
607038032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
607138032Speter		return db_map_lookup(map, name, av, pstat);
607264562Sgshapiro#endif /* NEWDB */
607390792Sgshapiro#if NDBM
607438032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
607538032Speter		return ndbm_map_lookup(map, name, av, pstat);
607664562Sgshapiro#endif /* NDBM */
607738032Speter	return stab_map_lookup(map, name, av, pstat);
607838032Speter}
607938032Speter
608038032Speter/*
608138032Speter**  IMPL_MAP_STORE -- store in open databases
608238032Speter*/
608338032Speter
608438032Spetervoid
608538032Speterimpl_map_store(map, lhs, rhs)
608638032Speter	MAP *map;
608738032Speter	char *lhs;
608838032Speter	char *rhs;
608938032Speter{
609038032Speter	if (tTd(38, 12))
609190792Sgshapiro		sm_dprintf("impl_map_store(%s, %s, %s)\n",
609238032Speter			map->map_mname, lhs, rhs);
609390792Sgshapiro#if NEWDB
609438032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
609538032Speter		db_map_store(map, lhs, rhs);
609664562Sgshapiro#endif /* NEWDB */
609790792Sgshapiro#if NDBM
609838032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
609938032Speter		ndbm_map_store(map, lhs, rhs);
610064562Sgshapiro#endif /* NDBM */
610138032Speter	stab_map_store(map, lhs, rhs);
610238032Speter}
610338032Speter
610438032Speter/*
610538032Speter**  IMPL_MAP_OPEN -- implicit database open
610638032Speter*/
610738032Speter
610838032Speterbool
610938032Speterimpl_map_open(map, mode)
611038032Speter	MAP *map;
611138032Speter	int mode;
611238032Speter{
611338032Speter	if (tTd(38, 2))
611490792Sgshapiro		sm_dprintf("impl_map_open(%s, %s, %d)\n",
611538032Speter			map->map_mname, map->map_file, mode);
611638032Speter
611738032Speter	mode &= O_ACCMODE;
611890792Sgshapiro#if NEWDB
611938032Speter	map->map_mflags |= MF_IMPL_HASH;
612038032Speter	if (hash_map_open(map, mode))
612138032Speter	{
612238032Speter# ifdef NDBM_YP_COMPAT
612338032Speter		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
612464562Sgshapiro# endif /* NDBM_YP_COMPAT */
612590792Sgshapiro			return true;
612638032Speter	}
612738032Speter	else
612838032Speter		map->map_mflags &= ~MF_IMPL_HASH;
612964562Sgshapiro#endif /* NEWDB */
613090792Sgshapiro#if NDBM
613138032Speter	map->map_mflags |= MF_IMPL_NDBM;
613238032Speter	if (ndbm_map_open(map, mode))
613338032Speter	{
613490792Sgshapiro		return true;
613538032Speter	}
613638032Speter	else
613738032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
613864562Sgshapiro#endif /* NDBM */
613938032Speter
614038032Speter#if defined(NEWDB) || defined(NDBM)
614138032Speter	if (Verbose)
614238032Speter		message("WARNING: cannot open alias database %s%s",
614338032Speter			map->map_file,
614438032Speter			mode == O_RDONLY ? "; reading text version" : "");
614564562Sgshapiro#else /* defined(NEWDB) || defined(NDBM) */
614638032Speter	if (mode != O_RDONLY)
614738032Speter		usrerr("Cannot rebuild aliases: no database format defined");
614864562Sgshapiro#endif /* defined(NEWDB) || defined(NDBM) */
614938032Speter
615038032Speter	if (mode == O_RDONLY)
615138032Speter		return stab_map_open(map, mode);
615238032Speter	else
615390792Sgshapiro		return false;
615438032Speter}
615538032Speter
615638032Speter
615738032Speter/*
615838032Speter**  IMPL_MAP_CLOSE -- close any open database(s)
615938032Speter*/
616038032Speter
616138032Spetervoid
616238032Speterimpl_map_close(map)
616338032Speter	MAP *map;
616438032Speter{
616538032Speter	if (tTd(38, 9))
616690792Sgshapiro		sm_dprintf("impl_map_close(%s, %s, %lx)\n",
616738032Speter			map->map_mname, map->map_file, map->map_mflags);
616890792Sgshapiro#if NEWDB
616938032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
617038032Speter	{
617138032Speter		db_map_close(map);
617238032Speter		map->map_mflags &= ~MF_IMPL_HASH;
617338032Speter	}
617464562Sgshapiro#endif /* NEWDB */
617538032Speter
617690792Sgshapiro#if NDBM
617738032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
617838032Speter	{
617938032Speter		ndbm_map_close(map);
618038032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
618138032Speter	}
618264562Sgshapiro#endif /* NDBM */
618338032Speter}
618490792Sgshapiro/*
618538032Speter**  User map class.
618638032Speter**
618738032Speter**	Provides access to the system password file.
618838032Speter*/
618938032Speter
619038032Speter/*
619138032Speter**  USER_MAP_OPEN -- open user map
619238032Speter**
619338032Speter**	Really just binds field names to field numbers.
619438032Speter*/
619538032Speter
619638032Speterbool
619738032Speteruser_map_open(map, mode)
619838032Speter	MAP *map;
619938032Speter	int mode;
620038032Speter{
620138032Speter	if (tTd(38, 2))
620290792Sgshapiro		sm_dprintf("user_map_open(%s, %d)\n",
620338032Speter			map->map_mname, mode);
620438032Speter
620538032Speter	mode &= O_ACCMODE;
620638032Speter	if (mode != O_RDONLY)
620738032Speter	{
620838032Speter		/* issue a pseudo-error message */
620990792Sgshapiro		errno = SM_EMAPCANTWRITE;
621090792Sgshapiro		return false;
621138032Speter	}
621238032Speter	if (map->map_valcolnm == NULL)
621364562Sgshapiro		/* EMPTY */
621438032Speter		/* nothing */ ;
621590792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "name") == 0)
621638032Speter		map->map_valcolno = 1;
621790792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "passwd") == 0)
621838032Speter		map->map_valcolno = 2;
621990792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "uid") == 0)
622038032Speter		map->map_valcolno = 3;
622190792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "gid") == 0)
622238032Speter		map->map_valcolno = 4;
622390792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "gecos") == 0)
622438032Speter		map->map_valcolno = 5;
622590792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "dir") == 0)
622638032Speter		map->map_valcolno = 6;
622790792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "shell") == 0)
622838032Speter		map->map_valcolno = 7;
622938032Speter	else
623038032Speter	{
623138032Speter		syserr("User map %s: unknown column name %s",
623238032Speter			map->map_mname, map->map_valcolnm);
623390792Sgshapiro		return false;
623438032Speter	}
623590792Sgshapiro	return true;
623638032Speter}
623738032Speter
623838032Speter
623938032Speter/*
624038032Speter**  USER_MAP_LOOKUP -- look up a user in the passwd file.
624138032Speter*/
624238032Speter
624338032Speter/* ARGSUSED3 */
624438032Speterchar *
624538032Speteruser_map_lookup(map, key, av, statp)
624638032Speter	MAP *map;
624738032Speter	char *key;
624838032Speter	char **av;
624938032Speter	int *statp;
625038032Speter{
625138032Speter	auto bool fuzzy;
625290792Sgshapiro	SM_MBDB_T user;
625338032Speter
625438032Speter	if (tTd(38, 20))
625590792Sgshapiro		sm_dprintf("user_map_lookup(%s, %s)\n",
625638032Speter			map->map_mname, key);
625738032Speter
625890792Sgshapiro	*statp = finduser(key, &fuzzy, &user);
625990792Sgshapiro	if (*statp != EX_OK)
626038032Speter		return NULL;
626138032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
626238032Speter		return map_rewrite(map, key, strlen(key), NULL);
626338032Speter	else
626438032Speter	{
626538032Speter		char *rwval = NULL;
626638032Speter		char buf[30];
626738032Speter
626838032Speter		switch (map->map_valcolno)
626938032Speter		{
627038032Speter		  case 0:
627138032Speter		  case 1:
627290792Sgshapiro			rwval = user.mbdb_name;
627338032Speter			break;
627438032Speter
627538032Speter		  case 2:
627690792Sgshapiro			rwval = "x";	/* passwd no longer supported */
627738032Speter			break;
627838032Speter
627938032Speter		  case 3:
6280168515Sgshapiro			(void) sm_snprintf(buf, sizeof(buf), "%d",
628190792Sgshapiro					   (int) user.mbdb_uid);
628238032Speter			rwval = buf;
628338032Speter			break;
628438032Speter
628538032Speter		  case 4:
6286168515Sgshapiro			(void) sm_snprintf(buf, sizeof(buf), "%d",
628790792Sgshapiro					   (int) user.mbdb_gid);
628838032Speter			rwval = buf;
628938032Speter			break;
629038032Speter
629138032Speter		  case 5:
629290792Sgshapiro			rwval = user.mbdb_fullname;
629338032Speter			break;
629438032Speter
629538032Speter		  case 6:
629690792Sgshapiro			rwval = user.mbdb_homedir;
629738032Speter			break;
629838032Speter
629938032Speter		  case 7:
630090792Sgshapiro			rwval = user.mbdb_shell;
630138032Speter			break;
6302159609Sgshapiro		  default:
6303159609Sgshapiro			syserr("user_map %s: bogus field %d",
6304159609Sgshapiro				map->map_mname, map->map_valcolno);
6305159609Sgshapiro			return NULL;
630638032Speter		}
630738032Speter		return map_rewrite(map, rwval, strlen(rwval), av);
630838032Speter	}
630938032Speter}
631090792Sgshapiro/*
631138032Speter**  Program map type.
631238032Speter**
631338032Speter**	This provides access to arbitrary programs.  It should be used
631438032Speter**	only very sparingly, since there is no way to bound the cost
631538032Speter**	of invoking an arbitrary program.
631638032Speter*/
631738032Speter
631838032Speterchar *
631938032Speterprog_map_lookup(map, name, av, statp)
632038032Speter	MAP *map;
632138032Speter	char *name;
632238032Speter	char **av;
632338032Speter	int *statp;
632438032Speter{
632538032Speter	int i;
632664562Sgshapiro	int save_errno;
632738032Speter	int fd;
632864562Sgshapiro	int status;
632938032Speter	auto pid_t pid;
633064562Sgshapiro	register char *p;
633138032Speter	char *rval;
633238032Speter	char *argv[MAXPV + 1];
633338032Speter	char buf[MAXLINE];
633438032Speter
633538032Speter	if (tTd(38, 20))
633690792Sgshapiro		sm_dprintf("prog_map_lookup(%s, %s) %s\n",
633738032Speter			map->map_mname, name, map->map_file);
633838032Speter
633938032Speter	i = 0;
634038032Speter	argv[i++] = map->map_file;
634138032Speter	if (map->map_rebuild != NULL)
634238032Speter	{
6343168515Sgshapiro		(void) sm_strlcpy(buf, map->map_rebuild, sizeof(buf));
634438032Speter		for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
634538032Speter		{
634638032Speter			if (i >= MAXPV - 1)
634738032Speter				break;
634838032Speter			argv[i++] = p;
634938032Speter		}
635038032Speter	}
635138032Speter	argv[i++] = name;
635238032Speter	argv[i] = NULL;
635338032Speter	if (tTd(38, 21))
635438032Speter	{
635590792Sgshapiro		sm_dprintf("prog_open:");
635638032Speter		for (i = 0; argv[i] != NULL; i++)
635790792Sgshapiro			sm_dprintf(" %s", argv[i]);
635890792Sgshapiro		sm_dprintf("\n");
635938032Speter	}
636090792Sgshapiro	(void) sm_blocksignal(SIGCHLD);
636138032Speter	pid = prog_open(argv, &fd, CurEnv);
636238032Speter	if (pid < 0)
636338032Speter	{
636438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
636538032Speter			syserr("prog_map_lookup(%s) failed (%s) -- closing",
636690792Sgshapiro			       map->map_mname, sm_errstring(errno));
636738032Speter		else if (tTd(38, 9))
636890792Sgshapiro			sm_dprintf("prog_map_lookup(%s) failed (%s) -- closing",
636990792Sgshapiro				   map->map_mname, sm_errstring(errno));
637038032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
637138032Speter		*statp = EX_OSFILE;
637238032Speter		return NULL;
637338032Speter	}
6374168515Sgshapiro	i = read(fd, buf, sizeof(buf) - 1);
637538032Speter	if (i < 0)
637638032Speter	{
637790792Sgshapiro		syserr("prog_map_lookup(%s): read error %s",
637890792Sgshapiro		       map->map_mname, sm_errstring(errno));
637938032Speter		rval = NULL;
638038032Speter	}
638138032Speter	else if (i == 0)
638238032Speter	{
638338032Speter		if (tTd(38, 20))
638490792Sgshapiro			sm_dprintf("prog_map_lookup(%s): empty answer\n",
638590792Sgshapiro				   map->map_mname);
638638032Speter		rval = NULL;
638738032Speter	}
638838032Speter	else
638938032Speter	{
639038032Speter		buf[i] = '\0';
639138032Speter		p = strchr(buf, '\n');
639238032Speter		if (p != NULL)
639338032Speter			*p = '\0';
639438032Speter
639538032Speter		/* collect the return value */
639638032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
639738032Speter			rval = map_rewrite(map, name, strlen(name), NULL);
639838032Speter		else
639977349Sgshapiro			rval = map_rewrite(map, buf, strlen(buf), av);
640038032Speter
640138032Speter		/* now flush any additional output */
6402168515Sgshapiro		while ((i = read(fd, buf, sizeof(buf))) > 0)
640338032Speter			continue;
640438032Speter	}
640538032Speter
640638032Speter	/* wait for the process to terminate */
640764562Sgshapiro	(void) close(fd);
640864562Sgshapiro	status = waitfor(pid);
640964562Sgshapiro	save_errno = errno;
641090792Sgshapiro	(void) sm_releasesignal(SIGCHLD);
641164562Sgshapiro	errno = save_errno;
641238032Speter
641364562Sgshapiro	if (status == -1)
641438032Speter	{
641590792Sgshapiro		syserr("prog_map_lookup(%s): wait error %s",
641690792Sgshapiro		       map->map_mname, sm_errstring(errno));
641738032Speter		*statp = EX_SOFTWARE;
641838032Speter		rval = NULL;
641938032Speter	}
642064562Sgshapiro	else if (WIFEXITED(status))
642138032Speter	{
642264562Sgshapiro		if ((*statp = WEXITSTATUS(status)) != EX_OK)
642338032Speter			rval = NULL;
642438032Speter	}
642538032Speter	else
642638032Speter	{
642738032Speter		syserr("prog_map_lookup(%s): child died on signal %d",
642890792Sgshapiro		       map->map_mname, status);
642938032Speter		*statp = EX_UNAVAILABLE;
643038032Speter		rval = NULL;
643138032Speter	}
643238032Speter	return rval;
643338032Speter}
643490792Sgshapiro/*
643538032Speter**  Sequenced map type.
643638032Speter**
643738032Speter**	Tries each map in order until something matches, much like
643838032Speter**	implicit.  Stores go to the first map in the list that can
643938032Speter**	support storing.
644038032Speter**
644138032Speter**	This is slightly unusual in that there are two interfaces.
644238032Speter**	The "sequence" interface lets you stack maps arbitrarily.
644338032Speter**	The "switch" interface builds a sequence map by looking
644438032Speter**	at a system-dependent configuration file such as
644538032Speter**	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
644638032Speter**
644738032Speter**	We don't need an explicit open, since all maps are
644890792Sgshapiro**	opened on demand.
644938032Speter*/
645038032Speter
645138032Speter/*
645238032Speter**  SEQ_MAP_PARSE -- Sequenced map parsing
645338032Speter*/
645438032Speter
645538032Speterbool
645638032Speterseq_map_parse(map, ap)
645738032Speter	MAP *map;
645838032Speter	char *ap;
645938032Speter{
646038032Speter	int maxmap;
646138032Speter
646238032Speter	if (tTd(38, 2))
646390792Sgshapiro		sm_dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
646438032Speter	maxmap = 0;
646538032Speter	while (*ap != '\0')
646638032Speter	{
646738032Speter		register char *p;
646838032Speter		STAB *s;
646938032Speter
647038032Speter		/* find beginning of map name */
647138032Speter		while (isascii(*ap) && isspace(*ap))
647238032Speter			ap++;
647364562Sgshapiro		for (p = ap;
647464562Sgshapiro		     (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.';
647564562Sgshapiro		     p++)
647638032Speter			continue;
647738032Speter		if (*p != '\0')
647838032Speter			*p++ = '\0';
647938032Speter		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
648038032Speter			p++;
648138032Speter		if (*ap == '\0')
648238032Speter		{
648338032Speter			ap = p;
648438032Speter			continue;
648538032Speter		}
648638032Speter		s = stab(ap, ST_MAP, ST_FIND);
648738032Speter		if (s == NULL)
648838032Speter		{
648938032Speter			syserr("Sequence map %s: unknown member map %s",
649038032Speter				map->map_mname, ap);
649138032Speter		}
649290792Sgshapiro		else if (maxmap >= MAXMAPSTACK)
649338032Speter		{
649438032Speter			syserr("Sequence map %s: too many member maps (%d max)",
649538032Speter				map->map_mname, MAXMAPSTACK);
649638032Speter			maxmap++;
649738032Speter		}
649838032Speter		else if (maxmap < MAXMAPSTACK)
649938032Speter		{
650038032Speter			map->map_stack[maxmap++] = &s->s_map;
650138032Speter		}
650238032Speter		ap = p;
650338032Speter	}
650490792Sgshapiro	return true;
650538032Speter}
650638032Speter
650738032Speter/*
650838032Speter**  SWITCH_MAP_OPEN -- open a switched map
650938032Speter**
651038032Speter**	This looks at the system-dependent configuration and builds
651138032Speter**	a sequence map that does the same thing.
651238032Speter**
651338032Speter**	Every system must define a switch_map_find routine in conf.c
651438032Speter**	that will return the list of service types associated with a
651538032Speter**	given service class.
651638032Speter*/
651738032Speter
651838032Speterbool
651938032Speterswitch_map_open(map, mode)
652038032Speter	MAP *map;
652138032Speter	int mode;
652238032Speter{
652338032Speter	int mapno;
652438032Speter	int nmaps;
652538032Speter	char *maptype[MAXMAPSTACK];
652638032Speter
652738032Speter	if (tTd(38, 2))
652890792Sgshapiro		sm_dprintf("switch_map_open(%s, %s, %d)\n",
652938032Speter			map->map_mname, map->map_file, mode);
653038032Speter
653138032Speter	mode &= O_ACCMODE;
653238032Speter	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
653338032Speter	if (tTd(38, 19))
653438032Speter	{
653590792Sgshapiro		sm_dprintf("\tswitch_map_find => %d\n", nmaps);
653638032Speter		for (mapno = 0; mapno < nmaps; mapno++)
653790792Sgshapiro			sm_dprintf("\t\t%s\n", maptype[mapno]);
653838032Speter	}
653938032Speter	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
654090792Sgshapiro		return false;
654138032Speter
654238032Speter	for (mapno = 0; mapno < nmaps; mapno++)
654338032Speter	{
654438032Speter		register STAB *s;
654538032Speter		char nbuf[MAXNAME + 1];
654638032Speter
654738032Speter		if (maptype[mapno] == NULL)
654838032Speter			continue;
6549168515Sgshapiro		(void) sm_strlcpyn(nbuf, sizeof(nbuf), 3,
655090792Sgshapiro				   map->map_mname, ".", maptype[mapno]);
655138032Speter		s = stab(nbuf, ST_MAP, ST_FIND);
655238032Speter		if (s == NULL)
655338032Speter		{
655438032Speter			syserr("Switch map %s: unknown member map %s",
655538032Speter				map->map_mname, nbuf);
655638032Speter		}
655738032Speter		else
655838032Speter		{
655938032Speter			map->map_stack[mapno] = &s->s_map;
656038032Speter			if (tTd(38, 4))
656190792Sgshapiro				sm_dprintf("\tmap_stack[%d] = %s:%s\n",
656290792Sgshapiro					   mapno,
656390792Sgshapiro					   s->s_map.map_class->map_cname,
656490792Sgshapiro					   nbuf);
656538032Speter		}
656638032Speter	}
656790792Sgshapiro	return true;
656838032Speter}
656938032Speter
657090792Sgshapiro#if 0
657138032Speter/*
657238032Speter**  SEQ_MAP_CLOSE -- close all underlying maps
657338032Speter*/
657438032Speter
657538032Spetervoid
657638032Speterseq_map_close(map)
657738032Speter	MAP *map;
657838032Speter{
657938032Speter	int mapno;
658038032Speter
658138032Speter	if (tTd(38, 9))
658290792Sgshapiro		sm_dprintf("seq_map_close(%s)\n", map->map_mname);
658338032Speter
658438032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
658538032Speter	{
658638032Speter		MAP *mm = map->map_stack[mapno];
658738032Speter
658838032Speter		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
658938032Speter			continue;
659077349Sgshapiro		mm->map_mflags |= MF_CLOSING;
659138032Speter		mm->map_class->map_close(mm);
659277349Sgshapiro		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
659338032Speter	}
659438032Speter}
659590792Sgshapiro#endif /* 0 */
659638032Speter
659738032Speter/*
659838032Speter**  SEQ_MAP_LOOKUP -- sequenced map lookup
659938032Speter*/
660038032Speter
660138032Speterchar *
660238032Speterseq_map_lookup(map, key, args, pstat)
660338032Speter	MAP *map;
660438032Speter	char *key;
660538032Speter	char **args;
660638032Speter	int *pstat;
660738032Speter{
660838032Speter	int mapno;
660938032Speter	int mapbit = 0x01;
661090792Sgshapiro	bool tempfail = false;
661138032Speter
661238032Speter	if (tTd(38, 20))
661390792Sgshapiro		sm_dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
661438032Speter
661538032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
661638032Speter	{
661738032Speter		MAP *mm = map->map_stack[mapno];
661838032Speter		char *rv;
661938032Speter
662038032Speter		if (mm == NULL)
662138032Speter			continue;
662264562Sgshapiro		if (!bitset(MF_OPEN, mm->map_mflags) &&
662364562Sgshapiro		    !openmap(mm))
662438032Speter		{
662538032Speter			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
662638032Speter			{
662738032Speter				*pstat = EX_UNAVAILABLE;
662838032Speter				return NULL;
662938032Speter			}
663038032Speter			continue;
663138032Speter		}
663238032Speter		*pstat = EX_OK;
663338032Speter		rv = mm->map_class->map_lookup(mm, key, args, pstat);
663438032Speter		if (rv != NULL)
663538032Speter			return rv;
663638032Speter		if (*pstat == EX_TEMPFAIL)
663738032Speter		{
663838032Speter			if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
663938032Speter				return NULL;
664090792Sgshapiro			tempfail = true;
664138032Speter		}
664238032Speter		else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
664338032Speter			break;
664438032Speter	}
664538032Speter	if (tempfail)
664638032Speter		*pstat = EX_TEMPFAIL;
664738032Speter	else if (*pstat == EX_OK)
664838032Speter		*pstat = EX_NOTFOUND;
664938032Speter	return NULL;
665038032Speter}
665138032Speter
665238032Speter/*
665338032Speter**  SEQ_MAP_STORE -- sequenced map store
665438032Speter*/
665538032Speter
665638032Spetervoid
665738032Speterseq_map_store(map, key, val)
665838032Speter	MAP *map;
665938032Speter	char *key;
666038032Speter	char *val;
666138032Speter{
666238032Speter	int mapno;
666338032Speter
666438032Speter	if (tTd(38, 12))
666590792Sgshapiro		sm_dprintf("seq_map_store(%s, %s, %s)\n",
666638032Speter			map->map_mname, key, val);
666738032Speter
666838032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
666938032Speter	{
667038032Speter		MAP *mm = map->map_stack[mapno];
667138032Speter
667238032Speter		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
667338032Speter			continue;
667438032Speter
667538032Speter		mm->map_class->map_store(mm, key, val);
667638032Speter		return;
667738032Speter	}
667838032Speter	syserr("seq_map_store(%s, %s, %s): no writable map",
667938032Speter		map->map_mname, key, val);
668038032Speter}
668190792Sgshapiro/*
668238032Speter**  NULL stubs
668338032Speter*/
668438032Speter
668538032Speter/* ARGSUSED */
668638032Speterbool
668738032Speternull_map_open(map, mode)
668838032Speter	MAP *map;
668938032Speter	int mode;
669038032Speter{
669190792Sgshapiro	return true;
669238032Speter}
669338032Speter
669438032Speter/* ARGSUSED */
669538032Spetervoid
669638032Speternull_map_close(map)
669738032Speter	MAP *map;
669838032Speter{
669938032Speter	return;
670038032Speter}
670138032Speter
670238032Speterchar *
670338032Speternull_map_lookup(map, key, args, pstat)
670438032Speter	MAP *map;
670538032Speter	char *key;
670638032Speter	char **args;
670738032Speter	int *pstat;
670838032Speter{
670938032Speter	*pstat = EX_NOTFOUND;
671038032Speter	return NULL;
671138032Speter}
671238032Speter
671338032Speter/* ARGSUSED */
671438032Spetervoid
671538032Speternull_map_store(map, key, val)
671638032Speter	MAP *map;
671738032Speter	char *key;
671838032Speter	char *val;
671938032Speter{
672038032Speter	return;
672138032Speter}
672238032Speter
6723203004SgshapiroMAPCLASS	NullMapClass =
6724203004Sgshapiro{
6725203004Sgshapiro	"null-map",		NULL,			0,
6726203004Sgshapiro	NULL,			null_map_lookup,	null_map_store,
6727203004Sgshapiro	null_map_open,		null_map_close,
6728203004Sgshapiro};
6729203004Sgshapiro
673038032Speter/*
673138032Speter**  BOGUS stubs
673238032Speter*/
673338032Speter
673438032Speterchar *
673538032Speterbogus_map_lookup(map, key, args, pstat)
673638032Speter	MAP *map;
673738032Speter	char *key;
673838032Speter	char **args;
673938032Speter	int *pstat;
674038032Speter{
674138032Speter	*pstat = EX_TEMPFAIL;
674238032Speter	return NULL;
674338032Speter}
674438032Speter
674538032SpeterMAPCLASS	BogusMapClass =
674638032Speter{
674790792Sgshapiro	"bogus-map",		NULL,			0,
674890792Sgshapiro	NULL,			bogus_map_lookup,	null_map_store,
674990792Sgshapiro	null_map_open,		null_map_close,
675038032Speter};
675190792Sgshapiro/*
675264562Sgshapiro**  MACRO modules
675364562Sgshapiro*/
675464562Sgshapiro
675564562Sgshapirochar *
675664562Sgshapiromacro_map_lookup(map, name, av, statp)
675764562Sgshapiro	MAP *map;
675864562Sgshapiro	char *name;
675964562Sgshapiro	char **av;
676064562Sgshapiro	int *statp;
676164562Sgshapiro{
676264562Sgshapiro	int mid;
676364562Sgshapiro
676464562Sgshapiro	if (tTd(38, 20))
676590792Sgshapiro		sm_dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
676664562Sgshapiro			name == NULL ? "NULL" : name);
676764562Sgshapiro
676864562Sgshapiro	if (name == NULL ||
676964562Sgshapiro	    *name == '\0' ||
677090792Sgshapiro	    (mid = macid(name)) == 0)
677164562Sgshapiro	{
677264562Sgshapiro		*statp = EX_CONFIG;
677364562Sgshapiro		return NULL;
677464562Sgshapiro	}
677564562Sgshapiro
677664562Sgshapiro	if (av[1] == NULL)
677790792Sgshapiro		macdefine(&CurEnv->e_macro, A_PERM, mid, NULL);
677864562Sgshapiro	else
677990792Sgshapiro		macdefine(&CurEnv->e_macro, A_TEMP, mid, av[1]);
678064562Sgshapiro
678164562Sgshapiro	*statp = EX_OK;
678264562Sgshapiro	return "";
678364562Sgshapiro}
678490792Sgshapiro/*
678538032Speter**  REGEX modules
678638032Speter*/
678738032Speter
678890792Sgshapiro#if MAP_REGEX
678938032Speter
679038032Speter# include <regex.h>
679138032Speter
679238032Speter# define DEFAULT_DELIM	CONDELSE
679338032Speter# define END_OF_FIELDS	-1
679438032Speter# define ERRBUF_SIZE	80
679538032Speter# define MAX_MATCH	32
679638032Speter
679764562Sgshapiro# define xnalloc(s)	memset(xalloc(s), '\0', s);
679838032Speter
679938032Speterstruct regex_map
680038032Speter{
680171345Sgshapiro	regex_t	*regex_pattern_buf;	/* xalloc it */
680238032Speter	int	*regex_subfields;	/* move to type MAP */
680364562Sgshapiro	char	*regex_delim;		/* move to type MAP */
680438032Speter};
680538032Speter
6806141858Sgshapirostatic int	parse_fields __P((char *, int *, int, int));
6807141858Sgshapirostatic char	*regex_map_rewrite __P((MAP *, const char*, size_t, char **));
6808141858Sgshapiro
680938032Speterstatic int
681038032Speterparse_fields(s, ibuf, blen, nr_substrings)
681138032Speter	char *s;
681238032Speter	int *ibuf;		/* array */
681338032Speter	int blen;		/* number of elements in ibuf */
681438032Speter	int nr_substrings;	/* number of substrings in the pattern */
681538032Speter{
681638032Speter	register char *cp;
681738032Speter	int i = 0;
681890792Sgshapiro	bool lastone = false;
681938032Speter
682038032Speter	blen--;		/* for terminating END_OF_FIELDS */
682138032Speter	cp = s;
682238032Speter	do
682338032Speter	{
682438032Speter		for (;; cp++)
682538032Speter		{
682638032Speter			if (*cp == ',')
682738032Speter			{
682838032Speter				*cp = '\0';
682938032Speter				break;
683038032Speter			}
683138032Speter			if (*cp == '\0')
683238032Speter			{
683390792Sgshapiro				lastone = true;
683438032Speter				break;
683538032Speter			}
683638032Speter		}
683738032Speter		if (i < blen)
683838032Speter		{
683938032Speter			int val = atoi(s);
684038032Speter
684138032Speter			if (val < 0 || val >= nr_substrings)
684238032Speter			{
684338032Speter				syserr("field (%d) out of range, only %d substrings in pattern",
684438032Speter				       val, nr_substrings);
684538032Speter				return -1;
684638032Speter			}
684738032Speter			ibuf[i++] = val;
684838032Speter		}
684938032Speter		else
685038032Speter		{
685190792Sgshapiro			syserr("too many fields, %d max", blen);
685238032Speter			return -1;
685338032Speter		}
685438032Speter		s = ++cp;
685538032Speter	} while (!lastone);
685638032Speter	ibuf[i] = END_OF_FIELDS;
685738032Speter	return i;
685838032Speter}
685938032Speter
686038032Speterbool
686138032Speterregex_map_init(map, ap)
686238032Speter	MAP *map;
686338032Speter	char *ap;
686438032Speter{
686538032Speter	int regerr;
686638032Speter	struct regex_map *map_p;
686738032Speter	register char *p;
686838032Speter	char *sub_param = NULL;
686938032Speter	int pflags;
687090792Sgshapiro	static char defdstr[] = { (char) DEFAULT_DELIM, '\0' };
687138032Speter
687238032Speter	if (tTd(38, 2))
687390792Sgshapiro		sm_dprintf("regex_map_init: mapname '%s', args '%s'\n",
687464562Sgshapiro			map->map_mname, ap);
687538032Speter
687638032Speter	pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
687738032Speter	p = ap;
6878168515Sgshapiro	map_p = (struct regex_map *) xnalloc(sizeof(*map_p));
687971345Sgshapiro	map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t));
688038032Speter
688138032Speter	for (;;)
688264562Sgshapiro	{
688338032Speter		while (isascii(*p) && isspace(*p))
688438032Speter			p++;
688538032Speter		if (*p != '-')
688638032Speter			break;
688738032Speter		switch (*++p)
688838032Speter		{
688938032Speter		  case 'n':	/* not */
689038032Speter			map->map_mflags |= MF_REGEX_NOT;
689138032Speter			break;
689238032Speter
689338032Speter		  case 'f':	/* case sensitive */
689438032Speter			map->map_mflags |= MF_NOFOLDCASE;
689538032Speter			pflags &= ~REG_ICASE;
689638032Speter			break;
689738032Speter
689838032Speter		  case 'b':	/* basic regular expressions */
689938032Speter			pflags &= ~REG_EXTENDED;
690038032Speter			break;
690138032Speter
690238032Speter		  case 's':	/* substring match () syntax */
690338032Speter			sub_param = ++p;
690438032Speter			pflags &= ~REG_NOSUB;
690538032Speter			break;
690638032Speter
690738032Speter		  case 'd':	/* delimiter */
690864562Sgshapiro			map_p->regex_delim = ++p;
690938032Speter			break;
691038032Speter
691138032Speter		  case 'a':	/* map append */
691238032Speter			map->map_app = ++p;
691338032Speter			break;
691438032Speter
691538032Speter		  case 'm':	/* matchonly */
691638032Speter			map->map_mflags |= MF_MATCHONLY;
691738032Speter			break;
691838032Speter
6919120256Sgshapiro		  case 'q':
6920120256Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
6921120256Sgshapiro			break;
6922120256Sgshapiro
692364562Sgshapiro		  case 'S':
692464562Sgshapiro			map->map_spacesub = *++p;
692564562Sgshapiro			break;
692664562Sgshapiro
692764562Sgshapiro		  case 'D':
692864562Sgshapiro			map->map_mflags |= MF_DEFER;
692964562Sgshapiro			break;
693064562Sgshapiro
693138032Speter		}
693264562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
693364562Sgshapiro			p++;
693464562Sgshapiro		if (*p != '\0')
693564562Sgshapiro			*p++ = '\0';
693638032Speter	}
693738032Speter	if (tTd(38, 3))
693890792Sgshapiro		sm_dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
693938032Speter
694071345Sgshapiro	if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0)
694138032Speter	{
694238032Speter		/* Errorhandling */
694338032Speter		char errbuf[ERRBUF_SIZE];
694438032Speter
694571345Sgshapiro		(void) regerror(regerr, map_p->regex_pattern_buf,
6946168515Sgshapiro			 errbuf, sizeof(errbuf));
694790792Sgshapiro		syserr("pattern-compile-error: %s", errbuf);
694890792Sgshapiro		sm_free(map_p->regex_pattern_buf); /* XXX */
694990792Sgshapiro		sm_free(map_p); /* XXX */
695090792Sgshapiro		return false;
695138032Speter	}
695238032Speter
695338032Speter	if (map->map_app != NULL)
695438032Speter		map->map_app = newstr(map->map_app);
695564562Sgshapiro	if (map_p->regex_delim != NULL)
695664562Sgshapiro		map_p->regex_delim = newstr(map_p->regex_delim);
695738032Speter	else
695864562Sgshapiro		map_p->regex_delim = defdstr;
695938032Speter
696038032Speter	if (!bitset(REG_NOSUB, pflags))
696138032Speter	{
696238032Speter		/* substring matching */
696338032Speter		int substrings;
696464562Sgshapiro		int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1));
696538032Speter
696671345Sgshapiro		substrings = map_p->regex_pattern_buf->re_nsub + 1;
696738032Speter
696838032Speter		if (tTd(38, 3))
696990792Sgshapiro			sm_dprintf("regex_map_init: nr of substrings %d\n",
697064562Sgshapiro				substrings);
697138032Speter
697238032Speter		if (substrings >= MAX_MATCH)
697338032Speter		{
697490792Sgshapiro			syserr("too many substrings, %d max", MAX_MATCH);
697590792Sgshapiro			sm_free(map_p->regex_pattern_buf); /* XXX */
697690792Sgshapiro			sm_free(map_p); /* XXX */
697790792Sgshapiro			return false;
697838032Speter		}
697938032Speter		if (sub_param != NULL && sub_param[0] != '\0')
698038032Speter		{
698138032Speter			/* optional parameter -sfields */
698238032Speter			if (parse_fields(sub_param, fields,
698338032Speter					 MAX_MATCH + 1, substrings) == -1)
698490792Sgshapiro				return false;
698538032Speter		}
698638032Speter		else
698738032Speter		{
698838032Speter			int i;
698938032Speter
699090792Sgshapiro			/* set default fields */
699138032Speter			for (i = 0; i < substrings; i++)
699238032Speter				fields[i] = i;
699338032Speter			fields[i] = END_OF_FIELDS;
699438032Speter		}
699538032Speter		map_p->regex_subfields = fields;
699638032Speter		if (tTd(38, 3))
699738032Speter		{
699838032Speter			int *ip;
699938032Speter
700090792Sgshapiro			sm_dprintf("regex_map_init: subfields");
700138032Speter			for (ip = fields; *ip != END_OF_FIELDS; ip++)
700290792Sgshapiro				sm_dprintf(" %d", *ip);
700390792Sgshapiro			sm_dprintf("\n");
700438032Speter		}
700538032Speter	}
700690792Sgshapiro	map->map_db1 = (ARBPTR_T) map_p;	/* dirty hack */
700790792Sgshapiro	return true;
700838032Speter}
700938032Speter
701038032Speterstatic char *
701138032Speterregex_map_rewrite(map, s, slen, av)
701238032Speter	MAP *map;
701338032Speter	const char *s;
701438032Speter	size_t slen;
701538032Speter	char **av;
701638032Speter{
701738032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
701838032Speter		return map_rewrite(map, av[0], strlen(av[0]), NULL);
701938032Speter	else
702077349Sgshapiro		return map_rewrite(map, s, slen, av);
702138032Speter}
702238032Speter
702338032Speterchar *
702438032Speterregex_map_lookup(map, name, av, statp)
702538032Speter	MAP *map;
702638032Speter	char *name;
702738032Speter	char **av;
702838032Speter	int *statp;
702938032Speter{
703038032Speter	int reg_res;
703138032Speter	struct regex_map *map_p;
703238032Speter	regmatch_t pmatch[MAX_MATCH];
703338032Speter
703438032Speter	if (tTd(38, 20))
703538032Speter	{
703638032Speter		char **cpp;
703738032Speter
703890792Sgshapiro		sm_dprintf("regex_map_lookup: key '%s'\n", name);
703964562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
704090792Sgshapiro			sm_dprintf("regex_map_lookup: arg '%s'\n", *cpp);
704138032Speter	}
704238032Speter
704338032Speter	map_p = (struct regex_map *)(map->map_db1);
704471345Sgshapiro	reg_res = regexec(map_p->regex_pattern_buf,
704564562Sgshapiro			  name, MAX_MATCH, pmatch, 0);
704638032Speter
704738032Speter	if (bitset(MF_REGEX_NOT, map->map_mflags))
704838032Speter	{
704938032Speter		/* option -n */
705038032Speter		if (reg_res == REG_NOMATCH)
705190792Sgshapiro			return regex_map_rewrite(map, "", (size_t) 0, av);
705238032Speter		else
705338032Speter			return NULL;
705438032Speter	}
705538032Speter	if (reg_res == REG_NOMATCH)
705638032Speter		return NULL;
705738032Speter
705838032Speter	if (map_p->regex_subfields != NULL)
705938032Speter	{
706038032Speter		/* option -s */
706138032Speter		static char retbuf[MAXNAME];
706238032Speter		int fields[MAX_MATCH + 1];
706390792Sgshapiro		bool first = true;
706438032Speter		int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
706590792Sgshapiro		bool quotemode = false, bslashmode = false;
706638032Speter		register char *dp, *sp;
706738032Speter		char *endp, *ldp;
706838032Speter		int *ip;
706938032Speter
707038032Speter		dp = retbuf;
707138032Speter		ldp = retbuf + sizeof(retbuf) - 1;
707238032Speter
707338032Speter		if (av[1] != NULL)
707438032Speter		{
707538032Speter			if (parse_fields(av[1], fields, MAX_MATCH + 1,
707671345Sgshapiro					 (int) map_p->regex_pattern_buf->re_nsub + 1) == -1)
707738032Speter			{
707838032Speter				*statp = EX_CONFIG;
707938032Speter				return NULL;
708038032Speter			}
708138032Speter			ip = fields;
708238032Speter		}
708338032Speter		else
708438032Speter			ip = map_p->regex_subfields;
708538032Speter
708638032Speter		for ( ; *ip != END_OF_FIELDS; ip++)
708738032Speter		{
708838032Speter			if (!first)
708938032Speter			{
709064562Sgshapiro				for (sp = map_p->regex_delim; *sp; sp++)
709138032Speter				{
709238032Speter					if (dp < ldp)
709338032Speter						*dp++ = *sp;
709438032Speter				}
709538032Speter			}
709638032Speter			else
709790792Sgshapiro				first = false;
709838032Speter
709971345Sgshapiro			if (*ip >= MAX_MATCH ||
710071345Sgshapiro			    pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
710138032Speter				continue;
710238032Speter
710338032Speter			sp = name + pmatch[*ip].rm_so;
710438032Speter			endp = name + pmatch[*ip].rm_eo;
710538032Speter			for (; endp > sp; sp++)
710638032Speter			{
710738032Speter				if (dp < ldp)
710838032Speter				{
710964562Sgshapiro					if (bslashmode)
711064562Sgshapiro					{
711138032Speter						*dp++ = *sp;
711290792Sgshapiro						bslashmode = false;
711338032Speter					}
711464562Sgshapiro					else if (quotemode && *sp != '"' &&
711538032Speter						*sp != '\\')
711638032Speter					{
711738032Speter						*dp++ = *sp;
711838032Speter					}
711990792Sgshapiro					else switch (*dp++ = *sp)
712038032Speter					{
712190792Sgshapiro					  case '\\':
712290792Sgshapiro						bslashmode = true;
712338032Speter						break;
712438032Speter
712590792Sgshapiro					  case '(':
712638032Speter						cmntcnt++;
712738032Speter						break;
712838032Speter
712990792Sgshapiro					  case ')':
713038032Speter						cmntcnt--;
713138032Speter						break;
713238032Speter
713390792Sgshapiro					  case '<':
713438032Speter						anglecnt++;
713538032Speter						break;
713638032Speter
713790792Sgshapiro					  case '>':
713838032Speter						anglecnt--;
713938032Speter						break;
714038032Speter
714190792Sgshapiro					  case ' ':
714238032Speter						spacecnt++;
714338032Speter						break;
714438032Speter
714590792Sgshapiro					  case '"':
714638032Speter						quotemode = !quotemode;
714738032Speter						break;
714838032Speter					}
714938032Speter				}
715038032Speter			}
715138032Speter		}
715238032Speter		if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
715338032Speter		    bslashmode || spacecnt != 0)
715438032Speter		{
715564562Sgshapiro			sm_syslog(LOG_WARNING, NOQID,
715664562Sgshapiro				  "Warning: regex may cause prescan() failure map=%s lookup=%s",
715764562Sgshapiro				  map->map_mname, name);
715838032Speter			return NULL;
715938032Speter		}
716038032Speter
716138032Speter		*dp = '\0';
716238032Speter
716338032Speter		return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
716438032Speter	}
716538032Speter	return regex_map_rewrite(map, "", (size_t)0, av);
716638032Speter}
716738032Speter#endif /* MAP_REGEX */
716890792Sgshapiro/*
716964562Sgshapiro**  NSD modules
717064562Sgshapiro*/
717190792Sgshapiro#if MAP_NSD
717264562Sgshapiro
717364562Sgshapiro# include <ndbm.h>
717464562Sgshapiro# define _DATUM_DEFINED
717564562Sgshapiro# include <ns_api.h>
717664562Sgshapiro
717764562Sgshapirotypedef struct ns_map_list
717864562Sgshapiro{
717990792Sgshapiro	ns_map_t		*map;		/* XXX ns_ ? */
718090792Sgshapiro	char			*mapname;
718190792Sgshapiro	struct ns_map_list	*next;
718264562Sgshapiro} ns_map_list_t;
718364562Sgshapiro
718464562Sgshapirostatic ns_map_t *
718564562Sgshapirons_map_t_find(mapname)
718664562Sgshapiro	char *mapname;
718764562Sgshapiro{
718864562Sgshapiro	static ns_map_list_t *ns_maps = NULL;
718964562Sgshapiro	ns_map_list_t *ns_map;
719064562Sgshapiro
719164562Sgshapiro	/* walk the list of maps looking for the correctly named map */
719264562Sgshapiro	for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next)
719364562Sgshapiro	{
719464562Sgshapiro		if (strcmp(ns_map->mapname, mapname) == 0)
719564562Sgshapiro			break;
719664562Sgshapiro	}
719764562Sgshapiro
719864562Sgshapiro	/* if we are looking at a NULL ns_map_list_t, then create a new one */
719964562Sgshapiro	if (ns_map == NULL)
720064562Sgshapiro	{
7201168515Sgshapiro		ns_map = (ns_map_list_t *) xalloc(sizeof(*ns_map));
720264562Sgshapiro		ns_map->mapname = newstr(mapname);
7203168515Sgshapiro		ns_map->map = (ns_map_t *) xalloc(sizeof(*ns_map->map));
7204168515Sgshapiro		memset(ns_map->map, '\0', sizeof(*ns_map->map));
720564562Sgshapiro		ns_map->next = ns_maps;
720664562Sgshapiro		ns_maps = ns_map;
720764562Sgshapiro	}
720864562Sgshapiro	return ns_map->map;
720964562Sgshapiro}
721064562Sgshapiro
721164562Sgshapirochar *
721264562Sgshapironsd_map_lookup(map, name, av, statp)
721364562Sgshapiro	MAP *map;
721464562Sgshapiro	char *name;
721564562Sgshapiro	char **av;
721664562Sgshapiro	int *statp;
721764562Sgshapiro{
721871345Sgshapiro	int buflen, r;
721964562Sgshapiro	char *p;
722064562Sgshapiro	ns_map_t *ns_map;
722164562Sgshapiro	char keybuf[MAXNAME + 1];
722264562Sgshapiro	char buf[MAXLINE];
722364562Sgshapiro
722464562Sgshapiro	if (tTd(38, 20))
722590792Sgshapiro		sm_dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
722664562Sgshapiro
722764562Sgshapiro	buflen = strlen(name);
7228168515Sgshapiro	if (buflen > sizeof(keybuf) - 1)
7229168515Sgshapiro		buflen = sizeof(keybuf) - 1;	/* XXX simply cut off? */
723064562Sgshapiro	memmove(keybuf, name, buflen);
723164562Sgshapiro	keybuf[buflen] = '\0';
723264562Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
723364562Sgshapiro		makelower(keybuf);
723464562Sgshapiro
723564562Sgshapiro	ns_map = ns_map_t_find(map->map_file);
723664562Sgshapiro	if (ns_map == NULL)
723764562Sgshapiro	{
723864562Sgshapiro		if (tTd(38, 20))
723990792Sgshapiro			sm_dprintf("nsd_map_t_find failed\n");
724071345Sgshapiro		*statp = EX_UNAVAILABLE;
724164562Sgshapiro		return NULL;
724264562Sgshapiro	}
724398121Sgshapiro	r = ns_lookup(ns_map, NULL, map->map_file, keybuf, NULL,
7244168515Sgshapiro		      buf, sizeof(buf));
724571345Sgshapiro	if (r == NS_UNAVAIL || r == NS_TRYAGAIN)
724671345Sgshapiro	{
724771345Sgshapiro		*statp = EX_TEMPFAIL;
724864562Sgshapiro		return NULL;
724971345Sgshapiro	}
725077349Sgshapiro	if (r == NS_BADREQ
725177349Sgshapiro# ifdef NS_NOPERM
725277349Sgshapiro	    || r == NS_NOPERM
725377349Sgshapiro# endif /* NS_NOPERM */
725477349Sgshapiro	    )
725571345Sgshapiro	{
725671345Sgshapiro		*statp = EX_CONFIG;
725771345Sgshapiro		return NULL;
725871345Sgshapiro	}
725971345Sgshapiro	if (r != NS_SUCCESS)
726071345Sgshapiro	{
726171345Sgshapiro		*statp = EX_NOTFOUND;
726271345Sgshapiro		return NULL;
726371345Sgshapiro	}
726464562Sgshapiro
726571345Sgshapiro	*statp = EX_OK;
726671345Sgshapiro
726764562Sgshapiro	/* Null out trailing \n */
726864562Sgshapiro	if ((p = strchr(buf, '\n')) != NULL)
726964562Sgshapiro		*p = '\0';
727064562Sgshapiro
727164562Sgshapiro	return map_rewrite(map, buf, strlen(buf), av);
727264562Sgshapiro}
727364562Sgshapiro#endif /* MAP_NSD */
727464562Sgshapiro
727564562Sgshapirochar *
727664562Sgshapiroarith_map_lookup(map, name, av, statp)
727764562Sgshapiro	MAP *map;
727864562Sgshapiro	char *name;
727964562Sgshapiro	char **av;
728064562Sgshapiro	int *statp;
728164562Sgshapiro{
728264562Sgshapiro	long r;
728364562Sgshapiro	long v[2];
728490792Sgshapiro	bool res = false;
728564562Sgshapiro	bool boolres;
728664562Sgshapiro	static char result[16];
728764562Sgshapiro	char **cpp;
728864562Sgshapiro
728964562Sgshapiro	if (tTd(38, 2))
729064562Sgshapiro	{
729190792Sgshapiro		sm_dprintf("arith_map_lookup: key '%s'\n", name);
729264562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
729390792Sgshapiro			sm_dprintf("arith_map_lookup: arg '%s'\n", *cpp);
729464562Sgshapiro	}
729564562Sgshapiro	r = 0;
729690792Sgshapiro	boolres = false;
729764562Sgshapiro	cpp = av;
729864562Sgshapiro	*statp = EX_OK;
729964562Sgshapiro
730064562Sgshapiro	/*
730164562Sgshapiro	**  read arguments for arith map
730264562Sgshapiro	**  - no check is made whether they are really numbers
730364562Sgshapiro	**  - just ignores args after the second
730464562Sgshapiro	*/
730590792Sgshapiro
730664562Sgshapiro	for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
730764562Sgshapiro		v[r++] = strtol(*cpp, NULL, 0);
730864562Sgshapiro
730964562Sgshapiro	/* operator and (at least) two operands given? */
731064562Sgshapiro	if (name != NULL && r == 2)
731164562Sgshapiro	{
731290792Sgshapiro		switch (*name)
731364562Sgshapiro		{
731464562Sgshapiro		  case '|':
731564562Sgshapiro			r = v[0] | v[1];
731664562Sgshapiro			break;
731764562Sgshapiro
731864562Sgshapiro		  case '&':
731964562Sgshapiro			r = v[0] & v[1];
732064562Sgshapiro			break;
732164562Sgshapiro
732264562Sgshapiro		  case '%':
732364562Sgshapiro			if (v[1] == 0)
732464562Sgshapiro				return NULL;
732564562Sgshapiro			r = v[0] % v[1];
732664562Sgshapiro			break;
732764562Sgshapiro		  case '+':
732864562Sgshapiro			r = v[0] + v[1];
732964562Sgshapiro			break;
733064562Sgshapiro
733164562Sgshapiro		  case '-':
733264562Sgshapiro			r = v[0] - v[1];
733364562Sgshapiro			break;
733464562Sgshapiro
733564562Sgshapiro		  case '*':
733664562Sgshapiro			r = v[0] * v[1];
733764562Sgshapiro			break;
733864562Sgshapiro
733964562Sgshapiro		  case '/':
734064562Sgshapiro			if (v[1] == 0)
734164562Sgshapiro				return NULL;
734264562Sgshapiro			r = v[0] / v[1];
734364562Sgshapiro			break;
734464562Sgshapiro
734564562Sgshapiro		  case 'l':
734664562Sgshapiro			res = v[0] < v[1];
734790792Sgshapiro			boolres = true;
734864562Sgshapiro			break;
734964562Sgshapiro
735064562Sgshapiro		  case '=':
735164562Sgshapiro			res = v[0] == v[1];
735290792Sgshapiro			boolres = true;
735364562Sgshapiro			break;
735464562Sgshapiro
7355168515Sgshapiro		  case 'r':
7356168515Sgshapiro			r = v[1] - v[0] + 1;
7357168515Sgshapiro			if (r <= 0)
7358168515Sgshapiro				return NULL;
7359168515Sgshapiro			r = get_random() % r + v[0];
7360168515Sgshapiro			break;
7361168515Sgshapiro
736264562Sgshapiro		  default:
736364562Sgshapiro			/* XXX */
736464562Sgshapiro			*statp = EX_CONFIG;
736564562Sgshapiro			if (LogLevel > 10)
736664562Sgshapiro				sm_syslog(LOG_WARNING, NOQID,
736764562Sgshapiro					  "arith_map: unknown operator %c",
7368203004Sgshapiro					  (isascii(*name) && isprint(*name)) ?
7369203004Sgshapiro					  *name : '?');
737064562Sgshapiro			return NULL;
737164562Sgshapiro		}
737264562Sgshapiro		if (boolres)
7373168515Sgshapiro			(void) sm_snprintf(result, sizeof(result),
737490792Sgshapiro				res ? "TRUE" : "FALSE");
737564562Sgshapiro		else
7376168515Sgshapiro			(void) sm_snprintf(result, sizeof(result), "%ld", r);
737764562Sgshapiro		return result;
737864562Sgshapiro	}
737964562Sgshapiro	*statp = EX_CONFIG;
738064562Sgshapiro	return NULL;
738164562Sgshapiro}
7382132943Sgshapiro
7383261363Sgshapirochar *
7384261363Sgshapiroarpa_map_lookup(map, name, av, statp)
7385261363Sgshapiro	MAP *map;
7386261363Sgshapiro	char *name;
7387261363Sgshapiro	char **av;
7388261363Sgshapiro	int *statp;
7389261363Sgshapiro{
7390261363Sgshapiro	int r;
7391261363Sgshapiro	char *rval;
7392261363Sgshapiro	char result[128];	/* IPv6: 64 + 10 + 1 would be enough */
7393261363Sgshapiro
7394261363Sgshapiro	if (tTd(38, 2))
7395261363Sgshapiro		sm_dprintf("arpa_map_lookup: key '%s'\n", name);
7396261363Sgshapiro	*statp = EX_DATAERR;
7397261363Sgshapiro	r = 1;
7398261363Sgshapiro	memset(result, '\0', sizeof(result));
7399261363Sgshapiro	rval = NULL;
7400261363Sgshapiro
7401261363Sgshapiro# if NETINET6
7402261363Sgshapiro	if (sm_strncasecmp(name, "IPv6:", 5) == 0)
7403261363Sgshapiro	{
7404261363Sgshapiro		struct in6_addr in6_addr;
7405261363Sgshapiro
7406261363Sgshapiro		r = anynet_pton(AF_INET6, name, &in6_addr);
7407261363Sgshapiro		if (r == 1)
7408261363Sgshapiro		{
7409261363Sgshapiro			static char hex_digits[] =
7410261363Sgshapiro				{ '0', '1', '2', '3', '4', '5', '6', '7', '8',
7411261363Sgshapiro				  '9', 'a', 'b', 'c', 'd', 'e', 'f' };
7412261363Sgshapiro
7413261363Sgshapiro			unsigned char *src;
7414261363Sgshapiro			char *dst;
7415261363Sgshapiro			int i;
7416261363Sgshapiro
7417261363Sgshapiro			src = (unsigned char *) &in6_addr;
7418261363Sgshapiro			dst = result;
7419261363Sgshapiro			for (i = 15; i >= 0; i--) {
7420261363Sgshapiro				*dst++ = hex_digits[src[i] & 0x0f];
7421261363Sgshapiro				*dst++ = '.';
7422261363Sgshapiro				*dst++ = hex_digits[(src[i] >> 4) & 0x0f];
7423261363Sgshapiro				if (i > 0)
7424261363Sgshapiro					*dst++ = '.';
7425261363Sgshapiro			}
7426261363Sgshapiro			*statp = EX_OK;
7427261363Sgshapiro		}
7428261363Sgshapiro	}
7429261363Sgshapiro	else
7430261363Sgshapiro# endif /* NETINET6 */
7431261363Sgshapiro# if NETINET
7432261363Sgshapiro	{
7433261363Sgshapiro		struct in_addr in_addr;
7434261363Sgshapiro
7435285303Sgshapiro		r = inet_pton(AF_INET, name, &in_addr);
7436261363Sgshapiro		if (r == 1)
7437261363Sgshapiro		{
7438261363Sgshapiro			unsigned char *src;
7439261363Sgshapiro
7440261363Sgshapiro			src = (unsigned char *) &in_addr;
7441261363Sgshapiro			(void) snprintf(result, sizeof(result),
7442261363Sgshapiro				"%u.%u.%u.%u",
7443261363Sgshapiro				src[3], src[2], src[1], src[0]);
7444261363Sgshapiro			*statp = EX_OK;
7445261363Sgshapiro		}
7446261363Sgshapiro	}
7447261363Sgshapiro# endif /* NETINET */
7448261363Sgshapiro	if (r < 0)
7449261363Sgshapiro		*statp = EX_UNAVAILABLE;
7450261363Sgshapiro	if (tTd(38, 2))
7451261363Sgshapiro		sm_dprintf("arpa_map_lookup: r=%d, result='%s'\n", r, result);
7452261363Sgshapiro	if (*statp == EX_OK)
7453261363Sgshapiro	{
7454261363Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
7455261363Sgshapiro			rval = map_rewrite(map, name, strlen(name), NULL);
7456261363Sgshapiro		else
7457261363Sgshapiro			rval = map_rewrite(map, result, strlen(result), av);
7458261363Sgshapiro	}
7459261363Sgshapiro	return rval;
7460261363Sgshapiro}
7461261363Sgshapiro
7462132943Sgshapiro#if SOCKETMAP
7463132943Sgshapiro
7464132943Sgshapiro# if NETINET || NETINET6
7465132943Sgshapiro#  include <arpa/inet.h>
7466132943Sgshapiro# endif /* NETINET || NETINET6 */
7467132943Sgshapiro
7468132943Sgshapiro# define socket_map_next map_stack[0]
7469132943Sgshapiro
7470132943Sgshapiro/*
7471132943Sgshapiro**  SOCKET_MAP_OPEN -- open socket table
7472132943Sgshapiro*/
7473132943Sgshapiro
7474132943Sgshapirobool
7475132943Sgshapirosocket_map_open(map, mode)
7476132943Sgshapiro	MAP *map;
7477132943Sgshapiro	int mode;
7478132943Sgshapiro{
7479132943Sgshapiro	STAB *s;
7480132943Sgshapiro	int sock = 0;
7481285303Sgshapiro	int tmo;
7482132943Sgshapiro	SOCKADDR_LEN_T addrlen = 0;
7483132943Sgshapiro	int addrno = 0;
7484132943Sgshapiro	int save_errno;
7485132943Sgshapiro	char *p;
7486132943Sgshapiro	char *colon;
7487132943Sgshapiro	char *at;
7488132943Sgshapiro	struct hostent *hp = NULL;
7489132943Sgshapiro	SOCKADDR addr;
7490132943Sgshapiro
7491132943Sgshapiro	if (tTd(38, 2))
7492132943Sgshapiro		sm_dprintf("socket_map_open(%s, %s, %d)\n",
7493132943Sgshapiro			map->map_mname, map->map_file, mode);
7494132943Sgshapiro
7495132943Sgshapiro	mode &= O_ACCMODE;
7496132943Sgshapiro
7497132943Sgshapiro	/* sendmail doesn't have the ability to write to SOCKET (yet) */
7498132943Sgshapiro	if (mode != O_RDONLY)
7499132943Sgshapiro	{
7500132943Sgshapiro		/* issue a pseudo-error message */
7501132943Sgshapiro		errno = SM_EMAPCANTWRITE;
7502132943Sgshapiro		return false;
7503132943Sgshapiro	}
7504132943Sgshapiro
7505132943Sgshapiro	if (*map->map_file == '\0')
7506132943Sgshapiro	{
7507132943Sgshapiro		syserr("socket map \"%s\": empty or missing socket information",
7508132943Sgshapiro			map->map_mname);
7509132943Sgshapiro		return false;
7510132943Sgshapiro	}
7511132943Sgshapiro
7512132943Sgshapiro	s = socket_map_findconn(map->map_file);
7513132943Sgshapiro	if (s->s_socketmap != NULL)
7514132943Sgshapiro	{
7515132943Sgshapiro		/* Copy open connection */
7516132943Sgshapiro		map->map_db1 = s->s_socketmap->map_db1;
7517132943Sgshapiro
7518132943Sgshapiro		/* Add this map as head of linked list */
7519132943Sgshapiro		map->socket_map_next = s->s_socketmap;
7520132943Sgshapiro		s->s_socketmap = map;
7521132943Sgshapiro
7522132943Sgshapiro		if (tTd(38, 2))
7523132943Sgshapiro			sm_dprintf("using cached connection\n");
7524132943Sgshapiro		return true;
7525132943Sgshapiro	}
7526132943Sgshapiro
7527132943Sgshapiro	if (tTd(38, 2))
7528132943Sgshapiro		sm_dprintf("opening new connection\n");
7529132943Sgshapiro
7530132943Sgshapiro	/* following code is ripped from milter.c */
7531132943Sgshapiro	/* XXX It should be put in a library... */
7532132943Sgshapiro
7533132943Sgshapiro	/* protocol:filename or protocol:port@host */
7534168515Sgshapiro	memset(&addr, '\0', sizeof(addr));
7535132943Sgshapiro	p = map->map_file;
7536132943Sgshapiro	colon = strchr(p, ':');
7537132943Sgshapiro	if (colon != NULL)
7538132943Sgshapiro	{
7539132943Sgshapiro		*colon = '\0';
7540132943Sgshapiro
7541132943Sgshapiro		if (*p == '\0')
7542132943Sgshapiro		{
7543132943Sgshapiro# if NETUNIX
7544132943Sgshapiro			/* default to AF_UNIX */
7545132943Sgshapiro			addr.sa.sa_family = AF_UNIX;
7546132943Sgshapiro# else /* NETUNIX */
7547132943Sgshapiro#  if NETINET
7548132943Sgshapiro			/* default to AF_INET */
7549132943Sgshapiro			addr.sa.sa_family = AF_INET;
7550132943Sgshapiro#  else /* NETINET */
7551132943Sgshapiro#   if NETINET6
7552132943Sgshapiro			/* default to AF_INET6 */
7553132943Sgshapiro			addr.sa.sa_family = AF_INET6;
7554132943Sgshapiro#   else /* NETINET6 */
7555132943Sgshapiro			/* no protocols available */
7556132943Sgshapiro			syserr("socket map \"%s\": no valid socket protocols available",
7557132943Sgshapiro			map->map_mname);
7558132943Sgshapiro			return false;
7559132943Sgshapiro#   endif /* NETINET6 */
7560132943Sgshapiro#  endif /* NETINET */
7561132943Sgshapiro# endif /* NETUNIX */
7562132943Sgshapiro		}
7563132943Sgshapiro# if NETUNIX
7564132943Sgshapiro		else if (sm_strcasecmp(p, "unix") == 0 ||
7565132943Sgshapiro			 sm_strcasecmp(p, "local") == 0)
7566132943Sgshapiro			addr.sa.sa_family = AF_UNIX;
7567132943Sgshapiro# endif /* NETUNIX */
7568132943Sgshapiro# if NETINET
7569132943Sgshapiro		else if (sm_strcasecmp(p, "inet") == 0)
7570132943Sgshapiro			addr.sa.sa_family = AF_INET;
7571132943Sgshapiro# endif /* NETINET */
7572132943Sgshapiro# if NETINET6
7573132943Sgshapiro		else if (sm_strcasecmp(p, "inet6") == 0)
7574132943Sgshapiro			addr.sa.sa_family = AF_INET6;
7575132943Sgshapiro# endif /* NETINET6 */
7576132943Sgshapiro		else
7577132943Sgshapiro		{
7578132943Sgshapiro# ifdef EPROTONOSUPPORT
7579132943Sgshapiro			errno = EPROTONOSUPPORT;
7580132943Sgshapiro# else /* EPROTONOSUPPORT */
7581132943Sgshapiro			errno = EINVAL;
7582132943Sgshapiro# endif /* EPROTONOSUPPORT */
7583132943Sgshapiro			syserr("socket map \"%s\": unknown socket type %s",
7584132943Sgshapiro			       map->map_mname, p);
7585132943Sgshapiro			return false;
7586132943Sgshapiro		}
7587132943Sgshapiro		*colon++ = ':';
7588132943Sgshapiro	}
7589132943Sgshapiro	else
7590132943Sgshapiro	{
7591132943Sgshapiro		colon = p;
7592132943Sgshapiro#if NETUNIX
7593132943Sgshapiro		/* default to AF_UNIX */
7594132943Sgshapiro		addr.sa.sa_family = AF_UNIX;
7595132943Sgshapiro#else /* NETUNIX */
7596132943Sgshapiro# if NETINET
7597132943Sgshapiro		/* default to AF_INET */
7598132943Sgshapiro		addr.sa.sa_family = AF_INET;
7599132943Sgshapiro# else /* NETINET */
7600132943Sgshapiro#  if NETINET6
7601132943Sgshapiro		/* default to AF_INET6 */
7602132943Sgshapiro		addr.sa.sa_family = AF_INET6;
7603132943Sgshapiro#  else /* NETINET6 */
7604132943Sgshapiro		syserr("socket map \"%s\": unknown socket type %s",
7605132943Sgshapiro		       map->map_mname, p);
7606132943Sgshapiro		return false;
7607132943Sgshapiro#  endif /* NETINET6 */
7608132943Sgshapiro# endif /* NETINET */
7609132943Sgshapiro#endif /* NETUNIX */
7610132943Sgshapiro	}
7611132943Sgshapiro
7612132943Sgshapiro# if NETUNIX
7613132943Sgshapiro	if (addr.sa.sa_family == AF_UNIX)
7614132943Sgshapiro	{
7615132943Sgshapiro		long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK;
7616132943Sgshapiro
7617132943Sgshapiro		at = colon;
7618168515Sgshapiro		if (strlen(colon) >= sizeof(addr.sunix.sun_path))
7619132943Sgshapiro		{
7620132943Sgshapiro			syserr("socket map \"%s\": local socket name %s too long",
7621132943Sgshapiro			       map->map_mname, colon);
7622132943Sgshapiro			return false;
7623132943Sgshapiro		}
7624132943Sgshapiro		errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
7625132943Sgshapiro				 S_IRUSR|S_IWUSR, NULL);
7626132943Sgshapiro
7627132943Sgshapiro		if (errno != 0)
7628132943Sgshapiro		{
7629132943Sgshapiro			/* if not safe, don't create */
7630132943Sgshapiro				syserr("socket map \"%s\": local socket name %s unsafe",
7631132943Sgshapiro			       map->map_mname, colon);
7632132943Sgshapiro			return false;
7633132943Sgshapiro		}
7634132943Sgshapiro
7635132943Sgshapiro		(void) sm_strlcpy(addr.sunix.sun_path, colon,
7636168515Sgshapiro			       sizeof(addr.sunix.sun_path));
7637168515Sgshapiro		addrlen = sizeof(struct sockaddr_un);
7638132943Sgshapiro	}
7639132943Sgshapiro	else
7640132943Sgshapiro# endif /* NETUNIX */
7641132943Sgshapiro# if NETINET || NETINET6
7642132943Sgshapiro	if (false
7643132943Sgshapiro#  if NETINET
7644132943Sgshapiro		 || addr.sa.sa_family == AF_INET
7645132943Sgshapiro#  endif /* NETINET */
7646132943Sgshapiro#  if NETINET6
7647132943Sgshapiro		 || addr.sa.sa_family == AF_INET6
7648132943Sgshapiro#  endif /* NETINET6 */
7649132943Sgshapiro		 )
7650132943Sgshapiro	{
7651132943Sgshapiro		unsigned short port;
7652132943Sgshapiro
7653132943Sgshapiro		/* Parse port@host */
7654132943Sgshapiro		at = strchr(colon, '@');
7655132943Sgshapiro		if (at == NULL)
7656132943Sgshapiro		{
7657132943Sgshapiro			syserr("socket map \"%s\": bad address %s (expected port@host)",
7658132943Sgshapiro				       map->map_mname, colon);
7659132943Sgshapiro			return false;
7660132943Sgshapiro		}
7661132943Sgshapiro		*at = '\0';
7662132943Sgshapiro		if (isascii(*colon) && isdigit(*colon))
7663132943Sgshapiro			port = htons((unsigned short) atoi(colon));
7664132943Sgshapiro		else
7665132943Sgshapiro		{
7666132943Sgshapiro#  ifdef NO_GETSERVBYNAME
7667132943Sgshapiro			syserr("socket map \"%s\": invalid port number %s",
7668132943Sgshapiro				       map->map_mname, colon);
7669132943Sgshapiro			return false;
7670132943Sgshapiro#  else /* NO_GETSERVBYNAME */
7671132943Sgshapiro			register struct servent *sp;
7672132943Sgshapiro
7673132943Sgshapiro			sp = getservbyname(colon, "tcp");
7674132943Sgshapiro			if (sp == NULL)
7675132943Sgshapiro			{
7676132943Sgshapiro				syserr("socket map \"%s\": unknown port name %s",
7677132943Sgshapiro					       map->map_mname, colon);
7678132943Sgshapiro				return false;
7679132943Sgshapiro			}
7680132943Sgshapiro			port = sp->s_port;
7681132943Sgshapiro#  endif /* NO_GETSERVBYNAME */
7682132943Sgshapiro		}
7683132943Sgshapiro		*at++ = '@';
7684132943Sgshapiro		if (*at == '[')
7685132943Sgshapiro		{
7686132943Sgshapiro			char *end;
7687132943Sgshapiro
7688132943Sgshapiro			end = strchr(at, ']');
7689132943Sgshapiro			if (end != NULL)
7690132943Sgshapiro			{
7691132943Sgshapiro				bool found = false;
7692132943Sgshapiro#  if NETINET
7693132943Sgshapiro				unsigned long hid = INADDR_NONE;
7694132943Sgshapiro#  endif /* NETINET */
7695132943Sgshapiro#  if NETINET6
7696132943Sgshapiro				struct sockaddr_in6 hid6;
7697132943Sgshapiro#  endif /* NETINET6 */
7698132943Sgshapiro
7699132943Sgshapiro				*end = '\0';
7700132943Sgshapiro#  if NETINET
7701132943Sgshapiro				if (addr.sa.sa_family == AF_INET &&
7702132943Sgshapiro				    (hid = inet_addr(&at[1])) != INADDR_NONE)
7703132943Sgshapiro				{
7704132943Sgshapiro					addr.sin.sin_addr.s_addr = hid;
7705132943Sgshapiro					addr.sin.sin_port = port;
7706132943Sgshapiro					found = true;
7707132943Sgshapiro				}
7708132943Sgshapiro#  endif /* NETINET */
7709132943Sgshapiro#  if NETINET6
7710168515Sgshapiro				(void) memset(&hid6, '\0', sizeof(hid6));
7711132943Sgshapiro				if (addr.sa.sa_family == AF_INET6 &&
7712132943Sgshapiro				    anynet_pton(AF_INET6, &at[1],
7713132943Sgshapiro						&hid6.sin6_addr) == 1)
7714132943Sgshapiro				{
7715132943Sgshapiro					addr.sin6.sin6_addr = hid6.sin6_addr;
7716132943Sgshapiro					addr.sin6.sin6_port = port;
7717132943Sgshapiro					found = true;
7718132943Sgshapiro				}
7719132943Sgshapiro#  endif /* NETINET6 */
7720132943Sgshapiro				*end = ']';
7721132943Sgshapiro				if (!found)
7722132943Sgshapiro				{
7723132943Sgshapiro					syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
7724132943Sgshapiro					       map->map_mname, at);
7725132943Sgshapiro					return false;
7726132943Sgshapiro				}
7727132943Sgshapiro			}
7728132943Sgshapiro			else
7729132943Sgshapiro			{
7730132943Sgshapiro				syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
7731132943Sgshapiro				       map->map_mname, at);
7732132943Sgshapiro				return false;
7733132943Sgshapiro			}
7734132943Sgshapiro		}
7735132943Sgshapiro		else
7736132943Sgshapiro		{
7737132943Sgshapiro			hp = sm_gethostbyname(at, addr.sa.sa_family);
7738132943Sgshapiro			if (hp == NULL)
7739132943Sgshapiro			{
7740132943Sgshapiro				syserr("socket map \"%s\": Unknown host name %s",
7741132943Sgshapiro					map->map_mname, at);
7742132943Sgshapiro				return false;
7743132943Sgshapiro			}
7744132943Sgshapiro			addr.sa.sa_family = hp->h_addrtype;
7745132943Sgshapiro			switch (hp->h_addrtype)
7746132943Sgshapiro			{
7747132943Sgshapiro#  if NETINET
7748132943Sgshapiro			  case AF_INET:
7749132943Sgshapiro				memmove(&addr.sin.sin_addr,
7750132943Sgshapiro					hp->h_addr, INADDRSZ);
7751132943Sgshapiro				addr.sin.sin_port = port;
7752168515Sgshapiro				addrlen = sizeof(struct sockaddr_in);
7753132943Sgshapiro				addrno = 1;
7754132943Sgshapiro				break;
7755132943Sgshapiro#  endif /* NETINET */
7756132943Sgshapiro
7757132943Sgshapiro#  if NETINET6
7758132943Sgshapiro			  case AF_INET6:
7759132943Sgshapiro				memmove(&addr.sin6.sin6_addr,
7760132943Sgshapiro					hp->h_addr, IN6ADDRSZ);
7761132943Sgshapiro				addr.sin6.sin6_port = port;
7762168515Sgshapiro				addrlen = sizeof(struct sockaddr_in6);
7763132943Sgshapiro				addrno = 1;
7764132943Sgshapiro				break;
7765132943Sgshapiro#  endif /* NETINET6 */
7766132943Sgshapiro
7767132943Sgshapiro			  default:
7768132943Sgshapiro				syserr("socket map \"%s\": Unknown protocol for %s (%d)",
7769132943Sgshapiro					map->map_mname, at, hp->h_addrtype);
7770132943Sgshapiro#  if NETINET6
7771132943Sgshapiro				freehostent(hp);
7772132943Sgshapiro#  endif /* NETINET6 */
7773132943Sgshapiro				return false;
7774132943Sgshapiro			}
7775132943Sgshapiro		}
7776132943Sgshapiro	}
7777132943Sgshapiro	else
7778132943Sgshapiro# endif /* NETINET || NETINET6 */
7779132943Sgshapiro	{
7780132943Sgshapiro		syserr("socket map \"%s\": unknown socket protocol",
7781132943Sgshapiro			map->map_mname);
7782132943Sgshapiro		return false;
7783132943Sgshapiro	}
7784132943Sgshapiro
7785132943Sgshapiro	/* nope, actually connecting */
7786132943Sgshapiro	for (;;)
7787132943Sgshapiro	{
7788132943Sgshapiro		sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
7789132943Sgshapiro		if (sock < 0)
7790132943Sgshapiro		{
7791132943Sgshapiro			save_errno = errno;
7792132943Sgshapiro			if (tTd(38, 5))
7793132943Sgshapiro				sm_dprintf("socket map \"%s\": error creating socket: %s\n",
7794132943Sgshapiro					   map->map_mname,
7795132943Sgshapiro					   sm_errstring(save_errno));
7796132943Sgshapiro# if NETINET6
7797132943Sgshapiro			if (hp != NULL)
7798132943Sgshapiro				freehostent(hp);
7799132943Sgshapiro# endif /* NETINET6 */
7800132943Sgshapiro			return false;
7801132943Sgshapiro		}
7802132943Sgshapiro
7803132943Sgshapiro		if (connect(sock, (struct sockaddr *) &addr, addrlen) >= 0)
7804132943Sgshapiro			break;
7805132943Sgshapiro
7806132943Sgshapiro		/* couldn't connect.... try next address */
7807132943Sgshapiro		save_errno = errno;
7808132943Sgshapiro		p = CurHostName;
7809132943Sgshapiro		CurHostName = at;
7810132943Sgshapiro		if (tTd(38, 5))
7811132943Sgshapiro			sm_dprintf("socket_open (%s): open %s failed: %s\n",
7812132943Sgshapiro				map->map_mname, at, sm_errstring(save_errno));
7813132943Sgshapiro		CurHostName = p;
7814132943Sgshapiro		(void) close(sock);
7815132943Sgshapiro
7816132943Sgshapiro		/* try next address */
7817132943Sgshapiro		if (hp != NULL && hp->h_addr_list[addrno] != NULL)
7818132943Sgshapiro		{
7819132943Sgshapiro			switch (addr.sa.sa_family)
7820132943Sgshapiro			{
7821132943Sgshapiro# if NETINET
7822132943Sgshapiro			  case AF_INET:
7823132943Sgshapiro				memmove(&addr.sin.sin_addr,
7824132943Sgshapiro					hp->h_addr_list[addrno++],
7825132943Sgshapiro					INADDRSZ);
7826132943Sgshapiro				break;
7827132943Sgshapiro# endif /* NETINET */
7828132943Sgshapiro
7829132943Sgshapiro# if NETINET6
7830132943Sgshapiro			  case AF_INET6:
7831132943Sgshapiro				memmove(&addr.sin6.sin6_addr,
7832132943Sgshapiro					hp->h_addr_list[addrno++],
7833132943Sgshapiro					IN6ADDRSZ);
7834132943Sgshapiro				break;
7835132943Sgshapiro# endif /* NETINET6 */
7836132943Sgshapiro
7837132943Sgshapiro			  default:
7838132943Sgshapiro				if (tTd(38, 5))
7839132943Sgshapiro					sm_dprintf("socket map \"%s\": Unknown protocol for %s (%d)\n",
7840132943Sgshapiro						   map->map_mname, at,
7841132943Sgshapiro						   hp->h_addrtype);
7842132943Sgshapiro# if NETINET6
7843132943Sgshapiro				freehostent(hp);
7844132943Sgshapiro# endif /* NETINET6 */
7845132943Sgshapiro				return false;
7846132943Sgshapiro			}
7847132943Sgshapiro			continue;
7848132943Sgshapiro		}
7849132943Sgshapiro		p = CurHostName;
7850132943Sgshapiro		CurHostName = at;
7851132943Sgshapiro		if (tTd(38, 5))
7852132943Sgshapiro			sm_dprintf("socket map \"%s\": error connecting to socket map: %s\n",
7853132943Sgshapiro				   map->map_mname, sm_errstring(save_errno));
7854132943Sgshapiro		CurHostName = p;
7855132943Sgshapiro# if NETINET6
7856132943Sgshapiro		if (hp != NULL)
7857132943Sgshapiro			freehostent(hp);
7858132943Sgshapiro# endif /* NETINET6 */
7859132943Sgshapiro		return false;
7860132943Sgshapiro	}
7861132943Sgshapiro# if NETINET6
7862132943Sgshapiro	if (hp != NULL)
7863132943Sgshapiro	{
7864132943Sgshapiro		freehostent(hp);
7865132943Sgshapiro		hp = NULL;
7866132943Sgshapiro	}
7867132943Sgshapiro# endif /* NETINET6 */
7868132943Sgshapiro	if ((map->map_db1 = (ARBPTR_T) sm_io_open(SmFtStdiofd,
7869132943Sgshapiro						  SM_TIME_DEFAULT,
7870132943Sgshapiro						  (void *) &sock,
7871132943Sgshapiro						  SM_IO_RDWR,
7872132943Sgshapiro						  NULL)) == NULL)
7873132943Sgshapiro	{
7874132943Sgshapiro		close(sock);
7875132943Sgshapiro		if (tTd(38, 2))
7876132943Sgshapiro		    sm_dprintf("socket_open (%s): failed to create stream: %s\n",
7877132943Sgshapiro			       map->map_mname, sm_errstring(errno));
7878132943Sgshapiro		return false;
7879132943Sgshapiro	}
7880132943Sgshapiro
7881285303Sgshapiro	tmo = map->map_timeout;
7882285303Sgshapiro	if (tmo == 0)
7883285303Sgshapiro		tmo = 30000;	/* default: 30s */
7884285303Sgshapiro	else
7885285303Sgshapiro		tmo *= 1000;	/* s -> ms */
7886285303Sgshapiro	sm_io_setinfo(map->map_db1, SM_IO_WHAT_TIMEOUT, &tmo);
7887285303Sgshapiro
7888132943Sgshapiro	/* Save connection for reuse */
7889132943Sgshapiro	s->s_socketmap = map;
7890132943Sgshapiro	return true;
7891132943Sgshapiro}
7892132943Sgshapiro
7893132943Sgshapiro/*
7894132943Sgshapiro**  SOCKET_MAP_FINDCONN -- find a SOCKET connection to the server
7895132943Sgshapiro**
7896132943Sgshapiro**	Cache SOCKET connections based on the connection specifier
7897132943Sgshapiro**	and PID so we don't have multiple connections open to
7898132943Sgshapiro**	the same server for different maps.  Need a separate connection
7899132943Sgshapiro**	per PID since a parent process may close the map before the
7900132943Sgshapiro**	child is done with it.
7901132943Sgshapiro**
7902132943Sgshapiro**	Parameters:
7903132943Sgshapiro**		conn -- SOCKET map connection specifier
7904132943Sgshapiro**
7905132943Sgshapiro**	Returns:
7906132943Sgshapiro**		Symbol table entry for the SOCKET connection.
7907132943Sgshapiro*/
7908132943Sgshapiro
7909132943Sgshapirostatic STAB *
7910132943Sgshapirosocket_map_findconn(conn)
7911132943Sgshapiro	const char *conn;
7912132943Sgshapiro{
7913132943Sgshapiro	char *nbuf;
7914132943Sgshapiro	STAB *SM_NONVOLATILE s = NULL;
7915132943Sgshapiro
7916132943Sgshapiro	nbuf = sm_stringf_x("%s%c%d", conn, CONDELSE, (int) CurrentPid);
7917132943Sgshapiro	SM_TRY
7918132943Sgshapiro		s = stab(nbuf, ST_SOCKETMAP, ST_ENTER);
7919132943Sgshapiro	SM_FINALLY
7920132943Sgshapiro		sm_free(nbuf);
7921132943Sgshapiro	SM_END_TRY
7922132943Sgshapiro	return s;
7923132943Sgshapiro}
7924132943Sgshapiro
7925132943Sgshapiro/*
7926132943Sgshapiro**  SOCKET_MAP_CLOSE -- close the socket
7927132943Sgshapiro*/
7928132943Sgshapiro
7929132943Sgshapirovoid
7930132943Sgshapirosocket_map_close(map)
7931132943Sgshapiro	MAP *map;
7932132943Sgshapiro{
7933132943Sgshapiro	STAB *s;
7934132943Sgshapiro	MAP *smap;
7935132943Sgshapiro
7936132943Sgshapiro	if (tTd(38, 20))
7937132943Sgshapiro		sm_dprintf("socket_map_close(%s), pid=%ld\n", map->map_file,
7938132943Sgshapiro			(long) CurrentPid);
7939132943Sgshapiro
7940132943Sgshapiro	/* Check if already closed */
7941132943Sgshapiro	if (map->map_db1 == NULL)
7942132943Sgshapiro	{
7943132943Sgshapiro		if (tTd(38, 20))
7944132943Sgshapiro			sm_dprintf("socket_map_close(%s) already closed\n",
7945132943Sgshapiro				map->map_file);
7946132943Sgshapiro		return;
7947132943Sgshapiro	}
7948132943Sgshapiro	sm_io_close((SM_FILE_T *)map->map_db1, SM_TIME_DEFAULT);
7949132943Sgshapiro
7950132943Sgshapiro	/* Mark all the maps that share the connection as closed */
7951132943Sgshapiro	s = socket_map_findconn(map->map_file);
7952132943Sgshapiro	smap = s->s_socketmap;
7953132943Sgshapiro	while (smap != NULL)
7954132943Sgshapiro	{
7955132943Sgshapiro		MAP *next;
7956132943Sgshapiro
7957132943Sgshapiro		if (tTd(38, 2) && smap != map)
7958132943Sgshapiro			sm_dprintf("socket_map_close(%s): closed %s (shared SOCKET connection)\n",
7959132943Sgshapiro				map->map_mname, smap->map_mname);
7960132943Sgshapiro
7961132943Sgshapiro		smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
7962132943Sgshapiro		smap->map_db1 = NULL;
7963132943Sgshapiro		next = smap->socket_map_next;
7964132943Sgshapiro		smap->socket_map_next = NULL;
7965132943Sgshapiro		smap = next;
7966132943Sgshapiro	}
7967132943Sgshapiro	s->s_socketmap = NULL;
7968132943Sgshapiro}
7969132943Sgshapiro
7970132943Sgshapiro/*
7971132943Sgshapiro** SOCKET_MAP_LOOKUP -- look up a datum in a SOCKET table
7972132943Sgshapiro*/
7973132943Sgshapiro
7974132943Sgshapirochar *
7975132943Sgshapirosocket_map_lookup(map, name, av, statp)
7976132943Sgshapiro	MAP *map;
7977132943Sgshapiro	char *name;
7978132943Sgshapiro	char **av;
7979132943Sgshapiro	int *statp;
7980132943Sgshapiro{
7981132943Sgshapiro	unsigned int nettolen, replylen, recvlen;
7982147078Sgshapiro	char *replybuf, *rval, *value, *status, *key;
7983132943Sgshapiro	SM_FILE_T *f;
7984147078Sgshapiro	char keybuf[MAXNAME + 1];
7985132943Sgshapiro
7986132943Sgshapiro	replybuf = NULL;
7987132943Sgshapiro	rval = NULL;
7988132943Sgshapiro	f = (SM_FILE_T *)map->map_db1;
7989132943Sgshapiro	if (tTd(38, 20))
7990132943Sgshapiro		sm_dprintf("socket_map_lookup(%s, %s) %s\n",
7991132943Sgshapiro			map->map_mname, name, map->map_file);
7992132943Sgshapiro
7993147078Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
7994147078Sgshapiro	{
7995147078Sgshapiro		nettolen = strlen(name);
7996168515Sgshapiro		if (nettolen > sizeof(keybuf) - 1)
7997168515Sgshapiro			nettolen = sizeof(keybuf) - 1;
7998147078Sgshapiro		memmove(keybuf, name, nettolen);
7999147078Sgshapiro		keybuf[nettolen] = '\0';
8000147078Sgshapiro		makelower(keybuf);
8001147078Sgshapiro		key = keybuf;
8002147078Sgshapiro	}
8003147078Sgshapiro	else
8004147078Sgshapiro		key = name;
8005147078Sgshapiro
8006147078Sgshapiro	nettolen = strlen(map->map_mname) + 1 + strlen(key);
8007132943Sgshapiro	SM_ASSERT(nettolen > strlen(map->map_mname));
8008147078Sgshapiro	SM_ASSERT(nettolen > strlen(key));
8009132943Sgshapiro	if ((sm_io_fprintf(f, SM_TIME_DEFAULT, "%u:%s %s,",
8010147078Sgshapiro			   nettolen, map->map_mname, key) == SM_IO_EOF) ||
8011132943Sgshapiro	    (sm_io_flush(f, SM_TIME_DEFAULT) != 0) ||
8012132943Sgshapiro	    (sm_io_error(f)))
8013132943Sgshapiro	{
8014132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): failed to send lookup request",
8015132943Sgshapiro			map->map_mname);
8016132943Sgshapiro		*statp = EX_TEMPFAIL;
8017132943Sgshapiro		goto errcl;
8018132943Sgshapiro	}
8019132943Sgshapiro
8020132943Sgshapiro	if (sm_io_fscanf(f, SM_TIME_DEFAULT, "%9u", &replylen) != 1)
8021132943Sgshapiro	{
8022285303Sgshapiro		if (errno == EAGAIN)
8023285303Sgshapiro		{
8024285303Sgshapiro			syserr("451 4.3.0 socket_map_lookup(%s): read timeout",
8025285303Sgshapiro				map->map_mname);
8026285303Sgshapiro		}
8027285303Sgshapiro		else
8028285303Sgshapiro		{
8029285303Sgshapiro			syserr("451 4.3.0 socket_map_lookup(%s): failed to read length parameter of reply %d",
8030285303Sgshapiro				map->map_mname, errno);
8031285303Sgshapiro		}
8032132943Sgshapiro		*statp = EX_TEMPFAIL;
8033132943Sgshapiro		goto errcl;
8034132943Sgshapiro	}
8035132943Sgshapiro	if (replylen > SOCKETMAP_MAXL)
8036132943Sgshapiro	{
8037132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): reply too long: %u",
8038132943Sgshapiro			   map->map_mname, replylen);
8039132943Sgshapiro		*statp = EX_TEMPFAIL;
8040132943Sgshapiro		goto errcl;
8041132943Sgshapiro	}
8042132943Sgshapiro	if (sm_io_getc(f, SM_TIME_DEFAULT) != ':')
8043132943Sgshapiro	{
8044132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): missing ':' in reply",
8045132943Sgshapiro			map->map_mname);
8046132943Sgshapiro		*statp = EX_TEMPFAIL;
8047132943Sgshapiro		goto error;
8048132943Sgshapiro	}
8049132943Sgshapiro
8050132943Sgshapiro	replybuf = (char *) sm_malloc(replylen + 1);
8051132943Sgshapiro	if (replybuf == NULL)
8052132943Sgshapiro	{
8053132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): can't allocate %u bytes",
8054132943Sgshapiro			map->map_mname, replylen + 1);
8055132943Sgshapiro		*statp = EX_OSERR;
8056132943Sgshapiro		goto error;
8057132943Sgshapiro	}
8058132943Sgshapiro
8059132943Sgshapiro	recvlen = sm_io_read(f, SM_TIME_DEFAULT, replybuf, replylen);
8060132943Sgshapiro	if (recvlen < replylen)
8061132943Sgshapiro	{
8062132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): received only %u of %u reply characters",
8063132943Sgshapiro			   map->map_mname, recvlen, replylen);
8064132943Sgshapiro		*statp = EX_TEMPFAIL;
8065132943Sgshapiro		goto errcl;
8066132943Sgshapiro	}
8067132943Sgshapiro	if (sm_io_getc(f, SM_TIME_DEFAULT) != ',')
8068132943Sgshapiro	{
8069132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): missing ',' in reply",
8070132943Sgshapiro			map->map_mname);
8071132943Sgshapiro		*statp = EX_TEMPFAIL;
8072132943Sgshapiro		goto errcl;
8073132943Sgshapiro	}
8074132943Sgshapiro	status = replybuf;
8075132943Sgshapiro	replybuf[recvlen] = '\0';
8076132943Sgshapiro	value = strchr(replybuf, ' ');
8077132943Sgshapiro	if (value != NULL)
8078132943Sgshapiro	{
8079132943Sgshapiro		*value = '\0';
8080132943Sgshapiro		value++;
8081132943Sgshapiro	}
8082132943Sgshapiro	if (strcmp(status, "OK") == 0)
8083132943Sgshapiro	{
8084132943Sgshapiro		*statp = EX_OK;
8085132943Sgshapiro
8086132943Sgshapiro		/* collect the return value */
8087132943Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
8088147078Sgshapiro			rval = map_rewrite(map, key, strlen(key), NULL);
8089132943Sgshapiro		else
8090132943Sgshapiro			rval = map_rewrite(map, value, strlen(value), av);
8091132943Sgshapiro	}
8092132943Sgshapiro	else if (strcmp(status, "NOTFOUND") == 0)
8093132943Sgshapiro	{
8094132943Sgshapiro		*statp = EX_NOTFOUND;
8095132943Sgshapiro		if (tTd(38, 20))
8096132943Sgshapiro			sm_dprintf("socket_map_lookup(%s): %s not found\n",
8097147078Sgshapiro				map->map_mname, key);
8098132943Sgshapiro	}
8099132943Sgshapiro	else
8100132943Sgshapiro	{
8101132943Sgshapiro		if (tTd(38, 5))
8102132943Sgshapiro			sm_dprintf("socket_map_lookup(%s, %s): server returned error: type=%s, reason=%s\n",
8103147078Sgshapiro				map->map_mname, key, status,
8104132943Sgshapiro				value ? value : "");
8105132943Sgshapiro		if ((strcmp(status, "TEMP") == 0) ||
8106132943Sgshapiro		    (strcmp(status, "TIMEOUT") == 0))
8107132943Sgshapiro			*statp = EX_TEMPFAIL;
8108132943Sgshapiro		else if(strcmp(status, "PERM") == 0)
8109132943Sgshapiro			*statp = EX_UNAVAILABLE;
8110132943Sgshapiro		else
8111132943Sgshapiro			*statp = EX_PROTOCOL;
8112132943Sgshapiro	}
8113132943Sgshapiro
8114132943Sgshapiro	if (replybuf != NULL)
8115132943Sgshapiro		sm_free(replybuf);
8116132943Sgshapiro	return rval;
8117132943Sgshapiro
8118132943Sgshapiro  errcl:
8119132943Sgshapiro	socket_map_close(map);
8120132943Sgshapiro  error:
8121132943Sgshapiro	if (replybuf != NULL)
8122132943Sgshapiro		sm_free(replybuf);
8123132943Sgshapiro	return rval;
8124132943Sgshapiro}
8125132943Sgshapiro#endif /* SOCKETMAP */
8126