map.c revision 157001
138032Speter/*
2147078Sgshapiro * Copyright (c) 1998-2005 Sendmail, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1992, 1995-1997 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1992, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1464562Sgshapiro#include <sendmail.h>
1538032Speter
16157001SgshapiroSM_RCSID("@(#)$Id: map.c,v 8.671 2005/10/25 17:55:50 ca Exp $")
1764562Sgshapiro
1890792Sgshapiro#if LDAPMAP
1990792Sgshapiro# include <sm/ldap.h>
2090792Sgshapiro#endif /* LDAPMAP */
2190792Sgshapiro
2290792Sgshapiro#if NDBM
2338032Speter# include <ndbm.h>
2438032Speter# ifdef R_FIRST
2538032Speter  ERROR README:	You are running the Berkeley DB version of ndbm.h.  See
2638032Speter  ERROR README:	the README file about tweaking Berkeley DB so it can
2738032Speter  ERROR README:	coexist with NDBM, or delete -DNDBM from the Makefile
2838032Speter  ERROR README: and use -DNEWDB instead.
2964562Sgshapiro# endif /* R_FIRST */
3064562Sgshapiro#endif /* NDBM */
3190792Sgshapiro#if NEWDB
32110560Sgshapiro# include "sm/bdb.h"
3364562Sgshapiro#endif /* NEWDB */
3490792Sgshapiro#if NIS
3538032Speter  struct dom_binding;	/* forward reference needed on IRIX */
3638032Speter# include <rpcsvc/ypclnt.h>
3790792Sgshapiro# if NDBM
3838032Speter#  define NDBM_YP_COMPAT	/* create YP-compatible NDBM files */
3964562Sgshapiro# endif /* NDBM */
4064562Sgshapiro#endif /* NIS */
4138032Speter
4290792Sgshapiro#if NEWDB
4364562Sgshapiro# if DB_VERSION_MAJOR < 2
4464562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
4564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
4664562Sgshapiro# if DB_VERSION_MAJOR == 2
4764562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
4864562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
4964562Sgshapiro# if DB_VERSION_MAJOR > 2
5064562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, void **));
5164562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
5264562Sgshapiro#endif /* NEWDB */
5373188Sgshapirostatic bool	extract_canonname __P((char *, char *, char *, char[], int));
5490792Sgshapirostatic void	map_close __P((STAB *, int));
5590792Sgshapirostatic void	map_init __P((STAB *, int));
5664562Sgshapiro#ifdef LDAPMAP
5790792Sgshapirostatic STAB *	ldapmap_findconn __P((SM_LDAP_STRUCT *));
5864562Sgshapiro#endif /* LDAPMAP */
5990792Sgshapiro#if NISPLUS
6064562Sgshapirostatic bool	nisplus_getcanonname __P((char *, int, int *));
6164562Sgshapiro#endif /* NISPLUS */
6290792Sgshapiro#if NIS
6364562Sgshapirostatic bool	nis_getcanonname __P((char *, int, int *));
6464562Sgshapiro#endif /* NIS */
6564562Sgshapiro#if NETINFO
6664562Sgshapirostatic bool	ni_getcanonname __P((char *, int, int *));
6764562Sgshapiro#endif /* NETINFO */
6864562Sgshapirostatic bool	text_getcanonname __P((char *, int, int *));
69132943Sgshapiro#if SOCKETMAP
70132943Sgshapirostatic STAB	*socket_map_findconn __P((const char*));
7164562Sgshapiro
72132943Sgshapiro/* XXX arbitrary limit for sanity */
73132943Sgshapiro# define SOCKETMAP_MAXL 1000000
74132943Sgshapiro#endif /* SOCKETMAP */
75132943Sgshapiro
7690792Sgshapiro/* default error message for trying to open a map in write mode */
7790792Sgshapiro#ifdef ENOSYS
7890792Sgshapiro# define SM_EMAPCANTWRITE	ENOSYS
7990792Sgshapiro#else /* ENOSYS */
8090792Sgshapiro# ifdef EFTYPE
8190792Sgshapiro#  define SM_EMAPCANTWRITE	EFTYPE
8290792Sgshapiro# else /* EFTYPE */
8390792Sgshapiro#  define SM_EMAPCANTWRITE	ENXIO
8490792Sgshapiro# endif /* EFTYPE */
8590792Sgshapiro#endif /* ENOSYS */
8690792Sgshapiro
8738032Speter/*
8838032Speter**  MAP.C -- implementations for various map classes.
8938032Speter**
9038032Speter**	Each map class implements a series of functions:
9138032Speter**
9238032Speter**	bool map_parse(MAP *map, char *args)
9390792Sgshapiro**		Parse the arguments from the config file.  Return true
9490792Sgshapiro**		if they were ok, false otherwise.  Fill in map with the
9538032Speter**		values.
9638032Speter**
9738032Speter**	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
9838032Speter**		Look up the key in the given map.  If found, do any
9938032Speter**		rewriting the map wants (including "args" if desired)
10038032Speter**		and return the value.  Set *pstat to the appropriate status
10138032Speter**		on error and return NULL.  Args will be NULL if called
10238032Speter**		from the alias routines, although this should probably
10338032Speter**		not be relied upon.  It is suggested you call map_rewrite
10438032Speter**		to return the results -- it takes care of null termination
10538032Speter**		and uses a dynamically expanded buffer as needed.
10638032Speter**
10738032Speter**	void map_store(MAP *map, char *key, char *value)
10838032Speter**		Store the key:value pair in the map.
10938032Speter**
11038032Speter**	bool map_open(MAP *map, int mode)
11138032Speter**		Open the map for the indicated mode.  Mode should
11290792Sgshapiro**		be either O_RDONLY or O_RDWR.  Return true if it
11390792Sgshapiro**		was opened successfully, false otherwise.  If the open
11490792Sgshapiro**		failed and the MF_OPTIONAL flag is not set, it should
11538032Speter**		also print an error.  If the MF_ALIAS bit is set
11638032Speter**		and this map class understands the @:@ convention, it
11738032Speter**		should call aliaswait() before returning.
11838032Speter**
11938032Speter**	void map_close(MAP *map)
12038032Speter**		Close the map.
12138032Speter**
12238032Speter**	This file also includes the implementation for getcanonname.
12338032Speter**	It is currently implemented in a pretty ad-hoc manner; it ought
12438032Speter**	to be more properly integrated into the map structure.
12538032Speter*/
12638032Speter
12738032Speter#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
12838032Speter# define LOCK_ON_OPEN	1	/* we can open/create a locked file */
12964562Sgshapiro#else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
13038032Speter# define LOCK_ON_OPEN	0	/* no such luck -- bend over backwards */
13164562Sgshapiro#endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
13238032Speter
13390792Sgshapiro/*
13438032Speter**  MAP_PARSEARGS -- parse config line arguments for database lookup
13538032Speter**
13638032Speter**	This is a generic version of the map_parse method.
13738032Speter**
13838032Speter**	Parameters:
13938032Speter**		map -- the map being initialized.
14038032Speter**		ap -- a pointer to the args on the config line.
14138032Speter**
14238032Speter**	Returns:
14390792Sgshapiro**		true -- if everything parsed OK.
14490792Sgshapiro**		false -- otherwise.
14538032Speter**
14638032Speter**	Side Effects:
14738032Speter**		null terminates the filename; stores it in map
14838032Speter*/
14938032Speter
15038032Speterbool
15138032Spetermap_parseargs(map, ap)
15238032Speter	MAP *map;
15338032Speter	char *ap;
15438032Speter{
15538032Speter	register char *p = ap;
15638032Speter
15764562Sgshapiro	/*
15890792Sgshapiro	**  There is no check whether there is really an argument,
15990792Sgshapiro	**  but that's not important enough to warrant extra code.
16064562Sgshapiro	*/
16190792Sgshapiro
16290792Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
16364562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
16438032Speter	for (;;)
16538032Speter	{
16638032Speter		while (isascii(*p) && isspace(*p))
16738032Speter			p++;
16838032Speter		if (*p != '-')
16938032Speter			break;
17038032Speter		switch (*++p)
17138032Speter		{
17238032Speter		  case 'N':
17338032Speter			map->map_mflags |= MF_INCLNULL;
17438032Speter			map->map_mflags &= ~MF_TRY0NULL;
17538032Speter			break;
17638032Speter
17738032Speter		  case 'O':
17838032Speter			map->map_mflags &= ~MF_TRY1NULL;
17938032Speter			break;
18038032Speter
18138032Speter		  case 'o':
18238032Speter			map->map_mflags |= MF_OPTIONAL;
18338032Speter			break;
18438032Speter
18538032Speter		  case 'f':
18638032Speter			map->map_mflags |= MF_NOFOLDCASE;
18738032Speter			break;
18838032Speter
18938032Speter		  case 'm':
19038032Speter			map->map_mflags |= MF_MATCHONLY;
19138032Speter			break;
19238032Speter
19338032Speter		  case 'A':
19438032Speter			map->map_mflags |= MF_APPEND;
19538032Speter			break;
19638032Speter
19738032Speter		  case 'q':
19838032Speter			map->map_mflags |= MF_KEEPQUOTES;
19938032Speter			break;
20038032Speter
20138032Speter		  case 'a':
20238032Speter			map->map_app = ++p;
20338032Speter			break;
20438032Speter
20538032Speter		  case 'T':
20638032Speter			map->map_tapp = ++p;
20738032Speter			break;
20838032Speter
20938032Speter		  case 'k':
21038032Speter			while (isascii(*++p) && isspace(*p))
21138032Speter				continue;
21238032Speter			map->map_keycolnm = p;
21338032Speter			break;
21438032Speter
21538032Speter		  case 'v':
21638032Speter			while (isascii(*++p) && isspace(*p))
21738032Speter				continue;
21838032Speter			map->map_valcolnm = p;
21938032Speter			break;
22038032Speter
22138032Speter		  case 'z':
22238032Speter			if (*++p != '\\')
22338032Speter				map->map_coldelim = *p;
22438032Speter			else
22538032Speter			{
22638032Speter				switch (*++p)
22738032Speter				{
22838032Speter				  case 'n':
22938032Speter					map->map_coldelim = '\n';
23038032Speter					break;
23138032Speter
23238032Speter				  case 't':
23338032Speter					map->map_coldelim = '\t';
23438032Speter					break;
23538032Speter
23638032Speter				  default:
23738032Speter					map->map_coldelim = '\\';
23838032Speter				}
23938032Speter			}
24038032Speter			break;
24138032Speter
24238032Speter		  case 't':
24338032Speter			map->map_mflags |= MF_NODEFER;
24438032Speter			break;
24538032Speter
24664562Sgshapiro
24764562Sgshapiro		  case 'S':
24864562Sgshapiro			map->map_spacesub = *++p;
24938032Speter			break;
25038032Speter
25164562Sgshapiro		  case 'D':
25264562Sgshapiro			map->map_mflags |= MF_DEFER;
25338032Speter			break;
25464562Sgshapiro
25564562Sgshapiro		  default:
25664562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
25764562Sgshapiro			break;
25838032Speter		}
25938032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
26038032Speter			p++;
26138032Speter		if (*p != '\0')
26238032Speter			*p++ = '\0';
26338032Speter	}
26438032Speter	if (map->map_app != NULL)
26538032Speter		map->map_app = newstr(map->map_app);
26638032Speter	if (map->map_tapp != NULL)
26738032Speter		map->map_tapp = newstr(map->map_tapp);
26838032Speter	if (map->map_keycolnm != NULL)
26938032Speter		map->map_keycolnm = newstr(map->map_keycolnm);
27038032Speter	if (map->map_valcolnm != NULL)
27138032Speter		map->map_valcolnm = newstr(map->map_valcolnm);
27238032Speter
27338032Speter	if (*p != '\0')
27438032Speter	{
27538032Speter		map->map_file = p;
27638032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
27738032Speter			p++;
27838032Speter		if (*p != '\0')
27938032Speter			*p++ = '\0';
28038032Speter		map->map_file = newstr(map->map_file);
28138032Speter	}
28238032Speter
28338032Speter	while (*p != '\0' && isascii(*p) && isspace(*p))
28438032Speter		p++;
28538032Speter	if (*p != '\0')
28638032Speter		map->map_rebuild = newstr(p);
28738032Speter
28838032Speter	if (map->map_file == NULL &&
28938032Speter	    !bitset(MCF_OPTFILE, map->map_class->map_cflags))
29038032Speter	{
29138032Speter		syserr("No file name for %s map %s",
29238032Speter			map->map_class->map_cname, map->map_mname);
29390792Sgshapiro		return false;
29438032Speter	}
29590792Sgshapiro	return true;
29638032Speter}
29790792Sgshapiro/*
29838032Speter**  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
29938032Speter**
30038032Speter**	It also adds the map_app string.  It can be used as a utility
30138032Speter**	in the map_lookup method.
30238032Speter**
30338032Speter**	Parameters:
30438032Speter**		map -- the map that causes this.
30538032Speter**		s -- the string to rewrite, NOT necessarily null terminated.
30638032Speter**		slen -- the length of s.
30738032Speter**		av -- arguments to interpolate into buf.
30838032Speter**
30938032Speter**	Returns:
31038032Speter**		Pointer to rewritten result.  This is static data that
31138032Speter**		should be copied if it is to be saved!
31238032Speter*/
31338032Speter
31438032Speterchar *
31538032Spetermap_rewrite(map, s, slen, av)
31638032Speter	register MAP *map;
31738032Speter	register const char *s;
31838032Speter	size_t slen;
31938032Speter	char **av;
32038032Speter{
32138032Speter	register char *bp;
32238032Speter	register char c;
32338032Speter	char **avp;
32438032Speter	register char *ap;
32538032Speter	size_t l;
32638032Speter	size_t len;
32738032Speter	static size_t buflen = 0;
32838032Speter	static char *buf = NULL;
32938032Speter
33038032Speter	if (tTd(39, 1))
33138032Speter	{
33290792Sgshapiro		sm_dprintf("map_rewrite(%.*s), av =", (int) slen, s);
33338032Speter		if (av == NULL)
33490792Sgshapiro			sm_dprintf(" (nullv)");
33538032Speter		else
33638032Speter		{
33738032Speter			for (avp = av; *avp != NULL; avp++)
33890792Sgshapiro				sm_dprintf("\n\t%s", *avp);
33938032Speter		}
34090792Sgshapiro		sm_dprintf("\n");
34138032Speter	}
34238032Speter
34338032Speter	/* count expected size of output (can safely overestimate) */
34438032Speter	l = len = slen;
34538032Speter	if (av != NULL)
34638032Speter	{
34738032Speter		const char *sp = s;
34838032Speter
34938032Speter		while (l-- > 0 && (c = *sp++) != '\0')
35038032Speter		{
35138032Speter			if (c != '%')
35238032Speter				continue;
35338032Speter			if (l-- <= 0)
35438032Speter				break;
35538032Speter			c = *sp++;
35638032Speter			if (!(isascii(c) && isdigit(c)))
35738032Speter				continue;
35838032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
35938032Speter				continue;
36038032Speter			if (*avp == NULL)
36138032Speter				continue;
36238032Speter			len += strlen(*avp);
36338032Speter		}
36438032Speter	}
36538032Speter	if (map->map_app != NULL)
36638032Speter		len += strlen(map->map_app);
36738032Speter	if (buflen < ++len)
36838032Speter	{
36938032Speter		/* need to malloc additional space */
37038032Speter		buflen = len;
37138032Speter		if (buf != NULL)
37277349Sgshapiro			sm_free(buf);
37390792Sgshapiro		buf = sm_pmalloc_x(buflen);
37438032Speter	}
37538032Speter
37638032Speter	bp = buf;
37738032Speter	if (av == NULL)
37838032Speter	{
37964562Sgshapiro		memmove(bp, s, slen);
38038032Speter		bp += slen;
38164562Sgshapiro
38264562Sgshapiro		/* assert(len > slen); */
38364562Sgshapiro		len -= slen;
38438032Speter	}
38538032Speter	else
38638032Speter	{
38738032Speter		while (slen-- > 0 && (c = *s++) != '\0')
38838032Speter		{
38938032Speter			if (c != '%')
39038032Speter			{
39138032Speter  pushc:
392120256Sgshapiro				if (len-- <= 1)
39390792Sgshapiro				     break;
39438032Speter				*bp++ = c;
39538032Speter				continue;
39638032Speter			}
39738032Speter			if (slen-- <= 0 || (c = *s++) == '\0')
39838032Speter				c = '%';
39938032Speter			if (c == '%')
40038032Speter				goto pushc;
40138032Speter			if (!(isascii(c) && isdigit(c)))
40238032Speter			{
403120256Sgshapiro				if (len-- <= 1)
404120256Sgshapiro				     break;
40538032Speter				*bp++ = '%';
40638032Speter				goto pushc;
40738032Speter			}
40838032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
40938032Speter				continue;
41038032Speter			if (*avp == NULL)
41138032Speter				continue;
41238032Speter
41338032Speter			/* transliterate argument into output string */
41464562Sgshapiro			for (ap = *avp; (c = *ap++) != '\0' && len > 0; --len)
41538032Speter				*bp++ = c;
41638032Speter		}
41738032Speter	}
41864562Sgshapiro	if (map->map_app != NULL && len > 0)
41990792Sgshapiro		(void) sm_strlcpy(bp, map->map_app, len);
42038032Speter	else
42138032Speter		*bp = '\0';
42238032Speter	if (tTd(39, 1))
42390792Sgshapiro		sm_dprintf("map_rewrite => %s\n", buf);
42438032Speter	return buf;
42538032Speter}
42690792Sgshapiro/*
42764562Sgshapiro**  INITMAPS -- rebuild alias maps
42838032Speter**
42938032Speter**	Parameters:
43064562Sgshapiro**		none.
43138032Speter**
43238032Speter**	Returns:
43338032Speter**		none.
43438032Speter*/
43538032Speter
43638032Spetervoid
43764562Sgshapiroinitmaps()
43838032Speter{
43938032Speter#if XDEBUG
44038032Speter	checkfd012("entering initmaps");
44164562Sgshapiro#endif /* XDEBUG */
44238032Speter	stabapply(map_init, 0);
44338032Speter#if XDEBUG
44438032Speter	checkfd012("exiting initmaps");
44564562Sgshapiro#endif /* XDEBUG */
44638032Speter}
44790792Sgshapiro/*
44864562Sgshapiro**  MAP_INIT -- rebuild a map
44964562Sgshapiro**
45064562Sgshapiro**	Parameters:
45164562Sgshapiro**		s -- STAB entry: if map: try to rebuild
45264562Sgshapiro**		unused -- unused variable
45364562Sgshapiro**
45464562Sgshapiro**	Returns:
45564562Sgshapiro**		none.
45664562Sgshapiro**
45764562Sgshapiro**	Side Effects:
45864562Sgshapiro**		will close already open rebuildable map.
45964562Sgshapiro*/
46038032Speter
46164562Sgshapiro/* ARGSUSED1 */
46264562Sgshapirostatic void
46364562Sgshapiromap_init(s, unused)
46438032Speter	register STAB *s;
46564562Sgshapiro	int unused;
46638032Speter{
46738032Speter	register MAP *map;
46838032Speter
46938032Speter	/* has to be a map */
47090792Sgshapiro	if (s->s_symtype != ST_MAP)
47138032Speter		return;
47238032Speter
47338032Speter	map = &s->s_map;
47438032Speter	if (!bitset(MF_VALID, map->map_mflags))
47538032Speter		return;
47638032Speter
47738032Speter	if (tTd(38, 2))
47890792Sgshapiro		sm_dprintf("map_init(%s:%s, %s)\n",
47938032Speter			map->map_class->map_cname == NULL ? "NULL" :
48038032Speter				map->map_class->map_cname,
48138032Speter			map->map_mname == NULL ? "NULL" : map->map_mname,
48264562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
48338032Speter
48464562Sgshapiro	if (!bitset(MF_ALIAS, map->map_mflags) ||
48564562Sgshapiro	    !bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
48638032Speter	{
48738032Speter		if (tTd(38, 3))
48890792Sgshapiro			sm_dprintf("\tnot rebuildable\n");
48938032Speter		return;
49038032Speter	}
49138032Speter
49238032Speter	/* if already open, close it (for nested open) */
49338032Speter	if (bitset(MF_OPEN, map->map_mflags))
49438032Speter	{
49577349Sgshapiro		map->map_mflags |= MF_CLOSING;
49638032Speter		map->map_class->map_close(map);
49777349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
49838032Speter	}
49938032Speter
50090792Sgshapiro	(void) rebuildaliases(map, false);
50164562Sgshapiro	return;
50264562Sgshapiro}
50390792Sgshapiro/*
50464562Sgshapiro**  OPENMAP -- open a map
50564562Sgshapiro**
50664562Sgshapiro**	Parameters:
50764562Sgshapiro**		map -- map to open (it must not be open).
50864562Sgshapiro**
50964562Sgshapiro**	Returns:
51064562Sgshapiro**		whether open succeeded.
51164562Sgshapiro*/
51264562Sgshapiro
51364562Sgshapirobool
51464562Sgshapiroopenmap(map)
51564562Sgshapiro	MAP *map;
51664562Sgshapiro{
51790792Sgshapiro	bool restore = false;
51864562Sgshapiro	bool savehold = HoldErrs;
51964562Sgshapiro	bool savequick = QuickAbort;
52064562Sgshapiro	int saveerrors = Errors;
52164562Sgshapiro
52264562Sgshapiro	if (!bitset(MF_VALID, map->map_mflags))
52390792Sgshapiro		return false;
52464562Sgshapiro
52564562Sgshapiro	/* better safe than sorry... */
52664562Sgshapiro	if (bitset(MF_OPEN, map->map_mflags))
52790792Sgshapiro		return true;
52864562Sgshapiro
52964562Sgshapiro	/* Don't send a map open error out via SMTP */
53064562Sgshapiro	if ((OnlyOneError || QuickAbort) &&
53164562Sgshapiro	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))
53238032Speter	{
53390792Sgshapiro		restore = true;
53490792Sgshapiro		HoldErrs = true;
53590792Sgshapiro		QuickAbort = false;
53638032Speter	}
53738032Speter
53864562Sgshapiro	errno = 0;
53938032Speter	if (map->map_class->map_open(map, O_RDONLY))
54038032Speter	{
54138032Speter		if (tTd(38, 4))
54290792Sgshapiro			sm_dprintf("openmap()\t%s:%s %s: valid\n",
54338032Speter				map->map_class->map_cname == NULL ? "NULL" :
54438032Speter					map->map_class->map_cname,
54538032Speter				map->map_mname == NULL ? "NULL" :
54638032Speter					map->map_mname,
54738032Speter				map->map_file == NULL ? "NULL" :
54838032Speter					map->map_file);
54938032Speter		map->map_mflags |= MF_OPEN;
55090792Sgshapiro		map->map_pid = CurrentPid;
55138032Speter	}
55238032Speter	else
55338032Speter	{
55438032Speter		if (tTd(38, 4))
55590792Sgshapiro			sm_dprintf("openmap()\t%s:%s %s: invalid%s%s\n",
55638032Speter				map->map_class->map_cname == NULL ? "NULL" :
55738032Speter					map->map_class->map_cname,
55838032Speter				map->map_mname == NULL ? "NULL" :
55938032Speter					map->map_mname,
56038032Speter				map->map_file == NULL ? "NULL" :
56138032Speter					map->map_file,
56264562Sgshapiro				errno == 0 ? "" : ": ",
56390792Sgshapiro				errno == 0 ? "" : sm_errstring(errno));
56438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
56538032Speter		{
56638032Speter			extern MAPCLASS BogusMapClass;
56738032Speter
56890792Sgshapiro			map->map_orgclass = map->map_class;
56938032Speter			map->map_class = &BogusMapClass;
57090792Sgshapiro			map->map_mflags |= MF_OPEN|MF_OPENBOGUS;
57190792Sgshapiro			map->map_pid = CurrentPid;
57238032Speter		}
57364562Sgshapiro		else
57464562Sgshapiro		{
57564562Sgshapiro			/* don't try again */
57664562Sgshapiro			map->map_mflags &= ~MF_VALID;
57764562Sgshapiro		}
57838032Speter	}
57964562Sgshapiro
58064562Sgshapiro	if (restore)
58164562Sgshapiro	{
58264562Sgshapiro		Errors = saveerrors;
58364562Sgshapiro		HoldErrs = savehold;
58464562Sgshapiro		QuickAbort = savequick;
58564562Sgshapiro	}
58664562Sgshapiro
58764562Sgshapiro	return bitset(MF_OPEN, map->map_mflags);
58838032Speter}
58990792Sgshapiro/*
59042575Speter**  CLOSEMAPS -- close all open maps opened by the current pid.
59142575Speter**
59242575Speter**	Parameters:
59390792Sgshapiro**		bogus -- only close bogus maps.
59442575Speter**
59542575Speter**	Returns:
59642575Speter**		none.
59742575Speter*/
59842575Speter
59942575Spetervoid
60090792Sgshapiroclosemaps(bogus)
60190792Sgshapiro	bool bogus;
60242575Speter{
60390792Sgshapiro	stabapply(map_close, bogus);
60442575Speter}
60590792Sgshapiro/*
60664562Sgshapiro**  MAP_CLOSE -- close a map opened by the current pid.
60764562Sgshapiro**
60864562Sgshapiro**	Parameters:
60990792Sgshapiro**		s -- STAB entry: if map: try to close
61090792Sgshapiro**		bogus -- only close bogus maps or MCF_NOTPERSIST maps.
61164562Sgshapiro**
61264562Sgshapiro**	Returns:
61364562Sgshapiro**		none.
61464562Sgshapiro*/
61542575Speter
61642575Speter/* ARGSUSED1 */
61764562Sgshapirostatic void
61890792Sgshapiromap_close(s, bogus)
61942575Speter	register STAB *s;
62090792Sgshapiro	int bogus;	/* int because of stabapply(), used as bool */
62142575Speter{
62242575Speter	MAP *map;
62390792Sgshapiro	extern MAPCLASS BogusMapClass;
62442575Speter
62590792Sgshapiro	if (s->s_symtype != ST_MAP)
62642575Speter		return;
62764562Sgshapiro
62842575Speter	map = &s->s_map;
62942575Speter
63090792Sgshapiro	/*
63190792Sgshapiro	**  close the map iff:
63290792Sgshapiro	**  it is valid and open and opened by this process
63390792Sgshapiro	**  and (!bogus or it's a bogus map or it is not persistent)
63490792Sgshapiro	**  negate this: return iff
63590792Sgshapiro	**  it is not valid or it is not open or not opened by this process
63690792Sgshapiro	**  or (bogus and it's not a bogus map and it's not not-persistent)
63790792Sgshapiro	*/
63890792Sgshapiro
63942575Speter	if (!bitset(MF_VALID, map->map_mflags) ||
64042575Speter	    !bitset(MF_OPEN, map->map_mflags) ||
64177349Sgshapiro	    bitset(MF_CLOSING, map->map_mflags) ||
64290792Sgshapiro	    map->map_pid != CurrentPid ||
64390792Sgshapiro	    (bogus && map->map_class != &BogusMapClass &&
64490792Sgshapiro	     !bitset(MCF_NOTPERSIST, map->map_class->map_cflags)))
64542575Speter		return;
64664562Sgshapiro
64790792Sgshapiro	if (map->map_class == &BogusMapClass && map->map_orgclass != NULL &&
64890792Sgshapiro	    map->map_orgclass != &BogusMapClass)
64990792Sgshapiro		map->map_class = map->map_orgclass;
65042575Speter	if (tTd(38, 5))
65190792Sgshapiro		sm_dprintf("closemaps: closing %s (%s)\n",
65264562Sgshapiro			map->map_mname == NULL ? "NULL" : map->map_mname,
65364562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
65464562Sgshapiro
65590792Sgshapiro	if (!bitset(MF_OPENBOGUS, map->map_mflags))
65690792Sgshapiro	{
65790792Sgshapiro		map->map_mflags |= MF_CLOSING;
65890792Sgshapiro		map->map_class->map_close(map);
65990792Sgshapiro	}
66090792Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_OPENBOGUS|MF_CLOSING);
66142575Speter}
66290792Sgshapiro/*
66338032Speter**  GETCANONNAME -- look up name using service switch
66438032Speter**
66538032Speter**	Parameters:
66638032Speter**		host -- the host name to look up.
66738032Speter**		hbsize -- the size of the host buffer.
66838032Speter**		trymx -- if set, try MX records.
66990792Sgshapiro**		pttl -- pointer to return TTL (can be NULL).
67038032Speter**
67138032Speter**	Returns:
67290792Sgshapiro**		true -- if the host was found.
67390792Sgshapiro**		false -- otherwise.
67438032Speter*/
67538032Speter
67638032Speterbool
67790792Sgshapirogetcanonname(host, hbsize, trymx, pttl)
67838032Speter	char *host;
67938032Speter	int hbsize;
68038032Speter	bool trymx;
68190792Sgshapiro	int *pttl;
68238032Speter{
68338032Speter	int nmaps;
68438032Speter	int mapno;
68590792Sgshapiro	bool found = false;
68690792Sgshapiro	bool got_tempfail = false;
68764562Sgshapiro	auto int status;
68838032Speter	char *maptype[MAXMAPSTACK];
68938032Speter	short mapreturn[MAXMAPACTIONS];
69038032Speter
69138032Speter	nmaps = switch_map_find("hosts", maptype, mapreturn);
69290792Sgshapiro	if (pttl != 0)
69390792Sgshapiro		*pttl = SM_DEFAULT_TTL;
69438032Speter	for (mapno = 0; mapno < nmaps; mapno++)
69538032Speter	{
69638032Speter		int i;
69738032Speter
69838032Speter		if (tTd(38, 20))
69990792Sgshapiro			sm_dprintf("getcanonname(%s), trying %s\n",
70038032Speter				host, maptype[mapno]);
70138032Speter		if (strcmp("files", maptype[mapno]) == 0)
70238032Speter		{
70364562Sgshapiro			found = text_getcanonname(host, hbsize, &status);
70438032Speter		}
70590792Sgshapiro#if NIS
70638032Speter		else if (strcmp("nis", maptype[mapno]) == 0)
70738032Speter		{
70864562Sgshapiro			found = nis_getcanonname(host, hbsize, &status);
70938032Speter		}
71064562Sgshapiro#endif /* NIS */
71190792Sgshapiro#if NISPLUS
71238032Speter		else if (strcmp("nisplus", maptype[mapno]) == 0)
71338032Speter		{
71464562Sgshapiro			found = nisplus_getcanonname(host, hbsize, &status);
71538032Speter		}
71664562Sgshapiro#endif /* NISPLUS */
71738032Speter#if NAMED_BIND
71838032Speter		else if (strcmp("dns", maptype[mapno]) == 0)
71938032Speter		{
72090792Sgshapiro			found = dns_getcanonname(host, hbsize, trymx, &status,							 pttl);
72138032Speter		}
72264562Sgshapiro#endif /* NAMED_BIND */
72338032Speter#if NETINFO
72438032Speter		else if (strcmp("netinfo", maptype[mapno]) == 0)
72538032Speter		{
72664562Sgshapiro			found = ni_getcanonname(host, hbsize, &status);
72738032Speter		}
72864562Sgshapiro#endif /* NETINFO */
72938032Speter		else
73038032Speter		{
73190792Sgshapiro			found = false;
73264562Sgshapiro			status = EX_UNAVAILABLE;
73338032Speter		}
73438032Speter
73538032Speter		/*
73638032Speter		**  Heuristic: if $m is not set, we are running during system
73738032Speter		**  startup.  In this case, when a name is apparently found
73838032Speter		**  but has no dot, treat is as not found.  This avoids
73938032Speter		**  problems if /etc/hosts has no FQDN but is listed first
74038032Speter		**  in the service switch.
74138032Speter		*/
74238032Speter
74338032Speter		if (found &&
74438032Speter		    (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
74538032Speter			break;
74638032Speter
74738032Speter		/* see if we should continue */
74864562Sgshapiro		if (status == EX_TEMPFAIL)
74938032Speter		{
75038032Speter			i = MA_TRYAGAIN;
75190792Sgshapiro			got_tempfail = true;
75238032Speter		}
75364562Sgshapiro		else if (status == EX_NOTFOUND)
75438032Speter			i = MA_NOTFOUND;
75538032Speter		else
75638032Speter			i = MA_UNAVAIL;
75738032Speter		if (bitset(1 << mapno, mapreturn[i]))
75838032Speter			break;
75938032Speter	}
76038032Speter
76138032Speter	if (found)
76238032Speter	{
76338032Speter		char *d;
76438032Speter
76538032Speter		if (tTd(38, 20))
76690792Sgshapiro			sm_dprintf("getcanonname(%s), found\n", host);
76738032Speter
76838032Speter		/*
76938032Speter		**  If returned name is still single token, compensate
77038032Speter		**  by tagging on $m.  This is because some sites set
77138032Speter		**  up their DNS or NIS databases wrong.
77238032Speter		*/
77338032Speter
77438032Speter		if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
77538032Speter		{
77638032Speter			d = macvalue('m', CurEnv);
77738032Speter			if (d != NULL &&
77838032Speter			    hbsize > (int) (strlen(host) + strlen(d) + 1))
77938032Speter			{
78038032Speter				if (host[strlen(host) - 1] != '.')
78190792Sgshapiro					(void) sm_strlcat2(host, ".", d,
78290792Sgshapiro							   hbsize);
78390792Sgshapiro				else
78490792Sgshapiro					(void) sm_strlcat(host, d, hbsize);
78538032Speter			}
78638032Speter			else
78790792Sgshapiro				return false;
78838032Speter		}
78990792Sgshapiro		return true;
79038032Speter	}
79138032Speter
79238032Speter	if (tTd(38, 20))
79390792Sgshapiro		sm_dprintf("getcanonname(%s), failed, status=%d\n", host,
79490792Sgshapiro			status);
79538032Speter
79638032Speter	if (got_tempfail)
79773188Sgshapiro		SM_SET_H_ERRNO(TRY_AGAIN);
79838032Speter	else
79973188Sgshapiro		SM_SET_H_ERRNO(HOST_NOT_FOUND);
80090792Sgshapiro
80190792Sgshapiro	return false;
80238032Speter}
80390792Sgshapiro/*
80438032Speter**  EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
80538032Speter**
80638032Speter**	Parameters:
80738032Speter**		name -- the name against which to match.
80873188Sgshapiro**		dot -- where to reinsert '.' to get FQDN
80938032Speter**		line -- the /etc/hosts line.
81038032Speter**		cbuf -- the location to store the result.
81138032Speter**		cbuflen -- the size of cbuf.
81238032Speter**
81338032Speter**	Returns:
81490792Sgshapiro**		true -- if the line matched the desired name.
81590792Sgshapiro**		false -- otherwise.
81638032Speter*/
81738032Speter
81864562Sgshapirostatic bool
81973188Sgshapiroextract_canonname(name, dot, line, cbuf, cbuflen)
82038032Speter	char *name;
82173188Sgshapiro	char *dot;
82238032Speter	char *line;
82338032Speter	char cbuf[];
82438032Speter	int cbuflen;
82538032Speter{
82638032Speter	int i;
82738032Speter	char *p;
82890792Sgshapiro	bool found = false;
82938032Speter
83038032Speter	cbuf[0] = '\0';
83138032Speter	if (line[0] == '#')
83290792Sgshapiro		return false;
83338032Speter
83438032Speter	for (i = 1; ; i++)
83538032Speter	{
83638032Speter		char nbuf[MAXNAME + 1];
83738032Speter
83838032Speter		p = get_column(line, i, '\0', nbuf, sizeof nbuf);
83938032Speter		if (p == NULL)
84038032Speter			break;
84138032Speter		if (*p == '\0')
84238032Speter			continue;
84338032Speter		if (cbuf[0] == '\0' ||
84438032Speter		    (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
84538032Speter		{
84690792Sgshapiro			(void) sm_strlcpy(cbuf, p, cbuflen);
84738032Speter		}
84890792Sgshapiro		if (sm_strcasecmp(name, p) == 0)
84990792Sgshapiro			found = true;
85073188Sgshapiro		else if (dot != NULL)
85173188Sgshapiro		{
85273188Sgshapiro			/* try looking for the FQDN as well */
85373188Sgshapiro			*dot = '.';
85490792Sgshapiro			if (sm_strcasecmp(name, p) == 0)
85590792Sgshapiro				found = true;
85673188Sgshapiro			*dot = '\0';
85773188Sgshapiro		}
85838032Speter	}
85938032Speter	if (found && strchr(cbuf, '.') == NULL)
86038032Speter	{
86138032Speter		/* try to add a domain on the end of the name */
86238032Speter		char *domain = macvalue('m', CurEnv);
86338032Speter
86438032Speter		if (domain != NULL &&
86564562Sgshapiro		    strlen(domain) + (i = strlen(cbuf)) + 1 < (size_t) cbuflen)
86638032Speter		{
86764562Sgshapiro			p = &cbuf[i];
86838032Speter			*p++ = '.';
86990792Sgshapiro			(void) sm_strlcpy(p, domain, cbuflen - i - 1);
87038032Speter		}
87138032Speter	}
87238032Speter	return found;
87338032Speter}
87490792Sgshapiro
87590792Sgshapiro/*
87690792Sgshapiro**  DNS modules
87790792Sgshapiro*/
87890792Sgshapiro
87990792Sgshapiro#if NAMED_BIND
88090792Sgshapiro# if DNSMAP
88190792Sgshapiro
88290792Sgshapiro#  include "sm_resolve.h"
88390792Sgshapiro#  if NETINET || NETINET6
88490792Sgshapiro#   include <arpa/inet.h>
88590792Sgshapiro#  endif /* NETINET || NETINET6 */
88690792Sgshapiro
88790792Sgshapiro/*
88890792Sgshapiro**  DNS_MAP_OPEN -- stub to check proper value for dns map type
88990792Sgshapiro*/
89090792Sgshapiro
89190792Sgshapirobool
89290792Sgshapirodns_map_open(map, mode)
89390792Sgshapiro	MAP *map;
89490792Sgshapiro	int mode;
89590792Sgshapiro{
89690792Sgshapiro	if (tTd(38,2))
89790792Sgshapiro		sm_dprintf("dns_map_open(%s, %d)\n", map->map_mname, mode);
89890792Sgshapiro
89990792Sgshapiro	mode &= O_ACCMODE;
90090792Sgshapiro	if (mode != O_RDONLY)
90190792Sgshapiro	{
90290792Sgshapiro		/* issue a pseudo-error message */
90390792Sgshapiro		errno = SM_EMAPCANTWRITE;
90490792Sgshapiro		return false;
90590792Sgshapiro	}
90690792Sgshapiro	return true;
90790792Sgshapiro}
90890792Sgshapiro
90990792Sgshapiro/*
91090792Sgshapiro**  DNS_MAP_PARSEARGS -- parse dns map definition args.
91190792Sgshapiro**
91290792Sgshapiro**	Parameters:
91390792Sgshapiro**		map -- pointer to MAP
91490792Sgshapiro**		args -- pointer to the args on the config line.
91590792Sgshapiro**
91690792Sgshapiro**	Returns:
91790792Sgshapiro**		true -- if everything parsed OK.
91890792Sgshapiro**		false -- otherwise.
91990792Sgshapiro*/
92090792Sgshapiro
92190792Sgshapiro#  if _FFR_DNSMAP_MULTILIMIT
92290792Sgshapiro#   if !_FFR_DNSMAP_MULTI
92390792Sgshapiro  ERROR README:	You must define _FFR_DNSMAP_MULTI to use _FFR_DNSMAP_MULTILIMIT
92490792Sgshapiro#   endif /* ! _FFR_DNSMAP_MULTI */
92590792Sgshapiro#  endif /* _FFR_DNSMAP_MULTILIMIT */
92690792Sgshapiro
92790792Sgshapiro#  if _FFR_DNSMAP_MULTI
92890792Sgshapiro#   if _FFR_DNSMAP_MULTILIMIT
92990792Sgshapiro#    define map_sizelimit	map_lockfd	/* overload field */
93090792Sgshapiro#   endif /* _FFR_DNSMAP_MULTILIMIT */
93190792Sgshapiro#  endif /* _FFR_DNSMAP_MULTI */
93290792Sgshapiro
93390792Sgshapirostruct dns_map
93490792Sgshapiro{
93590792Sgshapiro	int dns_m_type;
93690792Sgshapiro};
93790792Sgshapiro
93890792Sgshapirobool
93990792Sgshapirodns_map_parseargs(map,args)
94090792Sgshapiro	MAP *map;
94190792Sgshapiro	char *args;
94290792Sgshapiro{
94390792Sgshapiro	register char *p = args;
94490792Sgshapiro	struct dns_map *map_p;
94590792Sgshapiro
94690792Sgshapiro	map_p = (struct dns_map *) xalloc(sizeof *map_p);
94790792Sgshapiro	map_p->dns_m_type = -1;
94890792Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
94990792Sgshapiro
95090792Sgshapiro	for (;;)
95190792Sgshapiro	{
95290792Sgshapiro		while (isascii(*p) && isspace(*p))
95390792Sgshapiro			p++;
95490792Sgshapiro		if (*p != '-')
95590792Sgshapiro			break;
95690792Sgshapiro		switch (*++p)
95790792Sgshapiro		{
95890792Sgshapiro		  case 'N':
95990792Sgshapiro			map->map_mflags |= MF_INCLNULL;
96090792Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
96190792Sgshapiro			break;
96290792Sgshapiro
96390792Sgshapiro		  case 'O':
96490792Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
96590792Sgshapiro			break;
96690792Sgshapiro
96790792Sgshapiro		  case 'o':
96890792Sgshapiro			map->map_mflags |= MF_OPTIONAL;
96990792Sgshapiro			break;
97090792Sgshapiro
97190792Sgshapiro		  case 'f':
97290792Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
97390792Sgshapiro			break;
97490792Sgshapiro
97590792Sgshapiro		  case 'm':
97690792Sgshapiro			map->map_mflags |= MF_MATCHONLY;
97790792Sgshapiro			break;
97890792Sgshapiro
97990792Sgshapiro		  case 'A':
98090792Sgshapiro			map->map_mflags |= MF_APPEND;
98190792Sgshapiro			break;
98290792Sgshapiro
98390792Sgshapiro		  case 'q':
98490792Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
98590792Sgshapiro			break;
98690792Sgshapiro
98790792Sgshapiro		  case 't':
98890792Sgshapiro			map->map_mflags |= MF_NODEFER;
98990792Sgshapiro			break;
99090792Sgshapiro
99190792Sgshapiro		  case 'a':
99290792Sgshapiro			map->map_app = ++p;
99390792Sgshapiro			break;
99490792Sgshapiro
99590792Sgshapiro		  case 'T':
99690792Sgshapiro			map->map_tapp = ++p;
99790792Sgshapiro			break;
99890792Sgshapiro
99990792Sgshapiro		  case 'd':
100090792Sgshapiro			{
100190792Sgshapiro				char *h;
100290792Sgshapiro
100390792Sgshapiro				++p;
100490792Sgshapiro				h = strchr(p, ' ');
100590792Sgshapiro				if (h != NULL)
100690792Sgshapiro					*h = '\0';
100790792Sgshapiro				map->map_timeout = convtime(p, 's');
100890792Sgshapiro				if (h != NULL)
100990792Sgshapiro					*h = ' ';
101090792Sgshapiro			}
101190792Sgshapiro			break;
101290792Sgshapiro
101390792Sgshapiro		  case 'r':
101490792Sgshapiro			while (isascii(*++p) && isspace(*p))
101590792Sgshapiro				continue;
101690792Sgshapiro			map->map_retry = atoi(p);
101790792Sgshapiro			break;
101890792Sgshapiro
101990792Sgshapiro#  if _FFR_DNSMAP_MULTI
102090792Sgshapiro		  case 'z':
102190792Sgshapiro			if (*++p != '\\')
102290792Sgshapiro				map->map_coldelim = *p;
102390792Sgshapiro			else
102490792Sgshapiro			{
102590792Sgshapiro				switch (*++p)
102690792Sgshapiro				{
102790792Sgshapiro				  case 'n':
102890792Sgshapiro					map->map_coldelim = '\n';
102990792Sgshapiro					break;
103090792Sgshapiro
103190792Sgshapiro				  case 't':
103290792Sgshapiro					map->map_coldelim = '\t';
103390792Sgshapiro					break;
103490792Sgshapiro
103590792Sgshapiro				  default:
103690792Sgshapiro					map->map_coldelim = '\\';
103790792Sgshapiro				}
103890792Sgshapiro			}
103990792Sgshapiro			break;
104090792Sgshapiro
104190792Sgshapiro#   if _FFR_DNSMAP_MULTILIMIT
104290792Sgshapiro		  case 'Z':
104390792Sgshapiro			while (isascii(*++p) && isspace(*p))
104490792Sgshapiro				continue;
104590792Sgshapiro			map->map_sizelimit = atoi(p);
104690792Sgshapiro			break;
104790792Sgshapiro#   endif /* _FFR_DNSMAP_MULTILIMIT */
104890792Sgshapiro#  endif /* _FFR_DNSMAP_MULTI */
104990792Sgshapiro
105090792Sgshapiro			/* Start of dns_map specific args */
105190792Sgshapiro		  case 'R':		/* search field */
105290792Sgshapiro			{
105390792Sgshapiro				char *h;
105490792Sgshapiro
105590792Sgshapiro				while (isascii(*++p) && isspace(*p))
105690792Sgshapiro					continue;
105790792Sgshapiro				h = strchr(p, ' ');
105890792Sgshapiro				if (h != NULL)
105990792Sgshapiro					*h = '\0';
106090792Sgshapiro				map_p->dns_m_type = dns_string_to_type(p);
106190792Sgshapiro				if (h != NULL)
106290792Sgshapiro					*h = ' ';
106390792Sgshapiro				if (map_p->dns_m_type < 0)
106490792Sgshapiro					syserr("dns map %s: wrong type %s",
106590792Sgshapiro						map->map_mname, p);
106690792Sgshapiro			}
106790792Sgshapiro			break;
106890792Sgshapiro
106990792Sgshapiro#  if _FFR_DNSMAP_BASE
107090792Sgshapiro		  case 'B':		/* base domain */
107190792Sgshapiro			{
107290792Sgshapiro				char *h;
107390792Sgshapiro
107490792Sgshapiro				while (isascii(*++p) && isspace(*p))
107590792Sgshapiro					continue;
107690792Sgshapiro				h = strchr(p, ' ');
107790792Sgshapiro				if (h != NULL)
107890792Sgshapiro					*h = '\0';
107990792Sgshapiro
108090792Sgshapiro				/*
108190792Sgshapiro				**  slight abuse of map->map_file; it isn't
108290792Sgshapiro				**	used otherwise in this map type.
108390792Sgshapiro				*/
108490792Sgshapiro
108590792Sgshapiro				map->map_file = newstr(p);
108690792Sgshapiro				if (h != NULL)
108790792Sgshapiro					*h = ' ';
108890792Sgshapiro			}
108990792Sgshapiro			break;
109090792Sgshapiro#  endif /* _FFR_DNSMAP_BASE */
109190792Sgshapiro
109290792Sgshapiro		}
109390792Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
109490792Sgshapiro			p++;
109590792Sgshapiro		if (*p != '\0')
109690792Sgshapiro			*p++ = '\0';
109790792Sgshapiro	}
109890792Sgshapiro	if (map_p->dns_m_type < 0)
109990792Sgshapiro		syserr("dns map %s: missing -R type", map->map_mname);
110090792Sgshapiro	if (map->map_app != NULL)
110190792Sgshapiro		map->map_app = newstr(map->map_app);
110290792Sgshapiro	if (map->map_tapp != NULL)
110390792Sgshapiro		map->map_tapp = newstr(map->map_tapp);
110490792Sgshapiro
110590792Sgshapiro	/*
110690792Sgshapiro	**  Assumption: assert(sizeof int <= sizeof(ARBPTR_T));
110790792Sgshapiro	**  Even if this assumption is wrong, we use only one byte,
110890792Sgshapiro	**  so it doesn't really matter.
110990792Sgshapiro	*/
111090792Sgshapiro
111190792Sgshapiro	map->map_db1 = (ARBPTR_T) map_p;
111290792Sgshapiro	return true;
111390792Sgshapiro}
111490792Sgshapiro
111590792Sgshapiro/*
111690792Sgshapiro**  DNS_MAP_LOOKUP -- perform dns map lookup.
111790792Sgshapiro**
111890792Sgshapiro**	Parameters:
111990792Sgshapiro**		map -- pointer to MAP
112090792Sgshapiro**		name -- name to lookup
112190792Sgshapiro**		av -- arguments to interpolate into buf.
112290792Sgshapiro**		statp -- pointer to status (EX_)
112390792Sgshapiro**
112490792Sgshapiro**	Returns:
112590792Sgshapiro**		result of lookup if succeeded.
112690792Sgshapiro**		NULL -- otherwise.
112790792Sgshapiro*/
112890792Sgshapiro
112990792Sgshapirochar *
113090792Sgshapirodns_map_lookup(map, name, av, statp)
113190792Sgshapiro	MAP *map;
113290792Sgshapiro	char *name;
113390792Sgshapiro	char **av;
113490792Sgshapiro	int *statp;
113590792Sgshapiro{
113690792Sgshapiro#  if _FFR_DNSMAP_MULTI
113790792Sgshapiro#   if _FFR_DNSMAP_MULTILIMIT
113890792Sgshapiro	int resnum = 0;
113990792Sgshapiro#   endif /* _FFR_DNSMAP_MULTILIMIT */
114090792Sgshapiro#  endif /* _FFR_DNSMAP_MULTI */
114190792Sgshapiro	char *vp = NULL, *result = NULL;
114290792Sgshapiro	size_t vsize;
114390792Sgshapiro	struct dns_map *map_p;
114490792Sgshapiro	RESOURCE_RECORD_T *rr = NULL;
114590792Sgshapiro	DNS_REPLY_T *r = NULL;
114690792Sgshapiro#  if NETINET6
114790792Sgshapiro	static char buf6[INET6_ADDRSTRLEN];
114890792Sgshapiro#  endif /* NETINET6 */
114990792Sgshapiro
115090792Sgshapiro	if (tTd(38, 20))
115190792Sgshapiro		sm_dprintf("dns_map_lookup(%s, %s)\n",
115290792Sgshapiro			   map->map_mname, name);
115390792Sgshapiro
115490792Sgshapiro	map_p = (struct dns_map *)(map->map_db1);
115590792Sgshapiro#  if _FFR_DNSMAP_BASE
115690792Sgshapiro	if (map->map_file != NULL && *map->map_file != '\0')
115790792Sgshapiro	{
115890792Sgshapiro		size_t len;
115990792Sgshapiro		char *appdomain;
116090792Sgshapiro
116190792Sgshapiro		len = strlen(map->map_file) + strlen(name) + 2;
116290792Sgshapiro		appdomain = (char *) sm_malloc(len);
116390792Sgshapiro		if (appdomain == NULL)
116490792Sgshapiro		{
116590792Sgshapiro			*statp = EX_UNAVAILABLE;
116690792Sgshapiro			return NULL;
116790792Sgshapiro		}
116890792Sgshapiro		(void) sm_strlcpyn(appdomain, len, 3, name, ".", map->map_file);
116990792Sgshapiro		r = dns_lookup_int(appdomain, C_IN, map_p->dns_m_type,
117090792Sgshapiro				   map->map_timeout, map->map_retry);
117190792Sgshapiro		sm_free(appdomain);
117290792Sgshapiro	}
117390792Sgshapiro	else
117490792Sgshapiro#  endif /* _FFR_DNSMAP_BASE */
117590792Sgshapiro	{
117690792Sgshapiro		r = dns_lookup_int(name, C_IN, map_p->dns_m_type,
117790792Sgshapiro				   map->map_timeout, map->map_retry);
117890792Sgshapiro	}
117990792Sgshapiro
118090792Sgshapiro	if (r == NULL)
118190792Sgshapiro	{
118290792Sgshapiro		result = NULL;
1183120256Sgshapiro		if (h_errno == TRY_AGAIN || transienterror(errno))
118490792Sgshapiro			*statp = EX_TEMPFAIL;
118590792Sgshapiro		else
118690792Sgshapiro			*statp = EX_NOTFOUND;
118790792Sgshapiro		goto cleanup;
118890792Sgshapiro	}
118990792Sgshapiro	*statp = EX_OK;
119090792Sgshapiro	for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next)
119190792Sgshapiro	{
119290792Sgshapiro		char *type = NULL;
119390792Sgshapiro		char *value = NULL;
119490792Sgshapiro
119590792Sgshapiro		switch (rr->rr_type)
119690792Sgshapiro		{
119790792Sgshapiro		  case T_NS:
119890792Sgshapiro			type = "T_NS";
119990792Sgshapiro			value = rr->rr_u.rr_txt;
120090792Sgshapiro			break;
120190792Sgshapiro		  case T_CNAME:
120290792Sgshapiro			type = "T_CNAME";
120390792Sgshapiro			value = rr->rr_u.rr_txt;
120490792Sgshapiro			break;
120590792Sgshapiro		  case T_AFSDB:
120690792Sgshapiro			type = "T_AFSDB";
120790792Sgshapiro			value = rr->rr_u.rr_mx->mx_r_domain;
120890792Sgshapiro			break;
120990792Sgshapiro		  case T_SRV:
121090792Sgshapiro			type = "T_SRV";
121190792Sgshapiro			value = rr->rr_u.rr_srv->srv_r_target;
121290792Sgshapiro			break;
121390792Sgshapiro		  case T_PTR:
121490792Sgshapiro			type = "T_PTR";
121590792Sgshapiro			value = rr->rr_u.rr_txt;
121690792Sgshapiro			break;
121790792Sgshapiro		  case T_TXT:
121890792Sgshapiro			type = "T_TXT";
121990792Sgshapiro			value = rr->rr_u.rr_txt;
122090792Sgshapiro			break;
122190792Sgshapiro		  case T_MX:
122290792Sgshapiro			type = "T_MX";
122390792Sgshapiro			value = rr->rr_u.rr_mx->mx_r_domain;
122490792Sgshapiro			break;
122590792Sgshapiro#  if NETINET
122690792Sgshapiro		  case T_A:
122790792Sgshapiro			type = "T_A";
122890792Sgshapiro			value = inet_ntoa(*(rr->rr_u.rr_a));
122990792Sgshapiro			break;
123090792Sgshapiro#  endif /* NETINET */
123190792Sgshapiro#  if NETINET6
123290792Sgshapiro		  case T_AAAA:
123390792Sgshapiro			type = "T_AAAA";
123490792Sgshapiro			value = anynet_ntop(rr->rr_u.rr_aaaa, buf6,
123590792Sgshapiro					    sizeof buf6);
123690792Sgshapiro			break;
123790792Sgshapiro#  endif /* NETINET6 */
123890792Sgshapiro		}
123990792Sgshapiro
124098841Sgshapiro		(void) strreplnonprt(value, 'X');
124190792Sgshapiro		if (map_p->dns_m_type != rr->rr_type)
124290792Sgshapiro		{
124390792Sgshapiro			if (tTd(38, 40))
124490792Sgshapiro				sm_dprintf("\tskipping type %s (%d) value %s\n",
124590792Sgshapiro					   type != NULL ? type : "<UNKNOWN>",
124690792Sgshapiro					   rr->rr_type,
124790792Sgshapiro					   value != NULL ? value : "<NO VALUE>");
124890792Sgshapiro			continue;
124990792Sgshapiro		}
125090792Sgshapiro
125190792Sgshapiro#  if NETINET6
125290792Sgshapiro		if (rr->rr_type == T_AAAA && value == NULL)
125390792Sgshapiro		{
125490792Sgshapiro			result = NULL;
125590792Sgshapiro			*statp = EX_DATAERR;
125690792Sgshapiro			if (tTd(38, 40))
125790792Sgshapiro				sm_dprintf("\tbad T_AAAA conversion\n");
125890792Sgshapiro			goto cleanup;
125990792Sgshapiro		}
126090792Sgshapiro#  endif /* NETINET6 */
126190792Sgshapiro		if (tTd(38, 40))
126290792Sgshapiro			sm_dprintf("\tfound type %s (%d) value %s\n",
126390792Sgshapiro				   type != NULL ? type : "<UNKNOWN>",
126490792Sgshapiro				   rr->rr_type,
126590792Sgshapiro				   value != NULL ? value : "<NO VALUE>");
126690792Sgshapiro#  if _FFR_DNSMAP_MULTI
126790792Sgshapiro		if (value != NULL &&
126890792Sgshapiro		    (map->map_coldelim == '\0' ||
126990792Sgshapiro#   if _FFR_DNSMAP_MULTILIMIT
127090792Sgshapiro		     map->map_sizelimit == 1 ||
127190792Sgshapiro#   endif /* _FFR_DNSMAP_MULTILIMIT */
127290792Sgshapiro		     bitset(MF_MATCHONLY, map->map_mflags)))
127390792Sgshapiro		{
127490792Sgshapiro			/* Only care about the first match */
127590792Sgshapiro			vp = newstr(value);
127690792Sgshapiro			break;
127790792Sgshapiro		}
127890792Sgshapiro		else if (vp == NULL)
127990792Sgshapiro		{
128090792Sgshapiro			/* First result */
128190792Sgshapiro			vp = newstr(value);
128290792Sgshapiro		}
128390792Sgshapiro		else
128490792Sgshapiro		{
128590792Sgshapiro			/* concatenate the results */
128690792Sgshapiro			int sz;
128790792Sgshapiro			char *new;
128890792Sgshapiro
128990792Sgshapiro			sz = strlen(vp) + strlen(value) + 2;
129090792Sgshapiro			new = xalloc(sz);
129190792Sgshapiro			(void) sm_snprintf(new, sz, "%s%c%s",
129290792Sgshapiro					   vp, map->map_coldelim, value);
129390792Sgshapiro			sm_free(vp);
129490792Sgshapiro			vp = new;
129590792Sgshapiro#   if _FFR_DNSMAP_MULTILIMIT
129690792Sgshapiro			if (map->map_sizelimit > 0 &&
129790792Sgshapiro			    ++resnum >= map->map_sizelimit)
129890792Sgshapiro				break;
129990792Sgshapiro#   endif /* _FFR_DNSMAP_MULTILIMIT */
130090792Sgshapiro		}
130190792Sgshapiro#  else /* _FFR_DNSMAP_MULTI */
130290792Sgshapiro		vp = value;
130390792Sgshapiro		break;
130490792Sgshapiro#  endif /* _FFR_DNSMAP_MULTI */
130590792Sgshapiro	}
130690792Sgshapiro	if (vp == NULL)
130790792Sgshapiro	{
130890792Sgshapiro		result = NULL;
130990792Sgshapiro		*statp = EX_NOTFOUND;
131090792Sgshapiro		if (tTd(38, 40))
131190792Sgshapiro			sm_dprintf("\tno match found\n");
131290792Sgshapiro		goto cleanup;
131390792Sgshapiro	}
131490792Sgshapiro
131590792Sgshapiro#  if _FFR_DNSMAP_MULTI
131690792Sgshapiro	/* Cleanly truncate for rulesets */
131790792Sgshapiro	truncate_at_delim(vp, PSBUFSIZE / 2, map->map_coldelim);
131890792Sgshapiro#  endif /* _FFR_DNSMAP_MULTI */
131990792Sgshapiro
132090792Sgshapiro	vsize = strlen(vp);
132190792Sgshapiro
132290792Sgshapiro	if (LogLevel > 9)
132390792Sgshapiro		sm_syslog(LOG_INFO, CurEnv->e_id, "dns %.100s => %s",
132490792Sgshapiro			  name, vp);
132590792Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
132690792Sgshapiro		result = map_rewrite(map, name, strlen(name), NULL);
132790792Sgshapiro	else
132890792Sgshapiro		result = map_rewrite(map, vp, vsize, av);
132990792Sgshapiro
133090792Sgshapiro  cleanup:
133190792Sgshapiro#  if _FFR_DNSMAP_MULTI
133290792Sgshapiro	if (vp != NULL)
133390792Sgshapiro		sm_free(vp);
133490792Sgshapiro#  endif /* _FFR_DNSMAP_MULTI */
133590792Sgshapiro	if (r != NULL)
133690792Sgshapiro		dns_free_data(r);
133790792Sgshapiro	return result;
133890792Sgshapiro}
133990792Sgshapiro# endif /* DNSMAP */
134090792Sgshapiro#endif /* NAMED_BIND */
134190792Sgshapiro
134290792Sgshapiro/*
134338032Speter**  NDBM modules
134438032Speter*/
134538032Speter
134690792Sgshapiro#if NDBM
134738032Speter
134838032Speter/*
134938032Speter**  NDBM_MAP_OPEN -- DBM-style map open
135038032Speter*/
135138032Speter
135238032Speterbool
135338032Speterndbm_map_open(map, mode)
135438032Speter	MAP *map;
135538032Speter	int mode;
135638032Speter{
135738032Speter	register DBM *dbm;
135864562Sgshapiro	int save_errno;
135938032Speter	int dfd;
136038032Speter	int pfd;
136164562Sgshapiro	long sff;
136238032Speter	int ret;
136338032Speter	int smode = S_IREAD;
136498121Sgshapiro	char dirfile[MAXPATHLEN];
136598121Sgshapiro	char pagfile[MAXPATHLEN];
136664562Sgshapiro	struct stat st;
136738032Speter	struct stat std, stp;
136838032Speter
136938032Speter	if (tTd(38, 2))
137090792Sgshapiro		sm_dprintf("ndbm_map_open(%s, %s, %d)\n",
137138032Speter			map->map_mname, map->map_file, mode);
137238032Speter	map->map_lockfd = -1;
137338032Speter	mode &= O_ACCMODE;
137438032Speter
137538032Speter	/* do initial file and directory checks */
137698121Sgshapiro	if (sm_strlcpyn(dirfile, sizeof dirfile, 2,
137798121Sgshapiro			map->map_file, ".dir") >= sizeof dirfile ||
137898121Sgshapiro	    sm_strlcpyn(pagfile, sizeof pagfile, 2,
137998121Sgshapiro			map->map_file, ".pag") >= sizeof pagfile)
138098121Sgshapiro	{
138198121Sgshapiro		errno = 0;
138298121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
138398121Sgshapiro			syserr("dbm map \"%s\": map file %s name too long",
138498121Sgshapiro				map->map_mname, map->map_file);
138598121Sgshapiro		return false;
138698121Sgshapiro	}
138738032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
138838032Speter	if (mode == O_RDWR)
138938032Speter	{
139038032Speter		sff |= SFF_CREAT;
139164562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
139238032Speter			sff |= SFF_NOSLINK;
139364562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
139438032Speter			sff |= SFF_NOHLINK;
139538032Speter		smode = S_IWRITE;
139638032Speter	}
139738032Speter	else
139838032Speter	{
139964562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
140038032Speter			sff |= SFF_NOWLINK;
140138032Speter	}
140264562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
140338032Speter		sff |= SFF_SAFEDIRPATH;
140438032Speter	ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
140590792Sgshapiro		       sff, smode, &std);
140638032Speter	if (ret == 0)
140738032Speter		ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
140838032Speter			       sff, smode, &stp);
140964562Sgshapiro
141038032Speter	if (ret != 0)
141138032Speter	{
141238032Speter		char *prob = "unsafe";
141338032Speter
141438032Speter		/* cannot open this map */
141538032Speter		if (ret == ENOENT)
141638032Speter			prob = "missing";
141738032Speter		if (tTd(38, 2))
141890792Sgshapiro			sm_dprintf("\t%s map file: %d\n", prob, ret);
141938032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
142038032Speter			syserr("dbm map \"%s\": %s map file %s",
142138032Speter				map->map_mname, prob, map->map_file);
142290792Sgshapiro		return false;
142338032Speter	}
142438032Speter	if (std.st_mode == ST_MODE_NOFILE)
142538032Speter		mode |= O_CREAT|O_EXCL;
142638032Speter
142764562Sgshapiro# if LOCK_ON_OPEN
142838032Speter	if (mode == O_RDONLY)
142938032Speter		mode |= O_SHLOCK;
143038032Speter	else
143138032Speter		mode |= O_TRUNC|O_EXLOCK;
143264562Sgshapiro# else /* LOCK_ON_OPEN */
143338032Speter	if ((mode & O_ACCMODE) == O_RDWR)
143438032Speter	{
143564562Sgshapiro#  if NOFTRUNCATE
143638032Speter		/*
143738032Speter		**  Warning: race condition.  Try to lock the file as
143838032Speter		**  quickly as possible after opening it.
143938032Speter		**	This may also have security problems on some systems,
144038032Speter		**	but there isn't anything we can do about it.
144138032Speter		*/
144238032Speter
144338032Speter		mode |= O_TRUNC;
144464562Sgshapiro#  else /* NOFTRUNCATE */
144538032Speter		/*
144638032Speter		**  This ugly code opens the map without truncating it,
144738032Speter		**  locks the file, then truncates it.  Necessary to
144838032Speter		**  avoid race conditions.
144938032Speter		*/
145038032Speter
145138032Speter		int dirfd;
145238032Speter		int pagfd;
145364562Sgshapiro		long sff = SFF_CREAT|SFF_OPENASROOT;
145438032Speter
145564562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
145638032Speter			sff |= SFF_NOSLINK;
145764562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
145838032Speter			sff |= SFF_NOHLINK;
145938032Speter
146038032Speter		dirfd = safeopen(dirfile, mode, DBMMODE, sff);
146138032Speter		pagfd = safeopen(pagfile, mode, DBMMODE, sff);
146238032Speter
146338032Speter		if (dirfd < 0 || pagfd < 0)
146438032Speter		{
146564562Sgshapiro			save_errno = errno;
146638032Speter			if (dirfd >= 0)
146738032Speter				(void) close(dirfd);
146838032Speter			if (pagfd >= 0)
146938032Speter				(void) close(pagfd);
147038032Speter			errno = save_errno;
147138032Speter			syserr("ndbm_map_open: cannot create database %s",
147238032Speter				map->map_file);
147390792Sgshapiro			return false;
147438032Speter		}
147538032Speter		if (ftruncate(dirfd, (off_t) 0) < 0 ||
147638032Speter		    ftruncate(pagfd, (off_t) 0) < 0)
147738032Speter		{
147864562Sgshapiro			save_errno = errno;
147938032Speter			(void) close(dirfd);
148038032Speter			(void) close(pagfd);
148138032Speter			errno = save_errno;
148238032Speter			syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
148338032Speter				map->map_file);
148490792Sgshapiro			return false;
148538032Speter		}
148638032Speter
148738032Speter		/* if new file, get "before" bits for later filechanged check */
148838032Speter		if (std.st_mode == ST_MODE_NOFILE &&
148938032Speter		    (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
149038032Speter		{
149164562Sgshapiro			save_errno = errno;
149238032Speter			(void) close(dirfd);
149338032Speter			(void) close(pagfd);
149438032Speter			errno = save_errno;
149538032Speter			syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
149638032Speter				map->map_file);
149790792Sgshapiro			return false;
149838032Speter		}
149938032Speter
150038032Speter		/* have to save the lock for the duration (bletch) */
150138032Speter		map->map_lockfd = dirfd;
150264562Sgshapiro		(void) close(pagfd);
150338032Speter
150438032Speter		/* twiddle bits for dbm_open */
150538032Speter		mode &= ~(O_CREAT|O_EXCL);
150664562Sgshapiro#  endif /* NOFTRUNCATE */
150738032Speter	}
150864562Sgshapiro# endif /* LOCK_ON_OPEN */
150938032Speter
151038032Speter	/* open the database */
151138032Speter	dbm = dbm_open(map->map_file, mode, DBMMODE);
151238032Speter	if (dbm == NULL)
151338032Speter	{
151464562Sgshapiro		save_errno = errno;
151538032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
151690792Sgshapiro		    aliaswait(map, ".pag", false))
151790792Sgshapiro			return true;
151864562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
151938032Speter		if (map->map_lockfd >= 0)
152064562Sgshapiro			(void) close(map->map_lockfd);
152164562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
152238032Speter		errno = save_errno;
152338032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
152438032Speter			syserr("Cannot open DBM database %s", map->map_file);
152590792Sgshapiro		return false;
152638032Speter	}
152738032Speter	dfd = dbm_dirfno(dbm);
152838032Speter	pfd = dbm_pagfno(dbm);
152938032Speter	if (dfd == pfd)
153038032Speter	{
153138032Speter		/* heuristic: if files are linked, this is actually gdbm */
153238032Speter		dbm_close(dbm);
153364562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
153438032Speter		if (map->map_lockfd >= 0)
153564562Sgshapiro			(void) close(map->map_lockfd);
153664562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
153738032Speter		errno = 0;
153838032Speter		syserr("dbm map \"%s\": cannot support GDBM",
153938032Speter			map->map_mname);
154090792Sgshapiro		return false;
154138032Speter	}
154238032Speter
154338032Speter	if (filechanged(dirfile, dfd, &std) ||
154438032Speter	    filechanged(pagfile, pfd, &stp))
154538032Speter	{
154664562Sgshapiro		save_errno = errno;
154738032Speter		dbm_close(dbm);
154864562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
154938032Speter		if (map->map_lockfd >= 0)
155064562Sgshapiro			(void) close(map->map_lockfd);
155164562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
155238032Speter		errno = save_errno;
155338032Speter		syserr("ndbm_map_open(%s): file changed after open",
155438032Speter			map->map_file);
155590792Sgshapiro		return false;
155638032Speter	}
155738032Speter
155838032Speter	map->map_db1 = (ARBPTR_T) dbm;
155964562Sgshapiro
156064562Sgshapiro	/*
156164562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
156264562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
156364562Sgshapiro	**  map_mtime to be set
156464562Sgshapiro	*/
156564562Sgshapiro
156677349Sgshapiro	if (fstat(pfd, &st) >= 0)
156764562Sgshapiro		map->map_mtime = st.st_mtime;
156864562Sgshapiro
156938032Speter	if (mode == O_RDONLY)
157038032Speter	{
157164562Sgshapiro# if LOCK_ON_OPEN
157238032Speter		if (dfd >= 0)
157338032Speter			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
157438032Speter		if (pfd >= 0)
157538032Speter			(void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
157664562Sgshapiro# endif /* LOCK_ON_OPEN */
157738032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
157890792Sgshapiro		    !aliaswait(map, ".pag", true))
157990792Sgshapiro			return false;
158038032Speter	}
158138032Speter	else
158238032Speter	{
158338032Speter		map->map_mflags |= MF_LOCKED;
158442575Speter		if (geteuid() == 0 && TrustedUid != 0)
158538032Speter		{
158664562Sgshapiro#  if HASFCHOWN
158742575Speter			if (fchown(dfd, TrustedUid, -1) < 0 ||
158842575Speter			    fchown(pfd, TrustedUid, -1) < 0)
158938032Speter			{
159038032Speter				int err = errno;
159138032Speter
159238032Speter				sm_syslog(LOG_ALERT, NOQID,
159338032Speter					  "ownership change on %s failed: %s",
159490792Sgshapiro					  map->map_file, sm_errstring(err));
159538032Speter				message("050 ownership change on %s failed: %s",
159690792Sgshapiro					map->map_file, sm_errstring(err));
159738032Speter			}
159890792Sgshapiro#  else /* HASFCHOWN */
159990792Sgshapiro			sm_syslog(LOG_ALERT, NOQID,
160090792Sgshapiro				  "no fchown(): cannot change ownership on %s",
160190792Sgshapiro				  map->map_file);
160290792Sgshapiro			message("050 no fchown(): cannot change ownership on %s",
160390792Sgshapiro				map->map_file);
160464562Sgshapiro#  endif /* HASFCHOWN */
160538032Speter		}
160638032Speter	}
160790792Sgshapiro	return true;
160838032Speter}
160938032Speter
161038032Speter
161138032Speter/*
161238032Speter**  NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
161338032Speter*/
161438032Speter
161538032Speterchar *
161638032Speterndbm_map_lookup(map, name, av, statp)
161738032Speter	MAP *map;
161838032Speter	char *name;
161938032Speter	char **av;
162038032Speter	int *statp;
162138032Speter{
162238032Speter	datum key, val;
162377349Sgshapiro	int dfd, pfd;
162438032Speter	char keybuf[MAXNAME + 1];
162538032Speter	struct stat stbuf;
162638032Speter
162738032Speter	if (tTd(38, 20))
162890792Sgshapiro		sm_dprintf("ndbm_map_lookup(%s, %s)\n",
162938032Speter			map->map_mname, name);
163038032Speter
163138032Speter	key.dptr = name;
163238032Speter	key.dsize = strlen(name);
163338032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
163438032Speter	{
163538032Speter		if (key.dsize > sizeof keybuf - 1)
163638032Speter			key.dsize = sizeof keybuf - 1;
163764562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
163838032Speter		keybuf[key.dsize] = '\0';
163938032Speter		makelower(keybuf);
164038032Speter		key.dptr = keybuf;
164138032Speter	}
164238032Speterlockdbm:
164377349Sgshapiro	dfd = dbm_dirfno((DBM *) map->map_db1);
164477349Sgshapiro	if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
164577349Sgshapiro		(void) lockfile(dfd, map->map_file, ".dir", LOCK_SH);
164677349Sgshapiro	pfd = dbm_pagfno((DBM *) map->map_db1);
164777349Sgshapiro	if (pfd < 0 || fstat(pfd, &stbuf) < 0 ||
164877349Sgshapiro	    stbuf.st_mtime > map->map_mtime)
164938032Speter	{
165038032Speter		/* Reopen the database to sync the cache */
165138032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
165238032Speter								 : O_RDONLY;
165338032Speter
165477349Sgshapiro		if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
165577349Sgshapiro			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
165677349Sgshapiro		map->map_mflags |= MF_CLOSING;
165738032Speter		map->map_class->map_close(map);
165877349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
165938032Speter		if (map->map_class->map_open(map, omode))
166038032Speter		{
166138032Speter			map->map_mflags |= MF_OPEN;
166290792Sgshapiro			map->map_pid = CurrentPid;
166338032Speter			if ((omode && O_ACCMODE) == O_RDWR)
166438032Speter				map->map_mflags |= MF_WRITABLE;
166538032Speter			goto lockdbm;
166638032Speter		}
166738032Speter		else
166838032Speter		{
166938032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
167038032Speter			{
167138032Speter				extern MAPCLASS BogusMapClass;
167238032Speter
167338032Speter				*statp = EX_TEMPFAIL;
167490792Sgshapiro				map->map_orgclass = map->map_class;
167538032Speter				map->map_class = &BogusMapClass;
167638032Speter				map->map_mflags |= MF_OPEN;
167790792Sgshapiro				map->map_pid = CurrentPid;
167838032Speter				syserr("Cannot reopen NDBM database %s",
167938032Speter					map->map_file);
168038032Speter			}
168138032Speter			return NULL;
168238032Speter		}
168338032Speter	}
168438032Speter	val.dptr = NULL;
168538032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
168638032Speter	{
168738032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
168838032Speter		if (val.dptr != NULL)
168938032Speter			map->map_mflags &= ~MF_TRY1NULL;
169038032Speter	}
169138032Speter	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
169238032Speter	{
169338032Speter		key.dsize++;
169438032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
169538032Speter		if (val.dptr != NULL)
169638032Speter			map->map_mflags &= ~MF_TRY0NULL;
169738032Speter	}
169877349Sgshapiro	if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
169977349Sgshapiro		(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
170038032Speter	if (val.dptr == NULL)
170138032Speter		return NULL;
170238032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
170338032Speter		return map_rewrite(map, name, strlen(name), NULL);
170438032Speter	else
170538032Speter		return map_rewrite(map, val.dptr, val.dsize, av);
170638032Speter}
170738032Speter
170838032Speter
170938032Speter/*
171038032Speter**  NDBM_MAP_STORE -- store a datum in the database
171138032Speter*/
171238032Speter
171338032Spetervoid
171438032Speterndbm_map_store(map, lhs, rhs)
171538032Speter	register MAP *map;
171638032Speter	char *lhs;
171738032Speter	char *rhs;
171838032Speter{
171938032Speter	datum key;
172038032Speter	datum data;
172164562Sgshapiro	int status;
172238032Speter	char keybuf[MAXNAME + 1];
172338032Speter
172438032Speter	if (tTd(38, 12))
172590792Sgshapiro		sm_dprintf("ndbm_map_store(%s, %s, %s)\n",
172638032Speter			map->map_mname, lhs, rhs);
172738032Speter
172838032Speter	key.dsize = strlen(lhs);
172938032Speter	key.dptr = lhs;
173038032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
173138032Speter	{
173238032Speter		if (key.dsize > sizeof keybuf - 1)
173338032Speter			key.dsize = sizeof keybuf - 1;
173464562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
173538032Speter		keybuf[key.dsize] = '\0';
173638032Speter		makelower(keybuf);
173738032Speter		key.dptr = keybuf;
173838032Speter	}
173938032Speter
174038032Speter	data.dsize = strlen(rhs);
174138032Speter	data.dptr = rhs;
174238032Speter
174338032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
174438032Speter	{
174538032Speter		key.dsize++;
174638032Speter		data.dsize++;
174738032Speter	}
174838032Speter
174964562Sgshapiro	status = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
175064562Sgshapiro	if (status > 0)
175138032Speter	{
175238032Speter		if (!bitset(MF_APPEND, map->map_mflags))
175338032Speter			message("050 Warning: duplicate alias name %s", lhs);
175438032Speter		else
175538032Speter		{
175638032Speter			static char *buf = NULL;
175738032Speter			static int bufsiz = 0;
175838032Speter			auto int xstat;
175938032Speter			datum old;
176038032Speter
176138032Speter			old.dptr = ndbm_map_lookup(map, key.dptr,
176290792Sgshapiro						   (char **) NULL, &xstat);
176338032Speter			if (old.dptr != NULL && *(char *) old.dptr != '\0')
176438032Speter			{
176538032Speter				old.dsize = strlen(old.dptr);
176638032Speter				if (data.dsize + old.dsize + 2 > bufsiz)
176738032Speter				{
176838032Speter					if (buf != NULL)
176990792Sgshapiro						(void) sm_free(buf);
177038032Speter					bufsiz = data.dsize + old.dsize + 2;
177190792Sgshapiro					buf = sm_pmalloc_x(bufsiz);
177238032Speter				}
177390792Sgshapiro				(void) sm_strlcpyn(buf, bufsiz, 3,
177490792Sgshapiro					data.dptr, ",", old.dptr);
177538032Speter				data.dsize = data.dsize + old.dsize + 1;
177638032Speter				data.dptr = buf;
177738032Speter				if (tTd(38, 9))
177890792Sgshapiro					sm_dprintf("ndbm_map_store append=%s\n",
177964562Sgshapiro						data.dptr);
178038032Speter			}
178138032Speter		}
178264562Sgshapiro		status = dbm_store((DBM *) map->map_db1,
178364562Sgshapiro				   key, data, DBM_REPLACE);
178438032Speter	}
178564562Sgshapiro	if (status != 0)
178664562Sgshapiro		syserr("readaliases: dbm put (%s): %d", lhs, status);
178738032Speter}
178838032Speter
178938032Speter
179038032Speter/*
179138032Speter**  NDBM_MAP_CLOSE -- close the database
179238032Speter*/
179338032Speter
179438032Spetervoid
179538032Speterndbm_map_close(map)
179638032Speter	register MAP  *map;
179738032Speter{
179838032Speter	if (tTd(38, 9))
179990792Sgshapiro		sm_dprintf("ndbm_map_close(%s, %s, %lx)\n",
180038032Speter			map->map_mname, map->map_file, map->map_mflags);
180138032Speter
180238032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
180338032Speter	{
180464562Sgshapiro# ifdef NDBM_YP_COMPAT
180538032Speter		bool inclnull;
180642575Speter		char buf[MAXHOSTNAMELEN];
180738032Speter
180838032Speter		inclnull = bitset(MF_INCLNULL, map->map_mflags);
180938032Speter		map->map_mflags &= ~MF_INCLNULL;
181038032Speter
181138032Speter		if (strstr(map->map_file, "/yp/") != NULL)
181238032Speter		{
181338032Speter			long save_mflags = map->map_mflags;
181438032Speter
181538032Speter			map->map_mflags |= MF_NOFOLDCASE;
181638032Speter
181790792Sgshapiro			(void) sm_snprintf(buf, sizeof buf, "%010ld", curtime());
181838032Speter			ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
181938032Speter
182038032Speter			(void) gethostname(buf, sizeof buf);
182138032Speter			ndbm_map_store(map, "YP_MASTER_NAME", buf);
182238032Speter
182338032Speter			map->map_mflags = save_mflags;
182438032Speter		}
182538032Speter
182638032Speter		if (inclnull)
182738032Speter			map->map_mflags |= MF_INCLNULL;
182864562Sgshapiro# endif /* NDBM_YP_COMPAT */
182938032Speter
183038032Speter		/* write out the distinguished alias */
183138032Speter		ndbm_map_store(map, "@", "@");
183238032Speter	}
183338032Speter	dbm_close((DBM *) map->map_db1);
183438032Speter
183538032Speter	/* release lock (if needed) */
183664562Sgshapiro# if !LOCK_ON_OPEN
183738032Speter	if (map->map_lockfd >= 0)
183838032Speter		(void) close(map->map_lockfd);
183964562Sgshapiro# endif /* !LOCK_ON_OPEN */
184038032Speter}
184138032Speter
184264562Sgshapiro#endif /* NDBM */
184390792Sgshapiro/*
184438032Speter**  NEWDB (Hash and BTree) Modules
184538032Speter*/
184638032Speter
184790792Sgshapiro#if NEWDB
184838032Speter
184938032Speter/*
185038032Speter**  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
185138032Speter**
185238032Speter**	These do rather bizarre locking.  If you can lock on open,
185338032Speter**	do that to avoid the condition of opening a database that
185438032Speter**	is being rebuilt.  If you don't, we'll try to fake it, but
185538032Speter**	there will be a race condition.  If opening for read-only,
185638032Speter**	we immediately release the lock to avoid freezing things up.
185738032Speter**	We really ought to hold the lock, but guarantee that we won't
185838032Speter**	be pokey about it.  That's hard to do.
185938032Speter*/
186038032Speter
186138032Speter/* these should be K line arguments */
186264562Sgshapiro# if DB_VERSION_MAJOR < 2
186364562Sgshapiro#  define db_cachesize	cachesize
186464562Sgshapiro#  define h_nelem	nelem
186564562Sgshapiro#  ifndef DB_CACHE_SIZE
186664562Sgshapiro#   define DB_CACHE_SIZE	(1024 * 1024)	/* database memory cache size */
186764562Sgshapiro#  endif /* ! DB_CACHE_SIZE */
186864562Sgshapiro#  ifndef DB_HASH_NELEM
186964562Sgshapiro#   define DB_HASH_NELEM	4096		/* (starting) size of hash table */
187064562Sgshapiro#  endif /* ! DB_HASH_NELEM */
187164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
187238032Speter
187338032Speterbool
187438032Speterbt_map_open(map, mode)
187538032Speter	MAP *map;
187638032Speter	int mode;
187738032Speter{
187864562Sgshapiro# if DB_VERSION_MAJOR < 2
187938032Speter	BTREEINFO btinfo;
188064562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
188164562Sgshapiro# if DB_VERSION_MAJOR == 2
188238032Speter	DB_INFO btinfo;
188364562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
188464562Sgshapiro# if DB_VERSION_MAJOR > 2
188564562Sgshapiro	void *btinfo = NULL;
188664562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
188738032Speter
188838032Speter	if (tTd(38, 2))
188990792Sgshapiro		sm_dprintf("bt_map_open(%s, %s, %d)\n",
189038032Speter			map->map_mname, map->map_file, mode);
189138032Speter
189264562Sgshapiro# if DB_VERSION_MAJOR < 3
189364562Sgshapiro	memset(&btinfo, '\0', sizeof btinfo);
189464562Sgshapiro#  ifdef DB_CACHE_SIZE
189538032Speter	btinfo.db_cachesize = DB_CACHE_SIZE;
189664562Sgshapiro#  endif /* DB_CACHE_SIZE */
189764562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
189864562Sgshapiro
189938032Speter	return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
190038032Speter}
190138032Speter
190238032Speterbool
190338032Speterhash_map_open(map, mode)
190438032Speter	MAP *map;
190538032Speter	int mode;
190638032Speter{
190764562Sgshapiro# if DB_VERSION_MAJOR < 2
190838032Speter	HASHINFO hinfo;
190964562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
191064562Sgshapiro# if DB_VERSION_MAJOR == 2
191138032Speter	DB_INFO hinfo;
191264562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
191364562Sgshapiro# if DB_VERSION_MAJOR > 2
191464562Sgshapiro	void *hinfo = NULL;
191564562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
191638032Speter
191738032Speter	if (tTd(38, 2))
191890792Sgshapiro		sm_dprintf("hash_map_open(%s, %s, %d)\n",
191938032Speter			map->map_mname, map->map_file, mode);
192038032Speter
192164562Sgshapiro# if DB_VERSION_MAJOR < 3
192264562Sgshapiro	memset(&hinfo, '\0', sizeof hinfo);
192364562Sgshapiro#  ifdef DB_HASH_NELEM
192438032Speter	hinfo.h_nelem = DB_HASH_NELEM;
192564562Sgshapiro#  endif /* DB_HASH_NELEM */
192664562Sgshapiro#  ifdef DB_CACHE_SIZE
192738032Speter	hinfo.db_cachesize = DB_CACHE_SIZE;
192864562Sgshapiro#  endif /* DB_CACHE_SIZE */
192964562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
193064562Sgshapiro
193138032Speter	return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
193238032Speter}
193338032Speter
193464562Sgshapirostatic bool
193538032Speterdb_map_open(map, mode, mapclassname, dbtype, openinfo)
193638032Speter	MAP *map;
193738032Speter	int mode;
193838032Speter	char *mapclassname;
193938032Speter	DBTYPE dbtype;
194064562Sgshapiro# if DB_VERSION_MAJOR < 2
194138032Speter	const void *openinfo;
194264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
194364562Sgshapiro# if DB_VERSION_MAJOR == 2
194438032Speter	DB_INFO *openinfo;
194564562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
194664562Sgshapiro# if DB_VERSION_MAJOR > 2
194764562Sgshapiro	void **openinfo;
194864562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
194938032Speter{
195038032Speter	DB *db = NULL;
195138032Speter	int i;
195238032Speter	int omode;
195338032Speter	int smode = S_IREAD;
195438032Speter	int fd;
195564562Sgshapiro	long sff;
195664562Sgshapiro	int save_errno;
195738032Speter	struct stat st;
195898121Sgshapiro	char buf[MAXPATHLEN];
195938032Speter
196038032Speter	/* do initial file and directory checks */
196198121Sgshapiro	if (sm_strlcpy(buf, map->map_file, sizeof buf) >= sizeof buf)
196298121Sgshapiro	{
196398121Sgshapiro		errno = 0;
196498121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
196598121Sgshapiro			syserr("map \"%s\": map file %s name too long",
196698121Sgshapiro				map->map_mname, map->map_file);
196798121Sgshapiro		return false;
196898121Sgshapiro	}
196938032Speter	i = strlen(buf);
197038032Speter	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
197198121Sgshapiro	{
197298121Sgshapiro		if (sm_strlcat(buf, ".db", sizeof buf) >= sizeof buf)
197398121Sgshapiro		{
197498121Sgshapiro			errno = 0;
197598121Sgshapiro			if (!bitset(MF_OPTIONAL, map->map_mflags))
197698121Sgshapiro				syserr("map \"%s\": map file %s name too long",
197798121Sgshapiro					map->map_mname, map->map_file);
197898121Sgshapiro			return false;
197998121Sgshapiro		}
198098121Sgshapiro	}
198138032Speter
198238032Speter	mode &= O_ACCMODE;
198338032Speter	omode = mode;
198438032Speter
198538032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
198638032Speter	if (mode == O_RDWR)
198738032Speter	{
198838032Speter		sff |= SFF_CREAT;
198964562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
199038032Speter			sff |= SFF_NOSLINK;
199164562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
199238032Speter			sff |= SFF_NOHLINK;
199338032Speter		smode = S_IWRITE;
199438032Speter	}
199538032Speter	else
199638032Speter	{
199764562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
199838032Speter			sff |= SFF_NOWLINK;
199938032Speter	}
200064562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
200138032Speter		sff |= SFF_SAFEDIRPATH;
200238032Speter	i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
200364562Sgshapiro
200438032Speter	if (i != 0)
200538032Speter	{
200638032Speter		char *prob = "unsafe";
200738032Speter
200838032Speter		/* cannot open this map */
200938032Speter		if (i == ENOENT)
201038032Speter			prob = "missing";
201138032Speter		if (tTd(38, 2))
201290792Sgshapiro			sm_dprintf("\t%s map file: %s\n", prob, sm_errstring(i));
201338032Speter		errno = i;
201438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
201538032Speter			syserr("%s map \"%s\": %s map file %s",
201638032Speter				mapclassname, map->map_mname, prob, buf);
201790792Sgshapiro		return false;
201838032Speter	}
201938032Speter	if (st.st_mode == ST_MODE_NOFILE)
202038032Speter		omode |= O_CREAT|O_EXCL;
202138032Speter
202238032Speter	map->map_lockfd = -1;
202338032Speter
202464562Sgshapiro# if LOCK_ON_OPEN
202538032Speter	if (mode == O_RDWR)
202638032Speter		omode |= O_TRUNC|O_EXLOCK;
202738032Speter	else
202838032Speter		omode |= O_SHLOCK;
202964562Sgshapiro# else /* LOCK_ON_OPEN */
203038032Speter	/*
203138032Speter	**  Pre-lock the file to avoid race conditions.  In particular,
203238032Speter	**  since dbopen returns NULL if the file is zero length, we
203338032Speter	**  must have a locked instance around the dbopen.
203438032Speter	*/
203538032Speter
203638032Speter	fd = open(buf, omode, DBMMODE);
203738032Speter	if (fd < 0)
203838032Speter	{
203938032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
204038032Speter			syserr("db_map_open: cannot pre-open database %s", buf);
204190792Sgshapiro		return false;
204238032Speter	}
204338032Speter
204438032Speter	/* make sure no baddies slipped in just before the open... */
204538032Speter	if (filechanged(buf, fd, &st))
204638032Speter	{
204764562Sgshapiro		save_errno = errno;
204838032Speter		(void) close(fd);
204938032Speter		errno = save_errno;
205038032Speter		syserr("db_map_open(%s): file changed after pre-open", buf);
205190792Sgshapiro		return false;
205238032Speter	}
205338032Speter
205438032Speter	/* if new file, get the "before" bits for later filechanged check */
205538032Speter	if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
205638032Speter	{
205764562Sgshapiro		save_errno = errno;
205838032Speter		(void) close(fd);
205938032Speter		errno = save_errno;
206038032Speter		syserr("db_map_open(%s): cannot fstat pre-opened file",
206138032Speter			buf);
206290792Sgshapiro		return false;
206338032Speter	}
206438032Speter
206538032Speter	/* actually lock the pre-opened file */
206638032Speter	if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
206738032Speter		syserr("db_map_open: cannot lock %s", buf);
206838032Speter
206938032Speter	/* set up mode bits for dbopen */
207038032Speter	if (mode == O_RDWR)
207138032Speter		omode |= O_TRUNC;
207238032Speter	omode &= ~(O_EXCL|O_CREAT);
207364562Sgshapiro# endif /* LOCK_ON_OPEN */
207438032Speter
207564562Sgshapiro# if DB_VERSION_MAJOR < 2
207638032Speter	db = dbopen(buf, omode, DBMMODE, dbtype, openinfo);
207764562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
207838032Speter	{
207938032Speter		int flags = 0;
208064562Sgshapiro#  if DB_VERSION_MAJOR > 2
208164562Sgshapiro		int ret;
208264562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
208338032Speter
208438032Speter		if (mode == O_RDONLY)
208538032Speter			flags |= DB_RDONLY;
208638032Speter		if (bitset(O_CREAT, omode))
208738032Speter			flags |= DB_CREATE;
208838032Speter		if (bitset(O_TRUNC, omode))
208938032Speter			flags |= DB_TRUNCATE;
2090110560Sgshapiro		SM_DB_FLAG_ADD(flags);
209138032Speter
209264562Sgshapiro#  if DB_VERSION_MAJOR > 2
209364562Sgshapiro		ret = db_create(&db, NULL, 0);
209464562Sgshapiro#  ifdef DB_CACHE_SIZE
209564562Sgshapiro		if (ret == 0 && db != NULL)
209664562Sgshapiro		{
209764562Sgshapiro			ret = db->set_cachesize(db, 0, DB_CACHE_SIZE, 0);
209864562Sgshapiro			if (ret != 0)
209964562Sgshapiro			{
210064562Sgshapiro				(void) db->close(db, 0);
210164562Sgshapiro				db = NULL;
210264562Sgshapiro			}
210364562Sgshapiro		}
210464562Sgshapiro#  endif /* DB_CACHE_SIZE */
210564562Sgshapiro#  ifdef DB_HASH_NELEM
210664562Sgshapiro		if (dbtype == DB_HASH && ret == 0 && db != NULL)
210764562Sgshapiro		{
210864562Sgshapiro			ret = db->set_h_nelem(db, DB_HASH_NELEM);
210964562Sgshapiro			if (ret != 0)
211064562Sgshapiro			{
211164562Sgshapiro				(void) db->close(db, 0);
211264562Sgshapiro				db = NULL;
211364562Sgshapiro			}
211464562Sgshapiro		}
211564562Sgshapiro#  endif /* DB_HASH_NELEM */
211664562Sgshapiro		if (ret == 0 && db != NULL)
211764562Sgshapiro		{
2118110560Sgshapiro			ret = db->open(db,
2119110560Sgshapiro					DBTXN	/* transaction for DB 4.1 */
2120110560Sgshapiro					buf, NULL, dbtype, flags, DBMMODE);
212164562Sgshapiro			if (ret != 0)
212264562Sgshapiro			{
212373188Sgshapiro#ifdef DB_OLD_VERSION
212473188Sgshapiro				if (ret == DB_OLD_VERSION)
212573188Sgshapiro					ret = EINVAL;
212673188Sgshapiro#endif /* DB_OLD_VERSION */
212764562Sgshapiro				(void) db->close(db, 0);
212864562Sgshapiro				db = NULL;
212964562Sgshapiro			}
213064562Sgshapiro		}
213164562Sgshapiro		errno = ret;
213264562Sgshapiro#  else /* DB_VERSION_MAJOR > 2 */
213338032Speter		errno = db_open(buf, dbtype, flags, DBMMODE,
213438032Speter				NULL, openinfo, &db);
213564562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
213638032Speter	}
213764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
213864562Sgshapiro	save_errno = errno;
213938032Speter
214064562Sgshapiro# if !LOCK_ON_OPEN
214138032Speter	if (mode == O_RDWR)
214238032Speter		map->map_lockfd = fd;
214338032Speter	else
214438032Speter		(void) close(fd);
214564562Sgshapiro# endif /* !LOCK_ON_OPEN */
214638032Speter
214738032Speter	if (db == NULL)
214838032Speter	{
214938032Speter		if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
215090792Sgshapiro		    aliaswait(map, ".db", false))
215190792Sgshapiro			return true;
215264562Sgshapiro# if !LOCK_ON_OPEN
215338032Speter		if (map->map_lockfd >= 0)
215438032Speter			(void) close(map->map_lockfd);
215564562Sgshapiro# endif /* !LOCK_ON_OPEN */
215664562Sgshapiro		errno = save_errno;
215738032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
215838032Speter			syserr("Cannot open %s database %s",
215938032Speter				mapclassname, buf);
216090792Sgshapiro		return false;
216138032Speter	}
216238032Speter
216364562Sgshapiro# if DB_VERSION_MAJOR < 2
216438032Speter	fd = db->fd(db);
216564562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
216638032Speter	fd = -1;
216738032Speter	errno = db->fd(db, &fd);
216864562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
216938032Speter	if (filechanged(buf, fd, &st))
217038032Speter	{
217164562Sgshapiro		save_errno = errno;
217264562Sgshapiro# if DB_VERSION_MAJOR < 2
217364562Sgshapiro		(void) db->close(db);
217464562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
217538032Speter		errno = db->close(db, 0);
217664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
217764562Sgshapiro# if !LOCK_ON_OPEN
217838032Speter		if (map->map_lockfd >= 0)
217964562Sgshapiro			(void) close(map->map_lockfd);
218064562Sgshapiro# endif /* !LOCK_ON_OPEN */
218138032Speter		errno = save_errno;
218238032Speter		syserr("db_map_open(%s): file changed after open", buf);
218390792Sgshapiro		return false;
218438032Speter	}
218538032Speter
218638032Speter	if (mode == O_RDWR)
218738032Speter		map->map_mflags |= MF_LOCKED;
218864562Sgshapiro# if LOCK_ON_OPEN
218938032Speter	if (fd >= 0 && mode == O_RDONLY)
219038032Speter	{
219138032Speter		(void) lockfile(fd, buf, NULL, LOCK_UN);
219238032Speter	}
219364562Sgshapiro# endif /* LOCK_ON_OPEN */
219438032Speter
219538032Speter	/* try to make sure that at least the database header is on disk */
219638032Speter	if (mode == O_RDWR)
219738032Speter	{
219838032Speter		(void) db->sync(db, 0);
219942575Speter		if (geteuid() == 0 && TrustedUid != 0)
220038032Speter		{
220164562Sgshapiro#  if HASFCHOWN
220242575Speter			if (fchown(fd, TrustedUid, -1) < 0)
220338032Speter			{
220438032Speter				int err = errno;
220538032Speter
220638032Speter				sm_syslog(LOG_ALERT, NOQID,
220738032Speter					  "ownership change on %s failed: %s",
220890792Sgshapiro					  buf, sm_errstring(err));
220938032Speter				message("050 ownership change on %s failed: %s",
221090792Sgshapiro					buf, sm_errstring(err));
221138032Speter			}
221290792Sgshapiro#  else /* HASFCHOWN */
221390792Sgshapiro			sm_syslog(LOG_ALERT, NOQID,
221490792Sgshapiro				  "no fchown(): cannot change ownership on %s",
221590792Sgshapiro				  map->map_file);
221690792Sgshapiro			message("050 no fchown(): cannot change ownership on %s",
221790792Sgshapiro				map->map_file);
221864562Sgshapiro#  endif /* HASFCHOWN */
221938032Speter		}
222038032Speter	}
222138032Speter
222264562Sgshapiro	map->map_db2 = (ARBPTR_T) db;
222364562Sgshapiro
222464562Sgshapiro	/*
222564562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
222664562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
222764562Sgshapiro	**  map_mtime to be set
222864562Sgshapiro	*/
222964562Sgshapiro
223038032Speter	if (fd >= 0 && fstat(fd, &st) >= 0)
223138032Speter		map->map_mtime = st.st_mtime;
223238032Speter
223338032Speter	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
223490792Sgshapiro	    !aliaswait(map, ".db", true))
223590792Sgshapiro		return false;
223690792Sgshapiro	return true;
223738032Speter}
223838032Speter
223938032Speter
224038032Speter/*
224138032Speter**  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
224238032Speter*/
224338032Speter
224438032Speterchar *
224538032Speterdb_map_lookup(map, name, av, statp)
224638032Speter	MAP *map;
224738032Speter	char *name;
224838032Speter	char **av;
224938032Speter	int *statp;
225038032Speter{
225138032Speter	DBT key, val;
225238032Speter	register DB *db = (DB *) map->map_db2;
225338032Speter	int i;
225438032Speter	int st;
225564562Sgshapiro	int save_errno;
225638032Speter	int fd;
225738032Speter	struct stat stbuf;
225838032Speter	char keybuf[MAXNAME + 1];
225998121Sgshapiro	char buf[MAXPATHLEN];
226038032Speter
226164562Sgshapiro	memset(&key, '\0', sizeof key);
226264562Sgshapiro	memset(&val, '\0', sizeof val);
226338032Speter
226438032Speter	if (tTd(38, 20))
226590792Sgshapiro		sm_dprintf("db_map_lookup(%s, %s)\n",
226638032Speter			map->map_mname, name);
226738032Speter
226898121Sgshapiro	if (sm_strlcpy(buf, map->map_file, sizeof buf) >= sizeof buf)
226998121Sgshapiro	{
227098121Sgshapiro		errno = 0;
227198121Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
227298121Sgshapiro			syserr("map \"%s\": map file %s name too long",
227398121Sgshapiro				map->map_mname, map->map_file);
227498121Sgshapiro		return NULL;
227598121Sgshapiro	}
227698121Sgshapiro	i = strlen(buf);
227738032Speter	if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
227838032Speter		buf[i - 3] = '\0';
227938032Speter
228038032Speter	key.size = strlen(name);
228138032Speter	if (key.size > sizeof keybuf - 1)
228238032Speter		key.size = sizeof keybuf - 1;
228338032Speter	key.data = keybuf;
228464562Sgshapiro	memmove(keybuf, name, key.size);
228538032Speter	keybuf[key.size] = '\0';
228638032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
228738032Speter		makelower(keybuf);
228838032Speter  lockdb:
228964562Sgshapiro# if DB_VERSION_MAJOR < 2
229038032Speter	fd = db->fd(db);
229164562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
229238032Speter	fd = -1;
229338032Speter	errno = db->fd(db, &fd);
229464562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
229538032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
229638032Speter		(void) lockfile(fd, buf, ".db", LOCK_SH);
229738032Speter	if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
229838032Speter	{
229938032Speter		/* Reopen the database to sync the cache */
230038032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
230138032Speter								 : O_RDONLY;
230238032Speter
230364562Sgshapiro		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
230464562Sgshapiro			(void) lockfile(fd, buf, ".db", LOCK_UN);
230577349Sgshapiro		map->map_mflags |= MF_CLOSING;
230638032Speter		map->map_class->map_close(map);
230777349Sgshapiro		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
230838032Speter		if (map->map_class->map_open(map, omode))
230938032Speter		{
231038032Speter			map->map_mflags |= MF_OPEN;
231190792Sgshapiro			map->map_pid = CurrentPid;
231238032Speter			if ((omode && O_ACCMODE) == O_RDWR)
231338032Speter				map->map_mflags |= MF_WRITABLE;
231438032Speter			db = (DB *) map->map_db2;
231538032Speter			goto lockdb;
231638032Speter		}
231738032Speter		else
231838032Speter		{
231938032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
232038032Speter			{
232138032Speter				extern MAPCLASS BogusMapClass;
232238032Speter
232338032Speter				*statp = EX_TEMPFAIL;
232490792Sgshapiro				map->map_orgclass = map->map_class;
232538032Speter				map->map_class = &BogusMapClass;
232638032Speter				map->map_mflags |= MF_OPEN;
232790792Sgshapiro				map->map_pid = CurrentPid;
232838032Speter				syserr("Cannot reopen DB database %s",
232938032Speter					map->map_file);
233038032Speter			}
233138032Speter			return NULL;
233238032Speter		}
233338032Speter	}
233438032Speter
233538032Speter	st = 1;
233638032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
233738032Speter	{
233864562Sgshapiro# if DB_VERSION_MAJOR < 2
233938032Speter		st = db->get(db, &key, &val, 0);
234064562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
234138032Speter		errno = db->get(db, NULL, &key, &val, 0);
234238032Speter		switch (errno)
234338032Speter		{
234438032Speter		  case DB_NOTFOUND:
234538032Speter		  case DB_KEYEMPTY:
234638032Speter			st = 1;
234738032Speter			break;
234838032Speter
234938032Speter		  case 0:
235038032Speter			st = 0;
235138032Speter			break;
235238032Speter
235338032Speter		  default:
235438032Speter			st = -1;
235538032Speter			break;
235638032Speter		}
235764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
235838032Speter		if (st == 0)
235938032Speter			map->map_mflags &= ~MF_TRY1NULL;
236038032Speter	}
236138032Speter	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
236238032Speter	{
236338032Speter		key.size++;
236464562Sgshapiro# if DB_VERSION_MAJOR < 2
236538032Speter		st = db->get(db, &key, &val, 0);
236664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
236738032Speter		errno = db->get(db, NULL, &key, &val, 0);
236838032Speter		switch (errno)
236938032Speter		{
237038032Speter		  case DB_NOTFOUND:
237138032Speter		  case DB_KEYEMPTY:
237238032Speter			st = 1;
237338032Speter			break;
237438032Speter
237538032Speter		  case 0:
237638032Speter			st = 0;
237738032Speter			break;
237838032Speter
237938032Speter		  default:
238038032Speter			st = -1;
238138032Speter			break;
238238032Speter		}
238364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
238438032Speter		if (st == 0)
238538032Speter			map->map_mflags &= ~MF_TRY0NULL;
238638032Speter	}
238764562Sgshapiro	save_errno = errno;
238838032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
238938032Speter		(void) lockfile(fd, buf, ".db", LOCK_UN);
239038032Speter	if (st != 0)
239138032Speter	{
239264562Sgshapiro		errno = save_errno;
239338032Speter		if (st < 0)
239438032Speter			syserr("db_map_lookup: get (%s)", name);
239538032Speter		return NULL;
239638032Speter	}
239738032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
239838032Speter		return map_rewrite(map, name, strlen(name), NULL);
239938032Speter	else
240038032Speter		return map_rewrite(map, val.data, val.size, av);
240138032Speter}
240238032Speter
240338032Speter
240438032Speter/*
240538032Speter**  DB_MAP_STORE -- store a datum in the NEWDB database
240638032Speter*/
240738032Speter
240838032Spetervoid
240938032Speterdb_map_store(map, lhs, rhs)
241038032Speter	register MAP *map;
241138032Speter	char *lhs;
241238032Speter	char *rhs;
241338032Speter{
241464562Sgshapiro	int status;
241538032Speter	DBT key;
241638032Speter	DBT data;
241738032Speter	register DB *db = map->map_db2;
241838032Speter	char keybuf[MAXNAME + 1];
241938032Speter
242064562Sgshapiro	memset(&key, '\0', sizeof key);
242164562Sgshapiro	memset(&data, '\0', sizeof data);
242238032Speter
242338032Speter	if (tTd(38, 12))
242490792Sgshapiro		sm_dprintf("db_map_store(%s, %s, %s)\n",
242538032Speter			map->map_mname, lhs, rhs);
242638032Speter
242738032Speter	key.size = strlen(lhs);
242838032Speter	key.data = lhs;
242938032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
243038032Speter	{
243138032Speter		if (key.size > sizeof keybuf - 1)
243238032Speter			key.size = sizeof keybuf - 1;
243364562Sgshapiro		memmove(keybuf, key.data, key.size);
243438032Speter		keybuf[key.size] = '\0';
243538032Speter		makelower(keybuf);
243638032Speter		key.data = keybuf;
243738032Speter	}
243838032Speter
243938032Speter	data.size = strlen(rhs);
244038032Speter	data.data = rhs;
244138032Speter
244238032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
244338032Speter	{
244438032Speter		key.size++;
244538032Speter		data.size++;
244638032Speter	}
244738032Speter
244864562Sgshapiro# if DB_VERSION_MAJOR < 2
244964562Sgshapiro	status = db->put(db, &key, &data, R_NOOVERWRITE);
245064562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
245138032Speter	errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE);
245238032Speter	switch (errno)
245338032Speter	{
245438032Speter	  case DB_KEYEXIST:
245564562Sgshapiro		status = 1;
245638032Speter		break;
245738032Speter
245838032Speter	  case 0:
245964562Sgshapiro		status = 0;
246038032Speter		break;
246138032Speter
246238032Speter	  default:
246364562Sgshapiro		status = -1;
246438032Speter		break;
246538032Speter	}
246664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
246764562Sgshapiro	if (status > 0)
246838032Speter	{
246938032Speter		if (!bitset(MF_APPEND, map->map_mflags))
247038032Speter			message("050 Warning: duplicate alias name %s", lhs);
247138032Speter		else
247238032Speter		{
247338032Speter			static char *buf = NULL;
247438032Speter			static int bufsiz = 0;
247538032Speter			DBT old;
247638032Speter
247764562Sgshapiro			memset(&old, '\0', sizeof old);
247838032Speter
247964562Sgshapiro			old.data = db_map_lookup(map, key.data,
248090792Sgshapiro						 (char **) NULL, &status);
248138032Speter			if (old.data != NULL)
248238032Speter			{
248338032Speter				old.size = strlen(old.data);
248490792Sgshapiro				if (data.size + old.size + 2 > (size_t) bufsiz)
248538032Speter				{
248638032Speter					if (buf != NULL)
248777349Sgshapiro						sm_free(buf);
248838032Speter					bufsiz = data.size + old.size + 2;
248990792Sgshapiro					buf = sm_pmalloc_x(bufsiz);
249038032Speter				}
249190792Sgshapiro				(void) sm_strlcpyn(buf, bufsiz, 3,
249290792Sgshapiro					(char *) data.data, ",",
249390792Sgshapiro					(char *) old.data);
249438032Speter				data.size = data.size + old.size + 1;
249538032Speter				data.data = buf;
249638032Speter				if (tTd(38, 9))
249790792Sgshapiro					sm_dprintf("db_map_store append=%s\n",
249864562Sgshapiro						(char *) data.data);
249938032Speter			}
250038032Speter		}
250164562Sgshapiro# if DB_VERSION_MAJOR < 2
250264562Sgshapiro		status = db->put(db, &key, &data, 0);
250364562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
250464562Sgshapiro		status = errno = db->put(db, NULL, &key, &data, 0);
250564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
250638032Speter	}
250764562Sgshapiro	if (status != 0)
250838032Speter		syserr("readaliases: db put (%s)", lhs);
250938032Speter}
251038032Speter
251138032Speter
251238032Speter/*
251338032Speter**  DB_MAP_CLOSE -- add distinguished entries and close the database
251438032Speter*/
251538032Speter
251638032Spetervoid
251738032Speterdb_map_close(map)
251838032Speter	MAP *map;
251938032Speter{
252038032Speter	register DB *db = map->map_db2;
252138032Speter
252238032Speter	if (tTd(38, 9))
252390792Sgshapiro		sm_dprintf("db_map_close(%s, %s, %lx)\n",
252438032Speter			map->map_mname, map->map_file, map->map_mflags);
252538032Speter
252638032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
252738032Speter	{
252838032Speter		/* write out the distinguished alias */
252938032Speter		db_map_store(map, "@", "@");
253038032Speter	}
253138032Speter
253238032Speter	(void) db->sync(db, 0);
253338032Speter
253464562Sgshapiro# if !LOCK_ON_OPEN
253538032Speter	if (map->map_lockfd >= 0)
253638032Speter		(void) close(map->map_lockfd);
253764562Sgshapiro# endif /* !LOCK_ON_OPEN */
253838032Speter
253964562Sgshapiro# if DB_VERSION_MAJOR < 2
254038032Speter	if (db->close(db) != 0)
254164562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
254242575Speter	/*
254342575Speter	**  Berkeley DB can use internal shared memory
254442575Speter	**  locking for its memory pool.  Closing a map
254542575Speter	**  opened by another process will interfere
254642575Speter	**  with the shared memory and locks of the parent
254742575Speter	**  process leaving things in a bad state.
254843730Speter	*/
254943730Speter
255043730Speter	/*
255142575Speter	**  If this map was not opened by the current
255243730Speter	**  process, do not close the map but recover
255342575Speter	**  the file descriptor.
255442575Speter	*/
255590792Sgshapiro
255690792Sgshapiro	if (map->map_pid != CurrentPid)
255742575Speter	{
255842575Speter		int fd = -1;
255942575Speter
256042575Speter		errno = db->fd(db, &fd);
256142575Speter		if (fd >= 0)
256242575Speter			(void) close(fd);
256342575Speter		return;
256442575Speter	}
256542575Speter
256638032Speter	if ((errno = db->close(db, 0)) != 0)
256764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
256842575Speter		syserr("db_map_close(%s, %s, %lx): db close failure",
256942575Speter			map->map_mname, map->map_file, map->map_mflags);
257038032Speter}
257164562Sgshapiro#endif /* NEWDB */
257290792Sgshapiro/*
257338032Speter**  NIS Modules
257438032Speter*/
257538032Speter
257690792Sgshapiro#if NIS
257738032Speter
257838032Speter# ifndef YPERR_BUSY
257938032Speter#  define YPERR_BUSY	16
258064562Sgshapiro# endif /* ! YPERR_BUSY */
258138032Speter
258238032Speter/*
258338032Speter**  NIS_MAP_OPEN -- open DBM map
258438032Speter*/
258538032Speter
258638032Speterbool
258738032Speternis_map_open(map, mode)
258838032Speter	MAP *map;
258938032Speter	int mode;
259038032Speter{
259138032Speter	int yperr;
259238032Speter	register char *p;
259338032Speter	auto char *vp;
259438032Speter	auto int vsize;
259538032Speter
259638032Speter	if (tTd(38, 2))
259790792Sgshapiro		sm_dprintf("nis_map_open(%s, %s, %d)\n",
259838032Speter			map->map_mname, map->map_file, mode);
259938032Speter
260038032Speter	mode &= O_ACCMODE;
260138032Speter	if (mode != O_RDONLY)
260238032Speter	{
260338032Speter		/* issue a pseudo-error message */
260490792Sgshapiro		errno = SM_EMAPCANTWRITE;
260590792Sgshapiro		return false;
260638032Speter	}
260738032Speter
260838032Speter	p = strchr(map->map_file, '@');
260938032Speter	if (p != NULL)
261038032Speter	{
261138032Speter		*p++ = '\0';
261238032Speter		if (*p != '\0')
261338032Speter			map->map_domain = p;
261438032Speter	}
261538032Speter
261638032Speter	if (*map->map_file == '\0')
261738032Speter		map->map_file = "mail.aliases";
261838032Speter
261938032Speter	if (map->map_domain == NULL)
262038032Speter	{
262138032Speter		yperr = yp_get_default_domain(&map->map_domain);
262238032Speter		if (yperr != 0)
262338032Speter		{
262438032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
262594334Sgshapiro				syserr("451 4.3.5 NIS map %s specified, but NIS not running",
262664562Sgshapiro				       map->map_file);
262790792Sgshapiro			return false;
262838032Speter		}
262938032Speter	}
263038032Speter
263138032Speter	/* check to see if this map actually exists */
263264562Sgshapiro	vp = NULL;
263338032Speter	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
263438032Speter			&vp, &vsize);
263538032Speter	if (tTd(38, 10))
263690792Sgshapiro		sm_dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n",
263738032Speter			map->map_domain, map->map_file, yperr_string(yperr));
263864562Sgshapiro	if (vp != NULL)
263977349Sgshapiro		sm_free(vp);
264064562Sgshapiro
264138032Speter	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
264238032Speter	{
264338032Speter		/*
264438032Speter		**  We ought to be calling aliaswait() here if this is an
264538032Speter		**  alias file, but powerful HP-UX NIS servers  apparently
264638032Speter		**  don't insert the @:@ token into the alias map when it
264738032Speter		**  is rebuilt, so aliaswait() just hangs.  I hate HP-UX.
264838032Speter		*/
264938032Speter
265064562Sgshapiro# if 0
265138032Speter		if (!bitset(MF_ALIAS, map->map_mflags) ||
265290792Sgshapiro		    aliaswait(map, NULL, true))
265364562Sgshapiro# endif /* 0 */
265490792Sgshapiro			return true;
265538032Speter	}
265638032Speter
265738032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
265838032Speter	{
265994334Sgshapiro		syserr("451 4.3.5 Cannot bind to map %s in domain %s: %s",
266038032Speter			map->map_file, map->map_domain, yperr_string(yperr));
266138032Speter	}
266238032Speter
266390792Sgshapiro	return false;
266438032Speter}
266538032Speter
266638032Speter
266738032Speter/*
266838032Speter**  NIS_MAP_LOOKUP -- look up a datum in a NIS map
266938032Speter*/
267038032Speter
267138032Speter/* ARGSUSED3 */
267238032Speterchar *
267338032Speternis_map_lookup(map, name, av, statp)
267438032Speter	MAP *map;
267538032Speter	char *name;
267638032Speter	char **av;
267738032Speter	int *statp;
267838032Speter{
267938032Speter	char *vp;
268038032Speter	auto int vsize;
268138032Speter	int buflen;
268238032Speter	int yperr;
268338032Speter	char keybuf[MAXNAME + 1];
268490792Sgshapiro	char *SM_NONVOLATILE result = NULL;
268538032Speter
268638032Speter	if (tTd(38, 20))
268790792Sgshapiro		sm_dprintf("nis_map_lookup(%s, %s)\n",
268838032Speter			map->map_mname, name);
268938032Speter
269038032Speter	buflen = strlen(name);
269138032Speter	if (buflen > sizeof keybuf - 1)
269238032Speter		buflen = sizeof keybuf - 1;
269364562Sgshapiro	memmove(keybuf, name, buflen);
269438032Speter	keybuf[buflen] = '\0';
269538032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
269638032Speter		makelower(keybuf);
269738032Speter	yperr = YPERR_KEY;
269864562Sgshapiro	vp = NULL;
269938032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
270038032Speter	{
270138032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
270238032Speter			     &vp, &vsize);
270338032Speter		if (yperr == 0)
270438032Speter			map->map_mflags &= ~MF_TRY1NULL;
270538032Speter	}
270638032Speter	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
270738032Speter	{
270890792Sgshapiro		SM_FREE_CLR(vp);
270938032Speter		buflen++;
271038032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
271138032Speter			     &vp, &vsize);
271238032Speter		if (yperr == 0)
271338032Speter			map->map_mflags &= ~MF_TRY0NULL;
271438032Speter	}
271538032Speter	if (yperr != 0)
271638032Speter	{
271738032Speter		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
271838032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
271964562Sgshapiro		if (vp != NULL)
272077349Sgshapiro			sm_free(vp);
272138032Speter		return NULL;
272238032Speter	}
272390792Sgshapiro	SM_TRY
272490792Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
272590792Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
272690792Sgshapiro		else
272790792Sgshapiro			result = map_rewrite(map, vp, vsize, av);
272890792Sgshapiro	SM_FINALLY
272964562Sgshapiro		if (vp != NULL)
273077349Sgshapiro			sm_free(vp);
273190792Sgshapiro	SM_END_TRY
273290792Sgshapiro	return result;
273338032Speter}
273438032Speter
273538032Speter
273638032Speter/*
273738032Speter**  NIS_GETCANONNAME -- look up canonical name in NIS
273838032Speter*/
273938032Speter
274064562Sgshapirostatic bool
274138032Speternis_getcanonname(name, hbsize, statp)
274238032Speter	char *name;
274338032Speter	int hbsize;
274438032Speter	int *statp;
274538032Speter{
274638032Speter	char *vp;
274738032Speter	auto int vsize;
274838032Speter	int keylen;
274938032Speter	int yperr;
275090792Sgshapiro	static bool try0null = true;
275190792Sgshapiro	static bool try1null = true;
275238032Speter	static char *yp_domain = NULL;
275338032Speter	char host_record[MAXLINE];
275438032Speter	char cbuf[MAXNAME];
275538032Speter	char nbuf[MAXNAME + 1];
275638032Speter
275738032Speter	if (tTd(38, 20))
275890792Sgshapiro		sm_dprintf("nis_getcanonname(%s)\n", name);
275938032Speter
276090792Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
276138032Speter	{
276238032Speter		*statp = EX_UNAVAILABLE;
276390792Sgshapiro		return false;
276438032Speter	}
276573188Sgshapiro	(void) shorten_hostname(nbuf);
276638032Speter	keylen = strlen(nbuf);
276738032Speter
276838032Speter	if (yp_domain == NULL)
276964562Sgshapiro		(void) yp_get_default_domain(&yp_domain);
277038032Speter	makelower(nbuf);
277138032Speter	yperr = YPERR_KEY;
277264562Sgshapiro	vp = NULL;
277338032Speter	if (try0null)
277438032Speter	{
277538032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
277638032Speter			     &vp, &vsize);
277738032Speter		if (yperr == 0)
277890792Sgshapiro			try1null = false;
277938032Speter	}
278038032Speter	if (yperr == YPERR_KEY && try1null)
278138032Speter	{
278290792Sgshapiro		SM_FREE_CLR(vp);
278338032Speter		keylen++;
278438032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
278538032Speter			     &vp, &vsize);
278638032Speter		if (yperr == 0)
278790792Sgshapiro			try0null = false;
278838032Speter	}
278938032Speter	if (yperr != 0)
279038032Speter	{
279138032Speter		if (yperr == YPERR_KEY)
279238032Speter			*statp = EX_NOHOST;
279338032Speter		else if (yperr == YPERR_BUSY)
279438032Speter			*statp = EX_TEMPFAIL;
279538032Speter		else
279638032Speter			*statp = EX_UNAVAILABLE;
279764562Sgshapiro		if (vp != NULL)
279877349Sgshapiro			sm_free(vp);
279990792Sgshapiro		return false;
280038032Speter	}
280190792Sgshapiro	(void) sm_strlcpy(host_record, vp, sizeof host_record);
280277349Sgshapiro	sm_free(vp);
280338032Speter	if (tTd(38, 44))
280490792Sgshapiro		sm_dprintf("got record `%s'\n", host_record);
280590792Sgshapiro	vp = strpbrk(host_record, "#\n");
280690792Sgshapiro	if (vp != NULL)
280790792Sgshapiro		*vp = '\0';
280873188Sgshapiro	if (!extract_canonname(nbuf, NULL, host_record, cbuf, sizeof cbuf))
280938032Speter	{
281038032Speter		/* this should not happen, but.... */
281138032Speter		*statp = EX_NOHOST;
281290792Sgshapiro		return false;
281338032Speter	}
281490792Sgshapiro	if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
281538032Speter	{
281638032Speter		*statp = EX_UNAVAILABLE;
281790792Sgshapiro		return false;
281838032Speter	}
281938032Speter	*statp = EX_OK;
282090792Sgshapiro	return true;
282138032Speter}
282238032Speter
282364562Sgshapiro#endif /* NIS */
282490792Sgshapiro/*
282538032Speter**  NISPLUS Modules
282638032Speter**
282738032Speter**	This code donated by Sun Microsystems.
282838032Speter*/
282938032Speter
283090792Sgshapiro#if NISPLUS
283138032Speter
283264562Sgshapiro# undef NIS		/* symbol conflict in nis.h */
283364562Sgshapiro# undef T_UNSPEC	/* symbol conflict in nis.h -> ... -> sys/tiuser.h */
283464562Sgshapiro# include <rpcsvc/nis.h>
283564562Sgshapiro# include <rpcsvc/nislib.h>
283638032Speter
283764562Sgshapiro# define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
283864562Sgshapiro# define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
283964562Sgshapiro# define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
284064562Sgshapiro# define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
284138032Speter
284238032Speter/*
284338032Speter**  NISPLUS_MAP_OPEN -- open nisplus table
284438032Speter*/
284538032Speter
284638032Speterbool
284738032Speternisplus_map_open(map, mode)
284838032Speter	MAP *map;
284938032Speter	int mode;
285038032Speter{
285138032Speter	nis_result *res = NULL;
285238032Speter	int retry_cnt, max_col, i;
285338032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
285438032Speter
285538032Speter	if (tTd(38, 2))
285690792Sgshapiro		sm_dprintf("nisplus_map_open(%s, %s, %d)\n",
285738032Speter			map->map_mname, map->map_file, mode);
285838032Speter
285938032Speter	mode &= O_ACCMODE;
286038032Speter	if (mode != O_RDONLY)
286138032Speter	{
286238032Speter		errno = EPERM;
286390792Sgshapiro		return false;
286438032Speter	}
286538032Speter
286638032Speter	if (*map->map_file == '\0')
286738032Speter		map->map_file = "mail_aliases.org_dir";
286838032Speter
286938032Speter	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
287038032Speter	{
287138032Speter		/* set default NISPLUS Domain to $m */
287238032Speter		map->map_domain = newstr(nisplus_default_domain());
287338032Speter		if (tTd(38, 2))
287490792Sgshapiro			sm_dprintf("nisplus_map_open(%s): using domain %s\n",
287564562Sgshapiro				map->map_file, map->map_domain);
287638032Speter	}
287738032Speter	if (!PARTIAL_NAME(map->map_file))
287838032Speter	{
287938032Speter		map->map_domain = newstr("");
288090792Sgshapiro		(void) sm_strlcpy(qbuf, map->map_file, sizeof qbuf);
288138032Speter	}
288238032Speter	else
288338032Speter	{
288438032Speter		/* check to see if this map actually exists */
288590792Sgshapiro		(void) sm_strlcpyn(qbuf, sizeof qbuf, 3,
288690792Sgshapiro				   map->map_file, ".", map->map_domain);
288738032Speter	}
288838032Speter
288938032Speter	retry_cnt = 0;
289038032Speter	while (res == NULL || res->status != NIS_SUCCESS)
289138032Speter	{
289238032Speter		res = nis_lookup(qbuf, FOLLOW_LINKS);
289338032Speter		switch (res->status)
289438032Speter		{
289538032Speter		  case NIS_SUCCESS:
289638032Speter			break;
289738032Speter
289838032Speter		  case NIS_TRYAGAIN:
289938032Speter		  case NIS_RPCERROR:
290038032Speter		  case NIS_NAMEUNREACHABLE:
290138032Speter			if (retry_cnt++ > 4)
290238032Speter			{
290338032Speter				errno = EAGAIN;
290490792Sgshapiro				return false;
290538032Speter			}
290638032Speter			/* try not to overwhelm hosed server */
290738032Speter			sleep(2);
290838032Speter			break;
290938032Speter
291038032Speter		  default:		/* all other nisplus errors */
291164562Sgshapiro# if 0
291238032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
291394334Sgshapiro				syserr("451 4.3.5 Cannot find table %s.%s: %s",
291438032Speter					map->map_file, map->map_domain,
291538032Speter					nis_sperrno(res->status));
291664562Sgshapiro# endif /* 0 */
291738032Speter			errno = EAGAIN;
291890792Sgshapiro			return false;
291938032Speter		}
292038032Speter	}
292138032Speter
292238032Speter	if (NIS_RES_NUMOBJ(res) != 1 ||
292338032Speter	    (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
292438032Speter	{
292538032Speter		if (tTd(38, 10))
292690792Sgshapiro			sm_dprintf("nisplus_map_open: %s is not a table\n", qbuf);
292764562Sgshapiro# if 0
292838032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
292994334Sgshapiro			syserr("451 4.3.5 %s.%s: %s is not a table",
293038032Speter				map->map_file, map->map_domain,
293138032Speter				nis_sperrno(res->status));
293264562Sgshapiro# endif /* 0 */
293338032Speter		errno = EBADF;
293490792Sgshapiro		return false;
293538032Speter	}
293638032Speter	/* default key column is column 0 */
293738032Speter	if (map->map_keycolnm == NULL)
293838032Speter		map->map_keycolnm = newstr(COL_NAME(res,0));
293938032Speter
294038032Speter	max_col = COL_MAX(res);
294138032Speter
294238032Speter	/* verify the key column exist */
294390792Sgshapiro	for (i = 0; i < max_col; i++)
294438032Speter	{
294564562Sgshapiro		if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0)
294638032Speter			break;
294738032Speter	}
294838032Speter	if (i == max_col)
294938032Speter	{
295038032Speter		if (tTd(38, 2))
295190792Sgshapiro			sm_dprintf("nisplus_map_open(%s): can not find key column %s\n",
295238032Speter				map->map_file, map->map_keycolnm);
295338032Speter		errno = ENOENT;
295490792Sgshapiro		return false;
295538032Speter	}
295638032Speter
295738032Speter	/* default value column is the last column */
295838032Speter	if (map->map_valcolnm == NULL)
295938032Speter	{
296038032Speter		map->map_valcolno = max_col - 1;
296190792Sgshapiro		return true;
296238032Speter	}
296338032Speter
296464562Sgshapiro	for (i = 0; i< max_col; i++)
296538032Speter	{
296638032Speter		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
296738032Speter		{
296838032Speter			map->map_valcolno = i;
296990792Sgshapiro			return true;
297038032Speter		}
297138032Speter	}
297238032Speter
297338032Speter	if (tTd(38, 2))
297490792Sgshapiro		sm_dprintf("nisplus_map_open(%s): can not find column %s\n",
297564562Sgshapiro			map->map_file, map->map_keycolnm);
297638032Speter	errno = ENOENT;
297790792Sgshapiro	return false;
297838032Speter}
297938032Speter
298038032Speter
298138032Speter/*
298238032Speter**  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
298338032Speter*/
298438032Speter
298538032Speterchar *
298638032Speternisplus_map_lookup(map, name, av, statp)
298738032Speter	MAP *map;
298838032Speter	char *name;
298938032Speter	char **av;
299038032Speter	int *statp;
299138032Speter{
299238032Speter	char *p;
299338032Speter	auto int vsize;
299438032Speter	char *skp;
299538032Speter	int skleft;
299638032Speter	char search_key[MAXNAME + 4];
299738032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
299838032Speter	nis_result *result;
299938032Speter
300038032Speter	if (tTd(38, 20))
300190792Sgshapiro		sm_dprintf("nisplus_map_lookup(%s, %s)\n",
300238032Speter			map->map_mname, name);
300338032Speter
300438032Speter	if (!bitset(MF_OPEN, map->map_mflags))
300538032Speter	{
300638032Speter		if (nisplus_map_open(map, O_RDONLY))
300742575Speter		{
300838032Speter			map->map_mflags |= MF_OPEN;
300990792Sgshapiro			map->map_pid = CurrentPid;
301042575Speter		}
301138032Speter		else
301238032Speter		{
301338032Speter			*statp = EX_UNAVAILABLE;
301438032Speter			return NULL;
301538032Speter		}
301638032Speter	}
301738032Speter
301838032Speter	/*
301938032Speter	**  Copy the name to the key buffer, escaping double quote characters
302038032Speter	**  by doubling them and quoting "]" and "," to avoid having the
302138032Speter	**  NIS+ parser choke on them.
302238032Speter	*/
302338032Speter
302438032Speter	skleft = sizeof search_key - 4;
302538032Speter	skp = search_key;
302638032Speter	for (p = name; *p != '\0' && skleft > 0; p++)
302738032Speter	{
302838032Speter		switch (*p)
302938032Speter		{
303038032Speter		  case ']':
303138032Speter		  case ',':
303238032Speter			/* quote the character */
303338032Speter			*skp++ = '"';
303438032Speter			*skp++ = *p;
303538032Speter			*skp++ = '"';
303638032Speter			skleft -= 3;
303738032Speter			break;
303838032Speter
303938032Speter		  case '"':
304038032Speter			/* double the quote */
304138032Speter			*skp++ = '"';
304238032Speter			skleft--;
304364562Sgshapiro			/* FALLTHROUGH */
304438032Speter
304538032Speter		  default:
304638032Speter			*skp++ = *p;
304738032Speter			skleft--;
304838032Speter			break;
304938032Speter		}
305038032Speter	}
305138032Speter	*skp = '\0';
305238032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
305338032Speter		makelower(search_key);
305438032Speter
305538032Speter	/* construct the query */
305638032Speter	if (PARTIAL_NAME(map->map_file))
305790792Sgshapiro		(void) sm_snprintf(qbuf, sizeof qbuf, "[%s=%s],%s.%s",
305838032Speter			map->map_keycolnm, search_key, map->map_file,
305938032Speter			map->map_domain);
306038032Speter	else
306190792Sgshapiro		(void) sm_snprintf(qbuf, sizeof qbuf, "[%s=%s],%s",
306238032Speter			map->map_keycolnm, search_key, map->map_file);
306338032Speter
306438032Speter	if (tTd(38, 20))
306590792Sgshapiro		sm_dprintf("qbuf=%s\n", qbuf);
306638032Speter	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
306738032Speter	if (result->status == NIS_SUCCESS)
306838032Speter	{
306938032Speter		int count;
307038032Speter		char *str;
307138032Speter
307238032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
307338032Speter		{
307438032Speter			if (LogLevel > 10)
307538032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
307664562Sgshapiro					  "%s: lookup error, expected 1 entry, got %d",
307764562Sgshapiro					  map->map_file, count);
307838032Speter
307938032Speter			/* ignore second entry */
308038032Speter			if (tTd(38, 20))
308190792Sgshapiro				sm_dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
308238032Speter					name, count);
308338032Speter		}
308438032Speter
308538032Speter		p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
308638032Speter		/* set the length of the result */
308738032Speter		if (p == NULL)
308838032Speter			p = "";
308938032Speter		vsize = strlen(p);
309038032Speter		if (tTd(38, 20))
309190792Sgshapiro			sm_dprintf("nisplus_map_lookup(%s), found %s\n",
309238032Speter				name, p);
309338032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
309438032Speter			str = map_rewrite(map, name, strlen(name), NULL);
309538032Speter		else
309638032Speter			str = map_rewrite(map, p, vsize, av);
309738032Speter		nis_freeresult(result);
309838032Speter		*statp = EX_OK;
309938032Speter		return str;
310038032Speter	}
310138032Speter	else
310238032Speter	{
310338032Speter		if (result->status == NIS_NOTFOUND)
310438032Speter			*statp = EX_NOTFOUND;
310538032Speter		else if (result->status == NIS_TRYAGAIN)
310638032Speter			*statp = EX_TEMPFAIL;
310738032Speter		else
310838032Speter		{
310938032Speter			*statp = EX_UNAVAILABLE;
311038032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
311138032Speter		}
311238032Speter	}
311338032Speter	if (tTd(38, 20))
311490792Sgshapiro		sm_dprintf("nisplus_map_lookup(%s), failed\n", name);
311538032Speter	nis_freeresult(result);
311638032Speter	return NULL;
311738032Speter}
311838032Speter
311938032Speter
312038032Speter
312138032Speter/*
312238032Speter**  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
312338032Speter*/
312438032Speter
312564562Sgshapirostatic bool
312638032Speternisplus_getcanonname(name, hbsize, statp)
312738032Speter	char *name;
312838032Speter	int hbsize;
312938032Speter	int *statp;
313038032Speter{
313138032Speter	char *vp;
313238032Speter	auto int vsize;
313338032Speter	nis_result *result;
313438032Speter	char *p;
313538032Speter	char nbuf[MAXNAME + 1];
313638032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
313738032Speter
313890792Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
313938032Speter	{
314038032Speter		*statp = EX_UNAVAILABLE;
314190792Sgshapiro		return false;
314238032Speter	}
314373188Sgshapiro	(void) shorten_hostname(nbuf);
314438032Speter
314538032Speter	p = strchr(nbuf, '.');
314638032Speter	if (p == NULL)
314738032Speter	{
314838032Speter		/* single token */
314990792Sgshapiro		(void) sm_snprintf(qbuf, sizeof qbuf,
315090792Sgshapiro			"[name=%s],hosts.org_dir", nbuf);
315138032Speter	}
315238032Speter	else if (p[1] != '\0')
315338032Speter	{
315438032Speter		/* multi token -- take only first token in nbuf */
315538032Speter		*p = '\0';
315690792Sgshapiro		(void) sm_snprintf(qbuf, sizeof qbuf,
315790792Sgshapiro				   "[name=%s],hosts.org_dir.%s", nbuf, &p[1]);
315838032Speter	}
315938032Speter	else
316038032Speter	{
316138032Speter		*statp = EX_NOHOST;
316290792Sgshapiro		return false;
316338032Speter	}
316438032Speter
316538032Speter	if (tTd(38, 20))
316694334Sgshapiro		sm_dprintf("\nnisplus_getcanonname(%s), qbuf=%s\n",
316790792Sgshapiro			   name, qbuf);
316838032Speter
316938032Speter	result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
317090792Sgshapiro			  NULL, NULL);
317138032Speter
317238032Speter	if (result->status == NIS_SUCCESS)
317338032Speter	{
317438032Speter		int count;
317538032Speter		char *domain;
317638032Speter
317738032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
317838032Speter		{
317938032Speter			if (LogLevel > 10)
318038032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
318164562Sgshapiro					  "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
318264562Sgshapiro					  count);
318338032Speter
318438032Speter			/* ignore second entry */
318538032Speter			if (tTd(38, 20))
318694334Sgshapiro				sm_dprintf("nisplus_getcanonname(%s), got %d entries, all but first ignored\n",
318790792Sgshapiro					   name, count);
318838032Speter		}
318938032Speter
319038032Speter		if (tTd(38, 20))
319194334Sgshapiro			sm_dprintf("nisplus_getcanonname(%s), found in directory \"%s\"\n",
319290792Sgshapiro				   name, (NIS_RES_OBJECT(result))->zo_domain);
319338032Speter
319438032Speter
319538032Speter		vp = ((NIS_RES_OBJECT(result))->EN_col(0));
319638032Speter		vsize = strlen(vp);
319738032Speter		if (tTd(38, 20))
319890792Sgshapiro			sm_dprintf("nisplus_getcanonname(%s), found %s\n",
319990792Sgshapiro				   name, vp);
320038032Speter		if (strchr(vp, '.') != NULL)
320138032Speter		{
320238032Speter			domain = "";
320338032Speter		}
320438032Speter		else
320538032Speter		{
320638032Speter			domain = macvalue('m', CurEnv);
320738032Speter			if (domain == NULL)
320838032Speter				domain = "";
320938032Speter		}
321038032Speter		if (hbsize > vsize + (int) strlen(domain) + 1)
321138032Speter		{
321238032Speter			if (domain[0] == '\0')
321390792Sgshapiro				(void) sm_strlcpy(name, vp, hbsize);
321438032Speter			else
321590792Sgshapiro				(void) sm_snprintf(name, hbsize,
321690792Sgshapiro						   "%s.%s", vp, domain);
321738032Speter			*statp = EX_OK;
321838032Speter		}
321938032Speter		else
322038032Speter			*statp = EX_NOHOST;
322138032Speter		nis_freeresult(result);
322290792Sgshapiro		return true;
322338032Speter	}
322438032Speter	else
322538032Speter	{
322638032Speter		if (result->status == NIS_NOTFOUND)
322738032Speter			*statp = EX_NOHOST;
322838032Speter		else if (result->status == NIS_TRYAGAIN)
322938032Speter			*statp = EX_TEMPFAIL;
323038032Speter		else
323138032Speter			*statp = EX_UNAVAILABLE;
323238032Speter	}
323338032Speter	if (tTd(38, 20))
323490792Sgshapiro		sm_dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
323590792Sgshapiro			   name, result->status, *statp);
323638032Speter	nis_freeresult(result);
323790792Sgshapiro	return false;
323838032Speter}
323938032Speter
324038032Speterchar *
324138032Speternisplus_default_domain()
324238032Speter{
324338032Speter	static char default_domain[MAXNAME + 1] = "";
324438032Speter	char *p;
324538032Speter
324638032Speter	if (default_domain[0] != '\0')
324764562Sgshapiro		return default_domain;
324838032Speter
324938032Speter	p = nis_local_directory();
325090792Sgshapiro	(void) sm_strlcpy(default_domain, p, sizeof default_domain);
325138032Speter	return default_domain;
325238032Speter}
325338032Speter
325438032Speter#endif /* NISPLUS */
325590792Sgshapiro/*
325638032Speter**  LDAP Modules
325738032Speter*/
325838032Speter
325964562Sgshapiro/*
326064562Sgshapiro**  LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs
326164562Sgshapiro*/
326264562Sgshapiro
326364562Sgshapiro#if defined(LDAPMAP) || defined(PH_MAP)
326464562Sgshapiro
326590792Sgshapiro# if PH_MAP
326664562Sgshapiro#  define ph_map_dequote ldapmap_dequote
326764562Sgshapiro# endif /* PH_MAP */
326864562Sgshapiro
326990792Sgshapirostatic char *ldapmap_dequote __P((char *));
327090792Sgshapiro
327190792Sgshapirostatic char *
327264562Sgshapiroldapmap_dequote(str)
327364562Sgshapiro	char *str;
327464562Sgshapiro{
327564562Sgshapiro	char *p;
327664562Sgshapiro	char *start;
327764562Sgshapiro
327864562Sgshapiro	if (str == NULL)
327964562Sgshapiro		return NULL;
328064562Sgshapiro
328164562Sgshapiro	p = str;
328264562Sgshapiro	if (*p == '"')
328364562Sgshapiro	{
328464562Sgshapiro		/* Should probably swallow initial whitespace here */
328564562Sgshapiro		start = ++p;
328664562Sgshapiro	}
328764562Sgshapiro	else
328864562Sgshapiro		return str;
328964562Sgshapiro	while (*p != '"' && *p != '\0')
329064562Sgshapiro		p++;
329164562Sgshapiro	if (*p != '\0')
329264562Sgshapiro		*p = '\0';
329364562Sgshapiro	return start;
329464562Sgshapiro}
329564562Sgshapiro#endif /* defined(LDAPMAP) || defined(PH_MAP) */
329664562Sgshapiro
329790792Sgshapiro#if LDAPMAP
329838032Speter
329990792Sgshapirostatic SM_LDAP_STRUCT *LDAPDefaults = NULL;
330038032Speter
330138032Speter/*
330264562Sgshapiro**  LDAPMAP_OPEN -- open LDAP map
330338032Speter**
330464562Sgshapiro**	Connect to the LDAP server.  Re-use existing connections since a
330564562Sgshapiro**	single server connection to a host (with the same host, port,
330664562Sgshapiro**	bind DN, and secret) can answer queries for multiple maps.
330738032Speter*/
330838032Speter
330938032Speterbool
331064562Sgshapiroldapmap_open(map, mode)
331138032Speter	MAP *map;
331238032Speter	int mode;
331338032Speter{
331490792Sgshapiro	SM_LDAP_STRUCT *lmap;
331564562Sgshapiro	STAB *s;
3316132943Sgshapiro	char *id;
331764562Sgshapiro
331838032Speter	if (tTd(38, 2))
331990792Sgshapiro		sm_dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode);
332038032Speter
332138032Speter	mode &= O_ACCMODE;
332264562Sgshapiro
332364562Sgshapiro	/* sendmail doesn't have the ability to write to LDAP (yet) */
332438032Speter	if (mode != O_RDONLY)
332538032Speter	{
332638032Speter		/* issue a pseudo-error message */
332790792Sgshapiro		errno = SM_EMAPCANTWRITE;
332890792Sgshapiro		return false;
332938032Speter	}
333064562Sgshapiro
333190792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
333264562Sgshapiro
333364562Sgshapiro	s = ldapmap_findconn(lmap);
333477349Sgshapiro	if (s->s_lmap != NULL)
333564562Sgshapiro	{
333664562Sgshapiro		/* Already have a connection open to this LDAP server */
333790792Sgshapiro		lmap->ldap_ld = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_ld;
333890792Sgshapiro		lmap->ldap_pid = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_pid;
333977349Sgshapiro
334077349Sgshapiro		/* Add this map as head of linked list */
334177349Sgshapiro		lmap->ldap_next = s->s_lmap;
334277349Sgshapiro		s->s_lmap = map;
334377349Sgshapiro
334466494Sgshapiro		if (tTd(38, 2))
334590792Sgshapiro			sm_dprintf("using cached connection\n");
334690792Sgshapiro		return true;
334764562Sgshapiro	}
334864562Sgshapiro
334966494Sgshapiro	if (tTd(38, 2))
335090792Sgshapiro		sm_dprintf("opening new connection\n");
335166494Sgshapiro
3352132943Sgshapiro	if (lmap->ldap_host != NULL)
3353132943Sgshapiro		id = lmap->ldap_host;
3354132943Sgshapiro	else if (lmap->ldap_uri != NULL)
3355132943Sgshapiro		id = lmap->ldap_uri;
3356132943Sgshapiro	else
3357132943Sgshapiro		id = "localhost";
3358132943Sgshapiro
335964562Sgshapiro	/* No connection yet, connect */
336090792Sgshapiro	if (!sm_ldap_start(map->map_mname, lmap))
336138032Speter	{
336290792Sgshapiro		if (errno == ETIMEDOUT)
336338032Speter		{
336438032Speter			if (LogLevel > 1)
336538032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
336664562Sgshapiro					  "timeout conning to LDAP server %.100s",
3367132943Sgshapiro					  id);
336838032Speter		}
336938032Speter
337038032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
337138032Speter		{
337264562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
3373132943Sgshapiro			{
337464562Sgshapiro				syserr("%s failed to %s in map %s",
337564562Sgshapiro# if USE_LDAP_INIT
337690792Sgshapiro				       "ldap_init/ldap_bind",
337764562Sgshapiro# else /* USE_LDAP_INIT */
337864562Sgshapiro				       "ldap_open",
337964562Sgshapiro# endif /* USE_LDAP_INIT */
3380132943Sgshapiro				       id, map->map_mname);
3381132943Sgshapiro			}
338264562Sgshapiro			else
3383132943Sgshapiro			{
338494334Sgshapiro				syserr("451 4.3.5 %s failed to %s in map %s",
338564562Sgshapiro# if USE_LDAP_INIT
338690792Sgshapiro				       "ldap_init/ldap_bind",
338764562Sgshapiro# else /* USE_LDAP_INIT */
338864562Sgshapiro				       "ldap_open",
338964562Sgshapiro# endif /* USE_LDAP_INIT */
3390132943Sgshapiro				       id, map->map_mname);
3391132943Sgshapiro			}
339238032Speter		}
339390792Sgshapiro		return false;
339438032Speter	}
339538032Speter
339690792Sgshapiro	/* Save connection for reuse */
339790792Sgshapiro	s->s_lmap = map;
339890792Sgshapiro	return true;
339938032Speter}
340038032Speter
340138032Speter/*
340264562Sgshapiro**  LDAPMAP_CLOSE -- close ldap map
340338032Speter*/
340438032Speter
340538032Spetervoid
340664562Sgshapiroldapmap_close(map)
340738032Speter	MAP *map;
340838032Speter{
340990792Sgshapiro	SM_LDAP_STRUCT *lmap;
341064562Sgshapiro	STAB *s;
341143730Speter
341264562Sgshapiro	if (tTd(38, 2))
341390792Sgshapiro		sm_dprintf("ldapmap_close(%s)\n", map->map_mname);
341464562Sgshapiro
341590792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
341664562Sgshapiro
341764562Sgshapiro	/* Check if already closed */
341864562Sgshapiro	if (lmap->ldap_ld == NULL)
341964562Sgshapiro		return;
342064562Sgshapiro
342177349Sgshapiro	/* Close the LDAP connection */
342290792Sgshapiro	sm_ldap_close(lmap);
342377349Sgshapiro
342477349Sgshapiro	/* Mark all the maps that share the connection as closed */
342564562Sgshapiro	s = ldapmap_findconn(lmap);
342664562Sgshapiro
342777349Sgshapiro	while (s->s_lmap != NULL)
342877349Sgshapiro	{
342977349Sgshapiro		MAP *smap = s->s_lmap;
343064562Sgshapiro
343177349Sgshapiro		if (tTd(38, 2) && smap != map)
343290792Sgshapiro			sm_dprintf("ldapmap_close(%s): closed %s (shared LDAP connection)\n",
343390792Sgshapiro				   map->map_mname, smap->map_mname);
343477349Sgshapiro		smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
343590792Sgshapiro		lmap = (SM_LDAP_STRUCT *) smap->map_db1;
343664562Sgshapiro		lmap->ldap_ld = NULL;
343777349Sgshapiro		s->s_lmap = lmap->ldap_next;
343877349Sgshapiro		lmap->ldap_next = NULL;
343943730Speter	}
344038032Speter}
344138032Speter
344264562Sgshapiro# ifdef SUNET_ID
344343730Speter/*
344490792Sgshapiro**  SUNET_ID_HASH -- Convert a string to its Sunet_id canonical form
344542575Speter**  This only makes sense at Stanford University.
344638032Speter*/
344738032Speter
344890792Sgshapirostatic char *
344938032Spetersunet_id_hash(str)
345038032Speter	char *str;
345138032Speter{
345238032Speter	char *p, *p_last;
345338032Speter
345438032Speter	p = str;
345538032Speter	p_last = p;
345638032Speter	while (*p != '\0')
345738032Speter	{
345838032Speter		if (islower(*p) || isdigit(*p))
345938032Speter		{
346038032Speter			*p_last = *p;
346138032Speter			p_last++;
346238032Speter		}
346338032Speter		else if (isupper(*p))
346438032Speter		{
346538032Speter			*p_last = tolower(*p);
346638032Speter			p_last++;
346738032Speter		}
346838032Speter		++p;
346938032Speter	}
347038032Speter	if (*p_last != '\0')
347138032Speter		*p_last = '\0';
347264562Sgshapiro	return str;
347338032Speter}
347464562Sgshapiro# endif /* SUNET_ID */
347538032Speter
347638032Speter/*
347764562Sgshapiro**  LDAPMAP_LOOKUP -- look up a datum in a LDAP map
347838032Speter*/
347938032Speter
348038032Speterchar *
348164562Sgshapiroldapmap_lookup(map, name, av, statp)
348238032Speter	MAP *map;
348338032Speter	char *name;
348438032Speter	char **av;
348538032Speter	int *statp;
348638032Speter{
3487132943Sgshapiro	int flags;
348894334Sgshapiro	int plen = 0;
348994334Sgshapiro	int psize = 0;
349064562Sgshapiro	int msgid;
349190792Sgshapiro	int save_errno;
349290792Sgshapiro	char *vp, *p;
349364562Sgshapiro	char *result = NULL;
3494132943Sgshapiro	SM_RPOOL_T *rpool;
349590792Sgshapiro	SM_LDAP_STRUCT *lmap = NULL;
3496157001Sgshapiro	char keybuf[MAXKEY];
349738032Speter
349838032Speter	if (tTd(38, 20))
349990792Sgshapiro		sm_dprintf("ldapmap_lookup(%s, %s)\n", map->map_mname, name);
350038032Speter
350138032Speter	/* Get ldap struct pointer from map */
350290792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
350390792Sgshapiro	sm_ldap_setopts(lmap->ldap_ld, lmap);
350438032Speter
350590792Sgshapiro	(void) sm_strlcpy(keybuf, name, sizeof keybuf);
350638032Speter
350738032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
350864562Sgshapiro	{
350964562Sgshapiro# ifdef SUNET_ID
351038032Speter		sunet_id_hash(keybuf);
351164562Sgshapiro# else /* SUNET_ID */
351238032Speter		makelower(keybuf);
351364562Sgshapiro# endif /* SUNET_ID */
351464562Sgshapiro	}
351538032Speter
351690792Sgshapiro	msgid = sm_ldap_search(lmap, keybuf);
351764562Sgshapiro	if (msgid == -1)
351838032Speter	{
351990792Sgshapiro		errno = sm_ldap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
352077349Sgshapiro		save_errno = errno;
352164562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
352238032Speter		{
352364562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
352466494Sgshapiro				syserr("Error in ldap_search using %s in map %s",
352590792Sgshapiro				       keybuf, map->map_mname);
352664562Sgshapiro			else
352794334Sgshapiro				syserr("451 4.3.5 Error in ldap_search using %s in map %s",
352890792Sgshapiro				       keybuf, map->map_mname);
352938032Speter		}
353064562Sgshapiro		*statp = EX_TEMPFAIL;
353190792Sgshapiro		switch (save_errno - E_LDAPBASE)
353290792Sgshapiro		{
353394334Sgshapiro# ifdef LDAP_SERVER_DOWN
353490792Sgshapiro		  case LDAP_SERVER_DOWN:
353594334Sgshapiro# endif /* LDAP_SERVER_DOWN */
353690792Sgshapiro		  case LDAP_TIMEOUT:
353790792Sgshapiro		  case LDAP_UNAVAILABLE:
353866494Sgshapiro			/* server disappeared, try reopen on next search */
353977349Sgshapiro			ldapmap_close(map);
354090792Sgshapiro			break;
354166494Sgshapiro		}
354277349Sgshapiro		errno = save_errno;
354364562Sgshapiro		return NULL;
354464562Sgshapiro	}
354564562Sgshapiro
354664562Sgshapiro	*statp = EX_NOTFOUND;
354764562Sgshapiro	vp = NULL;
354864562Sgshapiro
3549132943Sgshapiro	flags = 0;
3550132943Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
3551132943Sgshapiro		flags |= SM_LDAP_SINGLEMATCH;
3552132943Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
3553132943Sgshapiro		flags |= SM_LDAP_MATCHONLY;
3554157001Sgshapiro# if _FFR_LDAP_SINGLEDN
3555157001Sgshapiro	if (bitset(MF_SINGLEDN, map->map_mflags))
3556157001Sgshapiro		flags |= SM_LDAP_SINGLEDN;
3557157001Sgshapiro# endif /* _FFR_LDAP_SINGLEDN */
355890792Sgshapiro
3559132943Sgshapiro	/* Create an rpool for search related memory usage */
3560132943Sgshapiro	rpool = sm_rpool_new_x(NULL);
356190792Sgshapiro
3562132943Sgshapiro	p = NULL;
3563132943Sgshapiro	*statp = sm_ldap_results(lmap, msgid, flags, map->map_coldelim,
3564132943Sgshapiro				 rpool, &p, &plen, &psize, NULL);
3565132943Sgshapiro	save_errno = errno;
356690792Sgshapiro
3567132943Sgshapiro	/* Copy result so rpool can be freed */
3568132943Sgshapiro	if (*statp == EX_OK && p != NULL)
3569132943Sgshapiro		vp = newstr(p);
3570132943Sgshapiro	sm_rpool_free(rpool);
357190792Sgshapiro
3572132943Sgshapiro	/* need to restart LDAP connection? */
3573132943Sgshapiro	if (*statp == EX_RESTART)
357464562Sgshapiro	{
3575132943Sgshapiro		*statp = EX_TEMPFAIL;
3576132943Sgshapiro		ldapmap_close(map);
357738032Speter	}
357838032Speter
3579132943Sgshapiro	errno = save_errno;
3580132943Sgshapiro	if (*statp != EX_OK && *statp != EX_NOTFOUND)
358138032Speter	{
358264562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
358364562Sgshapiro		{
358464562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
358564562Sgshapiro				syserr("Error getting LDAP results in map %s",
358664562Sgshapiro				       map->map_mname);
358764562Sgshapiro			else
358894334Sgshapiro				syserr("451 4.3.5 Error getting LDAP results in map %s",
358964562Sgshapiro				       map->map_mname);
359064562Sgshapiro		}
359177349Sgshapiro		errno = save_errno;
359264562Sgshapiro		return NULL;
359338032Speter	}
359490792Sgshapiro
359564562Sgshapiro	/* Did we match anything? */
359671345Sgshapiro	if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags))
359764562Sgshapiro		return NULL;
359838032Speter
359964562Sgshapiro	if (*statp == EX_OK)
360064562Sgshapiro	{
360164562Sgshapiro		if (LogLevel > 9)
360264562Sgshapiro			sm_syslog(LOG_INFO, CurEnv->e_id,
360371345Sgshapiro				  "ldap %.100s => %s", name,
360471345Sgshapiro				  vp == NULL ? "<NULL>" : vp);
360564562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
360664562Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
360764562Sgshapiro		else
360871345Sgshapiro		{
360971345Sgshapiro			/* vp != NULL according to test above */
361064562Sgshapiro			result = map_rewrite(map, vp, strlen(vp), av);
361171345Sgshapiro		}
361271345Sgshapiro		if (vp != NULL)
361390792Sgshapiro			sm_free(vp); /* XXX */
361464562Sgshapiro	}
361564562Sgshapiro	return result;
361638032Speter}
361738032Speter
361838032Speter/*
361964562Sgshapiro**  LDAPMAP_FINDCONN -- find an LDAP connection to the server
362064562Sgshapiro**
362164562Sgshapiro**	Cache LDAP connections based on the host, port, bind DN,
362266494Sgshapiro**	secret, and PID so we don't have multiple connections open to
362366494Sgshapiro**	the same server for different maps.  Need a separate connection
362466494Sgshapiro**	per PID since a parent process may close the map before the
362566494Sgshapiro**	child is done with it.
362664562Sgshapiro**
362764562Sgshapiro**	Parameters:
362864562Sgshapiro**		lmap -- LDAP map information
362964562Sgshapiro**
363064562Sgshapiro**	Returns:
363164562Sgshapiro**		Symbol table entry for the LDAP connection.
363238032Speter*/
363338032Speter
363464562Sgshapirostatic STAB *
363564562Sgshapiroldapmap_findconn(lmap)
363690792Sgshapiro	SM_LDAP_STRUCT *lmap;
363738032Speter{
363894334Sgshapiro	char *format;
363964562Sgshapiro	char *nbuf;
3640132943Sgshapiro	char *id;
364190792Sgshapiro	STAB *SM_NONVOLATILE s = NULL;
364238032Speter
3643132943Sgshapiro	if (lmap->ldap_host != NULL)
3644132943Sgshapiro		id = lmap->ldap_host;
3645132943Sgshapiro	else if (lmap->ldap_uri != NULL)
3646132943Sgshapiro		id = lmap->ldap_uri;
3647132943Sgshapiro	else
3648132943Sgshapiro		id = "localhost";
3649132943Sgshapiro
365094334Sgshapiro	format = "%s%c%d%c%d%c%s%c%s%d";
365194334Sgshapiro	nbuf = sm_stringf_x(format,
3652132943Sgshapiro			    id,
365390792Sgshapiro			    CONDELSE,
365490792Sgshapiro			    lmap->ldap_port,
365590792Sgshapiro			    CONDELSE,
365694334Sgshapiro			    lmap->ldap_version,
365794334Sgshapiro			    CONDELSE,
365890792Sgshapiro			    (lmap->ldap_binddn == NULL ? ""
365990792Sgshapiro						       : lmap->ldap_binddn),
366090792Sgshapiro			    CONDELSE,
366190792Sgshapiro			    (lmap->ldap_secret == NULL ? ""
366290792Sgshapiro						       : lmap->ldap_secret),
366390792Sgshapiro			    (int) CurrentPid);
366490792Sgshapiro	SM_TRY
366590792Sgshapiro		s = stab(nbuf, ST_LMAP, ST_ENTER);
366690792Sgshapiro	SM_FINALLY
366790792Sgshapiro		sm_free(nbuf);
366890792Sgshapiro	SM_END_TRY
366964562Sgshapiro	return s;
367064562Sgshapiro}
367138032Speter/*
367264562Sgshapiro**  LDAPMAP_PARSEARGS -- parse ldap map definition args.
367364562Sgshapiro*/
367438032Speter
367590792Sgshapirostatic struct lamvalues LDAPAuthMethods[] =
367664562Sgshapiro{
367764562Sgshapiro	{	"none",		LDAP_AUTH_NONE		},
367864562Sgshapiro	{	"simple",	LDAP_AUTH_SIMPLE	},
367964562Sgshapiro# ifdef LDAP_AUTH_KRBV4
368064562Sgshapiro	{	"krbv4",	LDAP_AUTH_KRBV4		},
368164562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
368264562Sgshapiro	{	NULL,		0			}
368364562Sgshapiro};
368438032Speter
368590792Sgshapirostatic struct ladvalues LDAPAliasDereference[] =
368664562Sgshapiro{
368764562Sgshapiro	{	"never",	LDAP_DEREF_NEVER	},
368864562Sgshapiro	{	"always",	LDAP_DEREF_ALWAYS	},
368964562Sgshapiro	{	"search",	LDAP_DEREF_SEARCHING	},
369064562Sgshapiro	{	"find",		LDAP_DEREF_FINDING	},
369164562Sgshapiro	{	NULL,		0			}
369264562Sgshapiro};
369338032Speter
369490792Sgshapirostatic struct lssvalues LDAPSearchScope[] =
369564562Sgshapiro{
369664562Sgshapiro	{	"base",		LDAP_SCOPE_BASE		},
369764562Sgshapiro	{	"one",		LDAP_SCOPE_ONELEVEL	},
369864562Sgshapiro	{	"sub",		LDAP_SCOPE_SUBTREE	},
369964562Sgshapiro	{	NULL,		0			}
370064562Sgshapiro};
370138032Speter
370264562Sgshapirobool
370364562Sgshapiroldapmap_parseargs(map, args)
370464562Sgshapiro	MAP *map;
370564562Sgshapiro	char *args;
370664562Sgshapiro{
370790792Sgshapiro	bool secretread = true;
3708132943Sgshapiro	bool attrssetup = false;
370964562Sgshapiro	int i;
371064562Sgshapiro	register char *p = args;
371190792Sgshapiro	SM_LDAP_STRUCT *lmap;
371264562Sgshapiro	struct lamvalues *lam;
371364562Sgshapiro	struct ladvalues *lad;
371464562Sgshapiro	struct lssvalues *lss;
371590792Sgshapiro	char ldapfilt[MAXLINE];
371664562Sgshapiro	char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
371764562Sgshapiro
371864562Sgshapiro	/* Get ldap struct pointer from map */
371990792Sgshapiro	lmap = (SM_LDAP_STRUCT *) map->map_db1;
372064562Sgshapiro
372164562Sgshapiro	/* Check if setting the initial LDAP defaults */
372264562Sgshapiro	if (lmap == NULL || lmap != LDAPDefaults)
372364562Sgshapiro	{
372490792Sgshapiro		/* We need to alloc an SM_LDAP_STRUCT struct */
372590792Sgshapiro		lmap = (SM_LDAP_STRUCT *) xalloc(sizeof *lmap);
372664562Sgshapiro		if (LDAPDefaults == NULL)
372790792Sgshapiro			sm_ldap_clear(lmap);
372864562Sgshapiro		else
372964562Sgshapiro			STRUCTCOPY(*LDAPDefaults, *lmap);
373064562Sgshapiro	}
373164562Sgshapiro
373264562Sgshapiro	/* there is no check whether there is really an argument */
373364562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
373464562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
373590792Sgshapiro
373690792Sgshapiro	/* Check if setting up an alias or file class LDAP map */
373790792Sgshapiro	if (bitset(MF_ALIAS, map->map_mflags))
373890792Sgshapiro	{
373990792Sgshapiro		/* Comma separate if used as an alias file */
374090792Sgshapiro		map->map_coldelim = ',';
374190792Sgshapiro		if (*args == '\0')
374290792Sgshapiro		{
374390792Sgshapiro			int n;
374490792Sgshapiro			char *lc;
374590792Sgshapiro			char jbuf[MAXHOSTNAMELEN];
374690792Sgshapiro			char lcbuf[MAXLINE];
374790792Sgshapiro
374890792Sgshapiro			/* Get $j */
374990792Sgshapiro			expand("\201j", jbuf, sizeof jbuf, &BlankEnvelope);
375090792Sgshapiro			if (jbuf[0] == '\0')
375190792Sgshapiro			{
375290792Sgshapiro				(void) sm_strlcpy(jbuf, "localhost",
375390792Sgshapiro						  sizeof jbuf);
375490792Sgshapiro			}
375590792Sgshapiro
375690792Sgshapiro			lc = macvalue(macid("{sendmailMTACluster}"), CurEnv);
375790792Sgshapiro			if (lc == NULL)
375890792Sgshapiro				lc = "";
375990792Sgshapiro			else
376090792Sgshapiro			{
376190792Sgshapiro				expand(lc, lcbuf, sizeof lcbuf, CurEnv);
376290792Sgshapiro				lc = lcbuf;
376390792Sgshapiro			}
376490792Sgshapiro
376590792Sgshapiro			n = sm_snprintf(ldapfilt, sizeof ldapfilt,
376690792Sgshapiro					"(&(objectClass=sendmailMTAAliasObject)(sendmailMTAAliasGrouping=aliases)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))(sendmailMTAKey=%%0))",
376790792Sgshapiro					lc, jbuf);
376890792Sgshapiro			if (n >= sizeof ldapfilt)
376990792Sgshapiro			{
377090792Sgshapiro				syserr("%s: Default LDAP string too long",
377190792Sgshapiro				       map->map_mname);
377290792Sgshapiro				return false;
377390792Sgshapiro			}
377490792Sgshapiro
377590792Sgshapiro			/* default args for an alias LDAP entry */
377690792Sgshapiro			lmap->ldap_filter = ldapfilt;
3777132943Sgshapiro			lmap->ldap_attr[0] = "objectClass";
3778132943Sgshapiro			lmap->ldap_attr_type[0] = SM_LDAP_ATTR_OBJCLASS;
3779132943Sgshapiro			lmap->ldap_attr_needobjclass[0] = NULL;
3780132943Sgshapiro			lmap->ldap_attr[1] = "sendmailMTAAliasValue";
3781132943Sgshapiro			lmap->ldap_attr_type[1] = SM_LDAP_ATTR_NORMAL;
3782132943Sgshapiro			lmap->ldap_attr_needobjclass[1] = NULL;
3783132943Sgshapiro			lmap->ldap_attr[2] = "sendmailMTAAliasSearch";
3784132943Sgshapiro			lmap->ldap_attr_type[2] = SM_LDAP_ATTR_FILTER;
3785132943Sgshapiro			lmap->ldap_attr_needobjclass[2] = "sendmailMTAMapObject";
3786132943Sgshapiro			lmap->ldap_attr[3] = "sendmailMTAAliasURL";
3787132943Sgshapiro			lmap->ldap_attr_type[3] = SM_LDAP_ATTR_URL;
3788132943Sgshapiro			lmap->ldap_attr_needobjclass[3] = "sendmailMTAMapObject";
3789132943Sgshapiro			lmap->ldap_attr[4] = NULL;
3790132943Sgshapiro			lmap->ldap_attr_type[4] = SM_LDAP_ATTR_NONE;
3791132943Sgshapiro			lmap->ldap_attr_needobjclass[4] = NULL;
3792132943Sgshapiro			attrssetup = true;
379390792Sgshapiro		}
379490792Sgshapiro	}
379590792Sgshapiro	else if (bitset(MF_FILECLASS, map->map_mflags))
379690792Sgshapiro	{
379790792Sgshapiro		/* Space separate if used as a file class file */
379890792Sgshapiro		map->map_coldelim = ' ';
379990792Sgshapiro	}
380090792Sgshapiro
380138032Speter	for (;;)
380238032Speter	{
380338032Speter		while (isascii(*p) && isspace(*p))
380438032Speter			p++;
380538032Speter		if (*p != '-')
380638032Speter			break;
380738032Speter		switch (*++p)
380838032Speter		{
380938032Speter		  case 'N':
381038032Speter			map->map_mflags |= MF_INCLNULL;
381138032Speter			map->map_mflags &= ~MF_TRY0NULL;
381238032Speter			break;
381338032Speter
381438032Speter		  case 'O':
381538032Speter			map->map_mflags &= ~MF_TRY1NULL;
381638032Speter			break;
381738032Speter
381838032Speter		  case 'o':
381938032Speter			map->map_mflags |= MF_OPTIONAL;
382038032Speter			break;
382138032Speter
382238032Speter		  case 'f':
382338032Speter			map->map_mflags |= MF_NOFOLDCASE;
382438032Speter			break;
382538032Speter
382638032Speter		  case 'm':
382738032Speter			map->map_mflags |= MF_MATCHONLY;
382838032Speter			break;
382938032Speter
383038032Speter		  case 'A':
383138032Speter			map->map_mflags |= MF_APPEND;
383238032Speter			break;
383338032Speter
383438032Speter		  case 'q':
383538032Speter			map->map_mflags |= MF_KEEPQUOTES;
383638032Speter			break;
383738032Speter
383838032Speter		  case 'a':
383938032Speter			map->map_app = ++p;
384038032Speter			break;
384138032Speter
384238032Speter		  case 'T':
384338032Speter			map->map_tapp = ++p;
384438032Speter			break;
384538032Speter
384664562Sgshapiro		  case 't':
384764562Sgshapiro			map->map_mflags |= MF_NODEFER;
384864562Sgshapiro			break;
384964562Sgshapiro
385064562Sgshapiro		  case 'S':
385164562Sgshapiro			map->map_spacesub = *++p;
385264562Sgshapiro			break;
385364562Sgshapiro
385464562Sgshapiro		  case 'D':
385564562Sgshapiro			map->map_mflags |= MF_DEFER;
385664562Sgshapiro			break;
385764562Sgshapiro
385864562Sgshapiro		  case 'z':
385964562Sgshapiro			if (*++p != '\\')
386064562Sgshapiro				map->map_coldelim = *p;
386164562Sgshapiro			else
386264562Sgshapiro			{
386364562Sgshapiro				switch (*++p)
386464562Sgshapiro				{
386564562Sgshapiro				  case 'n':
386664562Sgshapiro					map->map_coldelim = '\n';
386764562Sgshapiro					break;
386864562Sgshapiro
386964562Sgshapiro				  case 't':
387064562Sgshapiro					map->map_coldelim = '\t';
387164562Sgshapiro					break;
387264562Sgshapiro
387364562Sgshapiro				  default:
387464562Sgshapiro					map->map_coldelim = '\\';
387564562Sgshapiro				}
387664562Sgshapiro			}
387764562Sgshapiro			break;
387864562Sgshapiro
387964562Sgshapiro			/* Start of ldapmap specific args */
388090792Sgshapiro		  case 'V':
388190792Sgshapiro			if (*++p != '\\')
388290792Sgshapiro				lmap->ldap_attrsep = *p;
388390792Sgshapiro			else
388490792Sgshapiro			{
388590792Sgshapiro				switch (*++p)
388690792Sgshapiro				{
388790792Sgshapiro				  case 'n':
388890792Sgshapiro					lmap->ldap_attrsep = '\n';
388990792Sgshapiro					break;
389090792Sgshapiro
389190792Sgshapiro				  case 't':
389290792Sgshapiro					lmap->ldap_attrsep = '\t';
389390792Sgshapiro					break;
389490792Sgshapiro
389590792Sgshapiro				  default:
389690792Sgshapiro					lmap->ldap_attrsep = '\\';
389790792Sgshapiro				}
389890792Sgshapiro			}
389990792Sgshapiro			break;
390090792Sgshapiro
390138032Speter		  case 'k':		/* search field */
390238032Speter			while (isascii(*++p) && isspace(*p))
390338032Speter				continue;
390464562Sgshapiro			lmap->ldap_filter = p;
390538032Speter			break;
390638032Speter
390738032Speter		  case 'v':		/* attr to return */
390838032Speter			while (isascii(*++p) && isspace(*p))
390938032Speter				continue;
391064562Sgshapiro			lmap->ldap_attr[0] = p;
391164562Sgshapiro			lmap->ldap_attr[1] = NULL;
391238032Speter			break;
391338032Speter
391464562Sgshapiro		  case '1':
391564562Sgshapiro			map->map_mflags |= MF_SINGLEMATCH;
391664562Sgshapiro			break;
391764562Sgshapiro
3918157001Sgshapiro# if _FFR_LDAP_SINGLEDN
3919157001Sgshapiro		  case '2':
3920157001Sgshapiro			map->map_mflags |= MF_SINGLEDN;
3921157001Sgshapiro			break;
3922157001Sgshapiro# endif /* _FFR_LDAP_SINGLEDN */
3923157001Sgshapiro
392438032Speter			/* args stolen from ldapsearch.c */
392538032Speter		  case 'R':		/* don't auto chase referrals */
392664562Sgshapiro# ifdef LDAP_REFERRALS
392738032Speter			lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
392864562Sgshapiro# else /* LDAP_REFERRALS */
392990792Sgshapiro			syserr("compile with -DLDAP_REFERRALS for referral support");
393064562Sgshapiro# endif /* LDAP_REFERRALS */
393138032Speter			break;
393238032Speter
393364562Sgshapiro		  case 'n':		/* retrieve attribute names only */
393464562Sgshapiro			lmap->ldap_attrsonly = LDAPMAP_TRUE;
393538032Speter			break;
393638032Speter
393764562Sgshapiro		  case 'r':		/* alias dereferencing */
393864562Sgshapiro			while (isascii(*++p) && isspace(*p))
393964562Sgshapiro				continue;
394064562Sgshapiro
394190792Sgshapiro			if (sm_strncasecmp(p, "LDAP_DEREF_", 11) == 0)
394264562Sgshapiro				p += 11;
394364562Sgshapiro
394464562Sgshapiro			for (lad = LDAPAliasDereference;
394564562Sgshapiro			     lad != NULL && lad->lad_name != NULL; lad++)
394638032Speter			{
394790792Sgshapiro				if (sm_strncasecmp(p, lad->lad_name,
394890792Sgshapiro						   strlen(lad->lad_name)) == 0)
394964562Sgshapiro					break;
395038032Speter			}
395164562Sgshapiro			if (lad->lad_name != NULL)
395264562Sgshapiro				lmap->ldap_deref = lad->lad_code;
395364562Sgshapiro			else
395438032Speter			{
395564562Sgshapiro				/* bad config line */
395664562Sgshapiro				if (!bitset(MCF_OPTFILE,
395764562Sgshapiro					    map->map_class->map_cflags))
395864562Sgshapiro				{
395964562Sgshapiro					char *ptr;
396064562Sgshapiro
396164562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
396264562Sgshapiro						*ptr = '\0';
396373188Sgshapiro					syserr("Deref must be [never|always|search|find] (not %s) in map %s",
396464562Sgshapiro						p, map->map_mname);
396564562Sgshapiro					if (ptr != NULL)
396664562Sgshapiro						*ptr = ' ';
396790792Sgshapiro					return false;
396864562Sgshapiro				}
396938032Speter			}
397064562Sgshapiro			break;
397164562Sgshapiro
397264562Sgshapiro		  case 's':		/* search scope */
397364562Sgshapiro			while (isascii(*++p) && isspace(*p))
397464562Sgshapiro				continue;
397564562Sgshapiro
397690792Sgshapiro			if (sm_strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
397764562Sgshapiro				p += 11;
397864562Sgshapiro
397964562Sgshapiro			for (lss = LDAPSearchScope;
398064562Sgshapiro			     lss != NULL && lss->lss_name != NULL; lss++)
398138032Speter			{
398290792Sgshapiro				if (sm_strncasecmp(p, lss->lss_name,
398390792Sgshapiro						   strlen(lss->lss_name)) == 0)
398464562Sgshapiro					break;
398538032Speter			}
398664562Sgshapiro			if (lss->lss_name != NULL)
398764562Sgshapiro				lmap->ldap_scope = lss->lss_code;
398838032Speter			else
398964562Sgshapiro			{
399064562Sgshapiro				/* bad config line */
399164562Sgshapiro				if (!bitset(MCF_OPTFILE,
399264562Sgshapiro					    map->map_class->map_cflags))
399338032Speter				{
399438032Speter					char *ptr;
399538032Speter
399638032Speter					if ((ptr = strchr(p, ' ')) != NULL)
399738032Speter						*ptr = '\0';
399873188Sgshapiro					syserr("Scope must be [base|one|sub] (not %s) in map %s",
399938032Speter						p, map->map_mname);
400038032Speter					if (ptr != NULL)
400138032Speter						*ptr = ' ';
400290792Sgshapiro					return false;
400338032Speter				}
400438032Speter			}
400538032Speter			break;
400638032Speter
400738032Speter		  case 'h':		/* ldap host */
400838032Speter			while (isascii(*++p) && isspace(*p))
400938032Speter				continue;
4010132943Sgshapiro			if (lmap->ldap_uri != NULL)
401194334Sgshapiro			{
401294334Sgshapiro				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
401394334Sgshapiro				       map->map_mname);
401494334Sgshapiro				return false;
401594334Sgshapiro			}
4016132943Sgshapiro			lmap->ldap_host = p;
401738032Speter			break;
401838032Speter
401938032Speter		  case 'b':		/* search base */
402038032Speter			while (isascii(*++p) && isspace(*p))
402138032Speter				continue;
402264562Sgshapiro			lmap->ldap_base = p;
402338032Speter			break;
402438032Speter
402538032Speter		  case 'p':		/* ldap port */
402638032Speter			while (isascii(*++p) && isspace(*p))
402738032Speter				continue;
402864562Sgshapiro			lmap->ldap_port = atoi(p);
402938032Speter			break;
403038032Speter
403138032Speter		  case 'l':		/* time limit */
403238032Speter			while (isascii(*++p) && isspace(*p))
403338032Speter				continue;
403464562Sgshapiro			lmap->ldap_timelimit = atoi(p);
403564562Sgshapiro			lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit;
403638032Speter			break;
403738032Speter
403864562Sgshapiro		  case 'Z':
403964562Sgshapiro			while (isascii(*++p) && isspace(*p))
404064562Sgshapiro				continue;
404164562Sgshapiro			lmap->ldap_sizelimit = atoi(p);
404264562Sgshapiro			break;
404364562Sgshapiro
404464562Sgshapiro		  case 'd':		/* Dn to bind to server as */
404564562Sgshapiro			while (isascii(*++p) && isspace(*p))
404664562Sgshapiro				continue;
404764562Sgshapiro			lmap->ldap_binddn = p;
404864562Sgshapiro			break;
404964562Sgshapiro
405064562Sgshapiro		  case 'M':		/* Method for binding */
405164562Sgshapiro			while (isascii(*++p) && isspace(*p))
405264562Sgshapiro				continue;
405364562Sgshapiro
405490792Sgshapiro			if (sm_strncasecmp(p, "LDAP_AUTH_", 10) == 0)
405564562Sgshapiro				p += 10;
405664562Sgshapiro
405764562Sgshapiro			for (lam = LDAPAuthMethods;
405864562Sgshapiro			     lam != NULL && lam->lam_name != NULL; lam++)
405964562Sgshapiro			{
406090792Sgshapiro				if (sm_strncasecmp(p, lam->lam_name,
406190792Sgshapiro						   strlen(lam->lam_name)) == 0)
406264562Sgshapiro					break;
406364562Sgshapiro			}
406464562Sgshapiro			if (lam->lam_name != NULL)
406564562Sgshapiro				lmap->ldap_method = lam->lam_code;
406664562Sgshapiro			else
406764562Sgshapiro			{
406864562Sgshapiro				/* bad config line */
406964562Sgshapiro				if (!bitset(MCF_OPTFILE,
407064562Sgshapiro					    map->map_class->map_cflags))
407164562Sgshapiro				{
407264562Sgshapiro					char *ptr;
407364562Sgshapiro
407464562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
407564562Sgshapiro						*ptr = '\0';
407673188Sgshapiro					syserr("Method for binding must be [none|simple|krbv4] (not %s) in map %s",
407764562Sgshapiro						p, map->map_mname);
407864562Sgshapiro					if (ptr != NULL)
407964562Sgshapiro						*ptr = ' ';
408090792Sgshapiro					return false;
408164562Sgshapiro				}
408264562Sgshapiro			}
408364562Sgshapiro
408464562Sgshapiro			break;
408564562Sgshapiro
408664562Sgshapiro			/*
408764562Sgshapiro			**  This is a string that is dependent on the
408864562Sgshapiro			**  method used defined above.
408964562Sgshapiro			*/
409064562Sgshapiro
409164562Sgshapiro		  case 'P':		/* Secret password for binding */
409264562Sgshapiro			 while (isascii(*++p) && isspace(*p))
409364562Sgshapiro				continue;
409464562Sgshapiro			lmap->ldap_secret = p;
409590792Sgshapiro			secretread = false;
409664562Sgshapiro			break;
409764562Sgshapiro
409894334Sgshapiro		  case 'H':		/* Use LDAP URI */
409994334Sgshapiro#  if !USE_LDAP_INIT
410094334Sgshapiro			syserr("Must compile with -DUSE_LDAP_INIT to use LDAP URIs (-H) in map %s",
410194334Sgshapiro			       map->map_mname);
410294334Sgshapiro			return false;
4103132943Sgshapiro#   else /* !USE_LDAP_INIT */
4104132943Sgshapiro			if (lmap->ldap_host != NULL)
410594334Sgshapiro			{
410694334Sgshapiro				syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
410794334Sgshapiro				       map->map_mname);
410894334Sgshapiro				return false;
410994334Sgshapiro			}
411094334Sgshapiro			while (isascii(*++p) && isspace(*p))
411194334Sgshapiro				continue;
4112132943Sgshapiro			lmap->ldap_uri = p;
411394334Sgshapiro			break;
411494334Sgshapiro#  endif /* !USE_LDAP_INIT */
411594334Sgshapiro
411694334Sgshapiro		  case 'w':
411794334Sgshapiro			/* -w should be for passwd, -P should be for version */
411894334Sgshapiro			while (isascii(*++p) && isspace(*p))
411994334Sgshapiro				continue;
412094334Sgshapiro			lmap->ldap_version = atoi(p);
4121132943Sgshapiro# ifdef LDAP_VERSION_MAX
412294334Sgshapiro			if (lmap->ldap_version > LDAP_VERSION_MAX)
412394334Sgshapiro			{
412494334Sgshapiro				syserr("LDAP version %d exceeds max of %d in map %s",
412594334Sgshapiro				       lmap->ldap_version, LDAP_VERSION_MAX,
412694334Sgshapiro				       map->map_mname);
412794334Sgshapiro				return false;
412894334Sgshapiro			}
4129132943Sgshapiro# endif /* LDAP_VERSION_MAX */
4130132943Sgshapiro# ifdef LDAP_VERSION_MIN
413194334Sgshapiro			if (lmap->ldap_version < LDAP_VERSION_MIN)
413294334Sgshapiro			{
413394334Sgshapiro				syserr("LDAP version %d is lower than min of %d in map %s",
413494334Sgshapiro				       lmap->ldap_version, LDAP_VERSION_MIN,
413594334Sgshapiro				       map->map_mname);
413694334Sgshapiro				return false;
413794334Sgshapiro			}
4138132943Sgshapiro# endif /* LDAP_VERSION_MIN */
413994334Sgshapiro			break;
414094334Sgshapiro
414164562Sgshapiro		  default:
414264562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
414364562Sgshapiro			break;
414438032Speter		}
414538032Speter
414664562Sgshapiro		/* need to account for quoted strings here */
414764562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
414838032Speter		{
414938032Speter			if (*p == '"')
415038032Speter			{
415138032Speter				while (*++p != '"' && *p != '\0')
415238032Speter					continue;
415338032Speter				if (*p != '\0')
415438032Speter					p++;
415538032Speter			}
415638032Speter			else
415738032Speter				p++;
415838032Speter		}
415938032Speter
416038032Speter		if (*p != '\0')
416138032Speter			*p++ = '\0';
416238032Speter	}
416338032Speter
416438032Speter	if (map->map_app != NULL)
416564562Sgshapiro		map->map_app = newstr(ldapmap_dequote(map->map_app));
416638032Speter	if (map->map_tapp != NULL)
416764562Sgshapiro		map->map_tapp = newstr(ldapmap_dequote(map->map_tapp));
416838032Speter
416938032Speter	/*
417042575Speter	**  We need to swallow up all the stuff into a struct
417142575Speter	**  and dump it into map->map_dbptr1
417238032Speter	*/
417338032Speter
4174132943Sgshapiro	if (lmap->ldap_host != NULL &&
417564562Sgshapiro	    (LDAPDefaults == NULL ||
417664562Sgshapiro	     LDAPDefaults == lmap ||
4177132943Sgshapiro	     LDAPDefaults->ldap_host != lmap->ldap_host))
4178132943Sgshapiro		lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host));
4179132943Sgshapiro	map->map_domain = lmap->ldap_host;
418064562Sgshapiro
4181132943Sgshapiro	if (lmap->ldap_uri != NULL &&
4182132943Sgshapiro	    (LDAPDefaults == NULL ||
4183132943Sgshapiro	     LDAPDefaults == lmap ||
4184132943Sgshapiro	     LDAPDefaults->ldap_uri != lmap->ldap_uri))
4185132943Sgshapiro		lmap->ldap_uri = newstr(ldapmap_dequote(lmap->ldap_uri));
4186132943Sgshapiro	map->map_domain = lmap->ldap_uri;
4187132943Sgshapiro
418864562Sgshapiro	if (lmap->ldap_binddn != NULL &&
418964562Sgshapiro	    (LDAPDefaults == NULL ||
419064562Sgshapiro	     LDAPDefaults == lmap ||
419164562Sgshapiro	     LDAPDefaults->ldap_binddn != lmap->ldap_binddn))
419264562Sgshapiro		lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn));
419364562Sgshapiro
419464562Sgshapiro	if (lmap->ldap_secret != NULL &&
419564562Sgshapiro	    (LDAPDefaults == NULL ||
419664562Sgshapiro	     LDAPDefaults == lmap ||
419764562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
419838032Speter	{
419990792Sgshapiro		SM_FILE_T *sfd;
420064562Sgshapiro		long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
420138032Speter
420264562Sgshapiro		if (DontLockReadFiles)
420364562Sgshapiro			sff |= SFF_NOLOCK;
420438032Speter
420564562Sgshapiro		/* need to use method to map secret to passwd string */
420664562Sgshapiro		switch (lmap->ldap_method)
420764562Sgshapiro		{
420864562Sgshapiro		  case LDAP_AUTH_NONE:
420964562Sgshapiro			/* Do nothing */
421064562Sgshapiro			break;
421138032Speter
421264562Sgshapiro		  case LDAP_AUTH_SIMPLE:
421338032Speter
421464562Sgshapiro			/*
421564562Sgshapiro			**  Secret is the name of a file with
421664562Sgshapiro			**  the first line as the password.
421764562Sgshapiro			*/
421864562Sgshapiro
421964562Sgshapiro			/* Already read in the secret? */
422064562Sgshapiro			if (secretread)
422164562Sgshapiro				break;
422264562Sgshapiro
422364562Sgshapiro			sfd = safefopen(ldapmap_dequote(lmap->ldap_secret),
422464562Sgshapiro					O_RDONLY, 0, sff);
422564562Sgshapiro			if (sfd == NULL)
422664562Sgshapiro			{
422764562Sgshapiro				syserr("LDAP map: cannot open secret %s",
422864562Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
422990792Sgshapiro				return false;
423064562Sgshapiro			}
423198121Sgshapiro			lmap->ldap_secret = sfgets(m_tmp, sizeof m_tmp,
423266494Sgshapiro						   sfd, TimeOuts.to_fileopen,
423366494Sgshapiro						   "ldapmap_parseargs");
423490792Sgshapiro			(void) sm_io_close(sfd, SM_TIME_DEFAULT);
423598121Sgshapiro			if (strlen(m_tmp) > LDAPMAP_MAX_PASSWD)
423698121Sgshapiro			{
423798121Sgshapiro				syserr("LDAP map: secret in %s too long",
423898121Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
423998121Sgshapiro				return false;
424098121Sgshapiro			}
424164562Sgshapiro			if (lmap->ldap_secret != NULL &&
424264562Sgshapiro			    strlen(m_tmp) > 0)
424364562Sgshapiro			{
424464562Sgshapiro				/* chomp newline */
424564562Sgshapiro				if (m_tmp[strlen(m_tmp) - 1] == '\n')
424664562Sgshapiro					m_tmp[strlen(m_tmp) - 1] = '\0';
424764562Sgshapiro
424864562Sgshapiro				lmap->ldap_secret = m_tmp;
424964562Sgshapiro			}
425064562Sgshapiro			break;
425164562Sgshapiro
425264562Sgshapiro# ifdef LDAP_AUTH_KRBV4
425364562Sgshapiro		  case LDAP_AUTH_KRBV4:
425464562Sgshapiro
425564562Sgshapiro			/*
425664562Sgshapiro			**  Secret is where the ticket file is
425764562Sgshapiro			**  stashed
425864562Sgshapiro			*/
425964562Sgshapiro
426098121Sgshapiro			(void) sm_snprintf(m_tmp, sizeof m_tmp,
426190792Sgshapiro				"KRBTKFILE=%s",
426290792Sgshapiro				ldapmap_dequote(lmap->ldap_secret));
426364562Sgshapiro			lmap->ldap_secret = m_tmp;
426464562Sgshapiro			break;
426564562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
426664562Sgshapiro
426764562Sgshapiro		  default:	       /* Should NEVER get here */
426864562Sgshapiro			syserr("LDAP map: Illegal value in lmap method");
426990792Sgshapiro			return false;
427090792Sgshapiro			/* NOTREACHED */
427164562Sgshapiro			break;
427264562Sgshapiro		}
427338032Speter	}
427438032Speter
427564562Sgshapiro	if (lmap->ldap_secret != NULL &&
427664562Sgshapiro	    (LDAPDefaults == NULL ||
427764562Sgshapiro	     LDAPDefaults == lmap ||
427864562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
427964562Sgshapiro		lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret));
428038032Speter
428164562Sgshapiro	if (lmap->ldap_base != NULL &&
428264562Sgshapiro	    (LDAPDefaults == NULL ||
428364562Sgshapiro	     LDAPDefaults == lmap ||
428464562Sgshapiro	     LDAPDefaults->ldap_base != lmap->ldap_base))
428564562Sgshapiro		lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base));
428664562Sgshapiro
428764562Sgshapiro	/*
428864562Sgshapiro	**  Save the server from extra work.  If request is for a single
428964562Sgshapiro	**  match, tell the server to only return enough records to
429064562Sgshapiro	**  determine if there is a single match or not.  This can not
429164562Sgshapiro	**  be one since the server would only return one and we wouldn't
429264562Sgshapiro	**  know if there were others available.
429364562Sgshapiro	*/
429464562Sgshapiro
429564562Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
429664562Sgshapiro		lmap->ldap_sizelimit = 2;
429764562Sgshapiro
429864562Sgshapiro	/* If setting defaults, don't process ldap_filter and ldap_attr */
429964562Sgshapiro	if (lmap == LDAPDefaults)
430090792Sgshapiro		return true;
430164562Sgshapiro
430264562Sgshapiro	if (lmap->ldap_filter != NULL)
430364562Sgshapiro		lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
430438032Speter	else
430538032Speter	{
430638032Speter		if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
430738032Speter		{
430838032Speter			syserr("No filter given in map %s", map->map_mname);
430990792Sgshapiro			return false;
431038032Speter		}
431138032Speter	}
431264562Sgshapiro
4313132943Sgshapiro	if (!attrssetup && lmap->ldap_attr[0] != NULL)
431438032Speter	{
431590792Sgshapiro		bool recurse = false;
431694334Sgshapiro		bool normalseen = false;
431790792Sgshapiro
431864562Sgshapiro		i = 0;
431964562Sgshapiro		p = ldapmap_dequote(lmap->ldap_attr[0]);
432064562Sgshapiro		lmap->ldap_attr[0] = NULL;
432164562Sgshapiro
432294334Sgshapiro		/* Prime the attr list with the objectClass attribute */
432394334Sgshapiro		lmap->ldap_attr[i] = "objectClass";
432494334Sgshapiro		lmap->ldap_attr_type[i] = SM_LDAP_ATTR_OBJCLASS;
432594334Sgshapiro		lmap->ldap_attr_needobjclass[i] = NULL;
432694334Sgshapiro		i++;
432794334Sgshapiro
432864562Sgshapiro		while (p != NULL)
432938032Speter		{
433064562Sgshapiro			char *v;
433164562Sgshapiro
433264562Sgshapiro			while (isascii(*p) && isspace(*p))
433364562Sgshapiro				p++;
433464562Sgshapiro			if (*p == '\0')
433564562Sgshapiro				break;
433664562Sgshapiro			v = p;
433764562Sgshapiro			p = strchr(v, ',');
433864562Sgshapiro			if (p != NULL)
433964562Sgshapiro				*p++ = '\0';
434064562Sgshapiro
434171345Sgshapiro			if (i >= LDAPMAP_MAX_ATTR)
434264562Sgshapiro			{
434364562Sgshapiro				syserr("Too many return attributes in %s (max %d)",
434464562Sgshapiro				       map->map_mname, LDAPMAP_MAX_ATTR);
434590792Sgshapiro				return false;
434664562Sgshapiro			}
434764562Sgshapiro			if (*v != '\0')
434890792Sgshapiro			{
434994334Sgshapiro				int j;
435094334Sgshapiro				int use;
435190792Sgshapiro				char *type;
435294334Sgshapiro				char *needobjclass;
435390792Sgshapiro
435490792Sgshapiro				type = strchr(v, ':');
435590792Sgshapiro				if (type != NULL)
435694334Sgshapiro				{
435790792Sgshapiro					*type++ = '\0';
435894334Sgshapiro					needobjclass = strchr(type, ':');
435994334Sgshapiro					if (needobjclass != NULL)
436094334Sgshapiro						*needobjclass++ = '\0';
436194334Sgshapiro				}
436294334Sgshapiro				else
436394334Sgshapiro				{
436494334Sgshapiro					needobjclass = NULL;
436594334Sgshapiro				}
436690792Sgshapiro
436794334Sgshapiro				use = i;
436890792Sgshapiro
436994334Sgshapiro				/* allow override on "objectClass" type */
437094334Sgshapiro				if (sm_strcasecmp(v, "objectClass") == 0 &&
437194334Sgshapiro				    lmap->ldap_attr_type[0] == SM_LDAP_ATTR_OBJCLASS)
437290792Sgshapiro				{
437394334Sgshapiro					use = 0;
437494334Sgshapiro				}
437594334Sgshapiro				else
437694334Sgshapiro				{
437794334Sgshapiro					/*
437894334Sgshapiro					**  Don't add something to attribute
437994334Sgshapiro					**  list twice.
438094334Sgshapiro					*/
438194334Sgshapiro
438294334Sgshapiro					for (j = 1; j < i; j++)
438390792Sgshapiro					{
438494334Sgshapiro						if (sm_strcasecmp(v, lmap->ldap_attr[j]) == 0)
438594334Sgshapiro						{
438694334Sgshapiro							syserr("Duplicate attribute (%s) in %s",
438794334Sgshapiro							       v, map->map_mname);
438894334Sgshapiro							return false;
438994334Sgshapiro						}
439090792Sgshapiro					}
439194334Sgshapiro
439294334Sgshapiro					lmap->ldap_attr[use] = newstr(v);
439394334Sgshapiro					if (needobjclass != NULL &&
439494334Sgshapiro					    *needobjclass != '\0' &&
439594334Sgshapiro					    *needobjclass != '*')
439690792Sgshapiro					{
439794334Sgshapiro						lmap->ldap_attr_needobjclass[use] = newstr(needobjclass);
439894334Sgshapiro					}
439994334Sgshapiro					else
440094334Sgshapiro					{
440194334Sgshapiro						lmap->ldap_attr_needobjclass[use] = NULL;
440294334Sgshapiro					}
440394334Sgshapiro
440494334Sgshapiro				}
440594334Sgshapiro
440694334Sgshapiro				if (type != NULL && *type != '\0')
440794334Sgshapiro				{
440894334Sgshapiro					if (sm_strcasecmp(type, "dn") == 0)
440994334Sgshapiro					{
441090792Sgshapiro						recurse = true;
441194334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_DN;
441290792Sgshapiro					}
441390792Sgshapiro					else if (sm_strcasecmp(type, "filter") == 0)
441490792Sgshapiro					{
441590792Sgshapiro						recurse = true;
441694334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_FILTER;
441790792Sgshapiro					}
441890792Sgshapiro					else if (sm_strcasecmp(type, "url") == 0)
441990792Sgshapiro					{
442090792Sgshapiro						recurse = true;
442194334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_URL;
442290792Sgshapiro					}
442394334Sgshapiro					else if (sm_strcasecmp(type, "normal") == 0)
442490792Sgshapiro					{
442594334Sgshapiro						lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
442694334Sgshapiro						normalseen = true;
442790792Sgshapiro					}
442890792Sgshapiro					else
442990792Sgshapiro					{
443090792Sgshapiro						syserr("Unknown attribute type (%s) in %s",
443190792Sgshapiro						       type, map->map_mname);
443290792Sgshapiro						return false;
443390792Sgshapiro					}
443490792Sgshapiro				}
443590792Sgshapiro				else
443694334Sgshapiro				{
443794334Sgshapiro					lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
443894334Sgshapiro					normalseen = true;
443994334Sgshapiro				}
444090792Sgshapiro				i++;
444190792Sgshapiro			}
444238032Speter		}
444364562Sgshapiro		lmap->ldap_attr[i] = NULL;
4444141858Sgshapiro
4445141858Sgshapiro		/* Set in case needed in future code */
4446132943Sgshapiro		attrssetup = true;
4447141858Sgshapiro
444894334Sgshapiro		if (recurse && !normalseen)
444990792Sgshapiro		{
445094334Sgshapiro			syserr("LDAP recursion requested in %s but no returnable attribute given",
445190792Sgshapiro			       map->map_mname);
445290792Sgshapiro			return false;
445390792Sgshapiro		}
445490792Sgshapiro		if (recurse && lmap->ldap_attrsonly == LDAPMAP_TRUE)
445590792Sgshapiro		{
445690792Sgshapiro			syserr("LDAP recursion requested in %s can not be used with -n",
445790792Sgshapiro			       map->map_mname);
445890792Sgshapiro			return false;
445990792Sgshapiro		}
446038032Speter	}
446138032Speter	map->map_db1 = (ARBPTR_T) lmap;
446290792Sgshapiro	return true;
446338032Speter}
446438032Speter
446564562Sgshapiro/*
446664562Sgshapiro**  LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
446764562Sgshapiro**
446864562Sgshapiro**	Parameters:
446964562Sgshapiro**		spec -- map argument string from LDAPDefaults option
447064562Sgshapiro**
447164562Sgshapiro**	Returns:
447264562Sgshapiro**		None.
447364562Sgshapiro*/
447464562Sgshapiro
447564562Sgshapirovoid
447664562Sgshapiroldapmap_set_defaults(spec)
447764562Sgshapiro	char *spec;
447864562Sgshapiro{
447973188Sgshapiro	STAB *class;
448064562Sgshapiro	MAP map;
448164562Sgshapiro
448264562Sgshapiro	/* Allocate and set the default values */
448364562Sgshapiro	if (LDAPDefaults == NULL)
448490792Sgshapiro		LDAPDefaults = (SM_LDAP_STRUCT *) xalloc(sizeof *LDAPDefaults);
448590792Sgshapiro	sm_ldap_clear(LDAPDefaults);
448664562Sgshapiro
448764562Sgshapiro	memset(&map, '\0', sizeof map);
448873188Sgshapiro
448973188Sgshapiro	/* look up the class */
449073188Sgshapiro	class = stab("ldap", ST_MAPCLASS, ST_FIND);
449173188Sgshapiro	if (class == NULL)
449273188Sgshapiro	{
449373188Sgshapiro		syserr("readcf: LDAPDefaultSpec: class ldap not available");
449473188Sgshapiro		return;
449573188Sgshapiro	}
449673188Sgshapiro	map.map_class = &class->s_mapclass;
449764562Sgshapiro	map.map_db1 = (ARBPTR_T) LDAPDefaults;
449873188Sgshapiro	map.map_mname = "O LDAPDefaultSpec";
449964562Sgshapiro
450064562Sgshapiro	(void) ldapmap_parseargs(&map, spec);
450164562Sgshapiro
450264562Sgshapiro	/* These should never be set in LDAPDefaults */
450364562Sgshapiro	if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) ||
450464562Sgshapiro	    map.map_spacesub != SpaceSub ||
450564562Sgshapiro	    map.map_app != NULL ||
450664562Sgshapiro	    map.map_tapp != NULL)
450764562Sgshapiro	{
450864562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
450990792Sgshapiro		SM_FREE_CLR(map.map_app);
451090792Sgshapiro		SM_FREE_CLR(map.map_tapp);
451164562Sgshapiro	}
451264562Sgshapiro
451364562Sgshapiro	if (LDAPDefaults->ldap_filter != NULL)
451464562Sgshapiro	{
451564562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
451694334Sgshapiro
451764562Sgshapiro		/* don't free, it isn't malloc'ed in parseargs */
451864562Sgshapiro		LDAPDefaults->ldap_filter = NULL;
451964562Sgshapiro	}
452064562Sgshapiro
452164562Sgshapiro	if (LDAPDefaults->ldap_attr[0] != NULL)
452264562Sgshapiro	{
452364562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes");
452464562Sgshapiro		/* don't free, they aren't malloc'ed in parseargs */
452564562Sgshapiro		LDAPDefaults->ldap_attr[0] = NULL;
452664562Sgshapiro	}
452764562Sgshapiro}
452864562Sgshapiro#endif /* LDAPMAP */
452990792Sgshapiro/*
453064562Sgshapiro**  PH map
453164562Sgshapiro*/
453264562Sgshapiro
453390792Sgshapiro#if PH_MAP
453464562Sgshapiro
453564562Sgshapiro/*
453664562Sgshapiro**  Support for the CCSO Nameserver (ph/qi).
453764562Sgshapiro**  This code is intended to replace the so-called "ph mailer".
453864562Sgshapiro**  Contributed by Mark D. Roth <roth@uiuc.edu>.  Contact him for support.
453964562Sgshapiro*/
454064562Sgshapiro
454190792Sgshapiro/* what version of the ph map code we're running */
4542110560Sgshapirostatic char phmap_id[128];
454364562Sgshapiro
454490792Sgshapiro/* sendmail version for phmap id string */
454590792Sgshapiroextern const char Version[];
454690792Sgshapiro
4547132943Sgshapiro/* assume we're using nph-1.2.x if not specified */
4548110560Sgshapiro# ifndef NPH_VERSION
4549132943Sgshapiro#  define NPH_VERSION		10200
4550110560Sgshapiro# endif
4551110560Sgshapiro
4552110560Sgshapiro/* compatibility for versions older than nph-1.2.0 */
4553110560Sgshapiro# if NPH_VERSION < 10200
4554110560Sgshapiro#  define PH_OPEN_ROUNDROBIN	PH_ROUNDROBIN
4555110560Sgshapiro#  define PH_OPEN_DONTID	PH_DONTID
4556110560Sgshapiro#  define PH_CLOSE_FAST		PH_FASTCLOSE
4557110560Sgshapiro#  define PH_ERR_DATAERR	PH_DATAERR
4558110560Sgshapiro#  define PH_ERR_NOMATCH	PH_NOMATCH
4559110560Sgshapiro# endif /* NPH_VERSION < 10200 */
4560110560Sgshapiro
456164562Sgshapiro/*
456264562Sgshapiro**  PH_MAP_PARSEARGS -- parse ph map definition args.
456364562Sgshapiro*/
456464562Sgshapiro
456564562Sgshapirobool
456664562Sgshapiroph_map_parseargs(map, args)
456764562Sgshapiro	MAP *map;
456864562Sgshapiro	char *args;
456964562Sgshapiro{
457090792Sgshapiro	register bool done;
457190792Sgshapiro	register char *p = args;
457264562Sgshapiro	PH_MAP_STRUCT *pmap = NULL;
457364562Sgshapiro
457490792Sgshapiro	/* initialize version string */
457590792Sgshapiro	(void) sm_snprintf(phmap_id, sizeof phmap_id,
457690792Sgshapiro			   "sendmail-%s phmap-20010529 libphclient-%s",
457790792Sgshapiro			   Version, libphclient_version);
457890792Sgshapiro
457964562Sgshapiro	pmap = (PH_MAP_STRUCT *) xalloc(sizeof *pmap);
458064562Sgshapiro
458164562Sgshapiro	/* defaults */
458264562Sgshapiro	pmap->ph_servers = NULL;
458364562Sgshapiro	pmap->ph_field_list = NULL;
458490792Sgshapiro	pmap->ph = NULL;
458564562Sgshapiro	pmap->ph_timeout = 0;
458690792Sgshapiro	pmap->ph_fastclose = 0;
458764562Sgshapiro
458864562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
458964562Sgshapiro	for (;;)
459064562Sgshapiro	{
459164562Sgshapiro		while (isascii(*p) && isspace(*p))
459264562Sgshapiro			p++;
459364562Sgshapiro		if (*p != '-')
459464562Sgshapiro			break;
459564562Sgshapiro		switch (*++p)
459664562Sgshapiro		{
459764562Sgshapiro		  case 'N':
459864562Sgshapiro			map->map_mflags |= MF_INCLNULL;
459964562Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
460064562Sgshapiro			break;
460164562Sgshapiro
460264562Sgshapiro		  case 'O':
460364562Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
460464562Sgshapiro			break;
460564562Sgshapiro
460664562Sgshapiro		  case 'o':
460764562Sgshapiro			map->map_mflags |= MF_OPTIONAL;
460864562Sgshapiro			break;
460964562Sgshapiro
461064562Sgshapiro		  case 'f':
461164562Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
461264562Sgshapiro			break;
461364562Sgshapiro
461464562Sgshapiro		  case 'm':
461564562Sgshapiro			map->map_mflags |= MF_MATCHONLY;
461664562Sgshapiro			break;
461764562Sgshapiro
461864562Sgshapiro		  case 'A':
461964562Sgshapiro			map->map_mflags |= MF_APPEND;
462064562Sgshapiro			break;
462164562Sgshapiro
462264562Sgshapiro		  case 'q':
462364562Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
462464562Sgshapiro			break;
462564562Sgshapiro
462664562Sgshapiro		  case 't':
462764562Sgshapiro			map->map_mflags |= MF_NODEFER;
462864562Sgshapiro			break;
462964562Sgshapiro
463064562Sgshapiro		  case 'a':
463164562Sgshapiro			map->map_app = ++p;
463264562Sgshapiro			break;
463364562Sgshapiro
463464562Sgshapiro		  case 'T':
463564562Sgshapiro			map->map_tapp = ++p;
463664562Sgshapiro			break;
463764562Sgshapiro
463864562Sgshapiro		  case 'l':
463964562Sgshapiro			while (isascii(*++p) && isspace(*p))
464064562Sgshapiro				continue;
464164562Sgshapiro			pmap->ph_timeout = atoi(p);
464264562Sgshapiro			break;
464364562Sgshapiro
464464562Sgshapiro		  case 'S':
464564562Sgshapiro			map->map_spacesub = *++p;
464664562Sgshapiro			break;
464764562Sgshapiro
464864562Sgshapiro		  case 'D':
464964562Sgshapiro			map->map_mflags |= MF_DEFER;
465064562Sgshapiro			break;
465164562Sgshapiro
465264562Sgshapiro		  case 'h':		/* PH server list */
465364562Sgshapiro			while (isascii(*++p) && isspace(*p))
465464562Sgshapiro				continue;
465564562Sgshapiro			pmap->ph_servers = p;
465664562Sgshapiro			break;
465764562Sgshapiro
465890792Sgshapiro		  case 'k':		/* fields to search for */
465964562Sgshapiro			while (isascii(*++p) && isspace(*p))
466064562Sgshapiro				continue;
466164562Sgshapiro			pmap->ph_field_list = p;
466264562Sgshapiro			break;
466364562Sgshapiro
466464562Sgshapiro		  default:
466590792Sgshapiro			syserr("ph_map_parseargs: unknown option -%c", *p);
466664562Sgshapiro		}
466764562Sgshapiro
466864562Sgshapiro		/* try to account for quoted strings */
466964562Sgshapiro		done = isascii(*p) && isspace(*p);
467064562Sgshapiro		while (*p != '\0' && !done)
467164562Sgshapiro		{
467264562Sgshapiro			if (*p == '"')
467364562Sgshapiro			{
467464562Sgshapiro				while (*++p != '"' && *p != '\0')
467564562Sgshapiro					continue;
467664562Sgshapiro				if (*p != '\0')
467764562Sgshapiro					p++;
467864562Sgshapiro			}
467964562Sgshapiro			else
468064562Sgshapiro				p++;
468164562Sgshapiro			done = isascii(*p) && isspace(*p);
468264562Sgshapiro		}
468364562Sgshapiro
468464562Sgshapiro		if (*p != '\0')
468564562Sgshapiro			*p++ = '\0';
468664562Sgshapiro	}
468764562Sgshapiro
468864562Sgshapiro	if (map->map_app != NULL)
468964562Sgshapiro		map->map_app = newstr(ph_map_dequote(map->map_app));
469064562Sgshapiro	if (map->map_tapp != NULL)
469164562Sgshapiro		map->map_tapp = newstr(ph_map_dequote(map->map_tapp));
469264562Sgshapiro
469364562Sgshapiro	if (pmap->ph_field_list != NULL)
469464562Sgshapiro		pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
469564562Sgshapiro
469664562Sgshapiro	if (pmap->ph_servers != NULL)
469764562Sgshapiro		pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
469864562Sgshapiro	else
469964562Sgshapiro	{
470064562Sgshapiro		syserr("ph_map_parseargs: -h flag is required");
470190792Sgshapiro		return false;
470264562Sgshapiro	}
470364562Sgshapiro
470464562Sgshapiro	map->map_db1 = (ARBPTR_T) pmap;
470590792Sgshapiro	return true;
470664562Sgshapiro}
470764562Sgshapiro
470864562Sgshapiro/*
470964562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
471064562Sgshapiro*/
471164562Sgshapiro
471290792Sgshapirovoid
471390792Sgshapiroph_map_close(map)
471464562Sgshapiro	MAP *map;
471564562Sgshapiro{
471664562Sgshapiro	PH_MAP_STRUCT *pmap;
471764562Sgshapiro
471864562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
471990792Sgshapiro	if (tTd(38, 9))
472094334Sgshapiro		sm_dprintf("ph_map_close(%s): pmap->ph_fastclose=%d\n",
472190792Sgshapiro			   map->map_mname, pmap->ph_fastclose);
472264562Sgshapiro
472390792Sgshapiro
472490792Sgshapiro	if (pmap->ph != NULL)
472564562Sgshapiro	{
472690792Sgshapiro		ph_set_sendhook(pmap->ph, NULL);
472790792Sgshapiro		ph_set_recvhook(pmap->ph, NULL);
472890792Sgshapiro		ph_close(pmap->ph, pmap->ph_fastclose);
472964562Sgshapiro	}
473090792Sgshapiro
473164562Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
473264562Sgshapiro}
473364562Sgshapiro
473464562Sgshapirostatic jmp_buf  PHTimeout;
473564562Sgshapiro
473664562Sgshapiro/* ARGSUSED */
473764562Sgshapirostatic void
473890792Sgshapiroph_timeout(unused)
473990792Sgshapiro	int unused;
474064562Sgshapiro{
474177349Sgshapiro	/*
474277349Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
474377349Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
474477349Sgshapiro	**	DOING.
474577349Sgshapiro	*/
474677349Sgshapiro
474777349Sgshapiro	errno = ETIMEDOUT;
474864562Sgshapiro	longjmp(PHTimeout, 1);
474964562Sgshapiro}
475064562Sgshapiro
475190792Sgshapirostatic void
4752110560Sgshapiro#if NPH_VERSION >= 10200
4753110560Sgshapiroph_map_send_debug(appdata, text)
4754110560Sgshapiro	void *appdata;
4755110560Sgshapiro#else
475690792Sgshapiroph_map_send_debug(text)
4757110560Sgshapiro#endif
475890792Sgshapiro	char *text;
475964562Sgshapiro{
476090792Sgshapiro	if (LogLevel > 9)
476190792Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
476290792Sgshapiro			  "ph_map_send_debug: ==> %s", text);
476390792Sgshapiro	if (tTd(38, 20))
476490792Sgshapiro		sm_dprintf("ph_map_send_debug: ==> %s\n", text);
476590792Sgshapiro}
476664562Sgshapiro
476790792Sgshapirostatic void
4768110560Sgshapiro#if NPH_VERSION >= 10200
4769110560Sgshapiroph_map_recv_debug(appdata, text)
4770110560Sgshapiro	void *appdata;
4771110560Sgshapiro#else
477290792Sgshapiroph_map_recv_debug(text)
4773110560Sgshapiro#endif
477490792Sgshapiro	char *text;
477590792Sgshapiro{
477690792Sgshapiro	if (LogLevel > 10)
477790792Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
477890792Sgshapiro			  "ph_map_recv_debug: <== %s", text);
477990792Sgshapiro	if (tTd(38, 21))
478090792Sgshapiro		sm_dprintf("ph_map_recv_debug: <== %s\n", text);
478164562Sgshapiro}
478264562Sgshapiro
478390792Sgshapiro/*
478464562Sgshapiro**  PH_MAP_OPEN -- sub for opening PH map
478564562Sgshapiro*/
478664562Sgshapirobool
478764562Sgshapiroph_map_open(map, mode)
478864562Sgshapiro	MAP *map;
478964562Sgshapiro	int mode;
479064562Sgshapiro{
479190792Sgshapiro	PH_MAP_STRUCT *pmap;
479290792Sgshapiro	register SM_EVENT *ev = NULL;
479364562Sgshapiro	int save_errno = 0;
479490792Sgshapiro	char *hostlist, *host;
479564562Sgshapiro
479664562Sgshapiro	if (tTd(38, 2))
479790792Sgshapiro		sm_dprintf("ph_map_open(%s)\n", map->map_mname);
479864562Sgshapiro
479964562Sgshapiro	mode &= O_ACCMODE;
480064562Sgshapiro	if (mode != O_RDONLY)
480164562Sgshapiro	{
480264562Sgshapiro		/* issue a pseudo-error message */
480390792Sgshapiro		errno = SM_EMAPCANTWRITE;
480490792Sgshapiro		return false;
480564562Sgshapiro	}
480664562Sgshapiro
480766494Sgshapiro	if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER &&
480866494Sgshapiro	    bitset(MF_DEFER, map->map_mflags))
480966494Sgshapiro	{
481066494Sgshapiro		if (tTd(9, 1))
481190792Sgshapiro			sm_dprintf("ph_map_open(%s) => DEFERRED\n",
481290792Sgshapiro				   map->map_mname);
481366494Sgshapiro
481466494Sgshapiro		/*
481590792Sgshapiro		**  Unset MF_DEFER here so that map_lookup() returns
481690792Sgshapiro		**  a temporary failure using the bogus map and
481790792Sgshapiro		**  map->map_tapp instead of the default permanent error.
481866494Sgshapiro		*/
481966494Sgshapiro
482066494Sgshapiro		map->map_mflags &= ~MF_DEFER;
482190792Sgshapiro		return false;
482266494Sgshapiro	}
482366494Sgshapiro
482464562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
482590792Sgshapiro	pmap->ph_fastclose = 0;		/* refresh field for reopen */
482664562Sgshapiro
482790792Sgshapiro	/* try each host in the list */
482864562Sgshapiro	hostlist = newstr(pmap->ph_servers);
482990792Sgshapiro	for (host = strtok(hostlist, " ");
483090792Sgshapiro	     host != NULL;
483190792Sgshapiro	     host = strtok(NULL, " "))
483264562Sgshapiro	{
483390792Sgshapiro		/* set timeout */
483464562Sgshapiro		if (pmap->ph_timeout != 0)
483564562Sgshapiro		{
483664562Sgshapiro			if (setjmp(PHTimeout) != 0)
483764562Sgshapiro			{
483864562Sgshapiro				ev = NULL;
483964562Sgshapiro				if (LogLevel > 1)
484064562Sgshapiro					sm_syslog(LOG_NOTICE, CurEnv->e_id,
484164562Sgshapiro						  "timeout connecting to PH server %.100s",
484290792Sgshapiro						  host);
484364562Sgshapiro				errno = ETIMEDOUT;
484464562Sgshapiro				goto ph_map_open_abort;
484564562Sgshapiro			}
484690792Sgshapiro			ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
484764562Sgshapiro		}
484890792Sgshapiro
484990792Sgshapiro		/* open connection to server */
4850110560Sgshapiro		if (ph_open(&(pmap->ph), host,
4851110560Sgshapiro			    PH_OPEN_ROUNDROBIN|PH_OPEN_DONTID,
4852110560Sgshapiro			    ph_map_send_debug, ph_map_recv_debug
4853110560Sgshapiro#if NPH_VERSION >= 10200
4854110560Sgshapiro			    , NULL
4855110560Sgshapiro#endif
4856110560Sgshapiro			    ) == 0
4857110560Sgshapiro		    && ph_id(pmap->ph, phmap_id) == 0)
485864562Sgshapiro		{
485964562Sgshapiro			if (ev != NULL)
486090792Sgshapiro				sm_clrevent(ev);
486190792Sgshapiro			sm_free(hostlist); /* XXX */
486290792Sgshapiro			return true;
486364562Sgshapiro		}
486490792Sgshapiro
486564562Sgshapiro  ph_map_open_abort:
486690792Sgshapiro		save_errno = errno;
486764562Sgshapiro		if (ev != NULL)
486890792Sgshapiro			sm_clrevent(ev);
4869110560Sgshapiro		pmap->ph_fastclose = PH_CLOSE_FAST;
487090792Sgshapiro		ph_map_close(map);
487190792Sgshapiro		errno = save_errno;
487290792Sgshapiro	}
487364562Sgshapiro
487466494Sgshapiro	if (bitset(MF_NODEFER, map->map_mflags))
487564562Sgshapiro	{
487666494Sgshapiro		if (errno == 0)
487764562Sgshapiro			errno = EAGAIN;
487866494Sgshapiro		syserr("ph_map_open: %s: cannot connect to PH server",
487966494Sgshapiro		       map->map_mname);
488064562Sgshapiro	}
488166494Sgshapiro	else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1)
488264562Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
488366494Sgshapiro			  "ph_map_open: %s: cannot connect to PH server",
488466494Sgshapiro			  map->map_mname);
488590792Sgshapiro	sm_free(hostlist); /* XXX */
488690792Sgshapiro	return false;
488764562Sgshapiro}
488864562Sgshapiro
488964562Sgshapiro/*
489064562Sgshapiro**  PH_MAP_LOOKUP -- look up key from ph server
489164562Sgshapiro*/
489264562Sgshapiro
489364562Sgshapirochar *
489464562Sgshapiroph_map_lookup(map, key, args, pstat)
489564562Sgshapiro	MAP *map;
489664562Sgshapiro	char *key;
489764562Sgshapiro	char **args;
489864562Sgshapiro	int *pstat;
489964562Sgshapiro{
490090792Sgshapiro	int i, save_errno = 0;
490190792Sgshapiro	register SM_EVENT *ev = NULL;
490264562Sgshapiro	PH_MAP_STRUCT *pmap;
490390792Sgshapiro	char *value = NULL;
490464562Sgshapiro
490564562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
490664562Sgshapiro
490764562Sgshapiro	*pstat = EX_OK;
490864562Sgshapiro
490990792Sgshapiro	/* set timeout */
491064562Sgshapiro	if (pmap->ph_timeout != 0)
491164562Sgshapiro	{
491264562Sgshapiro		if (setjmp(PHTimeout) != 0)
491364562Sgshapiro		{
491464562Sgshapiro			ev = NULL;
491564562Sgshapiro			if (LogLevel > 1)
491664562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
491764562Sgshapiro					  "timeout during PH lookup of %.100s",
491864562Sgshapiro					  key);
491964562Sgshapiro			errno = ETIMEDOUT;
492064562Sgshapiro			*pstat = EX_TEMPFAIL;
492164562Sgshapiro			goto ph_map_lookup_abort;
492264562Sgshapiro		}
492390792Sgshapiro		ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
492464562Sgshapiro	}
492564562Sgshapiro
492690792Sgshapiro	/* perform lookup */
492790792Sgshapiro	i = ph_email_resolve(pmap->ph, key, pmap->ph_field_list, &value);
492890792Sgshapiro	if (i == -1)
492990792Sgshapiro		*pstat = EX_TEMPFAIL;
4930110560Sgshapiro	else if (i == PH_ERR_NOMATCH || i == PH_ERR_DATAERR)
493190792Sgshapiro		*pstat = EX_UNAVAILABLE;
493264562Sgshapiro
493364562Sgshapiro  ph_map_lookup_abort:
493464562Sgshapiro	if (ev != NULL)
493590792Sgshapiro		sm_clrevent(ev);
493664562Sgshapiro
493764562Sgshapiro	/*
493890792Sgshapiro	**  Close the connection if the timer popped
493964562Sgshapiro	**  or we got a temporary PH error
494064562Sgshapiro	*/
494164562Sgshapiro
494264562Sgshapiro	if (*pstat == EX_TEMPFAIL)
494390792Sgshapiro	{
494490792Sgshapiro		save_errno = errno;
4945110560Sgshapiro		pmap->ph_fastclose = PH_CLOSE_FAST;
494690792Sgshapiro		ph_map_close(map);
494790792Sgshapiro		errno = save_errno;
494890792Sgshapiro	}
494964562Sgshapiro
495064562Sgshapiro	if (*pstat == EX_OK)
495164562Sgshapiro	{
495264562Sgshapiro		if (tTd(38,20))
495390792Sgshapiro			sm_dprintf("ph_map_lookup: %s => %s\n", key, value);
495464562Sgshapiro
495564562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
495690792Sgshapiro			return map_rewrite(map, key, strlen(key), NULL);
495764562Sgshapiro		else
495890792Sgshapiro			return map_rewrite(map, value, strlen(value), args);
495964562Sgshapiro	}
496064562Sgshapiro
496164562Sgshapiro	return NULL;
496264562Sgshapiro}
496364562Sgshapiro#endif /* PH_MAP */
496490792Sgshapiro/*
496542575Speter**  syslog map
496638032Speter*/
496738032Speter
496838032Speter#define map_prio	map_lockfd	/* overload field */
496938032Speter
497038032Speter/*
497142575Speter**  SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
497238032Speter*/
497338032Speter
497438032Speterbool
497538032Spetersyslog_map_parseargs(map, args)
497638032Speter	MAP *map;
497738032Speter	char *args;
497838032Speter{
497938032Speter	char *p = args;
498038032Speter	char *priority = NULL;
498138032Speter
498264562Sgshapiro	/* there is no check whether there is really an argument */
498364562Sgshapiro	while (*p != '\0')
498438032Speter	{
498538032Speter		while (isascii(*p) && isspace(*p))
498638032Speter			p++;
498738032Speter		if (*p != '-')
498838032Speter			break;
498964562Sgshapiro		++p;
499064562Sgshapiro		if (*p == 'D')
499164562Sgshapiro		{
499264562Sgshapiro			map->map_mflags |= MF_DEFER;
499364562Sgshapiro			++p;
499464562Sgshapiro		}
499564562Sgshapiro		else if (*p == 'S')
499664562Sgshapiro		{
499764562Sgshapiro			map->map_spacesub = *++p;
499864562Sgshapiro			if (*p != '\0')
499964562Sgshapiro				p++;
500064562Sgshapiro		}
500164562Sgshapiro		else if (*p == 'L')
500264562Sgshapiro		{
500364562Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p))
500464562Sgshapiro				continue;
500564562Sgshapiro			if (*p == '\0')
500664562Sgshapiro				break;
500764562Sgshapiro			priority = p;
500864562Sgshapiro			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
500964562Sgshapiro				p++;
501064562Sgshapiro			if (*p != '\0')
501164562Sgshapiro				*p++ = '\0';
501264562Sgshapiro		}
501364562Sgshapiro		else
501464562Sgshapiro		{
501564562Sgshapiro			syserr("Illegal option %c map syslog", *p);
501664562Sgshapiro			++p;
501764562Sgshapiro		}
501838032Speter	}
501938032Speter
502038032Speter	if (priority == NULL)
502138032Speter		map->map_prio = LOG_INFO;
502238032Speter	else
502338032Speter	{
502490792Sgshapiro		if (sm_strncasecmp("LOG_", priority, 4) == 0)
502538032Speter			priority += 4;
502638032Speter
502738032Speter#ifdef LOG_EMERG
502890792Sgshapiro		if (sm_strcasecmp("EMERG", priority) == 0)
502938032Speter			map->map_prio = LOG_EMERG;
503038032Speter		else
503164562Sgshapiro#endif /* LOG_EMERG */
503238032Speter#ifdef LOG_ALERT
503390792Sgshapiro		if (sm_strcasecmp("ALERT", priority) == 0)
503438032Speter			map->map_prio = LOG_ALERT;
503538032Speter		else
503664562Sgshapiro#endif /* LOG_ALERT */
503738032Speter#ifdef LOG_CRIT
503890792Sgshapiro		if (sm_strcasecmp("CRIT", priority) == 0)
503938032Speter			map->map_prio = LOG_CRIT;
504038032Speter		else
504164562Sgshapiro#endif /* LOG_CRIT */
504238032Speter#ifdef LOG_ERR
504390792Sgshapiro		if (sm_strcasecmp("ERR", priority) == 0)
504438032Speter			map->map_prio = LOG_ERR;
504538032Speter		else
504664562Sgshapiro#endif /* LOG_ERR */
504738032Speter#ifdef LOG_WARNING
504890792Sgshapiro		if (sm_strcasecmp("WARNING", priority) == 0)
504938032Speter			map->map_prio = LOG_WARNING;
505038032Speter		else
505164562Sgshapiro#endif /* LOG_WARNING */
505238032Speter#ifdef LOG_NOTICE
505390792Sgshapiro		if (sm_strcasecmp("NOTICE", priority) == 0)
505438032Speter			map->map_prio = LOG_NOTICE;
505538032Speter		else
505664562Sgshapiro#endif /* LOG_NOTICE */
505738032Speter#ifdef LOG_INFO
505890792Sgshapiro		if (sm_strcasecmp("INFO", priority) == 0)
505938032Speter			map->map_prio = LOG_INFO;
506038032Speter		else
506164562Sgshapiro#endif /* LOG_INFO */
506238032Speter#ifdef LOG_DEBUG
506390792Sgshapiro		if (sm_strcasecmp("DEBUG", priority) == 0)
506438032Speter			map->map_prio = LOG_DEBUG;
506538032Speter		else
506664562Sgshapiro#endif /* LOG_DEBUG */
506738032Speter		{
506890792Sgshapiro			syserr("syslog_map_parseargs: Unknown priority %s",
506938032Speter			       priority);
507090792Sgshapiro			return false;
507138032Speter		}
507238032Speter	}
507390792Sgshapiro	return true;
507438032Speter}
507538032Speter
507638032Speter/*
507742575Speter**  SYSLOG_MAP_LOOKUP -- rewrite and syslog message.  Always return empty string
507838032Speter*/
507938032Speter
508038032Speterchar *
508138032Spetersyslog_map_lookup(map, string, args, statp)
508238032Speter	MAP *map;
508338032Speter	char *string;
508438032Speter	char **args;
508538032Speter	int *statp;
508638032Speter{
508738032Speter	char *ptr = map_rewrite(map, string, strlen(string), args);
508838032Speter
508938032Speter	if (ptr != NULL)
509038032Speter	{
509138032Speter		if (tTd(38, 20))
509290792Sgshapiro			sm_dprintf("syslog_map_lookup(%s (priority %d): %s\n",
509364562Sgshapiro				map->map_mname, map->map_prio, ptr);
509438032Speter
509538032Speter		sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
509638032Speter	}
509738032Speter
509838032Speter	*statp = EX_OK;
509938032Speter	return "";
510038032Speter}
510138032Speter
510290792Sgshapiro/*
510338032Speter**  HESIOD Modules
510438032Speter*/
510538032Speter
510690792Sgshapiro#if HESIOD
510738032Speter
510838032Speterbool
510938032Speterhes_map_open(map, mode)
511038032Speter	MAP *map;
511138032Speter	int mode;
511238032Speter{
511338032Speter	if (tTd(38, 2))
511490792Sgshapiro		sm_dprintf("hes_map_open(%s, %s, %d)\n",
511538032Speter			map->map_mname, map->map_file, mode);
511638032Speter
511738032Speter	if (mode != O_RDONLY)
511838032Speter	{
511938032Speter		/* issue a pseudo-error message */
512090792Sgshapiro		errno = SM_EMAPCANTWRITE;
512190792Sgshapiro		return false;
512238032Speter	}
512338032Speter
512464562Sgshapiro# ifdef HESIOD_INIT
512538032Speter	if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
512690792Sgshapiro		return true;
512738032Speter
512838032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
512994334Sgshapiro		syserr("451 4.3.5 cannot initialize Hesiod map (%s)",
513090792Sgshapiro			sm_errstring(errno));
513190792Sgshapiro	return false;
513264562Sgshapiro# else /* HESIOD_INIT */
513338032Speter	if (hes_error() == HES_ER_UNINIT)
513438032Speter		hes_init();
513538032Speter	switch (hes_error())
513638032Speter	{
513738032Speter	  case HES_ER_OK:
513838032Speter	  case HES_ER_NOTFOUND:
513990792Sgshapiro		return true;
514038032Speter	}
514138032Speter
514238032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
514394334Sgshapiro		syserr("451 4.3.5 cannot initialize Hesiod map (%d)", hes_error());
514438032Speter
514590792Sgshapiro	return false;
514664562Sgshapiro# endif /* HESIOD_INIT */
514738032Speter}
514838032Speter
514938032Speterchar *
515038032Speterhes_map_lookup(map, name, av, statp)
515138032Speter	MAP *map;
515238032Speter	char *name;
515338032Speter	char **av;
515438032Speter	int *statp;
515538032Speter{
515638032Speter	char **hp;
515738032Speter
515838032Speter	if (tTd(38, 20))
515990792Sgshapiro		sm_dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
516038032Speter
516138032Speter	if (name[0] == '\\')
516238032Speter	{
516338032Speter		char *np;
516438032Speter		int nl;
516577349Sgshapiro		int save_errno;
516638032Speter		char nbuf[MAXNAME];
516738032Speter
516838032Speter		nl = strlen(name);
516938032Speter		if (nl < sizeof nbuf - 1)
517038032Speter			np = nbuf;
517138032Speter		else
517238032Speter			np = xalloc(strlen(name) + 2);
517338032Speter		np[0] = '\\';
517490792Sgshapiro		(void) sm_strlcpy(&np[1], name, (sizeof nbuf) - 1);
517564562Sgshapiro# ifdef HESIOD_INIT
517638032Speter		hp = hesiod_resolve(HesiodContext, np, map->map_file);
517764562Sgshapiro# else /* HESIOD_INIT */
517838032Speter		hp = hes_resolve(np, map->map_file);
517964562Sgshapiro# endif /* HESIOD_INIT */
518077349Sgshapiro		save_errno = errno;
518138032Speter		if (np != nbuf)
518290792Sgshapiro			sm_free(np); /* XXX */
518377349Sgshapiro		errno = save_errno;
518438032Speter	}
518538032Speter	else
518638032Speter	{
518764562Sgshapiro# ifdef HESIOD_INIT
518838032Speter		hp = hesiod_resolve(HesiodContext, name, map->map_file);
518964562Sgshapiro# else /* HESIOD_INIT */
519038032Speter		hp = hes_resolve(name, map->map_file);
519164562Sgshapiro# endif /* HESIOD_INIT */
519238032Speter	}
519364562Sgshapiro# ifdef HESIOD_INIT
519477349Sgshapiro	if (hp == NULL || *hp == NULL)
519538032Speter	{
519638032Speter		switch (errno)
519738032Speter		{
519838032Speter		  case ENOENT:
519938032Speter			  *statp = EX_NOTFOUND;
520038032Speter			  break;
520138032Speter		  case ECONNREFUSED:
520238032Speter			  *statp = EX_TEMPFAIL;
520338032Speter			  break;
520490792Sgshapiro		  case EMSGSIZE:
520538032Speter		  case ENOMEM:
520638032Speter		  default:
520738032Speter			  *statp = EX_UNAVAILABLE;
520838032Speter			  break;
520938032Speter		}
521082017Sgshapiro		if (hp != NULL)
521182017Sgshapiro			hesiod_free_list(HesiodContext, hp);
521238032Speter		return NULL;
521338032Speter	}
521464562Sgshapiro# else /* HESIOD_INIT */
521538032Speter	if (hp == NULL || hp[0] == NULL)
521638032Speter	{
521738032Speter		switch (hes_error())
521838032Speter		{
521938032Speter		  case HES_ER_OK:
522038032Speter			*statp = EX_OK;
522138032Speter			break;
522238032Speter
522338032Speter		  case HES_ER_NOTFOUND:
522438032Speter			*statp = EX_NOTFOUND;
522538032Speter			break;
522638032Speter
522738032Speter		  case HES_ER_CONFIG:
522838032Speter			*statp = EX_UNAVAILABLE;
522938032Speter			break;
523038032Speter
523138032Speter		  case HES_ER_NET:
523238032Speter			*statp = EX_TEMPFAIL;
523338032Speter			break;
523438032Speter		}
523538032Speter		return NULL;
523638032Speter	}
523764562Sgshapiro# endif /* HESIOD_INIT */
523838032Speter
523938032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
524038032Speter		return map_rewrite(map, name, strlen(name), NULL);
524138032Speter	else
524238032Speter		return map_rewrite(map, hp[0], strlen(hp[0]), av);
524338032Speter}
524438032Speter
524590792Sgshapiro/*
524690792Sgshapiro**  HES_MAP_CLOSE -- free the Hesiod context
524790792Sgshapiro*/
524890792Sgshapiro
524990792Sgshapirovoid
525090792Sgshapirohes_map_close(map)
525190792Sgshapiro	MAP *map;
525290792Sgshapiro{
525390792Sgshapiro	if (tTd(38, 20))
525490792Sgshapiro		sm_dprintf("hes_map_close(%s)\n", map->map_file);
525590792Sgshapiro
525690792Sgshapiro# ifdef HESIOD_INIT
525790792Sgshapiro	/* Free the hesiod context */
525890792Sgshapiro	if (HesiodContext != NULL)
525990792Sgshapiro	{
526090792Sgshapiro		hesiod_end(HesiodContext);
526190792Sgshapiro		HesiodContext = NULL;
526290792Sgshapiro	}
526390792Sgshapiro# endif /* HESIOD_INIT */
526490792Sgshapiro}
526590792Sgshapiro
526664562Sgshapiro#endif /* HESIOD */
526790792Sgshapiro/*
526838032Speter**  NeXT NETINFO Modules
526938032Speter*/
527038032Speter
527138032Speter#if NETINFO
527238032Speter
527338032Speter# define NETINFO_DEFAULT_DIR		"/aliases"
527438032Speter# define NETINFO_DEFAULT_PROPERTY	"members"
527538032Speter
527638032Speter/*
527738032Speter**  NI_MAP_OPEN -- open NetInfo Aliases
527838032Speter*/
527938032Speter
528038032Speterbool
528138032Speterni_map_open(map, mode)
528238032Speter	MAP *map;
528338032Speter	int mode;
528438032Speter{
528538032Speter	if (tTd(38, 2))
528690792Sgshapiro		sm_dprintf("ni_map_open(%s, %s, %d)\n",
528738032Speter			map->map_mname, map->map_file, mode);
528838032Speter	mode &= O_ACCMODE;
528938032Speter
529038032Speter	if (*map->map_file == '\0')
529138032Speter		map->map_file = NETINFO_DEFAULT_DIR;
529238032Speter
529338032Speter	if (map->map_valcolnm == NULL)
529438032Speter		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
529538032Speter
529690792Sgshapiro	if (map->map_coldelim == '\0')
529790792Sgshapiro	{
529890792Sgshapiro		if (bitset(MF_ALIAS, map->map_mflags))
529990792Sgshapiro			map->map_coldelim = ',';
530090792Sgshapiro		else if (bitset(MF_FILECLASS, map->map_mflags))
530190792Sgshapiro			map->map_coldelim = ' ';
530290792Sgshapiro	}
530390792Sgshapiro	return true;
530438032Speter}
530538032Speter
530638032Speter
530738032Speter/*
530838032Speter**  NI_MAP_LOOKUP -- look up a datum in NetInfo
530938032Speter*/
531038032Speter
531138032Speterchar *
531238032Speterni_map_lookup(map, name, av, statp)
531338032Speter	MAP *map;
531438032Speter	char *name;
531538032Speter	char **av;
531638032Speter	int *statp;
531738032Speter{
531838032Speter	char *res;
531938032Speter	char *propval;
532038032Speter
532138032Speter	if (tTd(38, 20))
532290792Sgshapiro		sm_dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
532338032Speter
532438032Speter	propval = ni_propval(map->map_file, map->map_keycolnm, name,
532538032Speter			     map->map_valcolnm, map->map_coldelim);
532638032Speter
532738032Speter	if (propval == NULL)
532838032Speter		return NULL;
532938032Speter
533090792Sgshapiro	SM_TRY
533190792Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
533290792Sgshapiro			res = map_rewrite(map, name, strlen(name), NULL);
533390792Sgshapiro		else
533490792Sgshapiro			res = map_rewrite(map, propval, strlen(propval), av);
533590792Sgshapiro	SM_FINALLY
533690792Sgshapiro		sm_free(propval);
533790792Sgshapiro	SM_END_TRY
533838032Speter	return res;
533938032Speter}
534038032Speter
534138032Speter
534264562Sgshapirostatic bool
534338032Speterni_getcanonname(name, hbsize, statp)
534438032Speter	char *name;
534538032Speter	int hbsize;
534638032Speter	int *statp;
534738032Speter{
534838032Speter	char *vptr;
534938032Speter	char *ptr;
535038032Speter	char nbuf[MAXNAME + 1];
535138032Speter
535238032Speter	if (tTd(38, 20))
535390792Sgshapiro		sm_dprintf("ni_getcanonname(%s)\n", name);
535438032Speter
535590792Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
535638032Speter	{
535738032Speter		*statp = EX_UNAVAILABLE;
535890792Sgshapiro		return false;
535938032Speter	}
536073188Sgshapiro	(void) shorten_hostname(nbuf);
536138032Speter
536238032Speter	/* we only accept single token search key */
536338032Speter	if (strchr(nbuf, '.'))
536438032Speter	{
536538032Speter		*statp = EX_NOHOST;
536690792Sgshapiro		return false;
536738032Speter	}
536838032Speter
536938032Speter	/* Do the search */
537038032Speter	vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
537138032Speter
537238032Speter	if (vptr == NULL)
537338032Speter	{
537438032Speter		*statp = EX_NOHOST;
537590792Sgshapiro		return false;
537638032Speter	}
537738032Speter
537838032Speter	/* Only want the first machine name */
537938032Speter	if ((ptr = strchr(vptr, '\n')) != NULL)
538038032Speter		*ptr = '\0';
538138032Speter
538290792Sgshapiro	if (sm_strlcpy(name, vptr, hbsize) >= hbsize)
538338032Speter	{
538477349Sgshapiro		sm_free(vptr);
538590792Sgshapiro		*statp = EX_UNAVAILABLE;
538690792Sgshapiro		return true;
538738032Speter	}
538877349Sgshapiro	sm_free(vptr);
538990792Sgshapiro	*statp = EX_OK;
539090792Sgshapiro	return false;
539138032Speter}
539290792Sgshapiro#endif /* NETINFO */
539338032Speter/*
539438032Speter**  TEXT (unindexed text file) Modules
539538032Speter**
539638032Speter**	This code donated by Sun Microsystems.
539738032Speter*/
539838032Speter
539938032Speter#define map_sff		map_lockfd	/* overload field */
540038032Speter
540138032Speter
540238032Speter/*
540338032Speter**  TEXT_MAP_OPEN -- open text table
540438032Speter*/
540538032Speter
540638032Speterbool
540738032Spetertext_map_open(map, mode)
540838032Speter	MAP *map;
540938032Speter	int mode;
541038032Speter{
541164562Sgshapiro	long sff;
541238032Speter	int i;
541338032Speter
541438032Speter	if (tTd(38, 2))
541590792Sgshapiro		sm_dprintf("text_map_open(%s, %s, %d)\n",
541638032Speter			map->map_mname, map->map_file, mode);
541738032Speter
541838032Speter	mode &= O_ACCMODE;
541938032Speter	if (mode != O_RDONLY)
542038032Speter	{
542138032Speter		errno = EPERM;
542290792Sgshapiro		return false;
542338032Speter	}
542438032Speter
542538032Speter	if (*map->map_file == '\0')
542638032Speter	{
542738032Speter		syserr("text map \"%s\": file name required",
542838032Speter			map->map_mname);
542990792Sgshapiro		return false;
543038032Speter	}
543138032Speter
543238032Speter	if (map->map_file[0] != '/')
543338032Speter	{
543438032Speter		syserr("text map \"%s\": file name must be fully qualified",
543538032Speter			map->map_mname);
543690792Sgshapiro		return false;
543738032Speter	}
543838032Speter
543938032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
544064562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
544138032Speter		sff |= SFF_NOWLINK;
544264562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
544338032Speter		sff |= SFF_SAFEDIRPATH;
544438032Speter	if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
544538032Speter			  sff, S_IRUSR, NULL)) != 0)
544638032Speter	{
544764562Sgshapiro		int save_errno = errno;
544864562Sgshapiro
544938032Speter		/* cannot open this map */
545038032Speter		if (tTd(38, 2))
545190792Sgshapiro			sm_dprintf("\tunsafe map file: %d\n", i);
545264562Sgshapiro		errno = save_errno;
545338032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
545438032Speter			syserr("text map \"%s\": unsafe map file %s",
545538032Speter				map->map_mname, map->map_file);
545690792Sgshapiro		return false;
545738032Speter	}
545838032Speter
545938032Speter	if (map->map_keycolnm == NULL)
546038032Speter		map->map_keycolno = 0;
546138032Speter	else
546238032Speter	{
546338032Speter		if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
546438032Speter		{
546538032Speter			syserr("text map \"%s\", file %s: -k should specify a number, not %s",
546638032Speter				map->map_mname, map->map_file,
546738032Speter				map->map_keycolnm);
546890792Sgshapiro			return false;
546938032Speter		}
547038032Speter		map->map_keycolno = atoi(map->map_keycolnm);
547138032Speter	}
547238032Speter
547338032Speter	if (map->map_valcolnm == NULL)
547438032Speter		map->map_valcolno = 0;
547538032Speter	else
547638032Speter	{
547738032Speter		if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
547838032Speter		{
547938032Speter			syserr("text map \"%s\", file %s: -v should specify a number, not %s",
548038032Speter					map->map_mname, map->map_file,
548138032Speter					map->map_valcolnm);
548290792Sgshapiro			return false;
548338032Speter		}
548438032Speter		map->map_valcolno = atoi(map->map_valcolnm);
548538032Speter	}
548638032Speter
548738032Speter	if (tTd(38, 2))
548838032Speter	{
548990792Sgshapiro		sm_dprintf("text_map_open(%s, %s): delimiter = ",
549038032Speter			map->map_mname, map->map_file);
549138032Speter		if (map->map_coldelim == '\0')
549290792Sgshapiro			sm_dprintf("(white space)\n");
549338032Speter		else
549490792Sgshapiro			sm_dprintf("%c\n", map->map_coldelim);
549538032Speter	}
549638032Speter
549738032Speter	map->map_sff = sff;
549890792Sgshapiro	return true;
549938032Speter}
550038032Speter
550138032Speter
550238032Speter/*
550338032Speter**  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
550438032Speter*/
550538032Speter
550638032Speterchar *
550738032Spetertext_map_lookup(map, name, av, statp)
550838032Speter	MAP *map;
550938032Speter	char *name;
551038032Speter	char **av;
551138032Speter	int *statp;
551238032Speter{
551338032Speter	char *vp;
551438032Speter	auto int vsize;
551538032Speter	int buflen;
551690792Sgshapiro	SM_FILE_T *f;
551738032Speter	char delim;
551838032Speter	int key_idx;
551938032Speter	bool found_it;
552064562Sgshapiro	long sff = map->map_sff;
552138032Speter	char search_key[MAXNAME + 1];
552238032Speter	char linebuf[MAXLINE];
552338032Speter	char buf[MAXNAME + 1];
552438032Speter
552590792Sgshapiro	found_it = false;
552638032Speter	if (tTd(38, 20))
552790792Sgshapiro		sm_dprintf("text_map_lookup(%s, %s)\n", map->map_mname,  name);
552838032Speter
552938032Speter	buflen = strlen(name);
553038032Speter	if (buflen > sizeof search_key - 1)
553190792Sgshapiro		buflen = sizeof search_key - 1;	/* XXX just cut if off? */
553264562Sgshapiro	memmove(search_key, name, buflen);
553338032Speter	search_key[buflen] = '\0';
553438032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
553538032Speter		makelower(search_key);
553638032Speter
553738032Speter	f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
553838032Speter	if (f == NULL)
553938032Speter	{
554038032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
554138032Speter		*statp = EX_UNAVAILABLE;
554238032Speter		return NULL;
554338032Speter	}
554438032Speter	key_idx = map->map_keycolno;
554538032Speter	delim = map->map_coldelim;
554698121Sgshapiro	while (sm_io_fgets(f, SM_TIME_DEFAULT,
554798121Sgshapiro			   linebuf, sizeof linebuf) != NULL)
554838032Speter	{
554938032Speter		char *p;
555038032Speter
555138032Speter		/* skip comment line */
555238032Speter		if (linebuf[0] == '#')
555338032Speter			continue;
555438032Speter		p = strchr(linebuf, '\n');
555538032Speter		if (p != NULL)
555638032Speter			*p = '\0';
555738032Speter		p = get_column(linebuf, key_idx, delim, buf, sizeof buf);
555890792Sgshapiro		if (p != NULL && sm_strcasecmp(search_key, p) == 0)
555938032Speter		{
556090792Sgshapiro			found_it = true;
556138032Speter			break;
556238032Speter		}
556338032Speter	}
556490792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
556538032Speter	if (!found_it)
556638032Speter	{
556738032Speter		*statp = EX_NOTFOUND;
556838032Speter		return NULL;
556938032Speter	}
557038032Speter	vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof buf);
557142575Speter	if (vp == NULL)
557242575Speter	{
557342575Speter		*statp = EX_NOTFOUND;
557442575Speter		return NULL;
557542575Speter	}
557638032Speter	vsize = strlen(vp);
557738032Speter	*statp = EX_OK;
557838032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
557938032Speter		return map_rewrite(map, name, strlen(name), NULL);
558038032Speter	else
558138032Speter		return map_rewrite(map, vp, vsize, av);
558238032Speter}
558338032Speter
558438032Speter/*
558538032Speter**  TEXT_GETCANONNAME -- look up canonical name in hosts file
558638032Speter*/
558738032Speter
558864562Sgshapirostatic bool
558938032Spetertext_getcanonname(name, hbsize, statp)
559038032Speter	char *name;
559138032Speter	int hbsize;
559238032Speter	int *statp;
559338032Speter{
559438032Speter	bool found;
559573188Sgshapiro	char *dot;
559690792Sgshapiro	SM_FILE_T *f;
559738032Speter	char linebuf[MAXLINE];
559838032Speter	char cbuf[MAXNAME + 1];
559938032Speter	char nbuf[MAXNAME + 1];
560038032Speter
560138032Speter	if (tTd(38, 20))
560290792Sgshapiro		sm_dprintf("text_getcanonname(%s)\n", name);
560338032Speter
560490792Sgshapiro	if (sm_strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
560538032Speter	{
560638032Speter		*statp = EX_UNAVAILABLE;
560790792Sgshapiro		return false;
560838032Speter	}
560973188Sgshapiro	dot = shorten_hostname(nbuf);
561038032Speter
561190792Sgshapiro	f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, HostsFile, SM_IO_RDONLY,
561290792Sgshapiro		       NULL);
561338032Speter	if (f == NULL)
561438032Speter	{
561538032Speter		*statp = EX_UNAVAILABLE;
561690792Sgshapiro		return false;
561738032Speter	}
561890792Sgshapiro	found = false;
561990792Sgshapiro	while (!found &&
562098121Sgshapiro		sm_io_fgets(f, SM_TIME_DEFAULT,
562198121Sgshapiro			    linebuf, sizeof linebuf) != NULL)
562238032Speter	{
562338032Speter		char *p = strpbrk(linebuf, "#\n");
562438032Speter
562538032Speter		if (p != NULL)
562638032Speter			*p = '\0';
562738032Speter		if (linebuf[0] != '\0')
562873188Sgshapiro			found = extract_canonname(nbuf, dot, linebuf,
562973188Sgshapiro						  cbuf, sizeof cbuf);
563038032Speter	}
563190792Sgshapiro	(void) sm_io_close(f, SM_TIME_DEFAULT);
563238032Speter	if (!found)
563338032Speter	{
563438032Speter		*statp = EX_NOHOST;
563590792Sgshapiro		return false;
563638032Speter	}
563738032Speter
563890792Sgshapiro	if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
563938032Speter	{
564090792Sgshapiro		*statp = EX_UNAVAILABLE;
564190792Sgshapiro		return false;
564238032Speter	}
564390792Sgshapiro	*statp = EX_OK;
564490792Sgshapiro	return true;
564538032Speter}
564690792Sgshapiro/*
564738032Speter**  STAB (Symbol Table) Modules
564838032Speter*/
564938032Speter
565038032Speter
565138032Speter/*
565238032Speter**  STAB_MAP_LOOKUP -- look up alias in symbol table
565338032Speter*/
565438032Speter
565538032Speter/* ARGSUSED2 */
565638032Speterchar *
565738032Speterstab_map_lookup(map, name, av, pstat)
565838032Speter	register MAP *map;
565938032Speter	char *name;
566038032Speter	char **av;
566138032Speter	int *pstat;
566238032Speter{
566338032Speter	register STAB *s;
566438032Speter
566538032Speter	if (tTd(38, 20))
566690792Sgshapiro		sm_dprintf("stab_lookup(%s, %s)\n",
566738032Speter			map->map_mname, name);
566838032Speter
566938032Speter	s = stab(name, ST_ALIAS, ST_FIND);
5670147078Sgshapiro	if (s == NULL)
5671147078Sgshapiro		return NULL;
5672147078Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
5673147078Sgshapiro		return map_rewrite(map, name, strlen(name), NULL);
5674147078Sgshapiro	else
5675147078Sgshapiro		return map_rewrite(map, s->s_alias, strlen(s->s_alias), av);
567638032Speter}
567738032Speter
567838032Speter/*
567938032Speter**  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
568038032Speter*/
568138032Speter
568238032Spetervoid
568338032Speterstab_map_store(map, lhs, rhs)
568438032Speter	register MAP *map;
568538032Speter	char *lhs;
568638032Speter	char *rhs;
568738032Speter{
568838032Speter	register STAB *s;
568938032Speter
569038032Speter	s = stab(lhs, ST_ALIAS, ST_ENTER);
569138032Speter	s->s_alias = newstr(rhs);
569238032Speter}
569338032Speter
569438032Speter
569538032Speter/*
569638032Speter**  STAB_MAP_OPEN -- initialize (reads data file)
569738032Speter**
569838032Speter**	This is a wierd case -- it is only intended as a fallback for
569938032Speter**	aliases.  For this reason, opens for write (only during a
570038032Speter**	"newaliases") always fails, and opens for read open the
570138032Speter**	actual underlying text file instead of the database.
570238032Speter*/
570338032Speter
570438032Speterbool
570538032Speterstab_map_open(map, mode)
570638032Speter	register MAP *map;
570738032Speter	int mode;
570838032Speter{
570990792Sgshapiro	SM_FILE_T *af;
571064562Sgshapiro	long sff;
571138032Speter	struct stat st;
571238032Speter
571338032Speter	if (tTd(38, 2))
571490792Sgshapiro		sm_dprintf("stab_map_open(%s, %s, %d)\n",
571538032Speter			map->map_mname, map->map_file, mode);
571638032Speter
571738032Speter	mode &= O_ACCMODE;
571838032Speter	if (mode != O_RDONLY)
571938032Speter	{
572038032Speter		errno = EPERM;
572190792Sgshapiro		return false;
572238032Speter	}
572338032Speter
572438032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
572564562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
572638032Speter		sff |= SFF_NOWLINK;
572764562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
572838032Speter		sff |= SFF_SAFEDIRPATH;
572938032Speter	af = safefopen(map->map_file, O_RDONLY, 0444, sff);
573038032Speter	if (af == NULL)
573190792Sgshapiro		return false;
573290792Sgshapiro	readaliases(map, af, false, false);
573338032Speter
573490792Sgshapiro	if (fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &st) >= 0)
573538032Speter		map->map_mtime = st.st_mtime;
573690792Sgshapiro	(void) sm_io_close(af, SM_TIME_DEFAULT);
573738032Speter
573890792Sgshapiro	return true;
573938032Speter}
574090792Sgshapiro/*
574138032Speter**  Implicit Modules
574238032Speter**
574338032Speter**	Tries several types.  For back compatibility of aliases.
574438032Speter*/
574538032Speter
574638032Speter
574738032Speter/*
574838032Speter**  IMPL_MAP_LOOKUP -- lookup in best open database
574938032Speter*/
575038032Speter
575138032Speterchar *
575238032Speterimpl_map_lookup(map, name, av, pstat)
575338032Speter	MAP *map;
575438032Speter	char *name;
575538032Speter	char **av;
575638032Speter	int *pstat;
575738032Speter{
575838032Speter	if (tTd(38, 20))
575990792Sgshapiro		sm_dprintf("impl_map_lookup(%s, %s)\n",
576038032Speter			map->map_mname, name);
576138032Speter
576290792Sgshapiro#if NEWDB
576338032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
576438032Speter		return db_map_lookup(map, name, av, pstat);
576564562Sgshapiro#endif /* NEWDB */
576690792Sgshapiro#if NDBM
576738032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
576838032Speter		return ndbm_map_lookup(map, name, av, pstat);
576964562Sgshapiro#endif /* NDBM */
577038032Speter	return stab_map_lookup(map, name, av, pstat);
577138032Speter}
577238032Speter
577338032Speter/*
577438032Speter**  IMPL_MAP_STORE -- store in open databases
577538032Speter*/
577638032Speter
577738032Spetervoid
577838032Speterimpl_map_store(map, lhs, rhs)
577938032Speter	MAP *map;
578038032Speter	char *lhs;
578138032Speter	char *rhs;
578238032Speter{
578338032Speter	if (tTd(38, 12))
578490792Sgshapiro		sm_dprintf("impl_map_store(%s, %s, %s)\n",
578538032Speter			map->map_mname, lhs, rhs);
578690792Sgshapiro#if NEWDB
578738032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
578838032Speter		db_map_store(map, lhs, rhs);
578964562Sgshapiro#endif /* NEWDB */
579090792Sgshapiro#if NDBM
579138032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
579238032Speter		ndbm_map_store(map, lhs, rhs);
579364562Sgshapiro#endif /* NDBM */
579438032Speter	stab_map_store(map, lhs, rhs);
579538032Speter}
579638032Speter
579738032Speter/*
579838032Speter**  IMPL_MAP_OPEN -- implicit database open
579938032Speter*/
580038032Speter
580138032Speterbool
580238032Speterimpl_map_open(map, mode)
580338032Speter	MAP *map;
580438032Speter	int mode;
580538032Speter{
580638032Speter	if (tTd(38, 2))
580790792Sgshapiro		sm_dprintf("impl_map_open(%s, %s, %d)\n",
580838032Speter			map->map_mname, map->map_file, mode);
580938032Speter
581038032Speter	mode &= O_ACCMODE;
581190792Sgshapiro#if NEWDB
581238032Speter	map->map_mflags |= MF_IMPL_HASH;
581338032Speter	if (hash_map_open(map, mode))
581438032Speter	{
581538032Speter# ifdef NDBM_YP_COMPAT
581638032Speter		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
581764562Sgshapiro# endif /* NDBM_YP_COMPAT */
581890792Sgshapiro			return true;
581938032Speter	}
582038032Speter	else
582138032Speter		map->map_mflags &= ~MF_IMPL_HASH;
582264562Sgshapiro#endif /* NEWDB */
582390792Sgshapiro#if NDBM
582438032Speter	map->map_mflags |= MF_IMPL_NDBM;
582538032Speter	if (ndbm_map_open(map, mode))
582638032Speter	{
582790792Sgshapiro		return true;
582838032Speter	}
582938032Speter	else
583038032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
583164562Sgshapiro#endif /* NDBM */
583238032Speter
583338032Speter#if defined(NEWDB) || defined(NDBM)
583438032Speter	if (Verbose)
583538032Speter		message("WARNING: cannot open alias database %s%s",
583638032Speter			map->map_file,
583738032Speter			mode == O_RDONLY ? "; reading text version" : "");
583864562Sgshapiro#else /* defined(NEWDB) || defined(NDBM) */
583938032Speter	if (mode != O_RDONLY)
584038032Speter		usrerr("Cannot rebuild aliases: no database format defined");
584164562Sgshapiro#endif /* defined(NEWDB) || defined(NDBM) */
584238032Speter
584338032Speter	if (mode == O_RDONLY)
584438032Speter		return stab_map_open(map, mode);
584538032Speter	else
584690792Sgshapiro		return false;
584738032Speter}
584838032Speter
584938032Speter
585038032Speter/*
585138032Speter**  IMPL_MAP_CLOSE -- close any open database(s)
585238032Speter*/
585338032Speter
585438032Spetervoid
585538032Speterimpl_map_close(map)
585638032Speter	MAP *map;
585738032Speter{
585838032Speter	if (tTd(38, 9))
585990792Sgshapiro		sm_dprintf("impl_map_close(%s, %s, %lx)\n",
586038032Speter			map->map_mname, map->map_file, map->map_mflags);
586190792Sgshapiro#if NEWDB
586238032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
586338032Speter	{
586438032Speter		db_map_close(map);
586538032Speter		map->map_mflags &= ~MF_IMPL_HASH;
586638032Speter	}
586764562Sgshapiro#endif /* NEWDB */
586838032Speter
586990792Sgshapiro#if NDBM
587038032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
587138032Speter	{
587238032Speter		ndbm_map_close(map);
587338032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
587438032Speter	}
587564562Sgshapiro#endif /* NDBM */
587638032Speter}
587790792Sgshapiro/*
587838032Speter**  User map class.
587938032Speter**
588038032Speter**	Provides access to the system password file.
588138032Speter*/
588238032Speter
588338032Speter/*
588438032Speter**  USER_MAP_OPEN -- open user map
588538032Speter**
588638032Speter**	Really just binds field names to field numbers.
588738032Speter*/
588838032Speter
588938032Speterbool
589038032Speteruser_map_open(map, mode)
589138032Speter	MAP *map;
589238032Speter	int mode;
589338032Speter{
589438032Speter	if (tTd(38, 2))
589590792Sgshapiro		sm_dprintf("user_map_open(%s, %d)\n",
589638032Speter			map->map_mname, mode);
589738032Speter
589838032Speter	mode &= O_ACCMODE;
589938032Speter	if (mode != O_RDONLY)
590038032Speter	{
590138032Speter		/* issue a pseudo-error message */
590290792Sgshapiro		errno = SM_EMAPCANTWRITE;
590390792Sgshapiro		return false;
590438032Speter	}
590538032Speter	if (map->map_valcolnm == NULL)
590664562Sgshapiro		/* EMPTY */
590738032Speter		/* nothing */ ;
590890792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "name") == 0)
590938032Speter		map->map_valcolno = 1;
591090792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "passwd") == 0)
591138032Speter		map->map_valcolno = 2;
591290792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "uid") == 0)
591338032Speter		map->map_valcolno = 3;
591490792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "gid") == 0)
591538032Speter		map->map_valcolno = 4;
591690792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "gecos") == 0)
591738032Speter		map->map_valcolno = 5;
591890792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "dir") == 0)
591938032Speter		map->map_valcolno = 6;
592090792Sgshapiro	else if (sm_strcasecmp(map->map_valcolnm, "shell") == 0)
592138032Speter		map->map_valcolno = 7;
592238032Speter	else
592338032Speter	{
592438032Speter		syserr("User map %s: unknown column name %s",
592538032Speter			map->map_mname, map->map_valcolnm);
592690792Sgshapiro		return false;
592738032Speter	}
592890792Sgshapiro	return true;
592938032Speter}
593038032Speter
593138032Speter
593238032Speter/*
593338032Speter**  USER_MAP_LOOKUP -- look up a user in the passwd file.
593438032Speter*/
593538032Speter
593638032Speter/* ARGSUSED3 */
593738032Speterchar *
593838032Speteruser_map_lookup(map, key, av, statp)
593938032Speter	MAP *map;
594038032Speter	char *key;
594138032Speter	char **av;
594238032Speter	int *statp;
594338032Speter{
594438032Speter	auto bool fuzzy;
594590792Sgshapiro	SM_MBDB_T user;
594638032Speter
594738032Speter	if (tTd(38, 20))
594890792Sgshapiro		sm_dprintf("user_map_lookup(%s, %s)\n",
594938032Speter			map->map_mname, key);
595038032Speter
595190792Sgshapiro	*statp = finduser(key, &fuzzy, &user);
595290792Sgshapiro	if (*statp != EX_OK)
595338032Speter		return NULL;
595438032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
595538032Speter		return map_rewrite(map, key, strlen(key), NULL);
595638032Speter	else
595738032Speter	{
595838032Speter		char *rwval = NULL;
595938032Speter		char buf[30];
596038032Speter
596138032Speter		switch (map->map_valcolno)
596238032Speter		{
596338032Speter		  case 0:
596438032Speter		  case 1:
596590792Sgshapiro			rwval = user.mbdb_name;
596638032Speter			break;
596738032Speter
596838032Speter		  case 2:
596990792Sgshapiro			rwval = "x";	/* passwd no longer supported */
597038032Speter			break;
597138032Speter
597238032Speter		  case 3:
597390792Sgshapiro			(void) sm_snprintf(buf, sizeof buf, "%d",
597490792Sgshapiro					   (int) user.mbdb_uid);
597538032Speter			rwval = buf;
597638032Speter			break;
597738032Speter
597838032Speter		  case 4:
597990792Sgshapiro			(void) sm_snprintf(buf, sizeof buf, "%d",
598090792Sgshapiro					   (int) user.mbdb_gid);
598138032Speter			rwval = buf;
598238032Speter			break;
598338032Speter
598438032Speter		  case 5:
598590792Sgshapiro			rwval = user.mbdb_fullname;
598638032Speter			break;
598738032Speter
598838032Speter		  case 6:
598990792Sgshapiro			rwval = user.mbdb_homedir;
599038032Speter			break;
599138032Speter
599238032Speter		  case 7:
599390792Sgshapiro			rwval = user.mbdb_shell;
599438032Speter			break;
599538032Speter		}
599638032Speter		return map_rewrite(map, rwval, strlen(rwval), av);
599738032Speter	}
599838032Speter}
599990792Sgshapiro/*
600038032Speter**  Program map type.
600138032Speter**
600238032Speter**	This provides access to arbitrary programs.  It should be used
600338032Speter**	only very sparingly, since there is no way to bound the cost
600438032Speter**	of invoking an arbitrary program.
600538032Speter*/
600638032Speter
600738032Speterchar *
600838032Speterprog_map_lookup(map, name, av, statp)
600938032Speter	MAP *map;
601038032Speter	char *name;
601138032Speter	char **av;
601238032Speter	int *statp;
601338032Speter{
601438032Speter	int i;
601564562Sgshapiro	int save_errno;
601638032Speter	int fd;
601764562Sgshapiro	int status;
601838032Speter	auto pid_t pid;
601964562Sgshapiro	register char *p;
602038032Speter	char *rval;
602138032Speter	char *argv[MAXPV + 1];
602238032Speter	char buf[MAXLINE];
602338032Speter
602438032Speter	if (tTd(38, 20))
602590792Sgshapiro		sm_dprintf("prog_map_lookup(%s, %s) %s\n",
602638032Speter			map->map_mname, name, map->map_file);
602738032Speter
602838032Speter	i = 0;
602938032Speter	argv[i++] = map->map_file;
603038032Speter	if (map->map_rebuild != NULL)
603138032Speter	{
603290792Sgshapiro		(void) sm_strlcpy(buf, map->map_rebuild, sizeof buf);
603338032Speter		for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
603438032Speter		{
603538032Speter			if (i >= MAXPV - 1)
603638032Speter				break;
603738032Speter			argv[i++] = p;
603838032Speter		}
603938032Speter	}
604038032Speter	argv[i++] = name;
604138032Speter	argv[i] = NULL;
604238032Speter	if (tTd(38, 21))
604338032Speter	{
604490792Sgshapiro		sm_dprintf("prog_open:");
604538032Speter		for (i = 0; argv[i] != NULL; i++)
604690792Sgshapiro			sm_dprintf(" %s", argv[i]);
604790792Sgshapiro		sm_dprintf("\n");
604838032Speter	}
604990792Sgshapiro	(void) sm_blocksignal(SIGCHLD);
605038032Speter	pid = prog_open(argv, &fd, CurEnv);
605138032Speter	if (pid < 0)
605238032Speter	{
605338032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
605438032Speter			syserr("prog_map_lookup(%s) failed (%s) -- closing",
605590792Sgshapiro			       map->map_mname, sm_errstring(errno));
605638032Speter		else if (tTd(38, 9))
605790792Sgshapiro			sm_dprintf("prog_map_lookup(%s) failed (%s) -- closing",
605890792Sgshapiro				   map->map_mname, sm_errstring(errno));
605938032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
606038032Speter		*statp = EX_OSFILE;
606138032Speter		return NULL;
606238032Speter	}
606338032Speter	i = read(fd, buf, sizeof buf - 1);
606438032Speter	if (i < 0)
606538032Speter	{
606690792Sgshapiro		syserr("prog_map_lookup(%s): read error %s",
606790792Sgshapiro		       map->map_mname, sm_errstring(errno));
606838032Speter		rval = NULL;
606938032Speter	}
607038032Speter	else if (i == 0)
607138032Speter	{
607238032Speter		if (tTd(38, 20))
607390792Sgshapiro			sm_dprintf("prog_map_lookup(%s): empty answer\n",
607490792Sgshapiro				   map->map_mname);
607538032Speter		rval = NULL;
607638032Speter	}
607738032Speter	else
607838032Speter	{
607938032Speter		buf[i] = '\0';
608038032Speter		p = strchr(buf, '\n');
608138032Speter		if (p != NULL)
608238032Speter			*p = '\0';
608338032Speter
608438032Speter		/* collect the return value */
608538032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
608638032Speter			rval = map_rewrite(map, name, strlen(name), NULL);
608738032Speter		else
608877349Sgshapiro			rval = map_rewrite(map, buf, strlen(buf), av);
608938032Speter
609038032Speter		/* now flush any additional output */
609138032Speter		while ((i = read(fd, buf, sizeof buf)) > 0)
609238032Speter			continue;
609338032Speter	}
609438032Speter
609538032Speter	/* wait for the process to terminate */
609664562Sgshapiro	(void) close(fd);
609764562Sgshapiro	status = waitfor(pid);
609864562Sgshapiro	save_errno = errno;
609990792Sgshapiro	(void) sm_releasesignal(SIGCHLD);
610064562Sgshapiro	errno = save_errno;
610138032Speter
610264562Sgshapiro	if (status == -1)
610338032Speter	{
610490792Sgshapiro		syserr("prog_map_lookup(%s): wait error %s",
610590792Sgshapiro		       map->map_mname, sm_errstring(errno));
610638032Speter		*statp = EX_SOFTWARE;
610738032Speter		rval = NULL;
610838032Speter	}
610964562Sgshapiro	else if (WIFEXITED(status))
611038032Speter	{
611164562Sgshapiro		if ((*statp = WEXITSTATUS(status)) != EX_OK)
611238032Speter			rval = NULL;
611338032Speter	}
611438032Speter	else
611538032Speter	{
611638032Speter		syserr("prog_map_lookup(%s): child died on signal %d",
611790792Sgshapiro		       map->map_mname, status);
611838032Speter		*statp = EX_UNAVAILABLE;
611938032Speter		rval = NULL;
612038032Speter	}
612138032Speter	return rval;
612238032Speter}
612390792Sgshapiro/*
612438032Speter**  Sequenced map type.
612538032Speter**
612638032Speter**	Tries each map in order until something matches, much like
612738032Speter**	implicit.  Stores go to the first map in the list that can
612838032Speter**	support storing.
612938032Speter**
613038032Speter**	This is slightly unusual in that there are two interfaces.
613138032Speter**	The "sequence" interface lets you stack maps arbitrarily.
613238032Speter**	The "switch" interface builds a sequence map by looking
613338032Speter**	at a system-dependent configuration file such as
613438032Speter**	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
613538032Speter**
613638032Speter**	We don't need an explicit open, since all maps are
613790792Sgshapiro**	opened on demand.
613838032Speter*/
613938032Speter
614038032Speter/*
614138032Speter**  SEQ_MAP_PARSE -- Sequenced map parsing
614238032Speter*/
614338032Speter
614438032Speterbool
614538032Speterseq_map_parse(map, ap)
614638032Speter	MAP *map;
614738032Speter	char *ap;
614838032Speter{
614938032Speter	int maxmap;
615038032Speter
615138032Speter	if (tTd(38, 2))
615290792Sgshapiro		sm_dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
615338032Speter	maxmap = 0;
615438032Speter	while (*ap != '\0')
615538032Speter	{
615638032Speter		register char *p;
615738032Speter		STAB *s;
615838032Speter
615938032Speter		/* find beginning of map name */
616038032Speter		while (isascii(*ap) && isspace(*ap))
616138032Speter			ap++;
616264562Sgshapiro		for (p = ap;
616364562Sgshapiro		     (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.';
616464562Sgshapiro		     p++)
616538032Speter			continue;
616638032Speter		if (*p != '\0')
616738032Speter			*p++ = '\0';
616838032Speter		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
616938032Speter			p++;
617038032Speter		if (*ap == '\0')
617138032Speter		{
617238032Speter			ap = p;
617338032Speter			continue;
617438032Speter		}
617538032Speter		s = stab(ap, ST_MAP, ST_FIND);
617638032Speter		if (s == NULL)
617738032Speter		{
617838032Speter			syserr("Sequence map %s: unknown member map %s",
617938032Speter				map->map_mname, ap);
618038032Speter		}
618190792Sgshapiro		else if (maxmap >= MAXMAPSTACK)
618238032Speter		{
618338032Speter			syserr("Sequence map %s: too many member maps (%d max)",
618438032Speter				map->map_mname, MAXMAPSTACK);
618538032Speter			maxmap++;
618638032Speter		}
618738032Speter		else if (maxmap < MAXMAPSTACK)
618838032Speter		{
618938032Speter			map->map_stack[maxmap++] = &s->s_map;
619038032Speter		}
619138032Speter		ap = p;
619238032Speter	}
619390792Sgshapiro	return true;
619438032Speter}
619538032Speter
619638032Speter/*
619738032Speter**  SWITCH_MAP_OPEN -- open a switched map
619838032Speter**
619938032Speter**	This looks at the system-dependent configuration and builds
620038032Speter**	a sequence map that does the same thing.
620138032Speter**
620238032Speter**	Every system must define a switch_map_find routine in conf.c
620338032Speter**	that will return the list of service types associated with a
620438032Speter**	given service class.
620538032Speter*/
620638032Speter
620738032Speterbool
620838032Speterswitch_map_open(map, mode)
620938032Speter	MAP *map;
621038032Speter	int mode;
621138032Speter{
621238032Speter	int mapno;
621338032Speter	int nmaps;
621438032Speter	char *maptype[MAXMAPSTACK];
621538032Speter
621638032Speter	if (tTd(38, 2))
621790792Sgshapiro		sm_dprintf("switch_map_open(%s, %s, %d)\n",
621838032Speter			map->map_mname, map->map_file, mode);
621938032Speter
622038032Speter	mode &= O_ACCMODE;
622138032Speter	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
622238032Speter	if (tTd(38, 19))
622338032Speter	{
622490792Sgshapiro		sm_dprintf("\tswitch_map_find => %d\n", nmaps);
622538032Speter		for (mapno = 0; mapno < nmaps; mapno++)
622690792Sgshapiro			sm_dprintf("\t\t%s\n", maptype[mapno]);
622738032Speter	}
622838032Speter	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
622990792Sgshapiro		return false;
623038032Speter
623138032Speter	for (mapno = 0; mapno < nmaps; mapno++)
623238032Speter	{
623338032Speter		register STAB *s;
623438032Speter		char nbuf[MAXNAME + 1];
623538032Speter
623638032Speter		if (maptype[mapno] == NULL)
623738032Speter			continue;
623890792Sgshapiro		(void) sm_strlcpyn(nbuf, sizeof nbuf, 3,
623990792Sgshapiro				   map->map_mname, ".", maptype[mapno]);
624038032Speter		s = stab(nbuf, ST_MAP, ST_FIND);
624138032Speter		if (s == NULL)
624238032Speter		{
624338032Speter			syserr("Switch map %s: unknown member map %s",
624438032Speter				map->map_mname, nbuf);
624538032Speter		}
624638032Speter		else
624738032Speter		{
624838032Speter			map->map_stack[mapno] = &s->s_map;
624938032Speter			if (tTd(38, 4))
625090792Sgshapiro				sm_dprintf("\tmap_stack[%d] = %s:%s\n",
625190792Sgshapiro					   mapno,
625290792Sgshapiro					   s->s_map.map_class->map_cname,
625390792Sgshapiro					   nbuf);
625438032Speter		}
625538032Speter	}
625690792Sgshapiro	return true;
625738032Speter}
625838032Speter
625990792Sgshapiro#if 0
626038032Speter/*
626138032Speter**  SEQ_MAP_CLOSE -- close all underlying maps
626238032Speter*/
626338032Speter
626438032Spetervoid
626538032Speterseq_map_close(map)
626638032Speter	MAP *map;
626738032Speter{
626838032Speter	int mapno;
626938032Speter
627038032Speter	if (tTd(38, 9))
627190792Sgshapiro		sm_dprintf("seq_map_close(%s)\n", map->map_mname);
627238032Speter
627338032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
627438032Speter	{
627538032Speter		MAP *mm = map->map_stack[mapno];
627638032Speter
627738032Speter		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
627838032Speter			continue;
627977349Sgshapiro		mm->map_mflags |= MF_CLOSING;
628038032Speter		mm->map_class->map_close(mm);
628177349Sgshapiro		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
628238032Speter	}
628338032Speter}
628490792Sgshapiro#endif /* 0 */
628538032Speter
628638032Speter/*
628738032Speter**  SEQ_MAP_LOOKUP -- sequenced map lookup
628838032Speter*/
628938032Speter
629038032Speterchar *
629138032Speterseq_map_lookup(map, key, args, pstat)
629238032Speter	MAP *map;
629338032Speter	char *key;
629438032Speter	char **args;
629538032Speter	int *pstat;
629638032Speter{
629738032Speter	int mapno;
629838032Speter	int mapbit = 0x01;
629990792Sgshapiro	bool tempfail = false;
630038032Speter
630138032Speter	if (tTd(38, 20))
630290792Sgshapiro		sm_dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
630338032Speter
630438032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
630538032Speter	{
630638032Speter		MAP *mm = map->map_stack[mapno];
630738032Speter		char *rv;
630838032Speter
630938032Speter		if (mm == NULL)
631038032Speter			continue;
631164562Sgshapiro		if (!bitset(MF_OPEN, mm->map_mflags) &&
631264562Sgshapiro		    !openmap(mm))
631338032Speter		{
631438032Speter			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
631538032Speter			{
631638032Speter				*pstat = EX_UNAVAILABLE;
631738032Speter				return NULL;
631838032Speter			}
631938032Speter			continue;
632038032Speter		}
632138032Speter		*pstat = EX_OK;
632238032Speter		rv = mm->map_class->map_lookup(mm, key, args, pstat);
632338032Speter		if (rv != NULL)
632438032Speter			return rv;
632538032Speter		if (*pstat == EX_TEMPFAIL)
632638032Speter		{
632738032Speter			if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
632838032Speter				return NULL;
632990792Sgshapiro			tempfail = true;
633038032Speter		}
633138032Speter		else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
633238032Speter			break;
633338032Speter	}
633438032Speter	if (tempfail)
633538032Speter		*pstat = EX_TEMPFAIL;
633638032Speter	else if (*pstat == EX_OK)
633738032Speter		*pstat = EX_NOTFOUND;
633838032Speter	return NULL;
633938032Speter}
634038032Speter
634138032Speter/*
634238032Speter**  SEQ_MAP_STORE -- sequenced map store
634338032Speter*/
634438032Speter
634538032Spetervoid
634638032Speterseq_map_store(map, key, val)
634738032Speter	MAP *map;
634838032Speter	char *key;
634938032Speter	char *val;
635038032Speter{
635138032Speter	int mapno;
635238032Speter
635338032Speter	if (tTd(38, 12))
635490792Sgshapiro		sm_dprintf("seq_map_store(%s, %s, %s)\n",
635538032Speter			map->map_mname, key, val);
635638032Speter
635738032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
635838032Speter	{
635938032Speter		MAP *mm = map->map_stack[mapno];
636038032Speter
636138032Speter		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
636238032Speter			continue;
636338032Speter
636438032Speter		mm->map_class->map_store(mm, key, val);
636538032Speter		return;
636638032Speter	}
636738032Speter	syserr("seq_map_store(%s, %s, %s): no writable map",
636838032Speter		map->map_mname, key, val);
636938032Speter}
637090792Sgshapiro/*
637138032Speter**  NULL stubs
637238032Speter*/
637338032Speter
637438032Speter/* ARGSUSED */
637538032Speterbool
637638032Speternull_map_open(map, mode)
637738032Speter	MAP *map;
637838032Speter	int mode;
637938032Speter{
638090792Sgshapiro	return true;
638138032Speter}
638238032Speter
638338032Speter/* ARGSUSED */
638438032Spetervoid
638538032Speternull_map_close(map)
638638032Speter	MAP *map;
638738032Speter{
638838032Speter	return;
638938032Speter}
639038032Speter
639138032Speterchar *
639238032Speternull_map_lookup(map, key, args, pstat)
639338032Speter	MAP *map;
639438032Speter	char *key;
639538032Speter	char **args;
639638032Speter	int *pstat;
639738032Speter{
639838032Speter	*pstat = EX_NOTFOUND;
639938032Speter	return NULL;
640038032Speter}
640138032Speter
640238032Speter/* ARGSUSED */
640338032Spetervoid
640438032Speternull_map_store(map, key, val)
640538032Speter	MAP *map;
640638032Speter	char *key;
640738032Speter	char *val;
640838032Speter{
640938032Speter	return;
641038032Speter}
641138032Speter
641238032Speter/*
641338032Speter**  BOGUS stubs
641438032Speter*/
641538032Speter
641638032Speterchar *
641738032Speterbogus_map_lookup(map, key, args, pstat)
641838032Speter	MAP *map;
641938032Speter	char *key;
642038032Speter	char **args;
642138032Speter	int *pstat;
642238032Speter{
642338032Speter	*pstat = EX_TEMPFAIL;
642438032Speter	return NULL;
642538032Speter}
642638032Speter
642738032SpeterMAPCLASS	BogusMapClass =
642838032Speter{
642990792Sgshapiro	"bogus-map",		NULL,			0,
643090792Sgshapiro	NULL,			bogus_map_lookup,	null_map_store,
643190792Sgshapiro	null_map_open,		null_map_close,
643238032Speter};
643390792Sgshapiro/*
643464562Sgshapiro**  MACRO modules
643564562Sgshapiro*/
643664562Sgshapiro
643764562Sgshapirochar *
643864562Sgshapiromacro_map_lookup(map, name, av, statp)
643964562Sgshapiro	MAP *map;
644064562Sgshapiro	char *name;
644164562Sgshapiro	char **av;
644264562Sgshapiro	int *statp;
644364562Sgshapiro{
644464562Sgshapiro	int mid;
644564562Sgshapiro
644664562Sgshapiro	if (tTd(38, 20))
644790792Sgshapiro		sm_dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
644864562Sgshapiro			name == NULL ? "NULL" : name);
644964562Sgshapiro
645064562Sgshapiro	if (name == NULL ||
645164562Sgshapiro	    *name == '\0' ||
645290792Sgshapiro	    (mid = macid(name)) == 0)
645364562Sgshapiro	{
645464562Sgshapiro		*statp = EX_CONFIG;
645564562Sgshapiro		return NULL;
645664562Sgshapiro	}
645764562Sgshapiro
645864562Sgshapiro	if (av[1] == NULL)
645990792Sgshapiro		macdefine(&CurEnv->e_macro, A_PERM, mid, NULL);
646064562Sgshapiro	else
646190792Sgshapiro		macdefine(&CurEnv->e_macro, A_TEMP, mid, av[1]);
646264562Sgshapiro
646364562Sgshapiro	*statp = EX_OK;
646464562Sgshapiro	return "";
646564562Sgshapiro}
646690792Sgshapiro/*
646738032Speter**  REGEX modules
646838032Speter*/
646938032Speter
647090792Sgshapiro#if MAP_REGEX
647138032Speter
647238032Speter# include <regex.h>
647338032Speter
647438032Speter# define DEFAULT_DELIM	CONDELSE
647538032Speter# define END_OF_FIELDS	-1
647638032Speter# define ERRBUF_SIZE	80
647738032Speter# define MAX_MATCH	32
647838032Speter
647964562Sgshapiro# define xnalloc(s)	memset(xalloc(s), '\0', s);
648038032Speter
648138032Speterstruct regex_map
648238032Speter{
648371345Sgshapiro	regex_t	*regex_pattern_buf;	/* xalloc it */
648438032Speter	int	*regex_subfields;	/* move to type MAP */
648564562Sgshapiro	char	*regex_delim;		/* move to type MAP */
648638032Speter};
648738032Speter
6488141858Sgshapirostatic int	parse_fields __P((char *, int *, int, int));
6489141858Sgshapirostatic char	*regex_map_rewrite __P((MAP *, const char*, size_t, char **));
6490141858Sgshapiro
649138032Speterstatic int
649238032Speterparse_fields(s, ibuf, blen, nr_substrings)
649338032Speter	char *s;
649438032Speter	int *ibuf;		/* array */
649538032Speter	int blen;		/* number of elements in ibuf */
649638032Speter	int nr_substrings;	/* number of substrings in the pattern */
649738032Speter{
649838032Speter	register char *cp;
649938032Speter	int i = 0;
650090792Sgshapiro	bool lastone = false;
650138032Speter
650238032Speter	blen--;		/* for terminating END_OF_FIELDS */
650338032Speter	cp = s;
650438032Speter	do
650538032Speter	{
650638032Speter		for (;; cp++)
650738032Speter		{
650838032Speter			if (*cp == ',')
650938032Speter			{
651038032Speter				*cp = '\0';
651138032Speter				break;
651238032Speter			}
651338032Speter			if (*cp == '\0')
651438032Speter			{
651590792Sgshapiro				lastone = true;
651638032Speter				break;
651738032Speter			}
651838032Speter		}
651938032Speter		if (i < blen)
652038032Speter		{
652138032Speter			int val = atoi(s);
652238032Speter
652338032Speter			if (val < 0 || val >= nr_substrings)
652438032Speter			{
652538032Speter				syserr("field (%d) out of range, only %d substrings in pattern",
652638032Speter				       val, nr_substrings);
652738032Speter				return -1;
652838032Speter			}
652938032Speter			ibuf[i++] = val;
653038032Speter		}
653138032Speter		else
653238032Speter		{
653390792Sgshapiro			syserr("too many fields, %d max", blen);
653438032Speter			return -1;
653538032Speter		}
653638032Speter		s = ++cp;
653738032Speter	} while (!lastone);
653838032Speter	ibuf[i] = END_OF_FIELDS;
653938032Speter	return i;
654038032Speter}
654138032Speter
654238032Speterbool
654338032Speterregex_map_init(map, ap)
654438032Speter	MAP *map;
654538032Speter	char *ap;
654638032Speter{
654738032Speter	int regerr;
654838032Speter	struct regex_map *map_p;
654938032Speter	register char *p;
655038032Speter	char *sub_param = NULL;
655138032Speter	int pflags;
655290792Sgshapiro	static char defdstr[] = { (char) DEFAULT_DELIM, '\0' };
655338032Speter
655438032Speter	if (tTd(38, 2))
655590792Sgshapiro		sm_dprintf("regex_map_init: mapname '%s', args '%s'\n",
655664562Sgshapiro			map->map_mname, ap);
655738032Speter
655838032Speter	pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
655938032Speter	p = ap;
656064562Sgshapiro	map_p = (struct regex_map *) xnalloc(sizeof *map_p);
656171345Sgshapiro	map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t));
656238032Speter
656338032Speter	for (;;)
656464562Sgshapiro	{
656538032Speter		while (isascii(*p) && isspace(*p))
656638032Speter			p++;
656738032Speter		if (*p != '-')
656838032Speter			break;
656938032Speter		switch (*++p)
657038032Speter		{
657138032Speter		  case 'n':	/* not */
657238032Speter			map->map_mflags |= MF_REGEX_NOT;
657338032Speter			break;
657438032Speter
657538032Speter		  case 'f':	/* case sensitive */
657638032Speter			map->map_mflags |= MF_NOFOLDCASE;
657738032Speter			pflags &= ~REG_ICASE;
657838032Speter			break;
657938032Speter
658038032Speter		  case 'b':	/* basic regular expressions */
658138032Speter			pflags &= ~REG_EXTENDED;
658238032Speter			break;
658338032Speter
658438032Speter		  case 's':	/* substring match () syntax */
658538032Speter			sub_param = ++p;
658638032Speter			pflags &= ~REG_NOSUB;
658738032Speter			break;
658838032Speter
658938032Speter		  case 'd':	/* delimiter */
659064562Sgshapiro			map_p->regex_delim = ++p;
659138032Speter			break;
659238032Speter
659338032Speter		  case 'a':	/* map append */
659438032Speter			map->map_app = ++p;
659538032Speter			break;
659638032Speter
659738032Speter		  case 'm':	/* matchonly */
659838032Speter			map->map_mflags |= MF_MATCHONLY;
659938032Speter			break;
660038032Speter
6601120256Sgshapiro		  case 'q':
6602120256Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
6603120256Sgshapiro			break;
6604120256Sgshapiro
660564562Sgshapiro		  case 'S':
660664562Sgshapiro			map->map_spacesub = *++p;
660764562Sgshapiro			break;
660864562Sgshapiro
660964562Sgshapiro		  case 'D':
661064562Sgshapiro			map->map_mflags |= MF_DEFER;
661164562Sgshapiro			break;
661264562Sgshapiro
661338032Speter		}
661464562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
661564562Sgshapiro			p++;
661664562Sgshapiro		if (*p != '\0')
661764562Sgshapiro			*p++ = '\0';
661838032Speter	}
661938032Speter	if (tTd(38, 3))
662090792Sgshapiro		sm_dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
662138032Speter
662271345Sgshapiro	if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0)
662338032Speter	{
662438032Speter		/* Errorhandling */
662538032Speter		char errbuf[ERRBUF_SIZE];
662638032Speter
662771345Sgshapiro		(void) regerror(regerr, map_p->regex_pattern_buf,
662890792Sgshapiro			 errbuf, sizeof errbuf);
662990792Sgshapiro		syserr("pattern-compile-error: %s", errbuf);
663090792Sgshapiro		sm_free(map_p->regex_pattern_buf); /* XXX */
663190792Sgshapiro		sm_free(map_p); /* XXX */
663290792Sgshapiro		return false;
663338032Speter	}
663438032Speter
663538032Speter	if (map->map_app != NULL)
663638032Speter		map->map_app = newstr(map->map_app);
663764562Sgshapiro	if (map_p->regex_delim != NULL)
663864562Sgshapiro		map_p->regex_delim = newstr(map_p->regex_delim);
663938032Speter	else
664064562Sgshapiro		map_p->regex_delim = defdstr;
664138032Speter
664238032Speter	if (!bitset(REG_NOSUB, pflags))
664338032Speter	{
664438032Speter		/* substring matching */
664538032Speter		int substrings;
664664562Sgshapiro		int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1));
664738032Speter
664871345Sgshapiro		substrings = map_p->regex_pattern_buf->re_nsub + 1;
664938032Speter
665038032Speter		if (tTd(38, 3))
665190792Sgshapiro			sm_dprintf("regex_map_init: nr of substrings %d\n",
665264562Sgshapiro				substrings);
665338032Speter
665438032Speter		if (substrings >= MAX_MATCH)
665538032Speter		{
665690792Sgshapiro			syserr("too many substrings, %d max", MAX_MATCH);
665790792Sgshapiro			sm_free(map_p->regex_pattern_buf); /* XXX */
665890792Sgshapiro			sm_free(map_p); /* XXX */
665990792Sgshapiro			return false;
666038032Speter		}
666138032Speter		if (sub_param != NULL && sub_param[0] != '\0')
666238032Speter		{
666338032Speter			/* optional parameter -sfields */
666438032Speter			if (parse_fields(sub_param, fields,
666538032Speter					 MAX_MATCH + 1, substrings) == -1)
666690792Sgshapiro				return false;
666738032Speter		}
666838032Speter		else
666938032Speter		{
667038032Speter			int i;
667138032Speter
667290792Sgshapiro			/* set default fields */
667338032Speter			for (i = 0; i < substrings; i++)
667438032Speter				fields[i] = i;
667538032Speter			fields[i] = END_OF_FIELDS;
667638032Speter		}
667738032Speter		map_p->regex_subfields = fields;
667838032Speter		if (tTd(38, 3))
667938032Speter		{
668038032Speter			int *ip;
668138032Speter
668290792Sgshapiro			sm_dprintf("regex_map_init: subfields");
668338032Speter			for (ip = fields; *ip != END_OF_FIELDS; ip++)
668490792Sgshapiro				sm_dprintf(" %d", *ip);
668590792Sgshapiro			sm_dprintf("\n");
668638032Speter		}
668738032Speter	}
668890792Sgshapiro	map->map_db1 = (ARBPTR_T) map_p;	/* dirty hack */
668990792Sgshapiro	return true;
669038032Speter}
669138032Speter
669238032Speterstatic char *
669338032Speterregex_map_rewrite(map, s, slen, av)
669438032Speter	MAP *map;
669538032Speter	const char *s;
669638032Speter	size_t slen;
669738032Speter	char **av;
669838032Speter{
669938032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
670038032Speter		return map_rewrite(map, av[0], strlen(av[0]), NULL);
670138032Speter	else
670277349Sgshapiro		return map_rewrite(map, s, slen, av);
670338032Speter}
670438032Speter
670538032Speterchar *
670638032Speterregex_map_lookup(map, name, av, statp)
670738032Speter	MAP *map;
670838032Speter	char *name;
670938032Speter	char **av;
671038032Speter	int *statp;
671138032Speter{
671238032Speter	int reg_res;
671338032Speter	struct regex_map *map_p;
671438032Speter	regmatch_t pmatch[MAX_MATCH];
671538032Speter
671638032Speter	if (tTd(38, 20))
671738032Speter	{
671838032Speter		char **cpp;
671938032Speter
672090792Sgshapiro		sm_dprintf("regex_map_lookup: key '%s'\n", name);
672164562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
672290792Sgshapiro			sm_dprintf("regex_map_lookup: arg '%s'\n", *cpp);
672338032Speter	}
672438032Speter
672538032Speter	map_p = (struct regex_map *)(map->map_db1);
672671345Sgshapiro	reg_res = regexec(map_p->regex_pattern_buf,
672764562Sgshapiro			  name, MAX_MATCH, pmatch, 0);
672838032Speter
672938032Speter	if (bitset(MF_REGEX_NOT, map->map_mflags))
673038032Speter	{
673138032Speter		/* option -n */
673238032Speter		if (reg_res == REG_NOMATCH)
673390792Sgshapiro			return regex_map_rewrite(map, "", (size_t) 0, av);
673438032Speter		else
673538032Speter			return NULL;
673638032Speter	}
673738032Speter	if (reg_res == REG_NOMATCH)
673838032Speter		return NULL;
673938032Speter
674038032Speter	if (map_p->regex_subfields != NULL)
674138032Speter	{
674238032Speter		/* option -s */
674338032Speter		static char retbuf[MAXNAME];
674438032Speter		int fields[MAX_MATCH + 1];
674590792Sgshapiro		bool first = true;
674638032Speter		int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
674790792Sgshapiro		bool quotemode = false, bslashmode = false;
674838032Speter		register char *dp, *sp;
674938032Speter		char *endp, *ldp;
675038032Speter		int *ip;
675138032Speter
675238032Speter		dp = retbuf;
675338032Speter		ldp = retbuf + sizeof(retbuf) - 1;
675438032Speter
675538032Speter		if (av[1] != NULL)
675638032Speter		{
675738032Speter			if (parse_fields(av[1], fields, MAX_MATCH + 1,
675871345Sgshapiro					 (int) map_p->regex_pattern_buf->re_nsub + 1) == -1)
675938032Speter			{
676038032Speter				*statp = EX_CONFIG;
676138032Speter				return NULL;
676238032Speter			}
676338032Speter			ip = fields;
676438032Speter		}
676538032Speter		else
676638032Speter			ip = map_p->regex_subfields;
676738032Speter
676838032Speter		for ( ; *ip != END_OF_FIELDS; ip++)
676938032Speter		{
677038032Speter			if (!first)
677138032Speter			{
677264562Sgshapiro				for (sp = map_p->regex_delim; *sp; sp++)
677338032Speter				{
677438032Speter					if (dp < ldp)
677538032Speter						*dp++ = *sp;
677638032Speter				}
677738032Speter			}
677838032Speter			else
677990792Sgshapiro				first = false;
678038032Speter
678171345Sgshapiro			if (*ip >= MAX_MATCH ||
678271345Sgshapiro			    pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
678338032Speter				continue;
678438032Speter
678538032Speter			sp = name + pmatch[*ip].rm_so;
678638032Speter			endp = name + pmatch[*ip].rm_eo;
678738032Speter			for (; endp > sp; sp++)
678838032Speter			{
678938032Speter				if (dp < ldp)
679038032Speter				{
679164562Sgshapiro					if (bslashmode)
679264562Sgshapiro					{
679338032Speter						*dp++ = *sp;
679490792Sgshapiro						bslashmode = false;
679538032Speter					}
679664562Sgshapiro					else if (quotemode && *sp != '"' &&
679738032Speter						*sp != '\\')
679838032Speter					{
679938032Speter						*dp++ = *sp;
680038032Speter					}
680190792Sgshapiro					else switch (*dp++ = *sp)
680238032Speter					{
680390792Sgshapiro					  case '\\':
680490792Sgshapiro						bslashmode = true;
680538032Speter						break;
680638032Speter
680790792Sgshapiro					  case '(':
680838032Speter						cmntcnt++;
680938032Speter						break;
681038032Speter
681190792Sgshapiro					  case ')':
681238032Speter						cmntcnt--;
681338032Speter						break;
681438032Speter
681590792Sgshapiro					  case '<':
681638032Speter						anglecnt++;
681738032Speter						break;
681838032Speter
681990792Sgshapiro					  case '>':
682038032Speter						anglecnt--;
682138032Speter						break;
682238032Speter
682390792Sgshapiro					  case ' ':
682438032Speter						spacecnt++;
682538032Speter						break;
682638032Speter
682790792Sgshapiro					  case '"':
682838032Speter						quotemode = !quotemode;
682938032Speter						break;
683038032Speter					}
683138032Speter				}
683238032Speter			}
683338032Speter		}
683438032Speter		if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
683538032Speter		    bslashmode || spacecnt != 0)
683638032Speter		{
683764562Sgshapiro			sm_syslog(LOG_WARNING, NOQID,
683864562Sgshapiro				  "Warning: regex may cause prescan() failure map=%s lookup=%s",
683964562Sgshapiro				  map->map_mname, name);
684038032Speter			return NULL;
684138032Speter		}
684238032Speter
684338032Speter		*dp = '\0';
684438032Speter
684538032Speter		return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
684638032Speter	}
684738032Speter	return regex_map_rewrite(map, "", (size_t)0, av);
684838032Speter}
684938032Speter#endif /* MAP_REGEX */
685090792Sgshapiro/*
685164562Sgshapiro**  NSD modules
685264562Sgshapiro*/
685390792Sgshapiro#if MAP_NSD
685464562Sgshapiro
685564562Sgshapiro# include <ndbm.h>
685664562Sgshapiro# define _DATUM_DEFINED
685764562Sgshapiro# include <ns_api.h>
685864562Sgshapiro
685964562Sgshapirotypedef struct ns_map_list
686064562Sgshapiro{
686190792Sgshapiro	ns_map_t		*map;		/* XXX ns_ ? */
686290792Sgshapiro	char			*mapname;
686390792Sgshapiro	struct ns_map_list	*next;
686464562Sgshapiro} ns_map_list_t;
686564562Sgshapiro
686664562Sgshapirostatic ns_map_t *
686764562Sgshapirons_map_t_find(mapname)
686864562Sgshapiro	char *mapname;
686964562Sgshapiro{
687064562Sgshapiro	static ns_map_list_t *ns_maps = NULL;
687164562Sgshapiro	ns_map_list_t *ns_map;
687264562Sgshapiro
687364562Sgshapiro	/* walk the list of maps looking for the correctly named map */
687464562Sgshapiro	for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next)
687564562Sgshapiro	{
687664562Sgshapiro		if (strcmp(ns_map->mapname, mapname) == 0)
687764562Sgshapiro			break;
687864562Sgshapiro	}
687964562Sgshapiro
688064562Sgshapiro	/* if we are looking at a NULL ns_map_list_t, then create a new one */
688164562Sgshapiro	if (ns_map == NULL)
688264562Sgshapiro	{
688364562Sgshapiro		ns_map = (ns_map_list_t *) xalloc(sizeof *ns_map);
688464562Sgshapiro		ns_map->mapname = newstr(mapname);
688564562Sgshapiro		ns_map->map = (ns_map_t *) xalloc(sizeof *ns_map->map);
6886102528Sgshapiro		memset(ns_map->map, '\0', sizeof *ns_map->map);
688764562Sgshapiro		ns_map->next = ns_maps;
688864562Sgshapiro		ns_maps = ns_map;
688964562Sgshapiro	}
689064562Sgshapiro	return ns_map->map;
689164562Sgshapiro}
689264562Sgshapiro
689364562Sgshapirochar *
689464562Sgshapironsd_map_lookup(map, name, av, statp)
689564562Sgshapiro	MAP *map;
689664562Sgshapiro	char *name;
689764562Sgshapiro	char **av;
689864562Sgshapiro	int *statp;
689964562Sgshapiro{
690071345Sgshapiro	int buflen, r;
690164562Sgshapiro	char *p;
690264562Sgshapiro	ns_map_t *ns_map;
690364562Sgshapiro	char keybuf[MAXNAME + 1];
690464562Sgshapiro	char buf[MAXLINE];
690564562Sgshapiro
690664562Sgshapiro	if (tTd(38, 20))
690790792Sgshapiro		sm_dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
690864562Sgshapiro
690964562Sgshapiro	buflen = strlen(name);
691064562Sgshapiro	if (buflen > sizeof keybuf - 1)
691190792Sgshapiro		buflen = sizeof keybuf - 1;	/* XXX simply cut off? */
691264562Sgshapiro	memmove(keybuf, name, buflen);
691364562Sgshapiro	keybuf[buflen] = '\0';
691464562Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
691564562Sgshapiro		makelower(keybuf);
691664562Sgshapiro
691764562Sgshapiro	ns_map = ns_map_t_find(map->map_file);
691864562Sgshapiro	if (ns_map == NULL)
691964562Sgshapiro	{
692064562Sgshapiro		if (tTd(38, 20))
692190792Sgshapiro			sm_dprintf("nsd_map_t_find failed\n");
692271345Sgshapiro		*statp = EX_UNAVAILABLE;
692364562Sgshapiro		return NULL;
692464562Sgshapiro	}
692598121Sgshapiro	r = ns_lookup(ns_map, NULL, map->map_file, keybuf, NULL,
692698121Sgshapiro		      buf, sizeof buf);
692771345Sgshapiro	if (r == NS_UNAVAIL || r == NS_TRYAGAIN)
692871345Sgshapiro	{
692971345Sgshapiro		*statp = EX_TEMPFAIL;
693064562Sgshapiro		return NULL;
693171345Sgshapiro	}
693277349Sgshapiro	if (r == NS_BADREQ
693377349Sgshapiro# ifdef NS_NOPERM
693477349Sgshapiro	    || r == NS_NOPERM
693577349Sgshapiro# endif /* NS_NOPERM */
693677349Sgshapiro	    )
693771345Sgshapiro	{
693871345Sgshapiro		*statp = EX_CONFIG;
693971345Sgshapiro		return NULL;
694071345Sgshapiro	}
694171345Sgshapiro	if (r != NS_SUCCESS)
694271345Sgshapiro	{
694371345Sgshapiro		*statp = EX_NOTFOUND;
694471345Sgshapiro		return NULL;
694571345Sgshapiro	}
694664562Sgshapiro
694771345Sgshapiro	*statp = EX_OK;
694871345Sgshapiro
694964562Sgshapiro	/* Null out trailing \n */
695064562Sgshapiro	if ((p = strchr(buf, '\n')) != NULL)
695164562Sgshapiro		*p = '\0';
695264562Sgshapiro
695364562Sgshapiro	return map_rewrite(map, buf, strlen(buf), av);
695464562Sgshapiro}
695564562Sgshapiro#endif /* MAP_NSD */
695664562Sgshapiro
695764562Sgshapirochar *
695864562Sgshapiroarith_map_lookup(map, name, av, statp)
695964562Sgshapiro	MAP *map;
696064562Sgshapiro	char *name;
696164562Sgshapiro	char **av;
696264562Sgshapiro	int *statp;
696364562Sgshapiro{
696464562Sgshapiro	long r;
696564562Sgshapiro	long v[2];
696690792Sgshapiro	bool res = false;
696764562Sgshapiro	bool boolres;
696864562Sgshapiro	static char result[16];
696964562Sgshapiro	char **cpp;
697064562Sgshapiro
697164562Sgshapiro	if (tTd(38, 2))
697264562Sgshapiro	{
697390792Sgshapiro		sm_dprintf("arith_map_lookup: key '%s'\n", name);
697464562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
697590792Sgshapiro			sm_dprintf("arith_map_lookup: arg '%s'\n", *cpp);
697664562Sgshapiro	}
697764562Sgshapiro	r = 0;
697890792Sgshapiro	boolres = false;
697964562Sgshapiro	cpp = av;
698064562Sgshapiro	*statp = EX_OK;
698164562Sgshapiro
698264562Sgshapiro	/*
698364562Sgshapiro	**  read arguments for arith map
698464562Sgshapiro	**  - no check is made whether they are really numbers
698564562Sgshapiro	**  - just ignores args after the second
698664562Sgshapiro	*/
698790792Sgshapiro
698864562Sgshapiro	for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
698964562Sgshapiro		v[r++] = strtol(*cpp, NULL, 0);
699064562Sgshapiro
699164562Sgshapiro	/* operator and (at least) two operands given? */
699264562Sgshapiro	if (name != NULL && r == 2)
699364562Sgshapiro	{
699490792Sgshapiro		switch (*name)
699564562Sgshapiro		{
699664562Sgshapiro		  case '|':
699764562Sgshapiro			r = v[0] | v[1];
699864562Sgshapiro			break;
699964562Sgshapiro
700064562Sgshapiro		  case '&':
700164562Sgshapiro			r = v[0] & v[1];
700264562Sgshapiro			break;
700364562Sgshapiro
700464562Sgshapiro		  case '%':
700564562Sgshapiro			if (v[1] == 0)
700664562Sgshapiro				return NULL;
700764562Sgshapiro			r = v[0] % v[1];
700864562Sgshapiro			break;
700964562Sgshapiro		  case '+':
701064562Sgshapiro			r = v[0] + v[1];
701164562Sgshapiro			break;
701264562Sgshapiro
701364562Sgshapiro		  case '-':
701464562Sgshapiro			r = v[0] - v[1];
701564562Sgshapiro			break;
701664562Sgshapiro
701764562Sgshapiro		  case '*':
701864562Sgshapiro			r = v[0] * v[1];
701964562Sgshapiro			break;
702064562Sgshapiro
702164562Sgshapiro		  case '/':
702264562Sgshapiro			if (v[1] == 0)
702364562Sgshapiro				return NULL;
702464562Sgshapiro			r = v[0] / v[1];
702564562Sgshapiro			break;
702664562Sgshapiro
702764562Sgshapiro		  case 'l':
702864562Sgshapiro			res = v[0] < v[1];
702990792Sgshapiro			boolres = true;
703064562Sgshapiro			break;
703164562Sgshapiro
703264562Sgshapiro		  case '=':
703364562Sgshapiro			res = v[0] == v[1];
703490792Sgshapiro			boolres = true;
703564562Sgshapiro			break;
703664562Sgshapiro
703764562Sgshapiro		  default:
703864562Sgshapiro			/* XXX */
703964562Sgshapiro			*statp = EX_CONFIG;
704064562Sgshapiro			if (LogLevel > 10)
704164562Sgshapiro				sm_syslog(LOG_WARNING, NOQID,
704264562Sgshapiro					  "arith_map: unknown operator %c",
704364562Sgshapiro					  isprint(*name) ? *name : '?');
704464562Sgshapiro			return NULL;
704564562Sgshapiro		}
704664562Sgshapiro		if (boolres)
704790792Sgshapiro			(void) sm_snprintf(result, sizeof result,
704890792Sgshapiro				res ? "TRUE" : "FALSE");
704964562Sgshapiro		else
705090792Sgshapiro			(void) sm_snprintf(result, sizeof result, "%ld", r);
705164562Sgshapiro		return result;
705264562Sgshapiro	}
705364562Sgshapiro	*statp = EX_CONFIG;
705464562Sgshapiro	return NULL;
705564562Sgshapiro}
7056132943Sgshapiro
7057132943Sgshapiro#if SOCKETMAP
7058132943Sgshapiro
7059132943Sgshapiro# if NETINET || NETINET6
7060132943Sgshapiro#  include <arpa/inet.h>
7061132943Sgshapiro# endif /* NETINET || NETINET6 */
7062132943Sgshapiro
7063132943Sgshapiro# define socket_map_next map_stack[0]
7064132943Sgshapiro
7065132943Sgshapiro/*
7066132943Sgshapiro**  SOCKET_MAP_OPEN -- open socket table
7067132943Sgshapiro*/
7068132943Sgshapiro
7069132943Sgshapirobool
7070132943Sgshapirosocket_map_open(map, mode)
7071132943Sgshapiro	MAP *map;
7072132943Sgshapiro	int mode;
7073132943Sgshapiro{
7074132943Sgshapiro	STAB *s;
7075132943Sgshapiro	int sock = 0;
7076132943Sgshapiro	SOCKADDR_LEN_T addrlen = 0;
7077132943Sgshapiro	int addrno = 0;
7078132943Sgshapiro	int save_errno;
7079132943Sgshapiro	char *p;
7080132943Sgshapiro	char *colon;
7081132943Sgshapiro	char *at;
7082132943Sgshapiro	struct hostent *hp = NULL;
7083132943Sgshapiro	SOCKADDR addr;
7084132943Sgshapiro
7085132943Sgshapiro	if (tTd(38, 2))
7086132943Sgshapiro		sm_dprintf("socket_map_open(%s, %s, %d)\n",
7087132943Sgshapiro			map->map_mname, map->map_file, mode);
7088132943Sgshapiro
7089132943Sgshapiro	mode &= O_ACCMODE;
7090132943Sgshapiro
7091132943Sgshapiro	/* sendmail doesn't have the ability to write to SOCKET (yet) */
7092132943Sgshapiro	if (mode != O_RDONLY)
7093132943Sgshapiro	{
7094132943Sgshapiro		/* issue a pseudo-error message */
7095132943Sgshapiro		errno = SM_EMAPCANTWRITE;
7096132943Sgshapiro		return false;
7097132943Sgshapiro	}
7098132943Sgshapiro
7099132943Sgshapiro	if (*map->map_file == '\0')
7100132943Sgshapiro	{
7101132943Sgshapiro		syserr("socket map \"%s\": empty or missing socket information",
7102132943Sgshapiro			map->map_mname);
7103132943Sgshapiro		return false;
7104132943Sgshapiro	}
7105132943Sgshapiro
7106132943Sgshapiro	s = socket_map_findconn(map->map_file);
7107132943Sgshapiro	if (s->s_socketmap != NULL)
7108132943Sgshapiro	{
7109132943Sgshapiro		/* Copy open connection */
7110132943Sgshapiro		map->map_db1 = s->s_socketmap->map_db1;
7111132943Sgshapiro
7112132943Sgshapiro		/* Add this map as head of linked list */
7113132943Sgshapiro		map->socket_map_next = s->s_socketmap;
7114132943Sgshapiro		s->s_socketmap = map;
7115132943Sgshapiro
7116132943Sgshapiro		if (tTd(38, 2))
7117132943Sgshapiro			sm_dprintf("using cached connection\n");
7118132943Sgshapiro		return true;
7119132943Sgshapiro	}
7120132943Sgshapiro
7121132943Sgshapiro	if (tTd(38, 2))
7122132943Sgshapiro		sm_dprintf("opening new connection\n");
7123132943Sgshapiro
7124132943Sgshapiro	/* following code is ripped from milter.c */
7125132943Sgshapiro	/* XXX It should be put in a library... */
7126132943Sgshapiro
7127132943Sgshapiro	/* protocol:filename or protocol:port@host */
7128132943Sgshapiro	memset(&addr, '\0', sizeof addr);
7129132943Sgshapiro	p = map->map_file;
7130132943Sgshapiro	colon = strchr(p, ':');
7131132943Sgshapiro	if (colon != NULL)
7132132943Sgshapiro	{
7133132943Sgshapiro		*colon = '\0';
7134132943Sgshapiro
7135132943Sgshapiro		if (*p == '\0')
7136132943Sgshapiro		{
7137132943Sgshapiro# if NETUNIX
7138132943Sgshapiro			/* default to AF_UNIX */
7139132943Sgshapiro			addr.sa.sa_family = AF_UNIX;
7140132943Sgshapiro# else /* NETUNIX */
7141132943Sgshapiro#  if NETINET
7142132943Sgshapiro			/* default to AF_INET */
7143132943Sgshapiro			addr.sa.sa_family = AF_INET;
7144132943Sgshapiro#  else /* NETINET */
7145132943Sgshapiro#   if NETINET6
7146132943Sgshapiro			/* default to AF_INET6 */
7147132943Sgshapiro			addr.sa.sa_family = AF_INET6;
7148132943Sgshapiro#   else /* NETINET6 */
7149132943Sgshapiro			/* no protocols available */
7150132943Sgshapiro			syserr("socket map \"%s\": no valid socket protocols available",
7151132943Sgshapiro			map->map_mname);
7152132943Sgshapiro			return false;
7153132943Sgshapiro#   endif /* NETINET6 */
7154132943Sgshapiro#  endif /* NETINET */
7155132943Sgshapiro# endif /* NETUNIX */
7156132943Sgshapiro		}
7157132943Sgshapiro# if NETUNIX
7158132943Sgshapiro		else if (sm_strcasecmp(p, "unix") == 0 ||
7159132943Sgshapiro			 sm_strcasecmp(p, "local") == 0)
7160132943Sgshapiro			addr.sa.sa_family = AF_UNIX;
7161132943Sgshapiro# endif /* NETUNIX */
7162132943Sgshapiro# if NETINET
7163132943Sgshapiro		else if (sm_strcasecmp(p, "inet") == 0)
7164132943Sgshapiro			addr.sa.sa_family = AF_INET;
7165132943Sgshapiro# endif /* NETINET */
7166132943Sgshapiro# if NETINET6
7167132943Sgshapiro		else if (sm_strcasecmp(p, "inet6") == 0)
7168132943Sgshapiro			addr.sa.sa_family = AF_INET6;
7169132943Sgshapiro# endif /* NETINET6 */
7170132943Sgshapiro		else
7171132943Sgshapiro		{
7172132943Sgshapiro# ifdef EPROTONOSUPPORT
7173132943Sgshapiro			errno = EPROTONOSUPPORT;
7174132943Sgshapiro# else /* EPROTONOSUPPORT */
7175132943Sgshapiro			errno = EINVAL;
7176132943Sgshapiro# endif /* EPROTONOSUPPORT */
7177132943Sgshapiro			syserr("socket map \"%s\": unknown socket type %s",
7178132943Sgshapiro			       map->map_mname, p);
7179132943Sgshapiro			return false;
7180132943Sgshapiro		}
7181132943Sgshapiro		*colon++ = ':';
7182132943Sgshapiro	}
7183132943Sgshapiro	else
7184132943Sgshapiro	{
7185132943Sgshapiro		colon = p;
7186132943Sgshapiro#if NETUNIX
7187132943Sgshapiro		/* default to AF_UNIX */
7188132943Sgshapiro		addr.sa.sa_family = AF_UNIX;
7189132943Sgshapiro#else /* NETUNIX */
7190132943Sgshapiro# if NETINET
7191132943Sgshapiro		/* default to AF_INET */
7192132943Sgshapiro		addr.sa.sa_family = AF_INET;
7193132943Sgshapiro# else /* NETINET */
7194132943Sgshapiro#  if NETINET6
7195132943Sgshapiro		/* default to AF_INET6 */
7196132943Sgshapiro		addr.sa.sa_family = AF_INET6;
7197132943Sgshapiro#  else /* NETINET6 */
7198132943Sgshapiro		syserr("socket map \"%s\": unknown socket type %s",
7199132943Sgshapiro		       map->map_mname, p);
7200132943Sgshapiro		return false;
7201132943Sgshapiro#  endif /* NETINET6 */
7202132943Sgshapiro# endif /* NETINET */
7203132943Sgshapiro#endif /* NETUNIX */
7204132943Sgshapiro	}
7205132943Sgshapiro
7206132943Sgshapiro# if NETUNIX
7207132943Sgshapiro	if (addr.sa.sa_family == AF_UNIX)
7208132943Sgshapiro	{
7209132943Sgshapiro		long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK;
7210132943Sgshapiro
7211132943Sgshapiro		at = colon;
7212132943Sgshapiro		if (strlen(colon) >= sizeof addr.sunix.sun_path)
7213132943Sgshapiro		{
7214132943Sgshapiro			syserr("socket map \"%s\": local socket name %s too long",
7215132943Sgshapiro			       map->map_mname, colon);
7216132943Sgshapiro			return false;
7217132943Sgshapiro		}
7218132943Sgshapiro		errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
7219132943Sgshapiro				 S_IRUSR|S_IWUSR, NULL);
7220132943Sgshapiro
7221132943Sgshapiro		if (errno != 0)
7222132943Sgshapiro		{
7223132943Sgshapiro			/* if not safe, don't create */
7224132943Sgshapiro				syserr("socket map \"%s\": local socket name %s unsafe",
7225132943Sgshapiro			       map->map_mname, colon);
7226132943Sgshapiro			return false;
7227132943Sgshapiro		}
7228132943Sgshapiro
7229132943Sgshapiro		(void) sm_strlcpy(addr.sunix.sun_path, colon,
7230132943Sgshapiro			       sizeof addr.sunix.sun_path);
7231132943Sgshapiro		addrlen = sizeof (struct sockaddr_un);
7232132943Sgshapiro	}
7233132943Sgshapiro	else
7234132943Sgshapiro# endif /* NETUNIX */
7235132943Sgshapiro# if NETINET || NETINET6
7236132943Sgshapiro	if (false
7237132943Sgshapiro#  if NETINET
7238132943Sgshapiro		 || addr.sa.sa_family == AF_INET
7239132943Sgshapiro#  endif /* NETINET */
7240132943Sgshapiro#  if NETINET6
7241132943Sgshapiro		 || addr.sa.sa_family == AF_INET6
7242132943Sgshapiro#  endif /* NETINET6 */
7243132943Sgshapiro		 )
7244132943Sgshapiro	{
7245132943Sgshapiro		unsigned short port;
7246132943Sgshapiro
7247132943Sgshapiro		/* Parse port@host */
7248132943Sgshapiro		at = strchr(colon, '@');
7249132943Sgshapiro		if (at == NULL)
7250132943Sgshapiro		{
7251132943Sgshapiro			syserr("socket map \"%s\": bad address %s (expected port@host)",
7252132943Sgshapiro				       map->map_mname, colon);
7253132943Sgshapiro			return false;
7254132943Sgshapiro		}
7255132943Sgshapiro		*at = '\0';
7256132943Sgshapiro		if (isascii(*colon) && isdigit(*colon))
7257132943Sgshapiro			port = htons((unsigned short) atoi(colon));
7258132943Sgshapiro		else
7259132943Sgshapiro		{
7260132943Sgshapiro#  ifdef NO_GETSERVBYNAME
7261132943Sgshapiro			syserr("socket map \"%s\": invalid port number %s",
7262132943Sgshapiro				       map->map_mname, colon);
7263132943Sgshapiro			return false;
7264132943Sgshapiro#  else /* NO_GETSERVBYNAME */
7265132943Sgshapiro			register struct servent *sp;
7266132943Sgshapiro
7267132943Sgshapiro			sp = getservbyname(colon, "tcp");
7268132943Sgshapiro			if (sp == NULL)
7269132943Sgshapiro			{
7270132943Sgshapiro				syserr("socket map \"%s\": unknown port name %s",
7271132943Sgshapiro					       map->map_mname, colon);
7272132943Sgshapiro				return false;
7273132943Sgshapiro			}
7274132943Sgshapiro			port = sp->s_port;
7275132943Sgshapiro#  endif /* NO_GETSERVBYNAME */
7276132943Sgshapiro		}
7277132943Sgshapiro		*at++ = '@';
7278132943Sgshapiro		if (*at == '[')
7279132943Sgshapiro		{
7280132943Sgshapiro			char *end;
7281132943Sgshapiro
7282132943Sgshapiro			end = strchr(at, ']');
7283132943Sgshapiro			if (end != NULL)
7284132943Sgshapiro			{
7285132943Sgshapiro				bool found = false;
7286132943Sgshapiro#  if NETINET
7287132943Sgshapiro				unsigned long hid = INADDR_NONE;
7288132943Sgshapiro#  endif /* NETINET */
7289132943Sgshapiro#  if NETINET6
7290132943Sgshapiro				struct sockaddr_in6 hid6;
7291132943Sgshapiro#  endif /* NETINET6 */
7292132943Sgshapiro
7293132943Sgshapiro				*end = '\0';
7294132943Sgshapiro#  if NETINET
7295132943Sgshapiro				if (addr.sa.sa_family == AF_INET &&
7296132943Sgshapiro				    (hid = inet_addr(&at[1])) != INADDR_NONE)
7297132943Sgshapiro				{
7298132943Sgshapiro					addr.sin.sin_addr.s_addr = hid;
7299132943Sgshapiro					addr.sin.sin_port = port;
7300132943Sgshapiro					found = true;
7301132943Sgshapiro				}
7302132943Sgshapiro#  endif /* NETINET */
7303132943Sgshapiro#  if NETINET6
7304132943Sgshapiro				(void) memset(&hid6, '\0', sizeof hid6);
7305132943Sgshapiro				if (addr.sa.sa_family == AF_INET6 &&
7306132943Sgshapiro				    anynet_pton(AF_INET6, &at[1],
7307132943Sgshapiro						&hid6.sin6_addr) == 1)
7308132943Sgshapiro				{
7309132943Sgshapiro					addr.sin6.sin6_addr = hid6.sin6_addr;
7310132943Sgshapiro					addr.sin6.sin6_port = port;
7311132943Sgshapiro					found = true;
7312132943Sgshapiro				}
7313132943Sgshapiro#  endif /* NETINET6 */
7314132943Sgshapiro				*end = ']';
7315132943Sgshapiro				if (!found)
7316132943Sgshapiro				{
7317132943Sgshapiro					syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
7318132943Sgshapiro					       map->map_mname, at);
7319132943Sgshapiro					return false;
7320132943Sgshapiro				}
7321132943Sgshapiro			}
7322132943Sgshapiro			else
7323132943Sgshapiro			{
7324132943Sgshapiro				syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
7325132943Sgshapiro				       map->map_mname, at);
7326132943Sgshapiro				return false;
7327132943Sgshapiro			}
7328132943Sgshapiro		}
7329132943Sgshapiro		else
7330132943Sgshapiro		{
7331132943Sgshapiro			hp = sm_gethostbyname(at, addr.sa.sa_family);
7332132943Sgshapiro			if (hp == NULL)
7333132943Sgshapiro			{
7334132943Sgshapiro				syserr("socket map \"%s\": Unknown host name %s",
7335132943Sgshapiro					map->map_mname, at);
7336132943Sgshapiro				return false;
7337132943Sgshapiro			}
7338132943Sgshapiro			addr.sa.sa_family = hp->h_addrtype;
7339132943Sgshapiro			switch (hp->h_addrtype)
7340132943Sgshapiro			{
7341132943Sgshapiro#  if NETINET
7342132943Sgshapiro			  case AF_INET:
7343132943Sgshapiro				memmove(&addr.sin.sin_addr,
7344132943Sgshapiro					hp->h_addr, INADDRSZ);
7345132943Sgshapiro				addr.sin.sin_port = port;
7346132943Sgshapiro				addrlen = sizeof (struct sockaddr_in);
7347132943Sgshapiro				addrno = 1;
7348132943Sgshapiro				break;
7349132943Sgshapiro#  endif /* NETINET */
7350132943Sgshapiro
7351132943Sgshapiro#  if NETINET6
7352132943Sgshapiro			  case AF_INET6:
7353132943Sgshapiro				memmove(&addr.sin6.sin6_addr,
7354132943Sgshapiro					hp->h_addr, IN6ADDRSZ);
7355132943Sgshapiro				addr.sin6.sin6_port = port;
7356132943Sgshapiro				addrlen = sizeof (struct sockaddr_in6);
7357132943Sgshapiro				addrno = 1;
7358132943Sgshapiro				break;
7359132943Sgshapiro#  endif /* NETINET6 */
7360132943Sgshapiro
7361132943Sgshapiro			  default:
7362132943Sgshapiro				syserr("socket map \"%s\": Unknown protocol for %s (%d)",
7363132943Sgshapiro					map->map_mname, at, hp->h_addrtype);
7364132943Sgshapiro#  if NETINET6
7365132943Sgshapiro				freehostent(hp);
7366132943Sgshapiro#  endif /* NETINET6 */
7367132943Sgshapiro				return false;
7368132943Sgshapiro			}
7369132943Sgshapiro		}
7370132943Sgshapiro	}
7371132943Sgshapiro	else
7372132943Sgshapiro# endif /* NETINET || NETINET6 */
7373132943Sgshapiro	{
7374132943Sgshapiro		syserr("socket map \"%s\": unknown socket protocol",
7375132943Sgshapiro			map->map_mname);
7376132943Sgshapiro		return false;
7377132943Sgshapiro	}
7378132943Sgshapiro
7379132943Sgshapiro	/* nope, actually connecting */
7380132943Sgshapiro	for (;;)
7381132943Sgshapiro	{
7382132943Sgshapiro		sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
7383132943Sgshapiro		if (sock < 0)
7384132943Sgshapiro		{
7385132943Sgshapiro			save_errno = errno;
7386132943Sgshapiro			if (tTd(38, 5))
7387132943Sgshapiro				sm_dprintf("socket map \"%s\": error creating socket: %s\n",
7388132943Sgshapiro					   map->map_mname,
7389132943Sgshapiro					   sm_errstring(save_errno));
7390132943Sgshapiro# if NETINET6
7391132943Sgshapiro			if (hp != NULL)
7392132943Sgshapiro				freehostent(hp);
7393132943Sgshapiro# endif /* NETINET6 */
7394132943Sgshapiro			return false;
7395132943Sgshapiro		}
7396132943Sgshapiro
7397132943Sgshapiro		if (connect(sock, (struct sockaddr *) &addr, addrlen) >= 0)
7398132943Sgshapiro			break;
7399132943Sgshapiro
7400132943Sgshapiro		/* couldn't connect.... try next address */
7401132943Sgshapiro		save_errno = errno;
7402132943Sgshapiro		p = CurHostName;
7403132943Sgshapiro		CurHostName = at;
7404132943Sgshapiro		if (tTd(38, 5))
7405132943Sgshapiro			sm_dprintf("socket_open (%s): open %s failed: %s\n",
7406132943Sgshapiro				map->map_mname, at, sm_errstring(save_errno));
7407132943Sgshapiro		CurHostName = p;
7408132943Sgshapiro		(void) close(sock);
7409132943Sgshapiro
7410132943Sgshapiro		/* try next address */
7411132943Sgshapiro		if (hp != NULL && hp->h_addr_list[addrno] != NULL)
7412132943Sgshapiro		{
7413132943Sgshapiro			switch (addr.sa.sa_family)
7414132943Sgshapiro			{
7415132943Sgshapiro# if NETINET
7416132943Sgshapiro			  case AF_INET:
7417132943Sgshapiro				memmove(&addr.sin.sin_addr,
7418132943Sgshapiro					hp->h_addr_list[addrno++],
7419132943Sgshapiro					INADDRSZ);
7420132943Sgshapiro				break;
7421132943Sgshapiro# endif /* NETINET */
7422132943Sgshapiro
7423132943Sgshapiro# if NETINET6
7424132943Sgshapiro			  case AF_INET6:
7425132943Sgshapiro				memmove(&addr.sin6.sin6_addr,
7426132943Sgshapiro					hp->h_addr_list[addrno++],
7427132943Sgshapiro					IN6ADDRSZ);
7428132943Sgshapiro				break;
7429132943Sgshapiro# endif /* NETINET6 */
7430132943Sgshapiro
7431132943Sgshapiro			  default:
7432132943Sgshapiro				if (tTd(38, 5))
7433132943Sgshapiro					sm_dprintf("socket map \"%s\": Unknown protocol for %s (%d)\n",
7434132943Sgshapiro						   map->map_mname, at,
7435132943Sgshapiro						   hp->h_addrtype);
7436132943Sgshapiro# if NETINET6
7437132943Sgshapiro				freehostent(hp);
7438132943Sgshapiro# endif /* NETINET6 */
7439132943Sgshapiro				return false;
7440132943Sgshapiro			}
7441132943Sgshapiro			continue;
7442132943Sgshapiro		}
7443132943Sgshapiro		p = CurHostName;
7444132943Sgshapiro		CurHostName = at;
7445132943Sgshapiro		if (tTd(38, 5))
7446132943Sgshapiro			sm_dprintf("socket map \"%s\": error connecting to socket map: %s\n",
7447132943Sgshapiro				   map->map_mname, sm_errstring(save_errno));
7448132943Sgshapiro		CurHostName = p;
7449132943Sgshapiro# if NETINET6
7450132943Sgshapiro		if (hp != NULL)
7451132943Sgshapiro			freehostent(hp);
7452132943Sgshapiro# endif /* NETINET6 */
7453132943Sgshapiro		return false;
7454132943Sgshapiro	}
7455132943Sgshapiro# if NETINET6
7456132943Sgshapiro	if (hp != NULL)
7457132943Sgshapiro	{
7458132943Sgshapiro		freehostent(hp);
7459132943Sgshapiro		hp = NULL;
7460132943Sgshapiro	}
7461132943Sgshapiro# endif /* NETINET6 */
7462132943Sgshapiro	if ((map->map_db1 = (ARBPTR_T) sm_io_open(SmFtStdiofd,
7463132943Sgshapiro						  SM_TIME_DEFAULT,
7464132943Sgshapiro						  (void *) &sock,
7465132943Sgshapiro						  SM_IO_RDWR,
7466132943Sgshapiro						  NULL)) == NULL)
7467132943Sgshapiro	{
7468132943Sgshapiro		close(sock);
7469132943Sgshapiro		if (tTd(38, 2))
7470132943Sgshapiro		    sm_dprintf("socket_open (%s): failed to create stream: %s\n",
7471132943Sgshapiro			       map->map_mname, sm_errstring(errno));
7472132943Sgshapiro		return false;
7473132943Sgshapiro	}
7474132943Sgshapiro
7475132943Sgshapiro	/* Save connection for reuse */
7476132943Sgshapiro	s->s_socketmap = map;
7477132943Sgshapiro	return true;
7478132943Sgshapiro}
7479132943Sgshapiro
7480132943Sgshapiro/*
7481132943Sgshapiro**  SOCKET_MAP_FINDCONN -- find a SOCKET connection to the server
7482132943Sgshapiro**
7483132943Sgshapiro**	Cache SOCKET connections based on the connection specifier
7484132943Sgshapiro**	and PID so we don't have multiple connections open to
7485132943Sgshapiro**	the same server for different maps.  Need a separate connection
7486132943Sgshapiro**	per PID since a parent process may close the map before the
7487132943Sgshapiro**	child is done with it.
7488132943Sgshapiro**
7489132943Sgshapiro**	Parameters:
7490132943Sgshapiro**		conn -- SOCKET map connection specifier
7491132943Sgshapiro**
7492132943Sgshapiro**	Returns:
7493132943Sgshapiro**		Symbol table entry for the SOCKET connection.
7494132943Sgshapiro*/
7495132943Sgshapiro
7496132943Sgshapirostatic STAB *
7497132943Sgshapirosocket_map_findconn(conn)
7498132943Sgshapiro	const char *conn;
7499132943Sgshapiro{
7500132943Sgshapiro	char *nbuf;
7501132943Sgshapiro	STAB *SM_NONVOLATILE s = NULL;
7502132943Sgshapiro
7503132943Sgshapiro	nbuf = sm_stringf_x("%s%c%d", conn, CONDELSE, (int) CurrentPid);
7504132943Sgshapiro	SM_TRY
7505132943Sgshapiro		s = stab(nbuf, ST_SOCKETMAP, ST_ENTER);
7506132943Sgshapiro	SM_FINALLY
7507132943Sgshapiro		sm_free(nbuf);
7508132943Sgshapiro	SM_END_TRY
7509132943Sgshapiro	return s;
7510132943Sgshapiro}
7511132943Sgshapiro
7512132943Sgshapiro/*
7513132943Sgshapiro**  SOCKET_MAP_CLOSE -- close the socket
7514132943Sgshapiro*/
7515132943Sgshapiro
7516132943Sgshapirovoid
7517132943Sgshapirosocket_map_close(map)
7518132943Sgshapiro	MAP *map;
7519132943Sgshapiro{
7520132943Sgshapiro	STAB *s;
7521132943Sgshapiro	MAP *smap;
7522132943Sgshapiro
7523132943Sgshapiro	if (tTd(38, 20))
7524132943Sgshapiro		sm_dprintf("socket_map_close(%s), pid=%ld\n", map->map_file,
7525132943Sgshapiro			(long) CurrentPid);
7526132943Sgshapiro
7527132943Sgshapiro	/* Check if already closed */
7528132943Sgshapiro	if (map->map_db1 == NULL)
7529132943Sgshapiro	{
7530132943Sgshapiro		if (tTd(38, 20))
7531132943Sgshapiro			sm_dprintf("socket_map_close(%s) already closed\n",
7532132943Sgshapiro				map->map_file);
7533132943Sgshapiro		return;
7534132943Sgshapiro	}
7535132943Sgshapiro	sm_io_close((SM_FILE_T *)map->map_db1, SM_TIME_DEFAULT);
7536132943Sgshapiro
7537132943Sgshapiro	/* Mark all the maps that share the connection as closed */
7538132943Sgshapiro	s = socket_map_findconn(map->map_file);
7539132943Sgshapiro	smap = s->s_socketmap;
7540132943Sgshapiro	while (smap != NULL)
7541132943Sgshapiro	{
7542132943Sgshapiro		MAP *next;
7543132943Sgshapiro
7544132943Sgshapiro		if (tTd(38, 2) && smap != map)
7545132943Sgshapiro			sm_dprintf("socket_map_close(%s): closed %s (shared SOCKET connection)\n",
7546132943Sgshapiro				map->map_mname, smap->map_mname);
7547132943Sgshapiro
7548132943Sgshapiro		smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
7549132943Sgshapiro		smap->map_db1 = NULL;
7550132943Sgshapiro		next = smap->socket_map_next;
7551132943Sgshapiro		smap->socket_map_next = NULL;
7552132943Sgshapiro		smap = next;
7553132943Sgshapiro	}
7554132943Sgshapiro	s->s_socketmap = NULL;
7555132943Sgshapiro}
7556132943Sgshapiro
7557132943Sgshapiro/*
7558132943Sgshapiro** SOCKET_MAP_LOOKUP -- look up a datum in a SOCKET table
7559132943Sgshapiro*/
7560132943Sgshapiro
7561132943Sgshapirochar *
7562132943Sgshapirosocket_map_lookup(map, name, av, statp)
7563132943Sgshapiro	MAP *map;
7564132943Sgshapiro	char *name;
7565132943Sgshapiro	char **av;
7566132943Sgshapiro	int *statp;
7567132943Sgshapiro{
7568132943Sgshapiro	unsigned int nettolen, replylen, recvlen;
7569147078Sgshapiro	char *replybuf, *rval, *value, *status, *key;
7570132943Sgshapiro	SM_FILE_T *f;
7571147078Sgshapiro	char keybuf[MAXNAME + 1];
7572132943Sgshapiro
7573132943Sgshapiro	replybuf = NULL;
7574132943Sgshapiro	rval = NULL;
7575132943Sgshapiro	f = (SM_FILE_T *)map->map_db1;
7576132943Sgshapiro	if (tTd(38, 20))
7577132943Sgshapiro		sm_dprintf("socket_map_lookup(%s, %s) %s\n",
7578132943Sgshapiro			map->map_mname, name, map->map_file);
7579132943Sgshapiro
7580147078Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
7581147078Sgshapiro	{
7582147078Sgshapiro		nettolen = strlen(name);
7583147078Sgshapiro		if (nettolen > sizeof keybuf - 1)
7584147078Sgshapiro			nettolen = sizeof keybuf - 1;
7585147078Sgshapiro		memmove(keybuf, name, nettolen);
7586147078Sgshapiro		keybuf[nettolen] = '\0';
7587147078Sgshapiro		makelower(keybuf);
7588147078Sgshapiro		key = keybuf;
7589147078Sgshapiro	}
7590147078Sgshapiro	else
7591147078Sgshapiro		key = name;
7592147078Sgshapiro
7593147078Sgshapiro	nettolen = strlen(map->map_mname) + 1 + strlen(key);
7594132943Sgshapiro	SM_ASSERT(nettolen > strlen(map->map_mname));
7595147078Sgshapiro	SM_ASSERT(nettolen > strlen(key));
7596132943Sgshapiro	if ((sm_io_fprintf(f, SM_TIME_DEFAULT, "%u:%s %s,",
7597147078Sgshapiro			   nettolen, map->map_mname, key) == SM_IO_EOF) ||
7598132943Sgshapiro	    (sm_io_flush(f, SM_TIME_DEFAULT) != 0) ||
7599132943Sgshapiro	    (sm_io_error(f)))
7600132943Sgshapiro	{
7601132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): failed to send lookup request",
7602132943Sgshapiro			map->map_mname);
7603132943Sgshapiro		*statp = EX_TEMPFAIL;
7604132943Sgshapiro		goto errcl;
7605132943Sgshapiro	}
7606132943Sgshapiro
7607132943Sgshapiro	if (sm_io_fscanf(f, SM_TIME_DEFAULT, "%9u", &replylen) != 1)
7608132943Sgshapiro	{
7609132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): failed to read length parameter of reply",
7610132943Sgshapiro			map->map_mname);
7611132943Sgshapiro		*statp = EX_TEMPFAIL;
7612132943Sgshapiro		goto errcl;
7613132943Sgshapiro	}
7614132943Sgshapiro	if (replylen > SOCKETMAP_MAXL)
7615132943Sgshapiro	{
7616132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): reply too long: %u",
7617132943Sgshapiro			   map->map_mname, replylen);
7618132943Sgshapiro		*statp = EX_TEMPFAIL;
7619132943Sgshapiro		goto errcl;
7620132943Sgshapiro	}
7621132943Sgshapiro	if (sm_io_getc(f, SM_TIME_DEFAULT) != ':')
7622132943Sgshapiro	{
7623132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): missing ':' in reply",
7624132943Sgshapiro			map->map_mname);
7625132943Sgshapiro		*statp = EX_TEMPFAIL;
7626132943Sgshapiro		goto error;
7627132943Sgshapiro	}
7628132943Sgshapiro
7629132943Sgshapiro	replybuf = (char *) sm_malloc(replylen + 1);
7630132943Sgshapiro	if (replybuf == NULL)
7631132943Sgshapiro	{
7632132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): can't allocate %u bytes",
7633132943Sgshapiro			map->map_mname, replylen + 1);
7634132943Sgshapiro		*statp = EX_OSERR;
7635132943Sgshapiro		goto error;
7636132943Sgshapiro	}
7637132943Sgshapiro
7638132943Sgshapiro	recvlen = sm_io_read(f, SM_TIME_DEFAULT, replybuf, replylen);
7639132943Sgshapiro	if (recvlen < replylen)
7640132943Sgshapiro	{
7641132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): received only %u of %u reply characters",
7642132943Sgshapiro			   map->map_mname, recvlen, replylen);
7643132943Sgshapiro		*statp = EX_TEMPFAIL;
7644132943Sgshapiro		goto errcl;
7645132943Sgshapiro	}
7646132943Sgshapiro	if (sm_io_getc(f, SM_TIME_DEFAULT) != ',')
7647132943Sgshapiro	{
7648132943Sgshapiro		syserr("451 4.3.0 socket_map_lookup(%s): missing ',' in reply",
7649132943Sgshapiro			map->map_mname);
7650132943Sgshapiro		*statp = EX_TEMPFAIL;
7651132943Sgshapiro		goto errcl;
7652132943Sgshapiro	}
7653132943Sgshapiro	status = replybuf;
7654132943Sgshapiro	replybuf[recvlen] = '\0';
7655132943Sgshapiro	value = strchr(replybuf, ' ');
7656132943Sgshapiro	if (value != NULL)
7657132943Sgshapiro	{
7658132943Sgshapiro		*value = '\0';
7659132943Sgshapiro		value++;
7660132943Sgshapiro	}
7661132943Sgshapiro	if (strcmp(status, "OK") == 0)
7662132943Sgshapiro	{
7663132943Sgshapiro		*statp = EX_OK;
7664132943Sgshapiro
7665132943Sgshapiro		/* collect the return value */
7666132943Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
7667147078Sgshapiro			rval = map_rewrite(map, key, strlen(key), NULL);
7668132943Sgshapiro		else
7669132943Sgshapiro			rval = map_rewrite(map, value, strlen(value), av);
7670132943Sgshapiro	}
7671132943Sgshapiro	else if (strcmp(status, "NOTFOUND") == 0)
7672132943Sgshapiro	{
7673132943Sgshapiro		*statp = EX_NOTFOUND;
7674132943Sgshapiro		if (tTd(38, 20))
7675132943Sgshapiro			sm_dprintf("socket_map_lookup(%s): %s not found\n",
7676147078Sgshapiro				map->map_mname, key);
7677132943Sgshapiro	}
7678132943Sgshapiro	else
7679132943Sgshapiro	{
7680132943Sgshapiro		if (tTd(38, 5))
7681132943Sgshapiro			sm_dprintf("socket_map_lookup(%s, %s): server returned error: type=%s, reason=%s\n",
7682147078Sgshapiro				map->map_mname, key, status,
7683132943Sgshapiro				value ? value : "");
7684132943Sgshapiro		if ((strcmp(status, "TEMP") == 0) ||
7685132943Sgshapiro		    (strcmp(status, "TIMEOUT") == 0))
7686132943Sgshapiro			*statp = EX_TEMPFAIL;
7687132943Sgshapiro		else if(strcmp(status, "PERM") == 0)
7688132943Sgshapiro			*statp = EX_UNAVAILABLE;
7689132943Sgshapiro		else
7690132943Sgshapiro			*statp = EX_PROTOCOL;
7691132943Sgshapiro	}
7692132943Sgshapiro
7693132943Sgshapiro	if (replybuf != NULL)
7694132943Sgshapiro		sm_free(replybuf);
7695132943Sgshapiro	return rval;
7696132943Sgshapiro
7697132943Sgshapiro  errcl:
7698132943Sgshapiro	socket_map_close(map);
7699132943Sgshapiro  error:
7700132943Sgshapiro	if (replybuf != NULL)
7701132943Sgshapiro		sm_free(replybuf);
7702132943Sgshapiro	return rval;
7703132943Sgshapiro}
7704132943Sgshapiro#endif /* SOCKETMAP */
7705